diff options
author | David S. Miller <davem@davemloft.net> | 2012-05-27 21:14:48 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-27 21:14:48 -0700 |
commit | c2e1ff39c106ab026e3feb29c038855b7ed00393 (patch) | |
tree | e0255b5b9aed8645edc4426f2d4972280910e065 /arch | |
parent | 456d3d42460c1fc20ba0d27442443fcd63aaac35 (diff) | |
parent | b48b2c3e50433ff6f7e46186daa7f986bd960215 (diff) | |
download | linux-stable-c2e1ff39c106ab026e3feb29c038855b7ed00393.tar.gz linux-stable-c2e1ff39c106ab026e3feb29c038855b7ed00393.tar.bz2 linux-stable-c2e1ff39c106ab026e3feb29c038855b7ed00393.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
Pull in Linus's tree to get the commits that blew away
ARCH_USES_GETTIMEOFFSET but didn't update Sparc correctly, so
that I can apply Stephen Rothwell's fix for that mis-merge.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
586 files changed, 16079 insertions, 19988 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index e9a910876cda..8c3d957fa8e2 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -159,6 +159,9 @@ config HAVE_ARCH_TRACEHOOK config HAVE_DMA_ATTRS bool +config HAVE_DMA_CONTIGUOUS + bool + config USE_GENERIC_SMP_HELPERS bool diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 5458aa9db067..5e7601301b41 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -5,6 +5,9 @@ config ARM select HAVE_AOUT select HAVE_DMA_API_DEBUG select HAVE_IDE if PCI || ISA || PCMCIA + select HAVE_DMA_ATTRS + select HAVE_DMA_CONTIGUOUS if (CPU_V6 || CPU_V6K || CPU_V7) + select CMA if (CPU_V6 || CPU_V6K || CPU_V7) select HAVE_MEMBLOCK select RTC_LIB select SYS_SUPPORTS_APM_EMULATION @@ -54,6 +57,14 @@ config ARM config ARM_HAS_SG_CHAIN bool +config NEED_SG_DMA_LENGTH + bool + +config ARM_DMA_USE_IOMMU + select NEED_SG_DMA_LENGTH + select ARM_HAS_SG_CHAIN + bool + config HAVE_PWM bool @@ -445,8 +456,10 @@ config ARCH_MXS select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP select CLKSRC_MMIO + select COMMON_CLK select HAVE_CLK_PREPARE select PINCTRL + select USE_OF help Support for Freescale MXS-based family of processors @@ -936,6 +949,7 @@ config PLAT_SPEAR select ARM_AMBA select ARCH_REQUIRE_GPIOLIB select CLKDEV_LOOKUP + select COMMON_CLK select CLKSRC_MMIO select GENERIC_CLOCKEVENTS select HAVE_CLK @@ -1040,7 +1054,6 @@ source "arch/arm/mach-sa1100/Kconfig" source "arch/arm/plat-samsung/Kconfig" source "arch/arm/plat-s3c24xx/Kconfig" -source "arch/arm/plat-s5p/Kconfig" source "arch/arm/plat-spear/Kconfig" @@ -1091,6 +1104,7 @@ config PLAT_ORION bool select CLKSRC_MMIO select GENERIC_IRQ_CHIP + select COMMON_CLK config PLAT_PXA bool diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 85348a09d655..01a134141216 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 @@ -180,6 +209,14 @@ choice Say Y here if you want kernel low-level debugging support on i.MX50 or i.MX53. + config DEBUG_IMX6Q_UART2 + bool "i.MX6Q Debug UART2" + depends on SOC_IMX6Q + help + Say Y here if you want kernel low-level debugging support + on i.MX6Q UART2. This is correct for e.g. the SabreLite + board. + config DEBUG_IMX6Q_UART4 bool "i.MX6Q Debug UART4" depends on SOC_IMX6Q diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 157900da8782..0298b00fe241 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -160,9 +160,7 @@ machine-$(CONFIG_ARCH_MXS) := mxs machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_NOMADIK) := nomadik machine-$(CONFIG_ARCH_OMAP1) := omap1 -machine-$(CONFIG_ARCH_OMAP2) := omap2 -machine-$(CONFIG_ARCH_OMAP3) := omap2 -machine-$(CONFIG_ARCH_OMAP4) := omap2 +machine-$(CONFIG_ARCH_OMAP2PLUS) := omap2 machine-$(CONFIG_ARCH_ORION5X) := orion5x machine-$(CONFIG_ARCH_PICOXCELL) := picoxcell machine-$(CONFIG_ARCH_PNX4008) := pnx4008 @@ -188,6 +186,8 @@ machine-$(CONFIG_ARCH_VEXPRESS) := vexpress machine-$(CONFIG_ARCH_VT8500) := vt8500 machine-$(CONFIG_ARCH_W90X900) := w90x900 machine-$(CONFIG_FOOTBRIDGE) := footbridge +machine-$(CONFIG_MACH_SPEAR1310) := spear13xx +machine-$(CONFIG_MACH_SPEAR1340) := spear13xx machine-$(CONFIG_MACH_SPEAR300) := spear3xx machine-$(CONFIG_MACH_SPEAR310) := spear3xx machine-$(CONFIG_MACH_SPEAR320) := spear3xx @@ -205,7 +205,7 @@ plat-$(CONFIG_PLAT_NOMADIK) := nomadik plat-$(CONFIG_PLAT_ORION) := orion plat-$(CONFIG_PLAT_PXA) := pxa plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx samsung -plat-$(CONFIG_PLAT_S5P) := s5p samsung +plat-$(CONFIG_PLAT_S5P) := samsung plat-$(CONFIG_PLAT_SPEAR) := spear plat-$(CONFIG_PLAT_VERSATILE) := versatile diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 399d17b231d2..49945cc1bc7d 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -23,4 +23,52 @@ chosen { bootargs = "root=/dev/ram0 rw ramdisk=8192 console=ttySAC1,115200"; }; + + i2c@12C60000 { + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <20000>; + gpios = <&gpb3 0 2 3 0>, + <&gpb3 1 2 3 0>; + + eeprom@50 { + compatible = "samsung,s524ad0xd1"; + reg = <0x50>; + }; + }; + + i2c@12C70000 { + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <20000>; + gpios = <&gpb3 2 2 3 0>, + <&gpb3 3 2 3 0>; + + eeprom@51 { + compatible = "samsung,s524ad0xd1"; + reg = <0x51>; + }; + }; + + i2c@12C80000 { + status = "disabled"; + }; + + i2c@12C90000 { + status = "disabled"; + }; + + i2c@12CA0000 { + status = "disabled"; + }; + + i2c@12CB0000 { + status = "disabled"; + }; + + i2c@12CC0000 { + status = "disabled"; + }; + + i2c@12CD0000 { + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index dfc433599436..5ca0cdb76413 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -23,11 +23,11 @@ compatible = "samsung,exynos5250"; interrupt-parent = <&gic>; - gic:interrupt-controller@10490000 { + gic:interrupt-controller@10481000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; interrupt-controller; - reg = <0x10490000 0x1000>, <0x10480000 0x100>; + reg = <0x10481000 0x1000>, <0x10482000 0x2000>; }; watchdog { @@ -42,30 +42,6 @@ interrupts = <0 43 0>, <0 44 0>; }; - sdhci@12200000 { - compatible = "samsung,exynos4210-sdhci"; - reg = <0x12200000 0x100>; - interrupts = <0 75 0>; - }; - - sdhci@12210000 { - compatible = "samsung,exynos4210-sdhci"; - reg = <0x12210000 0x100>; - interrupts = <0 76 0>; - }; - - sdhci@12220000 { - compatible = "samsung,exynos4210-sdhci"; - reg = <0x12220000 0x100>; - interrupts = <0 77 0>; - }; - - sdhci@12230000 { - compatible = "samsung,exynos4210-sdhci"; - reg = <0x12230000 0x100>; - interrupts = <0 78 0>; - }; - serial@12C00000 { compatible = "samsung,exynos4210-uart"; reg = <0x12C00000 0x100>; @@ -94,48 +70,64 @@ compatible = "samsung,s3c2440-i2c"; reg = <0x12C60000 0x100>; interrupts = <0 56 0>; + #address-cells = <1>; + #size-cells = <0>; }; i2c@12C70000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C70000 0x100>; interrupts = <0 57 0>; + #address-cells = <1>; + #size-cells = <0>; }; i2c@12C80000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C80000 0x100>; interrupts = <0 58 0>; + #address-cells = <1>; + #size-cells = <0>; }; i2c@12C90000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12C90000 0x100>; interrupts = <0 59 0>; + #address-cells = <1>; + #size-cells = <0>; }; i2c@12CA0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CA0000 0x100>; interrupts = <0 60 0>; + #address-cells = <1>; + #size-cells = <0>; }; i2c@12CB0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CB0000 0x100>; interrupts = <0 61 0>; + #address-cells = <1>; + #size-cells = <0>; }; i2c@12CC0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CC0000 0x100>; interrupts = <0 62 0>; + #address-cells = <1>; + #size-cells = <0>; }; i2c@12CD0000 { compatible = "samsung,s3c2440-i2c"; reg = <0x12CD0000 0x100>; interrupts = <0 63 0>; + #address-cells = <1>; + #size-cells = <0>; }; amba { @@ -157,13 +149,13 @@ interrupts = <0 35 0>; }; - mdma0: pdma@10800000 { + mdma0: mdma@10800000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x10800000 0x1000>; interrupts = <0 33 0>; }; - mdma1: pdma@11C10000 { + mdma1: mdma@11C10000 { compatible = "arm,pl330", "arm,primecell"; reg = <0x11C10000 0x1000>; interrupts = <0 124 0>; @@ -242,6 +234,12 @@ #gpio-cells = <4>; }; + gpc4: gpio-controller@114002E0 { + compatible = "samsung,exynos4-gpio"; + reg = <0x114002E0 0x20>; + #gpio-cells = <4>; + }; + gpd0: gpio-controller@11400160 { compatible = "samsung,exynos4-gpio"; reg = <0x11400160 0x20>; @@ -388,19 +386,19 @@ gpv2: gpio-controller@10D10040 { compatible = "samsung,exynos4-gpio"; - reg = <0x10D10040 0x20>; + reg = <0x10D10060 0x20>; #gpio-cells = <4>; }; gpv3: gpio-controller@10D10060 { compatible = "samsung,exynos4-gpio"; - reg = <0x10D10060 0x20>; + reg = <0x10D10080 0x20>; #gpio-cells = <4>; }; gpv4: gpio-controller@10D10080 { compatible = "samsung,exynos4-gpio"; - reg = <0x10D10080 0x20>; + reg = <0x10D100C0 0x20>; #gpio-cells = <4>; }; diff --git a/arch/arm/boot/dts/imx23-evk.dts b/arch/arm/boot/dts/imx23-evk.dts new file mode 100644 index 000000000000..70bffa929b65 --- /dev/null +++ b/arch/arm/boot/dts/imx23-evk.dts @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx23.dtsi" + +/ { + model = "Freescale i.MX23 Evaluation Kit"; + compatible = "fsl,imx23-evk", "fsl,imx23"; + + memory { + reg = <0x40000000 0x08000000>; + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx23-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a &mmc0_pins_fixup>; + bus-width = <8>; + wp-gpios = <&gpio1 30 0>; + status = "okay"; + }; + }; + + apbx@80040000 { + duart: serial@80070000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi new file mode 100644 index 000000000000..8c5f9994f3fc --- /dev/null +++ b/arch/arm/boot/dts/imx23.dtsi @@ -0,0 +1,295 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "skeleton.dtsi" + +/ { + interrupt-parent = <&icoll>; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + }; + + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + apb@80000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80000000 0x80000>; + ranges; + + apbh@80000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80000000 0x40000>; + ranges; + + icoll: interrupt-controller@80000000 { + compatible = "fsl,imx23-icoll", "fsl,mxs-icoll"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x80000000 0x2000>; + }; + + dma-apbh@80004000 { + compatible = "fsl,imx23-dma-apbh"; + reg = <0x80004000 2000>; + }; + + ecc@80008000 { + reg = <0x80008000 2000>; + status = "disabled"; + }; + + bch@8000a000 { + reg = <0x8000a000 2000>; + status = "disabled"; + }; + + gpmi@8000c000 { + reg = <0x8000c000 2000>; + status = "disabled"; + }; + + ssp0: ssp@80010000 { + reg = <0x80010000 2000>; + interrupts = <15 14>; + fsl,ssp-dma-channel = <1>; + status = "disabled"; + }; + + etm@80014000 { + reg = <0x80014000 2000>; + status = "disabled"; + }; + + pinctrl@80018000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx23-pinctrl", "simple-bus"; + reg = <0x80018000 2000>; + + gpio0: gpio@0 { + compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + interrupts = <16>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@1 { + compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + interrupts = <17>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@2 { + compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + interrupts = <18>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + duart_pins_a: duart@0 { + reg = <0>; + fsl,pinmux-ids = <0x11a2 0x11b2>; + fsl,drive-strength = <0>; + fsl,voltage = <1>; + fsl,pull-up = <0>; + }; + + mmc0_8bit_pins_a: mmc0-8bit@0 { + reg = <0>; + fsl,pinmux-ids = <0x2020 0x2030 0x2040 + 0x2050 0x0082 0x0092 0x00a2 + 0x00b2 0x2000 0x2010 0x2060>; + fsl,drive-strength = <1>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + + mmc0_pins_fixup: mmc0-pins-fixup { + fsl,pinmux-ids = <0x2010 0x2060>; + fsl,pull-up = <0>; + }; + }; + + digctl@8001c000 { + reg = <0x8001c000 2000>; + status = "disabled"; + }; + + emi@80020000 { + reg = <0x80020000 2000>; + status = "disabled"; + }; + + dma-apbx@80024000 { + compatible = "fsl,imx23-dma-apbx"; + reg = <0x80024000 2000>; + }; + + dcp@80028000 { + reg = <0x80028000 2000>; + status = "disabled"; + }; + + pxp@8002a000 { + reg = <0x8002a000 2000>; + status = "disabled"; + }; + + ocotp@8002c000 { + reg = <0x8002c000 2000>; + status = "disabled"; + }; + + axi-ahb@8002e000 { + reg = <0x8002e000 2000>; + status = "disabled"; + }; + + lcdif@80030000 { + reg = <0x80030000 2000>; + status = "disabled"; + }; + + ssp1: ssp@80034000 { + reg = <0x80034000 2000>; + interrupts = <2 20>; + fsl,ssp-dma-channel = <2>; + status = "disabled"; + }; + + tvenc@80038000 { + reg = <0x80038000 2000>; + status = "disabled"; + }; + }; + + apbx@80040000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80040000 0x40000>; + ranges; + + clkctl@80040000 { + reg = <0x80040000 2000>; + status = "disabled"; + }; + + saif0: saif@80042000 { + reg = <0x80042000 2000>; + status = "disabled"; + }; + + power@80044000 { + reg = <0x80044000 2000>; + status = "disabled"; + }; + + saif1: saif@80046000 { + reg = <0x80046000 2000>; + status = "disabled"; + }; + + audio-out@80048000 { + reg = <0x80048000 2000>; + status = "disabled"; + }; + + audio-in@8004c000 { + reg = <0x8004c000 2000>; + status = "disabled"; + }; + + lradc@80050000 { + reg = <0x80050000 2000>; + status = "disabled"; + }; + + spdif@80054000 { + reg = <0x80054000 2000>; + status = "disabled"; + }; + + i2c@80058000 { + reg = <0x80058000 2000>; + status = "disabled"; + }; + + rtc@8005c000 { + reg = <0x8005c000 2000>; + status = "disabled"; + }; + + pwm@80064000 { + reg = <0x80064000 2000>; + status = "disabled"; + }; + + timrot@80068000 { + reg = <0x80068000 2000>; + status = "disabled"; + }; + + auart0: serial@8006c000 { + reg = <0x8006c000 0x2000>; + status = "disabled"; + }; + + auart1: serial@8006e000 { + reg = <0x8006e000 0x2000>; + status = "disabled"; + }; + + duart: serial@80070000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80070000 0x2000>; + interrupts = <0>; + status = "disabled"; + }; + + usbphy@8007c000 { + reg = <0x8007c000 0x2000>; + status = "disabled"; + }; + }; + }; + + ahb@80080000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80080000 0x80000>; + ranges; + + usbctrl@80080000 { + reg = <0x80080000 0x10000>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx27-phytec-phycore.dts b/arch/arm/boot/dts/imx27-phytec-phycore.dts index a51a08fc2af9..2b0ff60247a4 100644 --- a/arch/arm/boot/dts/imx27-phytec-phycore.dts +++ b/arch/arm/boot/dts/imx27-phytec-phycore.dts @@ -27,22 +27,22 @@ status = "okay"; }; - uart@1000a000 { + serial@1000a000 { fsl,uart-has-rtscts; status = "okay"; }; - uart@1000b000 { + serial@1000b000 { fsl,uart-has-rtscts; status = "okay"; }; - uart@1000c000 { + serial@1000c000 { fsl,uart-has-rtscts; status = "okay"; }; - fec@1002b000 { + ethernet@1002b000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi index bc5e7d5ddd54..2b1a166d41f9 100644 --- a/arch/arm/boot/dts/imx27.dtsi +++ b/arch/arm/boot/dts/imx27.dtsi @@ -59,28 +59,28 @@ status = "disabled"; }; - uart1: uart@1000a000 { + uart1: serial@1000a000 { compatible = "fsl,imx27-uart", "fsl,imx21-uart"; reg = <0x1000a000 0x1000>; interrupts = <20>; status = "disabled"; }; - uart2: uart@1000b000 { + uart2: serial@1000b000 { compatible = "fsl,imx27-uart", "fsl,imx21-uart"; reg = <0x1000b000 0x1000>; interrupts = <19>; status = "disabled"; }; - uart3: uart@1000c000 { + uart3: serial@1000c000 { compatible = "fsl,imx27-uart", "fsl,imx21-uart"; reg = <0x1000c000 0x1000>; interrupts = <18>; status = "disabled"; }; - uart4: uart@1000d000 { + uart4: serial@1000d000 { compatible = "fsl,imx27-uart", "fsl,imx21-uart"; reg = <0x1000d000 0x1000>; interrupts = <17>; @@ -183,14 +183,14 @@ status = "disabled"; }; - uart5: uart@1001b000 { + uart5: serial@1001b000 { compatible = "fsl,imx27-uart", "fsl,imx21-uart"; reg = <0x1001b000 0x1000>; interrupts = <49>; status = "disabled"; }; - uart6: uart@1001c000 { + uart6: serial@1001c000 { compatible = "fsl,imx27-uart", "fsl,imx21-uart"; reg = <0x1001c000 0x1000>; interrupts = <48>; @@ -206,7 +206,7 @@ status = "disabled"; }; - fec: fec@1002b000 { + fec: ethernet@1002b000 { compatible = "fsl,imx27-fec"; reg = <0x1002b000 0x4000>; interrupts = <50>; diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts new file mode 100644 index 000000000000..ee520a529cb4 --- /dev/null +++ b/arch/arm/boot/dts/imx28-evk.dts @@ -0,0 +1,114 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx28.dtsi" + +/ { + model = "Freescale i.MX28 Evaluation Kit"; + compatible = "fsl,imx28-evk", "fsl,imx28"; + + memory { + reg = <0x40000000 0x08000000>; + }; + + apb@80000000 { + apbh@80000000 { + ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_8bit_pins_a + &mmc0_cd_cfg &mmc0_sck_cfg>; + bus-width = <8>; + wp-gpios = <&gpio2 12 0>; + status = "okay"; + }; + + ssp1: ssp@80012000 { + compatible = "fsl,imx28-mmc"; + bus-width = <8>; + wp-gpios = <&gpio0 28 0>; + status = "okay"; + }; + }; + + apbx@80040000 { + saif0: saif@80042000 { + pinctrl-names = "default"; + pinctrl-0 = <&saif0_pins_a>; + status = "okay"; + }; + + saif1: saif@80046000 { + pinctrl-names = "default"; + pinctrl-0 = <&saif1_pins_a>; + fsl,saif-master = <&saif0>; + status = "okay"; + }; + + i2c0: i2c@80058000 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + + sgtl5000: codec@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; + + }; + }; + + duart: serial@80074000 { + pinctrl-names = "default"; + pinctrl-0 = <&duart_pins_a>; + status = "okay"; + }; + }; + }; + + ahb@80080000 { + mac0: ethernet@800f0000 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>; + status = "okay"; + }; + + mac1: ethernet@800f4000 { + phy-mode = "rmii"; + pinctrl-names = "default"; + pinctrl-0 = <&mac1_pins_a>; + status = "okay"; + }; + }; + + regulators { + compatible = "simple-bus"; + + reg_3p3v: 3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + + sound { + compatible = "fsl,imx28-evk-sgtl5000", + "fsl,mxs-audio-sgtl5000"; + model = "imx28-evk-sgtl5000"; + saif-controllers = <&saif0 &saif1>; + audio-codec = <&sgtl5000>; + }; +}; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi new file mode 100644 index 000000000000..4634cb861a59 --- /dev/null +++ b/arch/arm/boot/dts/imx28.dtsi @@ -0,0 +1,497 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "skeleton.dtsi" + +/ { + interrupt-parent = <&icoll>; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + saif0 = &saif0; + saif1 = &saif1; + }; + + cpus { + cpu@0 { + compatible = "arm,arm926ejs"; + }; + }; + + apb@80000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80000000 0x80000>; + ranges; + + apbh@80000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80000000 0x3c900>; + ranges; + + icoll: interrupt-controller@80000000 { + compatible = "fsl,imx28-icoll", "fsl,mxs-icoll"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x80000000 0x2000>; + }; + + hsadc@80002000 { + reg = <0x80002000 2000>; + interrupts = <13 87>; + status = "disabled"; + }; + + dma-apbh@80004000 { + compatible = "fsl,imx28-dma-apbh"; + reg = <0x80004000 2000>; + }; + + perfmon@80006000 { + reg = <0x80006000 800>; + interrupts = <27>; + status = "disabled"; + }; + + bch@8000a000 { + reg = <0x8000a000 2000>; + interrupts = <41>; + status = "disabled"; + }; + + gpmi@8000c000 { + reg = <0x8000c000 2000>; + interrupts = <42 88>; + status = "disabled"; + }; + + ssp0: ssp@80010000 { + reg = <0x80010000 2000>; + interrupts = <96 82>; + fsl,ssp-dma-channel = <0>; + status = "disabled"; + }; + + ssp1: ssp@80012000 { + reg = <0x80012000 2000>; + interrupts = <97 83>; + fsl,ssp-dma-channel = <1>; + status = "disabled"; + }; + + ssp2: ssp@80014000 { + reg = <0x80014000 2000>; + interrupts = <98 84>; + fsl,ssp-dma-channel = <2>; + status = "disabled"; + }; + + ssp3: ssp@80016000 { + reg = <0x80016000 2000>; + interrupts = <99 85>; + fsl,ssp-dma-channel = <3>; + status = "disabled"; + }; + + pinctrl@80018000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-pinctrl", "simple-bus"; + reg = <0x80018000 2000>; + + gpio0: gpio@0 { + compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + interrupts = <127>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@1 { + compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + interrupts = <126>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@2 { + compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + interrupts = <125>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@3 { + compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + interrupts = <124>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio@4 { + compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + interrupts = <123>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + duart_pins_a: duart@0 { + reg = <0>; + fsl,pinmux-ids = <0x3102 0x3112>; + fsl,drive-strength = <0>; + fsl,voltage = <1>; + fsl,pull-up = <0>; + }; + + mac0_pins_a: mac0@0 { + reg = <0>; + fsl,pinmux-ids = <0x4000 0x4010 0x4020 + 0x4030 0x4040 0x4060 0x4070 + 0x4080 0x4100>; + fsl,drive-strength = <1>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + + mac1_pins_a: mac1@0 { + reg = <0>; + fsl,pinmux-ids = <0x40f1 0x4091 0x40a1 + 0x40e1 0x40b1 0x40c1>; + fsl,drive-strength = <1>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + + mmc0_8bit_pins_a: mmc0-8bit@0 { + reg = <0>; + fsl,pinmux-ids = <0x2000 0x2010 0x2020 + 0x2030 0x2040 0x2050 0x2060 + 0x2070 0x2080 0x2090 0x20a0>; + fsl,drive-strength = <1>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + + mmc0_cd_cfg: mmc0-cd-cfg { + fsl,pinmux-ids = <0x2090>; + fsl,pull-up = <0>; + }; + + mmc0_sck_cfg: mmc0-sck-cfg { + fsl,pinmux-ids = <0x20a0>; + fsl,drive-strength = <2>; + fsl,pull-up = <0>; + }; + + i2c0_pins_a: i2c0@0 { + reg = <0>; + fsl,pinmux-ids = <0x3180 0x3190>; + fsl,drive-strength = <1>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + + saif0_pins_a: saif0@0 { + reg = <0>; + fsl,pinmux-ids = + <0x3140 0x3150 0x3160 0x3170>; + fsl,drive-strength = <2>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + + saif1_pins_a: saif1@0 { + reg = <0>; + fsl,pinmux-ids = <0x31a0>; + fsl,drive-strength = <2>; + fsl,voltage = <1>; + fsl,pull-up = <1>; + }; + }; + + digctl@8001c000 { + reg = <0x8001c000 2000>; + interrupts = <89>; + status = "disabled"; + }; + + etm@80022000 { + reg = <0x80022000 2000>; + status = "disabled"; + }; + + dma-apbx@80024000 { + compatible = "fsl,imx28-dma-apbx"; + reg = <0x80024000 2000>; + }; + + dcp@80028000 { + reg = <0x80028000 2000>; + interrupts = <52 53 54>; + status = "disabled"; + }; + + pxp@8002a000 { + reg = <0x8002a000 2000>; + interrupts = <39>; + status = "disabled"; + }; + + ocotp@8002c000 { + reg = <0x8002c000 2000>; + status = "disabled"; + }; + + axi-ahb@8002e000 { + reg = <0x8002e000 2000>; + status = "disabled"; + }; + + lcdif@80030000 { + reg = <0x80030000 2000>; + interrupts = <38 86>; + status = "disabled"; + }; + + can0: can@80032000 { + reg = <0x80032000 2000>; + interrupts = <8>; + status = "disabled"; + }; + + can1: can@80034000 { + reg = <0x80034000 2000>; + interrupts = <9>; + status = "disabled"; + }; + + simdbg@8003c000 { + reg = <0x8003c000 200>; + status = "disabled"; + }; + + simgpmisel@8003c200 { + reg = <0x8003c200 100>; + status = "disabled"; + }; + + simsspsel@8003c300 { + reg = <0x8003c300 100>; + status = "disabled"; + }; + + simmemsel@8003c400 { + reg = <0x8003c400 100>; + status = "disabled"; + }; + + gpiomon@8003c500 { + reg = <0x8003c500 100>; + status = "disabled"; + }; + + simenet@8003c700 { + reg = <0x8003c700 100>; + status = "disabled"; + }; + + armjtag@8003c800 { + reg = <0x8003c800 100>; + status = "disabled"; + }; + }; + + apbx@80040000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80040000 0x40000>; + ranges; + + clkctl@80040000 { + reg = <0x80040000 2000>; + status = "disabled"; + }; + + saif0: saif@80042000 { + compatible = "fsl,imx28-saif"; + reg = <0x80042000 2000>; + interrupts = <59 80>; + fsl,saif-dma-channel = <4>; + status = "disabled"; + }; + + power@80044000 { + reg = <0x80044000 2000>; + status = "disabled"; + }; + + saif1: saif@80046000 { + compatible = "fsl,imx28-saif"; + reg = <0x80046000 2000>; + interrupts = <58 81>; + fsl,saif-dma-channel = <5>; + status = "disabled"; + }; + + lradc@80050000 { + reg = <0x80050000 2000>; + status = "disabled"; + }; + + spdif@80054000 { + reg = <0x80054000 2000>; + interrupts = <45 66>; + status = "disabled"; + }; + + rtc@80056000 { + reg = <0x80056000 2000>; + interrupts = <28 29>; + status = "disabled"; + }; + + i2c0: i2c@80058000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-i2c"; + reg = <0x80058000 2000>; + interrupts = <111 68>; + status = "disabled"; + }; + + i2c1: i2c@8005a000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-i2c"; + reg = <0x8005a000 2000>; + interrupts = <110 69>; + status = "disabled"; + }; + + pwm@80064000 { + reg = <0x80064000 2000>; + status = "disabled"; + }; + + timrot@80068000 { + reg = <0x80068000 2000>; + status = "disabled"; + }; + + auart0: serial@8006a000 { + reg = <0x8006a000 0x2000>; + interrupts = <112 70 71>; + status = "disabled"; + }; + + auart1: serial@8006c000 { + reg = <0x8006c000 0x2000>; + interrupts = <113 72 73>; + status = "disabled"; + }; + + auart2: serial@8006e000 { + reg = <0x8006e000 0x2000>; + interrupts = <114 74 75>; + status = "disabled"; + }; + + auart3: serial@80070000 { + reg = <0x80070000 0x2000>; + interrupts = <115 76 77>; + status = "disabled"; + }; + + auart4: serial@80072000 { + reg = <0x80072000 0x2000>; + interrupts = <116 78 79>; + status = "disabled"; + }; + + duart: serial@80074000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80074000 0x1000>; + interrupts = <47>; + status = "disabled"; + }; + + usbphy0: usbphy@8007c000 { + reg = <0x8007c000 0x2000>; + status = "disabled"; + }; + + usbphy1: usbphy@8007e000 { + reg = <0x8007e000 0x2000>; + status = "disabled"; + }; + }; + }; + + ahb@80080000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x80080000 0x80000>; + ranges; + + usbctrl0: usbctrl@80080000 { + reg = <0x80080000 0x10000>; + status = "disabled"; + }; + + usbctrl1: usbctrl@80090000 { + reg = <0x80090000 0x10000>; + status = "disabled"; + }; + + dflpt@800c0000 { + reg = <0x800c0000 0x10000>; + status = "disabled"; + }; + + mac0: ethernet@800f0000 { + compatible = "fsl,imx28-fec"; + reg = <0x800f0000 0x4000>; + interrupts = <101>; + status = "disabled"; + }; + + mac1: ethernet@800f4000 { + compatible = "fsl,imx28-fec"; + reg = <0x800f4000 0x4000>; + interrupts = <102>; + status = "disabled"; + }; + + switch@800f8000 { + reg = <0x800f8000 0x8000>; + status = "disabled"; + }; + + }; +}; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index 9949e6060dee..de065b5976e6 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -17,10 +17,6 @@ model = "Freescale i.MX51 Babbage Board"; compatible = "fsl,imx51-babbage", "fsl,imx51"; - chosen { - bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; - }; - memory { reg = <0x90000000 0x20000000>; }; @@ -40,7 +36,7 @@ status = "okay"; }; - uart3: uart@7000c000 { + uart3: serial@7000c000 { fsl,uart-has-rtscts; status = "okay"; }; @@ -166,6 +162,11 @@ }; }; }; + + ssi2: ssi@70014000 { + fsl,mode = "i2s-slave"; + status = "okay"; + }; }; wdog@73f98000 { /* WDOG1 */ @@ -177,12 +178,12 @@ reg = <0x73fa8000 0x4000>; }; - uart1: uart@73fbc000 { + uart1: serial@73fbc000 { fsl,uart-has-rtscts; status = "okay"; }; - uart2: uart@73fc0000 { + uart2: serial@73fc0000 { status = "okay"; }; }; @@ -195,13 +196,20 @@ i2c@83fc4000 { /* I2C2 */ status = "okay"; - codec: sgtl5000@0a { + sgtl5000: codec@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; + clock-frequency = <26000000>; + VDDA-supply = <&vdig_reg>; + VDDIO-supply = <&vvideo_reg>; }; }; - fec@83fec000 { + audmux@83fd0000 { + status = "okay"; + }; + + ethernet@83fec000 { phy-mode = "mii"; status = "okay"; }; @@ -218,4 +226,18 @@ gpio-key,wakeup; }; }; + + sound { + compatible = "fsl,imx51-babbage-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx51-babbage-sgtl5000"; + ssi-controller = <&ssi2>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <2>; + mux-ext-port = <3>; + }; }; diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi index 6663986fe1c8..bfa65abe8ef2 100644 --- a/arch/arm/boot/dts/imx51.dtsi +++ b/arch/arm/boot/dts/imx51.dtsi @@ -86,7 +86,7 @@ status = "disabled"; }; - uart3: uart@7000c000 { + uart3: serial@7000c000 { compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x7000c000 0x4000>; interrupts = <33>; @@ -102,6 +102,15 @@ status = "disabled"; }; + ssi2: ssi@70014000 { + compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; + reg = <0x70014000 0x4000>; + interrupts = <30>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + esdhc@70020000 { /* ESDHC3 */ compatible = "fsl,imx51-esdhc"; reg = <0x70020000 0x4000>; @@ -171,14 +180,14 @@ status = "disabled"; }; - uart1: uart@73fbc000 { + uart1: serial@73fbc000 { compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x73fbc000 0x4000>; interrupts = <31>; status = "disabled"; }; - uart2: uart@73fc0000 { + uart2: serial@73fc0000 { compatible = "fsl,imx51-uart", "fsl,imx21-uart"; reg = <0x73fc0000 0x4000>; interrupts = <32>; @@ -235,7 +244,31 @@ status = "disabled"; }; - fec@83fec000 { + ssi1: ssi@83fcc000 { + compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; + reg = <0x83fcc000 0x4000>; + interrupts = <29>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <29 28 27 26>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + + audmux@83fd0000 { + compatible = "fsl,imx51-audmux", "fsl,imx31-audmux"; + reg = <0x83fd0000 0x4000>; + status = "disabled"; + }; + + ssi3: ssi@83fe8000 { + compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; + reg = <0x83fe8000 0x4000>; + interrupts = <96>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <47 46 37 35>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + + ethernet@83fec000 { compatible = "fsl,imx51-fec", "fsl,imx27-fec"; reg = <0x83fec000 0x4000>; interrupts = <87>; diff --git a/arch/arm/boot/dts/imx53-ard.dts b/arch/arm/boot/dts/imx53-ard.dts index 2dccce46ed81..5b8eafcdbeec 100644 --- a/arch/arm/boot/dts/imx53-ard.dts +++ b/arch/arm/boot/dts/imx53-ard.dts @@ -17,10 +17,6 @@ model = "Freescale i.MX53 Automotive Reference Design Board"; compatible = "fsl,imx53-ard", "fsl,imx53"; - chosen { - bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; - }; - memory { reg = <0x70000000 0x40000000>; }; @@ -44,7 +40,7 @@ reg = <0x53fa8000 0x4000>; }; - uart1: uart@53fbc000 { + uart1: serial@53fbc000 { status = "okay"; }; }; diff --git a/arch/arm/boot/dts/imx53-evk.dts b/arch/arm/boot/dts/imx53-evk.dts index 5bac4aa4800b..9c798034675e 100644 --- a/arch/arm/boot/dts/imx53-evk.dts +++ b/arch/arm/boot/dts/imx53-evk.dts @@ -17,10 +17,6 @@ model = "Freescale i.MX53 Evaluation Kit"; compatible = "fsl,imx53-evk", "fsl,imx53"; - chosen { - bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; - }; - memory { reg = <0x70000000 0x80000000>; }; @@ -75,7 +71,7 @@ reg = <0x53fa8000 0x4000>; }; - uart1: uart@53fbc000 { + uart1: serial@53fbc000 { status = "okay"; }; }; @@ -99,7 +95,7 @@ }; }; - fec@63fec000 { + ethernet@63fec000 { phy-mode = "rmii"; phy-reset-gpios = <&gpio7 6 0>; status = "okay"; diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 5c57c8672c36..2d803a9a6949 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -17,10 +17,6 @@ model = "Freescale i.MX53 Quick Start Board"; compatible = "fsl,imx53-qsb", "fsl,imx53"; - chosen { - bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; - }; - memory { reg = <0x70000000 0x40000000>; }; @@ -33,6 +29,11 @@ status = "okay"; }; + ssi2: ssi@50014000 { + fsl,mode = "i2s-slave"; + status = "okay"; + }; + esdhc@50020000 { /* ESDHC3 */ cd-gpios = <&gpio3 11 0>; wp-gpios = <&gpio3 12 0>; @@ -49,7 +50,7 @@ reg = <0x53fa8000 0x4000>; }; - uart1: uart@53fbc000 { + uart1: serial@53fbc000 { status = "okay"; }; }; @@ -62,9 +63,11 @@ i2c@63fc4000 { /* I2C2 */ status = "okay"; - codec: sgtl5000@0a { + sgtl5000: codec@0a { compatible = "fsl,sgtl5000"; reg = <0x0a>; + VDDA-supply = <®_3p2v>; + VDDIO-supply = <®_3p2v>; }; }; @@ -77,12 +80,88 @@ }; pmic: dialog@48 { - compatible = "dialog,da9053", "dialog,da9052"; + compatible = "dlg,da9053-aa", "dlg,da9052"; reg = <0x48>; + + regulators { + buck0 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2075000>; + }; + + buck1 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2075000>; + }; + + buck2 { + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <2500000>; + }; + + buck3 { + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <2500000>; + }; + + ldo4 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1800000>; + }; + + ldo5 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1800000>; + }; + + ldo6 { + regulator-min-microvolt = <1725000>; + regulator-max-microvolt = <3300000>; + }; + + ldo7 { + regulator-min-microvolt = <1725000>; + regulator-max-microvolt = <3300000>; + }; + + ldo8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + }; + + ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + }; + + ldo10 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + }; + + ldo11 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + }; + + ldo12 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3650000>; + }; + + ldo13 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + }; + }; }; }; - fec@63fec000 { + audmux@63fd0000 { + status = "okay"; + }; + + ethernet@63fec000 { phy-mode = "rmii"; phy-reset-gpios = <&gpio7 6 0>; status = "okay"; @@ -122,4 +201,30 @@ linux,default-trigger = "heartbeat"; }; }; + + regulators { + compatible = "simple-bus"; + + reg_3p2v: 3p2v { + compatible = "regulator-fixed"; + regulator-name = "3P2V"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-always-on; + }; + }; + + sound { + compatible = "fsl,imx53-qsb-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx53-qsb-sgtl5000"; + ssi-controller = <&ssi2>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <2>; + mux-ext-port = <5>; + }; }; diff --git a/arch/arm/boot/dts/imx53-smd.dts b/arch/arm/boot/dts/imx53-smd.dts index c7ee86c2dfb5..08091029168e 100644 --- a/arch/arm/boot/dts/imx53-smd.dts +++ b/arch/arm/boot/dts/imx53-smd.dts @@ -17,10 +17,6 @@ model = "Freescale i.MX53 Smart Mobile Reference Design Board"; compatible = "fsl,imx53-smd", "fsl,imx53"; - chosen { - bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p3 rootwait"; - }; - memory { reg = <0x70000000 0x40000000>; }; @@ -35,11 +31,11 @@ }; esdhc@50008000 { /* ESDHC2 */ - fsl,card-wired; + non-removable; status = "okay"; }; - uart3: uart@5000c000 { + uart3: serial@5000c000 { fsl,uart-has-rtscts; status = "okay"; }; @@ -76,7 +72,7 @@ }; esdhc@50020000 { /* ESDHC3 */ - fsl,card-wired; + non-removable; status = "okay"; }; }; @@ -90,11 +86,11 @@ reg = <0x53fa8000 0x4000>; }; - uart1: uart@53fbc000 { + uart1: serial@53fbc000 { status = "okay"; }; - uart2: uart@53fc0000 { + uart2: serial@53fc0000 { status = "okay"; }; }; @@ -142,7 +138,7 @@ }; }; - fec@63fec000 { + ethernet@63fec000 { phy-mode = "rmii"; phy-reset-gpios = <&gpio7 6 0>; status = "okay"; diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi index 5dd91b942c91..e3e869470cd3 100644 --- a/arch/arm/boot/dts/imx53.dtsi +++ b/arch/arm/boot/dts/imx53.dtsi @@ -88,7 +88,7 @@ status = "disabled"; }; - uart3: uart@5000c000 { + uart3: serial@5000c000 { compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x5000c000 0x4000>; interrupts = <33>; @@ -104,6 +104,15 @@ status = "disabled"; }; + ssi2: ssi@50014000 { + compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + reg = <0x50014000 0x4000>; + interrupts = <30>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <25 24 23 22>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + esdhc@50020000 { /* ESDHC3 */ compatible = "fsl,imx53-esdhc"; reg = <0x50020000 0x4000>; @@ -173,14 +182,14 @@ status = "disabled"; }; - uart1: uart@53fbc000 { + uart1: serial@53fbc000 { compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x53fbc000 0x4000>; interrupts = <31>; status = "disabled"; }; - uart2: uart@53fc0000 { + uart2: serial@53fc0000 { compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x53fc0000 0x4000>; interrupts = <32>; @@ -226,7 +235,7 @@ status = "disabled"; }; - uart4: uart@53ff0000 { + uart4: serial@53ff0000 { compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x53ff0000 0x4000>; interrupts = <13>; @@ -241,7 +250,7 @@ reg = <0x60000000 0x10000000>; ranges; - uart5: uart@63f90000 { + uart5: serial@63f90000 { compatible = "fsl,imx53-uart", "fsl,imx21-uart"; reg = <0x63f90000 0x4000>; interrupts = <86>; @@ -290,7 +299,31 @@ status = "disabled"; }; - fec@63fec000 { + ssi1: ssi@63fcc000 { + compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + reg = <0x63fcc000 0x4000>; + interrupts = <29>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <29 28 27 26>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + + audmux@63fd0000 { + compatible = "fsl,imx53-audmux", "fsl,imx31-audmux"; + reg = <0x63fd0000 0x4000>; + status = "disabled"; + }; + + ssi3: ssi@63fe8000 { + compatible = "fsl,imx53-ssi", "fsl,imx21-ssi"; + reg = <0x63fe8000 0x4000>; + interrupts = <96>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <47 46 45 44>; /* TX0 RX0 TX1 RX1 */ + status = "disabled"; + }; + + ethernet@63fec000 { compatible = "fsl,imx53-fec", "fsl,imx25-fec"; reg = <0x63fec000 0x4000>; interrupts = <87>; diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts index ce1c8238c897..db4c6096c562 100644 --- a/arch/arm/boot/dts/imx6q-arm2.dts +++ b/arch/arm/boot/dts/imx6q-arm2.dts @@ -17,19 +17,14 @@ model = "Freescale i.MX6 Quad Armadillo2 Board"; compatible = "fsl,imx6q-arm2", "fsl,imx6q"; - chosen { - bootargs = "console=ttymxc0,115200 root=/dev/mmcblk3p3 rootwait"; - }; - memory { reg = <0x10000000 0x80000000>; }; soc { aips-bus@02100000 { /* AIPS2 */ - enet@02188000 { + ethernet@02188000 { phy-mode = "rgmii"; - local-mac-address = [00 04 9F 01 1B 61]; status = "okay"; }; @@ -37,16 +32,20 @@ cd-gpios = <&gpio6 11 0>; wp-gpios = <&gpio6 14 0>; vmmc-supply = <®_3p3v>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3_1>; status = "okay"; }; usdhc@0219c000 { /* uSDHC4 */ - fsl,card-wired; + non-removable; vmmc-supply = <®_3p3v>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4_1>; status = "okay"; }; - uart4: uart@021f0000 { + uart4: serial@021f0000 { status = "okay"; }; }; diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts index 4663a4e5a285..e0ec92973e7e 100644 --- a/arch/arm/boot/dts/imx6q-sabrelite.dts +++ b/arch/arm/boot/dts/imx6q-sabrelite.dts @@ -22,8 +22,30 @@ }; soc { + aips-bus@02000000 { /* AIPS1 */ + spba-bus@02000000 { + ecspi@02008000 { /* eCSPI1 */ + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio3 19 0>; + status = "okay"; + + flash: m25p80@0 { + compatible = "sst,sst25vf016b"; + spi-max-frequency = <20000000>; + reg = <0>; + }; + }; + + ssi1: ssi@02028000 { + fsl,mode = "i2s-slave"; + status = "okay"; + }; + }; + + }; + aips-bus@02100000 { /* AIPS2 */ - enet@02188000 { + ethernet@02188000 { phy-mode = "rgmii"; phy-reset-gpios = <&gpio3 23 0>; status = "okay"; @@ -43,13 +65,23 @@ status = "okay"; }; - uart2: uart@021e8000 { + audmux@021d8000 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_audmux_1>; + }; + + uart2: serial@021e8000 { status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_serial2_1>; }; i2c@021a0000 { /* I2C1 */ status = "okay"; clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_1>; codec: sgtl5000@0a { compatible = "fsl,sgtl5000"; @@ -80,4 +112,18 @@ regulator-always-on; }; }; + + sound { + compatible = "fsl,imx6q-sabrelite-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx6q-sabrelite-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <4>; + }; }; diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts b/arch/arm/boot/dts/imx6q-sabresd.dts new file mode 100644 index 000000000000..07509a181178 --- /dev/null +++ b/arch/arm/boot/dts/imx6q-sabresd.dts @@ -0,0 +1,53 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "imx6q.dtsi" + +/ { + model = "Freescale i.MX6Q SABRE Smart Device Board"; + compatible = "fsl,imx6q-sabresd", "fsl,imx6q"; + + memory { + reg = <0x10000000 0x40000000>; + }; + + soc { + + aips-bus@02000000 { /* AIPS1 */ + spba-bus@02000000 { + uart1: serial@02020000 { + status = "okay"; + }; + }; + }; + + aips-bus@02100000 { /* AIPS2 */ + ethernet@02188000 { + phy-mode = "rgmii"; + status = "okay"; + }; + + usdhc@02194000 { /* uSDHC2 */ + cd-gpios = <&gpio2 2 0>; + wp-gpios = <&gpio2 3 0>; + status = "okay"; + }; + + usdhc@02198000 { /* uSDHC3 */ + cd-gpios = <&gpio2 0 0>; + wp-gpios = <&gpio2 1 0>; + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index 4905f51a106f..8c90cbac945f 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -165,7 +165,7 @@ status = "disabled"; }; - uart1: uart@02020000 { + uart1: serial@02020000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x02020000 0x4000>; interrupts = <0 26 0x04>; @@ -177,19 +177,31 @@ interrupts = <0 51 0x04>; }; - ssi@02028000 { /* SSI1 */ + ssi1: ssi@02028000 { + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x02028000 0x4000>; interrupts = <0 46 0x04>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <38 37>; + status = "disabled"; }; - ssi@0202c000 { /* SSI2 */ + ssi2: ssi@0202c000 { + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x0202c000 0x4000>; interrupts = <0 47 0x04>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <42 41>; + status = "disabled"; }; - ssi@02030000 { /* SSI3 */ + ssi3: ssi@02030000 { + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; reg = <0x02030000 0x4000>; interrupts = <0 48 0x04>; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <46 45>; + status = "disabled"; }; asrc@02034000 { @@ -346,6 +358,90 @@ compatible = "fsl,imx6q-anatop"; reg = <0x020c8000 0x1000>; interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; + + regulator-1p1@110 { + compatible = "fsl,anatop-regulator"; + regulator-name = "vdd1p1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1375000>; + regulator-always-on; + anatop-reg-offset = <0x110>; + anatop-vol-bit-shift = <8>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <4>; + anatop-min-voltage = <800000>; + anatop-max-voltage = <1375000>; + }; + + regulator-3p0@120 { + compatible = "fsl,anatop-regulator"; + regulator-name = "vdd3p0"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3150000>; + regulator-always-on; + anatop-reg-offset = <0x120>; + anatop-vol-bit-shift = <8>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <0>; + anatop-min-voltage = <2625000>; + anatop-max-voltage = <3400000>; + }; + + regulator-2p5@130 { + compatible = "fsl,anatop-regulator"; + regulator-name = "vdd2p5"; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2750000>; + regulator-always-on; + anatop-reg-offset = <0x130>; + anatop-vol-bit-shift = <8>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <0>; + anatop-min-voltage = <2000000>; + anatop-max-voltage = <2750000>; + }; + + regulator-vddcore@140 { + compatible = "fsl,anatop-regulator"; + regulator-name = "cpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; + regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <0>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; + }; + + regulator-vddpu@140 { + compatible = "fsl,anatop-regulator"; + regulator-name = "vddpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; + regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <9>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; + }; + + regulator-vddsoc@140 { + compatible = "fsl,anatop-regulator"; + regulator-name = "vddsoc"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; + regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <18>; + anatop-vol-bit-width = <5>; + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1450000>; + }; }; usbphy@020c9000 { /* USBPHY1 */ @@ -386,7 +482,62 @@ }; iomuxc@020e0000 { + compatible = "fsl,imx6q-iomuxc"; reg = <0x020e0000 0x4000>; + + /* shared pinctrl settings */ + audmux { + pinctrl_audmux_1: audmux-1 { + fsl,pins = <18 0x80000000 /* MX6Q_PAD_SD2_DAT0__AUDMUX_AUD4_RXD */ + 1586 0x80000000 /* MX6Q_PAD_SD2_DAT3__AUDMUX_AUD4_TXC */ + 11 0x80000000 /* MX6Q_PAD_SD2_DAT2__AUDMUX_AUD4_TXD */ + 3 0x80000000>; /* MX6Q_PAD_SD2_DAT1__AUDMUX_AUD4_TXFS */ + }; + }; + + i2c1 { + pinctrl_i2c1_1: i2c1grp-1 { + fsl,pins = <137 0x4001b8b1 /* MX6Q_PAD_EIM_D21__I2C1_SCL */ + 196 0x4001b8b1>; /* MX6Q_PAD_EIM_D28__I2C1_SDA */ + }; + }; + + serial2 { + pinctrl_serial2_1: serial2grp-1 { + fsl,pins = <183 0x1b0b1 /* MX6Q_PAD_EIM_D26__UART2_TXD */ + 191 0x1b0b1>; /* MX6Q_PAD_EIM_D27__UART2_RXD */ + }; + }; + + usdhc3 { + pinctrl_usdhc3_1: usdhc3grp-1 { + fsl,pins = <1273 0x17059 /* MX6Q_PAD_SD3_CMD__USDHC3_CMD */ + 1281 0x10059 /* MX6Q_PAD_SD3_CLK__USDHC3_CLK */ + 1289 0x17059 /* MX6Q_PAD_SD3_DAT0__USDHC3_DAT0 */ + 1297 0x17059 /* MX6Q_PAD_SD3_DAT1__USDHC3_DAT1 */ + 1305 0x17059 /* MX6Q_PAD_SD3_DAT2__USDHC3_DAT2 */ + 1312 0x17059 /* MX6Q_PAD_SD3_DAT3__USDHC3_DAT3 */ + 1265 0x17059 /* MX6Q_PAD_SD3_DAT4__USDHC3_DAT4 */ + 1257 0x17059 /* MX6Q_PAD_SD3_DAT5__USDHC3_DAT5 */ + 1249 0x17059 /* MX6Q_PAD_SD3_DAT6__USDHC3_DAT6 */ + 1241 0x17059>; /* MX6Q_PAD_SD3_DAT7__USDHC3_DAT7 */ + }; + }; + + usdhc4 { + pinctrl_usdhc4_1: usdhc4grp-1 { + fsl,pins = <1386 0x17059 /* MX6Q_PAD_SD4_CMD__USDHC4_CMD */ + 1392 0x10059 /* MX6Q_PAD_SD4_CLK__USDHC4_CLK */ + 1462 0x17059 /* MX6Q_PAD_SD4_DAT0__USDHC4_DAT0 */ + 1470 0x17059 /* MX6Q_PAD_SD4_DAT1__USDHC4_DAT1 */ + 1478 0x17059 /* MX6Q_PAD_SD4_DAT2__USDHC4_DAT2 */ + 1486 0x17059 /* MX6Q_PAD_SD4_DAT3__USDHC4_DAT3 */ + 1493 0x17059 /* MX6Q_PAD_SD4_DAT4__USDHC4_DAT4 */ + 1501 0x17059 /* MX6Q_PAD_SD4_DAT5__USDHC4_DAT5 */ + 1509 0x17059 /* MX6Q_PAD_SD4_DAT6__USDHC4_DAT6 */ + 1517 0x17059>; /* MX6Q_PAD_SD4_DAT7__USDHC4_DAT7 */ + }; + }; }; dcic@020e4000 { /* DCIC1 */ @@ -422,7 +573,7 @@ reg = <0x0217c000 0x4000>; }; - enet@02188000 { + ethernet@02188000 { compatible = "fsl,imx6q-fec"; reg = <0x02188000 0x4000>; interrupts = <0 118 0x04 0 119 0x04>; @@ -527,7 +678,9 @@ }; audmux@021d8000 { + compatible = "fsl,imx6q-audmux", "fsl,imx31-audmux"; reg = <0x021d8000 0x4000>; + status = "disabled"; }; mipi@021dc000 { /* MIPI-CSI */ @@ -543,28 +696,28 @@ interrupts = <0 18 0x04>; }; - uart2: uart@021e8000 { + uart2: serial@021e8000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021e8000 0x4000>; interrupts = <0 27 0x04>; status = "disabled"; }; - uart3: uart@021ec000 { + uart3: serial@021ec000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021ec000 0x4000>; interrupts = <0 28 0x04>; status = "disabled"; }; - uart4: uart@021f0000 { + uart4: serial@021f0000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f0000 0x4000>; interrupts = <0 29 0x04>; status = "disabled"; }; - uart5: uart@021f4000 { + uart5: serial@021f4000 { compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; reg = <0x021f4000 0x4000>; interrupts = <0 30 0x04>; 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/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts new file mode 100644 index 000000000000..8314e4171884 --- /dev/null +++ b/arch/arm/boot/dts/spear1310-evb.dts @@ -0,0 +1,292 @@ +/* + * DTS file for SPEAr1310 Evaluation Baord + * + * Copyright 2012 Viresh Kumar <viresh.kumar@st.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "spear1310.dtsi" + +/ { + model = "ST SPEAr1310 Evaluation Board"; + compatible = "st,spear1310-evb", "st,spear1310"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + reg = <0 0x40000000>; + }; + + ahb { + pinmux@e0700000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + i2c0-pmx { + st,pins = "i2c0_grp"; + st,function = "i2c0"; + }; + i2s1 { + st,pins = "i2s1_grp"; + st,function = "i2s1"; + }; + gpio { + st,pins = "arm_gpio_grp"; + st,function = "arm_gpio"; + }; + eth { + st,pins = "gmii_grp"; + st,function = "gmii"; + }; + ssp0 { + st,pins = "ssp0_grp"; + st,function = "ssp0"; + }; + kbd { + st,pins = "keyboard_6x6_grp"; + st,function = "keyboard"; + }; + sdhci { + st,pins = "sdhci_grp"; + st,function = "sdhci"; + }; + smi-pmx { + st,pins = "smi_2_chips_grp"; + st,function = "smi"; + }; + uart0 { + st,pins = "uart0_grp"; + st,function = "uart0"; + }; + rs485 { + st,pins = "rs485_0_1_tdm_0_1_grp"; + st,function = "rs485_0_1_tdm_0_1"; + }; + i2c1_2 { + st,pins = "i2c_1_2_grp"; + st,function = "i2c_1_2"; + }; + pci { + st,pins = "pcie0_grp","pcie1_grp", + "pcie2_grp"; + st,function = "pci"; + }; + smii { + st,pins = "smii_0_1_2_grp"; + st,function = "smii_0_1_2"; + }; + nand { + st,pins = "nand_8bit_grp", + "nand_16bit_grp"; + st,function = "nand"; + }; + }; + }; + + ahci@b1000000 { + status = "okay"; + }; + + cf@b2800000 { + status = "okay"; + }; + + dma@ea800000 { + status = "okay"; + }; + + dma@eb000000 { + status = "okay"; + }; + + fsmc: flash@b0000000 { + status = "okay"; + }; + + gmac0: eth@e2000000 { + status = "okay"; + }; + + sdhci@b3000000 { + status = "okay"; + }; + + smi: flash@ea000000 { + status = "okay"; + clock-rate=<50000000>; + + flash@e6000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe6000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; + }; + + spi0: spi@e0100000 { + status = "okay"; + }; + + ehci@e4800000 { + status = "okay"; + }; + + ehci@e5800000 { + status = "okay"; + }; + + ohci@e4000000 { + status = "okay"; + }; + + ohci@e5000000 { + status = "okay"; + }; + + apb { + adc@e0080000 { + status = "okay"; + }; + + gpio0: gpio@e0600000 { + status = "okay"; + }; + + gpio1: gpio@e0680000 { + status = "okay"; + }; + + i2c0: i2c@e0280000 { + status = "okay"; + }; + + i2c1: i2c@5cd00000 { + status = "okay"; + }; + + kbd@e0300000 { + linux,keymap = < 0x00000001 + 0x00010002 + 0x00020003 + 0x00030004 + 0x00040005 + 0x00050006 + 0x00060007 + 0x00070008 + 0x00080009 + 0x0100000a + 0x0101000c + 0x0102000d + 0x0103000e + 0x0104000f + 0x01050010 + 0x01060011 + 0x01070012 + 0x01080013 + 0x02000014 + 0x02010015 + 0x02020016 + 0x02030017 + 0x02040018 + 0x02050019 + 0x0206001a + 0x0207001b + 0x0208001c + 0x0300001d + 0x0301001e + 0x0302001f + 0x03030020 + 0x03040021 + 0x03050022 + 0x03060023 + 0x03070024 + 0x03080025 + 0x04000026 + 0x04010027 + 0x04020028 + 0x04030029 + 0x0404002a + 0x0405002b + 0x0406002c + 0x0407002d + 0x0408002e + 0x0500002f + 0x05010030 + 0x05020031 + 0x05030032 + 0x05040033 + 0x05050034 + 0x05060035 + 0x05070036 + 0x05080037 + 0x06000038 + 0x06010039 + 0x0602003a + 0x0603003b + 0x0604003c + 0x0605003d + 0x0606003e + 0x0607003f + 0x06080040 + 0x07000041 + 0x07010042 + 0x07020043 + 0x07030044 + 0x07040045 + 0x07050046 + 0x07060047 + 0x07070048 + 0x07080049 + 0x0800004a + 0x0801004b + 0x0802004c + 0x0803004d + 0x0804004e + 0x0805004f + 0x08060050 + 0x08070051 + 0x08080052 >; + autorepeat; + st,mode = <0>; + status = "okay"; + }; + + rtc@e0580000 { + status = "okay"; + }; + + serial@e0000000 { + status = "okay"; + }; + + wdt@ec800620 { + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi new file mode 100644 index 000000000000..9e61da404d57 --- /dev/null +++ b/arch/arm/boot/dts/spear1310.dtsi @@ -0,0 +1,184 @@ +/* + * DTS file for all SPEAr1310 SoCs + * + * Copyright 2012 Viresh Kumar <viresh.kumar@st.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "spear13xx.dtsi" + +/ { + compatible = "st,spear1310"; + + ahb { + ahci@b1000000 { + compatible = "snps,spear-ahci"; + reg = <0xb1000000 0x10000>; + interrupts = <0 68 0x4>; + status = "disabled"; + }; + + ahci@b1800000 { + compatible = "snps,spear-ahci"; + reg = <0xb1800000 0x10000>; + interrupts = <0 69 0x4>; + status = "disabled"; + }; + + ahci@b4000000 { + compatible = "snps,spear-ahci"; + reg = <0xb4000000 0x10000>; + interrupts = <0 70 0x4>; + status = "disabled"; + }; + + gmac1: eth@5c400000 { + compatible = "st,spear600-gmac"; + reg = <0x5c400000 0x8000>; + interrupts = <0 95 0x4>; + interrupt-names = "macirq"; + status = "disabled"; + }; + + gmac2: eth@5c500000 { + compatible = "st,spear600-gmac"; + reg = <0x5c500000 0x8000>; + interrupts = <0 96 0x4>; + interrupt-names = "macirq"; + status = "disabled"; + }; + + gmac3: eth@5c600000 { + compatible = "st,spear600-gmac"; + reg = <0x5c600000 0x8000>; + interrupts = <0 97 0x4>; + interrupt-names = "macirq"; + status = "disabled"; + }; + + gmac4: eth@5c700000 { + compatible = "st,spear600-gmac"; + reg = <0x5c700000 0x8000>; + interrupts = <0 98 0x4>; + interrupt-names = "macirq"; + status = "disabled"; + }; + + spi1: spi@5d400000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x5d400000 0x1000>; + interrupts = <0 99 0x4>; + status = "disabled"; + }; + + apb { + i2c1: i2c@5cd00000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x5cd00000 0x1000>; + interrupts = <0 87 0x4>; + status = "disabled"; + }; + + i2c2: i2c@5ce00000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x5ce00000 0x1000>; + interrupts = <0 88 0x4>; + status = "disabled"; + }; + + i2c3: i2c@5cf00000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x5cf00000 0x1000>; + interrupts = <0 89 0x4>; + status = "disabled"; + }; + + i2c4: i2c@5d000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x5d000000 0x1000>; + interrupts = <0 90 0x4>; + status = "disabled"; + }; + + i2c5: i2c@5d100000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x5d100000 0x1000>; + interrupts = <0 91 0x4>; + status = "disabled"; + }; + + i2c6: i2c@5d200000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x5d200000 0x1000>; + interrupts = <0 92 0x4>; + status = "disabled"; + }; + + i2c7: i2c@5d300000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x5d300000 0x1000>; + interrupts = <0 93 0x4>; + status = "disabled"; + }; + + serial@5c800000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x5c800000 0x1000>; + interrupts = <0 82 0x4>; + status = "disabled"; + }; + + serial@5c900000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x5c900000 0x1000>; + interrupts = <0 83 0x4>; + status = "disabled"; + }; + + serial@5ca00000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x5ca00000 0x1000>; + interrupts = <0 84 0x4>; + status = "disabled"; + }; + + serial@5cb00000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x5cb00000 0x1000>; + interrupts = <0 85 0x4>; + status = "disabled"; + }; + + serial@5cc00000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x5cc00000 0x1000>; + interrupts = <0 86 0x4>; + status = "disabled"; + }; + + thermal@e07008c4 { + st,thermal-flags = <0x7000>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts new file mode 100644 index 000000000000..0d8472e5ab9f --- /dev/null +++ b/arch/arm/boot/dts/spear1340-evb.dts @@ -0,0 +1,308 @@ +/* + * DTS file for SPEAr1340 Evaluation Baord + * + * Copyright 2012 Viresh Kumar <viresh.kumar@st.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "spear1340.dtsi" + +/ { + model = "ST SPEAr1340 Evaluation Board"; + compatible = "st,spear1340-evb", "st,spear1340"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + reg = <0 0x40000000>; + }; + + ahb { + pinmux@e0700000 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + pads_as_gpio { + st,pins = "pads_as_gpio_grp"; + st,function = "pads_as_gpio"; + }; + fsmc { + st,pins = "fsmc_8bit_grp"; + st,function = "fsmc"; + }; + kbd { + st,pins = "keyboard_row_col_grp", + "keyboard_col5_grp"; + st,function = "keyboard"; + }; + uart0 { + st,pins = "uart0_grp", "uart0_enh_grp"; + st,function = "uart0"; + }; + i2c0-pmx { + st,pins = "i2c0_grp"; + st,function = "i2c0"; + }; + i2c1-pmx { + st,pins = "i2c1_grp"; + st,function = "i2c1"; + }; + spdif-in { + st,pins = "spdif_in_grp"; + st,function = "spdif_in"; + }; + spdif-out { + st,pins = "spdif_out_grp"; + st,function = "spdif_out"; + }; + ssp0 { + st,pins = "ssp0_grp", "ssp0_cs1_grp", + "ssp0_cs3_grp"; + st,function = "ssp0"; + }; + pwm { + st,pins = "pwm2_grp", "pwm3_grp"; + st,function = "pwm"; + }; + smi-pmx { + st,pins = "smi_grp"; + st,function = "smi"; + }; + i2s { + st,pins = "i2s_in_grp", "i2s_out_grp"; + st,function = "i2s"; + }; + gmac { + st,pins = "gmii_grp", "rgmii_grp"; + st,function = "gmac"; + }; + cam3 { + st,pins = "cam3_grp"; + st,function = "cam3"; + }; + cec0 { + st,pins = "cec0_grp"; + st,function = "cec0"; + }; + cec1 { + st,pins = "cec1_grp"; + st,function = "cec1"; + }; + sdhci { + st,pins = "sdhci_grp"; + st,function = "sdhci"; + }; + clcd { + st,pins = "clcd_grp"; + st,function = "clcd"; + }; + sata { + st,pins = "sata_grp"; + st,function = "sata"; + }; + }; + }; + + dma@ea800000 { + status = "okay"; + }; + + dma@eb000000 { + status = "okay"; + }; + + fsmc: flash@b0000000 { + status = "okay"; + }; + + gmac0: eth@e2000000 { + status = "okay"; + }; + + sdhci@b3000000 { + status = "okay"; + }; + + smi: flash@ea000000 { + status = "okay"; + clock-rate=<50000000>; + + flash@e6000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xe6000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; + }; + + spi0: spi@e0100000 { + status = "okay"; + }; + + ehci@e4800000 { + status = "okay"; + }; + + ehci@e5800000 { + status = "okay"; + }; + + ohci@e4000000 { + status = "okay"; + }; + + ohci@e5000000 { + status = "okay"; + }; + + apb { + adc@e0080000 { + status = "okay"; + }; + + gpio0: gpio@e0600000 { + status = "okay"; + }; + + gpio1: gpio@e0680000 { + status = "okay"; + }; + + i2c0: i2c@e0280000 { + status = "okay"; + }; + + i2c1: i2c@b4000000 { + status = "okay"; + }; + + kbd@e0300000 { + linux,keymap = < 0x00000001 + 0x00010002 + 0x00020003 + 0x00030004 + 0x00040005 + 0x00050006 + 0x00060007 + 0x00070008 + 0x00080009 + 0x0100000a + 0x0101000c + 0x0102000d + 0x0103000e + 0x0104000f + 0x01050010 + 0x01060011 + 0x01070012 + 0x01080013 + 0x02000014 + 0x02010015 + 0x02020016 + 0x02030017 + 0x02040018 + 0x02050019 + 0x0206001a + 0x0207001b + 0x0208001c + 0x0300001d + 0x0301001e + 0x0302001f + 0x03030020 + 0x03040021 + 0x03050022 + 0x03060023 + 0x03070024 + 0x03080025 + 0x04000026 + 0x04010027 + 0x04020028 + 0x04030029 + 0x0404002a + 0x0405002b + 0x0406002c + 0x0407002d + 0x0408002e + 0x0500002f + 0x05010030 + 0x05020031 + 0x05030032 + 0x05040033 + 0x05050034 + 0x05060035 + 0x05070036 + 0x05080037 + 0x06000038 + 0x06010039 + 0x0602003a + 0x0603003b + 0x0604003c + 0x0605003d + 0x0606003e + 0x0607003f + 0x06080040 + 0x07000041 + 0x07010042 + 0x07020043 + 0x07030044 + 0x07040045 + 0x07050046 + 0x07060047 + 0x07070048 + 0x07080049 + 0x0800004a + 0x0801004b + 0x0802004c + 0x0803004d + 0x0804004e + 0x0805004f + 0x08060050 + 0x08070051 + 0x08080052 >; + autorepeat; + st,mode = <0>; + status = "okay"; + }; + + rtc@e0580000 { + status = "okay"; + }; + + serial@e0000000 { + status = "okay"; + }; + + serial@b4100000 { + status = "okay"; + }; + + wdt@ec800620 { + status = "okay"; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi new file mode 100644 index 000000000000..a26fc47a55e8 --- /dev/null +++ b/arch/arm/boot/dts/spear1340.dtsi @@ -0,0 +1,56 @@ +/* + * DTS file for all SPEAr1340 SoCs + * + * Copyright 2012 Viresh Kumar <viresh.kumar@st.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "spear13xx.dtsi" + +/ { + compatible = "st,spear1340"; + + ahb { + ahci@b1000000 { + compatible = "snps,spear-ahci"; + reg = <0xb1000000 0x10000>; + interrupts = <0 72 0x4>; + status = "disabled"; + }; + + spi1: spi@5d400000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0x5d400000 0x1000>; + interrupts = <0 99 0x4>; + status = "disabled"; + }; + + apb { + i2c1: i2c@b4000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0xb4000000 0x1000>; + interrupts = <0 104 0x4>; + status = "disabled"; + }; + + serial@b4100000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xb4100000 0x1000>; + interrupts = <0 105 0x4>; + status = "disabled"; + }; + + thermal@e07008c4 { + st,thermal-flags = <0x2a00>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi new file mode 100644 index 000000000000..1f8e1e1481df --- /dev/null +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -0,0 +1,262 @@ +/* + * DTS file for all SPEAr13xx SoCs + * + * Copyright 2012 Viresh Kumar <viresh.kumar@st.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/include/ "skeleton.dtsi" + +/ { + interrupt-parent = <&gic>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + }; + }; + + gic: interrupt-controller@ec801000 { + compatible = "arm,cortex-a9-gic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = < 0xec801000 0x1000 >, + < 0xec800100 0x0100 >; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 8 0x04 + 0 9 0x04>; + }; + + L2: l2-cache { + compatible = "arm,pl310-cache"; + reg = <0xed000000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + memory { + name = "memory"; + device_type = "memory"; + reg = <0 0x40000000>; + }; + + chosen { + bootargs = "console=ttyAMA0,115200"; + }; + + ahb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x50000000 0x50000000 0x10000000 + 0xb0000000 0xb0000000 0x10000000 + 0xe0000000 0xe0000000 0x10000000>; + + sdhci@b3000000 { + compatible = "st,sdhci-spear"; + reg = <0xb3000000 0x100>; + interrupts = <0 28 0x4>; + status = "disabled"; + }; + + cf@b2800000 { + compatible = "arasan,cf-spear1340"; + reg = <0xb2800000 0x100>; + interrupts = <0 29 0x4>; + status = "disabled"; + }; + + dma@ea800000 { + compatible = "snps,dma-spear1340"; + reg = <0xea800000 0x1000>; + interrupts = <0 19 0x4>; + status = "disabled"; + }; + + dma@eb000000 { + compatible = "snps,dma-spear1340"; + reg = <0xeb000000 0x1000>; + interrupts = <0 59 0x4>; + status = "disabled"; + }; + + fsmc: flash@b0000000 { + compatible = "st,spear600-fsmc-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xb0000000 0x1000 /* FSMC Register */ + 0xb0800000 0x0010>; /* NAND Base */ + reg-names = "fsmc_regs", "nand_data"; + interrupts = <0 20 0x4 + 0 21 0x4 + 0 22 0x4 + 0 23 0x4>; + st,ale-off = <0x20000>; + st,cle-off = <0x10000>; + status = "disabled"; + }; + + gmac0: eth@e2000000 { + compatible = "st,spear600-gmac"; + reg = <0xe2000000 0x8000>; + interrupts = <0 23 0x4 + 0 24 0x4>; + interrupt-names = "macirq", "eth_wake_irq"; + status = "disabled"; + }; + + smi: flash@ea000000 { + compatible = "st,spear600-smi"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xea000000 0x1000>; + interrupts = <0 30 0x4>; + status = "disabled"; + }; + + spi0: spi@e0100000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0xe0100000 0x1000>; + interrupts = <0 31 0x4>; + status = "disabled"; + }; + + ehci@e4800000 { + compatible = "st,spear600-ehci", "usb-ehci"; + reg = <0xe4800000 0x1000>; + interrupts = <0 64 0x4>; + status = "disabled"; + }; + + ehci@e5800000 { + compatible = "st,spear600-ehci", "usb-ehci"; + reg = <0xe5800000 0x1000>; + interrupts = <0 66 0x4>; + status = "disabled"; + }; + + ohci@e4000000 { + compatible = "st,spear600-ohci", "usb-ohci"; + reg = <0xe4000000 0x1000>; + interrupts = <0 65 0x4>; + status = "disabled"; + }; + + ohci@e5000000 { + compatible = "st,spear600-ohci", "usb-ohci"; + reg = <0xe5000000 0x1000>; + interrupts = <0 67 0x4>; + status = "disabled"; + }; + + apb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x50000000 0x50000000 0x10000000 + 0xb0000000 0xb0000000 0x10000000 + 0xe0000000 0xe0000000 0x10000000>; + + gpio0: gpio@e0600000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0xe0600000 0x1000>; + interrupts = <0 24 0x4>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + status = "disabled"; + }; + + gpio1: gpio@e0680000 { + compatible = "arm,pl061", "arm,primecell"; + reg = <0xe0680000 0x1000>; + interrupts = <0 25 0x4>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + status = "disabled"; + }; + + kbd@e0300000 { + compatible = "st,spear300-kbd"; + reg = <0xe0300000 0x1000>; + status = "disabled"; + }; + + i2c0: i2c@e0280000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0xe0280000 0x1000>; + interrupts = <0 41 0x4>; + status = "disabled"; + }; + + rtc@e0580000 { + compatible = "st,spear-rtc"; + reg = <0xe0580000 0x1000>; + interrupts = <0 36 0x4>; + status = "disabled"; + }; + + serial@e0000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xe0000000 0x1000>; + interrupts = <0 36 0x4>; + status = "disabled"; + }; + + adc@e0080000 { + compatible = "st,spear600-adc"; + reg = <0xe0080000 0x1000>; + interrupts = <0 44 0x4>; + status = "disabled"; + }; + + timer@e0380000 { + compatible = "st,spear-timer"; + reg = <0xe0380000 0x400>; + interrupts = <0 37 0x4>; + }; + + timer@ec800600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xec800600 0x20>; + interrupts = <1 13 0x301>; + }; + + wdt@ec800620 { + compatible = "arm,cortex-a9-twd-wdt"; + reg = <0xec800620 0x20>; + status = "disabled"; + }; + + thermal@e07008c4 { + compatible = "st,thermal-spear1340"; + reg = <0xe07008c4 0x4>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/spear300-evb.dts b/arch/arm/boot/dts/spear300-evb.dts index 910e264b87c0..fc82b1a26458 100644 --- a/arch/arm/boot/dts/spear300-evb.dts +++ b/arch/arm/boot/dts/spear300-evb.dts @@ -87,6 +87,31 @@ smi: flash@fc000000 { status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; }; spi0: spi@d0100000 { diff --git a/arch/arm/boot/dts/spear310-evb.dts b/arch/arm/boot/dts/spear310-evb.dts index 6d95317100ad..dc5e2d445a93 100644 --- a/arch/arm/boot/dts/spear310-evb.dts +++ b/arch/arm/boot/dts/spear310-evb.dts @@ -103,11 +103,27 @@ clock-rate=<50000000>; flash@f8000000 { - label = "m25p64"; - reg = <0xf8000000 0x800000>; #address-cells = <1>; #size-cells = <1>; + reg = <0xf8000000 0x800000>; st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; }; }; diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts index 0c6463b71a37..6308fa3bec1e 100644 --- a/arch/arm/boot/dts/spear320-evb.dts +++ b/arch/arm/boot/dts/spear320-evb.dts @@ -110,6 +110,31 @@ smi: flash@fc000000 { status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; }; spi0: spi@d0100000 { diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi index 0ae7c8e86311..91072553963f 100644 --- a/arch/arm/boot/dts/spear3xx.dtsi +++ b/arch/arm/boot/dts/spear3xx.dtsi @@ -139,6 +139,12 @@ interrupts = <12>; status = "disabled"; }; + + timer@f0000000 { + compatible = "st,spear-timer"; + reg = <0xf0000000 0x400>; + interrupts = <2>; + }; }; }; }; diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts index 790a7a8a5ccd..1119c22c9a82 100644 --- a/arch/arm/boot/dts/spear600-evb.dts +++ b/arch/arm/boot/dts/spear600-evb.dts @@ -33,6 +33,35 @@ status = "okay"; }; + smi: flash@fc000000 { + status = "okay"; + clock-rate=<50000000>; + + flash@f8000000 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf8000000 0x800000>; + st,smi-fast-mode; + + partition@0 { + label = "xloader"; + reg = <0x0 0x10000>; + }; + partition@10000 { + label = "u-boot"; + reg = <0x10000 0x40000>; + }; + partition@50000 { + label = "linux"; + reg = <0x50000 0x2c0000>; + }; + partition@310000 { + label = "rootfs"; + reg = <0x310000 0x4f0000>; + }; + }; + }; + apb { serial@d0000000 { status = "okay"; diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi index d777e3a6f178..089f0a42c50e 100644 --- a/arch/arm/boot/dts/spear600.dtsi +++ b/arch/arm/boot/dts/spear600.dtsi @@ -177,6 +177,12 @@ interrupts = <28>; status = "disabled"; }; + + timer@f0000000 { + compatible = "st,spear-timer"; + reg = <0xf0000000 0x400>; + interrupts = <16>; + }; }; }; }; diff --git a/arch/arm/boot/dts/tegra-cardhu.dts b/arch/arm/boot/dts/tegra-cardhu.dts index 0a9f34a2c3aa..36321bceec46 100644 --- a/arch/arm/boot/dts/tegra-cardhu.dts +++ b/arch/arm/boot/dts/tegra-cardhu.dts @@ -7,10 +7,10 @@ compatible = "nvidia,cardhu", "nvidia,tegra30"; memory { - reg = < 0x80000000 0x40000000 >; + reg = <0x80000000 0x40000000>; }; - pinmux@70000000 { + pinmux { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -51,64 +51,122 @@ 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>; + }; }; }; serial@70006000 { - clock-frequency = < 408000000 >; - }; - - serial@70006040 { - status = "disable"; - }; - - serial@70006200 { - status = "disable"; - }; - - serial@70006300 { - status = "disable"; - }; - - serial@70006400 { - status = "disable"; + status = "okay"; + clock-frequency = <408000000>; }; i2c@7000c000 { + status = "okay"; clock-frequency = <100000>; }; i2c@7000c400 { + status = "okay"; clock-frequency = <100000>; }; i2c@7000c500 { + status = "okay"; clock-frequency = <100000>; + + /* ALS and Proximity sensor */ + isl29028@44 { + compatible = "isil,isl29028"; + reg = <0x44>; + interrupt-parent = <&gpio>; + interrupts = <88 0x04>; /*gpio PL0 */ + }; }; i2c@7000c700 { + status = "okay"; clock-frequency = <100000>; }; i2c@7000d000 { + status = "okay"; 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>; + }; + + tps62361 { + compatible = "ti,tps62361"; + reg = <0x60>; + + regulator-name = "tps62361-vout"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + ti,vsel0-state-high; + ti,vsel1-state-high; + }; + }; + + ahub { + i2s@70080400 { + status = "okay"; + }; }; sdhci@78000000 { + status = "okay"; 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 { - status = "disable"; + sdhci@78000600 { + status = "okay"; + support-8bit; + bus-width = <8>; }; - sdhci@78000400 { - status = "disable"; - }; + sound { + compatible = "nvidia,tegra-audio-wm8903-cardhu", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Cardhu"; - sdhci@78000400 { - support-8bit; + 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..7de701365fce 100644 --- a/arch/arm/boot/dts/tegra-harmony.dts +++ b/arch/arm/boot/dts/tegra-harmony.dts @@ -6,11 +6,11 @@ model = "NVIDIA Tegra2 Harmony evaluation board"; compatible = "nvidia,harmony", "nvidia,tegra20"; - memory@0 { - reg = < 0x00000000 0x40000000 >; + memory { + reg = <0x00000000 0x40000000>; }; - pinmux@70000000 { + pinmux { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -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>; }; @@ -234,42 +234,81 @@ }; }; - pmc@7000f400 { - nvidia,invert-interrupt; + i2s@70002800 { + status = "okay"; + }; + + serial@70006300 { + status = "okay"; + clock-frequency = <216000000>; }; i2c@7000c000 { + status = "okay"; clock-frequency = <400000>; wm8903: wm8903@1a { compatible = "wlf,wm8903"; reg = <0x1a>; interrupt-parent = <&gpio>; - interrupts = < 187 0x04 >; + interrupts = <187 0x04>; gpio-controller; #gpio-cells = <2>; micdet-cfg = <0>; micdet-delay = <100>; - gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; + gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>; }; }; i2c@7000c400 { + status = "okay"; clock-frequency = <400000>; }; i2c@7000c500 { + status = "okay"; clock-frequency = <400000>; }; i2c@7000d000 { + status = "okay"; clock-frequency = <400000>; }; - i2s@70002a00 { - status = "disable"; + pmc { + nvidia,invert-interrupt; + }; + + usb@c5000000 { + status = "okay"; + }; + + usb@c5004000 { + status = "okay"; + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ + }; + + usb@c5008000 { + status = "okay"; + }; + + sdhci@c8000200 { + status = "okay"; + 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@c8000600 { + status = "okay"; + cd-gpios = <&gpio 58 0>; /* gpio PH2 */ + wp-gpios = <&gpio 59 0>; /* gpio PH3 */ + power-gpios = <&gpio 70 0>; /* gpio PI6 */ + support-8bit; + bus-width = <8>; }; sound { @@ -295,45 +334,4 @@ nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ }; - - serial@70006000 { - status = "disable"; - }; - - serial@70006040 { - status = "disable"; - }; - - serial@70006200 { - status = "disable"; - }; - - serial@70006300 { - clock-frequency = < 216000000 >; - }; - - serial@70006400 { - status = "disable"; - }; - - sdhci@c8000000 { - status = "disable"; - }; - - sdhci@c8000200 { - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ - wp-gpios = <&gpio 57 0>; /* gpio PH1 */ - power-gpios = <&gpio 155 0>; /* gpio PT3 */ - }; - - sdhci@c8000400 { - status = "disable"; - }; - - sdhci@c8000600 { - cd-gpios = <&gpio 58 0>; /* gpio PH2 */ - wp-gpios = <&gpio 59 0>; /* gpio PH3 */ - power-gpios = <&gpio 70 0>; /* gpio PI6 */ - support-8bit; - }; }; diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index 10943fb2561c..bfeb117d5aea 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts @@ -6,11 +6,11 @@ model = "Toshiba AC100 / Dynabook AZ"; compatible = "compal,paz00", "nvidia,tegra20"; - memory@0 { + memory { reg = <0x00000000 0x20000000>; }; - pinmux@70000000 { + pinmux { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -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"; @@ -230,7 +226,22 @@ }; }; + i2s@70002800 { + status = "okay"; + }; + + serial@70006000 { + status = "okay"; + clock-frequency = <216000000>; + }; + + serial@70006200 { + status = "okay"; + clock-frequency = <216000000>; + }; + i2c@7000c000 { + status = "okay"; clock-frequency = <400000>; alc5632: alc5632@1e { @@ -242,25 +253,23 @@ }; i2c@7000c400 { + status = "okay"; clock-frequency = <400000>; }; - i2c@7000c500 { - status = "disable"; - }; - - nvec@7000c500 { - #address-cells = <1>; - #size-cells = <0>; + nvec { compatible = "nvidia,nvec"; - reg = <0x7000C500 0x100>; + reg = <0x7000c500 0x100>; interrupts = <0 92 0x04>; + #address-cells = <1>; + #size-cells = <0>; clock-frequency = <80000>; - request-gpios = <&gpio 170 0>; + request-gpios = <&gpio 170 0>; /* gpio PV2 */ slave-addr = <138>; }; i2c@7000d000 { + status = "okay"; clock-frequency = <400000>; adt7461@4c { @@ -269,66 +278,31 @@ }; }; - i2s@70002a00 { - status = "disable"; - }; - - sound { - compatible = "nvidia,tegra-audio-alc5632-paz00", - "nvidia,tegra-audio-alc5632"; - - nvidia,model = "Compal PAZ00"; - - nvidia,audio-routing = - "Int Spk", "SPKOUT", - "Int Spk", "SPKOUTN", - "Headset Mic", "MICBIAS1", - "MIC1", "Headset Mic", - "Headset Stereophone", "HPR", - "Headset Stereophone", "HPL", - "DMICDAT", "Digital Mic"; - - nvidia,audio-codec = <&alc5632>; - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ - }; - - serial@70006000 { - clock-frequency = <216000000>; + usb@c5000000 { + status = "okay"; }; - serial@70006040 { - status = "disable"; + usb@c5004000 { + status = "okay"; + nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ }; - serial@70006200 { - clock-frequency = <216000000>; - }; - - serial@70006300 { - status = "disable"; - }; - - serial@70006400 { - status = "disable"; + usb@c5008000 { + status = "okay"; }; sdhci@c8000000 { + status = "okay"; cd-gpios = <&gpio 173 0>; /* gpio PV5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 169 0>; /* gpio PV1 */ - }; - - sdhci@c8000200 { - status = "disable"; - }; - - sdhci@c8000400 { - status = "disable"; + bus-width = <4>; }; sdhci@c8000600 { + status = "okay"; support-8bit; + bus-width = <8>; }; gpio-keys { @@ -347,8 +321,28 @@ wifi { label = "wifi-led"; - gpios = <&gpio 24 0>; + gpios = <&gpio 24 0>; /* gpio PD0 */ linux,default-trigger = "rfkill0"; }; }; + + sound { + compatible = "nvidia,tegra-audio-alc5632-paz00", + "nvidia,tegra-audio-alc5632"; + + nvidia,model = "Compal PAZ00"; + + nvidia,audio-routing = + "Int Spk", "SPKOUT", + "Int Spk", "SPKOUTN", + "Headset Mic", "MICBIAS1", + "MIC1", "Headset Mic", + "Headset Stereophone", "HPR", + "Headset Stereophone", "HPL", + "DMICDAT", "Digital Mic"; + + nvidia,audio-codec = <&alc5632>; + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + }; }; diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index ec33116f5df9..89cb7f2acd92 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -7,11 +7,10 @@ compatible = "nvidia,seaboard", "nvidia,tegra20"; memory { - device_type = "memory"; - reg = < 0x00000000 0x40000000 >; + reg = <0x00000000 0x40000000>; }; - pinmux@70000000 { + pinmux { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -100,7 +99,7 @@ }; hdint { nvidia,pins = "hdint", "lpw0", "lpw2", "lsc1", - "lsck", "lsda", "pta"; + "lsck", "lsda"; nvidia,function = "hdmi"; }; i2cp { @@ -134,6 +133,10 @@ nvidia,pins = "pmc"; nvidia,function = "pwr_on"; }; + pta { + nvidia,pins = "pta"; + nvidia,function = "i2c2"; + }; rm { nvidia,pins = "rm"; nvidia,function = "i2c1"; @@ -254,108 +257,148 @@ }; }; + i2s@70002800 { + status = "okay"; + }; + + serial@70006300 { + status = "okay"; + clock-frequency = <216000000>; + }; + i2c@7000c000 { + status = "okay"; clock-frequency = <400000>; wm8903: wm8903@1a { compatible = "wlf,wm8903"; reg = <0x1a>; interrupt-parent = <&gpio>; - interrupts = < 187 0x04 >; + interrupts = <187 0x04>; gpio-controller; #gpio-cells = <2>; micdet-cfg = <0>; micdet-delay = <100>; - gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; + gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>; + }; + + /* ALS and proximity sensor */ + isl29018@44 { + compatible = "isil,isl29018"; + reg = <0x44>; + interrupt-parent = <&gpio>; + interrupts = <202 0x04>; /* GPIO PZ2 */ + }; + + gyrometer@68 { + compatible = "invn,mpu3050"; + reg = <0x68>; + interrupt-parent = <&gpio>; + interrupts = <204 0x04>; /* gpio PZ4 */ }; }; i2c@7000c400 { - clock-frequency = <400000>; + status = "okay"; + clock-frequency = <100000>; + + smart-battery@b { + compatible = "ti,bq20z75", "smart-battery-1.1"; + reg = <0xb>; + ti,i2c-retry-count = <2>; + ti,poll-retry-count = <10>; + }; }; i2c@7000c500 { + status = "okay"; clock-frequency = <400000>; }; i2c@7000d000 { + status = "okay"; clock-frequency = <400000>; - adt7461@4c { - compatible = "adt7461"; + temperature-sensor@4c { + compatible = "nct1008"; reg = <0x4c>; }; - }; - - i2s@70002a00 { - status = "disable"; - }; - - sound { - compatible = "nvidia,tegra-audio-wm8903-seaboard", - "nvidia,tegra-audio-wm8903"; - nvidia,model = "NVIDIA Tegra Seaboard"; - - nvidia,audio-routing = - "Headphone Jack", "HPOUTR", - "Headphone Jack", "HPOUTL", - "Int Spk", "ROP", - "Int Spk", "RON", - "Int Spk", "LOP", - "Int Spk", "LON", - "Mic Jack", "MICBIAS", - "IN1R", "Mic Jack"; - - nvidia,i2s-controller = <&tegra_i2s1>; - nvidia,audio-codec = <&wm8903>; - - nvidia,spkr-en-gpios = <&wm8903 2 0>; - nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */ - }; - serial@70006000 { - status = "disable"; - }; - - serial@70006040 { - status = "disable"; + magnetometer@c { + compatible = "ak8975"; + reg = <0xc>; + interrupt-parent = <&gpio>; + interrupts = <109 0x04>; /* gpio PN5 */ + }; }; - serial@70006200 { - status = "disable"; - }; + emc { + emc-table@190000 { + reg = <190000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = <190000>; + nvidia,emc-registers = <0x0000000c 0x00000026 + 0x00000009 0x00000003 0x00000004 0x00000004 + 0x00000002 0x0000000c 0x00000003 0x00000003 + 0x00000002 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x0000059f + 0x00000000 0x00000003 0x00000003 0x00000003 + 0x00000003 0x00000001 0x0000000b 0x000000c8 + 0x00000003 0x00000007 0x00000004 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xa06204ae + 0x007dc010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000>; + }; - serial@70006300 { - clock-frequency = < 216000000 >; + emc-table@380000 { + reg = <380000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = <380000>; + nvidia,emc-registers = <0x00000017 0x0000004b + 0x00000012 0x00000006 0x00000004 0x00000005 + 0x00000003 0x0000000c 0x00000006 0x00000006 + 0x00000003 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x00000b5f + 0x00000000 0x00000003 0x00000003 0x00000006 + 0x00000006 0x00000001 0x00000011 0x000000c8 + 0x00000003 0x0000000e 0x00000007 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xe044048b + 0x007d8010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000>; + }; }; - serial@70006400 { - status = "disable"; + usb@c5000000 { + status = "okay"; + nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */ + dr_mode = "otg"; }; - sdhci@c8000000 { - status = "disable"; + usb@c5004000 { + status = "okay"; + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ }; - sdhci@c8000200 { - status = "disable"; + usb@c5008000 { + status = "okay"; }; sdhci@c8000400 { + status = "okay"; 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 { + status = "okay"; support-8bit; - }; - - usb@c5000000 { - nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */ - dr_mode = "otg"; + bus-width = <8>; }; gpio-keys { @@ -378,41 +421,25 @@ }; }; - emc@7000f400 { - emc-table@190000 { - reg = < 190000 >; - compatible = "nvidia,tegra20-emc-table"; - clock-frequency = < 190000 >; - nvidia,emc-registers = < 0x0000000c 0x00000026 - 0x00000009 0x00000003 0x00000004 0x00000004 - 0x00000002 0x0000000c 0x00000003 0x00000003 - 0x00000002 0x00000001 0x00000004 0x00000005 - 0x00000004 0x00000009 0x0000000d 0x0000059f - 0x00000000 0x00000003 0x00000003 0x00000003 - 0x00000003 0x00000001 0x0000000b 0x000000c8 - 0x00000003 0x00000007 0x00000004 0x0000000f - 0x00000002 0x00000000 0x00000000 0x00000002 - 0x00000000 0x00000000 0x00000083 0xa06204ae - 0x007dc010 0x00000000 0x00000000 0x00000000 - 0x00000000 0x00000000 0x00000000 0x00000000 >; - }; + sound { + compatible = "nvidia,tegra-audio-wm8903-seaboard", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Seaboard"; - emc-table@380000 { - reg = < 380000 >; - compatible = "nvidia,tegra20-emc-table"; - clock-frequency = < 380000 >; - nvidia,emc-registers = < 0x00000017 0x0000004b - 0x00000012 0x00000006 0x00000004 0x00000005 - 0x00000003 0x0000000c 0x00000006 0x00000006 - 0x00000003 0x00000001 0x00000004 0x00000005 - 0x00000004 0x00000009 0x0000000d 0x00000b5f - 0x00000000 0x00000003 0x00000003 0x00000006 - 0x00000006 0x00000001 0x00000011 0x000000c8 - 0x00000003 0x0000000e 0x00000007 0x0000000f - 0x00000002 0x00000000 0x00000000 0x00000002 - 0x00000000 0x00000000 0x00000083 0xe044048b - 0x007d8010 0x00000000 0x00000000 0x00000000 - 0x00000000 0x00000000 0x00000000 0x00000000 >; - }; + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1R", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */ }; }; diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts index 98efd5b0d7f9..9de5636023f6 100644 --- a/arch/arm/boot/dts/tegra-trimslice.dts +++ b/arch/arm/boot/dts/tegra-trimslice.dts @@ -6,11 +6,11 @@ model = "Compulab TrimSlice board"; compatible = "compulab,trimslice", "nvidia,tegra20"; - memory@0 { - reg = < 0x00000000 0x40000000 >; + memory { + reg = <0x00000000 0x40000000>; }; - pinmux@70000000 { + pinmux { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -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>; @@ -240,68 +240,67 @@ }; }; + i2s@70002800 { + status = "okay"; + }; + + serial@70006000 { + status = "okay"; + clock-frequency = <216000000>; + }; + i2c@7000c000 { + status = "okay"; clock-frequency = <400000>; }; i2c@7000c400 { + status = "okay"; clock-frequency = <400000>; }; i2c@7000c500 { + status = "okay"; clock-frequency = <400000>; - }; - - i2c@7000d000 { - status = "disable"; - }; - - i2s@70002800 { - status = "disable"; - }; - - i2s@70002a00 { - status = "disable"; - }; - - das@70000c00 { - status = "disable"; - }; - serial@70006000 { - clock-frequency = < 216000000 >; - }; + codec: codec@1a { + compatible = "ti,tlv320aic23"; + reg = <0x1a>; + }; - serial@70006040 { - status = "disable"; + rtc@56 { + compatible = "emmicro,em3027"; + reg = <0x56>; + }; }; - serial@70006200 { - status = "disable"; + usb@c5000000 { + status = "okay"; }; - serial@70006300 { - status = "disable"; + usb@c5004000 { + nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ }; - serial@70006400 { - status = "disable"; + usb@c5008000 { + status = "okay"; }; sdhci@c8000000 { - status = "disable"; + status = "okay"; + bus-width = <4>; }; - sdhci@c8000200 { - status = "disable"; - }; - - sdhci@c8000400 { - status = "disable"; + sdhci@c8000600 { + status = "okay"; + cd-gpios = <&gpio 121 0>; /* gpio PP1 */ + wp-gpios = <&gpio 122 0>; /* gpio PP2 */ + bus-width = <4>; }; - sdhci@c8000600 { - cd-gpios = <&gpio 121 0>; - wp-gpios = <&gpio 122 0>; + sound { + compatible = "nvidia,tegra-audio-trimslice"; + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&codec>; }; }; diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts index 71eb2e50a668..445343b0fbdd 100644 --- a/arch/arm/boot/dts/tegra-ventana.dts +++ b/arch/arm/boot/dts/tegra-ventana.dts @@ -7,10 +7,10 @@ compatible = "nvidia,ventana", "nvidia,tegra20"; memory { - reg = < 0x00000000 0x40000000 >; + reg = <0x00000000 0x40000000>; }; - pinmux@70000000 { + pinmux { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -240,38 +240,82 @@ }; }; + i2s@70002800 { + status = "okay"; + }; + + serial@70006300 { + status = "okay"; + clock-frequency = <216000000>; + }; + i2c@7000c000 { + status = "okay"; clock-frequency = <400000>; wm8903: wm8903@1a { compatible = "wlf,wm8903"; reg = <0x1a>; interrupt-parent = <&gpio>; - interrupts = < 187 0x04 >; + interrupts = <187 0x04>; gpio-controller; #gpio-cells = <2>; micdet-cfg = <0>; micdet-delay = <100>; - gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >; + gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>; + }; + + /* ALS and proximity sensor */ + isl29018@44 { + compatible = "isil,isl29018"; + reg = <0x44>; + interrupt-parent = <&gpio>; + interrupts = <202 0x04>; /*gpio PZ2 */ }; }; i2c@7000c400 { + status = "okay"; clock-frequency = <400000>; }; i2c@7000c500 { + status = "okay"; clock-frequency = <400000>; }; i2c@7000d000 { + status = "okay"; clock-frequency = <400000>; }; - i2s@70002a00 { - status = "disable"; + usb@c5000000 { + status = "okay"; + }; + + usb@c5004000 { + status = "okay"; + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ + }; + + usb@c5008000 { + status = "okay"; + }; + + sdhci@c8000400 { + status = "okay"; + 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 { + status = "okay"; + support-8bit; + bus-width = <8>; }; sound { @@ -294,45 +338,7 @@ nvidia,spkr-en-gpios = <&wm8903 2 0>; nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ - nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /* gpio PX0 */ nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ }; - - serial@70006000 { - status = "disable"; - }; - - serial@70006040 { - status = "disable"; - }; - - serial@70006200 { - status = "disable"; - }; - - serial@70006300 { - clock-frequency = < 216000000 >; - }; - - serial@70006400 { - status = "disable"; - }; - - sdhci@c8000000 { - status = "disable"; - }; - - sdhci@c8000200 { - status = "disable"; - }; - - sdhci@c8000400 { - cd-gpios = <&gpio 69 0>; /* gpio PI5 */ - wp-gpios = <&gpio 57 0>; /* gpio PH1 */ - power-gpios = <&gpio 70 0>; /* gpio PI6 */ - }; - - sdhci@c8000600 { - support-8bit; - }; }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 108e894a8926..c417d67e9027 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -4,207 +4,242 @@ compatible = "nvidia,tegra20"; interrupt-parent = <&intc>; - pmc@7000f400 { - compatible = "nvidia,tegra20-pmc"; - reg = <0x7000e400 0x400>; - }; - - intc: interrupt-controller@50041000 { + intc: interrupt-controller { compatible = "arm,cortex-a9-gic"; + reg = <0x50041000 0x1000 + 0x50040100 0x0100>; interrupt-controller; #interrupt-cells = <3>; - reg = < 0x50041000 0x1000 >, - < 0x50040100 0x0100 >; }; - pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = <0 56 0x04 - 0 57 0x04>; - }; - - apbdma: dma@6000a000 { + apbdma: dma { compatible = "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1200>; - interrupts = < 0 104 0x04 - 0 105 0x04 - 0 106 0x04 - 0 107 0x04 - 0 108 0x04 - 0 109 0x04 - 0 110 0x04 - 0 111 0x04 - 0 112 0x04 - 0 113 0x04 - 0 114 0x04 - 0 115 0x04 - 0 116 0x04 - 0 117 0x04 - 0 118 0x04 - 0 119 0x04 >; - }; - - i2c@7000c000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-i2c"; - reg = <0x7000C000 0x100>; - interrupts = < 0 38 0x04 >; - }; - - i2c@7000c400 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-i2c"; - reg = <0x7000C400 0x100>; - interrupts = < 0 84 0x04 >; + interrupts = <0 104 0x04 + 0 105 0x04 + 0 106 0x04 + 0 107 0x04 + 0 108 0x04 + 0 109 0x04 + 0 110 0x04 + 0 111 0x04 + 0 112 0x04 + 0 113 0x04 + 0 114 0x04 + 0 115 0x04 + 0 116 0x04 + 0 117 0x04 + 0 118 0x04 + 0 119 0x04>; + }; + + ahb { + compatible = "nvidia,tegra20-ahb"; + reg = <0x6000c004 0x10c>; /* AHB Arbitration + Gizmo Controller */ + }; + + gpio: gpio { + compatible = "nvidia,tegra20-gpio"; + reg = <0x6000d000 0x1000>; + interrupts = <0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04>; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; }; - i2c@7000c500 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-i2c"; - reg = <0x7000C500 0x100>; - interrupts = < 0 92 0x04 >; + pinmux: pinmux { + compatible = "nvidia,tegra20-pinmux"; + reg = <0x70000014 0x10 /* Tri-state registers */ + 0x70000080 0x20 /* Mux registers */ + 0x700000a0 0x14 /* Pull-up/down registers */ + 0x70000868 0xa8>; /* Pad control registers */ }; - i2c@7000d000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra20-i2c-dvc"; - reg = <0x7000D000 0x200>; - interrupts = < 0 53 0x04 >; + das { + compatible = "nvidia,tegra20-das"; + reg = <0x70000c00 0x80>; }; tegra_i2s1: i2s@70002800 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; - interrupts = < 0 13 0x04 >; - nvidia,dma-request-selector = < &apbdma 2 >; + interrupts = <0 13 0x04>; + nvidia,dma-request-selector = <&apbdma 2>; + status = "disable"; }; tegra_i2s2: i2s@70002a00 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002a00 0x200>; - interrupts = < 0 3 0x04 >; - nvidia,dma-request-selector = < &apbdma 1 >; - }; - - das@70000c00 { - compatible = "nvidia,tegra20-das"; - reg = <0x70000c00 0x80>; - }; - - gpio: gpio@6000d000 { - compatible = "nvidia,tegra20-gpio"; - reg = < 0x6000d000 0x1000 >; - interrupts = < 0 32 0x04 - 0 33 0x04 - 0 34 0x04 - 0 35 0x04 - 0 55 0x04 - 0 87 0x04 - 0 89 0x04 >; - #gpio-cells = <2>; - gpio-controller; - #interrupt-cells = <2>; - interrupt-controller; - }; - - pinmux: pinmux@70000000 { - compatible = "nvidia,tegra20-pinmux"; - reg = < 0x70000014 0x10 /* Tri-state registers */ - 0x70000080 0x20 /* Mux registers */ - 0x700000a0 0x14 /* Pull-up/down registers */ - 0x70000868 0xa8 >; /* Pad control registers */ + interrupts = <0 3 0x04>; + nvidia,dma-request-selector = <&apbdma 1>; + status = "disable"; }; serial@70006000 { compatible = "nvidia,tegra20-uart"; reg = <0x70006000 0x40>; reg-shift = <2>; - interrupts = < 0 36 0x04 >; + interrupts = <0 36 0x04>; + status = "disable"; }; serial@70006040 { compatible = "nvidia,tegra20-uart"; reg = <0x70006040 0x40>; reg-shift = <2>; - interrupts = < 0 37 0x04 >; + interrupts = <0 37 0x04>; + status = "disable"; }; serial@70006200 { compatible = "nvidia,tegra20-uart"; reg = <0x70006200 0x100>; reg-shift = <2>; - interrupts = < 0 46 0x04 >; + interrupts = <0 46 0x04>; + status = "disable"; }; serial@70006300 { compatible = "nvidia,tegra20-uart"; reg = <0x70006300 0x100>; reg-shift = <2>; - interrupts = < 0 90 0x04 >; + interrupts = <0 90 0x04>; + status = "disable"; }; serial@70006400 { compatible = "nvidia,tegra20-uart"; reg = <0x70006400 0x100>; reg-shift = <2>; - interrupts = < 0 91 0x04 >; + interrupts = <0 91 0x04>; + status = "disable"; }; - emc@7000f400 { + i2c@7000c000 { + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000c000 0x100>; + interrupts = <0 38 0x04>; #address-cells = <1>; #size-cells = <0>; - compatible = "nvidia,tegra20-emc"; - reg = <0x7000f400 0x200>; + status = "disable"; }; - sdhci@c8000000 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000000 0x200>; - interrupts = < 0 14 0x04 >; + i2c@7000c400 { + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000c400 0x100>; + interrupts = <0 84 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; }; - sdhci@c8000200 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000200 0x200>; - interrupts = < 0 15 0x04 >; + i2c@7000c500 { + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000c500 0x100>; + interrupts = <0 92 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; }; - sdhci@c8000400 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000400 0x200>; - interrupts = < 0 19 0x04 >; + i2c@7000d000 { + compatible = "nvidia,tegra20-i2c-dvc"; + reg = <0x7000d000 0x200>; + interrupts = <0 53 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; }; - sdhci@c8000600 { - compatible = "nvidia,tegra20-sdhci"; - reg = <0xc8000600 0x200>; - interrupts = < 0 31 0x04 >; + pmc { + compatible = "nvidia,tegra20-pmc"; + reg = <0x7000e400 0x400>; + }; + + mc { + compatible = "nvidia,tegra20-mc"; + reg = <0x7000f000 0x024 + 0x7000f03c 0x3c4>; + interrupts = <0 77 0x04>; + }; + + gart { + compatible = "nvidia,tegra20-gart"; + reg = <0x7000f024 0x00000018 /* controller registers */ + 0x58000000 0x02000000>; /* GART aperture */ + }; + + emc { + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f400 0x200>; + #address-cells = <1>; + #size-cells = <0>; }; usb@c5000000 { compatible = "nvidia,tegra20-ehci", "usb-ehci"; reg = <0xc5000000 0x4000>; - interrupts = < 0 20 0x04 >; + interrupts = <0 20 0x04>; phy_type = "utmi"; nvidia,has-legacy-mode; + status = "disable"; }; usb@c5004000 { compatible = "nvidia,tegra20-ehci", "usb-ehci"; reg = <0xc5004000 0x4000>; - interrupts = < 0 21 0x04 >; + interrupts = <0 21 0x04>; phy_type = "ulpi"; + status = "disable"; }; usb@c5008000 { compatible = "nvidia,tegra20-ehci", "usb-ehci"; reg = <0xc5008000 0x4000>; - interrupts = < 0 97 0x04 >; + interrupts = <0 97 0x04>; phy_type = "utmi"; + status = "disable"; + }; + + sdhci@c8000000 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000000 0x200>; + interrupts = <0 14 0x04>; + status = "disable"; }; -}; + sdhci@c8000200 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000200 0x200>; + interrupts = <0 15 0x04>; + status = "disable"; + }; + + sdhci@c8000400 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000400 0x200>; + interrupts = <0 19 0x04>; + status = "disable"; + }; + + sdhci@c8000600 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000600 0x200>; + interrupts = <0 31 0x04>; + status = "disable"; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 56 0x04 + 0 57 0x04>; + }; +}; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 62a7b39f1c9a..2dcc09e784b5 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -4,183 +4,268 @@ compatible = "nvidia,tegra30"; interrupt-parent = <&intc>; - pmc@7000f400 { - compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc"; - reg = <0x7000e400 0x400>; - }; - - intc: interrupt-controller@50041000 { + intc: interrupt-controller { compatible = "arm,cortex-a9-gic"; + reg = <0x50041000 0x1000 + 0x50040100 0x0100>; interrupt-controller; #interrupt-cells = <3>; - reg = < 0x50041000 0x1000 >, - < 0x50040100 0x0100 >; }; - pmu { - compatible = "arm,cortex-a9-pmu"; - interrupts = <0 144 0x04 - 0 145 0x04 - 0 146 0x04 - 0 147 0x04>; - }; - - apbdma: dma@6000a000 { + apbdma: dma { compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; reg = <0x6000a000 0x1400>; - interrupts = < 0 104 0x04 - 0 105 0x04 - 0 106 0x04 - 0 107 0x04 - 0 108 0x04 - 0 109 0x04 - 0 110 0x04 - 0 111 0x04 - 0 112 0x04 - 0 113 0x04 - 0 114 0x04 - 0 115 0x04 - 0 116 0x04 - 0 117 0x04 - 0 118 0x04 - 0 119 0x04 - 0 128 0x04 - 0 129 0x04 - 0 130 0x04 - 0 131 0x04 - 0 132 0x04 - 0 133 0x04 - 0 134 0x04 - 0 135 0x04 - 0 136 0x04 - 0 137 0x04 - 0 138 0x04 - 0 139 0x04 - 0 140 0x04 - 0 141 0x04 - 0 142 0x04 - 0 143 0x04 >; - }; - - i2c@7000c000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000C000 0x100>; - interrupts = < 0 38 0x04 >; - }; - - i2c@7000c400 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000C400 0x100>; - interrupts = < 0 84 0x04 >; - }; - - i2c@7000c500 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000C500 0x100>; - interrupts = < 0 92 0x04 >; + interrupts = <0 104 0x04 + 0 105 0x04 + 0 106 0x04 + 0 107 0x04 + 0 108 0x04 + 0 109 0x04 + 0 110 0x04 + 0 111 0x04 + 0 112 0x04 + 0 113 0x04 + 0 114 0x04 + 0 115 0x04 + 0 116 0x04 + 0 117 0x04 + 0 118 0x04 + 0 119 0x04 + 0 128 0x04 + 0 129 0x04 + 0 130 0x04 + 0 131 0x04 + 0 132 0x04 + 0 133 0x04 + 0 134 0x04 + 0 135 0x04 + 0 136 0x04 + 0 137 0x04 + 0 138 0x04 + 0 139 0x04 + 0 140 0x04 + 0 141 0x04 + 0 142 0x04 + 0 143 0x04>; }; - i2c@7000c700 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000c700 0x100>; - interrupts = < 0 120 0x04 >; + ahb: ahb { + compatible = "nvidia,tegra30-ahb"; + reg = <0x6000c004 0x14c>; /* AHB Arbitration + Gizmo Controller */ }; - i2c@7000d000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; - reg = <0x7000D000 0x100>; - interrupts = < 0 53 0x04 >; - }; - - gpio: gpio@6000d000 { + gpio: gpio { compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio"; - reg = < 0x6000d000 0x1000 >; - interrupts = < 0 32 0x04 - 0 33 0x04 - 0 34 0x04 - 0 35 0x04 - 0 55 0x04 - 0 87 0x04 - 0 89 0x04 - 0 125 0x04 >; + reg = <0x6000d000 0x1000>; + interrupts = <0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 + 0 125 0x04>; #gpio-cells = <2>; gpio-controller; #interrupt-cells = <2>; interrupt-controller; }; + pinmux: pinmux { + compatible = "nvidia,tegra30-pinmux"; + reg = <0x70000868 0xd0 /* Pad control registers */ + 0x70003000 0x3e0>; /* Mux registers */ + }; + serial@70006000 { compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; reg = <0x70006000 0x40>; reg-shift = <2>; - interrupts = < 0 36 0x04 >; + interrupts = <0 36 0x04>; + status = "disable"; }; serial@70006040 { compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; reg = <0x70006040 0x40>; reg-shift = <2>; - interrupts = < 0 37 0x04 >; + interrupts = <0 37 0x04>; + status = "disable"; }; serial@70006200 { compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; reg = <0x70006200 0x100>; reg-shift = <2>; - interrupts = < 0 46 0x04 >; + interrupts = <0 46 0x04>; + status = "disable"; }; serial@70006300 { compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; reg = <0x70006300 0x100>; reg-shift = <2>; - interrupts = < 0 90 0x04 >; + interrupts = <0 90 0x04>; + status = "disable"; }; serial@70006400 { compatible = "nvidia,tegra30-uart", "nvidia,tegra20-uart"; reg = <0x70006400 0x100>; reg-shift = <2>; - interrupts = < 0 91 0x04 >; + interrupts = <0 91 0x04>; + status = "disable"; + }; + + i2c@7000c000 { + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000c000 0x100>; + interrupts = <0 38 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; + }; + + i2c@7000c400 { + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000c400 0x100>; + interrupts = <0 84 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; + }; + + i2c@7000c500 { + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000c500 0x100>; + interrupts = <0 92 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; + }; + + i2c@7000c700 { + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000c700 0x100>; + interrupts = <0 120 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; + }; + + i2c@7000d000 { + compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c"; + reg = <0x7000d000 0x100>; + interrupts = <0 53 0x04>; + #address-cells = <1>; + #size-cells = <0>; + status = "disable"; + }; + + pmc { + compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc"; + reg = <0x7000e400 0x400>; + }; + + mc { + compatible = "nvidia,tegra30-mc"; + reg = <0x7000f000 0x010 + 0x7000f03c 0x1b4 + 0x7000f200 0x028 + 0x7000f284 0x17c>; + interrupts = <0 77 0x04>; + }; + + smmu { + compatible = "nvidia,tegra30-smmu"; + reg = <0x7000f010 0x02c + 0x7000f1f0 0x010 + 0x7000f228 0x05c>; + nvidia,#asids = <4>; /* # of ASIDs */ + dma-window = <0 0x40000000>; /* IOVA start & length */ + nvidia,ahb = <&ahb>; + }; + + 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>; + status = "disable"; + }; + + tegra_i2s1: i2s@70080400 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080400 0x100>; + nvidia,ahub-cif-ids = <5 5>; + status = "disable"; + }; + + tegra_i2s2: i2s@70080500 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080500 0x100>; + nvidia,ahub-cif-ids = <6 6>; + status = "disable"; + }; + + tegra_i2s3: i2s@70080600 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080600 0x100>; + nvidia,ahub-cif-ids = <7 7>; + status = "disable"; + }; + + tegra_i2s4: i2s@70080700 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080700 0x100>; + nvidia,ahub-cif-ids = <8 8>; + status = "disable"; + }; }; sdhci@78000000 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000000 0x200>; - interrupts = < 0 14 0x04 >; + interrupts = <0 14 0x04>; + status = "disable"; }; sdhci@78000200 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000200 0x200>; - interrupts = < 0 15 0x04 >; + interrupts = <0 15 0x04>; + status = "disable"; }; sdhci@78000400 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000400 0x200>; - interrupts = < 0 19 0x04 >; + interrupts = <0 19 0x04>; + status = "disable"; }; sdhci@78000600 { compatible = "nvidia,tegra30-sdhci", "nvidia,tegra20-sdhci"; reg = <0x78000600 0x200>; - interrupts = < 0 31 0x04 >; + interrupts = <0 31 0x04>; + status = "disable"; }; - pinmux: pinmux@70000000 { - compatible = "nvidia,tegra30-pinmux"; - reg = < 0x70000868 0xd0 /* Pad control registers */ - 0x70003000 0x3e0 >; /* Mux registers */ + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <0 144 0x04 + 0 145 0x04 + 0 146 0x04 + 0 147 0x04>; }; }; diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index 595ecd290ebf..9d7eb530f95f 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c @@ -173,7 +173,8 @@ find_safe_buffer(struct dmabounce_device_info *device_info, dma_addr_t safe_dma_ read_lock_irqsave(&device_info->lock, flags); list_for_each_entry(b, &device_info->safe_buffers, node) - if (b->safe_dma_addr == safe_dma_addr) { + if (b->safe_dma_addr <= safe_dma_addr && + b->safe_dma_addr + b->size > safe_dma_addr) { rb = b; break; } @@ -254,7 +255,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, if (buf == NULL) { dev_err(dev, "%s: unable to map unsafe buffer %p!\n", __func__, ptr); - return ~0; + return DMA_ERROR_CODE; } dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", @@ -307,8 +308,9 @@ static inline void unmap_single(struct device *dev, struct safe_buffer *buf, * substitute the safe buffer for the unsafe one. * (basically move the buffer from an unsafe area to a safe one) */ -dma_addr_t __dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction dir) +static dma_addr_t dmabounce_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) { dma_addr_t dma_addr; int ret; @@ -320,21 +322,20 @@ dma_addr_t __dma_map_page(struct device *dev, struct page *page, ret = needs_bounce(dev, dma_addr, size); if (ret < 0) - return ~0; + return DMA_ERROR_CODE; if (ret == 0) { - __dma_page_cpu_to_dev(page, offset, size, dir); + arm_dma_ops.sync_single_for_device(dev, dma_addr, size, dir); return dma_addr; } if (PageHighMem(page)) { dev_err(dev, "DMA buffer bouncing of HIGHMEM pages is not supported\n"); - return ~0; + return DMA_ERROR_CODE; } return map_single(dev, page_address(page) + offset, size, dir); } -EXPORT_SYMBOL(__dma_map_page); /* * see if a mapped address was really a "safe" buffer and if so, copy @@ -342,8 +343,8 @@ EXPORT_SYMBOL(__dma_map_page); * the safe buffer. (basically return things back to the way they * should be) */ -void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction dir) +static void dmabounce_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir, struct dma_attrs *attrs) { struct safe_buffer *buf; @@ -352,19 +353,18 @@ void __dma_unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, buf = find_safe_buffer_dev(dev, dma_addr, __func__); if (!buf) { - __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, dma_addr)), - dma_addr & ~PAGE_MASK, size, dir); + arm_dma_ops.sync_single_for_cpu(dev, dma_addr, size, dir); return; } unmap_single(dev, buf, size, dir); } -EXPORT_SYMBOL(__dma_unmap_page); -int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr, - unsigned long off, size_t sz, enum dma_data_direction dir) +static int __dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr, + size_t sz, enum dma_data_direction dir) { struct safe_buffer *buf; + unsigned long off; dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n", __func__, addr, off, sz, dir); @@ -373,6 +373,8 @@ int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr, if (!buf) return 1; + off = addr - buf->safe_dma_addr; + BUG_ON(buf->direction != dir); dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", @@ -388,12 +390,21 @@ int dmabounce_sync_for_cpu(struct device *dev, dma_addr_t addr, } return 0; } -EXPORT_SYMBOL(dmabounce_sync_for_cpu); -int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr, - unsigned long off, size_t sz, enum dma_data_direction dir) +static void dmabounce_sync_for_cpu(struct device *dev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + if (!__dmabounce_sync_for_cpu(dev, handle, size, dir)) + return; + + arm_dma_ops.sync_single_for_cpu(dev, handle, size, dir); +} + +static int __dmabounce_sync_for_device(struct device *dev, dma_addr_t addr, + size_t sz, enum dma_data_direction dir) { struct safe_buffer *buf; + unsigned long off; dev_dbg(dev, "%s(dma=%#x,off=%#lx,sz=%zx,dir=%x)\n", __func__, addr, off, sz, dir); @@ -402,6 +413,8 @@ int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr, if (!buf) return 1; + off = addr - buf->safe_dma_addr; + BUG_ON(buf->direction != dir); dev_dbg(dev, "%s: unsafe buffer %p (dma=%#x) mapped to %p (dma=%#x)\n", @@ -417,7 +430,38 @@ int dmabounce_sync_for_device(struct device *dev, dma_addr_t addr, } return 0; } -EXPORT_SYMBOL(dmabounce_sync_for_device); + +static void dmabounce_sync_for_device(struct device *dev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + if (!__dmabounce_sync_for_device(dev, handle, size, dir)) + return; + + arm_dma_ops.sync_single_for_device(dev, handle, size, dir); +} + +static int dmabounce_set_mask(struct device *dev, u64 dma_mask) +{ + if (dev->archdata.dmabounce) + return 0; + + return arm_dma_ops.set_dma_mask(dev, dma_mask); +} + +static struct dma_map_ops dmabounce_ops = { + .alloc = arm_dma_alloc, + .free = arm_dma_free, + .mmap = arm_dma_mmap, + .map_page = dmabounce_map_page, + .unmap_page = dmabounce_unmap_page, + .sync_single_for_cpu = dmabounce_sync_for_cpu, + .sync_single_for_device = dmabounce_sync_for_device, + .map_sg = arm_dma_map_sg, + .unmap_sg = arm_dma_unmap_sg, + .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, + .sync_sg_for_device = arm_dma_sync_sg_for_device, + .set_dma_mask = dmabounce_set_mask, +}; static int dmabounce_init_pool(struct dmabounce_pool *pool, struct device *dev, const char *name, unsigned long size) @@ -479,6 +523,7 @@ int dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, #endif dev->archdata.dmabounce = device_info; + set_dma_ops(dev, &dmabounce_ops); dev_info(dev, "dmabounce: registered device\n"); @@ -497,6 +542,7 @@ void dmabounce_unregister_dev(struct device *dev) struct dmabounce_device_info *device_info = dev->archdata.dmabounce; dev->archdata.dmabounce = NULL; + set_dma_ops(dev, NULL); if (!device_info) { dev_warn(dev, diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index 09a02963cf58..ebda45bd5763 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -33,6 +33,7 @@ CONFIG_MACH_IMX27LITE=y CONFIG_MACH_PCA100=y CONFIG_MACH_MXT_TD60=y CONFIG_MACH_IMX27IPCAM=y +CONFIG_MACH_IMX27_DT=y CONFIG_MXC_IRQ_PRIOR=y CONFIG_MXC_PWM=y CONFIG_NO_HZ=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index dc6f6411bbf5..12617f7296e6 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -64,6 +64,12 @@ CONFIG_IPV6=y # CONFIG_WIRELESS is not set CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y +CONFIG_MTD=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_DATAFLASH=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_SST25L=y # CONFIG_STANDALONE is not set CONFIG_CONNECTOR=y CONFIG_BLK_DEV_LOOP=y diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index 1ebbf451c48d..5406c23a02e3 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -22,6 +22,7 @@ CONFIG_BLK_DEV_INTEGRITY=y # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set CONFIG_ARCH_MXS=y +CONFIG_MACH_MXS_DT=y CONFIG_MACH_MX23EVK=y CONFIG_MACH_MX28EVK=y CONFIG_MACH_STMP378X_DEVB=y diff --git a/arch/arm/configs/prima2_defconfig b/arch/arm/configs/prima2_defconfig new file mode 100644 index 000000000000..c328ac65479a --- /dev/null +++ b/arch/arm/configs/prima2_defconfig @@ -0,0 +1,69 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_BSD_DISKLABEL=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_ARCH_PRIMA2=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_KEXEC=y +CONFIG_BINFMT_MISC=y +CONFIG_PM_RUNTIME=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_SERIAL_SIRFSOC=y +CONFIG_SERIAL_SIRFSOC_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_SIRF=y +CONFIG_SPI=y +CONFIG_SPI_SIRF=y +CONFIG_SPI_SPIDEV=y +# CONFIG_HWMON is not set +# CONFIG_HID_SUPPORT is not set +CONFIG_USB_GADGET=y +CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_MASS_STORAGE=m +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_DMADEVICES=y +CONFIG_DMADEVICES_DEBUG=y +CONFIG_DMADEVICES_VDEBUG=y +CONFIG_SIRF_DMA=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT2_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CRAMFS=y +CONFIG_ROMFS_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_INFO=y +CONFIG_CRC_CCITT=y diff --git a/arch/arm/configs/spear13xx_defconfig b/arch/arm/configs/spear13xx_defconfig new file mode 100644 index 000000000000..1fdb82694ca2 --- /dev/null +++ b/arch/arm/configs/spear13xx_defconfig @@ -0,0 +1,95 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_PLAT_SPEAR=y +CONFIG_ARCH_SPEAR13XX=y +CONFIG_MACH_SPEAR1310=y +CONFIG_MACH_SPEAR1340=y +# CONFIG_SWP_EMULATE is not set +CONFIG_SMP=y +# CONFIG_SMP_ON_UP is not set +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_BINFMT_MISC=y +CONFIG_NET=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_MTD=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_FSMC=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_ATA=y +# CONFIG_SATA_PMP is not set +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_PATA_ARASAN_CF=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +CONFIG_STMMAC_ETH=y +# CONFIG_WLAN is not set +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_SPEAR=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_RAW_DRIVER=y +CONFIG_MAX_RAW_DEVS=8192 +CONFIG_I2C=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_SPI=y +CONFIG_SPI_PL022=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_PL061=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_MPCORE_WATCHDOG=y +# CONFIG_HID_SUPPORT is not set +CONFIG_USB=y +# CONFIG_USB_DEVICE_CLASS is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_SPEAR=y +CONFIG_RTC_CLASS=y +CONFIG_DMADEVICES=y +CONFIG_DW_DMAC=y +CONFIG_DMATEST=m +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_AUTOFS4_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=m +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_INFO=y diff --git a/arch/arm/configs/spear3xx_defconfig b/arch/arm/configs/spear3xx_defconfig index 7ed42912d69a..865980c5f212 100644 --- a/arch/arm/configs/spear3xx_defconfig +++ b/arch/arm/configs/spear3xx_defconfig @@ -14,6 +14,9 @@ CONFIG_BINFMT_MISC=y CONFIG_NET=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y @@ -73,6 +76,7 @@ CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m diff --git a/arch/arm/configs/spear6xx_defconfig b/arch/arm/configs/spear6xx_defconfig index cf94bc73a0e0..a2a1265f86b6 100644 --- a/arch/arm/configs/spear6xx_defconfig +++ b/arch/arm/configs/spear6xx_defconfig @@ -8,11 +8,13 @@ CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y CONFIG_PLAT_SPEAR=y CONFIG_ARCH_SPEAR6XX=y -CONFIG_BOARD_SPEAR600_DT=y CONFIG_BINFMT_MISC=y CONFIG_NET=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y +CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSMC=y CONFIG_BLK_DEV_RAM=y @@ -64,6 +66,7 @@ CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=m CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_TMPFS=y +CONFIG_JFFS2_FS=y CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=m diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 351d6708c3ae..1198dd61c7c4 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -45,6 +45,7 @@ CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_IDLE=y CONFIG_VFP=y +CONFIG_PM_RUNTIME=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -91,6 +92,8 @@ CONFIG_USB_NET_SMSC75XX=y CONFIG_USB_NET_SMSC95XX=y # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MPU3050=y # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVKMEM is not set @@ -103,12 +106,15 @@ CONFIG_I2C=y CONFIG_I2C_TEGRA=y CONFIG_SPI=y CONFIG_SPI_TEGRA=y +CONFIG_POWER_SUPPLY=y +CONFIG_BATTERY_SBS=y CONFIG_SENSORS_LM90=y CONFIG_MFD_TPS6586X=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_VIRTUAL_CONSUMER=y CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_TPS62360=y CONFIG_REGULATOR_TPS6586X=y CONFIG_SOUND=y CONFIG_SND=y @@ -133,16 +139,19 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_TEGRA=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_EM3027=y CONFIG_RTC_DRV_TEGRA=y CONFIG_STAGING=y -CONFIG_IIO=y CONFIG_SENSORS_ISL29018=y +CONFIG_SENSORS_ISL29028=y CONFIG_SENSORS_AK8975=y CONFIG_MFD_NVEC=y CONFIG_KEYBOARD_NVEC=y CONFIG_SERIO_NVEC_PS2=y CONFIG_TEGRA_IOMMU_GART=y CONFIG_TEGRA_IOMMU_SMMU=y +CONFIG_MEMORY=y +CONFIG_IIO=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y diff --git a/arch/arm/include/asm/device.h b/arch/arm/include/asm/device.h index 7aa368003b05..b69c0d3285f8 100644 --- a/arch/arm/include/asm/device.h +++ b/arch/arm/include/asm/device.h @@ -7,12 +7,16 @@ #define ASMARM_DEVICE_H struct dev_archdata { + struct dma_map_ops *dma_ops; #ifdef CONFIG_DMABOUNCE struct dmabounce_device_info *dmabounce; #endif #ifdef CONFIG_IOMMU_API void *iommu; /* private IOMMU data */ #endif +#ifdef CONFIG_ARM_DMA_USE_IOMMU + struct dma_iommu_mapping *mapping; +#endif }; struct omap_device; diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h new file mode 100644 index 000000000000..3ed37b4d93da --- /dev/null +++ b/arch/arm/include/asm/dma-contiguous.h @@ -0,0 +1,15 @@ +#ifndef ASMARM_DMA_CONTIGUOUS_H +#define ASMARM_DMA_CONTIGUOUS_H + +#ifdef __KERNEL__ +#ifdef CONFIG_CMA + +#include <linux/types.h> +#include <asm-generic/dma-contiguous.h> + +void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size); + +#endif +#endif + +#endif diff --git a/arch/arm/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h new file mode 100644 index 000000000000..799b09409fad --- /dev/null +++ b/arch/arm/include/asm/dma-iommu.h @@ -0,0 +1,34 @@ +#ifndef ASMARM_DMA_IOMMU_H +#define ASMARM_DMA_IOMMU_H + +#ifdef __KERNEL__ + +#include <linux/mm_types.h> +#include <linux/scatterlist.h> +#include <linux/dma-debug.h> +#include <linux/kmemcheck.h> + +struct dma_iommu_mapping { + /* iommu specific data */ + struct iommu_domain *domain; + + void *bitmap; + size_t bits; + unsigned int order; + dma_addr_t base; + + spinlock_t lock; + struct kref kref; +}; + +struct dma_iommu_mapping * +arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size, + int order); + +void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping); + +int arm_iommu_attach_device(struct device *dev, + struct dma_iommu_mapping *mapping); + +#endif /* __KERNEL__ */ +#endif diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index cb3b7c981c4b..bbef15d04890 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -5,11 +5,35 @@ #include <linux/mm_types.h> #include <linux/scatterlist.h> +#include <linux/dma-attrs.h> #include <linux/dma-debug.h> #include <asm-generic/dma-coherent.h> #include <asm/memory.h> +#define DMA_ERROR_CODE (~0) +extern struct dma_map_ops arm_dma_ops; + +static inline struct dma_map_ops *get_dma_ops(struct device *dev) +{ + if (dev && dev->archdata.dma_ops) + return dev->archdata.dma_ops; + return &arm_dma_ops; +} + +static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) +{ + BUG_ON(!dev); + dev->archdata.dma_ops = ops; +} + +#include <asm-generic/dma-mapping-common.h> + +static inline int dma_set_mask(struct device *dev, u64 mask) +{ + return get_dma_ops(dev)->set_dma_mask(dev, mask); +} + #ifdef __arch_page_to_dma #error Please update to __arch_pfn_to_dma #endif @@ -62,68 +86,11 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr) #endif /* - * The DMA API is built upon the notion of "buffer ownership". A buffer - * is either exclusively owned by the CPU (and therefore may be accessed - * by it) or exclusively owned by the DMA device. These helper functions - * represent the transitions between these two ownership states. - * - * Note, however, that on later ARMs, this notion does not work due to - * speculative prefetches. We model our approach on the assumption that - * the CPU does do speculative prefetches, which means we clean caches - * before transfers and delay cache invalidation until transfer completion. - * - * Private support functions: these are not part of the API and are - * liable to change. Drivers must not use these. - */ -static inline void __dma_single_cpu_to_dev(const void *kaddr, size_t size, - enum dma_data_direction dir) -{ - extern void ___dma_single_cpu_to_dev(const void *, size_t, - enum dma_data_direction); - - if (!arch_is_coherent()) - ___dma_single_cpu_to_dev(kaddr, size, dir); -} - -static inline void __dma_single_dev_to_cpu(const void *kaddr, size_t size, - enum dma_data_direction dir) -{ - extern void ___dma_single_dev_to_cpu(const void *, size_t, - enum dma_data_direction); - - if (!arch_is_coherent()) - ___dma_single_dev_to_cpu(kaddr, size, dir); -} - -static inline void __dma_page_cpu_to_dev(struct page *page, unsigned long off, - size_t size, enum dma_data_direction dir) -{ - extern void ___dma_page_cpu_to_dev(struct page *, unsigned long, - size_t, enum dma_data_direction); - - if (!arch_is_coherent()) - ___dma_page_cpu_to_dev(page, off, size, dir); -} - -static inline void __dma_page_dev_to_cpu(struct page *page, unsigned long off, - size_t size, enum dma_data_direction dir) -{ - extern void ___dma_page_dev_to_cpu(struct page *, unsigned long, - size_t, enum dma_data_direction); - - if (!arch_is_coherent()) - ___dma_page_dev_to_cpu(page, off, size, dir); -} - -extern int dma_supported(struct device *, u64); -extern int dma_set_mask(struct device *, u64); - -/* * DMA errors are defined by all-bits-set in the DMA address. */ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { - return dma_addr == ~0; + return dma_addr == DMA_ERROR_CODE; } /* @@ -141,69 +108,118 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size, { } +extern int dma_supported(struct device *dev, u64 mask); + /** - * dma_alloc_coherent - allocate consistent memory for DMA + * arm_dma_alloc - allocate consistent memory for DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @size: required memory size * @handle: bus-specific DMA address + * @attrs: optinal attributes that specific mapping properties * - * Allocate some uncached, unbuffered memory for a device for - * performing DMA. This function allocates pages, and will - * return the CPU-viewed address, and sets @handle to be the - * device-viewed address. + * Allocate some memory for a device for performing DMA. This function + * allocates pages, and will return the CPU-viewed address, and sets @handle + * to be the device-viewed address. */ -extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t); +extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, + gfp_t gfp, struct dma_attrs *attrs); + +#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) + +static inline void *dma_alloc_attrs(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + void *cpu_addr; + BUG_ON(!ops); + + cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs); + debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); + return cpu_addr; +} /** - * dma_free_coherent - free memory allocated by dma_alloc_coherent + * arm_dma_free - free memory allocated by arm_dma_alloc * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @size: size of memory originally requested in dma_alloc_coherent * @cpu_addr: CPU-view address returned from dma_alloc_coherent * @handle: device-view address returned from dma_alloc_coherent + * @attrs: optinal attributes that specific mapping properties * * Free (and unmap) a DMA buffer previously allocated by - * dma_alloc_coherent(). + * arm_dma_alloc(). * * References to memory and mappings associated with cpu_addr/handle * during and after this call executing are illegal. */ -extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t); +extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle, struct dma_attrs *attrs); + +#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL) + +static inline void dma_free_attrs(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); + + debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); + ops->free(dev, size, cpu_addr, dma_handle, attrs); +} /** - * dma_mmap_coherent - map a coherent DMA allocation into user space + * arm_dma_mmap - map a coherent DMA allocation into user space * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @vma: vm_area_struct describing requested user mapping * @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent * @handle: device-view address returned from dma_alloc_coherent * @size: size of memory originally requested in dma_alloc_coherent + * @attrs: optinal attributes that specific mapping properties * * Map a coherent DMA buffer previously allocated by dma_alloc_coherent * into user space. The coherent DMA buffer must not be freed by the * driver until the user space mapping has been released. */ -int dma_mmap_coherent(struct device *, struct vm_area_struct *, - void *, dma_addr_t, size_t); +extern int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs); +#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, NULL) -/** - * dma_alloc_writecombine - allocate writecombining memory for DMA - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices - * @size: required memory size - * @handle: bus-specific DMA address - * - * Allocate some uncached, buffered memory for a device for - * performing DMA. This function allocates pages, and will - * return the CPU-viewed address, and sets @handle to be the - * device-viewed address. - */ -extern void *dma_alloc_writecombine(struct device *, size_t, dma_addr_t *, - gfp_t); +static inline int dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, + size_t size, struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + BUG_ON(!ops); + return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); +} + +static inline void *dma_alloc_writecombine(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_alloc_attrs(dev, size, dma_handle, flag, &attrs); +} -#define dma_free_writecombine(dev,size,cpu_addr,handle) \ - dma_free_coherent(dev,size,cpu_addr,handle) +static inline void dma_free_writecombine(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); +} -int dma_mmap_writecombine(struct device *, struct vm_area_struct *, - void *, dma_addr_t, size_t); +static inline int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size) +{ + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, &attrs); +} /* * This can be called during boot to increase the size of the consistent @@ -212,8 +228,6 @@ int dma_mmap_writecombine(struct device *, struct vm_area_struct *, */ extern void __init init_consistent_dma_size(unsigned long size); - -#ifdef CONFIG_DMABOUNCE /* * For SA-1111, IXP425, and ADI systems the dma-mapping functions are "magic" * and utilize bounce buffers as needed to work around limited DMA windows. @@ -253,222 +267,19 @@ extern int dmabounce_register_dev(struct device *, unsigned long, */ extern void dmabounce_unregister_dev(struct device *); -/* - * The DMA API, implemented by dmabounce.c. See below for descriptions. - */ -extern dma_addr_t __dma_map_page(struct device *, struct page *, - unsigned long, size_t, enum dma_data_direction); -extern void __dma_unmap_page(struct device *, dma_addr_t, size_t, - enum dma_data_direction); - -/* - * Private functions - */ -int dmabounce_sync_for_cpu(struct device *, dma_addr_t, unsigned long, - size_t, enum dma_data_direction); -int dmabounce_sync_for_device(struct device *, dma_addr_t, unsigned long, - size_t, enum dma_data_direction); -#else -static inline int dmabounce_sync_for_cpu(struct device *d, dma_addr_t addr, - unsigned long offset, size_t size, enum dma_data_direction dir) -{ - return 1; -} -static inline int dmabounce_sync_for_device(struct device *d, dma_addr_t addr, - unsigned long offset, size_t size, enum dma_data_direction dir) -{ - return 1; -} - - -static inline dma_addr_t __dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction dir) -{ - __dma_page_cpu_to_dev(page, offset, size, dir); - return pfn_to_dma(dev, page_to_pfn(page)) + offset; -} - -static inline void __dma_unmap_page(struct device *dev, dma_addr_t handle, - size_t size, enum dma_data_direction dir) -{ - __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)), - handle & ~PAGE_MASK, size, dir); -} -#endif /* CONFIG_DMABOUNCE */ - -/** - * dma_map_single - map a single buffer for streaming DMA - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices - * @cpu_addr: CPU direct mapped address of buffer - * @size: size of buffer to map - * @dir: DMA transfer direction - * - * Ensure that any data held in the cache is appropriately discarded - * or written back. - * - * The device owns this memory once this call has completed. The CPU - * can regain ownership by calling dma_unmap_single() or - * dma_sync_single_for_cpu(). - */ -static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, - size_t size, enum dma_data_direction dir) -{ - unsigned long offset; - struct page *page; - dma_addr_t addr; - - BUG_ON(!virt_addr_valid(cpu_addr)); - BUG_ON(!virt_addr_valid(cpu_addr + size - 1)); - BUG_ON(!valid_dma_direction(dir)); - - page = virt_to_page(cpu_addr); - offset = (unsigned long)cpu_addr & ~PAGE_MASK; - addr = __dma_map_page(dev, page, offset, size, dir); - debug_dma_map_page(dev, page, offset, size, dir, addr, true); - - return addr; -} - -/** - * dma_map_page - map a portion of a page for streaming DMA - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices - * @page: page that buffer resides in - * @offset: offset into page for start of buffer - * @size: size of buffer to map - * @dir: DMA transfer direction - * - * Ensure that any data held in the cache is appropriately discarded - * or written back. - * - * The device owns this memory once this call has completed. The CPU - * can regain ownership by calling dma_unmap_page(). - */ -static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction dir) -{ - dma_addr_t addr; - - BUG_ON(!valid_dma_direction(dir)); - - addr = __dma_map_page(dev, page, offset, size, dir); - debug_dma_map_page(dev, page, offset, size, dir, addr, false); - - return addr; -} - -/** - * dma_unmap_single - unmap a single buffer previously mapped - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices - * @handle: DMA address of buffer - * @size: size of buffer (same as passed to dma_map_single) - * @dir: DMA transfer direction (same as passed to dma_map_single) - * - * Unmap a single streaming mode DMA translation. The handle and size - * must match what was provided in the previous dma_map_single() call. - * All other usages are undefined. - * - * After this call, reads by the CPU to the buffer are guaranteed to see - * whatever the device wrote there. - */ -static inline void dma_unmap_single(struct device *dev, dma_addr_t handle, - size_t size, enum dma_data_direction dir) -{ - debug_dma_unmap_page(dev, handle, size, dir, true); - __dma_unmap_page(dev, handle, size, dir); -} - -/** - * dma_unmap_page - unmap a buffer previously mapped through dma_map_page() - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices - * @handle: DMA address of buffer - * @size: size of buffer (same as passed to dma_map_page) - * @dir: DMA transfer direction (same as passed to dma_map_page) - * - * Unmap a page streaming mode DMA translation. The handle and size - * must match what was provided in the previous dma_map_page() call. - * All other usages are undefined. - * - * After this call, reads by the CPU to the buffer are guaranteed to see - * whatever the device wrote there. - */ -static inline void dma_unmap_page(struct device *dev, dma_addr_t handle, - size_t size, enum dma_data_direction dir) -{ - debug_dma_unmap_page(dev, handle, size, dir, false); - __dma_unmap_page(dev, handle, size, dir); -} - -/** - * dma_sync_single_range_for_cpu - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices - * @handle: DMA address of buffer - * @offset: offset of region to start sync - * @size: size of region to sync - * @dir: DMA transfer direction (same as passed to dma_map_single) - * - * Make physical memory consistent for a single streaming mode DMA - * translation after a transfer. - * - * If you perform a dma_map_single() but wish to interrogate the - * buffer using the cpu, yet do not wish to teardown the PCI dma - * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, you - * must first the perform a dma_sync_for_device, and then the - * device again owns the buffer. - */ -static inline void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t handle, unsigned long offset, size_t size, - enum dma_data_direction dir) -{ - BUG_ON(!valid_dma_direction(dir)); - - debug_dma_sync_single_for_cpu(dev, handle + offset, size, dir); - - if (!dmabounce_sync_for_cpu(dev, handle, offset, size, dir)) - return; - - __dma_single_dev_to_cpu(dma_to_virt(dev, handle) + offset, size, dir); -} - -static inline void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t handle, unsigned long offset, size_t size, - enum dma_data_direction dir) -{ - BUG_ON(!valid_dma_direction(dir)); - - debug_dma_sync_single_for_device(dev, handle + offset, size, dir); - - if (!dmabounce_sync_for_device(dev, handle, offset, size, dir)) - return; - - __dma_single_cpu_to_dev(dma_to_virt(dev, handle) + offset, size, dir); -} - -static inline void dma_sync_single_for_cpu(struct device *dev, - dma_addr_t handle, size_t size, enum dma_data_direction dir) -{ - dma_sync_single_range_for_cpu(dev, handle, 0, size, dir); -} - -static inline void dma_sync_single_for_device(struct device *dev, - dma_addr_t handle, size_t size, enum dma_data_direction dir) -{ - dma_sync_single_range_for_device(dev, handle, 0, size, dir); -} /* * The scatter list versions of the above methods. */ -extern int dma_map_sg(struct device *, struct scatterlist *, int, - enum dma_data_direction); -extern void dma_unmap_sg(struct device *, struct scatterlist *, int, +extern int arm_dma_map_sg(struct device *, struct scatterlist *, int, + enum dma_data_direction, struct dma_attrs *attrs); +extern void arm_dma_unmap_sg(struct device *, struct scatterlist *, int, + enum dma_data_direction, struct dma_attrs *attrs); +extern void arm_dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int, enum dma_data_direction); -extern void dma_sync_sg_for_cpu(struct device *, struct scatterlist *, int, +extern void arm_dma_sync_sg_for_device(struct device *, struct scatterlist *, int, enum dma_data_direction); -extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int, - enum dma_data_direction); - #endif /* __KERNEL__ */ #endif diff --git a/arch/arm/include/asm/hardware/pl080.h b/arch/arm/include/asm/hardware/pl080.h index 33c78d7af2e1..4eea2107214b 100644 --- a/arch/arm/include/asm/hardware/pl080.h +++ b/arch/arm/include/asm/hardware/pl080.h @@ -102,6 +102,8 @@ #define PL080_WIDTH_16BIT (0x1) #define PL080_WIDTH_32BIT (0x2) +#define PL080N_CONFIG_ITPROT (1 << 20) +#define PL080N_CONFIG_SECPROT (1 << 19) #define PL080_CONFIG_HALT (1 << 18) #define PL080_CONFIG_ACTIVE (1 << 17) /* RO */ #define PL080_CONFIG_LOCK (1 << 16) diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index d7692cafde7f..0b1c94b8c652 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -43,6 +43,7 @@ struct machine_desc { void (*init_irq)(void); struct sys_timer *timer; /* system tick timer */ void (*init_machine)(void); + void (*init_late)(void); #ifdef CONFIG_MULTI_IRQ_HANDLER void (*handle_irq)(struct pt_regs *); #endif diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index b36f3654bf54..a6efcdd6fd25 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h @@ -30,6 +30,7 @@ struct map_desc { #define MT_MEMORY_DTCM 12 #define MT_MEMORY_ITCM 13 #define MT_MEMORY_SO 14 +#define MT_MEMORY_DMA_READY 15 #ifdef CONFIG_MMU extern void iotable_init(struct map_desc *, int); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index ebfac782593f..e15d83bb4ea3 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -81,6 +81,7 @@ __setup("fpe=", fpe_setup); extern void paging_init(struct machine_desc *desc); extern void sanity_check_meminfo(void); extern void reboot_setup(char *str); +extern void setup_dma_zone(struct machine_desc *desc); unsigned int processor_id; EXPORT_SYMBOL(processor_id); @@ -800,6 +801,14 @@ static int __init customize_machine(void) } arch_initcall(customize_machine); +static int __init init_machine_late(void) +{ + if (machine_desc->init_late) + machine_desc->init_late(); + return 0; +} +late_initcall(init_machine_late); + #ifdef CONFIG_KEXEC static inline unsigned long long get_total_mem(void) { @@ -939,12 +948,8 @@ void __init setup_arch(char **cmdline_p) machine_desc = mdesc; machine_name = mdesc->name; -#ifdef CONFIG_ZONE_DMA - if (mdesc->dma_zone_size) { - extern unsigned long arm_dma_zone_size; - arm_dma_zone_size = mdesc->dma_zone_size; - } -#endif + setup_dma_zone(mdesc); + if (mdesc->restart_mode) reboot_setup(&mdesc->restart_mode); diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index f6747246d649..933fc9afe7d0 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -436,7 +436,6 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) atslave->dma_dev = &at_hdmac_device.dev; atslave->cfg = ATC_FIFOCFG_HALFFIFO | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW; - atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16; if (mmc_id == 0) /* MCI0 */ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0) | ATC_DST_PER(AT_DMA_ID_MCI0); diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h index fff48d1a0f4e..cab0997be3de 100644 --- a/arch/arm/mach-at91/include/mach/at_hdmac.h +++ b/arch/arm/mach-at91/include/mach/at_hdmac.h @@ -26,18 +26,11 @@ struct at_dma_platform_data { /** * struct at_dma_slave - Controller-specific information about a slave * @dma_dev: required DMA master device - * @tx_reg: physical address of data register used for - * memory-to-peripheral transfers - * @rx_reg: physical address of data register used for - * peripheral-to-memory transfers - * @reg_width: peripheral register width * @cfg: Platform-specific initializer for the CFG register - * @ctrla: Platform-specific initializer for the CTRLA register */ struct at_dma_slave { struct device *dma_dev; u32 cfg; - u32 ctrla; }; @@ -64,24 +57,5 @@ struct at_dma_slave { #define ATC_FIFOCFG_HALFFIFO (0x1 << 28) #define ATC_FIFOCFG_ENOUGHSPACE (0x2 << 28) -/* Platform-configurable bits in CTRLA */ -#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */ -#define ATC_SCSIZE_1 (0x0 << 16) -#define ATC_SCSIZE_4 (0x1 << 16) -#define ATC_SCSIZE_8 (0x2 << 16) -#define ATC_SCSIZE_16 (0x3 << 16) -#define ATC_SCSIZE_32 (0x4 << 16) -#define ATC_SCSIZE_64 (0x5 << 16) -#define ATC_SCSIZE_128 (0x6 << 16) -#define ATC_SCSIZE_256 (0x7 << 16) -#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */ -#define ATC_DCSIZE_1 (0x0 << 20) -#define ATC_DCSIZE_4 (0x1 << 20) -#define ATC_DCSIZE_8 (0x2 << 20) -#define ATC_DCSIZE_16 (0x3 << 20) -#define ATC_DCSIZE_32 (0x4 << 20) -#define ATC_DCSIZE_64 (0x5 << 20) -#define ATC_DCSIZE_128 (0x6 << 20) -#define ATC_DCSIZE_256 (0x7 << 20) #endif /* AT_HDMAC_H */ diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index dc1afe5be20c..0031864e7f11 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -681,6 +681,7 @@ MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = da830_evm_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = da8xx_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 09f61073c8d9..0149fb453be3 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1411,6 +1411,7 @@ MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = da850_evm_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = da8xx_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 82ed753fb360..1c7b1f46a8f3 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -357,6 +357,7 @@ MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm355_evm_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index d74a8b3445fb..8e7703213b08 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -276,6 +276,7 @@ MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm355_leopard_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 5bce2b83bb4f..688a9c556dc9 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -618,6 +618,7 @@ MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = dm365_evm_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 3683306e0245..d34ed55912b2 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -825,6 +825,7 @@ MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_evm_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index d72ab948d630..958679a20e13 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -788,6 +788,7 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = evm_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END @@ -798,6 +799,7 @@ MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = evm_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 672d820e2aa4..beecde3a1d2f 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -572,6 +572,7 @@ MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = mityomapl138_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = da8xx_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index a772bb45570a..5de69f2fcca9 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -278,6 +278,7 @@ MACHINE_START(NEUROS_OSD2, "Neuros OSD2") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_ntosd2_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index 45e815760a27..dc1208e9e664 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -343,6 +343,7 @@ MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = omapl138_hawk_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = da8xx_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index 76e675096104..9078acf94bac 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -157,6 +157,7 @@ MACHINE_START(SFFSDR, "Lyrtech SFFSDR") .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = davinci_sffsdr_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = davinci_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/board-tnetv107x-evm.c b/arch/arm/mach-davinci/board-tnetv107x-evm.c index 5f14e30b00d8..ac4e003ad863 100644 --- a/arch/arm/mach-davinci/board-tnetv107x-evm.c +++ b/arch/arm/mach-davinci/board-tnetv107x-evm.c @@ -282,6 +282,7 @@ MACHINE_START(TNETV107X, "TNETV107X EVM") .init_irq = cp_intc_init, .timer = &davinci_timer, .init_machine = tnetv107x_evm_board_init, + .init_late = davinci_init_late, .dma_zone_size = SZ_128M, .restart = tnetv107x_restart, MACHINE_END diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 008772e3b843..34668ead53c7 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -213,7 +213,7 @@ EXPORT_SYMBOL(clk_unregister); /* * Disable any unused clocks left on by the bootloader */ -static int __init clk_disable_unused(void) +int __init davinci_clk_disable_unused(void) { struct clk *ck; @@ -237,7 +237,6 @@ static int __init clk_disable_unused(void) return 0; } -late_initcall(clk_disable_unused); #endif static unsigned long clk_sysclk_recalc(struct clk *clk) diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c index cb9b2e47510c..64b0f65a8639 100644 --- a/arch/arm/mach-davinci/common.c +++ b/arch/arm/mach-davinci/common.c @@ -117,3 +117,10 @@ void __init davinci_common_init(struct davinci_soc_info *soc_info) err: panic("davinci_common_init: SoC Initialization failed\n"); } + +void __init davinci_init_late(void) +{ + davinci_cpufreq_init(); + davinci_pm_init(); + davinci_clk_disable_unused(); +} diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c index 031048fec9f5..4729eaab0f40 100644 --- a/arch/arm/mach-davinci/cpufreq.c +++ b/arch/arm/mach-davinci/cpufreq.c @@ -240,10 +240,9 @@ static struct platform_driver davinci_cpufreq_driver = { .remove = __exit_p(davinci_cpufreq_remove), }; -static int __init davinci_cpufreq_init(void) +int __init davinci_cpufreq_init(void) { return platform_driver_probe(&davinci_cpufreq_driver, davinci_cpufreq_probe); } -late_initcall(davinci_cpufreq_init); 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/common.h b/arch/arm/mach-davinci/include/mach/common.h index 5cd39a4e0c96..bdc4aa8e672a 100644 --- a/arch/arm/mach-davinci/include/mach/common.h +++ b/arch/arm/mach-davinci/include/mach/common.h @@ -84,6 +84,25 @@ extern struct davinci_soc_info davinci_soc_info; extern void davinci_common_init(struct davinci_soc_info *soc_info); extern void davinci_init_ide(void); void davinci_restart(char mode, const char *cmd); +void davinci_init_late(void); + +#ifdef CONFIG_DAVINCI_RESET_CLOCKS +int davinci_clk_disable_unused(void); +#else +static inline int davinci_clk_disable_unused(void) { return 0; } +#endif + +#ifdef CONFIG_CPU_FREQ +int davinci_cpufreq_init(void); +#else +static inline int davinci_cpufreq_init(void) { return 0; } +#endif + +#ifdef CONFIG_SUSPEND +int davinci_pm_init(void); +#else +static inline int davinci_pm_init(void) { return 0; } +#endif /* standard place to map on-chip SRAMs; they *may* support DMA */ #define SRAM_VIRT 0xfffe0000 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-davinci/pm.c b/arch/arm/mach-davinci/pm.c index 04c49f7543ef..eb8360b33aa9 100644 --- a/arch/arm/mach-davinci/pm.c +++ b/arch/arm/mach-davinci/pm.c @@ -152,8 +152,7 @@ static struct platform_driver davinci_pm_driver = { .remove = __exit_p(davinci_pm_remove), }; -static int __init davinci_pm_init(void) +int __init davinci_pm_init(void) { return platform_driver_probe(&davinci_pm_driver, davinci_pm_probe); } -late_initcall(davinci_pm_init); diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index 42ab1e7c4ecc..9493076fc594 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -13,7 +13,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/pci.h> -#include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/ata_platform.h> #include <linux/gpio.h> #include <asm/page.h> @@ -68,6 +68,19 @@ void __init dove_map_io(void) } /***************************************************************************** + * CLK tree + ****************************************************************************/ +static struct clk *tclk; + +static void __init clk_init(void) +{ + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, + get_tclk()); + + orion_clkdev_init(tclk); +} + +/***************************************************************************** * EHCI0 ****************************************************************************/ void __init dove_ehci0_init(void) @@ -89,8 +102,7 @@ void __init dove_ehci1_init(void) void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, - DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, - 0, get_tclk()); + DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, 0); } /***************************************************************************** @@ -116,7 +128,7 @@ void __init dove_sata_init(struct mv_sata_platform_data *sata_data) void __init dove_uart0_init(void) { orion_uart0_init(DOVE_UART0_VIRT_BASE, DOVE_UART0_PHYS_BASE, - IRQ_DOVE_UART_0, get_tclk()); + IRQ_DOVE_UART_0, tclk); } /***************************************************************************** @@ -125,7 +137,7 @@ void __init dove_uart0_init(void) void __init dove_uart1_init(void) { orion_uart1_init(DOVE_UART1_VIRT_BASE, DOVE_UART1_PHYS_BASE, - IRQ_DOVE_UART_1, get_tclk()); + IRQ_DOVE_UART_1, tclk); } /***************************************************************************** @@ -134,7 +146,7 @@ void __init dove_uart1_init(void) void __init dove_uart2_init(void) { orion_uart2_init(DOVE_UART2_VIRT_BASE, DOVE_UART2_PHYS_BASE, - IRQ_DOVE_UART_2, get_tclk()); + IRQ_DOVE_UART_2, tclk); } /***************************************************************************** @@ -143,7 +155,7 @@ void __init dove_uart2_init(void) void __init dove_uart3_init(void) { orion_uart3_init(DOVE_UART3_VIRT_BASE, DOVE_UART3_PHYS_BASE, - IRQ_DOVE_UART_3, get_tclk()); + IRQ_DOVE_UART_3, tclk); } /***************************************************************************** @@ -151,12 +163,12 @@ void __init dove_uart3_init(void) ****************************************************************************/ void __init dove_spi0_init(void) { - orion_spi_init(DOVE_SPI0_PHYS_BASE, get_tclk()); + orion_spi_init(DOVE_SPI0_PHYS_BASE); } void __init dove_spi1_init(void) { - orion_spi_1_init(DOVE_SPI1_PHYS_BASE, get_tclk()); + orion_spi_1_init(DOVE_SPI1_PHYS_BASE); } /***************************************************************************** @@ -272,18 +284,17 @@ void __init dove_sdio1_init(void) void __init dove_init(void) { - int tclk; - - tclk = get_tclk(); - printk(KERN_INFO "Dove 88AP510 SoC, "); - printk(KERN_INFO "TCLK = %dMHz\n", (tclk + 499999) / 1000000); + printk(KERN_INFO "TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000); #ifdef CONFIG_CACHE_TAUROS2 tauros2_init(); #endif dove_setup_cpu_mbus(); + /* Setup root of clk tree */ + clk_init(); + /* internal devices that every board has */ dove_rtc_init(); dove_xor0_init(); diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c index ea77ae430b2d..bc2867f11346 100644 --- a/arch/arm/mach-dove/dove-db-setup.c +++ b/arch/arm/mach-dove/dove-db-setup.c @@ -20,7 +20,6 @@ #include <linux/i2c.h> #include <linux/pci.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/spi/flash.h> #include <linux/gpio.h> #include <asm/mach-types.h> diff --git a/arch/arm/mach-ep93xx/adssphere.c b/arch/arm/mach-ep93xx/adssphere.c index 2d45947a3034..a472777e9eba 100644 --- a/arch/arm/mach-ep93xx/adssphere.c +++ b/arch/arm/mach-ep93xx/adssphere.c @@ -41,5 +41,6 @@ MACHINE_START(ADSSPHERE, "ADS Sphere board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = adssphere_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 66b1494f23a6..4dd07a0e3604 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)); } @@ -834,3 +834,8 @@ void ep93xx_restart(char mode, const char *cmd) while (1) ; } + +void __init ep93xx_init_late(void) +{ + crunch_init(); +} diff --git a/arch/arm/mach-ep93xx/crunch.c b/arch/arm/mach-ep93xx/crunch.c index 74753e2df603..a4a2ab9648c9 100644 --- a/arch/arm/mach-ep93xx/crunch.c +++ b/arch/arm/mach-ep93xx/crunch.c @@ -79,12 +79,10 @@ static struct notifier_block crunch_notifier_block = { .notifier_call = crunch_do, }; -static int __init crunch_init(void) +int __init crunch_init(void) { thread_register_notifier(&crunch_notifier_block); elf_hwcap |= HWCAP_CRUNCH; return 0; } - -late_initcall(crunch_init); diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index da9047d726f0..d74c5cddb98b 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -255,6 +255,7 @@ MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -268,6 +269,7 @@ MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -281,6 +283,7 @@ MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -294,6 +297,7 @@ MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -307,6 +311,7 @@ MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -320,6 +325,7 @@ MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -333,6 +339,7 @@ MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -346,6 +353,7 @@ MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = edb93xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c index fcdffbe49dcc..437c34111155 100644 --- a/arch/arm/mach-ep93xx/gesbc9312.c +++ b/arch/arm/mach-ep93xx/gesbc9312.c @@ -41,5 +41,6 @@ MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = gesbc9312_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index 602bd87fd0ab..1ecb040d98bf 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h @@ -53,5 +53,12 @@ void ep93xx_init_devices(void); extern struct sys_timer ep93xx_timer; void ep93xx_restart(char, const char *); +void ep93xx_init_late(void); + +#ifdef CONFIG_CRUNCH +int crunch_init(void); +#else +static inline int crunch_init(void) { return 0; } +#endif #endif diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c index dc431c5f04ce..3d7cdab725b2 100644 --- a/arch/arm/mach-ep93xx/micro9.c +++ b/arch/arm/mach-ep93xx/micro9.c @@ -85,6 +85,7 @@ MACHINE_START(MICRO9, "Contec Micro9-High") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -98,6 +99,7 @@ MACHINE_START(MICRO9M, "Contec Micro9-Mid") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -111,6 +113,7 @@ MACHINE_START(MICRO9L, "Contec Micro9-Lite") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif @@ -124,6 +127,7 @@ MACHINE_START(MICRO9S, "Contec Micro9-Slim") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = micro9_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END #endif diff --git a/arch/arm/mach-ep93xx/simone.c b/arch/arm/mach-ep93xx/simone.c index f40c2987e545..33dc07917417 100644 --- a/arch/arm/mach-ep93xx/simone.c +++ b/arch/arm/mach-ep93xx/simone.c @@ -86,5 +86,6 @@ MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = simone_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c index 0c00852ef160..eb282378fa78 100644 --- a/arch/arm/mach-ep93xx/snappercl15.c +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -183,5 +183,6 @@ MACHINE_START(SNAPPER_CL15, "Bluewater Systems Snapper CL15") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = snappercl15_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 5ea790942e94..d4ef339d961e 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -252,5 +252,6 @@ MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = ts72xx_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index ba156eb225e8..2905a4929bdc 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -367,5 +367,6 @@ MACHINE_START(VISION_EP9307, "Vision Engraving Systems EP9307") .handle_irq = vic_handle_irq, .timer = &ep93xx_timer, .init_machine = vision_init_machine, + .init_late = ep93xx_init_late, .restart = ep93xx_restart, MACHINE_END diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 15b05b89cc39..43ebe9094411 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -61,6 +61,7 @@ config SOC_EXYNOS5250 bool "SAMSUNG EXYNOS5250" default y depends on ARCH_EXYNOS5 + select SAMSUNG_DMADEV help Enable EXYNOS5250 SoC support @@ -70,7 +71,7 @@ config EXYNOS4_MCT help Use MCT (Multi Core Timer) as kernel timers -config EXYNOS4_DEV_DMA +config EXYNOS_DEV_DMA bool help Compile in amba device definitions for DMA controller @@ -80,15 +81,20 @@ config EXYNOS4_DEV_AHCI help Compile in platform device definitions for AHCI +config EXYNOS_DEV_DRM + bool + help + Compile in platform device definitions for core DRM device + config EXYNOS4_SETUP_FIMD0 bool 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 @@ -161,7 +167,7 @@ config EXYNOS4_SETUP_USB_PHY help Common setup code for USB PHY controller -config EXYNOS4_SETUP_SPI +config EXYNOS_SETUP_SPI bool help Common setup code for SPI GPIO configurations. @@ -201,12 +207,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 @@ -224,8 +230,7 @@ config MACH_ARMLEX4210 select S3C_DEV_HSMMC2 select S3C_DEV_HSMMC3 select EXYNOS4_DEV_AHCI - select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_SYSMMU + select EXYNOS_DEV_DMA select EXYNOS4_SETUP_SDHCI help Machine support for Samsung ARMLEX4210 based on EXYNOS4210 @@ -256,6 +261,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 +338,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,7 +367,8 @@ config MACH_SMDK4212 select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_KEYPAD select SAMSUNG_DEV_PWM - select EXYNOS4_DEV_DMA + select EXYNOS_DEV_SYSMMU + select EXYNOS_DEV_DMA select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_I2C3 select EXYNOS4_SETUP_I2C7 diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 8631840d1b5e..440a637c76f1 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -50,10 +50,11 @@ 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_EXYNOS4_DEV_DWMCI) += dev-dwmci.o -obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o +obj-$(CONFIG_EXYNOS_DEV_DMA) += dma.o obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o +obj-$(CONFIG_EXYNOS_DEV_DRM) += dev-drm.o +obj-$(CONFIG_EXYNOS_DEV_SYSMMU) += dev-sysmmu.o obj-$(CONFIG_ARCH_EXYNOS) += setup-i2c0.o obj-$(CONFIG_EXYNOS4_SETUP_FIMC) += setup-fimc.o @@ -68,4 +69,4 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o obj-$(CONFIG_EXYNOS4_SETUP_USB_PHY) += setup-usb-phy.o -obj-$(CONFIG_EXYNOS4_SETUP_SPI) += setup-spi.o +obj-$(CONFIG_EXYNOS_SETUP_SPI) += setup-spi.o diff --git a/arch/arm/mach-exynos/Makefile.boot b/arch/arm/mach-exynos/Makefile.boot index b9862e22bf10..31bd181b0514 100644 --- a/arch/arm/mach-exynos/Makefile.boot +++ b/arch/arm/mach-exynos/Makefile.boot @@ -1,2 +1,5 @@ zreladdr-y += 0x40008000 params_phys-y := 0x40000100 + +dtb-$(CONFIG_MACH_EXYNOS4_DT) += exynos4210-origen.dtb exynos4210-smdkv310.dtb +dtb-$(CONFIG_MACH_EXYNOS5_DT) += exynos5250-smdk5250.dtb 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..da397d21bbcf 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,32 @@ 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), + }, { + .name = "flite", + .devname = "exynos-fimc-lite.0", + .enable = exynos4212_clk_ip_isp0_ctrl, + .ctrlbit = (1 << 4), + }, { + .name = "flite", + .devname = "exynos-fimc-lite.1", + .enable = exynos4212_clk_ip_isp0_ctrl, + .ctrlbit = (1 << 3), + } }; #ifdef CONFIG_PM_SLEEP diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c index 7ac6ff4c46bd..5aa460b01fdf 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 = { @@ -145,11 +165,29 @@ static struct clksrc_clk exynos5_clk_sclk_apll = { .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 24, .size = 3 }, }; +static struct clksrc_clk exynos5_clk_mout_bpll_fout = { + .clk = { + .name = "mout_bpll_fout", + }, + .sources = &clk_src_bpll_fout, + .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 0, .size = 1 }, +}; + +static struct clk *exynos5_clk_src_bpll_list[] = { + [0] = &clk_fin_bpll, + [1] = &exynos5_clk_mout_bpll_fout.clk, +}; + +static struct clksrc_sources exynos5_clk_src_bpll = { + .sources = exynos5_clk_src_bpll_list, + .nr_sources = ARRAY_SIZE(exynos5_clk_src_bpll_list), +}; + static struct clksrc_clk exynos5_clk_mout_bpll = { .clk = { .name = "mout_bpll", }, - .sources = &clk_src_bpll, + .sources = &exynos5_clk_src_bpll, .reg_src = { .reg = EXYNOS5_CLKSRC_CDREX, .shift = 0, .size = 1 }, }; @@ -187,11 +225,29 @@ static struct clksrc_clk exynos5_clk_mout_epll = { .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 12, .size = 1 }, }; +static struct clksrc_clk exynos5_clk_mout_mpll_fout = { + .clk = { + .name = "mout_mpll_fout", + }, + .sources = &clk_src_mpll_fout, + .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 4, .size = 1 }, +}; + +static struct clk *exynos5_clk_src_mpll_list[] = { + [0] = &clk_fin_mpll, + [1] = &exynos5_clk_mout_mpll_fout.clk, +}; + +static struct clksrc_sources exynos5_clk_src_mpll = { + .sources = exynos5_clk_src_mpll_list, + .nr_sources = ARRAY_SIZE(exynos5_clk_src_mpll_list), +}; + struct clksrc_clk exynos5_clk_mout_mpll = { .clk = { .name = "mout_mpll", }, - .sources = &clk_src_mpll, + .sources = &exynos5_clk_src_mpll, .reg_src = { .reg = EXYNOS5_CLKSRC_CORE1, .shift = 8, .size = 1 }, }; @@ -454,6 +510,11 @@ static struct clk exynos5_init_clocks_off[] = { .enable = exynos5_clk_ip_peris_ctrl, .ctrlbit = (1 << 20), }, { + .name = "watchdog", + .parent = &exynos5_clk_aclk_66.clk, + .enable = exynos5_clk_ip_peris_ctrl, + .ctrlbit = (1 << 19), + }, { .name = "hsmmc", .devname = "exynos4-sdhci.0", .parent = &exynos5_clk_aclk_200.clk, @@ -630,6 +691,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) } }; @@ -941,10 +1072,12 @@ static struct clksrc_clk *exynos5_sysclks[] = { &exynos5_clk_mout_apll, &exynos5_clk_sclk_apll, &exynos5_clk_mout_bpll, + &exynos5_clk_mout_bpll_fout, &exynos5_clk_mout_bpll_user, &exynos5_clk_mout_cpll, &exynos5_clk_mout_epll, &exynos5_clk_mout_mpll, + &exynos5_clk_mout_mpll_fout, &exynos5_clk_mout_mpll_user, &exynos5_clk_vpllsrc, &exynos5_clk_sclk_vpll, @@ -1008,7 +1141,9 @@ static struct clk *exynos5_clks[] __initdata = { &exynos5_clk_sclk_hdmi27m, &exynos5_clk_sclk_hdmiphy, &clk_fout_bpll, + &clk_fout_bpll_div2, &clk_fout_cpll, + &clk_fout_mpll_div2, &exynos5_clk_armclk, }; @@ -1173,8 +1308,10 @@ void __init_or_cpufreq exynos5_setup_clocks(void) clk_fout_apll.ops = &exynos5_fout_apll_ops; clk_fout_bpll.rate = bpll; + clk_fout_bpll_div2.rate = bpll >> 1; clk_fout_cpll.rate = cpll; clk_fout_mpll.rate = mpll; + clk_fout_mpll_div2.rate = mpll >> 1; clk_fout_epll.rate = epll; clk_fout_vpll.rate = vpll; diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 5ccd6e80a607..742edd3bbec3 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -19,6 +19,9 @@ #include <linux/serial_core.h> #include <linux/of.h> #include <linux/of_irq.h> +#include <linux/export.h> +#include <linux/irqdomain.h> +#include <linux/of_address.h> #include <asm/proc-fns.h> #include <asm/exception.h> @@ -265,12 +268,12 @@ static struct map_desc exynos5_iodesc[] __initdata = { }, { .virtual = (unsigned long)S5P_VA_GIC_CPU, .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_CPU), - .length = SZ_64K, + .length = SZ_8K, .type = MT_DEVICE, }, { .virtual = (unsigned long)S5P_VA_GIC_DIST, .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_DIST), - .length = SZ_64K, + .length = SZ_4K, .type = MT_DEVICE, }, }; @@ -285,6 +288,11 @@ void exynos5_restart(char mode, const char *cmd) __raw_writel(0x1, EXYNOS_SWRESET); } +void __init exynos_init_late(void) +{ + exynos_pm_late_initcall(); +} + /* * exynos_map_io * @@ -399,6 +407,7 @@ struct combiner_chip_data { void __iomem *base; }; +static struct irq_domain *combiner_irq_domain; static struct combiner_chip_data combiner_data[MAX_COMBINER_NR]; static inline void __iomem *combiner_base(struct irq_data *data) @@ -411,14 +420,14 @@ static inline void __iomem *combiner_base(struct irq_data *data) static void combiner_mask_irq(struct irq_data *data) { - u32 mask = 1 << (data->irq % 32); + u32 mask = 1 << (data->hwirq % 32); __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR); } static void combiner_unmask_irq(struct irq_data *data) { - u32 mask = 1 << (data->irq % 32); + u32 mask = 1 << (data->hwirq % 32); __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); } @@ -474,49 +483,131 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i irq_set_chained_handler(irq, combiner_handle_cascade_irq); } -static void __init combiner_init(unsigned int combiner_nr, void __iomem *base, - unsigned int irq_start) +static void __init combiner_init_one(unsigned int combiner_nr, + void __iomem *base) { - unsigned int i; - unsigned int max_nr; - - if (soc_is_exynos5250()) - max_nr = EXYNOS5_MAX_COMBINER_NR; - else - max_nr = EXYNOS4_MAX_COMBINER_NR; - - if (combiner_nr >= max_nr) - BUG(); - combiner_data[combiner_nr].base = base; - combiner_data[combiner_nr].irq_offset = irq_start; + combiner_data[combiner_nr].irq_offset = irq_find_mapping( + combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER); combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); /* Disable all interrupts */ - __raw_writel(combiner_data[combiner_nr].irq_mask, base + COMBINER_ENABLE_CLEAR); +} + +#ifdef CONFIG_OF +static int combiner_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + if (d->of_node != controller) + return -EINVAL; + + if (intsize < 2) + return -EINVAL; + + *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1]; + *out_type = 0; + + return 0; +} +#else +static int combiner_irq_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + return -EINVAL; +} +#endif + +static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq); + irq_set_chip_data(irq, &combiner_data[hw >> 3]); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +static struct irq_domain_ops combiner_irq_domain_ops = { + .xlate = combiner_irq_domain_xlate, + .map = combiner_irq_domain_map, +}; + +void __init combiner_init(void __iomem *combiner_base, struct device_node *np) +{ + int i, irq, irq_base; + unsigned int max_nr, nr_irq; + + if (np) { + if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { + pr_warning("%s: number of combiners not specified, " + "setting default as %d.\n", + __func__, EXYNOS4_MAX_COMBINER_NR); + max_nr = EXYNOS4_MAX_COMBINER_NR; + } + } else { + max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : + EXYNOS4_MAX_COMBINER_NR; + } + nr_irq = max_nr * MAX_IRQ_IN_COMBINER; - /* Setup the Linux IRQ subsystem */ + irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); + if (IS_ERR_VALUE(irq_base)) { + irq_base = COMBINER_IRQ(0, 0); + pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base); + } - for (i = irq_start; i < combiner_data[combiner_nr].irq_offset - + MAX_IRQ_IN_COMBINER; i++) { - irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq); - irq_set_chip_data(i, &combiner_data[combiner_nr]); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0, + &combiner_irq_domain_ops, &combiner_data); + if (WARN_ON(!combiner_irq_domain)) { + pr_warning("%s: irq domain init failed\n", __func__); + return; + } + + for (i = 0; i < max_nr; i++) { + combiner_init_one(i, combiner_base + (i >> 2) * 0x10); + irq = IRQ_SPI(i); +#ifdef CONFIG_OF + if (np) + irq = irq_of_parse_and_map(np, i); +#endif + combiner_cascade_irq(i, irq); } } #ifdef CONFIG_OF +int __init combiner_of_init(struct device_node *np, struct device_node *parent) +{ + void __iomem *combiner_base; + + combiner_base = of_iomap(np, 0); + if (!combiner_base) { + pr_err("%s: failed to map combiner registers\n", __func__); + return -ENXIO; + } + + combiner_init(combiner_base, np); + + return 0; +} + static const struct of_device_id exynos4_dt_irq_match[] = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, + { .compatible = "samsung,exynos4210-combiner", + .data = combiner_of_init, }, {}, }; #endif void __init exynos4_init_irq(void) { - int irq; unsigned int gic_bank_offset; gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000; @@ -528,12 +619,8 @@ void __init exynos4_init_irq(void) of_irq_init(exynos4_dt_irq_match); #endif - for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) { - - combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq), - COMBINER_IRQ(irq, 0)); - combiner_cascade_irq(irq, IRQ_SPI(irq)); - } + if (!of_have_populated_dt()) + combiner_init(S5P_VA_COMBINER_BASE, NULL); /* * The parameters of s5p_init_irq() are for VIC init. @@ -545,18 +632,9 @@ void __init exynos4_init_irq(void) void __init exynos5_init_irq(void) { - int irq; - #ifdef CONFIG_OF of_irq_init(exynos4_dt_irq_match); #endif - - for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) { - combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq), - COMBINER_IRQ(irq, 0)); - combiner_cascade_irq(irq, IRQ_SPI(irq)); - } - /* * The parameters of s5p_init_irq() are for VIC init. * Theses parameters should be NULL and 0 because EXYNOS4 @@ -565,30 +643,18 @@ void __init exynos5_init_irq(void) s5p_init_irq(NULL, 0); } -struct bus_type exynos4_subsys = { - .name = "exynos4-core", - .dev_name = "exynos4-core", -}; - -struct bus_type exynos5_subsys = { - .name = "exynos5-core", - .dev_name = "exynos5-core", +struct bus_type exynos_subsys = { + .name = "exynos-core", + .dev_name = "exynos-core", }; static struct device exynos4_dev = { - .bus = &exynos4_subsys, -}; - -static struct device exynos5_dev = { - .bus = &exynos5_subsys, + .bus = &exynos_subsys, }; static int __init exynos_core_init(void) { - if (soc_is_exynos5250()) - return subsys_system_register(&exynos5_subsys, NULL); - else - return subsys_system_register(&exynos4_subsys, NULL); + return subsys_system_register(&exynos_subsys, NULL); } core_initcall(exynos_core_init); @@ -675,10 +741,7 @@ static int __init exynos_init(void) { printk(KERN_INFO "EXYNOS: Initializing architecture\n"); - if (soc_is_exynos5250()) - return device_register(&exynos5_dev); - else - return device_register(&exynos4_dev); + return device_register(&exynos4_dev); } /* uart registration process */ diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 677b5467df18..aed2eeb06517 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -19,6 +19,13 @@ void exynos4_init_irq(void); void exynos5_init_irq(void); void exynos4_restart(char mode, const char *cmd); void exynos5_restart(char mode, const char *cmd); +void exynos_init_late(void); + +#ifdef CONFIG_PM_GENERIC_DOMAINS +int exynos_pm_late_initcall(void); +#else +static int exynos_pm_late_initcall(void) { return 0; } +#endif #ifdef CONFIG_ARCH_EXYNOS4 void exynos4_register_clocks(void); diff --git a/arch/arm/mach-exynos/dev-drm.c b/arch/arm/mach-exynos/dev-drm.c new file mode 100644 index 000000000000..17c9c6ecc2e0 --- /dev/null +++ b/arch/arm/mach-exynos/dev-drm.c @@ -0,0 +1,29 @@ +/* + * linux/arch/arm/mach-exynos/dev-drm.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - core DRM device + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> + +#include <plat/devs.h> + +static u64 exynos_drm_dma_mask = DMA_BIT_MASK(32); + +struct platform_device exynos_device_drm = { + .name = "exynos-drm", + .dev = { + .dma_mask = &exynos_drm_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; 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/dma.c b/arch/arm/mach-exynos/dma.c index 69aaa4503205..f60b66dbcf84 100644 --- a/arch/arm/mach-exynos/dma.c +++ b/arch/arm/mach-exynos/dma.c @@ -103,10 +103,45 @@ static u8 exynos4212_pdma0_peri[] = { DMACH_MIPI_HSI5, }; -struct dma_pl330_platdata exynos4_pdma0_pdata; +static u8 exynos5250_pdma0_peri[] = { + DMACH_PCM0_RX, + DMACH_PCM0_TX, + DMACH_PCM2_RX, + DMACH_PCM2_TX, + DMACH_SPI0_RX, + DMACH_SPI0_TX, + DMACH_SPI2_RX, + DMACH_SPI2_TX, + DMACH_I2S0S_TX, + DMACH_I2S0_RX, + DMACH_I2S0_TX, + DMACH_I2S2_RX, + DMACH_I2S2_TX, + DMACH_UART0_RX, + DMACH_UART0_TX, + DMACH_UART2_RX, + DMACH_UART2_TX, + DMACH_UART4_RX, + DMACH_UART4_TX, + DMACH_SLIMBUS0_RX, + DMACH_SLIMBUS0_TX, + DMACH_SLIMBUS2_RX, + DMACH_SLIMBUS2_TX, + DMACH_SLIMBUS4_RX, + DMACH_SLIMBUS4_TX, + DMACH_AC97_MICIN, + DMACH_AC97_PCMIN, + DMACH_AC97_PCMOUT, + DMACH_MIPI_HSI0, + DMACH_MIPI_HSI2, + DMACH_MIPI_HSI4, + DMACH_MIPI_HSI6, +}; + +static struct dma_pl330_platdata exynos_pdma0_pdata; -static AMBA_AHB_DEVICE(exynos4_pdma0, "dma-pl330.0", 0x00041330, - EXYNOS4_PA_PDMA0, {EXYNOS4_IRQ_PDMA0}, &exynos4_pdma0_pdata); +static AMBA_AHB_DEVICE(exynos_pdma0, "dma-pl330.0", 0x00041330, + EXYNOS4_PA_PDMA0, {EXYNOS4_IRQ_PDMA0}, &exynos_pdma0_pdata); static u8 exynos4210_pdma1_peri[] = { DMACH_PCM0_RX, @@ -169,10 +204,45 @@ static u8 exynos4212_pdma1_peri[] = { DMACH_MIPI_HSI7, }; -static struct dma_pl330_platdata exynos4_pdma1_pdata; +static u8 exynos5250_pdma1_peri[] = { + DMACH_PCM0_RX, + DMACH_PCM0_TX, + DMACH_PCM1_RX, + DMACH_PCM1_TX, + DMACH_SPI1_RX, + DMACH_SPI1_TX, + DMACH_PWM, + DMACH_SPDIF, + DMACH_I2S0S_TX, + DMACH_I2S0_RX, + DMACH_I2S0_TX, + DMACH_I2S1_RX, + DMACH_I2S1_TX, + DMACH_UART0_RX, + DMACH_UART0_TX, + DMACH_UART1_RX, + DMACH_UART1_TX, + DMACH_UART3_RX, + DMACH_UART3_TX, + DMACH_SLIMBUS1_RX, + DMACH_SLIMBUS1_TX, + DMACH_SLIMBUS3_RX, + DMACH_SLIMBUS3_TX, + DMACH_SLIMBUS5_RX, + DMACH_SLIMBUS5_TX, + DMACH_SLIMBUS0AUX_RX, + DMACH_SLIMBUS0AUX_TX, + DMACH_DISP1, + DMACH_MIPI_HSI1, + DMACH_MIPI_HSI3, + DMACH_MIPI_HSI5, + DMACH_MIPI_HSI7, +}; -static AMBA_AHB_DEVICE(exynos4_pdma1, "dma-pl330.1", 0x00041330, - EXYNOS4_PA_PDMA1, {EXYNOS4_IRQ_PDMA1}, &exynos4_pdma1_pdata); +static struct dma_pl330_platdata exynos_pdma1_pdata; + +static AMBA_AHB_DEVICE(exynos_pdma1, "dma-pl330.1", 0x00041330, + EXYNOS4_PA_PDMA1, {EXYNOS4_IRQ_PDMA1}, &exynos_pdma1_pdata); static u8 mdma_peri[] = { DMACH_MTOM_0, @@ -185,46 +255,63 @@ static u8 mdma_peri[] = { DMACH_MTOM_7, }; -static struct dma_pl330_platdata exynos4_mdma1_pdata = { +static struct dma_pl330_platdata exynos_mdma1_pdata = { .nr_valid_peri = ARRAY_SIZE(mdma_peri), .peri_id = mdma_peri, }; -static AMBA_AHB_DEVICE(exynos4_mdma1, "dma-pl330.2", 0x00041330, - EXYNOS4_PA_MDMA1, {EXYNOS4_IRQ_MDMA1}, &exynos4_mdma1_pdata); +static AMBA_AHB_DEVICE(exynos_mdma1, "dma-pl330.2", 0x00041330, + EXYNOS4_PA_MDMA1, {EXYNOS4_IRQ_MDMA1}, &exynos_mdma1_pdata); -static int __init exynos4_dma_init(void) +static int __init exynos_dma_init(void) { if (of_have_populated_dt()) return 0; if (soc_is_exynos4210()) { - exynos4_pdma0_pdata.nr_valid_peri = + exynos_pdma0_pdata.nr_valid_peri = ARRAY_SIZE(exynos4210_pdma0_peri); - exynos4_pdma0_pdata.peri_id = exynos4210_pdma0_peri; - exynos4_pdma1_pdata.nr_valid_peri = + exynos_pdma0_pdata.peri_id = exynos4210_pdma0_peri; + exynos_pdma1_pdata.nr_valid_peri = ARRAY_SIZE(exynos4210_pdma1_peri); - exynos4_pdma1_pdata.peri_id = exynos4210_pdma1_peri; + exynos_pdma1_pdata.peri_id = exynos4210_pdma1_peri; } else if (soc_is_exynos4212() || soc_is_exynos4412()) { - exynos4_pdma0_pdata.nr_valid_peri = + exynos_pdma0_pdata.nr_valid_peri = ARRAY_SIZE(exynos4212_pdma0_peri); - exynos4_pdma0_pdata.peri_id = exynos4212_pdma0_peri; - exynos4_pdma1_pdata.nr_valid_peri = + exynos_pdma0_pdata.peri_id = exynos4212_pdma0_peri; + exynos_pdma1_pdata.nr_valid_peri = ARRAY_SIZE(exynos4212_pdma1_peri); - exynos4_pdma1_pdata.peri_id = exynos4212_pdma1_peri; + exynos_pdma1_pdata.peri_id = exynos4212_pdma1_peri; + } else if (soc_is_exynos5250()) { + exynos_pdma0_pdata.nr_valid_peri = + ARRAY_SIZE(exynos5250_pdma0_peri); + exynos_pdma0_pdata.peri_id = exynos5250_pdma0_peri; + exynos_pdma1_pdata.nr_valid_peri = + ARRAY_SIZE(exynos5250_pdma1_peri); + exynos_pdma1_pdata.peri_id = exynos5250_pdma1_peri; + + exynos_pdma0_device.res.start = EXYNOS5_PA_PDMA0; + exynos_pdma0_device.res.end = EXYNOS5_PA_PDMA0 + SZ_4K; + exynos_pdma0_device.irq[0] = EXYNOS5_IRQ_PDMA0; + exynos_pdma1_device.res.start = EXYNOS5_PA_PDMA1; + exynos_pdma1_device.res.end = EXYNOS5_PA_PDMA1 + SZ_4K; + exynos_pdma0_device.irq[0] = EXYNOS5_IRQ_PDMA1; + exynos_mdma1_device.res.start = EXYNOS5_PA_MDMA1; + exynos_mdma1_device.res.end = EXYNOS5_PA_MDMA1 + SZ_4K; + exynos_pdma0_device.irq[0] = EXYNOS5_IRQ_MDMA1; } - dma_cap_set(DMA_SLAVE, exynos4_pdma0_pdata.cap_mask); - dma_cap_set(DMA_CYCLIC, exynos4_pdma0_pdata.cap_mask); - amba_device_register(&exynos4_pdma0_device, &iomem_resource); + dma_cap_set(DMA_SLAVE, exynos_pdma0_pdata.cap_mask); + dma_cap_set(DMA_CYCLIC, exynos_pdma0_pdata.cap_mask); + amba_device_register(&exynos_pdma0_device, &iomem_resource); - dma_cap_set(DMA_SLAVE, exynos4_pdma1_pdata.cap_mask); - dma_cap_set(DMA_CYCLIC, exynos4_pdma1_pdata.cap_mask); - amba_device_register(&exynos4_pdma1_device, &iomem_resource); + dma_cap_set(DMA_SLAVE, exynos_pdma1_pdata.cap_mask); + dma_cap_set(DMA_CYCLIC, exynos_pdma1_pdata.cap_mask); + amba_device_register(&exynos_pdma1_device, &iomem_resource); - dma_cap_set(DMA_MEMCPY, exynos4_mdma1_pdata.cap_mask); - amba_device_register(&exynos4_mdma1_device, &iomem_resource); + dma_cap_set(DMA_MEMCPY, exynos_mdma1_pdata.cap_mask); + amba_device_register(&exynos_mdma1_device, &iomem_resource); return 0; } -arch_initcall(exynos4_dma_init); +arch_initcall(exynos_dma_init); diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h index d7498afe036a..eb24f1eb8e3b 100644 --- a/arch/arm/mach-exynos/include/mach/gpio.h +++ b/arch/arm/mach-exynos/include/mach/gpio.h @@ -153,10 +153,11 @@ enum exynos4_gpio_number { #define EXYNOS5_GPIO_B2_NR (4) #define EXYNOS5_GPIO_B3_NR (4) #define EXYNOS5_GPIO_C0_NR (7) -#define EXYNOS5_GPIO_C1_NR (7) +#define EXYNOS5_GPIO_C1_NR (4) #define EXYNOS5_GPIO_C2_NR (7) #define EXYNOS5_GPIO_C3_NR (7) -#define EXYNOS5_GPIO_D0_NR (8) +#define EXYNOS5_GPIO_C4_NR (7) +#define EXYNOS5_GPIO_D0_NR (4) #define EXYNOS5_GPIO_D1_NR (8) #define EXYNOS5_GPIO_Y0_NR (6) #define EXYNOS5_GPIO_Y1_NR (4) @@ -199,7 +200,8 @@ enum exynos5_gpio_number { EXYNOS5_GPIO_C1_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C0), EXYNOS5_GPIO_C2_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C1), EXYNOS5_GPIO_C3_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C2), - EXYNOS5_GPIO_D0_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C3), + EXYNOS5_GPIO_C4_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C3), + EXYNOS5_GPIO_D0_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C4), EXYNOS5_GPIO_D1_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D0), EXYNOS5_GPIO_Y0_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D1), EXYNOS5_GPIO_Y1_START = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y0), @@ -242,6 +244,7 @@ enum exynos5_gpio_number { #define EXYNOS5_GPC1(_nr) (EXYNOS5_GPIO_C1_START + (_nr)) #define EXYNOS5_GPC2(_nr) (EXYNOS5_GPIO_C2_START + (_nr)) #define EXYNOS5_GPC3(_nr) (EXYNOS5_GPIO_C3_START + (_nr)) +#define EXYNOS5_GPC4(_nr) (EXYNOS5_GPIO_C4_START + (_nr)) #define EXYNOS5_GPD0(_nr) (EXYNOS5_GPIO_D0_START + (_nr)) #define EXYNOS5_GPD1(_nr) (EXYNOS5_GPIO_D1_START + (_nr)) #define EXYNOS5_GPY0(_nr) (EXYNOS5_GPIO_Y0_START + (_nr)) diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h index c02dae7bf4a3..7a4b4789eb72 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 @@ -298,6 +287,7 @@ #define EXYNOS5_IRQ_MIPICSI1 IRQ_SPI(80) #define EXYNOS5_IRQ_EFNFCON_DMA_ABORT IRQ_SPI(81) #define EXYNOS5_IRQ_MIPIDSI0 IRQ_SPI(82) +#define EXYNOS5_IRQ_WDT_IOP IRQ_SPI(83) #define EXYNOS5_IRQ_ROTATOR IRQ_SPI(84) #define EXYNOS5_IRQ_GSC0 IRQ_SPI(85) #define EXYNOS5_IRQ_GSC1 IRQ_SPI(86) @@ -306,8 +296,8 @@ #define EXYNOS5_IRQ_JPEG IRQ_SPI(89) #define EXYNOS5_IRQ_EFNFCON_DMA IRQ_SPI(90) #define EXYNOS5_IRQ_2D IRQ_SPI(91) -#define EXYNOS5_IRQ_SFMC0 IRQ_SPI(92) -#define EXYNOS5_IRQ_SFMC1 IRQ_SPI(93) +#define EXYNOS5_IRQ_EFNFCON_0 IRQ_SPI(92) +#define EXYNOS5_IRQ_EFNFCON_1 IRQ_SPI(93) #define EXYNOS5_IRQ_MIXER IRQ_SPI(94) #define EXYNOS5_IRQ_HDMI IRQ_SPI(95) #define EXYNOS5_IRQ_MFC IRQ_SPI(96) @@ -321,7 +311,7 @@ #define EXYNOS5_IRQ_PCM2 IRQ_SPI(104) #define EXYNOS5_IRQ_SPDIF IRQ_SPI(105) #define EXYNOS5_IRQ_ADC0 IRQ_SPI(106) - +#define EXYNOS5_IRQ_ADC1 IRQ_SPI(107) #define EXYNOS5_IRQ_SATA_PHY IRQ_SPI(108) #define EXYNOS5_IRQ_SATA_PMEMREQ IRQ_SPI(109) #define EXYNOS5_IRQ_CAM_C IRQ_SPI(110) @@ -330,8 +320,9 @@ #define EXYNOS5_IRQ_DP1_INTP1 IRQ_SPI(113) #define EXYNOS5_IRQ_CEC IRQ_SPI(114) #define EXYNOS5_IRQ_SATA IRQ_SPI(115) -#define EXYNOS5_IRQ_NFCON IRQ_SPI(116) +#define EXYNOS5_IRQ_MCT_L0 IRQ_SPI(120) +#define EXYNOS5_IRQ_MCT_L1 IRQ_SPI(121) #define EXYNOS5_IRQ_MMC44 IRQ_SPI(123) #define EXYNOS5_IRQ_MDMA1 IRQ_SPI(124) #define EXYNOS5_IRQ_FIMC_LITE0 IRQ_SPI(125) @@ -339,7 +330,6 @@ #define EXYNOS5_IRQ_RP_TIMER IRQ_SPI(127) #define EXYNOS5_IRQ_PMU COMBINER_IRQ(1, 2) -#define EXYNOS5_IRQ_PMU_CPU1 COMBINER_IRQ(1, 6) #define EXYNOS5_IRQ_SYSMMU_GSC0_0 COMBINER_IRQ(2, 0) #define EXYNOS5_IRQ_SYSMMU_GSC0_1 COMBINER_IRQ(2, 1) @@ -350,6 +340,8 @@ #define EXYNOS5_IRQ_SYSMMU_GSC3_0 COMBINER_IRQ(2, 6) #define EXYNOS5_IRQ_SYSMMU_GSC3_1 COMBINER_IRQ(2, 7) +#define EXYNOS5_IRQ_SYSMMU_LITE2_0 COMBINER_IRQ(3, 0) +#define EXYNOS5_IRQ_SYSMMU_LITE2_1 COMBINER_IRQ(3, 1) #define EXYNOS5_IRQ_SYSMMU_FIMD1_0 COMBINER_IRQ(3, 2) #define EXYNOS5_IRQ_SYSMMU_FIMD1_1 COMBINER_IRQ(3, 3) #define EXYNOS5_IRQ_SYSMMU_LITE0_0 COMBINER_IRQ(3, 4) @@ -373,8 +365,8 @@ #define EXYNOS5_IRQ_SYSMMU_ARM_0 COMBINER_IRQ(6, 0) #define EXYNOS5_IRQ_SYSMMU_ARM_1 COMBINER_IRQ(6, 1) -#define EXYNOS5_IRQ_SYSMMU_MFC_L_0 COMBINER_IRQ(6, 2) -#define EXYNOS5_IRQ_SYSMMU_MFC_L_1 COMBINER_IRQ(6, 3) +#define EXYNOS5_IRQ_SYSMMU_MFC_R_0 COMBINER_IRQ(6, 2) +#define EXYNOS5_IRQ_SYSMMU_MFC_R_1 COMBINER_IRQ(6, 3) #define EXYNOS5_IRQ_SYSMMU_RTIC_0 COMBINER_IRQ(6, 4) #define EXYNOS5_IRQ_SYSMMU_RTIC_1 COMBINER_IRQ(6, 5) #define EXYNOS5_IRQ_SYSMMU_SSS_0 COMBINER_IRQ(6, 6) @@ -386,11 +378,9 @@ #define EXYNOS5_IRQ_SYSMMU_MDMA1_1 COMBINER_IRQ(7, 3) #define EXYNOS5_IRQ_SYSMMU_TV_0 COMBINER_IRQ(7, 4) #define EXYNOS5_IRQ_SYSMMU_TV_1 COMBINER_IRQ(7, 5) -#define EXYNOS5_IRQ_SYSMMU_GPSX_0 COMBINER_IRQ(7, 6) -#define EXYNOS5_IRQ_SYSMMU_GPSX_1 COMBINER_IRQ(7, 7) -#define EXYNOS5_IRQ_SYSMMU_MFC_R_0 COMBINER_IRQ(8, 5) -#define EXYNOS5_IRQ_SYSMMU_MFC_R_1 COMBINER_IRQ(8, 6) +#define EXYNOS5_IRQ_SYSMMU_MFC_L_0 COMBINER_IRQ(8, 5) +#define EXYNOS5_IRQ_SYSMMU_MFC_L_1 COMBINER_IRQ(8, 6) #define EXYNOS5_IRQ_SYSMMU_DIS1_0 COMBINER_IRQ(9, 4) #define EXYNOS5_IRQ_SYSMMU_DIS1_1 COMBINER_IRQ(9, 5) @@ -406,17 +396,24 @@ #define EXYNOS5_IRQ_SYSMMU_DRC_0 COMBINER_IRQ(11, 6) #define EXYNOS5_IRQ_SYSMMU_DRC_1 COMBINER_IRQ(11, 7) +#define EXYNOS5_IRQ_MDMA1_ABORT COMBINER_IRQ(13, 1) + +#define EXYNOS5_IRQ_MDMA0_ABORT COMBINER_IRQ(15, 3) + #define EXYNOS5_IRQ_FIMD1_FIFO COMBINER_IRQ(18, 4) #define EXYNOS5_IRQ_FIMD1_VSYNC COMBINER_IRQ(18, 5) #define EXYNOS5_IRQ_FIMD1_SYSTEM COMBINER_IRQ(18, 6) +#define EXYNOS5_IRQ_ARMIOP_GIC COMBINER_IRQ(19, 0) +#define EXYNOS5_IRQ_ARMISP_GIC COMBINER_IRQ(19, 1) +#define EXYNOS5_IRQ_IOP_GIC COMBINER_IRQ(19, 3) +#define EXYNOS5_IRQ_ISP_GIC COMBINER_IRQ(19, 4) + +#define EXYNOS5_IRQ_PMU_CPU1 COMBINER_IRQ(22, 4) + #define EXYNOS5_IRQ_EINT0 COMBINER_IRQ(23, 0) -#define EXYNOS5_IRQ_MCT_L0 COMBINER_IRQ(23, 1) -#define EXYNOS5_IRQ_MCT_L1 COMBINER_IRQ(23, 2) #define EXYNOS5_IRQ_MCT_G0 COMBINER_IRQ(23, 3) #define EXYNOS5_IRQ_MCT_G1 COMBINER_IRQ(23, 4) -#define EXYNOS5_IRQ_MCT_G2 COMBINER_IRQ(23, 5) -#define EXYNOS5_IRQ_MCT_G3 COMBINER_IRQ(23, 6) #define EXYNOS5_IRQ_EINT1 COMBINER_IRQ(24, 0) #define EXYNOS5_IRQ_SYSMMU_LITE1_0 COMBINER_IRQ(24, 1) @@ -447,7 +444,7 @@ #define EXYNOS5_MAX_COMBINER_NR 32 -#define EXYNOS5_IRQ_GPIO1_NR_GROUPS 13 +#define EXYNOS5_IRQ_GPIO1_NR_GROUPS 14 #define EXYNOS5_IRQ_GPIO2_NR_GROUPS 9 #define EXYNOS5_IRQ_GPIO3_NR_GROUPS 5 #define EXYNOS5_IRQ_GPIO4_NR_GROUPS 1 diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index e009a66477f4..ca4aa89aa46b 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -34,6 +34,9 @@ #define EXYNOS4_PA_JPEG 0x11840000 +/* x = 0...1 */ +#define EXYNOS4_PA_FIMC_LITE(x) (0x12390000 + ((x) * 0x10000)) + #define EXYNOS4_PA_G2D 0x12800000 #define EXYNOS4_PA_I2S0 0x03830000 @@ -78,8 +81,8 @@ #define EXYNOS4_PA_GIC_CPU 0x10480000 #define EXYNOS4_PA_GIC_DIST 0x10490000 -#define EXYNOS5_PA_GIC_CPU 0x10480000 -#define EXYNOS5_PA_GIC_DIST 0x10490000 +#define EXYNOS5_PA_GIC_CPU 0x10482000 +#define EXYNOS5_PA_GIC_DIST 0x10481000 #define EXYNOS4_PA_COREPERI 0x10500000 #define EXYNOS4_PA_TWD 0x10500600 @@ -95,6 +98,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 +107,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 +120,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..b78b5f3ad9c0 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) @@ -317,6 +322,8 @@ #define EXYNOS5_CLKSRC_CDREX EXYNOS_CLKREG(0x20200) #define EXYNOS5_CLKDIV_CDREX EXYNOS_CLKREG(0x20500) +#define EXYNOS5_PLL_DIV2_SEL EXYNOS_CLKREG(0x20A24) + #define EXYNOS5_EPLL_LOCK EXYNOS_CLKREG(0x10030) #define EXYNOS5_EPLLCON0_LOCKED_SHIFT (29) diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h index d457d052a420..4dbb8629b200 100644 --- a/arch/arm/mach-exynos/include/mach/regs-pmu.h +++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h @@ -180,7 +180,7 @@ #define S5P_PMU_LCD1_CONF S5P_PMUREG(0x3CA0) -/* Only for EXYNOS4212 */ +/* Only for EXYNOS4x12 */ #define S5P_ISP_ARM_LOWPWR S5P_PMUREG(0x1050) #define S5P_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR S5P_PMUREG(0x1054) #define S5P_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR S5P_PMUREG(0x1058) @@ -221,4 +221,12 @@ #define S5P_SECSS_MEM_OPTION S5P_PMUREG(0x2EC8) #define S5P_ROTATOR_MEM_OPTION S5P_PMUREG(0x2F48) +/* Only for EXYNOS4412 */ +#define S5P_ARM_CORE2_LOWPWR S5P_PMUREG(0x1020) +#define S5P_DIS_IRQ_CORE2 S5P_PMUREG(0x1024) +#define S5P_DIS_IRQ_CENTRAL2 S5P_PMUREG(0x1028) +#define S5P_ARM_CORE3_LOWPWR S5P_PMUREG(0x1030) +#define S5P_DIS_IRQ_CORE3 S5P_PMUREG(0x1034) +#define S5P_DIS_IRQ_CENTRAL3 S5P_PMUREG(0x1038) + #endif /* __ASM_ARCH_REGS_PMU_H */ 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/spi-clocks.h b/arch/arm/mach-exynos/include/mach/spi-clocks.h index 576efdf6d091..c71a5fba6a84 100644 --- a/arch/arm/mach-exynos/include/mach/spi-clocks.h +++ b/arch/arm/mach-exynos/include/mach/spi-clocks.h @@ -11,6 +11,6 @@ #define __ASM_ARCH_SPI_CLKS_H __FILE__ /* Must source from SCLK_SPI */ -#define EXYNOS4_SPI_SRCCLK_SCLK 0 +#define EXYNOS_SPI_SRCCLK_SCLK 0 #endif /* __ASM_ARCH_SPI_CLKS_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..5a3daa0168d8 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, @@ -204,6 +203,7 @@ MACHINE_START(ARMLEX4210, "ARMLEX4210") .map_io = armlex4210_map_io, .handle_irq = gic_handle_irq, .init_machine = armlex4210_machine_init, + .init_late = exynos_init_late, .timer = &exynos4_timer, .restart = exynos4_restart, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c index 8245f1c761d9..e7e9743543ac 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c @@ -83,6 +83,7 @@ DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)") .map_io = exynos4210_dt_map_io, .handle_irq = gic_handle_irq, .init_machine = exynos4210_dt_machine_init, + .init_late = exynos_init_late, .timer = &exynos4_timer, .dt_compat = exynos4210_dt_compat, .restart = exynos4_restart, diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index 4711c8920e37..7b1e11a228cc 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -43,6 +43,10 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { "exynos4210-uart.2", NULL), OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART3, "exynos4210-uart.3", NULL), + OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(0), + "s3c2440-i2c.0", NULL), + OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(1), + "s3c2440-i2c.1", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_MDMA1, "dma-pl330.2", NULL), @@ -72,6 +76,7 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)") .map_io = exynos5250_dt_map_io, .handle_irq = gic_handle_irq, .init_machine = exynos5250_dt_machine_init, + .init_late = exynos_init_late, .timer = &exynos4_timer, .dt_compat = exynos5250_dt_compat, .restart = exynos5_restart, diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 6c31f2ad765d..972983e392bc 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1389,6 +1389,7 @@ MACHINE_START(NURI, "NURI") .map_io = nuri_map_io, .handle_irq = gic_handle_irq, .init_machine = nuri_machine_init, + .init_late = exynos_init_late, .timer = &exynos4_timer, .reserve = &nuri_reserve, .restart = exynos4_restart, diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 26124a38bcbd..a7f7fd567dde 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -766,6 +766,7 @@ MACHINE_START(ORIGEN, "ORIGEN") .map_io = origen_map_io, .handle_irq = gic_handle_irq, .init_machine = origen_machine_init, + .init_late = exynos_init_late, .timer = &exynos4_timer, .reserve = &origen_reserve, .restart = exynos4_restart, diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c index fe772d893cc9..fb09c70e195a 100644 --- a/arch/arm/mach-exynos/mach-smdk4x12.c +++ b/arch/arm/mach-exynos/mach-smdk4x12.c @@ -316,6 +316,7 @@ MACHINE_START(SMDK4412, "SMDK4412") .map_io = smdk4x12_map_io, .handle_irq = gic_handle_irq, .init_machine = smdk4x12_machine_init, + .init_late = exynos_init_late, .timer = &exynos4_timer, .restart = exynos4_restart, .reserve = &smdk4x12_reserve, diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index 5af96064ca51..70df1a0c2118 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, @@ -412,6 +411,7 @@ MACHINE_START(SMDKC210, "SMDKC210") .map_io = smdkv310_map_io, .handle_irq = gic_handle_irq, .init_machine = smdkv310_machine_init, + .init_late = exynos_init_late, .timer = &exynos4_timer, .restart = exynos4_restart, MACHINE_END diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 6b731b863275..083b44de9c10 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -1157,6 +1157,7 @@ MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") .map_io = universal_map_io, .handle_irq = gic_handle_irq, .init_machine = universal_machine_init, + .init_late = exynos_init_late, .timer = &s5p_timer, .reserve = &universal_reserve, .restart = exynos4_restart, diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c index 897d9a9cf226..b601fb8a408b 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/arch/arm/mach-exynos/mct.c @@ -388,6 +388,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) { struct mct_clock_event_device *mevt; unsigned int cpu = smp_processor_id(); + int mct_lx_irq; mevt = this_cpu_ptr(&percpu_mct_tick); mevt->evt = evt; @@ -414,14 +415,18 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) if (mct_int_type == MCT_INT_SPI) { if (cpu == 0) { + mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L0 : + EXYNOS5_IRQ_MCT_L0; mct_tick0_event_irq.dev_id = mevt; - evt->irq = EXYNOS4_IRQ_MCT_L0; - setup_irq(EXYNOS4_IRQ_MCT_L0, &mct_tick0_event_irq); + evt->irq = mct_lx_irq; + setup_irq(mct_lx_irq, &mct_tick0_event_irq); } else { + mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L1 : + EXYNOS5_IRQ_MCT_L1; mct_tick1_event_irq.dev_id = mevt; - evt->irq = EXYNOS4_IRQ_MCT_L1; - setup_irq(EXYNOS4_IRQ_MCT_L1, &mct_tick1_event_irq); - irq_set_affinity(EXYNOS4_IRQ_MCT_L1, cpumask_of(1)); + evt->irq = mct_lx_irq; + setup_irq(mct_lx_irq, &mct_tick1_event_irq); + irq_set_affinity(mct_lx_irq, cpumask_of(1)); } } else { enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0); @@ -473,7 +478,7 @@ static void __init exynos4_timer_resources(void) static void __init exynos4_timer_init(void) { - if (soc_is_exynos4210()) + if ((soc_is_exynos4210()) || (soc_is_exynos5250())) mct_int_type = MCT_INT_SPI; else mct_int_type = MCT_INT_PPI; diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 428cfeb57724..563dea9a6dbb 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -275,7 +275,7 @@ static void exynos4_restore_pll(void) static struct subsys_interface exynos4_pm_interface = { .name = "exynos4_pm", - .subsys = &exynos4_subsys, + .subsys = &exynos_subsys, .add_dev = exynos4_pm_add, }; @@ -313,7 +313,7 @@ static int exynos4_pm_suspend(void) tmp &= ~S5P_CENTRAL_LOWPWR_CFG; __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); - if (soc_is_exynos4212()) { + if (soc_is_exynos4212() || soc_is_exynos4412()) { tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION); tmp &= ~(S5P_USE_STANDBYWFI_ISP_ARM | S5P_USE_STANDBYWFE_ISP_ARM); diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index 13b306808b42..e9fafcf163de 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -193,9 +193,8 @@ static __init int exynos4_pm_init_power_domain(void) } arch_initcall(exynos4_pm_init_power_domain); -static __init int exynos_pm_late_initcall(void) +int __init exynos_pm_late_initcall(void) { pm_genpd_poweroff_unused(); return 0; } -late_initcall(exynos_pm_late_initcall); diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index bba48f5c3e8f..77c6815eebee 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -94,7 +94,7 @@ static struct exynos4_pmu_conf exynos4210_pmu_config[] = { { PMU_TABLE_END,}, }; -static struct exynos4_pmu_conf exynos4212_pmu_config[] = { +static struct exynos4_pmu_conf exynos4x12_pmu_config[] = { { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } }, { S5P_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } }, { S5P_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } }, @@ -202,6 +202,16 @@ static struct exynos4_pmu_conf exynos4212_pmu_config[] = { { PMU_TABLE_END,}, }; +static struct exynos4_pmu_conf exynos4412_pmu_config[] = { + { S5P_ARM_CORE2_LOWPWR, { 0x0, 0x0, 0x2 } }, + { S5P_DIS_IRQ_CORE2, { 0x0, 0x0, 0x0 } }, + { S5P_DIS_IRQ_CENTRAL2, { 0x0, 0x0, 0x0 } }, + { S5P_ARM_CORE3_LOWPWR, { 0x0, 0x0, 0x2 } }, + { S5P_DIS_IRQ_CORE3, { 0x0, 0x0, 0x0 } }, + { S5P_DIS_IRQ_CENTRAL3, { 0x0, 0x0, 0x0 } }, + { PMU_TABLE_END,}, +}; + void exynos4_sys_powerdown_conf(enum sys_powerdown mode) { unsigned int i; @@ -209,6 +219,12 @@ void exynos4_sys_powerdown_conf(enum sys_powerdown mode) for (i = 0; (exynos4_pmu_config[i].reg != PMU_TABLE_END) ; i++) __raw_writel(exynos4_pmu_config[i].val[mode], exynos4_pmu_config[i].reg); + + if (soc_is_exynos4412()) { + for (i = 0; exynos4412_pmu_config[i].reg != PMU_TABLE_END ; i++) + __raw_writel(exynos4412_pmu_config[i].val[mode], + exynos4412_pmu_config[i].reg); + } } static int __init exynos4_pmu_init(void) @@ -218,9 +234,9 @@ static int __init exynos4_pmu_init(void) if (soc_is_exynos4210()) { exynos4_pmu_config = exynos4210_pmu_config; pr_info("EXYNOS4210 PMU Initialize\n"); - } else if (soc_is_exynos4212()) { - exynos4_pmu_config = exynos4212_pmu_config; - pr_info("EXYNOS4212 PMU Initialize\n"); + } else if (soc_is_exynos4212() || soc_is_exynos4412()) { + exynos4_pmu_config = exynos4x12_pmu_config; + pr_info("EXYNOS4x12 PMU Initialize\n"); } else { pr_info("EXYNOS4: PMU not supported\n"); } diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index cca8c0c74794..0021f726b153 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -34,6 +34,7 @@ config ARCH_MX53 config SOC_IMX1 bool select ARCH_MX1 + select COMMON_CLK select CPU_ARM920T select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -42,12 +43,14 @@ config SOC_IMX21 bool select MACH_MX21 select CPU_ARM926T + select COMMON_CLK select IMX_HAVE_IOMUX_V1 select MXC_AVIC config SOC_IMX25 bool select ARCH_MX25 + select COMMON_CLK select CPU_ARM926T select ARCH_MXC_IOMUX_V3 select MXC_AVIC @@ -56,6 +59,7 @@ config SOC_IMX27 bool select MACH_MX27 select CPU_ARM926T + select COMMON_CLK select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -64,12 +68,14 @@ config SOC_IMX31 select CPU_V6 select IMX_HAVE_PLATFORM_MXC_RNGA select MXC_AVIC + select COMMON_CLK select SMP_ON_UP if SMP config SOC_IMX35 bool select CPU_V6 select ARCH_MXC_IOMUX_V3 + select COMMON_CLK select HAVE_EPIT select MXC_AVIC select SMP_ON_UP if SMP @@ -77,6 +83,7 @@ config SOC_IMX35 config SOC_IMX5 select CPU_V7 select MXC_TZIC + select COMMON_CLK select ARCH_MXC_IOMUX_V3 select ARCH_HAS_CPUFREQ select ARCH_MX5 @@ -815,6 +822,7 @@ config SOC_IMX6Q bool "i.MX6 Quad support" select ARM_CPU_SUSPEND if PM select ARM_GIC + select COMMON_CLK select CPU_V7 select HAVE_ARM_SCU select HAVE_IMX_GPC diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 4937c070a57e..ff29421414f2 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -1,15 +1,18 @@ -obj-$(CONFIG_SOC_IMX1) += clock-imx1.o mm-imx1.o -obj-$(CONFIG_SOC_IMX21) += clock-imx21.o mm-imx21.o +obj-$(CONFIG_SOC_IMX1) += clk-imx1.o mm-imx1.o +obj-$(CONFIG_SOC_IMX21) += clk-imx21.o mm-imx21.o -obj-$(CONFIG_SOC_IMX25) += clock-imx25.o mm-imx25.o ehci-imx25.o cpu-imx25.o +obj-$(CONFIG_SOC_IMX25) += clk-imx25.o mm-imx25.o ehci-imx25.o cpu-imx25.o obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o -obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o +obj-$(CONFIG_SOC_IMX27) += clk-imx27.o mm-imx27.o ehci-imx27.o -obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o -obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o pm-imx3.o +obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o +obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o -obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o +obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o + +obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ + clk-pfd.o clk-busy.o # Support for CMOS sensor interface obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o @@ -70,7 +73,7 @@ obj-$(CONFIG_CPU_V7) += head-v7.o AFLAGS_head-v7.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o +obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot index 3851d8a27875..05541cf4a878 100644 --- a/arch/arm/mach-imx/Makefile.boot +++ b/arch/arm/mach-imx/Makefile.boot @@ -42,4 +42,5 @@ dtb-$(CONFIG_MACH_IMX51_DT) += imx51-babbage.dtb dtb-$(CONFIG_MACH_IMX53_DT) += imx53-ard.dtb imx53-evk.dtb \ imx53-qsb.dtb imx53-smd.dtb dtb-$(CONFIG_SOC_IMX6Q) += imx6q-arm2.dtb \ - imx6q-sabrelite.dtb + imx6q-sabrelite.dtb \ + imx6q-sabresd.dtb \ diff --git a/arch/arm/mach-imx/clk-busy.c b/arch/arm/mach-imx/clk-busy.c new file mode 100644 index 000000000000..1a7a8dd045a1 --- /dev/null +++ b/arch/arm/mach-imx/clk-busy.c @@ -0,0 +1,189 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/err.h> +#include "clk.h" + +static int clk_busy_wait(void __iomem *reg, u8 shift) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + + while (readl_relaxed(reg) & (1 << shift)) + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} + +struct clk_busy_divider { + struct clk_divider div; + const struct clk_ops *div_ops; + void __iomem *reg; + u8 shift; +}; + +static inline struct clk_busy_divider *to_clk_busy_divider(struct clk_hw *hw) +{ + struct clk_divider *div = container_of(hw, struct clk_divider, hw); + + return container_of(div, struct clk_busy_divider, div); +} + +static unsigned long clk_busy_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + + return busy->div_ops->recalc_rate(&busy->div.hw, parent_rate); +} + +static long clk_busy_divider_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + + return busy->div_ops->round_rate(&busy->div.hw, rate, prate); +} + +static int clk_busy_divider_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_busy_divider *busy = to_clk_busy_divider(hw); + int ret; + + ret = busy->div_ops->set_rate(&busy->div.hw, rate, parent_rate); + if (!ret) + ret = clk_busy_wait(busy->reg, busy->shift); + + return ret; +} + +static struct clk_ops clk_busy_divider_ops = { + .recalc_rate = clk_busy_divider_recalc_rate, + .round_rate = clk_busy_divider_round_rate, + .set_rate = clk_busy_divider_set_rate, +}; + +struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, + void __iomem *busy_reg, u8 busy_shift) +{ + struct clk_busy_divider *busy; + struct clk *clk; + struct clk_init_data init; + + busy = kzalloc(sizeof(*busy), GFP_KERNEL); + if (!busy) + return ERR_PTR(-ENOMEM); + + busy->reg = busy_reg; + busy->shift = busy_shift; + + busy->div.reg = reg; + busy->div.shift = shift; + busy->div.width = width; + busy->div.lock = &imx_ccm_lock; + busy->div_ops = &clk_divider_ops; + + init.name = name; + init.ops = &clk_busy_divider_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + + busy->div.hw.init = &init; + + clk = clk_register(NULL, &busy->div.hw); + if (!clk) + kfree(busy); + + return clk; +} + +struct clk_busy_mux { + struct clk_mux mux; + const struct clk_ops *mux_ops; + void __iomem *reg; + u8 shift; +}; + +static inline struct clk_busy_mux *to_clk_busy_mux(struct clk_hw *hw) +{ + struct clk_mux *mux = container_of(hw, struct clk_mux, hw); + + return container_of(mux, struct clk_busy_mux, mux); +} + +static u8 clk_busy_mux_get_parent(struct clk_hw *hw) +{ + struct clk_busy_mux *busy = to_clk_busy_mux(hw); + + return busy->mux_ops->get_parent(&busy->mux.hw); +} + +static int clk_busy_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_busy_mux *busy = to_clk_busy_mux(hw); + int ret; + + ret = busy->mux_ops->set_parent(&busy->mux.hw, index); + if (!ret) + ret = clk_busy_wait(busy->reg, busy->shift); + + return ret; +} + +struct clk_ops clk_busy_mux_ops = { + .get_parent = clk_busy_mux_get_parent, + .set_parent = clk_busy_mux_set_parent, +}; + +struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, + u8 width, void __iomem *busy_reg, u8 busy_shift, + const char **parent_names, int num_parents) +{ + struct clk_busy_mux *busy; + struct clk *clk; + struct clk_init_data init; + + busy = kzalloc(sizeof(*busy), GFP_KERNEL); + if (!busy) + return ERR_PTR(-ENOMEM); + + busy->reg = busy_reg; + busy->shift = busy_shift; + + busy->mux.reg = reg; + busy->mux.shift = shift; + busy->mux.width = width; + busy->mux.lock = &imx_ccm_lock; + busy->mux_ops = &clk_mux_ops; + + init.name = name; + init.ops = &clk_busy_mux_ops; + init.flags = 0; + init.parent_names = parent_names; + init.num_parents = num_parents; + + busy->mux.hw.init = &init; + + clk = clk_register(NULL, &busy->mux.hw); + if (IS_ERR(clk)) + kfree(busy); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c new file mode 100644 index 000000000000..3c1b8ff9a0a6 --- /dev/null +++ b/arch/arm/mach-imx/clk-gate2.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> + * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Gated clock implementation + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/string.h> + +/** + * DOC: basic gatable clock which can gate and ungate it's ouput + * + * Traits of this clock: + * prepare - clk_(un)prepare only ensures parent is (un)prepared + * enable - clk_enable and clk_disable are functional & control gating + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) + +static int clk_gate2_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + u32 reg; + unsigned long flags = 0; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + reg |= 3 << gate->bit_idx; + writel(reg, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); + + return 0; +} + +static void clk_gate2_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + u32 reg; + unsigned long flags = 0; + + if (gate->lock) + spin_lock_irqsave(gate->lock, flags); + + reg = readl(gate->reg); + reg &= ~(3 << gate->bit_idx); + writel(reg, gate->reg); + + if (gate->lock) + spin_unlock_irqrestore(gate->lock, flags); +} + +static int clk_gate2_is_enabled(struct clk_hw *hw) +{ + u32 reg; + struct clk_gate *gate = to_clk_gate(hw); + + reg = readl(gate->reg); + + if (((reg >> gate->bit_idx) & 3) == 3) + return 1; + + return 0; +} + +static struct clk_ops clk_gate2_ops = { + .enable = clk_gate2_enable, + .disable = clk_gate2_disable, + .is_enabled = clk_gate2_is_enabled, +}; + +struct clk *clk_register_gate2(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate2_flags, spinlock_t *lock) +{ + struct clk_gate *gate; + struct clk *clk; + struct clk_init_data init; + + gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + /* struct clk_gate assignments */ + gate->reg = reg; + gate->bit_idx = bit_idx; + gate->flags = clk_gate2_flags; + gate->lock = lock; + + init.name = name; + init.ops = &clk_gate2_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + gate->hw.init = &init; + + clk = clk_register(dev, &gate->hw); + if (IS_ERR(clk)) + kfree(clk); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-imx1.c b/arch/arm/mach-imx/clk-imx1.c new file mode 100644 index 000000000000..0f0beb580b73 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx1.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include "clk.h" + +/* CCM register addresses */ +#define IO_ADDR_CCM(off) (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off))) + +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_PCDR IO_ADDR_CCM(0x20) + +/* SCM register addresses */ +#define IO_ADDR_SCM(off) (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off))) + +#define SCM_GCCR IO_ADDR_SCM(0xc) + +static const char *prem_sel_clks[] = { "clk32_premult", "clk16m", }; +static const char *clko_sel_clks[] = { "per1", "hclk", "clk48m", "clk16m", "prem", + "fclk", }; +enum imx1_clks { + dummy, clk32, clk16m_ext, clk16m, clk32_premult, prem, mpll, spll, mcu, + fclk, hclk, clk48m, per1, per2, per3, clko, dma_gate, csi_gate, + mma_gate, usbd_gate, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx1_clocks_init(unsigned long fref) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[clk32] = imx_clk_fixed("clk32", fref); + clk[clk16m_ext] = imx_clk_fixed("clk16m_ext", 16000000); + clk[clk16m] = imx_clk_gate("clk16m", "clk16m_ext", CCM_CSCR, 17); + clk[clk32_premult] = imx_clk_fixed_factor("clk32_premult", "clk32", 512, 1); + clk[prem] = imx_clk_mux("prem", CCM_CSCR, 16, 1, prem_sel_clks, + ARRAY_SIZE(prem_sel_clks)); + clk[mpll] = imx_clk_pllv1("mpll", "clk32_premult", CCM_MPCTL0); + clk[spll] = imx_clk_pllv1("spll", "prem", CCM_SPCTL0); + clk[mcu] = imx_clk_divider("mcu", "clk32_premult", CCM_CSCR, 15, 1); + clk[fclk] = imx_clk_divider("fclk", "mpll", CCM_CSCR, 15, 1); + clk[hclk] = imx_clk_divider("hclk", "spll", CCM_CSCR, 10, 4); + clk[clk48m] = imx_clk_divider("clk48m", "spll", CCM_CSCR, 26, 3); + clk[per1] = imx_clk_divider("per1", "spll", CCM_PCDR, 0, 4); + clk[per2] = imx_clk_divider("per2", "spll", CCM_PCDR, 4, 4); + clk[per3] = imx_clk_divider("per3", "spll", CCM_PCDR, 16, 7); + clk[clko] = imx_clk_mux("clko", CCM_CSCR, 29, 3, clko_sel_clks, + ARRAY_SIZE(clko_sel_clks)); + clk[dma_gate] = imx_clk_gate("dma_gate", "hclk", SCM_GCCR, 4); + clk[csi_gate] = imx_clk_gate("csi_gate", "hclk", SCM_GCCR, 2); + clk[mma_gate] = imx_clk_gate("mma_gate", "hclk", SCM_GCCR, 1); + clk[usbd_gate] = imx_clk_gate("usbd_gate", "clk48m", SCM_GCCR, 0); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("imx1 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[dma_gate], "ahb", "imx-dma"); + clk_register_clkdev(clk[csi_gate], NULL, "mx1-camera.0"); + clk_register_clkdev(clk[mma_gate], "mma", NULL); + clk_register_clkdev(clk[usbd_gate], NULL, "imx_udc.0"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.0"); + clk_register_clkdev(clk[hclk], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[per1], "per", "imx1-uart.0"); + clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.0"); + clk_register_clkdev(clk[per1], "per", "imx1-uart.1"); + clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.1"); + clk_register_clkdev(clk[per1], "per", "imx1-uart.2"); + clk_register_clkdev(clk[hclk], "ipg", "imx1-uart.2"); + clk_register_clkdev(clk[hclk], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[per2], "per", "imx1-cspi.0"); + clk_register_clkdev(clk[dummy], "ipg", "imx1-cspi.0"); + clk_register_clkdev(clk[per2], "per", "imx1-cspi.1"); + clk_register_clkdev(clk[dummy], "ipg", "imx1-cspi.1"); + clk_register_clkdev(clk[per2], NULL, "imx-mmc.0"); + clk_register_clkdev(clk[per2], "per", "imx-fb.0"); + clk_register_clkdev(clk[dummy], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[dummy], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[hclk], "mshc", NULL); + clk_register_clkdev(clk[per3], "ssi", NULL); + clk_register_clkdev(clk[clk32], NULL, "mxc_rtc.0"); + clk_register_clkdev(clk[clko], "clko", NULL); + + mxc_timer_init(NULL, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), + MX1_TIM1_INT); + + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx21.c b/arch/arm/mach-imx/clk-imx21.c new file mode 100644 index 000000000000..4e4f384ee8dd --- /dev/null +++ b/arch/arm/mach-imx/clk-imx21.c @@ -0,0 +1,186 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/clkdev.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include "clk.h" + +#define IO_ADDR_CCM(off) (MX21_IO_ADDRESS(MX21_CCM_BASE_ADDR + (off))) + +/* Register offsets */ +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_MPCTL1 IO_ADDR_CCM(0x8) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_SPCTL1 IO_ADDR_CCM(0x10) +#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) +#define CCM_PCDR0 IO_ADDR_CCM(0x18) +#define CCM_PCDR1 IO_ADDR_CCM(0x1c) +#define CCM_PCCR0 IO_ADDR_CCM(0x20) +#define CCM_PCCR1 IO_ADDR_CCM(0x24) +#define CCM_CCSR IO_ADDR_CCM(0x28) +#define CCM_PMCTL IO_ADDR_CCM(0x2c) +#define CCM_PMCOUNT IO_ADDR_CCM(0x30) +#define CCM_WKGDCTL IO_ADDR_CCM(0x34) + +static const char *mpll_sel_clks[] = { "fpm", "ckih", }; +static const char *spll_sel_clks[] = { "fpm", "ckih", }; + +enum imx21_clks { + ckil, ckih, fpm, mpll_sel, spll_sel, mpll, spll, fclk, hclk, ipg, per1, + per2, per3, per4, uart1_ipg_gate, uart2_ipg_gate, uart3_ipg_gate, + uart4_ipg_gate, gpt1_ipg_gate, gpt2_ipg_gate, gpt3_ipg_gate, + pwm_ipg_gate, sdhc1_ipg_gate, sdhc2_ipg_gate, lcdc_ipg_gate, + lcdc_hclk_gate, cspi3_ipg_gate, cspi2_ipg_gate, cspi1_ipg_gate, + per4_gate, csi_hclk_gate, usb_div, usb_gate, usb_hclk_gate, ssi1_gate, + ssi2_gate, nfc_div, nfc_gate, dma_gate, dma_hclk_gate, brom_gate, + emma_gate, emma_hclk_gate, slcdc_gate, slcdc_hclk_gate, wdog_gate, + gpio_gate, i2c_gate, kpp_gate, owire_gate, rtc_gate, clk_max +}; + +static struct clk *clk[clk_max]; + +/* + * must be called very early to get information about the + * available clock rate when the timer framework starts + */ +int __init mx21_clocks_init(unsigned long lref, unsigned long href) +{ + int i; + + clk[ckil] = imx_clk_fixed("ckil", lref); + clk[ckih] = imx_clk_fixed("ckih", href); + clk[fpm] = imx_clk_fixed_factor("fpm", "ckil", 512, 1); + clk[mpll_sel] = imx_clk_mux("mpll_sel", CCM_CSCR, 16, 1, mpll_sel_clks, + ARRAY_SIZE(mpll_sel_clks)); + clk[spll_sel] = imx_clk_mux("spll_sel", CCM_CSCR, 17, 1, spll_sel_clks, + ARRAY_SIZE(spll_sel_clks)); + clk[mpll] = imx_clk_pllv1("mpll", "mpll_sel", CCM_MPCTL0); + clk[spll] = imx_clk_pllv1("spll", "spll_sel", CCM_SPCTL0); + clk[fclk] = imx_clk_divider("fclk", "mpll", CCM_CSCR, 29, 3); + clk[hclk] = imx_clk_divider("hclk", "fclk", CCM_CSCR, 10, 4); + clk[ipg] = imx_clk_divider("ipg", "hclk", CCM_CSCR, 9, 1); + clk[per1] = imx_clk_divider("per1", "mpll", CCM_PCDR1, 0, 6); + clk[per2] = imx_clk_divider("per2", "mpll", CCM_PCDR1, 8, 6); + clk[per3] = imx_clk_divider("per3", "mpll", CCM_PCDR1, 16, 6); + clk[per4] = imx_clk_divider("per4", "mpll", CCM_PCDR1, 24, 6); + clk[uart1_ipg_gate] = imx_clk_gate("uart1_ipg_gate", "ipg", CCM_PCCR0, 0); + clk[uart2_ipg_gate] = imx_clk_gate("uart2_ipg_gate", "ipg", CCM_PCCR0, 1); + clk[uart3_ipg_gate] = imx_clk_gate("uart3_ipg_gate", "ipg", CCM_PCCR0, 2); + clk[uart4_ipg_gate] = imx_clk_gate("uart4_ipg_gate", "ipg", CCM_PCCR0, 3); + clk[gpt1_ipg_gate] = imx_clk_gate("gpt1_ipg_gate", "ipg", CCM_PCCR1, 25); + clk[gpt2_ipg_gate] = imx_clk_gate("gpt2_ipg_gate", "ipg", CCM_PCCR1, 26); + clk[gpt3_ipg_gate] = imx_clk_gate("gpt3_ipg_gate", "ipg", CCM_PCCR1, 27); + clk[pwm_ipg_gate] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR1, 28); + clk[sdhc1_ipg_gate] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 9); + clk[sdhc2_ipg_gate] = imx_clk_gate("sdhc2_ipg_gate", "ipg", CCM_PCCR0, 10); + clk[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 18); + clk[lcdc_hclk_gate] = imx_clk_gate("lcdc_hclk_gate", "hclk", CCM_PCCR0, 26); + clk[cspi3_ipg_gate] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR1, 23); + clk[cspi2_ipg_gate] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 5); + clk[cspi1_ipg_gate] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 4); + clk[per4_gate] = imx_clk_gate("per4_gate", "per4", CCM_PCCR0, 22); + clk[csi_hclk_gate] = imx_clk_gate("csi_hclk_gate", "hclk", CCM_PCCR0, 31); + clk[usb_div] = imx_clk_divider("usb_div", "spll", CCM_CSCR, 26, 3); + clk[usb_gate] = imx_clk_gate("usb_gate", "usb_div", CCM_PCCR0, 14); + clk[usb_hclk_gate] = imx_clk_gate("usb_hclk_gate", "hclk", CCM_PCCR0, 24); + clk[ssi1_gate] = imx_clk_gate("ssi1_gate", "ipg", CCM_PCCR0, 6); + clk[ssi2_gate] = imx_clk_gate("ssi2_gate", "ipg", CCM_PCCR0, 7); + clk[nfc_div] = imx_clk_divider("nfc_div", "ipg", CCM_PCDR0, 12, 4); + clk[nfc_gate] = imx_clk_gate("nfc_gate", "nfc_div", CCM_PCCR0, 19); + clk[dma_gate] = imx_clk_gate("dma_gate", "ipg", CCM_PCCR0, 13); + clk[dma_hclk_gate] = imx_clk_gate("dma_hclk_gate", "hclk", CCM_PCCR0, 30); + clk[brom_gate] = imx_clk_gate("brom_gate", "hclk", CCM_PCCR0, 28); + clk[emma_gate] = imx_clk_gate("emma_gate", "ipg", CCM_PCCR0, 15); + clk[emma_hclk_gate] = imx_clk_gate("emma_hclk_gate", "hclk", CCM_PCCR0, 27); + clk[slcdc_gate] = imx_clk_gate("slcdc_gate", "ipg", CCM_PCCR0, 25); + clk[slcdc_hclk_gate] = imx_clk_gate("slcdc_hclk_gate", "hclk", CCM_PCCR0, 21); + clk[wdog_gate] = imx_clk_gate("wdog_gate", "ipg", CCM_PCCR1, 24); + clk[gpio_gate] = imx_clk_gate("gpio_gate", "ipg", CCM_PCCR0, 11); + clk[i2c_gate] = imx_clk_gate("i2c_gate", "ipg", CCM_PCCR0, 12); + clk[kpp_gate] = imx_clk_gate("kpp_gate", "ipg", CCM_PCCR1, 30); + clk[owire_gate] = imx_clk_gate("owire_gate", "ipg", CCM_PCCR1, 31); + clk[rtc_gate] = imx_clk_gate("rtc_gate", "ipg", CCM_PCCR1, 29); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX21 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[per1], "per1", NULL); + clk_register_clkdev(clk[per2], "per2", NULL); + clk_register_clkdev(clk[per3], "per3", NULL); + clk_register_clkdev(clk[per4], "per4", NULL); + clk_register_clkdev(clk[per1], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart1_ipg_gate], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[per1], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart2_ipg_gate], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[per1], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart3_ipg_gate], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[per1], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart4_ipg_gate], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[gpt1_ipg_gate], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.0"); + clk_register_clkdev(clk[gpt2_ipg_gate], "ipg", "imx-gpt.1"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.1"); + clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2"); + clk_register_clkdev(clk[per1], "per", "imx-gpt.2"); + clk_register_clkdev(clk[pwm_ipg_gate], "pwm", "mxc_pwm.0"); + clk_register_clkdev(clk[per2], "per", "imx21-cspi.0"); + clk_register_clkdev(clk[cspi1_ipg_gate], "ipg", "imx21-cspi.0"); + clk_register_clkdev(clk[per2], "per", "imx21-cspi.1"); + clk_register_clkdev(clk[cspi2_ipg_gate], "ipg", "imx21-cspi.1"); + clk_register_clkdev(clk[per2], "per", "imx21-cspi.2"); + clk_register_clkdev(clk[cspi3_ipg_gate], "ipg", "imx21-cspi.2"); + clk_register_clkdev(clk[per3], "per", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_hclk_gate], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[usb_gate], "per", "imx21-hcd.0"); + clk_register_clkdev(clk[usb_hclk_gate], "ahb", "imx21-hcd.0"); + clk_register_clkdev(clk[nfc_gate], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[dma_hclk_gate], "ahb", "imx-dma"); + clk_register_clkdev(clk[dma_gate], "ipg", "imx-dma"); + clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[i2c_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[kpp_gate], NULL, "mxc-keypad"); + clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); + clk_register_clkdev(clk[brom_gate], "brom", NULL); + clk_register_clkdev(clk[emma_gate], "emma", NULL); + clk_register_clkdev(clk[slcdc_gate], "slcdc", NULL); + clk_register_clkdev(clk[gpio_gate], "gpio", NULL); + clk_register_clkdev(clk[rtc_gate], "rtc", NULL); + clk_register_clkdev(clk[csi_hclk_gate], "csi", NULL); + clk_register_clkdev(clk[ssi1_gate], "ssi1", NULL); + clk_register_clkdev(clk[ssi2_gate], "ssi2", NULL); + clk_register_clkdev(clk[sdhc1_ipg_gate], "sdhc1", NULL); + clk_register_clkdev(clk[sdhc2_ipg_gate], "sdhc2", NULL); + + mxc_timer_init(NULL, MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), + MX21_INT_GPT1); + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c new file mode 100644 index 000000000000..d9833bb5fd61 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx25.c @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2009 by Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/mx25.h> +#include "clk.h" + +#define CRM_BASE MX25_IO_ADDRESS(MX25_CRM_BASE_ADDR) + +#define CCM_MPCTL 0x00 +#define CCM_UPCTL 0x04 +#define CCM_CCTL 0x08 +#define CCM_CGCR0 0x0C +#define CCM_CGCR1 0x10 +#define CCM_CGCR2 0x14 +#define CCM_PCDR0 0x18 +#define CCM_PCDR1 0x1C +#define CCM_PCDR2 0x20 +#define CCM_PCDR3 0x24 +#define CCM_RCSR 0x28 +#define CCM_CRDR 0x2C +#define CCM_DCVR0 0x30 +#define CCM_DCVR1 0x34 +#define CCM_DCVR2 0x38 +#define CCM_DCVR3 0x3c +#define CCM_LTR0 0x40 +#define CCM_LTR1 0x44 +#define CCM_LTR2 0x48 +#define CCM_LTR3 0x4c +#define CCM_MCR 0x64 + +#define ccm(x) (CRM_BASE + (x)) + +static const char *cpu_sel_clks[] = { "mpll", "mpll_cpu_3_4", }; +static const char *per_sel_clks[] = { "ahb", "upll", }; + +enum mx25_clks { + dummy, osc, mpll, upll, mpll_cpu_3_4, cpu_sel, cpu, ahb, usb_div, ipg, + per0_sel, per1_sel, per2_sel, per3_sel, per4_sel, per5_sel, per6_sel, + per7_sel, per8_sel, per9_sel, per10_sel, per11_sel, per12_sel, + per13_sel, per14_sel, per15_sel, per0, per1, per2, per3, per4, per5, + per6, per7, per8, per9, per10, per11, per12, per13, per14, per15, + csi_ipg_per, esdhc1_ipg_per, esdhc2_ipg_per, gpt_ipg_per, i2c_ipg_per, + lcdc_ipg_per, nfc_ipg_per, ssi1_ipg_per, ssi2_ipg_per, uart_ipg_per, + csi_ahb, esdhc1_ahb, esdhc2_ahb, fec_ahb, lcdc_ahb, sdma_ahb, + usbotg_ahb, can1_ipg, can2_ipg, csi_ipg, cspi1_ipg, cspi2_ipg, + cspi3_ipg, dryice_ipg, esdhc1_ipg, esdhc2_ipg, fec_ipg, iim_ipg, + kpp_ipg, lcdc_ipg, pwm1_ipg, pwm2_ipg, pwm3_ipg, pwm4_ipg, sdma_ipg, + ssi1_ipg, ssi2_ipg, tsc_ipg, uart1_ipg, uart2_ipg, uart3_ipg, + uart4_ipg, uart5_ipg, wdt_ipg, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx25_clocks_init(void) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[osc] = imx_clk_fixed("osc", 24000000); + clk[mpll] = imx_clk_pllv1("mpll", "osc", ccm(CCM_MPCTL)); + clk[upll] = imx_clk_pllv1("upll", "osc", ccm(CCM_UPCTL)); + clk[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4); + clk[cpu_sel] = imx_clk_mux("cpu_sel", ccm(CCM_CCTL), 14, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); + clk[cpu] = imx_clk_divider("cpu", "cpu_sel", ccm(CCM_CCTL), 30, 2); + clk[ahb] = imx_clk_divider("ahb", "cpu", ccm(CCM_CCTL), 28, 2); + clk[usb_div] = imx_clk_divider("usb_div", "upll", ccm(CCM_CCTL), 16, 6); + clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + clk[per0_sel] = imx_clk_mux("per0_sel", ccm(CCM_MCR), 0, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per1_sel] = imx_clk_mux("per1_sel", ccm(CCM_MCR), 1, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per2_sel] = imx_clk_mux("per2_sel", ccm(CCM_MCR), 2, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per3_sel] = imx_clk_mux("per3_sel", ccm(CCM_MCR), 3, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per4_sel] = imx_clk_mux("per4_sel", ccm(CCM_MCR), 4, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per5_sel] = imx_clk_mux("per5_sel", ccm(CCM_MCR), 5, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per6_sel] = imx_clk_mux("per6_sel", ccm(CCM_MCR), 6, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per7_sel] = imx_clk_mux("per7_sel", ccm(CCM_MCR), 7, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per8_sel] = imx_clk_mux("per8_sel", ccm(CCM_MCR), 8, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per9_sel] = imx_clk_mux("per9_sel", ccm(CCM_MCR), 9, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per10_sel] = imx_clk_mux("per10_sel", ccm(CCM_MCR), 10, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per11_sel] = imx_clk_mux("per11_sel", ccm(CCM_MCR), 11, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per12_sel] = imx_clk_mux("per12_sel", ccm(CCM_MCR), 12, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per13_sel] = imx_clk_mux("per13_sel", ccm(CCM_MCR), 13, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per14_sel] = imx_clk_mux("per14_sel", ccm(CCM_MCR), 14, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per15_sel] = imx_clk_mux("per15_sel", ccm(CCM_MCR), 15, 1, per_sel_clks, ARRAY_SIZE(per_sel_clks)); + clk[per0] = imx_clk_divider("per0", "per0_sel", ccm(CCM_PCDR0), 0, 6); + clk[per1] = imx_clk_divider("per1", "per1_sel", ccm(CCM_PCDR0), 8, 6); + clk[per2] = imx_clk_divider("per2", "per2_sel", ccm(CCM_PCDR0), 16, 6); + clk[per3] = imx_clk_divider("per3", "per3_sel", ccm(CCM_PCDR0), 24, 6); + clk[per4] = imx_clk_divider("per4", "per4_sel", ccm(CCM_PCDR1), 0, 6); + clk[per5] = imx_clk_divider("per5", "per5_sel", ccm(CCM_PCDR1), 8, 6); + clk[per6] = imx_clk_divider("per6", "per6_sel", ccm(CCM_PCDR1), 16, 6); + clk[per7] = imx_clk_divider("per7", "per7_sel", ccm(CCM_PCDR1), 24, 6); + clk[per8] = imx_clk_divider("per8", "per8_sel", ccm(CCM_PCDR2), 0, 6); + clk[per9] = imx_clk_divider("per9", "per9_sel", ccm(CCM_PCDR2), 8, 6); + clk[per10] = imx_clk_divider("per10", "per10_sel", ccm(CCM_PCDR2), 16, 6); + clk[per11] = imx_clk_divider("per11", "per11_sel", ccm(CCM_PCDR2), 24, 6); + clk[per12] = imx_clk_divider("per12", "per12_sel", ccm(CCM_PCDR3), 0, 6); + clk[per13] = imx_clk_divider("per13", "per13_sel", ccm(CCM_PCDR3), 8, 6); + clk[per14] = imx_clk_divider("per14", "per14_sel", ccm(CCM_PCDR3), 16, 6); + clk[per15] = imx_clk_divider("per15", "per15_sel", ccm(CCM_PCDR3), 24, 6); + clk[csi_ipg_per] = imx_clk_gate("csi_ipg_per", "per0", ccm(CCM_CGCR0), 0); + clk[esdhc1_ipg_per] = imx_clk_gate("esdhc1_ipg_per", "per3", ccm(CCM_CGCR0), 3); + clk[esdhc2_ipg_per] = imx_clk_gate("esdhc2_ipg_per", "per4", ccm(CCM_CGCR0), 4); + clk[gpt_ipg_per] = imx_clk_gate("gpt_ipg_per", "per5", ccm(CCM_CGCR0), 5); + clk[i2c_ipg_per] = imx_clk_gate("i2c_ipg_per", "per6", ccm(CCM_CGCR0), 6); + clk[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per8", ccm(CCM_CGCR0), 7); + clk[nfc_ipg_per] = imx_clk_gate("nfc_ipg_per", "ipg_per", ccm(CCM_CGCR0), 8); + clk[ssi1_ipg_per] = imx_clk_gate("ssi1_ipg_per", "per13", ccm(CCM_CGCR0), 13); + clk[ssi2_ipg_per] = imx_clk_gate("ssi2_ipg_per", "per14", ccm(CCM_CGCR0), 14); + clk[uart_ipg_per] = imx_clk_gate("uart_ipg_per", "per15", ccm(CCM_CGCR0), 15); + clk[csi_ahb] = imx_clk_gate("csi_ahb", "ahb", ccm(CCM_CGCR0), 18); + clk[esdhc1_ahb] = imx_clk_gate("esdhc1_ahb", "ahb", ccm(CCM_CGCR0), 21); + clk[esdhc2_ahb] = imx_clk_gate("esdhc2_ahb", "ahb", ccm(CCM_CGCR0), 22); + clk[fec_ahb] = imx_clk_gate("fec_ahb", "ahb", ccm(CCM_CGCR0), 23); + clk[lcdc_ahb] = imx_clk_gate("lcdc_ahb", "ahb", ccm(CCM_CGCR0), 24); + clk[sdma_ahb] = imx_clk_gate("sdma_ahb", "ahb", ccm(CCM_CGCR0), 26); + clk[usbotg_ahb] = imx_clk_gate("usbotg_ahb", "ahb", ccm(CCM_CGCR0), 28); + clk[can1_ipg] = imx_clk_gate("can1_ipg", "ipg", ccm(CCM_CGCR1), 2); + clk[can2_ipg] = imx_clk_gate("can2_ipg", "ipg", ccm(CCM_CGCR1), 3); + clk[csi_ipg] = imx_clk_gate("csi_ipg", "ipg", ccm(CCM_CGCR1), 4); + clk[cspi1_ipg] = imx_clk_gate("cspi1_ipg", "ipg", ccm(CCM_CGCR1), 5); + clk[cspi2_ipg] = imx_clk_gate("cspi2_ipg", "ipg", ccm(CCM_CGCR1), 6); + clk[cspi3_ipg] = imx_clk_gate("cspi3_ipg", "ipg", ccm(CCM_CGCR1), 7); + clk[dryice_ipg] = imx_clk_gate("dryice_ipg", "ipg", ccm(CCM_CGCR1), 8); + clk[esdhc1_ipg] = imx_clk_gate("esdhc1_ipg", "ipg", ccm(CCM_CGCR1), 13); + clk[esdhc2_ipg] = imx_clk_gate("esdhc2_ipg", "ipg", ccm(CCM_CGCR1), 14); + clk[fec_ipg] = imx_clk_gate("fec_ipg", "ipg", ccm(CCM_CGCR1), 15); + clk[iim_ipg] = imx_clk_gate("iim_ipg", "ipg", ccm(CCM_CGCR1), 26); + clk[kpp_ipg] = imx_clk_gate("kpp_ipg", "ipg", ccm(CCM_CGCR1), 28); + clk[lcdc_ipg] = imx_clk_gate("lcdc_ipg", "ipg", ccm(CCM_CGCR1), 29); + clk[pwm1_ipg] = imx_clk_gate("pwm1_ipg", "ipg", ccm(CCM_CGCR1), 31); + clk[pwm2_ipg] = imx_clk_gate("pwm2_ipg", "ipg", ccm(CCM_CGCR2), 0); + clk[pwm3_ipg] = imx_clk_gate("pwm3_ipg", "ipg", ccm(CCM_CGCR2), 1); + clk[pwm4_ipg] = imx_clk_gate("pwm4_ipg", "ipg", ccm(CCM_CGCR2), 2); + clk[sdma_ipg] = imx_clk_gate("sdma_ipg", "ipg", ccm(CCM_CGCR2), 6); + clk[ssi1_ipg] = imx_clk_gate("ssi1_ipg", "ipg", ccm(CCM_CGCR2), 11); + clk[ssi2_ipg] = imx_clk_gate("ssi2_ipg", "ipg", ccm(CCM_CGCR2), 12); + clk[tsc_ipg] = imx_clk_gate("tsc_ipg", "ipg", ccm(CCM_CGCR2), 13); + clk[uart1_ipg] = imx_clk_gate("uart1_ipg", "ipg", ccm(CCM_CGCR2), 14); + clk[uart2_ipg] = imx_clk_gate("uart2_ipg", "ipg", ccm(CCM_CGCR2), 15); + clk[uart3_ipg] = imx_clk_gate("uart3_ipg", "ipg", ccm(CCM_CGCR2), 16); + clk[uart4_ipg] = imx_clk_gate("uart4_ipg", "ipg", ccm(CCM_CGCR2), 17); + clk[uart5_ipg] = imx_clk_gate("uart5_ipg", "ipg", ccm(CCM_CGCR2), 18); + clk[wdt_ipg] = imx_clk_gate("wdt_ipg", "ipg", ccm(CCM_CGCR2), 19); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX25 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + /* i.mx25 has the i.mx21 type uart */ + clk_register_clkdev(clk[uart1_ipg], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_ipg], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_ipg], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_ipg], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_ipg], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[uart_ipg_per], "per", "imx21-uart.4"); + clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usbotg_ahb], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[nfc_ipg_per], NULL, "mxc_nand.0"); + /* i.mx25 has the i.mx35 type cspi */ + clk_register_clkdev(clk[cspi1_ipg], NULL, "imx35-cspi.0"); + clk_register_clkdev(clk[cspi2_ipg], NULL, "imx35-cspi.1"); + clk_register_clkdev(clk[cspi3_ipg], NULL, "imx35-cspi.2"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.0"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.0"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.1"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.1"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.2"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.2"); + clk_register_clkdev(clk[pwm1_ipg], "ipg", "mxc_pwm.3"); + clk_register_clkdev(clk[per10], "per", "mxc_pwm.3"); + clk_register_clkdev(clk[kpp_ipg], NULL, "imx-keypad"); + clk_register_clkdev(clk[tsc_ipg], NULL, "mx25-adc"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c_ipg_per], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[fec_ipg], "ipg", "imx25-fec.0"); + clk_register_clkdev(clk[fec_ahb], "ahb", "imx25-fec.0"); + clk_register_clkdev(clk[dryice_ipg], NULL, "imxdi_rtc.0"); + clk_register_clkdev(clk[lcdc_ipg_per], "per", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ipg], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ahb], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[wdt_ipg], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[ssi1_ipg_per], "per", "imx-ssi.0"); + clk_register_clkdev(clk[ssi1_ipg], "ipg", "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_ipg_per], "per", "imx-ssi.1"); + clk_register_clkdev(clk[ssi2_ipg], "ipg", "imx-ssi.1"); + clk_register_clkdev(clk[esdhc1_ipg_per], "per", "sdhci-esdhc-imx25.0"); + clk_register_clkdev(clk[esdhc1_ipg], "ipg", "sdhci-esdhc-imx25.0"); + clk_register_clkdev(clk[esdhc1_ahb], "ahb", "sdhci-esdhc-imx25.0"); + clk_register_clkdev(clk[esdhc2_ipg_per], "per", "sdhci-esdhc-imx25.1"); + clk_register_clkdev(clk[esdhc2_ipg], "ipg", "sdhci-esdhc-imx25.1"); + clk_register_clkdev(clk[esdhc2_ahb], "ahb", "sdhci-esdhc-imx25.1"); + clk_register_clkdev(clk[csi_ipg_per], "per", "mx2-camera.0"); + clk_register_clkdev(clk[csi_ipg], "ipg", "mx2-camera.0"); + clk_register_clkdev(clk[csi_ahb], "ahb", "mx2-camera.0"); + clk_register_clkdev(clk[dummy], "audmux", NULL); + clk_register_clkdev(clk[can1_ipg], NULL, "flexcan.0"); + clk_register_clkdev(clk[can2_ipg], NULL, "flexcan.1"); + /* i.mx25 has the i.mx35 type sdma */ + clk_register_clkdev(clk[sdma_ipg], "ipg", "imx35-sdma"); + clk_register_clkdev(clk[sdma_ahb], "ahb", "imx35-sdma"); + clk_register_clkdev(clk[iim_ipg], "iim", NULL); + + mxc_timer_init(NULL, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54); + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c new file mode 100644 index 000000000000..50a7ebd8d1b2 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx27.c @@ -0,0 +1,290 @@ +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/clk-provider.h> +#include <linux/of.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include "clk.h" + +#define IO_ADDR_CCM(off) (MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR + (off))) + +/* Register offsets */ +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_MPCTL1 IO_ADDR_CCM(0x8) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_SPCTL1 IO_ADDR_CCM(0x10) +#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) +#define CCM_PCDR0 IO_ADDR_CCM(0x18) +#define CCM_PCDR1 IO_ADDR_CCM(0x1c) +#define CCM_PCCR0 IO_ADDR_CCM(0x20) +#define CCM_PCCR1 IO_ADDR_CCM(0x24) +#define CCM_CCSR IO_ADDR_CCM(0x28) +#define CCM_PMCTL IO_ADDR_CCM(0x2c) +#define CCM_PMCOUNT IO_ADDR_CCM(0x30) +#define CCM_WKGDCTL IO_ADDR_CCM(0x34) + +#define CCM_CSCR_UPDATE_DIS (1 << 31) +#define CCM_CSCR_SSI2 (1 << 23) +#define CCM_CSCR_SSI1 (1 << 22) +#define CCM_CSCR_VPU (1 << 21) +#define CCM_CSCR_MSHC (1 << 20) +#define CCM_CSCR_SPLLRES (1 << 19) +#define CCM_CSCR_MPLLRES (1 << 18) +#define CCM_CSCR_SP (1 << 17) +#define CCM_CSCR_MCU (1 << 16) +#define CCM_CSCR_OSC26MDIV (1 << 4) +#define CCM_CSCR_OSC26M (1 << 3) +#define CCM_CSCR_FPM (1 << 2) +#define CCM_CSCR_SPEN (1 << 1) +#define CCM_CSCR_MPEN (1 << 0) + +/* i.MX27 TO 2+ */ +#define CCM_CSCR_ARM_SRC (1 << 15) + +#define CCM_SPCTL1_LF (1 << 15) +#define CCM_SPCTL1_BRMO (1 << 6) + +static const char *vpu_sel_clks[] = { "spll", "mpll_main2", }; +static const char *cpu_sel_clks[] = { "mpll_main2", "mpll", }; +static const char *clko_sel_clks[] = { + "ckil", "prem", "ckih", "ckih", + "ckih", "mpll", "spll", "cpu_div", + "ahb", "ipg", "per1_div", "per2_div", + "per3_div", "per4_div", "ssi1_div", "ssi2_div", + "nfc_div", "mshc_div", "vpu_div", "60m", + "32k", "usb_div", "dptc", +}; + +static const char *ssi_sel_clks[] = { "spll", "mpll", }; + +enum mx27_clks { + dummy, ckih, ckil, mpll, spll, mpll_main2, ahb, ipg, nfc_div, per1_div, + per2_div, per3_div, per4_div, vpu_sel, vpu_div, usb_div, cpu_sel, + clko_sel, cpu_div, clko_div, ssi1_sel, ssi2_sel, ssi1_div, ssi2_div, + clko_en, ssi2_ipg_gate, ssi1_ipg_gate, slcdc_ipg_gate, sdhc3_ipg_gate, + sdhc2_ipg_gate, sdhc1_ipg_gate, scc_ipg_gate, sahara_ipg_gate, + rtc_ipg_gate, pwm_ipg_gate, owire_ipg_gate, lcdc_ipg_gate, + kpp_ipg_gate, iim_ipg_gate, i2c2_ipg_gate, i2c1_ipg_gate, + gpt6_ipg_gate, gpt5_ipg_gate, gpt4_ipg_gate, gpt3_ipg_gate, + gpt2_ipg_gate, gpt1_ipg_gate, gpio_ipg_gate, fec_ipg_gate, + emma_ipg_gate, dma_ipg_gate, cspi3_ipg_gate, cspi2_ipg_gate, + cspi1_ipg_gate, nfc_baud_gate, ssi2_baud_gate, ssi1_baud_gate, + vpu_baud_gate, per4_gate, per3_gate, per2_gate, per1_gate, + usb_ahb_gate, slcdc_ahb_gate, sahara_ahb_gate, lcdc_ahb_gate, + vpu_ahb_gate, fec_ahb_gate, emma_ahb_gate, emi_ahb_gate, dma_ahb_gate, + csi_ahb_gate, brom_ahb_gate, ata_ahb_gate, wdog_ipg_gate, usb_ipg_gate, + uart6_ipg_gate, uart5_ipg_gate, uart4_ipg_gate, uart3_ipg_gate, + uart2_ipg_gate, uart1_ipg_gate, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx27_clocks_init(unsigned long fref) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[ckih] = imx_clk_fixed("ckih", fref); + clk[ckil] = imx_clk_fixed("ckil", 32768); + clk[mpll] = imx_clk_pllv1("mpll", "ckih", CCM_MPCTL0); + clk[spll] = imx_clk_pllv1("spll", "ckih", CCM_SPCTL0); + clk[mpll_main2] = imx_clk_fixed_factor("mpll_main2", "mpll", 2, 3); + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { + clk[ahb] = imx_clk_divider("ahb", "mpll_main2", CCM_CSCR, 8, 2); + clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + } else { + clk[ahb] = imx_clk_divider("ahb", "mpll_main2", CCM_CSCR, 9, 4); + clk[ipg] = imx_clk_divider("ipg", "ahb", CCM_CSCR, 8, 1); + } + + clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", CCM_PCDR0, 6, 4); + clk[per1_div] = imx_clk_divider("per1_div", "mpll_main2", CCM_PCDR1, 0, 6); + clk[per2_div] = imx_clk_divider("per2_div", "mpll_main2", CCM_PCDR1, 8, 6); + clk[per3_div] = imx_clk_divider("per3_div", "mpll_main2", CCM_PCDR1, 16, 6); + clk[per4_div] = imx_clk_divider("per4_div", "mpll_main2", CCM_PCDR1, 24, 6); + clk[vpu_sel] = imx_clk_mux("vpu_sel", CCM_CSCR, 21, 1, vpu_sel_clks, ARRAY_SIZE(vpu_sel_clks)); + clk[vpu_div] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 3); + clk[usb_div] = imx_clk_divider("usb_div", "spll", CCM_CSCR, 28, 3); + clk[cpu_sel] = imx_clk_mux("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); + clk[clko_sel] = imx_clk_mux("clko_sel", CCM_CCSR, 0, 5, clko_sel_clks, ARRAY_SIZE(clko_sel_clks)); + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + clk[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", CCM_CSCR, 12, 2); + else + clk[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", CCM_CSCR, 13, 3); + clk[clko_div] = imx_clk_divider("clko_div", "clko_sel", CCM_PCDR0, 22, 3); + clk[ssi1_sel] = imx_clk_mux("ssi1_sel", CCM_CSCR, 22, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks)); + clk[ssi2_sel] = imx_clk_mux("ssi2_sel", CCM_CSCR, 23, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks)); + clk[ssi1_div] = imx_clk_divider("ssi1_div", "ssi1_sel", CCM_PCDR0, 16, 6); + clk[ssi2_div] = imx_clk_divider("ssi2_div", "ssi2_sel", CCM_PCDR0, 26, 3); + clk[clko_en] = imx_clk_gate("clko_en", "clko_div", CCM_PCCR0, 0); + clk[ssi2_ipg_gate] = imx_clk_gate("ssi2_ipg_gate", "ipg", CCM_PCCR0, 0); + clk[ssi1_ipg_gate] = imx_clk_gate("ssi1_ipg_gate", "ipg", CCM_PCCR0, 1); + clk[slcdc_ipg_gate] = imx_clk_gate("slcdc_ipg_gate", "ipg", CCM_PCCR0, 2); + clk[sdhc3_ipg_gate] = imx_clk_gate("sdhc3_ipg_gate", "ipg", CCM_PCCR0, 3); + clk[sdhc2_ipg_gate] = imx_clk_gate("sdhc2_ipg_gate", "ipg", CCM_PCCR0, 4); + clk[sdhc1_ipg_gate] = imx_clk_gate("sdhc1_ipg_gate", "ipg", CCM_PCCR0, 5); + clk[scc_ipg_gate] = imx_clk_gate("scc_ipg_gate", "ipg", CCM_PCCR0, 6); + clk[sahara_ipg_gate] = imx_clk_gate("sahara_ipg_gate", "ipg", CCM_PCCR0, 7); + clk[rtc_ipg_gate] = imx_clk_gate("rtc_ipg_gate", "ipg", CCM_PCCR0, 9); + clk[pwm_ipg_gate] = imx_clk_gate("pwm_ipg_gate", "ipg", CCM_PCCR0, 11); + clk[owire_ipg_gate] = imx_clk_gate("owire_ipg_gate", "ipg", CCM_PCCR0, 12); + clk[lcdc_ipg_gate] = imx_clk_gate("lcdc_ipg_gate", "ipg", CCM_PCCR0, 14); + clk[kpp_ipg_gate] = imx_clk_gate("kpp_ipg_gate", "ipg", CCM_PCCR0, 15); + clk[iim_ipg_gate] = imx_clk_gate("iim_ipg_gate", "ipg", CCM_PCCR0, 16); + clk[i2c2_ipg_gate] = imx_clk_gate("i2c2_ipg_gate", "ipg", CCM_PCCR0, 17); + clk[i2c1_ipg_gate] = imx_clk_gate("i2c1_ipg_gate", "ipg", CCM_PCCR0, 18); + clk[gpt6_ipg_gate] = imx_clk_gate("gpt6_ipg_gate", "ipg", CCM_PCCR0, 19); + clk[gpt5_ipg_gate] = imx_clk_gate("gpt5_ipg_gate", "ipg", CCM_PCCR0, 20); + clk[gpt4_ipg_gate] = imx_clk_gate("gpt4_ipg_gate", "ipg", CCM_PCCR0, 21); + clk[gpt3_ipg_gate] = imx_clk_gate("gpt3_ipg_gate", "ipg", CCM_PCCR0, 22); + clk[gpt2_ipg_gate] = imx_clk_gate("gpt2_ipg_gate", "ipg", CCM_PCCR0, 23); + clk[gpt1_ipg_gate] = imx_clk_gate("gpt1_ipg_gate", "ipg", CCM_PCCR0, 24); + clk[gpio_ipg_gate] = imx_clk_gate("gpio_ipg_gate", "ipg", CCM_PCCR0, 25); + clk[fec_ipg_gate] = imx_clk_gate("fec_ipg_gate", "ipg", CCM_PCCR0, 26); + clk[emma_ipg_gate] = imx_clk_gate("emma_ipg_gate", "ipg", CCM_PCCR0, 27); + clk[dma_ipg_gate] = imx_clk_gate("dma_ipg_gate", "ipg", CCM_PCCR0, 28); + clk[cspi3_ipg_gate] = imx_clk_gate("cspi3_ipg_gate", "ipg", CCM_PCCR0, 29); + clk[cspi2_ipg_gate] = imx_clk_gate("cspi2_ipg_gate", "ipg", CCM_PCCR0, 30); + clk[cspi1_ipg_gate] = imx_clk_gate("cspi1_ipg_gate", "ipg", CCM_PCCR0, 31); + clk[nfc_baud_gate] = imx_clk_gate("nfc_baud_gate", "nfc_div", CCM_PCCR1, 3); + clk[ssi2_baud_gate] = imx_clk_gate("ssi2_baud_gate", "ssi2_div", CCM_PCCR1, 4); + clk[ssi1_baud_gate] = imx_clk_gate("ssi1_baud_gate", "ssi1_div", CCM_PCCR1, 5); + clk[vpu_baud_gate] = imx_clk_gate("vpu_baud_gate", "vpu_div", CCM_PCCR1, 6); + clk[per4_gate] = imx_clk_gate("per4_gate", "per4_div", CCM_PCCR1, 7); + clk[per3_gate] = imx_clk_gate("per3_gate", "per3_div", CCM_PCCR1, 8); + clk[per2_gate] = imx_clk_gate("per2_gate", "per2_div", CCM_PCCR1, 9); + clk[per1_gate] = imx_clk_gate("per1_gate", "per1_div", CCM_PCCR1, 10); + clk[usb_ahb_gate] = imx_clk_gate("usb_ahb_gate", "ahb", CCM_PCCR1, 11); + clk[slcdc_ahb_gate] = imx_clk_gate("slcdc_ahb_gate", "ahb", CCM_PCCR1, 12); + clk[sahara_ahb_gate] = imx_clk_gate("sahara_ahb_gate", "ahb", CCM_PCCR1, 13); + clk[lcdc_ahb_gate] = imx_clk_gate("lcdc_ahb_gate", "ahb", CCM_PCCR1, 15); + clk[vpu_ahb_gate] = imx_clk_gate("vpu_ahb_gate", "ahb", CCM_PCCR1, 16); + clk[fec_ahb_gate] = imx_clk_gate("fec_ahb_gate", "ahb", CCM_PCCR1, 17); + clk[emma_ahb_gate] = imx_clk_gate("emma_ahb_gate", "ahb", CCM_PCCR1, 18); + clk[emi_ahb_gate] = imx_clk_gate("emi_ahb_gate", "ahb", CCM_PCCR1, 19); + clk[dma_ahb_gate] = imx_clk_gate("dma_ahb_gate", "ahb", CCM_PCCR1, 20); + clk[csi_ahb_gate] = imx_clk_gate("csi_ahb_gate", "ahb", CCM_PCCR1, 21); + clk[brom_ahb_gate] = imx_clk_gate("brom_ahb_gate", "ahb", CCM_PCCR1, 22); + clk[ata_ahb_gate] = imx_clk_gate("ata_ahb_gate", "ahb", CCM_PCCR1, 23); + clk[wdog_ipg_gate] = imx_clk_gate("wdog_ipg_gate", "ipg", CCM_PCCR1, 24); + clk[usb_ipg_gate] = imx_clk_gate("usb_ipg_gate", "ipg", CCM_PCCR1, 25); + clk[uart6_ipg_gate] = imx_clk_gate("uart6_ipg_gate", "ipg", CCM_PCCR1, 26); + clk[uart5_ipg_gate] = imx_clk_gate("uart5_ipg_gate", "ipg", CCM_PCCR1, 27); + clk[uart4_ipg_gate] = imx_clk_gate("uart4_ipg_gate", "ipg", CCM_PCCR1, 28); + clk[uart3_ipg_gate] = imx_clk_gate("uart3_ipg_gate", "ipg", CCM_PCCR1, 29); + clk[uart2_ipg_gate] = imx_clk_gate("uart2_ipg_gate", "ipg", CCM_PCCR1, 30); + clk[uart1_ipg_gate] = imx_clk_gate("uart1_ipg_gate", "ipg", CCM_PCCR1, 31); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX27 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[uart1_ipg_gate], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_ipg_gate], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_ipg_gate], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_ipg_gate], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_ipg_gate], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.4"); + clk_register_clkdev(clk[uart6_ipg_gate], "ipg", "imx21-uart.5"); + clk_register_clkdev(clk[per1_gate], "per", "imx21-uart.5"); + clk_register_clkdev(clk[gpt1_ipg_gate], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[gpt2_ipg_gate], "ipg", "imx-gpt.1"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.1"); + clk_register_clkdev(clk[gpt3_ipg_gate], "ipg", "imx-gpt.2"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.2"); + clk_register_clkdev(clk[gpt4_ipg_gate], "ipg", "imx-gpt.3"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.3"); + clk_register_clkdev(clk[gpt5_ipg_gate], "ipg", "imx-gpt.4"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.4"); + clk_register_clkdev(clk[gpt6_ipg_gate], "ipg", "imx-gpt.5"); + clk_register_clkdev(clk[per1_gate], "per", "imx-gpt.5"); + clk_register_clkdev(clk[pwm_ipg_gate], NULL, "mxc_pwm.0"); + clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.0"); + clk_register_clkdev(clk[sdhc1_ipg_gate], "ipg", "mxc-mmc.0"); + clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.1"); + clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "mxc-mmc.1"); + clk_register_clkdev(clk[per2_gate], "per", "mxc-mmc.2"); + clk_register_clkdev(clk[sdhc2_ipg_gate], "ipg", "mxc-mmc.2"); + clk_register_clkdev(clk[cspi1_ipg_gate], NULL, "imx27-cspi.0"); + clk_register_clkdev(clk[cspi2_ipg_gate], NULL, "imx27-cspi.1"); + clk_register_clkdev(clk[cspi3_ipg_gate], NULL, "imx27-cspi.2"); + clk_register_clkdev(clk[per3_gate], "per", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0"); + clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx-fb.0"); + clk_register_clkdev(clk[csi_ahb_gate], NULL, "mx2-camera.0"); + clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_ipg_gate], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1"); + clk_register_clkdev(clk[nfc_baud_gate], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[vpu_baud_gate], "per", "imx-vpu"); + clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "imx-vpu"); + clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma"); + clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx-dma"); + clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0"); + clk_register_clkdev(clk[fec_ahb_gate], "ahb", "imx27-fec.0"); + clk_register_clkdev(clk[wdog_ipg_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[i2c1_ipg_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_ipg_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[owire_ipg_gate], NULL, "mxc_w1.0"); + clk_register_clkdev(clk[kpp_ipg_gate], NULL, "imx-keypad"); + clk_register_clkdev(clk[emma_ahb_gate], "ahb", "imx-emma"); + clk_register_clkdev(clk[emma_ipg_gate], "ipg", "imx-emma"); + clk_register_clkdev(clk[iim_ipg_gate], "iim", NULL); + clk_register_clkdev(clk[gpio_ipg_gate], "gpio", NULL); + clk_register_clkdev(clk[brom_ahb_gate], "brom", NULL); + clk_register_clkdev(clk[ata_ahb_gate], "ata", NULL); + clk_register_clkdev(clk[rtc_ipg_gate], "rtc", NULL); + clk_register_clkdev(clk[scc_ipg_gate], "scc", NULL); + clk_register_clkdev(clk[cpu_div], "cpu", NULL); + clk_register_clkdev(clk[emi_ahb_gate], "emi_ahb" , NULL); + clk_register_clkdev(clk[ssi1_baud_gate], "bitrate" , "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_baud_gate], "bitrate" , "imx-ssi.1"); + + mxc_timer_init(NULL, MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), + MX27_INT_GPT1); + + clk_prepare_enable(clk[emi_ahb_gate]); + + return 0; +} + +#ifdef CONFIG_OF +int __init mx27_clocks_init_dt(void) +{ + struct device_node *np; + u32 fref = 26000000; /* default */ + + for_each_compatible_node(np, NULL, "fixed-clock") { + if (!of_device_is_compatible(np, "fsl,imx-osc26m")) + continue; + + if (!of_property_read_u32(np, "clock-frequency", &fref)) + break; + } + + return mx27_clocks_init(fref); +} +#endif diff --git a/arch/arm/mach-imx/clk-imx31.c b/arch/arm/mach-imx/clk-imx31.c new file mode 100644 index 000000000000..a854b9cae5ea --- /dev/null +++ b/arch/arm/mach-imx/clk-imx31.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2012 Sascha Hauer <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation. + */ + +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/io.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/mx31.h> +#include <mach/common.h> + +#include "clk.h" +#include "crmregs-imx3.h" + +static const char *mcu_main_sel[] = { "spll", "mpll", }; +static const char *per_sel[] = { "per_div", "ipg", }; +static const char *csi_sel[] = { "upll", "spll", }; +static const char *fir_sel[] = { "mcu_main", "upll", "spll" }; + +enum mx31_clks { + ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg, per_div, + per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre, + fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate, + iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate, + uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate, + mstick1_gate, mstick2_gate, csi_gate, rtc_gate, wdog_gate, pwm_gate, + sim_gate, ect_gate, usb_gate, kpp_gate, ipu_gate, uart3_gate, + uart4_gate, uart5_gate, owire_gate, ssi2_gate, cspi1_gate, cspi2_gate, + gacc_gate, emi_gate, rtic_gate, firi_gate, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx31_clocks_init(unsigned long fref) +{ + void __iomem *base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); + int i; + + clk[ckih] = imx_clk_fixed("ckih", fref); + clk[ckil] = imx_clk_fixed("ckil", 32768); + clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MXC_CCM_MPCTL); + clk[spll] = imx_clk_pllv1("spll", "ckih", base + MXC_CCM_SRPCTL); + clk[upll] = imx_clk_pllv1("upll", "ckih", base + MXC_CCM_UPCTL); + clk[mcu_main] = imx_clk_mux("mcu_main", base + MXC_CCM_PMCR0, 31, 1, mcu_main_sel, ARRAY_SIZE(mcu_main_sel)); + clk[hsp] = imx_clk_divider("hsp", "mcu_main", base + MXC_CCM_PDR0, 11, 3); + clk[ahb] = imx_clk_divider("ahb", "mcu_main", base + MXC_CCM_PDR0, 3, 3); + clk[nfc] = imx_clk_divider("nfc", "ahb", base + MXC_CCM_PDR0, 8, 3); + clk[ipg] = imx_clk_divider("ipg", "ahb", base + MXC_CCM_PDR0, 6, 2); + clk[per_div] = imx_clk_divider("per_div", "upll", base + MXC_CCM_PDR0, 16, 5); + clk[per] = imx_clk_mux("per", base + MXC_CCM_CCMR, 24, 1, per_sel, ARRAY_SIZE(per_sel)); + clk[csi] = imx_clk_mux("csi_sel", base + MXC_CCM_CCMR, 25, 1, csi_sel, ARRAY_SIZE(csi_sel)); + clk[fir] = imx_clk_mux("fir_sel", base + MXC_CCM_CCMR, 11, 2, fir_sel, ARRAY_SIZE(fir_sel)); + clk[csi_div] = imx_clk_divider("csi_div", "csi_sel", base + MXC_CCM_PDR0, 23, 9); + clk[usb_div_pre] = imx_clk_divider("usb_div_pre", "upll", base + MXC_CCM_PDR1, 30, 2); + clk[usb_div_post] = imx_clk_divider("usb_div_post", "usb_div_pre", base + MXC_CCM_PDR1, 27, 3); + clk[fir_div_pre] = imx_clk_divider("fir_div_pre", "fir_sel", base + MXC_CCM_PDR1, 24, 3); + clk[fir_div_post] = imx_clk_divider("fir_div_post", "fir_div_pre", base + MXC_CCM_PDR1, 23, 6); + clk[sdhc1_gate] = imx_clk_gate2("sdhc1_gate", "per", base + MXC_CCM_CGR0, 0); + clk[sdhc2_gate] = imx_clk_gate2("sdhc2_gate", "per", base + MXC_CCM_CGR0, 2); + clk[gpt_gate] = imx_clk_gate2("gpt_gate", "per", base + MXC_CCM_CGR0, 4); + clk[epit1_gate] = imx_clk_gate2("epit1_gate", "per", base + MXC_CCM_CGR0, 6); + clk[epit2_gate] = imx_clk_gate2("epit2_gate", "per", base + MXC_CCM_CGR0, 8); + clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MXC_CCM_CGR0, 10); + clk[ata_gate] = imx_clk_gate2("ata_gate", "ipg", base + MXC_CCM_CGR0, 12); + clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ahb", base + MXC_CCM_CGR0, 14); + clk[cspi3_gate] = imx_clk_gate2("cspi3_gate", "ipg", base + MXC_CCM_CGR0, 16); + clk[rng_gate] = imx_clk_gate2("rng_gate", "ipg", base + MXC_CCM_CGR0, 18); + clk[uart1_gate] = imx_clk_gate2("uart1_gate", "per", base + MXC_CCM_CGR0, 20); + clk[uart2_gate] = imx_clk_gate2("uart2_gate", "per", base + MXC_CCM_CGR0, 22); + clk[ssi1_gate] = imx_clk_gate2("ssi1_gate", "spll", base + MXC_CCM_CGR0, 24); + clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "per", base + MXC_CCM_CGR0, 26); + clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "per", base + MXC_CCM_CGR0, 28); + clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per", base + MXC_CCM_CGR0, 30); + clk[hantro_gate] = imx_clk_gate2("hantro_gate", "per", base + MXC_CCM_CGR1, 0); + clk[mstick1_gate] = imx_clk_gate2("mstick1_gate", "per", base + MXC_CCM_CGR1, 2); + clk[mstick2_gate] = imx_clk_gate2("mstick2_gate", "per", base + MXC_CCM_CGR1, 4); + clk[csi_gate] = imx_clk_gate2("csi_gate", "csi_div", base + MXC_CCM_CGR1, 6); + clk[rtc_gate] = imx_clk_gate2("rtc_gate", "ipg", base + MXC_CCM_CGR1, 8); + clk[wdog_gate] = imx_clk_gate2("wdog_gate", "ipg", base + MXC_CCM_CGR1, 10); + clk[pwm_gate] = imx_clk_gate2("pwm_gate", "per", base + MXC_CCM_CGR1, 12); + clk[sim_gate] = imx_clk_gate2("sim_gate", "per", base + MXC_CCM_CGR1, 14); + clk[ect_gate] = imx_clk_gate2("ect_gate", "per", base + MXC_CCM_CGR1, 16); + clk[usb_gate] = imx_clk_gate2("usb_gate", "ahb", base + MXC_CCM_CGR1, 18); + clk[kpp_gate] = imx_clk_gate2("kpp_gate", "ipg", base + MXC_CCM_CGR1, 20); + clk[ipu_gate] = imx_clk_gate2("ipu_gate", "hsp", base + MXC_CCM_CGR1, 22); + clk[uart3_gate] = imx_clk_gate2("uart3_gate", "per", base + MXC_CCM_CGR1, 24); + clk[uart4_gate] = imx_clk_gate2("uart4_gate", "per", base + MXC_CCM_CGR1, 26); + clk[uart5_gate] = imx_clk_gate2("uart5_gate", "per", base + MXC_CCM_CGR1, 28); + clk[owire_gate] = imx_clk_gate2("owire_gate", "per", base + MXC_CCM_CGR1, 30); + clk[ssi2_gate] = imx_clk_gate2("ssi2_gate", "spll", base + MXC_CCM_CGR2, 0); + clk[cspi1_gate] = imx_clk_gate2("cspi1_gate", "ipg", base + MXC_CCM_CGR2, 2); + clk[cspi2_gate] = imx_clk_gate2("cspi2_gate", "ipg", base + MXC_CCM_CGR2, 4); + clk[gacc_gate] = imx_clk_gate2("gacc_gate", "per", base + MXC_CCM_CGR2, 6); + clk[emi_gate] = imx_clk_gate2("emi_gate", "ahb", base + MXC_CCM_CGR2, 8); + clk[rtic_gate] = imx_clk_gate2("rtic_gate", "ahb", base + MXC_CCM_CGR2, 10); + clk[firi_gate] = imx_clk_gate2("firi_gate", "upll", base+MXC_CCM_CGR2, 12); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("imx31 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[cspi1_gate], NULL, "imx31-cspi.0"); + clk_register_clkdev(clk[cspi2_gate], NULL, "imx31-cspi.1"); + clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2"); + clk_register_clkdev(clk[pwm_gate], "pwm", NULL); + clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[rtc_gate], "rtc", NULL); + clk_register_clkdev(clk[epit1_gate], "epit", NULL); + clk_register_clkdev(clk[epit2_gate], "epit", NULL); + clk_register_clkdev(clk[nfc], NULL, "mxc_nand.0"); + clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); + clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); + clk_register_clkdev(clk[kpp_gate], "kpp", NULL); + clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_div_post], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[usb_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0"); + /* i.mx31 has the i.mx21 type uart */ + clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_gate], "per", "imx21-uart.3"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_gate], "per", "imx21-uart.4"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); + clk_register_clkdev(clk[sdhc1_gate], NULL, "mxc-mmc.0"); + clk_register_clkdev(clk[sdhc2_gate], NULL, "mxc-mmc.1"); + clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1"); + clk_register_clkdev(clk[firi_gate], "firi", NULL); + clk_register_clkdev(clk[ata_gate], NULL, "pata_imx"); + clk_register_clkdev(clk[rtic_gate], "rtic", NULL); + clk_register_clkdev(clk[rng_gate], "rng", NULL); + clk_register_clkdev(clk[sdma_gate], NULL, "imx31-sdma"); + clk_register_clkdev(clk[iim_gate], "iim", NULL); + + clk_set_parent(clk[csi], clk[upll]); + clk_prepare_enable(clk[emi_gate]); + clk_prepare_enable(clk[iim_gate]); + mx31_revision(); + clk_disable_unprepare(clk[iim_gate]); + + mxc_timer_init(NULL, MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), + MX31_INT_GPT); + + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c new file mode 100644 index 000000000000..a9e60bf7dd75 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx35.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2012 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> + * + * 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/mm.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> + +#include "crmregs-imx3.h" +#include "clk.h" + +struct arm_ahb_div { + unsigned char arm, ahb, sel; +}; + +static struct arm_ahb_div clk_consumer[] = { + { .arm = 1, .ahb = 4, .sel = 0}, + { .arm = 1, .ahb = 3, .sel = 1}, + { .arm = 2, .ahb = 2, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 4, .ahb = 1, .sel = 0}, + { .arm = 1, .ahb = 5, .sel = 0}, + { .arm = 1, .ahb = 8, .sel = 0}, + { .arm = 1, .ahb = 6, .sel = 1}, + { .arm = 2, .ahb = 4, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 4, .ahb = 2, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, +}; + +static char hsp_div_532[] = { 4, 8, 3, 0 }; +static char hsp_div_400[] = { 3, 6, 3, 0 }; + +static const char *std_sel[] = {"ppll", "arm"}; +static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"}; + +enum mx35_clks { + ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, + arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel, + esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre, + spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre, + ssi2_div_post, usb_sel, usb_div, nfc_div, asrc_gate, pata_gate, + audmux_gate, can1_gate, can2_gate, cspi1_gate, cspi2_gate, ect_gate, + edio_gate, emi_gate, epit1_gate, epit2_gate, esai_gate, esdhc1_gate, + esdhc2_gate, esdhc3_gate, fec_gate, gpio1_gate, gpio2_gate, gpio3_gate, + gpt_gate, i2c1_gate, i2c2_gate, i2c3_gate, iomuxc_gate, ipu_gate, + kpp_gate, mlb_gate, mshc_gate, owire_gate, pwm_gate, rngc_gate, + rtc_gate, rtic_gate, scc_gate, sdma_gate, spba_gate, spdif_gate, + ssi1_gate, ssi2_gate, uart1_gate, uart2_gate, uart3_gate, usbotg_gate, + wdog_gate, max_gate, admux_gate, csi_gate, iim_gate, gpu2d_gate, + clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx35_clocks_init() +{ + void __iomem *base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR); + u32 pdr0, consumer_sel, hsp_sel; + struct arm_ahb_div *aad; + unsigned char *hsp_div; + int i; + + pdr0 = __raw_readl(base + MXC_CCM_PDR0); + consumer_sel = (pdr0 >> 16) & 0xf; + aad = &clk_consumer[consumer_sel]; + if (!aad->arm) { + pr_err("i.MX35 clk: illegal consumer mux selection 0x%x\n", consumer_sel); + /* + * We are basically stuck. Continue with a default entry and hope we + * get far enough to actually show the above message + */ + aad = &clk_consumer[0]; + } + + clk[ckih] = imx_clk_fixed("ckih", 24000000); + clk[mpll] = imx_clk_pllv1("mpll", "ckih", base + MX35_CCM_MPCTL); + clk[ppll] = imx_clk_pllv1("ppll", "ckih", base + MX35_CCM_PPCTL); + + clk[mpll] = imx_clk_fixed_factor("mpll_075", "mpll", 3, 4); + + if (aad->sel) + clk[arm] = imx_clk_fixed_factor("arm", "mpll_075", 1, aad->arm); + else + clk[arm] = imx_clk_fixed_factor("arm", "mpll", 1, aad->arm); + + if (clk_get_rate(clk[arm]) > 400000000) + hsp_div = hsp_div_532; + else + hsp_div = hsp_div_400; + + hsp_sel = (pdr0 >> 20) & 0x3; + if (!hsp_div[hsp_sel]) { + pr_err("i.MX35 clk: illegal hsp clk selection 0x%x\n", hsp_sel); + hsp_sel = 0; + } + + clk[hsp] = imx_clk_fixed_factor("hsp", "arm", 1, hsp_div[hsp_sel]); + + clk[ahb] = imx_clk_fixed_factor("ahb", "arm", 1, aad->ahb); + clk[ipg] = imx_clk_fixed_factor("ipg", "ahb", 1, 2); + + clk[arm_per_div] = imx_clk_divider("arm_per_div", "arm", base + MX35_CCM_PDR4, 16, 6); + clk[ahb_per_div] = imx_clk_divider("ahb_per_div", "ahb", base + MXC_CCM_PDR0, 12, 3); + clk[ipg_per] = imx_clk_mux("ipg_per", base + MXC_CCM_PDR0, 26, 1, ipg_per_sel, ARRAY_SIZE(ipg_per_sel)); + + clk[uart_sel] = imx_clk_mux("uart_sel", base + MX35_CCM_PDR3, 14, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[uart_div] = imx_clk_divider("uart_div", "uart_sel", base + MX35_CCM_PDR4, 10, 6); + + clk[esdhc_sel] = imx_clk_mux("esdhc_sel", base + MX35_CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[esdhc1_div] = imx_clk_divider("esdhc1_div", "esdhc_sel", base + MX35_CCM_PDR3, 0, 6); + clk[esdhc2_div] = imx_clk_divider("esdhc2_div", "esdhc_sel", base + MX35_CCM_PDR3, 8, 6); + clk[esdhc3_div] = imx_clk_divider("esdhc3_div", "esdhc_sel", base + MX35_CCM_PDR3, 16, 6); + + clk[spdif_sel] = imx_clk_mux("spdif_sel", base + MX35_CCM_PDR3, 22, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[spdif_div_pre] = imx_clk_divider("spdif_div_pre", "spdif_sel", base + MX35_CCM_PDR3, 29, 3); /* divide by 1 not allowed */ + clk[spdif_div_post] = imx_clk_divider("spdif_div_post", "spdif_div_pre", base + MX35_CCM_PDR3, 23, 6); + + clk[ssi_sel] = imx_clk_mux("ssi_sel", base + MX35_CCM_PDR2, 6, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[ssi1_div_pre] = imx_clk_divider("ssi1_div_pre", "ssi_sel", base + MX35_CCM_PDR2, 24, 3); + clk[ssi1_div_post] = imx_clk_divider("ssi1_div_post", "ssi1_div_pre", base + MX35_CCM_PDR2, 0, 6); + clk[ssi2_div_pre] = imx_clk_divider("ssi2_div_pre", "ssi_sel", base + MX35_CCM_PDR2, 27, 3); + clk[ssi2_div_post] = imx_clk_divider("ssi2_div_post", "ssi2_div_pre", base + MX35_CCM_PDR2, 8, 6); + + clk[usb_sel] = imx_clk_mux("usb_sel", base + MX35_CCM_PDR4, 9, 1, std_sel, ARRAY_SIZE(std_sel)); + clk[usb_div] = imx_clk_divider("usb_div", "usb_sel", base + MX35_CCM_PDR4, 22, 6); + + clk[nfc_div] = imx_clk_divider("nfc_div", "ahb", base + MX35_CCM_PDR4, 28, 4); + + clk[asrc_gate] = imx_clk_gate2("asrc_gate", "ipg", base + MX35_CCM_CGR0, 0); + clk[pata_gate] = imx_clk_gate2("pata_gate", "ipg", base + MX35_CCM_CGR0, 2); + clk[audmux_gate] = imx_clk_gate2("audmux_gate", "ipg", base + MX35_CCM_CGR0, 4); + clk[can1_gate] = imx_clk_gate2("can1_gate", "ipg", base + MX35_CCM_CGR0, 6); + clk[can2_gate] = imx_clk_gate2("can2_gate", "ipg", base + MX35_CCM_CGR0, 8); + clk[cspi1_gate] = imx_clk_gate2("cspi1_gate", "ipg", base + MX35_CCM_CGR0, 10); + clk[cspi2_gate] = imx_clk_gate2("cspi2_gate", "ipg", base + MX35_CCM_CGR0, 12); + clk[ect_gate] = imx_clk_gate2("ect_gate", "ipg", base + MX35_CCM_CGR0, 14); + clk[edio_gate] = imx_clk_gate2("edio_gate", "ipg", base + MX35_CCM_CGR0, 16); + clk[emi_gate] = imx_clk_gate2("emi_gate", "ipg", base + MX35_CCM_CGR0, 18); + clk[epit1_gate] = imx_clk_gate2("epit1_gate", "ipg", base + MX35_CCM_CGR0, 20); + clk[epit2_gate] = imx_clk_gate2("epit2_gate", "ipg", base + MX35_CCM_CGR0, 22); + clk[esai_gate] = imx_clk_gate2("esai_gate", "ipg", base + MX35_CCM_CGR0, 24); + clk[esdhc1_gate] = imx_clk_gate2("esdhc1_gate", "esdhc1_div", base + MX35_CCM_CGR0, 26); + clk[esdhc2_gate] = imx_clk_gate2("esdhc2_gate", "esdhc2_div", base + MX35_CCM_CGR0, 28); + clk[esdhc3_gate] = imx_clk_gate2("esdhc3_gate", "esdhc3_div", base + MX35_CCM_CGR0, 30); + + clk[fec_gate] = imx_clk_gate2("fec_gate", "ipg", base + MX35_CCM_CGR1, 0); + clk[gpio1_gate] = imx_clk_gate2("gpio1_gate", "ipg", base + MX35_CCM_CGR1, 2); + clk[gpio2_gate] = imx_clk_gate2("gpio2_gate", "ipg", base + MX35_CCM_CGR1, 4); + clk[gpio3_gate] = imx_clk_gate2("gpio3_gate", "ipg", base + MX35_CCM_CGR1, 6); + clk[gpt_gate] = imx_clk_gate2("gpt_gate", "ipg", base + MX35_CCM_CGR1, 8); + clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "ipg_per", base + MX35_CCM_CGR1, 10); + clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "ipg_per", base + MX35_CCM_CGR1, 12); + clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "ipg_per", base + MX35_CCM_CGR1, 14); + clk[iomuxc_gate] = imx_clk_gate2("iomuxc_gate", "ipg", base + MX35_CCM_CGR1, 16); + clk[ipu_gate] = imx_clk_gate2("ipu_gate", "hsp", base + MX35_CCM_CGR1, 18); + clk[kpp_gate] = imx_clk_gate2("kpp_gate", "ipg", base + MX35_CCM_CGR1, 20); + clk[mlb_gate] = imx_clk_gate2("mlb_gate", "ahb", base + MX35_CCM_CGR1, 22); + clk[mshc_gate] = imx_clk_gate2("mshc_gate", "dummy", base + MX35_CCM_CGR1, 24); + clk[owire_gate] = imx_clk_gate2("owire_gate", "ipg_per", base + MX35_CCM_CGR1, 26); + clk[pwm_gate] = imx_clk_gate2("pwm_gate", "ipg_per", base + MX35_CCM_CGR1, 28); + clk[rngc_gate] = imx_clk_gate2("rngc_gate", "ipg", base + MX35_CCM_CGR1, 30); + + clk[rtc_gate] = imx_clk_gate2("rtc_gate", "ipg", base + MX35_CCM_CGR2, 0); + clk[rtic_gate] = imx_clk_gate2("rtic_gate", "ahb", base + MX35_CCM_CGR2, 2); + clk[scc_gate] = imx_clk_gate2("scc_gate", "ipg", base + MX35_CCM_CGR2, 4); + clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ahb", base + MX35_CCM_CGR2, 6); + clk[spba_gate] = imx_clk_gate2("spba_gate", "ipg", base + MX35_CCM_CGR2, 8); + clk[spdif_gate] = imx_clk_gate2("spdif_gate", "spdif_div_post", base + MX35_CCM_CGR2, 10); + clk[ssi1_gate] = imx_clk_gate2("ssi1_gate", "ssi1_div_post", base + MX35_CCM_CGR2, 12); + clk[ssi2_gate] = imx_clk_gate2("ssi2_gate", "ssi2_div_post", base + MX35_CCM_CGR2, 14); + clk[uart1_gate] = imx_clk_gate2("uart1_gate", "uart_div", base + MX35_CCM_CGR2, 16); + clk[uart2_gate] = imx_clk_gate2("uart2_gate", "uart_div", base + MX35_CCM_CGR2, 18); + clk[uart3_gate] = imx_clk_gate2("uart3_gate", "uart_div", base + MX35_CCM_CGR2, 20); + clk[usbotg_gate] = imx_clk_gate2("usbotg_gate", "ahb", base + MX35_CCM_CGR2, 22); + clk[wdog_gate] = imx_clk_gate2("wdog_gate", "ipg", base + MX35_CCM_CGR2, 24); + clk[max_gate] = imx_clk_gate2("max_gate", "dummy", base + MX35_CCM_CGR2, 26); + clk[admux_gate] = imx_clk_gate2("admux_gate", "ipg", base + MX35_CCM_CGR2, 30); + + clk[csi_gate] = imx_clk_gate2("csi_gate", "ipg", base + MX35_CCM_CGR3, 0); + clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MX35_CCM_CGR3, 2); + clk[gpu2d_gate] = imx_clk_gate2("gpu2d_gate", "ahb", base + MX35_CCM_CGR3, 4); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX35 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + + clk_register_clkdev(clk[pata_gate], NULL, "pata_imx"); + clk_register_clkdev(clk[can1_gate], NULL, "flexcan.0"); + clk_register_clkdev(clk[can2_gate], NULL, "flexcan.1"); + clk_register_clkdev(clk[cspi1_gate], "per", "imx35-cspi.0"); + clk_register_clkdev(clk[cspi1_gate], "ipg", "imx35-cspi.0"); + clk_register_clkdev(clk[cspi2_gate], "per", "imx35-cspi.1"); + clk_register_clkdev(clk[cspi2_gate], "ipg", "imx35-cspi.1"); + clk_register_clkdev(clk[epit1_gate], NULL, "imx-epit.0"); + clk_register_clkdev(clk[epit2_gate], NULL, "imx-epit.1"); + clk_register_clkdev(clk[esdhc1_gate], "per", "sdhci-esdhc-imx35.0"); + clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.0"); + clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.0"); + clk_register_clkdev(clk[esdhc2_gate], "per", "sdhci-esdhc-imx35.1"); + clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.1"); + clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.1"); + clk_register_clkdev(clk[esdhc3_gate], "per", "sdhci-esdhc-imx35.2"); + clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.2"); + clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.2"); + /* i.mx35 has the i.mx27 type fec */ + clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0"); + clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); + clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); + clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1"); + clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma"); + clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.0"); + clk_register_clkdev(clk[ssi1_div_post], "per", "imx-ssi.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.1"); + clk_register_clkdev(clk[ssi2_div_post], "per", "imx-ssi.1"); + /* i.mx35 has the i.mx21 type uart */ + clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usbotg_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[nfc_div], NULL, "mxc_nand.0"); + + clk_prepare_enable(clk[spba_gate]); + clk_prepare_enable(clk[gpio1_gate]); + clk_prepare_enable(clk[gpio2_gate]); + clk_prepare_enable(clk[gpio3_gate]); + clk_prepare_enable(clk[iim_gate]); + clk_prepare_enable(clk[emi_gate]); + + imx_print_silicon_rev("i.MX35", mx35_revision()); + +#ifdef CONFIG_MXC_USE_EPIT + epit_timer_init(&epit1_clk, + MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1); +#else + mxc_timer_init(NULL, MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), + MX35_INT_GPT); +#endif + + return 0; +} diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c new file mode 100644 index 000000000000..fcd94f3b0f0e --- /dev/null +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> + * + * 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/mm.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <mach/common.h> + +#include "crm-regs-imx5.h" +#include "clk.h" + +/* Low-power Audio Playback Mode clock */ +static const char *lp_apm_sel[] = { "osc", }; + +/* This is used multiple times */ +static const char *standard_pll_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "lp_apm", }; +static const char *periph_apm_sel[] = { "pll1_sw", "pll3_sw", "lp_apm", }; +static const char *main_bus_sel[] = { "pll2_sw", "periph_apm", }; +static const char *per_lp_apm_sel[] = { "main_bus", "lp_apm", }; +static const char *per_root_sel[] = { "per_podf", "ipg", }; +static const char *esdhc_c_sel[] = { "esdhc_a_podf", "esdhc_b_podf", }; +static const char *esdhc_d_sel[] = { "esdhc_a_podf", "esdhc_b_podf", }; +static const char *ssi_apm_sels[] = { "ckih1", "lp_amp", "ckih2", }; +static const char *ssi_clk_sels[] = { "pll1_sw", "pll2_sw", "pll3_sw", "ssi_apm", }; +static const char *ssi3_clk_sels[] = { "ssi1_root_gate", "ssi2_root_gate", }; +static const char *ssi_ext1_com_sels[] = { "ssi_ext1_podf", "ssi1_root_gate", }; +static const char *ssi_ext2_com_sels[] = { "ssi_ext2_podf", "ssi2_root_gate", }; +static const char *emi_slow_sel[] = { "main_bus", "ahb", }; +static const char *usb_phy_sel_str[] = { "osc", "usb_phy_podf", }; +static const char *mx51_ipu_di0_sel[] = { "di_pred", "osc", "ckih1", "tve_di", }; +static const char *mx53_ipu_di0_sel[] = { "di_pred", "osc", "ckih1", "di_pll4_podf", "dummy", "ldb_di0", }; +static const char *mx53_ldb_di0_sel[] = { "pll3_sw", "pll4_sw", }; +static const char *mx51_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "ipp_di1", }; +static const char *mx53_ipu_di1_sel[] = { "di_pred", "osc", "ckih1", "tve_di", "ipp_di1", "ldb_di1", }; +static const char *mx53_ldb_di1_sel[] = { "pll3_sw", "pll4_sw", }; +static const char *mx51_tve_ext_sel[] = { "osc", "ckih1", }; +static const char *mx53_tve_ext_sel[] = { "pll4_sw", "ckih1", }; +static const char *tve_sel[] = { "tve_pred", "tve_ext_sel", }; +static const char *ipu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", }; +static const char *vpu_sel[] = { "axi_a", "axi_b", "emi_slow_gate", "ahb", }; + +enum imx5_clks { + dummy, ckil, osc, ckih1, ckih2, ahb, ipg, axi_a, axi_b, uart_pred, + uart_root, esdhc_a_pred, esdhc_b_pred, esdhc_c_s, esdhc_d_s, + emi_sel, emi_slow_podf, nfc_podf, ecspi_pred, ecspi_podf, usboh3_pred, + usboh3_podf, usb_phy_pred, usb_phy_podf, cpu_podf, di_pred, tve_di, + tve_s, uart1_ipg_gate, uart1_per_gate, uart2_ipg_gate, + uart2_per_gate, uart3_ipg_gate, uart3_per_gate, i2c1_gate, i2c2_gate, + gpt_ipg_gate, pwm1_ipg_gate, pwm1_hf_gate, pwm2_ipg_gate, pwm2_hf_gate, + gpt_gate, fec_gate, usboh3_per_gate, esdhc1_ipg_gate, esdhc2_ipg_gate, + esdhc3_ipg_gate, esdhc4_ipg_gate, ssi1_ipg_gate, ssi2_ipg_gate, + ssi3_ipg_gate, ecspi1_ipg_gate, ecspi1_per_gate, ecspi2_ipg_gate, + ecspi2_per_gate, cspi_ipg_gate, sdma_gate, emi_slow_gate, ipu_s, + ipu_gate, nfc_gate, ipu_di1_gate, vpu_s, vpu_gate, + vpu_reference_gate, uart4_ipg_gate, uart4_per_gate, uart5_ipg_gate, + uart5_per_gate, tve_gate, tve_pred, esdhc1_per_gate, esdhc2_per_gate, + esdhc3_per_gate, esdhc4_per_gate, usb_phy_gate, hsi2c_gate, + mipi_hsc1_gate, mipi_hsc2_gate, mipi_esc_gate, mipi_hsp_gate, + ldb_di1_div_3_5, ldb_di1_div, ldb_di0_div_3_5, ldb_di0_div, + ldb_di1_gate, can2_serial_gate, can2_ipg_gate, i2c3_gate, lp_apm, + periph_apm, main_bus, ahb_max, aips_tz1, aips_tz2, tmax1, tmax2, + tmax3, spba, uart_sel, esdhc_a_sel, esdhc_b_sel, esdhc_a_podf, + esdhc_b_podf, ecspi_sel, usboh3_sel, usb_phy_sel, iim_gate, + usboh3_gate, emi_fast_gate, ipu_di0_gate,gpc_dvfs, pll1_sw, pll2_sw, + pll3_sw, ipu_di0_sel, ipu_di1_sel, tve_ext_sel, mx51_mipi, pll4_sw, + ldb_di1_sel, di_pll4_podf, ldb_di0_sel, ldb_di0_gate, usb_phy1_gate, + usb_phy2_gate, per_lp_apm, per_pred1, per_pred2, per_podf, per_root, + ssi_apm, ssi1_root_sel, ssi2_root_sel, ssi3_root_sel, ssi_ext1_sel, + ssi_ext2_sel, ssi_ext1_com_sel, ssi_ext2_com_sel, ssi1_root_pred, + ssi1_root_podf, ssi2_root_pred, ssi2_root_podf, ssi_ext1_pred, + ssi_ext1_podf, ssi_ext2_pred, ssi_ext2_podf, ssi1_root_gate, + ssi2_root_gate, ssi3_root_gate, ssi_ext1_gate, ssi_ext2_gate, + clk_max +}; + +static struct clk *clk[clk_max]; + +static void __init mx5_clocks_common_init(unsigned long rate_ckil, + unsigned long rate_osc, unsigned long rate_ckih1, + unsigned long rate_ckih2) +{ + int i; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[ckil] = imx_clk_fixed("ckil", rate_ckil); + clk[osc] = imx_clk_fixed("osc", rate_osc); + clk[ckih1] = imx_clk_fixed("ckih1", rate_ckih1); + clk[ckih2] = imx_clk_fixed("ckih2", rate_ckih2); + + clk[lp_apm] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1, + lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); + clk[periph_apm] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2, + periph_apm_sel, ARRAY_SIZE(periph_apm_sel)); + clk[main_bus] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1, + main_bus_sel, ARRAY_SIZE(main_bus_sel)); + clk[per_lp_apm] = imx_clk_mux("per_lp_apm", MXC_CCM_CBCDR, 1, 1, + per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel)); + clk[per_pred1] = imx_clk_divider("per_pred1", "per_lp_apm", MXC_CCM_CBCDR, 6, 2); + clk[per_pred2] = imx_clk_divider("per_pred2", "per_pred1", MXC_CCM_CBCDR, 3, 3); + clk[per_podf] = imx_clk_divider("per_podf", "per_pred2", MXC_CCM_CBCDR, 0, 3); + clk[per_root] = imx_clk_mux("per_root", MXC_CCM_CBCDR, 1, 0, + per_root_sel, ARRAY_SIZE(per_root_sel)); + clk[ahb] = imx_clk_divider("ahb", "main_bus", MXC_CCM_CBCDR, 10, 3); + clk[ahb_max] = imx_clk_gate2("ahb_max", "ahb", MXC_CCM_CCGR0, 28); + clk[aips_tz1] = imx_clk_gate2("aips_tz1", "ahb", MXC_CCM_CCGR0, 24); + clk[aips_tz2] = imx_clk_gate2("aips_tz2", "ahb", MXC_CCM_CCGR0, 26); + clk[tmax1] = imx_clk_gate2("tmax1", "ahb", MXC_CCM_CCGR1, 0); + clk[tmax2] = imx_clk_gate2("tmax2", "ahb", MXC_CCM_CCGR1, 2); + clk[tmax3] = imx_clk_gate2("tmax3", "ahb", MXC_CCM_CCGR1, 4); + clk[spba] = imx_clk_gate2("spba", "ipg", MXC_CCM_CCGR5, 0); + clk[ipg] = imx_clk_divider("ipg", "ahb", MXC_CCM_CBCDR, 8, 2); + clk[axi_a] = imx_clk_divider("axi_a", "main_bus", MXC_CCM_CBCDR, 16, 3); + clk[axi_b] = imx_clk_divider("axi_b", "main_bus", MXC_CCM_CBCDR, 19, 3); + clk[uart_sel] = imx_clk_mux("uart_sel", MXC_CCM_CSCMR1, 24, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[uart_pred] = imx_clk_divider("uart_pred", "uart_sel", MXC_CCM_CSCDR1, 3, 3); + clk[uart_root] = imx_clk_divider("uart_root", "uart_pred", MXC_CCM_CSCDR1, 0, 3); + + clk[esdhc_a_sel] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[esdhc_b_sel] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[esdhc_a_pred] = imx_clk_divider("esdhc_a_pred", "esdhc_a_sel", MXC_CCM_CSCDR1, 16, 3); + clk[esdhc_a_podf] = imx_clk_divider("esdhc_a_podf", "esdhc_a_pred", MXC_CCM_CSCDR1, 11, 3); + clk[esdhc_b_pred] = imx_clk_divider("esdhc_b_pred", "esdhc_b_sel", MXC_CCM_CSCDR1, 22, 3); + clk[esdhc_b_podf] = imx_clk_divider("esdhc_b_podf", "esdhc_b_pred", MXC_CCM_CSCDR1, 19, 3); + clk[esdhc_c_s] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel)); + clk[esdhc_d_s] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel)); + + clk[emi_sel] = imx_clk_mux("emi_sel", MXC_CCM_CBCDR, 26, 1, + emi_slow_sel, ARRAY_SIZE(emi_slow_sel)); + clk[emi_slow_podf] = imx_clk_divider("emi_slow_podf", "emi_sel", MXC_CCM_CBCDR, 22, 3); + clk[nfc_podf] = imx_clk_divider("nfc_podf", "emi_slow_podf", MXC_CCM_CBCDR, 13, 3); + clk[ecspi_sel] = imx_clk_mux("ecspi_sel", MXC_CCM_CSCMR1, 4, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[ecspi_pred] = imx_clk_divider("ecspi_pred", "ecspi_sel", MXC_CCM_CSCDR2, 25, 3); + clk[ecspi_podf] = imx_clk_divider("ecspi_podf", "ecspi_pred", MXC_CCM_CSCDR2, 19, 6); + clk[usboh3_sel] = imx_clk_mux("usboh3_sel", MXC_CCM_CSCMR1, 22, 2, + standard_pll_sel, ARRAY_SIZE(standard_pll_sel)); + clk[usboh3_pred] = imx_clk_divider("usboh3_pred", "usboh3_sel", MXC_CCM_CSCDR1, 8, 3); + clk[usboh3_podf] = imx_clk_divider("usboh3_podf", "usboh3_pred", MXC_CCM_CSCDR1, 6, 2); + clk[usb_phy_pred] = imx_clk_divider("usb_phy_pred", "pll3_sw", MXC_CCM_CDCDR, 3, 3); + clk[usb_phy_podf] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3); + clk[usb_phy_sel] = imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1, + usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str)); + clk[cpu_podf] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3); + clk[di_pred] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3); + clk[tve_di] = imx_clk_fixed("tve_di", 65000000); /* FIXME */ + clk[tve_s] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1, tve_sel, ARRAY_SIZE(tve_sel)); + clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30); + clk[uart1_ipg_gate] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6); + clk[uart1_per_gate] = imx_clk_gate2("uart1_per_gate", "uart_root", MXC_CCM_CCGR1, 8); + clk[uart2_ipg_gate] = imx_clk_gate2("uart2_ipg_gate", "ipg", MXC_CCM_CCGR1, 10); + clk[uart2_per_gate] = imx_clk_gate2("uart2_per_gate", "uart_root", MXC_CCM_CCGR1, 12); + clk[uart3_ipg_gate] = imx_clk_gate2("uart3_ipg_gate", "ipg", MXC_CCM_CCGR1, 14); + clk[uart3_per_gate] = imx_clk_gate2("uart3_per_gate", "uart_root", MXC_CCM_CCGR1, 16); + clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "per_root", MXC_CCM_CCGR1, 18); + clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "per_root", MXC_CCM_CCGR1, 20); + clk[gpt_ipg_gate] = imx_clk_gate2("gpt_ipg_gate", "ipg", MXC_CCM_CCGR2, 20); + clk[pwm1_ipg_gate] = imx_clk_gate2("pwm1_ipg_gate", "ipg", MXC_CCM_CCGR2, 10); + clk[pwm1_hf_gate] = imx_clk_gate2("pwm1_hf_gate", "ipg", MXC_CCM_CCGR2, 12); + clk[pwm2_ipg_gate] = imx_clk_gate2("pwm2_ipg_gate", "ipg", MXC_CCM_CCGR2, 14); + clk[pwm2_hf_gate] = imx_clk_gate2("pwm2_hf_gate", "ipg", MXC_CCM_CCGR2, 16); + clk[gpt_gate] = imx_clk_gate2("gpt_gate", "ipg", MXC_CCM_CCGR2, 18); + clk[fec_gate] = imx_clk_gate2("fec_gate", "ipg", MXC_CCM_CCGR2, 24); + clk[usboh3_gate] = imx_clk_gate2("usboh3_gate", "ipg", MXC_CCM_CCGR2, 26); + clk[usboh3_per_gate] = imx_clk_gate2("usboh3_per_gate", "usboh3_podf", MXC_CCM_CCGR2, 28); + clk[esdhc1_ipg_gate] = imx_clk_gate2("esdhc1_ipg_gate", "ipg", MXC_CCM_CCGR3, 0); + clk[esdhc2_ipg_gate] = imx_clk_gate2("esdhc2_ipg_gate", "ipg", MXC_CCM_CCGR3, 4); + clk[esdhc3_ipg_gate] = imx_clk_gate2("esdhc3_ipg_gate", "ipg", MXC_CCM_CCGR3, 8); + clk[esdhc4_ipg_gate] = imx_clk_gate2("esdhc4_ipg_gate", "ipg", MXC_CCM_CCGR3, 12); + clk[ssi1_ipg_gate] = imx_clk_gate2("ssi1_ipg_gate", "ipg", MXC_CCM_CCGR3, 16); + clk[ssi2_ipg_gate] = imx_clk_gate2("ssi2_ipg_gate", "ipg", MXC_CCM_CCGR3, 20); + clk[ssi3_ipg_gate] = imx_clk_gate2("ssi3_ipg_gate", "ipg", MXC_CCM_CCGR3, 24); + clk[ecspi1_ipg_gate] = imx_clk_gate2("ecspi1_ipg_gate", "ipg", MXC_CCM_CCGR4, 18); + clk[ecspi1_per_gate] = imx_clk_gate2("ecspi1_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 20); + clk[ecspi2_ipg_gate] = imx_clk_gate2("ecspi2_ipg_gate", "ipg", MXC_CCM_CCGR4, 22); + clk[ecspi2_per_gate] = imx_clk_gate2("ecspi2_per_gate", "ecspi_podf", MXC_CCM_CCGR4, 24); + clk[cspi_ipg_gate] = imx_clk_gate2("cspi_ipg_gate", "ipg", MXC_CCM_CCGR4, 26); + clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ipg", MXC_CCM_CCGR4, 30); + clk[emi_fast_gate] = imx_clk_gate2("emi_fast_gate", "dummy", MXC_CCM_CCGR5, 14); + clk[emi_slow_gate] = imx_clk_gate2("emi_slow_gate", "emi_slow_podf", MXC_CCM_CCGR5, 16); + clk[ipu_s] = imx_clk_mux("ipu_sel", MXC_CCM_CBCMR, 6, 2, ipu_sel, ARRAY_SIZE(ipu_sel)); + clk[ipu_gate] = imx_clk_gate2("ipu_gate", "ipu_sel", MXC_CCM_CCGR5, 10); + clk[nfc_gate] = imx_clk_gate2("nfc_gate", "nfc_podf", MXC_CCM_CCGR5, 20); + clk[ipu_di0_gate] = imx_clk_gate2("ipu_di0_gate", "ipu_di0_sel", MXC_CCM_CCGR6, 10); + clk[ipu_di1_gate] = imx_clk_gate2("ipu_di1_gate", "ipu_di1_sel", MXC_CCM_CCGR6, 12); + clk[vpu_s] = imx_clk_mux("vpu_sel", MXC_CCM_CBCMR, 14, 2, vpu_sel, ARRAY_SIZE(vpu_sel)); + clk[vpu_gate] = imx_clk_gate2("vpu_gate", "vpu_sel", MXC_CCM_CCGR5, 6); + clk[vpu_reference_gate] = imx_clk_gate2("vpu_reference_gate", "osc", MXC_CCM_CCGR5, 8); + clk[uart4_ipg_gate] = imx_clk_gate2("uart4_ipg_gate", "ipg", MXC_CCM_CCGR7, 8); + clk[uart4_per_gate] = imx_clk_gate2("uart4_per_gate", "uart_root", MXC_CCM_CCGR7, 10); + clk[uart5_ipg_gate] = imx_clk_gate2("uart5_ipg_gate", "ipg", MXC_CCM_CCGR7, 12); + clk[uart5_per_gate] = imx_clk_gate2("uart5_per_gate", "uart_root", MXC_CCM_CCGR7, 14); + clk[gpc_dvfs] = imx_clk_gate2("gpc_dvfs", "dummy", MXC_CCM_CCGR5, 24); + + clk[ssi_apm] = imx_clk_mux("ssi_apm", MXC_CCM_CSCMR1, 8, 2, ssi_apm_sels, ARRAY_SIZE(ssi_apm_sels)); + clk[ssi1_root_sel] = imx_clk_mux("ssi1_root_sel", MXC_CCM_CSCMR1, 14, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels)); + clk[ssi2_root_sel] = imx_clk_mux("ssi2_root_sel", MXC_CCM_CSCMR1, 12, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels)); + clk[ssi3_root_sel] = imx_clk_mux("ssi3_root_sel", MXC_CCM_CSCMR1, 11, 1, ssi3_clk_sels, ARRAY_SIZE(ssi3_clk_sels)); + clk[ssi_ext1_sel] = imx_clk_mux("ssi_ext1_sel", MXC_CCM_CSCMR1, 28, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels)); + clk[ssi_ext2_sel] = imx_clk_mux("ssi_ext2_sel", MXC_CCM_CSCMR1, 30, 2, ssi_clk_sels, ARRAY_SIZE(ssi_clk_sels)); + clk[ssi_ext1_com_sel] = imx_clk_mux("ssi_ext1_com_sel", MXC_CCM_CSCMR1, 0, 1, ssi_ext1_com_sels, ARRAY_SIZE(ssi_ext1_com_sels)); + clk[ssi_ext2_com_sel] = imx_clk_mux("ssi_ext2_com_sel", MXC_CCM_CSCMR1, 1, 1, ssi_ext2_com_sels, ARRAY_SIZE(ssi_ext2_com_sels)); + clk[ssi1_root_pred] = imx_clk_divider("ssi1_root_pred", "ssi1_root_sel", MXC_CCM_CS1CDR, 6, 3); + clk[ssi1_root_podf] = imx_clk_divider("ssi1_root_podf", "ssi1_root_pred", MXC_CCM_CS1CDR, 0, 6); + clk[ssi2_root_pred] = imx_clk_divider("ssi2_root_pred", "ssi2_root_sel", MXC_CCM_CS2CDR, 6, 3); + clk[ssi2_root_podf] = imx_clk_divider("ssi2_root_podf", "ssi2_root_pred", MXC_CCM_CS2CDR, 0, 6); + clk[ssi_ext1_pred] = imx_clk_divider("ssi_ext1_pred", "ssi_ext1_sel", MXC_CCM_CS1CDR, 22, 3); + clk[ssi_ext1_podf] = imx_clk_divider("ssi_ext1_podf", "ssi_ext1_pred", MXC_CCM_CS1CDR, 16, 6); + clk[ssi_ext2_pred] = imx_clk_divider("ssi_ext2_pred", "ssi_ext2_sel", MXC_CCM_CS2CDR, 22, 3); + clk[ssi_ext2_podf] = imx_clk_divider("ssi_ext2_podf", "ssi_ext2_pred", MXC_CCM_CS2CDR, 16, 6); + clk[ssi1_root_gate] = imx_clk_gate2("ssi1_root_gate", "ssi1_root_podf", MXC_CCM_CCGR3, 18); + clk[ssi2_root_gate] = imx_clk_gate2("ssi2_root_gate", "ssi2_root_podf", MXC_CCM_CCGR3, 22); + clk[ssi3_root_gate] = imx_clk_gate2("ssi3_root_gate", "ssi3_root_sel", MXC_CCM_CCGR3, 26); + clk[ssi_ext1_gate] = imx_clk_gate2("ssi_ext1_gate", "ssi_ext1_com_sel", MXC_CCM_CCGR3, 28); + clk[ssi_ext2_gate] = imx_clk_gate2("ssi_ext2_gate", "ssi_ext2_com_sel", MXC_CCM_CCGR3, 30); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX5 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); + clk_register_clkdev(clk[gpt_ipg_gate], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[uart1_per_gate], "per", "imx21-uart.0"); + clk_register_clkdev(clk[uart1_ipg_gate], "ipg", "imx21-uart.0"); + clk_register_clkdev(clk[uart2_per_gate], "per", "imx21-uart.1"); + clk_register_clkdev(clk[uart2_ipg_gate], "ipg", "imx21-uart.1"); + clk_register_clkdev(clk[uart3_per_gate], "per", "imx21-uart.2"); + clk_register_clkdev(clk[uart3_ipg_gate], "ipg", "imx21-uart.2"); + clk_register_clkdev(clk[uart4_per_gate], "per", "imx21-uart.3"); + clk_register_clkdev(clk[uart4_ipg_gate], "ipg", "imx21-uart.3"); + clk_register_clkdev(clk[uart5_per_gate], "per", "imx21-uart.4"); + clk_register_clkdev(clk[uart5_ipg_gate], "ipg", "imx21-uart.4"); + clk_register_clkdev(clk[ecspi1_per_gate], "per", "imx51-ecspi.0"); + clk_register_clkdev(clk[ecspi1_ipg_gate], "ipg", "imx51-ecspi.0"); + clk_register_clkdev(clk[ecspi2_per_gate], "per", "imx51-ecspi.1"); + clk_register_clkdev(clk[ecspi2_ipg_gate], "ipg", "imx51-ecspi.1"); + clk_register_clkdev(clk[cspi_ipg_gate], NULL, "imx51-cspi.0"); + clk_register_clkdev(clk[pwm1_ipg_gate], "pwm", "mxc_pwm.0"); + clk_register_clkdev(clk[pwm2_ipg_gate], "pwm", "mxc_pwm.1"); + clk_register_clkdev(clk[i2c1_gate], NULL, "imx-i2c.0"); + clk_register_clkdev(clk[i2c2_gate], NULL, "imx-i2c.1"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.0"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.0"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.0"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.1"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.1"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.1"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.2"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.2"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.2"); + clk_register_clkdev(clk[usboh3_per_gate], "per", "fsl-usb2-udc"); + clk_register_clkdev(clk[usboh3_gate], "ipg", "fsl-usb2-udc"); + clk_register_clkdev(clk[usboh3_gate], "ahb", "fsl-usb2-udc"); + clk_register_clkdev(clk[nfc_gate], NULL, "mxc_nand"); + clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1"); + clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "imx-ssi.2"); + clk_register_clkdev(clk[ssi_ext1_gate], "ssi_ext1", NULL); + clk_register_clkdev(clk[ssi_ext2_gate], "ssi_ext2", NULL); + clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma"); + clk_register_clkdev(clk[cpu_podf], "cpu", NULL); + clk_register_clkdev(clk[iim_gate], "iim", NULL); + clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.0"); + clk_register_clkdev(clk[dummy], NULL, "imx2-wdt.1"); + clk_register_clkdev(clk[dummy], NULL, "imx-keypad"); + clk_register_clkdev(clk[tve_gate], NULL, "imx-tve.0"); + clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx-tve.0"); + + /* Set SDHC parents to be PLL2 */ + clk_set_parent(clk[esdhc_a_sel], clk[pll2_sw]); + clk_set_parent(clk[esdhc_b_sel], clk[pll2_sw]); + + /* move usb phy clk to 24MHz */ + clk_set_parent(clk[usb_phy_sel], clk[osc]); + + clk_prepare_enable(clk[gpc_dvfs]); + clk_prepare_enable(clk[ahb_max]); /* esdhc3 */ + clk_prepare_enable(clk[aips_tz1]); + clk_prepare_enable(clk[aips_tz2]); /* fec */ + clk_prepare_enable(clk[spba]); + clk_prepare_enable(clk[emi_fast_gate]); /* fec */ + clk_prepare_enable(clk[tmax1]); + clk_prepare_enable(clk[tmax2]); /* esdhc2, fec */ + clk_prepare_enable(clk[tmax3]); /* esdhc1, esdhc4 */ +} + +int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, + unsigned long rate_ckih1, unsigned long rate_ckih2) +{ + int i; + + clk[pll1_sw] = imx_clk_pllv2("pll1_sw", "osc", MX51_DPLL1_BASE); + clk[pll2_sw] = imx_clk_pllv2("pll2_sw", "osc", MX51_DPLL2_BASE); + clk[pll3_sw] = imx_clk_pllv2("pll3_sw", "osc", MX51_DPLL3_BASE); + clk[ipu_di0_sel] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3, + mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel)); + clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3, + mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel)); + clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, + mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel)); + clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_sel", MXC_CCM_CCGR2, 30); + clk[tve_pred] = imx_clk_divider("tve_pred", "pll3_sw", MXC_CCM_CDCDR, 28, 3); + clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); + clk[esdhc2_per_gate] = imx_clk_gate2("esdhc2_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 6); + clk[esdhc3_per_gate] = imx_clk_gate2("esdhc3_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 10); + clk[esdhc4_per_gate] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14); + clk[usb_phy_gate] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0); + clk[hsi2c_gate] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22); + clk[mipi_hsc1_gate] = imx_clk_gate2("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6); + clk[mipi_hsc2_gate] = imx_clk_gate2("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8); + clk[mipi_esc_gate] = imx_clk_gate2("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10); + clk[mipi_hsp_gate] = imx_clk_gate2("mipi_hsp_gate", "ipg", MXC_CCM_CCGR4, 12); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX51 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + mx5_clocks_common_init(rate_ckil, rate_osc, rate_ckih1, rate_ckih2); + + clk_register_clkdev(clk[hsi2c_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[mx51_mipi], "mipi_hsp", NULL); + clk_register_clkdev(clk[vpu_gate], NULL, "imx51-vpu.0"); + clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0"); + clk_register_clkdev(clk[gpc_dvfs], "gpc_dvfs", NULL); + clk_register_clkdev(clk[ipu_gate], "bus", "imx51-ipu"); + clk_register_clkdev(clk[ipu_di0_gate], "di0", "imx51-ipu"); + clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx51-ipu"); + clk_register_clkdev(clk[ipu_gate], "hsp", "imx51-ipu"); + clk_register_clkdev(clk[usb_phy_gate], "phy", "mxc-ehci.0"); + clk_register_clkdev(clk[esdhc1_ipg_gate], "ipg", "sdhci-esdhc-imx51.0"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.0"); + clk_register_clkdev(clk[esdhc1_per_gate], "per", "sdhci-esdhc-imx51.0"); + clk_register_clkdev(clk[esdhc2_ipg_gate], "ipg", "sdhci-esdhc-imx51.1"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.1"); + clk_register_clkdev(clk[esdhc2_per_gate], "per", "sdhci-esdhc-imx51.1"); + clk_register_clkdev(clk[esdhc3_ipg_gate], "ipg", "sdhci-esdhc-imx51.2"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.2"); + clk_register_clkdev(clk[esdhc3_per_gate], "per", "sdhci-esdhc-imx51.2"); + clk_register_clkdev(clk[esdhc4_ipg_gate], "ipg", "sdhci-esdhc-imx51.3"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx51.3"); + clk_register_clkdev(clk[esdhc4_per_gate], "per", "sdhci-esdhc-imx51.3"); + clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "83fcc000.ssi"); + clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "70014000.ssi"); + clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "83fe8000.ssi"); + + /* set the usboh3 parent to pll2_sw */ + clk_set_parent(clk[usboh3_sel], clk[pll2_sw]); + + /* set SDHC root clock to 166.25MHZ*/ + clk_set_rate(clk[esdhc_a_podf], 166250000); + clk_set_rate(clk[esdhc_b_podf], 166250000); + + /* System timer */ + mxc_timer_init(NULL, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), + MX51_INT_GPT); + + clk_prepare_enable(clk[iim_gate]); + imx_print_silicon_rev("i.MX51", mx51_revision()); + clk_disable_unprepare(clk[iim_gate]); + + return 0; +} + +int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc, + unsigned long rate_ckih1, unsigned long rate_ckih2) +{ + int i; + unsigned long r; + + clk[pll1_sw] = imx_clk_pllv2("pll1_sw", "osc", MX53_DPLL1_BASE); + clk[pll2_sw] = imx_clk_pllv2("pll2_sw", "osc", MX53_DPLL2_BASE); + clk[pll3_sw] = imx_clk_pllv2("pll3_sw", "osc", MX53_DPLL3_BASE); + clk[pll4_sw] = imx_clk_pllv2("pll4_sw", "osc", MX53_DPLL4_BASE); + + clk[ldb_di1_sel] = imx_clk_mux("ldb_di1_sel", MXC_CCM_CSCMR2, 9, 1, + mx53_ldb_di1_sel, ARRAY_SIZE(mx53_ldb_di1_sel)); + clk[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clk[ldb_di1_div] = imx_clk_divider("ldb_di1_div", "ldb_di1_div_3_5", MXC_CCM_CSCMR2, 11, 1); + clk[di_pll4_podf] = imx_clk_divider("di_pll4_podf", "pll4_sw", MXC_CCM_CDCDR, 16, 3); + clk[ldb_di0_sel] = imx_clk_mux("ldb_di0_sel", MXC_CCM_CSCMR2, 8, 1, + mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel)); + clk[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clk[ldb_di0_div] = imx_clk_divider("ldb_di0_div", "ldb_di0_div_3_5", MXC_CCM_CSCMR2, 10, 1); + clk[ldb_di0_gate] = imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28); + clk[ldb_di1_gate] = imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30); + clk[ipu_di0_sel] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3, + mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel)); + clk[ipu_di1_sel] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3, + mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel)); + clk[tve_ext_sel] = imx_clk_mux("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1, + mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel)); + clk[tve_gate] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30); + clk[tve_pred] = imx_clk_divider("tve_pred", "tve_ext_sel", MXC_CCM_CDCDR, 28, 3); + clk[esdhc1_per_gate] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2); + clk[esdhc2_per_gate] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6); + clk[esdhc3_per_gate] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10); + clk[esdhc4_per_gate] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14); + clk[usb_phy1_gate] = imx_clk_gate2("usb_phy1_gate", "usb_phy_sel", MXC_CCM_CCGR4, 10); + clk[usb_phy2_gate] = imx_clk_gate2("usb_phy2_gate", "usb_phy_sel", MXC_CCM_CCGR4, 12); + clk[can2_serial_gate] = imx_clk_gate2("can2_serial_gate", "ipg", MXC_CCM_CCGR4, 6); + clk[can2_ipg_gate] = imx_clk_gate2("can2_ipg_gate", "ipg", MXC_CCM_CCGR4, 8); + clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per_root", MXC_CCM_CCGR1, 22); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX53 clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + mx5_clocks_common_init(rate_ckil, rate_osc, rate_ckih1, rate_ckih2); + + clk_register_clkdev(clk[vpu_gate], NULL, "imx53-vpu.0"); + clk_register_clkdev(clk[i2c3_gate], NULL, "imx-i2c.2"); + clk_register_clkdev(clk[fec_gate], NULL, "imx25-fec.0"); + clk_register_clkdev(clk[ipu_gate], "bus", "imx53-ipu"); + clk_register_clkdev(clk[ipu_di0_gate], "di0", "imx53-ipu"); + clk_register_clkdev(clk[ipu_di1_gate], "di1", "imx53-ipu"); + clk_register_clkdev(clk[ipu_gate], "hsp", "imx53-ipu"); + clk_register_clkdev(clk[usb_phy1_gate], "usb_phy1", "mxc-ehci.0"); + clk_register_clkdev(clk[esdhc1_ipg_gate], "ipg", "sdhci-esdhc-imx53.0"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.0"); + clk_register_clkdev(clk[esdhc1_per_gate], "per", "sdhci-esdhc-imx53.0"); + clk_register_clkdev(clk[esdhc2_ipg_gate], "ipg", "sdhci-esdhc-imx53.1"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.1"); + clk_register_clkdev(clk[esdhc2_per_gate], "per", "sdhci-esdhc-imx53.1"); + clk_register_clkdev(clk[esdhc3_ipg_gate], "ipg", "sdhci-esdhc-imx53.2"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.2"); + clk_register_clkdev(clk[esdhc3_per_gate], "per", "sdhci-esdhc-imx53.2"); + clk_register_clkdev(clk[esdhc4_ipg_gate], "ipg", "sdhci-esdhc-imx53.3"); + clk_register_clkdev(clk[dummy], "ahb", "sdhci-esdhc-imx53.3"); + clk_register_clkdev(clk[esdhc4_per_gate], "per", "sdhci-esdhc-imx53.3"); + clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi"); + clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi"); + clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi"); + + /* set SDHC root clock to 200MHZ*/ + clk_set_rate(clk[esdhc_a_podf], 200000000); + clk_set_rate(clk[esdhc_b_podf], 200000000); + + /* System timer */ + mxc_timer_init(NULL, MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), + MX53_INT_GPT); + + clk_prepare_enable(clk[iim_gate]); + imx_print_silicon_rev("i.MX53", mx53_revision()); + clk_disable_unprepare(clk[iim_gate]); + + r = clk_round_rate(clk[usboh3_per_gate], 54000000); + clk_set_rate(clk[usboh3_per_gate], r); + + return 0; +} + +#ifdef CONFIG_OF +static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc, + unsigned long *ckih1, unsigned long *ckih2) +{ + struct device_node *np; + + /* retrieve the freqency of fixed clocks from device tree */ + for_each_compatible_node(np, NULL, "fixed-clock") { + u32 rate; + if (of_property_read_u32(np, "clock-frequency", &rate)) + continue; + + if (of_device_is_compatible(np, "fsl,imx-ckil")) + *ckil = rate; + else if (of_device_is_compatible(np, "fsl,imx-osc")) + *osc = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih1")) + *ckih1 = rate; + else if (of_device_is_compatible(np, "fsl,imx-ckih2")) + *ckih2 = rate; + } +} + +int __init mx51_clocks_init_dt(void) +{ + unsigned long ckil, osc, ckih1, ckih2; + + clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); + return mx51_clocks_init(ckil, osc, ckih1, ckih2); +} + +int __init mx53_clocks_init_dt(void) +{ + unsigned long ckil, osc, ckih1, ckih2; + + clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); + return mx53_clocks_init(ckil, osc, ckih1, ckih2); +} +#endif diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c new file mode 100644 index 000000000000..cab02d0a15d6 --- /dev/null +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -0,0 +1,444 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <mach/common.h> +#include "clk.h" + +#define CCGR0 0x68 +#define CCGR1 0x6c +#define CCGR2 0x70 +#define CCGR3 0x74 +#define CCGR4 0x78 +#define CCGR5 0x7c +#define CCGR6 0x80 +#define CCGR7 0x84 + +#define CLPCR 0x54 +#define BP_CLPCR_LPM 0 +#define BM_CLPCR_LPM (0x3 << 0) +#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) +#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) +#define BM_CLPCR_SBYOS (0x1 << 6) +#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) +#define BM_CLPCR_VSTBY (0x1 << 8) +#define BP_CLPCR_STBY_COUNT 9 +#define BM_CLPCR_STBY_COUNT (0x3 << 9) +#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) +#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) +#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) +#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) +#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) +#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) +#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) +#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) +#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) +#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) +#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) + +static void __iomem *ccm_base; + +void __init imx6q_clock_map_io(void) { } + +int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +{ + u32 val = readl_relaxed(ccm_base + CLPCR); + + val &= ~BM_CLPCR_LPM; + switch (mode) { + case WAIT_CLOCKED: + break; + case WAIT_UNCLOCKED: + val |= 0x1 << BP_CLPCR_LPM; + break; + case STOP_POWER_ON: + val |= 0x2 << BP_CLPCR_LPM; + break; + case WAIT_UNCLOCKED_POWER_OFF: + val |= 0x1 << BP_CLPCR_LPM; + val &= ~BM_CLPCR_VSTBY; + val &= ~BM_CLPCR_SBYOS; + break; + case STOP_POWER_OFF: + val |= 0x2 << BP_CLPCR_LPM; + val |= 0x3 << BP_CLPCR_STBY_COUNT; + val |= BM_CLPCR_VSTBY; + val |= BM_CLPCR_SBYOS; + break; + default: + return -EINVAL; + } + + writel_relaxed(val, ccm_base + CLPCR); + + return 0; +} + +static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; +static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; +static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; +static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", }; +static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; +static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; +static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *audio_sels[] = { "pll4_audio", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; +static const char *gpu_axi_sels[] = { "axi", "ahb", }; +static const char *gpu2d_core_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", }; +static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd2_396m", }; +static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd9_720m", }; +static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; +static const char *ldb_di_sels[] = { "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", }; +static const char *pcie_axi_sels[] = { "axi", "ahb", }; +static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio", }; +static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", }; +static const char *emi_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *vdo_axi_sels[] = { "axi", "ahb", }; +static const char *vpu_axi_sels[] = { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video", + "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", + "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio", }; + +static const char * const clks_init_on[] __initconst = { + "mmdc_ch0_axi", "mmdc_ch1_axi", "usboh3", +}; + +enum mx6q_clks { + dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, + pll3_pfd0_720m, pll3_pfd1_540m, pll3_pfd2_508m, pll3_pfd3_454m, + pll2_198m, pll3_120m, pll3_80m, pll3_60m, twd, step, pll1_sw, + periph_pre, periph2_pre, periph_clk2_sel, periph2_clk2_sel, axi_sel, + esai_sel, asrc_sel, spdif_sel, gpu2d_axi, gpu3d_axi, gpu2d_core_sel, + gpu3d_core_sel, gpu3d_shader_sel, ipu1_sel, ipu2_sel, ldb_di0_sel, + ldb_di1_sel, ipu1_di0_pre_sel, ipu1_di1_pre_sel, ipu2_di0_pre_sel, + ipu2_di1_pre_sel, ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, + ipu2_di1_sel, hsi_tx_sel, pcie_axi_sel, ssi1_sel, ssi2_sel, ssi3_sel, + usdhc1_sel, usdhc2_sel, usdhc3_sel, usdhc4_sel, enfc_sel, emi_sel, + emi_slow_sel, vdo_axi_sel, vpu_axi_sel, cko1_sel, periph, periph2, + periph_clk2, periph2_clk2, ipg, ipg_per, esai_pred, esai_podf, + asrc_pred, asrc_podf, spdif_pred, spdif_podf, can_root, ecspi_root, + gpu2d_core_podf, gpu3d_core_podf, gpu3d_shader, ipu1_podf, ipu2_podf, + ldb_di0_podf, ldb_di1_podf, ipu1_di0_pre, ipu1_di1_pre, ipu2_di0_pre, + ipu2_di1_pre, hsi_tx_podf, ssi1_pred, ssi1_podf, ssi2_pred, ssi2_podf, + ssi3_pred, ssi3_podf, uart_serial_podf, usdhc1_podf, usdhc2_podf, + usdhc3_podf, usdhc4_podf, enfc_pred, enfc_podf, emi_podf, + emi_slow_podf, vpu_axi_podf, cko1_podf, axi, mmdc_ch0_axi_podf, + mmdc_ch1_axi_podf, arm, ahb, apbh_dma, asrc, can1_ipg, can1_serial, + can2_ipg, can2_serial, ecspi1, ecspi2, ecspi3, ecspi4, ecspi5, enet, + esai, gpt_ipg, gpt_ipg_per, gpu2d_core, gpu3d_core, hdmi_iahb, + hdmi_isfr, i2c1, i2c2, i2c3, iim, enfc, ipu1, ipu1_di0, ipu1_di1, ipu2, + ipu2_di0, ldb_di0, ldb_di1, ipu2_di1, hsi_tx, mlb, mmdc_ch0_axi, + mmdc_ch1_axi, ocram, openvg_axi, pcie_axi, pwm1, pwm2, pwm3, pwm4, + gpmi_bch_apb, gpmi_bch, gpmi_io, gpmi_apb, sata, sdma, spba, ssi1, + ssi2, ssi3, uart_ipg, uart_serial, usboh3, usdhc1, usdhc2, usdhc3, + usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg, + pll4_audio, pll5_video, pll6_mlb, pll7_usb_host, pll8_enet, ssi1_ipg, + ssi2_ipg, ssi3_ipg, clk_max +}; + +static struct clk *clk[clk_max]; + +int __init mx6q_clocks_init(void) +{ + struct device_node *np; + void __iomem *base; + struct clk *c; + int i, irq; + + clk[dummy] = imx_clk_fixed("dummy", 0); + + /* retrieve the freqency of fixed clocks from device tree */ + for_each_compatible_node(np, NULL, "fixed-clock") { + u32 rate; + if (of_property_read_u32(np, "clock-frequency", &rate)) + continue; + + if (of_device_is_compatible(np, "fsl,imx-ckil")) + clk[ckil] = imx_clk_fixed("ckil", rate); + else if (of_device_is_compatible(np, "fsl,imx-ckih1")) + clk[ckih] = imx_clk_fixed("ckih", rate); + else if (of_device_is_compatible(np, "fsl,imx-osc")) + clk[osc] = imx_clk_fixed("osc", rate); + } + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); + base = of_iomap(np, 0); + WARN_ON(!base); + + /* type name parent_name base gate_mask div_mask */ + clk[pll1_sys] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x2000, 0x7f); + clk[pll2_bus] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x2000, 0x1); + clk[pll3_usb_otg] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x2000, 0x3); + clk[pll4_audio] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x2000, 0x7f); + clk[pll5_video] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x2000, 0x7f); + clk[pll6_mlb] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll6_mlb", "osc", base + 0xd0, 0x2000, 0x0); + clk[pll7_usb_host] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x2000, 0x3); + clk[pll8_enet] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll8_enet", "osc", base + 0xe0, 0x182000, 0x3); + + /* name parent_name reg idx */ + clk[pll2_pfd0_352m] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clk[pll2_pfd1_594m] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); + clk[pll2_pfd2_396m] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); + clk[pll3_pfd0_720m] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); + clk[pll3_pfd1_540m] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); + clk[pll3_pfd2_508m] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); + clk[pll3_pfd3_454m] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); + + /* name parent_name mult div */ + clk[pll2_198m] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); + clk[pll3_120m] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); + clk[pll3_80m] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clk[pll3_60m] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + clk[twd] = imx_clk_fixed_factor("twd", "arm", 1, 2); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm"); + base = of_iomap(np, 0); + WARN_ON(!base); + ccm_base = base; + + /* name reg shift width parent_names num_parents */ + clk[step] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); + clk[pll1_sw] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); + clk[periph_pre] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clk[periph2_pre] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clk[periph_clk2_sel] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clk[periph2_clk2_sel] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clk[axi_sel] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels)); + clk[esai_sel] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clk[asrc_sel] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clk[spdif_sel] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); + clk[gpu2d_axi] = imx_clk_mux("gpu2d_axi", base + 0x18, 0, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + clk[gpu3d_axi] = imx_clk_mux("gpu3d_axi", base + 0x18, 1, 1, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels)); + clk[gpu2d_core_sel] = imx_clk_mux("gpu2d_core_sel", base + 0x18, 16, 2, gpu2d_core_sels, ARRAY_SIZE(gpu2d_core_sels)); + clk[gpu3d_core_sel] = imx_clk_mux("gpu3d_core_sel", base + 0x18, 4, 2, gpu3d_core_sels, ARRAY_SIZE(gpu3d_core_sels)); + clk[gpu3d_shader_sel] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels)); + clk[ipu1_sel] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clk[ipu2_sel] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clk[ldb_di0_sel] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clk[ldb_di1_sel] = imx_clk_mux("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels)); + clk[ipu1_di0_pre_sel] = imx_clk_mux("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu1_di1_pre_sel] = imx_clk_mux("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu2_di0_pre_sel] = imx_clk_mux("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu2_di1_pre_sel] = imx_clk_mux("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); + clk[ipu1_di0_sel] = imx_clk_mux("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels)); + clk[ipu1_di1_sel] = imx_clk_mux("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels)); + clk[ipu2_di0_sel] = imx_clk_mux("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels)); + clk[ipu2_di1_sel] = imx_clk_mux("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels)); + clk[hsi_tx_sel] = imx_clk_mux("hsi_tx_sel", base + 0x30, 28, 1, hsi_tx_sels, ARRAY_SIZE(hsi_tx_sels)); + clk[pcie_axi_sel] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); + clk[ssi1_sel] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clk[ssi2_sel] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clk[ssi3_sel] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); + clk[usdhc1_sel] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[usdhc2_sel] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[usdhc3_sel] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[usdhc4_sel] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clk[enfc_sel] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels)); + clk[emi_sel] = imx_clk_mux("emi_sel", base + 0x1c, 27, 2, emi_sels, ARRAY_SIZE(emi_sels)); + clk[emi_slow_sel] = imx_clk_mux("emi_slow_sel", base + 0x1c, 29, 2, emi_sels, ARRAY_SIZE(emi_sels)); + clk[vdo_axi_sel] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels)); + clk[vpu_axi_sel] = imx_clk_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels)); + clk[cko1_sel] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); + + /* name reg shift width busy: reg, shift parent_names num_parents */ + clk[periph] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); + clk[periph2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); + + /* name parent_name reg shift width */ + clk[periph_clk2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clk[periph2_clk2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clk[ipg] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); + clk[ipg_per] = imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6); + clk[esai_pred] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3); + clk[esai_podf] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3); + clk[asrc_pred] = imx_clk_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3); + clk[asrc_podf] = imx_clk_divider("asrc_podf", "asrc_pred", base + 0x30, 9, 3); + clk[spdif_pred] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); + clk[spdif_podf] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); + clk[can_root] = imx_clk_divider("can_root", "pll3_usb_otg", base + 0x20, 2, 6); + clk[ecspi_root] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6); + clk[gpu2d_core_podf] = imx_clk_divider("gpu2d_core_podf", "gpu2d_core_sel", base + 0x18, 23, 3); + clk[gpu3d_core_podf] = imx_clk_divider("gpu3d_core_podf", "gpu3d_core_sel", base + 0x18, 26, 3); + clk[gpu3d_shader] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); + clk[ipu1_podf] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3); + clk[ipu2_podf] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3); + clk[ldb_di0_podf] = imx_clk_divider("ldb_di0_podf", "ldb_di0_sel", base + 0x20, 10, 1); + clk[ldb_di1_podf] = imx_clk_divider("ldb_di1_podf", "ldb_di1_sel", base + 0x20, 11, 1); + clk[ipu1_di0_pre] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3); + clk[ipu1_di1_pre] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3); + clk[ipu2_di0_pre] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3); + clk[ipu2_di1_pre] = imx_clk_divider("ipu2_di1_pre", "ipu2_di1_pre_sel", base + 0x38, 12, 3); + clk[hsi_tx_podf] = imx_clk_divider("hsi_tx_podf", "hsi_tx_sel", base + 0x30, 29, 3); + clk[ssi1_pred] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3); + clk[ssi1_podf] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6); + clk[ssi2_pred] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3); + clk[ssi2_podf] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6); + clk[ssi3_pred] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3); + clk[ssi3_podf] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6); + clk[uart_serial_podf] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6); + clk[usdhc1_podf] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); + clk[usdhc2_podf] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); + clk[usdhc3_podf] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); + clk[usdhc4_podf] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); + clk[enfc_pred] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); + clk[enfc_podf] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); + clk[emi_podf] = imx_clk_divider("emi_podf", "emi_sel", base + 0x1c, 20, 3); + clk[emi_slow_podf] = imx_clk_divider("emi_slow_podf", "emi_slow_sel", base + 0x1c, 23, 3); + clk[vpu_axi_podf] = imx_clk_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3); + clk[cko1_podf] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); + + /* name parent_name reg shift width busy: reg, shift */ + clk[axi] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); + clk[mmdc_ch0_axi_podf] = imx_clk_busy_divider("mmdc_ch0_axi_podf", "periph", base + 0x14, 19, 3, base + 0x48, 4); + clk[mmdc_ch1_axi_podf] = imx_clk_busy_divider("mmdc_ch1_axi_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); + clk[arm] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); + clk[ahb] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); + + /* name parent_name reg shift */ + clk[apbh_dma] = imx_clk_gate2("apbh_dma", "ahb", base + 0x68, 4); + clk[asrc] = imx_clk_gate2("asrc", "asrc_podf", base + 0x68, 6); + clk[can1_ipg] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); + clk[can1_serial] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16); + clk[can2_ipg] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); + clk[can2_serial] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20); + clk[ecspi1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0); + clk[ecspi2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); + clk[ecspi3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); + clk[ecspi4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); + clk[ecspi5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); + clk[enet] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); + clk[esai] = imx_clk_gate2("esai", "esai_podf", base + 0x6c, 16); + clk[gpt_ipg] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); + clk[gpt_ipg_per] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); + clk[gpu2d_core] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); + clk[gpu3d_core] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); + clk[hdmi_iahb] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); + clk[hdmi_isfr] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4); + clk[i2c1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); + clk[i2c2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); + clk[i2c3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); + clk[iim] = imx_clk_gate2("iim", "ipg", base + 0x70, 12); + clk[enfc] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14); + clk[ipu1] = imx_clk_gate2("ipu1", "ipu1_podf", base + 0x74, 0); + clk[ipu1_di0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", base + 0x74, 2); + clk[ipu1_di1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", base + 0x74, 4); + clk[ipu2] = imx_clk_gate2("ipu2", "ipu2_podf", base + 0x74, 6); + clk[ipu2_di0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", base + 0x74, 8); + clk[ldb_di0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12); + clk[ldb_di1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14); + clk[ipu2_di1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10); + clk[hsi_tx] = imx_clk_gate2("hsi_tx", "hsi_tx_podf", base + 0x74, 16); + clk[mlb] = imx_clk_gate2("mlb", "pll6_mlb", base + 0x74, 18); + clk[mmdc_ch0_axi] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20); + clk[mmdc_ch1_axi] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22); + clk[ocram] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28); + clk[openvg_axi] = imx_clk_gate2("openvg_axi", "axi", base + 0x74, 30); + clk[pcie_axi] = imx_clk_gate2("pcie_axi", "pcie_axi_sel", base + 0x78, 0); + clk[pwm1] = imx_clk_gate2("pwm1", "ipg_per", base + 0x78, 16); + clk[pwm2] = imx_clk_gate2("pwm2", "ipg_per", base + 0x78, 18); + clk[pwm3] = imx_clk_gate2("pwm3", "ipg_per", base + 0x78, 20); + clk[pwm4] = imx_clk_gate2("pwm4", "ipg_per", base + 0x78, 22); + clk[gpmi_bch_apb] = imx_clk_gate2("gpmi_bch_apb", "usdhc3", base + 0x78, 24); + clk[gpmi_bch] = imx_clk_gate2("gpmi_bch", "usdhc4", base + 0x78, 26); + clk[gpmi_io] = imx_clk_gate2("gpmi_io", "enfc", base + 0x78, 28); + clk[gpmi_apb] = imx_clk_gate2("gpmi_apb", "usdhc3", base + 0x78, 30); + clk[sata] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4); + clk[sdma] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); + clk[spba] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); + clk[ssi1_ipg] = imx_clk_gate2("ssi1_ipg", "ipg", base + 0x7c, 18); + clk[ssi2_ipg] = imx_clk_gate2("ssi2_ipg", "ipg", base + 0x7c, 20); + clk[ssi3_ipg] = imx_clk_gate2("ssi3_ipg", "ipg", base + 0x7c, 22); + clk[uart_ipg] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); + clk[uart_serial] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26); + clk[usboh3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); + clk[usdhc1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); + clk[usdhc2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clk[usdhc3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); + clk[usdhc4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); + clk[vdo_axi] = imx_clk_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12); + clk[vpu_axi] = imx_clk_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14); + clk[cko1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX6q clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + + clk_register_clkdev(clk[mmdc_ch0_axi], NULL, "mmdc_ch0_axi"); + clk_register_clkdev(clk[mmdc_ch1_axi], NULL, "mmdc_ch1_axi"); + clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); + clk_register_clkdev(clk[twd], NULL, "smp_twd"); + clk_register_clkdev(clk[usboh3], NULL, "usboh3"); + clk_register_clkdev(clk[uart_serial], "per", "2020000.serial"); + clk_register_clkdev(clk[uart_ipg], "ipg", "2020000.serial"); + clk_register_clkdev(clk[uart_serial], "per", "21e8000.serial"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21e8000.serial"); + clk_register_clkdev(clk[uart_serial], "per", "21ec000.serial"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21ec000.serial"); + clk_register_clkdev(clk[uart_serial], "per", "21f0000.serial"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21f0000.serial"); + clk_register_clkdev(clk[uart_serial], "per", "21f4000.serial"); + clk_register_clkdev(clk[uart_ipg], "ipg", "21f4000.serial"); + clk_register_clkdev(clk[enet], NULL, "2188000.ethernet"); + clk_register_clkdev(clk[usdhc1], NULL, "2190000.usdhc"); + clk_register_clkdev(clk[usdhc2], NULL, "2194000.usdhc"); + clk_register_clkdev(clk[usdhc3], NULL, "2198000.usdhc"); + clk_register_clkdev(clk[usdhc4], NULL, "219c000.usdhc"); + clk_register_clkdev(clk[i2c1], NULL, "21a0000.i2c"); + clk_register_clkdev(clk[i2c2], NULL, "21a4000.i2c"); + clk_register_clkdev(clk[i2c3], NULL, "21a8000.i2c"); + clk_register_clkdev(clk[ecspi1], NULL, "2008000.ecspi"); + clk_register_clkdev(clk[ecspi2], NULL, "200c000.ecspi"); + clk_register_clkdev(clk[ecspi3], NULL, "2010000.ecspi"); + clk_register_clkdev(clk[ecspi4], NULL, "2014000.ecspi"); + clk_register_clkdev(clk[ecspi5], NULL, "2018000.ecspi"); + clk_register_clkdev(clk[sdma], NULL, "20ec000.sdma"); + clk_register_clkdev(clk[dummy], NULL, "20bc000.wdog"); + clk_register_clkdev(clk[dummy], NULL, "20c0000.wdog"); + clk_register_clkdev(clk[ssi1_ipg], NULL, "2028000.ssi"); + clk_register_clkdev(clk[cko1_sel], "cko1_sel", NULL); + clk_register_clkdev(clk[ahb], "ahb", NULL); + clk_register_clkdev(clk[cko1], "cko1", NULL); + + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) { + c = clk_get_sys(clks_init_on[i], NULL); + if (IS_ERR(c)) { + pr_err("%s: failed to get clk %s", __func__, + clks_init_on[i]); + return PTR_ERR(c); + } + clk_prepare_enable(c); + } + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); + base = of_iomap(np, 0); + WARN_ON(!base); + irq = irq_of_parse_and_map(np, 0); + mxc_timer_init(NULL, base, irq); + + return 0; +} diff --git a/arch/arm/mach-imx/clk-pfd.c b/arch/arm/mach-imx/clk-pfd.c new file mode 100644 index 000000000000..e2ed4160f329 --- /dev/null +++ b/arch/arm/mach-imx/clk-pfd.c @@ -0,0 +1,147 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/err.h> +#include "clk.h" + +/** + * struct clk_pfd - IMX PFD clock + * @clk_hw: clock source + * @reg: PFD register address + * @idx: the index of PFD encoded in the register + * + * PFD clock found on i.MX6 series. Each register for PFD has 4 clk_pfd + * data encoded, and member idx is used to specify the one. And each + * register has SET, CLR and TOG registers at offset 0x4 0x8 and 0xc. + */ +struct clk_pfd { + struct clk_hw hw; + void __iomem *reg; + u8 idx; +}; + +#define to_clk_pfd(_hw) container_of(_hw, struct clk_pfd, hw) + +#define SET 0x4 +#define CLR 0x8 +#define OTG 0xc + +static int clk_pfd_enable(struct clk_hw *hw) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + + writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR); + + return 0; +} + +static void clk_pfd_disable(struct clk_hw *hw) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + + writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET); +} + +static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + u64 tmp = parent_rate; + u8 frac = (readl_relaxed(pfd->reg) >> (pfd->idx * 8)) & 0x3f; + + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static long clk_pfd_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u64 tmp = *prate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + tmp = *prate; + tmp *= 18; + do_div(tmp, frac); + + return tmp; +} + +static int clk_pfd_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pfd *pfd = to_clk_pfd(hw); + u64 tmp = parent_rate; + u8 frac; + + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; + if (frac < 12) + frac = 12; + else if (frac > 35) + frac = 35; + + writel_relaxed(0x3f << (pfd->idx * 8), pfd->reg + CLR); + writel_relaxed(frac << (pfd->idx * 8), pfd->reg + SET); + + return 0; +} + +static const struct clk_ops clk_pfd_ops = { + .enable = clk_pfd_enable, + .disable = clk_pfd_disable, + .recalc_rate = clk_pfd_recalc_rate, + .round_rate = clk_pfd_round_rate, + .set_rate = clk_pfd_set_rate, +}; + +struct clk *imx_clk_pfd(const char *name, const char *parent_name, + void __iomem *reg, u8 idx) +{ + struct clk_pfd *pfd; + struct clk *clk; + struct clk_init_data init; + + pfd = kzalloc(sizeof(*pfd), GFP_KERNEL); + if (!pfd) + return ERR_PTR(-ENOMEM); + + pfd->reg = reg; + pfd->idx = idx; + + init.name = name; + init.ops = &clk_pfd_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + pfd->hw.init = &init; + + clk = clk_register(NULL, &pfd->hw); + if (IS_ERR(clk)) + kfree(pfd); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-pllv1.c b/arch/arm/mach-imx/clk-pllv1.c new file mode 100644 index 000000000000..2d856f9ccf59 --- /dev/null +++ b/arch/arm/mach-imx/clk-pllv1.c @@ -0,0 +1,66 @@ +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include "clk.h" + +/** + * pll v1 + * + * @clk_hw clock source + * @parent the parent clock name + * @base base address of pll registers + * + * PLL clock version 1, found on i.MX1/21/25/27/31/35 + */ +struct clk_pllv1 { + struct clk_hw hw; + void __iomem *base; +}; + +#define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk)) + +static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv1 *pll = to_clk_pllv1(hw); + + return mxc_decode_pll(readl(pll->base), parent_rate); +} + +struct clk_ops clk_pllv1_ops = { + .recalc_rate = clk_pllv1_recalc_rate, +}; + +struct clk *imx_clk_pllv1(const char *name, const char *parent, + void __iomem *base) +{ + struct clk_pllv1 *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kmalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->base = base; + + init.name = name; + init.ops = &clk_pllv1_ops; + init.flags = 0; + init.parent_names = &parent; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-pllv2.c b/arch/arm/mach-imx/clk-pllv2.c new file mode 100644 index 000000000000..4685919deb63 --- /dev/null +++ b/arch/arm/mach-imx/clk-pllv2.c @@ -0,0 +1,249 @@ +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/err.h> + +#include <asm/div64.h> + +#include "clk.h" + +#define to_clk_pllv2(clk) (container_of(clk, struct clk_pllv2, clk)) + +/* PLL Register Offsets */ +#define MXC_PLL_DP_CTL 0x00 +#define MXC_PLL_DP_CONFIG 0x04 +#define MXC_PLL_DP_OP 0x08 +#define MXC_PLL_DP_MFD 0x0C +#define MXC_PLL_DP_MFN 0x10 +#define MXC_PLL_DP_MFNMINUS 0x14 +#define MXC_PLL_DP_MFNPLUS 0x18 +#define MXC_PLL_DP_HFS_OP 0x1C +#define MXC_PLL_DP_HFS_MFD 0x20 +#define MXC_PLL_DP_HFS_MFN 0x24 +#define MXC_PLL_DP_MFN_TOGC 0x28 +#define MXC_PLL_DP_DESTAT 0x2c + +/* PLL Register Bit definitions */ +#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000 +#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000 +#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12 +#define MXC_PLL_DP_CTL_ADE 0x800 +#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400 +#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8) +#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8 +#define MXC_PLL_DP_CTL_HFSM 0x80 +#define MXC_PLL_DP_CTL_PRE 0x40 +#define MXC_PLL_DP_CTL_UPEN 0x20 +#define MXC_PLL_DP_CTL_RST 0x10 +#define MXC_PLL_DP_CTL_RCP 0x8 +#define MXC_PLL_DP_CTL_PLM 0x4 +#define MXC_PLL_DP_CTL_BRM0 0x2 +#define MXC_PLL_DP_CTL_LRF 0x1 + +#define MXC_PLL_DP_CONFIG_BIST 0x8 +#define MXC_PLL_DP_CONFIG_SJC_CE 0x4 +#define MXC_PLL_DP_CONFIG_AREN 0x2 +#define MXC_PLL_DP_CONFIG_LDREQ 0x1 + +#define MXC_PLL_DP_OP_MFI_OFFSET 4 +#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4) +#define MXC_PLL_DP_OP_PDF_OFFSET 0 +#define MXC_PLL_DP_OP_PDF_MASK 0xF + +#define MXC_PLL_DP_MFD_OFFSET 0 +#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_OFFSET 0x0 +#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17) +#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16) +#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x0 +#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF + +#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) +#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF + +#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ + +struct clk_pllv2 { + struct clk_hw hw; + void __iomem *base; +}; + +static unsigned long clk_pllv2_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; + unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; + void __iomem *pllbase; + s64 temp; + struct clk_pllv2 *pll = to_clk_pllv2(hw); + + pllbase = pll->base; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; + + if (pll_hfsm == 0) { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); + } else { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); + } + pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; + mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; + mfi = (mfi <= 5) ? 5 : mfi; + mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; + mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; + /* Sign extend to 32-bits */ + if (mfn >= 0x04000000) { + mfn |= 0xFC000000; + mfn_abs = -mfn; + } + + ref_clk = 2 * parent_rate; + if (dbl != 0) + ref_clk *= 2; + + ref_clk /= (pdf + 1); + temp = (u64) ref_clk * mfn_abs; + do_div(temp, mfd + 1); + if (mfn < 0) + temp = -temp; + temp = (ref_clk * mfi) + temp; + + return temp; +} + +static int clk_pllv2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv2 *pll = to_clk_pllv2(hw); + u32 reg; + void __iomem *pllbase; + long mfi, pdf, mfn, mfd = 999999; + s64 temp64; + unsigned long quad_parent_rate; + unsigned long pll_hfsm, dp_ctl; + + pllbase = pll->base; + + quad_parent_rate = 4 * parent_rate; + pdf = mfi = -1; + while (++pdf < 16 && mfi < 5) + mfi = rate * (pdf+1) / quad_parent_rate; + if (mfi > 15) + return -EINVAL; + pdf--; + + temp64 = rate * (pdf+1) - quad_parent_rate * mfi; + do_div(temp64, quad_parent_rate/1000000); + mfn = (long)temp64; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + /* use dpdck0_2 */ + __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + if (pll_hfsm == 0) { + reg = mfi << 4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); + } else { + reg = mfi << 4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); + } + + return 0; +} + +static long clk_pllv2_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return rate; +} + +static int clk_pllv2_prepare(struct clk_hw *hw) +{ + struct clk_pllv2 *pll = to_clk_pllv2(hw); + u32 reg; + void __iomem *pllbase; + int i = 0; + + pllbase = pll->base; + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + do { + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + if (reg & MXC_PLL_DP_CTL_LRF) + break; + + udelay(1); + } while (++i < MAX_DPLL_WAIT_TRIES); + + if (i == MAX_DPLL_WAIT_TRIES) { + pr_err("MX5: pll locking failed\n"); + return -EINVAL; + } + + return 0; +} + +static void clk_pllv2_unprepare(struct clk_hw *hw) +{ + struct clk_pllv2 *pll = to_clk_pllv2(hw); + u32 reg; + void __iomem *pllbase; + + pllbase = pll->base; + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); +} + +struct clk_ops clk_pllv2_ops = { + .prepare = clk_pllv2_prepare, + .unprepare = clk_pllv2_unprepare, + .recalc_rate = clk_pllv2_recalc_rate, + .round_rate = clk_pllv2_round_rate, + .set_rate = clk_pllv2_set_rate, +}; + +struct clk *imx_clk_pllv2(const char *name, const char *parent, + void __iomem *base) +{ + struct clk_pllv2 *pll; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->base = base; + + init.name = name; + init.ops = &clk_pllv2_ops; + init.flags = 0; + init.parent_names = &parent; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c new file mode 100644 index 000000000000..36aac947bce1 --- /dev/null +++ b/arch/arm/mach-imx/clk-pllv3.c @@ -0,0 +1,419 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/err.h> +#include "clk.h" + +#define PLL_NUM_OFFSET 0x10 +#define PLL_DENOM_OFFSET 0x20 + +#define BM_PLL_POWER (0x1 << 12) +#define BM_PLL_ENABLE (0x1 << 13) +#define BM_PLL_BYPASS (0x1 << 16) +#define BM_PLL_LOCK (0x1 << 31) + +/** + * struct clk_pllv3 - IMX PLL clock version 3 + * @clk_hw: clock source + * @base: base address of PLL registers + * @powerup_set: set POWER bit to power up the PLL + * @gate_mask: mask of gate bits + * @div_mask: mask of divider bits + * + * IMX PLL clock version 3, found on i.MX6 series. Divider for pllv3 + * is actually a multiplier, and always sits at bit 0. + */ +struct clk_pllv3 { + struct clk_hw hw; + void __iomem *base; + bool powerup_set; + u32 gate_mask; + u32 div_mask; +}; + +#define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw) + +static int clk_pllv3_prepare(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~BM_PLL_BYPASS; + if (pll->powerup_set) + val |= BM_PLL_POWER; + else + val &= ~BM_PLL_POWER; + writel_relaxed(val, pll->base); + + /* Wait for PLL to lock */ + while (!(readl_relaxed(pll->base) & BM_PLL_LOCK)) + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; + + return 0; +} + +static void clk_pllv3_unprepare(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= BM_PLL_BYPASS; + if (pll->powerup_set) + val &= ~BM_PLL_POWER; + else + val |= BM_PLL_POWER; + writel_relaxed(val, pll->base); +} + +static int clk_pllv3_enable(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= pll->gate_mask; + writel_relaxed(val, pll->base); + + return 0; +} + +static void clk_pllv3_disable(struct clk_hw *hw) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~pll->gate_mask; + writel_relaxed(val, pll->base); +} + +static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + return (div == 1) ? parent_rate * 22 : parent_rate * 20; +} + +static long clk_pllv3_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + + return (rate >= parent_rate * 22) ? parent_rate * 22 : + parent_rate * 20; +} + +static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val, div; + + if (rate == parent_rate * 22) + div = 1; + else if (rate == parent_rate * 20) + div = 0; + else + return -EINVAL; + + val = readl_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_recalc_rate, + .round_rate = clk_pllv3_round_rate, + .set_rate = clk_pllv3_set_rate, +}; + +static unsigned long clk_pllv3_sys_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + return parent_rate * div / 2; +} + +static long clk_pllv3_sys_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long min_rate = parent_rate * 54 / 2; + unsigned long max_rate = parent_rate * 108 / 2; + u32 div; + + if (rate > max_rate) + rate = max_rate; + else if (rate < min_rate) + rate = min_rate; + div = rate * 2 / parent_rate; + + return parent_rate * div / 2; +} + +static int clk_pllv3_sys_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + unsigned long min_rate = parent_rate * 54 / 2; + unsigned long max_rate = parent_rate * 108 / 2; + u32 val, div; + + if (rate < min_rate || rate > max_rate) + return -EINVAL; + + div = rate * 2 / parent_rate; + val = readl_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_sys_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_sys_recalc_rate, + .round_rate = clk_pllv3_sys_round_rate, + .set_rate = clk_pllv3_sys_set_rate, +}; + +static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET); + u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + return (parent_rate * div) + ((parent_rate / mfd) * mfn); +} + +static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; + u32 div; + u32 mfn, mfd = 1000000; + s64 temp64; + + if (rate > max_rate) + rate = max_rate; + else if (rate < min_rate) + rate = min_rate; + + div = rate / parent_rate; + temp64 = (u64) (rate - div * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + return parent_rate * div + parent_rate / mfd * mfn; +} + +static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; + u32 val, div; + u32 mfn, mfd = 1000000; + s64 temp64; + + if (rate < min_rate || rate > max_rate) + return -EINVAL; + + div = rate / parent_rate; + temp64 = (u64) (rate - div * parent_rate); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + val = readl_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); + writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); + + return 0; +} + +static const struct clk_ops clk_pllv3_av_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_av_recalc_rate, + .round_rate = clk_pllv3_av_round_rate, + .set_rate = clk_pllv3_av_set_rate, +}; + +static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; + + switch (div) { + case 0: + return 25000000; + case 1: + return 50000000; + case 2: + return 100000000; + case 3: + return 125000000; + } + + return 0; +} + +static long clk_pllv3_enet_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + if (rate >= 125000000) + rate = 125000000; + else if (rate >= 100000000) + rate = 100000000; + else if (rate >= 50000000) + rate = 50000000; + else + rate = 25000000; + return rate; +} + +static int clk_pllv3_enet_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val, div; + + switch (rate) { + case 25000000: + div = 0; + break; + case 50000000: + div = 1; + break; + case 100000000: + div = 2; + break; + case 125000000: + div = 3; + break; + default: + return -EINVAL; + } + + val = readl_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + + return 0; +} + +static const struct clk_ops clk_pllv3_enet_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_enet_recalc_rate, + .round_rate = clk_pllv3_enet_round_rate, + .set_rate = clk_pllv3_enet_set_rate, +}; + +static const struct clk_ops clk_pllv3_mlb_ops = { + .prepare = clk_pllv3_prepare, + .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, +}; + +struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, + const char *parent_name, void __iomem *base, + u32 gate_mask, u32 div_mask) +{ + struct clk_pllv3 *pll; + const struct clk_ops *ops; + struct clk *clk; + struct clk_init_data init; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + switch (type) { + case IMX_PLLV3_SYS: + ops = &clk_pllv3_sys_ops; + break; + case IMX_PLLV3_USB: + ops = &clk_pllv3_ops; + pll->powerup_set = true; + break; + case IMX_PLLV3_AV: + ops = &clk_pllv3_av_ops; + break; + case IMX_PLLV3_ENET: + ops = &clk_pllv3_enet_ops; + break; + case IMX_PLLV3_MLB: + ops = &clk_pllv3_mlb_ops; + break; + default: + ops = &clk_pllv3_ops; + } + pll->base = base; + pll->gate_mask = gate_mask; + pll->div_mask = div_mask; + + init.name = name; + init.ops = ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + pll->hw.init = &init; + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h new file mode 100644 index 000000000000..1bf64fe2523c --- /dev/null +++ b/arch/arm/mach-imx/clk.h @@ -0,0 +1,83 @@ +#ifndef __MACH_IMX_CLK_H +#define __MACH_IMX_CLK_H + +#include <linux/spinlock.h> +#include <linux/clk-provider.h> +#include <mach/clock.h> + +struct clk *imx_clk_pllv1(const char *name, const char *parent, + void __iomem *base); + +struct clk *imx_clk_pllv2(const char *name, const char *parent, + void __iomem *base); + +enum imx_pllv3_type { + IMX_PLLV3_GENERIC, + IMX_PLLV3_SYS, + IMX_PLLV3_USB, + IMX_PLLV3_AV, + IMX_PLLV3_ENET, + IMX_PLLV3_MLB, +}; + +struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, + const char *parent_name, void __iomem *base, u32 gate_mask, + u32 div_mask); + +struct clk *clk_register_gate2(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); + +static inline struct clk *imx_clk_gate2(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &imx_ccm_lock); +} + +struct clk *imx_clk_pfd(const char *name, const char *parent_name, + void __iomem *reg, u8 idx); + +struct clk *imx_clk_busy_divider(const char *name, const char *parent_name, + void __iomem *reg, u8 shift, u8 width, + void __iomem *busy_reg, u8 busy_shift); + +struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift, + u8 width, void __iomem *busy_reg, u8 busy_shift, + const char **parent_names, int num_parents); + +static inline struct clk *imx_clk_fixed(const char *name, int rate) +{ + return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); +} + +static inline struct clk *imx_clk_divider(const char *name, const char *parent, + void __iomem *reg, u8 shift, u8 width) +{ + return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, shift, width, 0, &imx_ccm_lock); +} + +static inline struct clk *imx_clk_gate(const char *name, const char *parent, + void __iomem *reg, u8 shift) +{ + return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + shift, 0, &imx_ccm_lock); +} + +static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, + u8 shift, u8 width, const char **parents, int num_parents) +{ + return clk_register_mux(NULL, name, parents, num_parents, 0, reg, shift, + width, 0, &imx_ccm_lock); +} + +static inline struct clk *imx_clk_fixed_factor(const char *name, + const char *parent, unsigned int mult, unsigned int div) +{ + return clk_register_fixed_factor(NULL, name, parent, + CLK_SET_RATE_PARENT, mult, div); +} + +#endif diff --git a/arch/arm/mach-imx/clock-imx1.c b/arch/arm/mach-imx/clock-imx1.c deleted file mode 100644 index 4aabeb241563..000000000000 --- a/arch/arm/mach-imx/clock-imx1.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/math64.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> - -#define IO_ADDR_CCM(off) (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off))) - -/* CCM register addresses */ -#define CCM_CSCR IO_ADDR_CCM(0x0) -#define CCM_MPCTL0 IO_ADDR_CCM(0x4) -#define CCM_SPCTL0 IO_ADDR_CCM(0xc) -#define CCM_PCDR IO_ADDR_CCM(0x20) - -#define CCM_CSCR_CLKO_OFFSET 29 -#define CCM_CSCR_CLKO_MASK (0x7 << 29) -#define CCM_CSCR_USB_OFFSET 26 -#define CCM_CSCR_USB_MASK (0x7 << 26) -#define CCM_CSCR_OSC_EN_SHIFT 17 -#define CCM_CSCR_SYSTEM_SEL (1 << 16) -#define CCM_CSCR_BCLK_OFFSET 10 -#define CCM_CSCR_BCLK_MASK (0xf << 10) -#define CCM_CSCR_PRESC (1 << 15) - -#define CCM_PCDR_PCLK3_OFFSET 16 -#define CCM_PCDR_PCLK3_MASK (0x7f << 16) -#define CCM_PCDR_PCLK2_OFFSET 4 -#define CCM_PCDR_PCLK2_MASK (0xf << 4) -#define CCM_PCDR_PCLK1_OFFSET 0 -#define CCM_PCDR_PCLK1_MASK 0xf - -#define IO_ADDR_SCM(off) (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off))) - -/* SCM register addresses */ -#define SCM_GCCR IO_ADDR_SCM(0xc) - -#define SCM_GCCR_DMA_CLK_EN_OFFSET 3 -#define SCM_GCCR_CSI_CLK_EN_OFFSET 2 -#define SCM_GCCR_MMA_CLK_EN_OFFSET 1 -#define SCM_GCCR_USBD_CLK_EN_OFFSET 0 - -static int _clk_enable(struct clk *clk) -{ - unsigned int reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void _clk_disable(struct clk *clk) -{ - unsigned int reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size, - struct clk *parent) -{ - int i; - - for (i = 0; i < size; i++) - if (parent == clk_arr[i]) - return i; - - return -EINVAL; -} - -static unsigned long -_clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit) -{ - int div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > limit) - div = limit; - - return parent_rate / div; -} - -static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->round_rate(clk->parent, rate); -} - -static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->set_rate(clk->parent, rate); -} - -static unsigned long clk16m_get_rate(struct clk *clk) -{ - return 16000000; -} - -static struct clk clk16m = { - .get_rate = clk16m_get_rate, - .enable = _clk_enable, - .enable_reg = CCM_CSCR, - .enable_shift = CCM_CSCR_OSC_EN_SHIFT, - .disable = _clk_disable, -}; - -/* in Hz */ -static unsigned long clk32_rate; - -static unsigned long clk32_get_rate(struct clk *clk) -{ - return clk32_rate; -} - -static struct clk clk32 = { - .get_rate = clk32_get_rate, -}; - -static unsigned long clk32_premult_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) * 512; -} - -static struct clk clk32_premult = { - .parent = &clk32, - .get_rate = clk32_premult_get_rate, -}; - -static const struct clk *prem_clk_clocks[] = { - &clk32_premult, - &clk16m, -}; - -static int prem_clk_set_parent(struct clk *clk, struct clk *parent) -{ - int i; - unsigned int reg = __raw_readl(CCM_CSCR); - - i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks), - parent); - - switch (i) { - case 0: - reg &= ~CCM_CSCR_SYSTEM_SEL; - break; - case 1: - reg |= CCM_CSCR_SYSTEM_SEL; - break; - default: - return i; - } - - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static struct clk prem_clk = { - .set_parent = prem_clk_set_parent, -}; - -static unsigned long system_clk_get_rate(struct clk *clk) -{ - return mxc_decode_pll(__raw_readl(CCM_SPCTL0), - clk_get_rate(clk->parent)); -} - -static struct clk system_clk = { - .parent = &prem_clk, - .get_rate = system_clk_get_rate, -}; - -static unsigned long mcu_clk_get_rate(struct clk *clk) -{ - return mxc_decode_pll(__raw_readl(CCM_MPCTL0), - clk_get_rate(clk->parent)); -} - -static struct clk mcu_clk = { - .parent = &clk32_premult, - .get_rate = mcu_clk_get_rate, -}; - -static unsigned long fclk_get_rate(struct clk *clk) -{ - unsigned long fclk = clk_get_rate(clk->parent); - - if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC) - fclk /= 2; - - return fclk; -} - -static struct clk fclk = { - .parent = &mcu_clk, - .get_rate = fclk_get_rate, -}; - -/* - * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA ) - */ -static unsigned long hclk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & - CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1); -} - -static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 16); -} - -static int hclk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 16 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_BCLK_MASK; - reg |= div << CCM_CSCR_BCLK_OFFSET; - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static struct clk hclk = { - .parent = &system_clk, - .get_rate = hclk_get_rate, - .round_rate = hclk_round_rate, - .set_rate = hclk_set_rate, -}; - -static unsigned long clk48m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & - CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1); -} - -static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 8); -} - -static int clk48m_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_USB_MASK; - reg |= div << CCM_CSCR_USB_OFFSET; - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static struct clk clk48m = { - .parent = &system_clk, - .get_rate = clk48m_get_rate, - .round_rate = clk48m_round_rate, - .set_rate = clk48m_set_rate, -}; - -/* - * get peripheral clock 1 ( UART[12], Timer[12], PWM ) - */ -static unsigned long perclk1_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & - CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1); -} - -static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 16); -} - -static int perclk1_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 16 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_PCDR); - reg &= ~CCM_PCDR_PCLK1_MASK; - reg |= div << CCM_PCDR_PCLK1_OFFSET; - __raw_writel(reg, CCM_PCDR); - - return 0; -} - -/* - * get peripheral clock 2 ( LCD, SD, SPI[12] ) - */ -static unsigned long perclk2_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & - CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1); -} - -static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 16); -} - -static int perclk2_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 16 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_PCDR); - reg &= ~CCM_PCDR_PCLK2_MASK; - reg |= div << CCM_PCDR_PCLK2_OFFSET; - __raw_writel(reg, CCM_PCDR); - - return 0; -} - -/* - * get peripheral clock 3 ( SSI ) - */ -static unsigned long perclk3_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & - CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1); -} - -static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_simple_round_rate(clk, rate, 128); -} - -static int perclk3_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned int div; - unsigned int reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 128 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_PCDR); - reg &= ~CCM_PCDR_PCLK3_MASK; - reg |= div << CCM_PCDR_PCLK3_OFFSET; - __raw_writel(reg, CCM_PCDR); - - return 0; -} - -static struct clk perclk[] = { - { - .id = 0, - .parent = &system_clk, - .get_rate = perclk1_get_rate, - .round_rate = perclk1_round_rate, - .set_rate = perclk1_set_rate, - }, { - .id = 1, - .parent = &system_clk, - .get_rate = perclk2_get_rate, - .round_rate = perclk2_round_rate, - .set_rate = perclk2_set_rate, - }, { - .id = 2, - .parent = &system_clk, - .get_rate = perclk3_get_rate, - .round_rate = perclk3_round_rate, - .set_rate = perclk3_set_rate, - } -}; - -static const struct clk *clko_clocks[] = { - &perclk[0], - &hclk, - &clk48m, - &clk16m, - &prem_clk, - &fclk, -}; - -static int clko_set_parent(struct clk *clk, struct clk *parent) -{ - int i; - unsigned int reg; - - i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent); - if (i < 0) - return i; - - reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK; - reg |= i << CCM_CSCR_CLKO_OFFSET; - __raw_writel(reg, CCM_CSCR); - - if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) { - clk->set_rate = _clk_parent_set_rate; - clk->round_rate = _clk_parent_round_rate; - } else { - clk->set_rate = NULL; - clk->round_rate = NULL; - } - - return 0; -} - -static struct clk clko_clk = { - .set_parent = clko_set_parent, -}; - -static struct clk dma_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk csi_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk mma_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk usbd_clk = { - .parent = &clk48m, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - .enable = _clk_enable, - .enable_reg = SCM_GCCR, - .enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET, - .disable = _clk_disable, -}; - -static struct clk gpt_clk = { - .parent = &perclk[0], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk uart_clk = { - .parent = &perclk[0], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk i2c_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk spi_clk = { - .parent = &perclk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk sdhc_clk = { - .parent = &perclk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk lcdc_clk = { - .parent = &perclk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk mshc_clk = { - .parent = &hclk, - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk ssi_clk = { - .parent = &perclk[2], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, -}; - -static struct clk rtc_clk = { - .parent = &clk32, -}; - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, -static struct clk_lookup lookups[] __initdata = { - _REGISTER_CLOCK(NULL, "dma", dma_clk) - _REGISTER_CLOCK("mx1-camera.0", NULL, csi_clk) - _REGISTER_CLOCK(NULL, "mma", mma_clk) - _REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - _REGISTER_CLOCK("imx1-uart.0", NULL, uart_clk) - _REGISTER_CLOCK("imx1-uart.1", NULL, uart_clk) - _REGISTER_CLOCK("imx1-uart.2", NULL, uart_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) - _REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk) - _REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk) - _REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) - _REGISTER_CLOCK(NULL, "mshc", mshc_clk) - _REGISTER_CLOCK(NULL, "ssi", ssi_clk) - _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk) -}; - -int __init mx1_clocks_init(unsigned long fref) -{ - unsigned int reg; - - /* disable clocks we are able to */ - __raw_writel(0, SCM_GCCR); - - clk32_rate = fref; - reg = __raw_readl(CCM_CSCR); - - /* detect clock reference for system PLL */ - if (reg & CCM_CSCR_SYSTEM_SEL) { - prem_clk.parent = &clk16m; - } else { - /* ensure that oscillator is disabled */ - reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT); - __raw_writel(reg, CCM_CSCR); - prem_clk.parent = &clk32_premult; - } - - /* detect reference for CLKO */ - reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET; - clko_clk.parent = (struct clk *)clko_clocks[reg]; - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - clk_enable(&hclk); - clk_enable(&fclk); - - mxc_timer_init(&gpt_clk, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), - MX1_TIM1_INT); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx21.c b/arch/arm/mach-imx/clock-imx21.c deleted file mode 100644 index ee15d8c9db08..000000000000 --- a/arch/arm/mach-imx/clock-imx21.c +++ /dev/null @@ -1,1239 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> -#include <asm/div64.h> - -#define IO_ADDR_CCM(off) (MX21_IO_ADDRESS(MX21_CCM_BASE_ADDR + (off))) - -/* Register offsets */ -#define CCM_CSCR IO_ADDR_CCM(0x0) -#define CCM_MPCTL0 IO_ADDR_CCM(0x4) -#define CCM_MPCTL1 IO_ADDR_CCM(0x8) -#define CCM_SPCTL0 IO_ADDR_CCM(0xc) -#define CCM_SPCTL1 IO_ADDR_CCM(0x10) -#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) -#define CCM_PCDR0 IO_ADDR_CCM(0x18) -#define CCM_PCDR1 IO_ADDR_CCM(0x1c) -#define CCM_PCCR0 IO_ADDR_CCM(0x20) -#define CCM_PCCR1 IO_ADDR_CCM(0x24) -#define CCM_CCSR IO_ADDR_CCM(0x28) -#define CCM_PMCTL IO_ADDR_CCM(0x2c) -#define CCM_PMCOUNT IO_ADDR_CCM(0x30) -#define CCM_WKGDCTL IO_ADDR_CCM(0x34) - -#define CCM_CSCR_PRESC_OFFSET 29 -#define CCM_CSCR_PRESC_MASK (0x7 << CCM_CSCR_PRESC_OFFSET) - -#define CCM_CSCR_USB_OFFSET 26 -#define CCM_CSCR_USB_MASK (0x7 << CCM_CSCR_USB_OFFSET) -#define CCM_CSCR_SD_OFFSET 24 -#define CCM_CSCR_SD_MASK (0x3 << CCM_CSCR_SD_OFFSET) -#define CCM_CSCR_SPLLRES (1 << 22) -#define CCM_CSCR_MPLLRES (1 << 21) -#define CCM_CSCR_SSI2_OFFSET 20 -#define CCM_CSCR_SSI2 (1 << CCM_CSCR_SSI2_OFFSET) -#define CCM_CSCR_SSI1_OFFSET 19 -#define CCM_CSCR_SSI1 (1 << CCM_CSCR_SSI1_OFFSET) -#define CCM_CSCR_FIR_OFFSET 18 -#define CCM_CSCR_FIR (1 << CCM_CSCR_FIR_OFFSET) -#define CCM_CSCR_SP (1 << 17) -#define CCM_CSCR_MCU (1 << 16) -#define CCM_CSCR_BCLK_OFFSET 10 -#define CCM_CSCR_BCLK_MASK (0xf << CCM_CSCR_BCLK_OFFSET) -#define CCM_CSCR_IPDIV_OFFSET 9 -#define CCM_CSCR_IPDIV (1 << CCM_CSCR_IPDIV_OFFSET) - -#define CCM_CSCR_OSC26MDIV (1 << 4) -#define CCM_CSCR_OSC26M (1 << 3) -#define CCM_CSCR_FPM (1 << 2) -#define CCM_CSCR_SPEN (1 << 1) -#define CCM_CSCR_MPEN 1 - -#define CCM_MPCTL0_CPLM (1 << 31) -#define CCM_MPCTL0_PD_OFFSET 26 -#define CCM_MPCTL0_PD_MASK (0xf << 26) -#define CCM_MPCTL0_MFD_OFFSET 16 -#define CCM_MPCTL0_MFD_MASK (0x3ff << 16) -#define CCM_MPCTL0_MFI_OFFSET 10 -#define CCM_MPCTL0_MFI_MASK (0xf << 10) -#define CCM_MPCTL0_MFN_OFFSET 0 -#define CCM_MPCTL0_MFN_MASK 0x3ff - -#define CCM_MPCTL1_LF (1 << 15) -#define CCM_MPCTL1_BRMO (1 << 6) - -#define CCM_SPCTL0_CPLM (1 << 31) -#define CCM_SPCTL0_PD_OFFSET 26 -#define CCM_SPCTL0_PD_MASK (0xf << 26) -#define CCM_SPCTL0_MFD_OFFSET 16 -#define CCM_SPCTL0_MFD_MASK (0x3ff << 16) -#define CCM_SPCTL0_MFI_OFFSET 10 -#define CCM_SPCTL0_MFI_MASK (0xf << 10) -#define CCM_SPCTL0_MFN_OFFSET 0 -#define CCM_SPCTL0_MFN_MASK 0x3ff - -#define CCM_SPCTL1_LF (1 << 15) -#define CCM_SPCTL1_BRMO (1 << 6) - -#define CCM_OSC26MCTL_PEAK_OFFSET 16 -#define CCM_OSC26MCTL_PEAK_MASK (0x3 << 16) -#define CCM_OSC26MCTL_AGC_OFFSET 8 -#define CCM_OSC26MCTL_AGC_MASK (0x3f << 8) -#define CCM_OSC26MCTL_ANATEST_OFFSET 0 -#define CCM_OSC26MCTL_ANATEST_MASK 0x3f - -#define CCM_PCDR0_SSI2BAUDDIV_OFFSET 26 -#define CCM_PCDR0_SSI2BAUDDIV_MASK (0x3f << 26) -#define CCM_PCDR0_SSI1BAUDDIV_OFFSET 16 -#define CCM_PCDR0_SSI1BAUDDIV_MASK (0x3f << 16) -#define CCM_PCDR0_NFCDIV_OFFSET 12 -#define CCM_PCDR0_NFCDIV_MASK (0xf << 12) -#define CCM_PCDR0_48MDIV_OFFSET 5 -#define CCM_PCDR0_48MDIV_MASK (0x7 << CCM_PCDR0_48MDIV_OFFSET) -#define CCM_PCDR0_FIRIDIV_OFFSET 0 -#define CCM_PCDR0_FIRIDIV_MASK 0x1f -#define CCM_PCDR1_PERDIV4_OFFSET 24 -#define CCM_PCDR1_PERDIV4_MASK (0x3f << 24) -#define CCM_PCDR1_PERDIV3_OFFSET 16 -#define CCM_PCDR1_PERDIV3_MASK (0x3f << 16) -#define CCM_PCDR1_PERDIV2_OFFSET 8 -#define CCM_PCDR1_PERDIV2_MASK (0x3f << 8) -#define CCM_PCDR1_PERDIV1_OFFSET 0 -#define CCM_PCDR1_PERDIV1_MASK 0x3f - -#define CCM_PCCR_HCLK_CSI_OFFSET 31 -#define CCM_PCCR_HCLK_CSI_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_DMA_OFFSET 30 -#define CCM_PCCR_HCLK_DMA_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_BROM_OFFSET 28 -#define CCM_PCCR_HCLK_BROM_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_EMMA_OFFSET 27 -#define CCM_PCCR_HCLK_EMMA_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_LCDC_OFFSET 26 -#define CCM_PCCR_HCLK_LCDC_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_SLCDC_OFFSET 25 -#define CCM_PCCR_HCLK_SLCDC_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_USBOTG_OFFSET 24 -#define CCM_PCCR_HCLK_USBOTG_REG CCM_PCCR0 -#define CCM_PCCR_HCLK_BMI_OFFSET 23 -#define CCM_PCCR_BMI_MASK (1 << CCM_PCCR_BMI_MASK) -#define CCM_PCCR_HCLK_BMI_REG CCM_PCCR0 -#define CCM_PCCR_PERCLK4_OFFSET 22 -#define CCM_PCCR_PERCLK4_REG CCM_PCCR0 -#define CCM_PCCR_SLCDC_OFFSET 21 -#define CCM_PCCR_SLCDC_REG CCM_PCCR0 -#define CCM_PCCR_FIRI_BAUD_OFFSET 20 -#define CCM_PCCR_FIRI_BAUD_MASK (1 << CCM_PCCR_FIRI_BAUD_MASK) -#define CCM_PCCR_FIRI_BAUD_REG CCM_PCCR0 -#define CCM_PCCR_NFC_OFFSET 19 -#define CCM_PCCR_NFC_REG CCM_PCCR0 -#define CCM_PCCR_LCDC_OFFSET 18 -#define CCM_PCCR_LCDC_REG CCM_PCCR0 -#define CCM_PCCR_SSI1_BAUD_OFFSET 17 -#define CCM_PCCR_SSI1_BAUD_REG CCM_PCCR0 -#define CCM_PCCR_SSI2_BAUD_OFFSET 16 -#define CCM_PCCR_SSI2_BAUD_REG CCM_PCCR0 -#define CCM_PCCR_EMMA_OFFSET 15 -#define CCM_PCCR_EMMA_REG CCM_PCCR0 -#define CCM_PCCR_USBOTG_OFFSET 14 -#define CCM_PCCR_USBOTG_REG CCM_PCCR0 -#define CCM_PCCR_DMA_OFFSET 13 -#define CCM_PCCR_DMA_REG CCM_PCCR0 -#define CCM_PCCR_I2C1_OFFSET 12 -#define CCM_PCCR_I2C1_REG CCM_PCCR0 -#define CCM_PCCR_GPIO_OFFSET 11 -#define CCM_PCCR_GPIO_REG CCM_PCCR0 -#define CCM_PCCR_SDHC2_OFFSET 10 -#define CCM_PCCR_SDHC2_REG CCM_PCCR0 -#define CCM_PCCR_SDHC1_OFFSET 9 -#define CCM_PCCR_SDHC1_REG CCM_PCCR0 -#define CCM_PCCR_FIRI_OFFSET 8 -#define CCM_PCCR_FIRI_MASK (1 << CCM_PCCR_BAUD_MASK) -#define CCM_PCCR_FIRI_REG CCM_PCCR0 -#define CCM_PCCR_SSI2_IPG_OFFSET 7 -#define CCM_PCCR_SSI2_REG CCM_PCCR0 -#define CCM_PCCR_SSI1_IPG_OFFSET 6 -#define CCM_PCCR_SSI1_REG CCM_PCCR0 -#define CCM_PCCR_CSPI2_OFFSET 5 -#define CCM_PCCR_CSPI2_REG CCM_PCCR0 -#define CCM_PCCR_CSPI1_OFFSET 4 -#define CCM_PCCR_CSPI1_REG CCM_PCCR0 -#define CCM_PCCR_UART4_OFFSET 3 -#define CCM_PCCR_UART4_REG CCM_PCCR0 -#define CCM_PCCR_UART3_OFFSET 2 -#define CCM_PCCR_UART3_REG CCM_PCCR0 -#define CCM_PCCR_UART2_OFFSET 1 -#define CCM_PCCR_UART2_REG CCM_PCCR0 -#define CCM_PCCR_UART1_OFFSET 0 -#define CCM_PCCR_UART1_REG CCM_PCCR0 - -#define CCM_PCCR_OWIRE_OFFSET 31 -#define CCM_PCCR_OWIRE_REG CCM_PCCR1 -#define CCM_PCCR_KPP_OFFSET 30 -#define CCM_PCCR_KPP_REG CCM_PCCR1 -#define CCM_PCCR_RTC_OFFSET 29 -#define CCM_PCCR_RTC_REG CCM_PCCR1 -#define CCM_PCCR_PWM_OFFSET 28 -#define CCM_PCCR_PWM_REG CCM_PCCR1 -#define CCM_PCCR_GPT3_OFFSET 27 -#define CCM_PCCR_GPT3_REG CCM_PCCR1 -#define CCM_PCCR_GPT2_OFFSET 26 -#define CCM_PCCR_GPT2_REG CCM_PCCR1 -#define CCM_PCCR_GPT1_OFFSET 25 -#define CCM_PCCR_GPT1_REG CCM_PCCR1 -#define CCM_PCCR_WDT_OFFSET 24 -#define CCM_PCCR_WDT_REG CCM_PCCR1 -#define CCM_PCCR_CSPI3_OFFSET 23 -#define CCM_PCCR_CSPI3_REG CCM_PCCR1 - -#define CCM_PCCR_CSPI1_MASK (1 << CCM_PCCR_CSPI1_OFFSET) -#define CCM_PCCR_CSPI2_MASK (1 << CCM_PCCR_CSPI2_OFFSET) -#define CCM_PCCR_CSPI3_MASK (1 << CCM_PCCR_CSPI3_OFFSET) -#define CCM_PCCR_DMA_MASK (1 << CCM_PCCR_DMA_OFFSET) -#define CCM_PCCR_EMMA_MASK (1 << CCM_PCCR_EMMA_OFFSET) -#define CCM_PCCR_GPIO_MASK (1 << CCM_PCCR_GPIO_OFFSET) -#define CCM_PCCR_GPT1_MASK (1 << CCM_PCCR_GPT1_OFFSET) -#define CCM_PCCR_GPT2_MASK (1 << CCM_PCCR_GPT2_OFFSET) -#define CCM_PCCR_GPT3_MASK (1 << CCM_PCCR_GPT3_OFFSET) -#define CCM_PCCR_HCLK_BROM_MASK (1 << CCM_PCCR_HCLK_BROM_OFFSET) -#define CCM_PCCR_HCLK_CSI_MASK (1 << CCM_PCCR_HCLK_CSI_OFFSET) -#define CCM_PCCR_HCLK_DMA_MASK (1 << CCM_PCCR_HCLK_DMA_OFFSET) -#define CCM_PCCR_HCLK_EMMA_MASK (1 << CCM_PCCR_HCLK_EMMA_OFFSET) -#define CCM_PCCR_HCLK_LCDC_MASK (1 << CCM_PCCR_HCLK_LCDC_OFFSET) -#define CCM_PCCR_HCLK_SLCDC_MASK (1 << CCM_PCCR_HCLK_SLCDC_OFFSET) -#define CCM_PCCR_HCLK_USBOTG_MASK (1 << CCM_PCCR_HCLK_USBOTG_OFFSET) -#define CCM_PCCR_I2C1_MASK (1 << CCM_PCCR_I2C1_OFFSET) -#define CCM_PCCR_KPP_MASK (1 << CCM_PCCR_KPP_OFFSET) -#define CCM_PCCR_LCDC_MASK (1 << CCM_PCCR_LCDC_OFFSET) -#define CCM_PCCR_NFC_MASK (1 << CCM_PCCR_NFC_OFFSET) -#define CCM_PCCR_OWIRE_MASK (1 << CCM_PCCR_OWIRE_OFFSET) -#define CCM_PCCR_PERCLK4_MASK (1 << CCM_PCCR_PERCLK4_OFFSET) -#define CCM_PCCR_PWM_MASK (1 << CCM_PCCR_PWM_OFFSET) -#define CCM_PCCR_RTC_MASK (1 << CCM_PCCR_RTC_OFFSET) -#define CCM_PCCR_SDHC1_MASK (1 << CCM_PCCR_SDHC1_OFFSET) -#define CCM_PCCR_SDHC2_MASK (1 << CCM_PCCR_SDHC2_OFFSET) -#define CCM_PCCR_SLCDC_MASK (1 << CCM_PCCR_SLCDC_OFFSET) -#define CCM_PCCR_SSI1_BAUD_MASK (1 << CCM_PCCR_SSI1_BAUD_OFFSET) -#define CCM_PCCR_SSI1_IPG_MASK (1 << CCM_PCCR_SSI1_IPG_OFFSET) -#define CCM_PCCR_SSI2_BAUD_MASK (1 << CCM_PCCR_SSI2_BAUD_OFFSET) -#define CCM_PCCR_SSI2_IPG_MASK (1 << CCM_PCCR_SSI2_IPG_OFFSET) -#define CCM_PCCR_UART1_MASK (1 << CCM_PCCR_UART1_OFFSET) -#define CCM_PCCR_UART2_MASK (1 << CCM_PCCR_UART2_OFFSET) -#define CCM_PCCR_UART3_MASK (1 << CCM_PCCR_UART3_OFFSET) -#define CCM_PCCR_UART4_MASK (1 << CCM_PCCR_UART4_OFFSET) -#define CCM_PCCR_USBOTG_MASK (1 << CCM_PCCR_USBOTG_OFFSET) -#define CCM_PCCR_WDT_MASK (1 << CCM_PCCR_WDT_OFFSET) - -#define CCM_CCSR_32KSR (1 << 15) - -#define CCM_CCSR_CLKMODE1 (1 << 9) -#define CCM_CCSR_CLKMODE0 (1 << 8) - -#define CCM_CCSR_CLKOSEL_OFFSET 0 -#define CCM_CCSR_CLKOSEL_MASK 0x1f - -#define SYS_FMCR 0x14 /* Functional Muxing Control Reg */ -#define SYS_CHIP_ID 0x00 /* The offset of CHIP ID register */ - -static int _clk_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - return 0; -} - -static void _clk_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -static unsigned long _clk_generic_round_rate(struct clk *clk, - unsigned long rate, - u32 max_divisor) -{ - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > max_divisor) - div = max_divisor; - - return parent_rate / div; -} - -static int _clk_spll_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(CCM_CSCR); - reg |= CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); - - while ((__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF) == 0) - ; - return 0; -} - -static void _clk_spll_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); -} - - -#define CSCR() (__raw_readl(CCM_CSCR)) -#define PCDR0() (__raw_readl(CCM_PCDR0)) -#define PCDR1() (__raw_readl(CCM_PCDR1)) - -static unsigned long _clk_perclkx_round_rate(struct clk *clk, - unsigned long rate) -{ - return _clk_generic_round_rate(clk, rate, 64); -} - -static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return -EINVAL; - - div = parent_rate / rate; - if (div > 64 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = - __raw_readl(CCM_PCDR1) & ~(CCM_PCDR1_PERDIV1_MASK << - (clk->id << 3)); - reg |= div << (clk->id << 3); - __raw_writel(reg, CCM_PCDR1); - - return 0; -} - -static unsigned long _clk_usb_recalc(struct clk *clk) -{ - unsigned long usb_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - usb_pdf = (CSCR() & CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET; - - return parent_rate / (usb_pdf + 1U); -} - -static unsigned long _clk_usb_round_rate(struct clk *clk, - unsigned long rate) -{ - return _clk_generic_round_rate(clk, rate, 8); -} - -static int _clk_usb_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = CSCR() & ~CCM_CSCR_USB_MASK; - reg |= div << CCM_CSCR_USB_OFFSET; - __raw_writel(reg, CCM_CSCR); - - return 0; -} - -static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf) -{ - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */ - - return 2UL * parent_rate / pdf; -} - -static unsigned long _clk_ssi1_recalc(struct clk *clk) -{ - return _clk_ssix_recalc(clk, - (PCDR0() & CCM_PCDR0_SSI1BAUDDIV_MASK) - >> CCM_PCDR0_SSI1BAUDDIV_OFFSET); -} - -static unsigned long _clk_ssi2_recalc(struct clk *clk) -{ - return _clk_ssix_recalc(clk, - (PCDR0() & CCM_PCDR0_SSI2BAUDDIV_MASK) >> - CCM_PCDR0_SSI2BAUDDIV_OFFSET); -} - -static unsigned long _clk_nfc_recalc(struct clk *clk) -{ - unsigned long nfc_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - nfc_pdf = (PCDR0() & CCM_PCDR0_NFCDIV_MASK) - >> CCM_PCDR0_NFCDIV_OFFSET; - - return parent_rate / (nfc_pdf + 1); -} - -static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->round_rate(clk->parent, rate); -} - -static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) -{ - return clk->parent->set_rate(clk->parent, rate); -} - -static unsigned long external_high_reference; /* in Hz */ - -static unsigned long get_high_reference_clock_rate(struct clk *clk) -{ - return external_high_reference; -} - -/* - * the high frequency external clock reference - * Default case is 26MHz. - */ -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static unsigned long external_low_reference; /* in Hz */ - -static unsigned long get_low_reference_clock_rate(struct clk *clk) -{ - return external_low_reference; -} - -/* - * the low frequency external clock reference - * Default case is 32.768kHz. - */ -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - - -static unsigned long _clk_fpm_recalc(struct clk *clk) -{ - return clk_get_rate(clk->parent) * 512; -} - -/* Output of frequency pre multiplier */ -static struct clk fpm_clk = { - .parent = &ckil_clk, - .get_rate = _clk_fpm_recalc, -}; - -static unsigned long get_mpll_clk(struct clk *clk) -{ - uint32_t reg; - unsigned long ref_clk; - unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0; - unsigned long long temp; - - ref_clk = clk_get_rate(clk->parent); - - reg = __raw_readl(CCM_MPCTL0); - pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET; - mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET; - mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET; - mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET; - - mfi = (mfi <= 5) ? 5 : mfi; - temp = 2LL * ref_clk * mfn; - do_div(temp, mfd + 1); - temp = 2LL * ref_clk * mfi + temp; - do_div(temp, pdf + 1); - - return (unsigned long)temp; -} - -static struct clk mpll_clk = { - .parent = &ckih_clk, - .get_rate = get_mpll_clk, -}; - -static unsigned long _clk_fclk_get_rate(struct clk *clk) -{ - unsigned long parent_rate; - u32 div; - - div = (CSCR() & CCM_CSCR_PRESC_MASK) >> CCM_CSCR_PRESC_OFFSET; - parent_rate = clk_get_rate(clk->parent); - - return parent_rate / (div+1); -} - -static struct clk fclk_clk = { - .parent = &mpll_clk, - .get_rate = _clk_fclk_get_rate -}; - -static unsigned long get_spll_clk(struct clk *clk) -{ - uint32_t reg; - unsigned long ref_clk; - unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0; - unsigned long long temp; - - ref_clk = clk_get_rate(clk->parent); - - reg = __raw_readl(CCM_SPCTL0); - pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET; - mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET; - mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET; - mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET; - - mfi = (mfi <= 5) ? 5 : mfi; - temp = 2LL * ref_clk * mfn; - do_div(temp, mfd + 1); - temp = 2LL * ref_clk * mfi + temp; - do_div(temp, pdf + 1); - - return (unsigned long)temp; -} - -static struct clk spll_clk = { - .parent = &ckih_clk, - .get_rate = get_spll_clk, - .enable = _clk_spll_enable, - .disable = _clk_spll_disable, -}; - -static unsigned long get_hclk_clk(struct clk *clk) -{ - unsigned long rate; - unsigned long bclk_pdf; - - bclk_pdf = (CSCR() & CCM_CSCR_BCLK_MASK) - >> CCM_CSCR_BCLK_OFFSET; - - rate = clk_get_rate(clk->parent); - return rate / (bclk_pdf + 1); -} - -static struct clk hclk_clk = { - .parent = &fclk_clk, - .get_rate = get_hclk_clk, -}; - -static unsigned long get_ipg_clk(struct clk *clk) -{ - unsigned long rate; - unsigned long ipg_pdf; - - ipg_pdf = (CSCR() & CCM_CSCR_IPDIV) >> CCM_CSCR_IPDIV_OFFSET; - - rate = clk_get_rate(clk->parent); - return rate / (ipg_pdf + 1); -} - -static struct clk ipg_clk = { - .parent = &hclk_clk, - .get_rate = get_ipg_clk, -}; - -static unsigned long _clk_perclkx_recalc(struct clk *clk) -{ - unsigned long perclk_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return 0; - - perclk_pdf = (PCDR1() >> (clk->id << 3)) & CCM_PCDR1_PERDIV1_MASK; - - return parent_rate / (perclk_pdf + 1); -} - -static struct clk per_clk[] = { - { - .id = 0, - .parent = &mpll_clk, - .get_rate = _clk_perclkx_recalc, - }, { - .id = 1, - .parent = &mpll_clk, - .get_rate = _clk_perclkx_recalc, - }, { - .id = 2, - .parent = &mpll_clk, - .round_rate = _clk_perclkx_round_rate, - .set_rate = _clk_perclkx_set_rate, - .get_rate = _clk_perclkx_recalc, - /* Enable/Disable done via lcd_clkc[1] */ - }, { - .id = 3, - .parent = &mpll_clk, - .round_rate = _clk_perclkx_round_rate, - .set_rate = _clk_perclkx_set_rate, - .get_rate = _clk_perclkx_recalc, - /* Enable/Disable done via csi_clk[1] */ - }, -}; - -static struct clk uart_ipg_clk[]; - -static struct clk uart_clk[] = { - { - .id = 0, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[1], - }, { - .id = 2, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[2], - }, { - .id = 3, - .parent = &per_clk[0], - .secondary = &uart_ipg_clk[3], - }, -}; - -static struct clk uart_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART1_REG, - .enable_shift = CCM_PCCR_UART1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART2_REG, - .enable_shift = CCM_PCCR_UART2_OFFSET, - .disable = _clk_disable, - }, { - .id = 2, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART3_REG, - .enable_shift = CCM_PCCR_UART3_OFFSET, - .disable = _clk_disable, - }, { - .id = 3, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_UART4_REG, - .enable_shift = CCM_PCCR_UART4_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk gpt_ipg_clk[]; - -static struct clk gpt_clk[] = { - { - .id = 0, - .parent = &per_clk[0], - .secondary = &gpt_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[0], - .secondary = &gpt_ipg_clk[1], - }, { - .id = 2, - .parent = &per_clk[0], - .secondary = &gpt_ipg_clk[2], - }, -}; - -static struct clk gpt_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPT1_REG, - .enable_shift = CCM_PCCR_GPT1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPT2_REG, - .enable_shift = CCM_PCCR_GPT2_OFFSET, - .disable = _clk_disable, - }, { - .id = 2, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPT3_REG, - .enable_shift = CCM_PCCR_GPT3_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk pwm_clk[] = { - { - .parent = &per_clk[0], - .secondary = &pwm_clk[1], - }, { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_PWM_REG, - .enable_shift = CCM_PCCR_PWM_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk sdhc_ipg_clk[]; - -static struct clk sdhc_clk[] = { - { - .id = 0, - .parent = &per_clk[1], - .secondary = &sdhc_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[1], - .secondary = &sdhc_ipg_clk[1], - }, -}; - -static struct clk sdhc_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SDHC1_REG, - .enable_shift = CCM_PCCR_SDHC1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SDHC2_REG, - .enable_shift = CCM_PCCR_SDHC2_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk cspi_ipg_clk[]; - -static struct clk cspi_clk[] = { - { - .id = 0, - .parent = &per_clk[1], - .secondary = &cspi_ipg_clk[0], - }, { - .id = 1, - .parent = &per_clk[1], - .secondary = &cspi_ipg_clk[1], - }, { - .id = 2, - .parent = &per_clk[1], - .secondary = &cspi_ipg_clk[2], - }, -}; - -static struct clk cspi_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_CSPI1_REG, - .enable_shift = CCM_PCCR_CSPI1_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_CSPI2_REG, - .enable_shift = CCM_PCCR_CSPI2_OFFSET, - .disable = _clk_disable, - }, { - .id = 3, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_CSPI3_REG, - .enable_shift = CCM_PCCR_CSPI3_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk lcdc_clk[] = { - { - .parent = &per_clk[2], - .secondary = &lcdc_clk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - }, { - .parent = &ipg_clk, - .secondary = &lcdc_clk[2], - .enable = _clk_enable, - .enable_reg = CCM_PCCR_LCDC_REG, - .enable_shift = CCM_PCCR_LCDC_OFFSET, - .disable = _clk_disable, - }, { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_LCDC_REG, - .enable_shift = CCM_PCCR_HCLK_LCDC_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk csi_clk[] = { - { - .parent = &per_clk[3], - .secondary = &csi_clk[1], - .round_rate = _clk_parent_round_rate, - .set_rate = _clk_parent_set_rate, - }, { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_CSI_REG, - .enable_shift = CCM_PCCR_HCLK_CSI_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk usb_clk[] = { - { - .parent = &spll_clk, - .secondary = &usb_clk[1], - .get_rate = _clk_usb_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_USBOTG_REG, - .enable_shift = CCM_PCCR_USBOTG_OFFSET, - .disable = _clk_disable, - .round_rate = _clk_usb_round_rate, - .set_rate = _clk_usb_set_rate, - }, { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_USBOTG_REG, - .enable_shift = CCM_PCCR_HCLK_USBOTG_OFFSET, - .disable = _clk_disable, - } -}; - -static struct clk ssi_ipg_clk[]; - -static struct clk ssi_clk[] = { - { - .id = 0, - .parent = &mpll_clk, - .secondary = &ssi_ipg_clk[0], - .get_rate = _clk_ssi1_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI1_BAUD_REG, - .enable_shift = CCM_PCCR_SSI1_BAUD_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &mpll_clk, - .secondary = &ssi_ipg_clk[1], - .get_rate = _clk_ssi2_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI2_BAUD_REG, - .enable_shift = CCM_PCCR_SSI2_BAUD_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk ssi_ipg_clk[] = { - { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI1_REG, - .enable_shift = CCM_PCCR_SSI1_IPG_OFFSET, - .disable = _clk_disable, - }, { - .id = 1, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SSI2_REG, - .enable_shift = CCM_PCCR_SSI2_IPG_OFFSET, - .disable = _clk_disable, - }, -}; - - -static struct clk nfc_clk = { - .parent = &fclk_clk, - .get_rate = _clk_nfc_recalc, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_NFC_REG, - .enable_shift = CCM_PCCR_NFC_OFFSET, - .disable = _clk_disable, -}; - -static struct clk dma_clk[] = { - { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_DMA_REG, - .enable_shift = CCM_PCCR_DMA_OFFSET, - .disable = _clk_disable, - .secondary = &dma_clk[1], - }, { - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_DMA_REG, - .enable_shift = CCM_PCCR_HCLK_DMA_OFFSET, - .disable = _clk_disable, - }, -}; - -static struct clk brom_clk = { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_BROM_REG, - .enable_shift = CCM_PCCR_HCLK_BROM_OFFSET, - .disable = _clk_disable, -}; - -static struct clk emma_clk[] = { - { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_EMMA_REG, - .enable_shift = CCM_PCCR_EMMA_OFFSET, - .disable = _clk_disable, - .secondary = &emma_clk[1], - }, { - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_EMMA_REG, - .enable_shift = CCM_PCCR_HCLK_EMMA_OFFSET, - .disable = _clk_disable, - } -}; - -static struct clk slcdc_clk[] = { - { - .parent = &hclk_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_SLCDC_REG, - .enable_shift = CCM_PCCR_SLCDC_OFFSET, - .disable = _clk_disable, - .secondary = &slcdc_clk[1], - }, { - .enable = _clk_enable, - .enable_reg = CCM_PCCR_HCLK_SLCDC_REG, - .enable_shift = CCM_PCCR_HCLK_SLCDC_OFFSET, - .disable = _clk_disable, - } -}; - -static struct clk wdog_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_WDT_REG, - .enable_shift = CCM_PCCR_WDT_OFFSET, - .disable = _clk_disable, -}; - -static struct clk gpio_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_GPIO_REG, - .enable_shift = CCM_PCCR_GPIO_OFFSET, - .disable = _clk_disable, -}; - -static struct clk i2c_clk = { - .id = 0, - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_I2C1_REG, - .enable_shift = CCM_PCCR_I2C1_OFFSET, - .disable = _clk_disable, -}; - -static struct clk kpp_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_KPP_REG, - .enable_shift = CCM_PCCR_KPP_OFFSET, - .disable = _clk_disable, -}; - -static struct clk owire_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_OWIRE_REG, - .enable_shift = CCM_PCCR_OWIRE_OFFSET, - .disable = _clk_disable, -}; - -static struct clk rtc_clk = { - .parent = &ipg_clk, - .enable = _clk_enable, - .enable_reg = CCM_PCCR_RTC_REG, - .enable_shift = CCM_PCCR_RTC_OFFSET, - .disable = _clk_disable, -}; - -static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate) -{ - return _clk_generic_round_rate(clk, rate, 8); -} - -static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = __raw_readl(CCM_PCDR0); - - if (clk->parent == &usb_clk[0]) { - reg &= ~CCM_PCDR0_48MDIV_MASK; - reg |= div << CCM_PCDR0_48MDIV_OFFSET; - } - __raw_writel(reg, CCM_PCDR0); - - return 0; -} - -static unsigned long _clk_clko_recalc(struct clk *clk) -{ - u32 div = 0; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->parent == &usb_clk[0]) /* 48M */ - div = __raw_readl(CCM_PCDR0) & CCM_PCDR0_48MDIV_MASK - >> CCM_PCDR0_48MDIV_OFFSET; - div++; - - return parent_rate / div; -} - -static struct clk clko_clk; - -static int _clk_clko_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(CCM_CCSR) & ~CCM_CCSR_CLKOSEL_MASK; - - if (parent == &ckil_clk) - reg |= 0 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &fpm_clk) - reg |= 1 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ckih_clk) - reg |= 2 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == mpll_clk.parent) - reg |= 3 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == spll_clk.parent) - reg |= 4 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &mpll_clk) - reg |= 5 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &spll_clk) - reg |= 6 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &fclk_clk) - reg |= 7 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &hclk_clk) - reg |= 8 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ipg_clk) - reg |= 9 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[0]) - reg |= 0xA << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[1]) - reg |= 0xB << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[2]) - reg |= 0xC << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &per_clk[3]) - reg |= 0xD << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ssi_clk[0]) - reg |= 0xE << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &ssi_clk[1]) - reg |= 0xF << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &nfc_clk) - reg |= 0x10 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &usb_clk[0]) - reg |= 0x14 << CCM_CCSR_CLKOSEL_OFFSET; - else if (parent == &clko_clk) - reg |= 0x15 << CCM_CCSR_CLKOSEL_OFFSET; - else - return -EINVAL; - - __raw_writel(reg, CCM_CCSR); - - return 0; -} - -static struct clk clko_clk = { - .get_rate = _clk_clko_recalc, - .set_rate = _clk_clko_set_rate, - .round_rate = _clk_clko_round_rate, - .set_parent = _clk_clko_set_parent, -}; - - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, -static struct clk_lookup lookups[] = { -/* It's unlikely that any driver wants one of them directly: - _REGISTER_CLOCK(NULL, "ckih", ckih_clk) - _REGISTER_CLOCK(NULL, "ckil", ckil_clk) - _REGISTER_CLOCK(NULL, "fpm", fpm_clk) - _REGISTER_CLOCK(NULL, "mpll", mpll_clk) - _REGISTER_CLOCK(NULL, "spll", spll_clk) - _REGISTER_CLOCK(NULL, "fclk", fclk_clk) - _REGISTER_CLOCK(NULL, "hclk", hclk_clk) - _REGISTER_CLOCK(NULL, "ipg", ipg_clk) -*/ - _REGISTER_CLOCK(NULL, "perclk1", per_clk[0]) - _REGISTER_CLOCK(NULL, "perclk2", per_clk[1]) - _REGISTER_CLOCK(NULL, "perclk3", per_clk[2]) - _REGISTER_CLOCK(NULL, "perclk4", per_clk[3]) - _REGISTER_CLOCK(NULL, "clko", clko_clk) - _REGISTER_CLOCK("imx21-uart.0", NULL, uart_clk[0]) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart_clk[1]) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart_clk[2]) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart_clk[3]) - _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0]) - _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1]) - _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2]) - _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0]) - _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0]) - _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1]) - _REGISTER_CLOCK("imx21-cspi.0", NULL, cspi_clk[0]) - _REGISTER_CLOCK("imx21-cspi.1", NULL, cspi_clk[1]) - _REGISTER_CLOCK("imx21-cspi.2", NULL, cspi_clk[2]) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0]) - _REGISTER_CLOCK(NULL, "csi", csi_clk[0]) - _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0]) - _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0]) - _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1]) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - _REGISTER_CLOCK(NULL, "dma", dma_clk[0]) - _REGISTER_CLOCK(NULL, "brom", brom_clk) - _REGISTER_CLOCK(NULL, "emma", emma_clk[0]) - _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk[0]) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) - _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk) - _REGISTER_CLOCK(NULL, "owire", owire_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) -}; - -/* - * must be called very early to get information about the - * available clock rate when the timer framework starts - */ -int __init mx21_clocks_init(unsigned long lref, unsigned long href) -{ - u32 cscr; - - external_low_reference = lref; - external_high_reference = href; - - /* detect clock reference for both system PLL */ - cscr = CSCR(); - if (cscr & CCM_CSCR_MCU) - mpll_clk.parent = &ckih_clk; - else - mpll_clk.parent = &fpm_clk; - - if (cscr & CCM_CSCR_SP) - spll_clk.parent = &ckih_clk; - else - spll_clk.parent = &fpm_clk; - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clock gates */ - __raw_writel(0, CCM_PCCR0); - __raw_writel(CCM_PCCR_GPT1_MASK, CCM_PCCR1); - - /* This turns of the serial PLL as well */ - spll_clk.disable(&spll_clk); - - /* This will propagate to all children and init all the clock rates. */ - clk_enable(&per_clk[0]); - clk_enable(&gpio_clk); - -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - clk_enable(&uart_clk[0]); -#endif - - mxc_timer_init(&gpt_clk[0], MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), - MX21_INT_GPT1); - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx25.c b/arch/arm/mach-imx/clock-imx25.c deleted file mode 100644 index b0fec74c8c91..000000000000 --- a/arch/arm/mach-imx/clock-imx25.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (C) 2009 by Sascha Hauer, Pengutronix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> -#include <mach/mx25.h> - -#define CRM_BASE MX25_IO_ADDRESS(MX25_CRM_BASE_ADDR) - -#define CCM_MPCTL 0x00 -#define CCM_UPCTL 0x04 -#define CCM_CCTL 0x08 -#define CCM_CGCR0 0x0C -#define CCM_CGCR1 0x10 -#define CCM_CGCR2 0x14 -#define CCM_PCDR0 0x18 -#define CCM_PCDR1 0x1C -#define CCM_PCDR2 0x20 -#define CCM_PCDR3 0x24 -#define CCM_RCSR 0x28 -#define CCM_CRDR 0x2C -#define CCM_DCVR0 0x30 -#define CCM_DCVR1 0x34 -#define CCM_DCVR2 0x38 -#define CCM_DCVR3 0x3c -#define CCM_LTR0 0x40 -#define CCM_LTR1 0x44 -#define CCM_LTR2 0x48 -#define CCM_LTR3 0x4c - -static unsigned long get_rate_mpll(void) -{ - ulong mpctl = __raw_readl(CRM_BASE + CCM_MPCTL); - - return mxc_decode_pll(mpctl, 24000000); -} - -static unsigned long get_rate_upll(void) -{ - ulong mpctl = __raw_readl(CRM_BASE + CCM_UPCTL); - - return mxc_decode_pll(mpctl, 24000000); -} - -unsigned long get_rate_arm(struct clk *clk) -{ - unsigned long cctl = readl(CRM_BASE + CCM_CCTL); - unsigned long rate = get_rate_mpll(); - - if (cctl & (1 << 14)) - rate = (rate * 3) >> 2; - - return rate / ((cctl >> 30) + 1); -} - -static unsigned long get_rate_ahb(struct clk *clk) -{ - unsigned long cctl = readl(CRM_BASE + CCM_CCTL); - - return get_rate_arm(NULL) / (((cctl >> 28) & 0x3) + 1); -} - -static unsigned long get_rate_ipg(struct clk *clk) -{ - return get_rate_ahb(NULL) >> 1; -} - -static unsigned long get_rate_per(int per) -{ - unsigned long ofs = (per & 0x3) * 8; - unsigned long reg = per & ~0x3; - unsigned long val = (readl(CRM_BASE + CCM_PCDR0 + reg) >> ofs) & 0x3f; - unsigned long fref; - - if (readl(CRM_BASE + 0x64) & (1 << per)) - fref = get_rate_upll(); - else - fref = get_rate_ahb(NULL); - - return fref / (val + 1); -} - -static unsigned long get_rate_uart(struct clk *clk) -{ - return get_rate_per(15); -} - -static unsigned long get_rate_ssi2(struct clk *clk) -{ - return get_rate_per(14); -} - -static unsigned long get_rate_ssi1(struct clk *clk) -{ - return get_rate_per(13); -} - -static unsigned long get_rate_i2c(struct clk *clk) -{ - return get_rate_per(6); -} - -static unsigned long get_rate_nfc(struct clk *clk) -{ - return get_rate_per(8); -} - -static unsigned long get_rate_gpt(struct clk *clk) -{ - return get_rate_per(5); -} - -static unsigned long get_rate_lcdc(struct clk *clk) -{ - return get_rate_per(7); -} - -static unsigned long get_rate_esdhc1(struct clk *clk) -{ - return get_rate_per(3); -} - -static unsigned long get_rate_esdhc2(struct clk *clk) -{ - return get_rate_per(4); -} - -static unsigned long get_rate_csi(struct clk *clk) -{ - return get_rate_per(0); -} - -static unsigned long get_rate_otg(struct clk *clk) -{ - unsigned long cctl = readl(CRM_BASE + CCM_CCTL); - unsigned long rate = get_rate_upll(); - - return (cctl & (1 << 23)) ? 0 : rate / ((0x3F & (cctl >> 16)) + 1); -} - -static int clk_cgcr_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void clk_cgcr_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -#define DEFINE_CLOCK(name, i, er, es, gr, sr, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = CRM_BASE + er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = clk_cgcr_enable, \ - .disable = clk_cgcr_disable, \ - .secondary = s, \ - } - -/* - * Note: the following IPG clock gating bits are wrongly marked "Reserved" in - * the i.MX25 Reference Manual Rev 1, table 15-13. The information below is - * taken from the Freescale released BSP. - * - * bit reg offset clock - * - * 0 CGCR1 0 AUDMUX - * 12 CGCR1 12 ESAI - * 16 CGCR1 16 GPIO1 - * 17 CGCR1 17 GPIO2 - * 18 CGCR1 18 GPIO3 - * 23 CGCR1 23 I2C1 - * 24 CGCR1 24 I2C2 - * 25 CGCR1 25 I2C3 - * 27 CGCR1 27 IOMUXC - * 28 CGCR1 28 KPP - * 30 CGCR1 30 OWIRE - * 36 CGCR2 4 RTIC - * 51 CGCR2 19 WDOG - */ - -DEFINE_CLOCK(gpt_clk, 0, CCM_CGCR0, 5, get_rate_gpt, NULL, NULL); -DEFINE_CLOCK(uart_per_clk, 0, CCM_CGCR0, 15, get_rate_uart, NULL, NULL); -DEFINE_CLOCK(ssi1_per_clk, 0, CCM_CGCR0, 13, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(ssi2_per_clk, 0, CCM_CGCR0, 14, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(cspi1_clk, 0, CCM_CGCR1, 5, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(cspi2_clk, 0, CCM_CGCR1, 6, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(cspi3_clk, 0, CCM_CGCR1, 7, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(esdhc1_ahb_clk, 0, CCM_CGCR0, 21, get_rate_esdhc1, NULL, NULL); -DEFINE_CLOCK(esdhc1_per_clk, 0, CCM_CGCR0, 3, get_rate_esdhc1, NULL, - &esdhc1_ahb_clk); -DEFINE_CLOCK(esdhc2_ahb_clk, 0, CCM_CGCR0, 22, get_rate_esdhc2, NULL, NULL); -DEFINE_CLOCK(esdhc2_per_clk, 0, CCM_CGCR0, 4, get_rate_esdhc2, NULL, - &esdhc2_ahb_clk); -DEFINE_CLOCK(sdma_ahb_clk, 0, CCM_CGCR0, 26, NULL, NULL, NULL); -DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL, NULL, NULL); -DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL, NULL, NULL); -DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0, 7, NULL, NULL, &lcdc_ahb_clk); -DEFINE_CLOCK(csi_ahb_clk, 0, CCM_CGCR0, 18, get_rate_csi, NULL, NULL); -DEFINE_CLOCK(csi_per_clk, 0, CCM_CGCR0, 0, get_rate_csi, NULL, &csi_ahb_clk); -DEFINE_CLOCK(uart1_clk, 0, CCM_CGCR2, 14, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart2_clk, 0, CCM_CGCR2, 15, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart3_clk, 0, CCM_CGCR2, 16, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart4_clk, 0, CCM_CGCR2, 17, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(uart5_clk, 0, CCM_CGCR2, 18, get_rate_uart, NULL, &uart_per_clk); -DEFINE_CLOCK(nfc_clk, 0, CCM_CGCR0, 8, get_rate_nfc, NULL, NULL); -DEFINE_CLOCK(usbotg_clk, 0, CCM_CGCR0, 28, get_rate_otg, NULL, NULL); -DEFINE_CLOCK(pwm1_clk, 0, CCM_CGCR1, 31, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(pwm2_clk, 0, CCM_CGCR2, 0, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(pwm3_clk, 0, CCM_CGCR2, 1, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(pwm4_clk, 0, CCM_CGCR2, 2, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(kpp_clk, 0, CCM_CGCR1, 28, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(tsc_clk, 0, CCM_CGCR2, 13, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(i2c_clk, 0, CCM_CGCR0, 6, get_rate_i2c, NULL, NULL); -DEFINE_CLOCK(fec_clk, 0, CCM_CGCR1, 15, get_rate_ipg, NULL, &fec_ahb_clk); -DEFINE_CLOCK(dryice_clk, 0, CCM_CGCR1, 8, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(lcdc_clk, 0, CCM_CGCR1, 29, get_rate_lcdc, NULL, &lcdc_per_clk); -DEFINE_CLOCK(wdt_clk, 0, CCM_CGCR2, 19, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(ssi1_clk, 0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk); -DEFINE_CLOCK(ssi2_clk, 1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk); -DEFINE_CLOCK(sdma_clk, 0, CCM_CGCR2, 6, get_rate_ipg, NULL, &sdma_ahb_clk); -DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGCR1, 13, get_rate_esdhc1, NULL, - &esdhc1_per_clk); -DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGCR1, 14, get_rate_esdhc2, NULL, - &esdhc2_per_clk); -DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL); -DEFINE_CLOCK(csi_clk, 0, CCM_CGCR1, 4, get_rate_csi, NULL, &csi_per_clk); -DEFINE_CLOCK(can1_clk, 0, CCM_CGCR1, 2, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(can2_clk, 1, CCM_CGCR1, 3, get_rate_ipg, NULL, NULL); -DEFINE_CLOCK(iim_clk, 0, CCM_CGCR1, 26, NULL, NULL, NULL); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* i.mx25 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - /* i.mx25 has the i.mx35 type cspi */ - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK("imx35-cspi.2", NULL, cspi3_clk) - _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk) - _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk) - _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk) - _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm4_clk) - _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk) - _REGISTER_CLOCK("mx25-adc", NULL, tsc_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk) - _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk) - _REGISTER_CLOCK("imxdi_rtc.0", NULL, dryice_clk) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdt_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx25.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx25.1", NULL, esdhc2_clk) - _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk) - _REGISTER_CLOCK(NULL, "audmux", audmux_clk) - _REGISTER_CLOCK("flexcan.0", NULL, can1_clk) - _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) - /* i.mx25 has the i.mx35 type sdma */ - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) -}; - -int __init mx25_clocks_init(void) -{ - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clocks except the ones we need to survive, namely: - * EMI, GPIO1-3 (CCM_CGCR1[18:16]), GPT1, IOMUXC (CCM_CGCR1[27]), IIM, - * SCC - */ - __raw_writel((1 << 19), CRM_BASE + CCM_CGCR0); - __raw_writel((0xf << 16) | (3 << 26), CRM_BASE + CCM_CGCR1); - __raw_writel((1 << 5), CRM_BASE + CCM_CGCR2); -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - clk_enable(&uart1_clk); -#endif - - /* Clock source for lcdc and csi is upll */ - __raw_writel(__raw_readl(CRM_BASE+0x64) | (1 << 7) | (1 << 0), - CRM_BASE + 0x64); - - /* Clock source for gpt is ahb_div */ - __raw_writel(__raw_readl(CRM_BASE+0x64) & ~(1 << 5), CRM_BASE + 0x64); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX25", mx25_revision()); - clk_disable(&iim_clk); - - mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx27.c b/arch/arm/mach-imx/clock-imx27.c deleted file mode 100644 index 98e04f5a87dd..000000000000 --- a/arch/arm/mach-imx/clock-imx27.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/clkdev.h> -#include <linux/of.h> - -#include <asm/div64.h> - -#include <mach/clock.h> -#include <mach/common.h> -#include <mach/hardware.h> - -#define IO_ADDR_CCM(off) (MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR + (off))) - -/* Register offsets */ -#define CCM_CSCR IO_ADDR_CCM(0x0) -#define CCM_MPCTL0 IO_ADDR_CCM(0x4) -#define CCM_MPCTL1 IO_ADDR_CCM(0x8) -#define CCM_SPCTL0 IO_ADDR_CCM(0xc) -#define CCM_SPCTL1 IO_ADDR_CCM(0x10) -#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) -#define CCM_PCDR0 IO_ADDR_CCM(0x18) -#define CCM_PCDR1 IO_ADDR_CCM(0x1c) -#define CCM_PCCR0 IO_ADDR_CCM(0x20) -#define CCM_PCCR1 IO_ADDR_CCM(0x24) -#define CCM_CCSR IO_ADDR_CCM(0x28) -#define CCM_PMCTL IO_ADDR_CCM(0x2c) -#define CCM_PMCOUNT IO_ADDR_CCM(0x30) -#define CCM_WKGDCTL IO_ADDR_CCM(0x34) - -#define CCM_CSCR_UPDATE_DIS (1 << 31) -#define CCM_CSCR_SSI2 (1 << 23) -#define CCM_CSCR_SSI1 (1 << 22) -#define CCM_CSCR_VPU (1 << 21) -#define CCM_CSCR_MSHC (1 << 20) -#define CCM_CSCR_SPLLRES (1 << 19) -#define CCM_CSCR_MPLLRES (1 << 18) -#define CCM_CSCR_SP (1 << 17) -#define CCM_CSCR_MCU (1 << 16) -#define CCM_CSCR_OSC26MDIV (1 << 4) -#define CCM_CSCR_OSC26M (1 << 3) -#define CCM_CSCR_FPM (1 << 2) -#define CCM_CSCR_SPEN (1 << 1) -#define CCM_CSCR_MPEN (1 << 0) - -/* i.MX27 TO 2+ */ -#define CCM_CSCR_ARM_SRC (1 << 15) - -#define CCM_SPCTL1_LF (1 << 15) -#define CCM_SPCTL1_BRMO (1 << 6) - -static struct clk mpll_main1_clk, mpll_main2_clk; - -static int clk_pccr_enable(struct clk *clk) -{ - unsigned long reg; - - if (!clk->enable_reg) - return 0; - - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void clk_pccr_disable(struct clk *clk) -{ - unsigned long reg; - - if (!clk->enable_reg) - return; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -static int clk_spll_enable(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(CCM_CSCR); - reg |= CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); - - while (!(__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF)); - - return 0; -} - -static void clk_spll_disable(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(CCM_CSCR); - reg &= ~CCM_CSCR_SPEN; - __raw_writel(reg, CCM_CSCR); -} - -static int clk_cpu_set_parent(struct clk *clk, struct clk *parent) -{ - int cscr = __raw_readl(CCM_CSCR); - - if (clk->parent == parent) - return 0; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - if (parent == &mpll_main1_clk) { - cscr |= CCM_CSCR_ARM_SRC; - } else { - if (parent == &mpll_main2_clk) - cscr &= ~CCM_CSCR_ARM_SRC; - else - return -EINVAL; - } - __raw_writel(cscr, CCM_CSCR); - clk->parent = parent; - return 0; - } - return -ENODEV; -} - -static unsigned long round_rate_cpu(struct clk *clk, unsigned long rate) -{ - int div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > 4) - div = 4; - - return parent_rate / div; -} - -static int set_rate_cpu(struct clk *clk, unsigned long rate) -{ - unsigned int div; - uint32_t reg; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - - if (div > 4 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - div--; - - reg = __raw_readl(CCM_CSCR); - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - reg &= ~(3 << 12); - reg |= div << 12; - reg &= ~(CCM_CSCR_FPM | CCM_CSCR_SPEN); - __raw_writel(reg | CCM_CSCR_UPDATE_DIS, CCM_CSCR); - } else { - printk(KERN_ERR "Can't set CPU frequency!\n"); - } - - return 0; -} - -static unsigned long round_rate_per(struct clk *clk, unsigned long rate) -{ - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (parent_rate % rate) - div++; - - if (div > 64) - div = 64; - - return parent_rate / div; -} - -static int set_rate_per(struct clk *clk, unsigned long rate) -{ - u32 reg; - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return -EINVAL; - - div = parent_rate / rate; - if (div > 64 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - div--; - - reg = __raw_readl(CCM_PCDR1) & ~(0x3f << (clk->id << 3)); - reg |= div << (clk->id << 3); - __raw_writel(reg, CCM_PCDR1); - - return 0; -} - -static unsigned long get_rate_usb(struct clk *clk) -{ - unsigned long usb_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - usb_pdf = (__raw_readl(CCM_CSCR) >> 28) & 0x7; - - return parent_rate / (usb_pdf + 1U); -} - -static unsigned long get_rate_ssix(struct clk *clk, unsigned long pdf) -{ - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - pdf += 4; /* MX27 TO2+ */ - else - pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */ - - return 2UL * parent_rate / pdf; -} - -static unsigned long get_rate_ssi1(struct clk *clk) -{ - return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 16) & 0x3f); -} - -static unsigned long get_rate_ssi2(struct clk *clk) -{ - return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 26) & 0x3f); -} - -static unsigned long get_rate_nfc(struct clk *clk) -{ - unsigned long nfc_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - nfc_pdf = (__raw_readl(CCM_PCDR0) >> 6) & 0xf; - else - nfc_pdf = (__raw_readl(CCM_PCDR0) >> 12) & 0xf; - - return parent_rate / (nfc_pdf + 1); -} - -static unsigned long get_rate_vpu(struct clk *clk) -{ - unsigned long vpu_pdf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - vpu_pdf = (__raw_readl(CCM_PCDR0) >> 10) & 0x3f; - vpu_pdf += 4; - } else { - vpu_pdf = (__raw_readl(CCM_PCDR0) >> 8) & 0xf; - vpu_pdf = (vpu_pdf < 2) ? 124 : vpu_pdf; - } - - return 2UL * parent_rate / vpu_pdf; -} - -static unsigned long round_rate_parent(struct clk *clk, unsigned long rate) -{ - return clk->parent->round_rate(clk->parent, rate); -} - -static unsigned long get_rate_parent(struct clk *clk) -{ - return clk_get_rate(clk->parent); -} - -static int set_rate_parent(struct clk *clk, unsigned long rate) -{ - return clk->parent->set_rate(clk->parent, rate); -} - -/* in Hz */ -static unsigned long external_high_reference = 26000000; - -static unsigned long get_rate_high_reference(struct clk *clk) -{ - return external_high_reference; -} - -/* in Hz */ -static unsigned long external_low_reference = 32768; - -static unsigned long get_rate_low_reference(struct clk *clk) -{ - return external_low_reference; -} - -static unsigned long get_rate_fpm(struct clk *clk) -{ - return clk_get_rate(clk->parent) * 1024; -} - -static unsigned long get_rate_mpll(struct clk *clk) -{ - return mxc_decode_pll(__raw_readl(CCM_MPCTL0), - clk_get_rate(clk->parent)); -} - -static unsigned long get_rate_mpll_main(struct clk *clk) -{ - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - /* i.MX27 TO2: - * clk->id == 0: arm clock source path 1 which is from 2 * MPLL / 2 - * clk->id == 1: arm clock source path 2 which is from 2 * MPLL / 3 - */ - if (mx27_revision() >= IMX_CHIP_REVISION_2_0 && clk->id == 1) - return 2UL * parent_rate / 3UL; - - return parent_rate; -} - -static unsigned long get_rate_spll(struct clk *clk) -{ - uint32_t reg; - unsigned long rate; - - rate = clk_get_rate(clk->parent); - - reg = __raw_readl(CCM_SPCTL0); - - /* On TO2 we have to write the value back. Otherwise we - * read 0 from this register the next time. - */ - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - __raw_writel(reg, CCM_SPCTL0); - - return mxc_decode_pll(reg, rate); -} - -static unsigned long get_rate_cpu(struct clk *clk) -{ - u32 div; - unsigned long rate; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - div = (__raw_readl(CCM_CSCR) >> 12) & 0x3; - else - div = (__raw_readl(CCM_CSCR) >> 13) & 0x7; - - rate = clk_get_rate(clk->parent); - return rate / (div + 1); -} - -static unsigned long get_rate_ahb(struct clk *clk) -{ - unsigned long rate, bclk_pdf; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - bclk_pdf = (__raw_readl(CCM_CSCR) >> 8) & 0x3; - else - bclk_pdf = (__raw_readl(CCM_CSCR) >> 9) & 0xf; - - rate = clk_get_rate(clk->parent); - return rate / (bclk_pdf + 1); -} - -static unsigned long get_rate_ipg(struct clk *clk) -{ - unsigned long rate, ipg_pdf; - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) - return clk_get_rate(clk->parent); - else - ipg_pdf = (__raw_readl(CCM_CSCR) >> 8) & 1; - - rate = clk_get_rate(clk->parent); - return rate / (ipg_pdf + 1); -} - -static unsigned long get_rate_per(struct clk *clk) -{ - unsigned long perclk_pdf, parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->id < 0 || clk->id > 3) - return 0; - - perclk_pdf = (__raw_readl(CCM_PCDR1) >> (clk->id << 3)) & 0x3f; - - return parent_rate / (perclk_pdf + 1); -} - -/* - * the high frequency external clock reference - * Default case is 26MHz. Could be changed at runtime - * with a call to change_external_high_reference() - */ -static struct clk ckih_clk = { - .get_rate = get_rate_high_reference, -}; - -static struct clk mpll_clk = { - .parent = &ckih_clk, - .get_rate = get_rate_mpll, -}; - -/* For i.MX27 TO2, it is the MPLL path 1 of ARM core - * It provides the clock source whose rate is same as MPLL - */ -static struct clk mpll_main1_clk = { - .id = 0, - .parent = &mpll_clk, - .get_rate = get_rate_mpll_main, -}; - -/* For i.MX27 TO2, it is the MPLL path 2 of ARM core - * It provides the clock source whose rate is same MPLL * 2 / 3 - */ -static struct clk mpll_main2_clk = { - .id = 1, - .parent = &mpll_clk, - .get_rate = get_rate_mpll_main, -}; - -static struct clk ahb_clk = { - .parent = &mpll_main2_clk, - .get_rate = get_rate_ahb, -}; - -static struct clk ipg_clk = { - .parent = &ahb_clk, - .get_rate = get_rate_ipg, -}; - -static struct clk cpu_clk = { - .parent = &mpll_main2_clk, - .set_parent = clk_cpu_set_parent, - .round_rate = round_rate_cpu, - .get_rate = get_rate_cpu, - .set_rate = set_rate_cpu, -}; - -static struct clk spll_clk = { - .parent = &ckih_clk, - .get_rate = get_rate_spll, - .enable = clk_spll_enable, - .disable = clk_spll_disable, -}; - -/* - * the low frequency external clock reference - * Default case is 32.768kHz. - */ -static struct clk ckil_clk = { - .get_rate = get_rate_low_reference, -}; - -/* Output of frequency pre multiplier */ -static struct clk fpm_clk = { - .parent = &ckil_clk, - .get_rate = get_rate_fpm, -}; - -#define PCCR0 CCM_PCCR0 -#define PCCR1 CCM_PCCR1 - -#define DEFINE_CLOCK(name, i, er, es, gr, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .enable = clk_pccr_enable, \ - .disable = clk_pccr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = get_rate_##getsetround, \ - .set_rate = set_rate_##getsetround, \ - .round_rate = round_rate_##getsetround, \ - .enable = clk_pccr_enable, \ - .disable = clk_pccr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -/* Forward declaration to keep the following list in order */ -static struct clk slcdc_clk1, sahara2_clk1, rtic_clk1, fec_clk1, emma_clk1, - dma_clk1, lcdc_clk2, vpu_clk1; - -/* All clocks we can gate through PCCRx in the order of PCCRx bits */ -DEFINE_CLOCK(ssi2_clk1, 1, PCCR0, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ssi1_clk1, 0, PCCR0, 1, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(slcdc_clk, 0, PCCR0, 2, NULL, &slcdc_clk1, &ahb_clk); -DEFINE_CLOCK(sdhc3_clk1, 0, PCCR0, 3, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sdhc2_clk1, 0, PCCR0, 4, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sdhc1_clk1, 0, PCCR0, 5, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(scc_clk, 0, PCCR0, 6, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sahara2_clk, 0, PCCR0, 7, NULL, &sahara2_clk1, &ahb_clk); -DEFINE_CLOCK(rtic_clk, 0, PCCR0, 8, NULL, &rtic_clk1, &ahb_clk); -DEFINE_CLOCK(rtc_clk, 0, PCCR0, 9, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(pwm_clk1, 0, PCCR0, 11, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(owire_clk, 0, PCCR0, 12, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(mstick_clk1, 0, PCCR0, 13, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(lcdc_clk1, 0, PCCR0, 14, NULL, &lcdc_clk2, &ipg_clk); -DEFINE_CLOCK(kpp_clk, 0, PCCR0, 15, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(iim_clk, 0, PCCR0, 16, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(i2c2_clk, 1, PCCR0, 17, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(i2c1_clk, 0, PCCR0, 18, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt6_clk1, 0, PCCR0, 29, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt5_clk1, 0, PCCR0, 20, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt4_clk1, 0, PCCR0, 21, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt3_clk1, 0, PCCR0, 22, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt2_clk1, 0, PCCR0, 23, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpt1_clk1, 0, PCCR0, 24, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(gpio_clk, 0, PCCR0, 25, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(fec_clk, 0, PCCR0, 26, NULL, &fec_clk1, &ahb_clk); -DEFINE_CLOCK(emma_clk, 0, PCCR0, 27, NULL, &emma_clk1, &ahb_clk); -DEFINE_CLOCK(dma_clk, 0, PCCR0, 28, NULL, &dma_clk1, &ahb_clk); -DEFINE_CLOCK(cspi13_clk1, 0, PCCR0, 29, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(cspi2_clk1, 0, PCCR0, 30, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(cspi1_clk1, 0, PCCR0, 31, NULL, NULL, &ipg_clk); - -DEFINE_CLOCK(mstick_clk, 0, PCCR1, 2, NULL, &mstick_clk1, &ipg_clk); -DEFINE_CLOCK(nfc_clk, 0, PCCR1, 3, get_rate_nfc, NULL, &cpu_clk); -DEFINE_CLOCK(ssi2_clk, 1, PCCR1, 4, get_rate_ssi2, &ssi2_clk1, &mpll_main2_clk); -DEFINE_CLOCK(ssi1_clk, 0, PCCR1, 5, get_rate_ssi1, &ssi1_clk1, &mpll_main2_clk); -DEFINE_CLOCK(vpu_clk, 0, PCCR1, 6, get_rate_vpu, &vpu_clk1, &mpll_main2_clk); -DEFINE_CLOCK1(per4_clk, 3, PCCR1, 7, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK1(per3_clk, 2, PCCR1, 8, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK1(per2_clk, 1, PCCR1, 9, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK1(per1_clk, 0, PCCR1, 10, per, NULL, &mpll_main2_clk); -DEFINE_CLOCK(usb_clk1, 0, PCCR1, 11, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(slcdc_clk1, 0, PCCR1, 12, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(sahara2_clk1, 0, PCCR1, 13, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(rtic_clk1, 0, PCCR1, 14, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(lcdc_clk2, 0, PCCR1, 15, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(vpu_clk1, 0, PCCR1, 16, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(fec_clk1, 0, PCCR1, 17, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(emma_clk1, 0, PCCR1, 18, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(emi_clk, 0, PCCR1, 19, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(dma_clk1, 0, PCCR1, 20, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(csi_clk1, 0, PCCR1, 21, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(brom_clk, 0, PCCR1, 22, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(pata_clk, 0, PCCR1, 23, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(wdog_clk, 0, PCCR1, 24, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(usb_clk, 0, PCCR1, 25, get_rate_usb, &usb_clk1, &spll_clk); -DEFINE_CLOCK(uart6_clk1, 0, PCCR1, 26, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart5_clk1, 0, PCCR1, 27, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart4_clk1, 0, PCCR1, 28, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart3_clk1, 0, PCCR1, 29, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart2_clk1, 0, PCCR1, 30, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart1_clk1, 0, PCCR1, 31, NULL, NULL, &ipg_clk); - -/* Clocks we cannot directly gate, but drivers need their rates */ -DEFINE_CLOCK(cspi1_clk, 0, NULL, 0, NULL, &cspi1_clk1, &per2_clk); -DEFINE_CLOCK(cspi2_clk, 1, NULL, 0, NULL, &cspi2_clk1, &per2_clk); -DEFINE_CLOCK(cspi3_clk, 2, NULL, 0, NULL, &cspi13_clk1, &per2_clk); -DEFINE_CLOCK(sdhc1_clk, 0, NULL, 0, NULL, &sdhc1_clk1, &per2_clk); -DEFINE_CLOCK(sdhc2_clk, 1, NULL, 0, NULL, &sdhc2_clk1, &per2_clk); -DEFINE_CLOCK(sdhc3_clk, 2, NULL, 0, NULL, &sdhc3_clk1, &per2_clk); -DEFINE_CLOCK(pwm_clk, 0, NULL, 0, NULL, &pwm_clk1, &per1_clk); -DEFINE_CLOCK(gpt1_clk, 0, NULL, 0, NULL, &gpt1_clk1, &per1_clk); -DEFINE_CLOCK(gpt2_clk, 1, NULL, 0, NULL, &gpt2_clk1, &per1_clk); -DEFINE_CLOCK(gpt3_clk, 2, NULL, 0, NULL, &gpt3_clk1, &per1_clk); -DEFINE_CLOCK(gpt4_clk, 3, NULL, 0, NULL, &gpt4_clk1, &per1_clk); -DEFINE_CLOCK(gpt5_clk, 4, NULL, 0, NULL, &gpt5_clk1, &per1_clk); -DEFINE_CLOCK(gpt6_clk, 5, NULL, 0, NULL, &gpt6_clk1, &per1_clk); -DEFINE_CLOCK(uart1_clk, 0, NULL, 0, NULL, &uart1_clk1, &per1_clk); -DEFINE_CLOCK(uart2_clk, 1, NULL, 0, NULL, &uart2_clk1, &per1_clk); -DEFINE_CLOCK(uart3_clk, 2, NULL, 0, NULL, &uart3_clk1, &per1_clk); -DEFINE_CLOCK(uart4_clk, 3, NULL, 0, NULL, &uart4_clk1, &per1_clk); -DEFINE_CLOCK(uart5_clk, 4, NULL, 0, NULL, &uart5_clk1, &per1_clk); -DEFINE_CLOCK(uart6_clk, 5, NULL, 0, NULL, &uart6_clk1, &per1_clk); -DEFINE_CLOCK1(lcdc_clk, 0, NULL, 0, parent, &lcdc_clk1, &per3_clk); -DEFINE_CLOCK1(csi_clk, 0, NULL, 0, parent, &csi_clk1, &per4_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* i.mx27 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK("imx21-uart.5", NULL, uart6_clk) - _REGISTER_CLOCK(NULL, "gpt1", gpt1_clk) - _REGISTER_CLOCK(NULL, "gpt2", gpt2_clk) - _REGISTER_CLOCK(NULL, "gpt3", gpt3_clk) - _REGISTER_CLOCK(NULL, "gpt4", gpt4_clk) - _REGISTER_CLOCK(NULL, "gpt5", gpt5_clk) - _REGISTER_CLOCK(NULL, "gpt6", gpt6_clk) - _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm_clk) - _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk) - _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk) - _REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk) - _REGISTER_CLOCK("imx27-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx27-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK("imx27-cspi.2", NULL, cspi3_clk) - _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) - _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk1) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - _REGISTER_CLOCK(NULL, "vpu", vpu_clk) - _REGISTER_CLOCK(NULL, "dma", dma_clk) - _REGISTER_CLOCK(NULL, "rtic", rtic_clk) - _REGISTER_CLOCK(NULL, "brom", brom_clk) - _REGISTER_CLOCK(NULL, "emma", emma_clk) - _REGISTER_CLOCK("m2m-emmaprp.0", NULL, emma_clk) - _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk) - _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk) - _REGISTER_CLOCK(NULL, "emi", emi_clk) - _REGISTER_CLOCK(NULL, "sahara2", sahara2_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK(NULL, "mstick", mstick_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) - _REGISTER_CLOCK(NULL, "kpp", kpp_clk) - _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) - _REGISTER_CLOCK(NULL, "scc", scc_clk) -}; - -/* Adjust the clock path for TO2 and later */ -static void __init to2_adjust_clocks(void) -{ - unsigned long cscr = __raw_readl(CCM_CSCR); - - if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { - if (cscr & CCM_CSCR_ARM_SRC) - cpu_clk.parent = &mpll_main1_clk; - - if (!(cscr & CCM_CSCR_SSI2)) - ssi1_clk.parent = &spll_clk; - - if (!(cscr & CCM_CSCR_SSI1)) - ssi1_clk.parent = &spll_clk; - - if (!(cscr & CCM_CSCR_VPU)) - vpu_clk.parent = &spll_clk; - } else { - cpu_clk.parent = &mpll_clk; - cpu_clk.set_parent = NULL; - cpu_clk.round_rate = NULL; - cpu_clk.set_rate = NULL; - ahb_clk.parent = &mpll_clk; - - per1_clk.parent = &mpll_clk; - per2_clk.parent = &mpll_clk; - per3_clk.parent = &mpll_clk; - per4_clk.parent = &mpll_clk; - - ssi1_clk.parent = &mpll_clk; - ssi2_clk.parent = &mpll_clk; - - vpu_clk.parent = &mpll_clk; - } -} - -/* - * must be called very early to get information about the - * available clock rate when the timer framework starts - */ -int __init mx27_clocks_init(unsigned long fref) -{ - u32 cscr = __raw_readl(CCM_CSCR); - - external_high_reference = fref; - - /* detect clock reference for both system PLLs */ - if (cscr & CCM_CSCR_MCU) - mpll_clk.parent = &ckih_clk; - else - mpll_clk.parent = &fpm_clk; - - if (cscr & CCM_CSCR_SP) - spll_clk.parent = &ckih_clk; - else - spll_clk.parent = &fpm_clk; - - to2_adjust_clocks(); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clocks we do not need */ - __raw_writel(0, CCM_PCCR0); - __raw_writel((1 << 10) | (1 << 19), CCM_PCCR1); - - spll_clk.disable(&spll_clk); - - /* enable basic clocks */ - clk_enable(&per1_clk); - clk_enable(&gpio_clk); - clk_enable(&emi_clk); - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX27", mx27_revision()); - clk_disable(&iim_clk); - -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - clk_enable(&uart1_clk); -#endif - - mxc_timer_init(&gpt1_clk, MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), - MX27_INT_GPT1); - - return 0; -} - -#ifdef CONFIG_OF -int __init mx27_clocks_init_dt(void) -{ - struct device_node *np; - u32 fref = 26000000; /* default */ - - for_each_compatible_node(np, NULL, "fixed-clock") { - if (!of_device_is_compatible(np, "fsl,imx-osc26m")) - continue; - - if (!of_property_read_u32(np, "clock-frequency", &fref)) - break; - } - - return mx27_clocks_init(fref); -} -#endif diff --git a/arch/arm/mach-imx/clock-imx31.c b/arch/arm/mach-imx/clock-imx31.c deleted file mode 100644 index 3a943cd4159f..000000000000 --- a/arch/arm/mach-imx/clock-imx31.c +++ /dev/null @@ -1,630 +0,0 @@ -/* - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <asm/div64.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/mx31.h> -#include <mach/common.h> - -#include "crmregs-imx3.h" - -#define PRE_DIV_MIN_FREQ 10000000 /* Minimum Frequency after Predivider */ - -static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post) -{ - u32 min_pre, temp_pre, old_err, err; - - if (div >= 512) { - *pre = 8; - *post = 64; - } else if (div >= 64) { - min_pre = (div - 1) / 64 + 1; - old_err = 8; - for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { - err = div % temp_pre; - if (err == 0) { - *pre = temp_pre; - break; - } - err = temp_pre - err; - if (err < old_err) { - old_err = err; - *pre = temp_pre; - } - } - *post = (div + *pre - 1) / *pre; - } else if (div <= 8) { - *pre = div; - *post = 1; - } else { - *pre = 1; - *post = div; - } -} - -static struct clk mcu_pll_clk; -static struct clk serial_pll_clk; -static struct clk ipg_clk; -static struct clk ckih_clk; - -static int cgr_enable(struct clk *clk) -{ - u32 reg; - - if (!clk->enable_reg) - return 0; - - reg = __raw_readl(clk->enable_reg); - reg |= 3 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void cgr_disable(struct clk *clk) -{ - u32 reg; - - if (!clk->enable_reg) - return; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(3 << clk->enable_shift); - - /* special case for EMI clock */ - if (clk->enable_reg == MXC_CCM_CGR2 && clk->enable_shift == 8) - reg |= (1 << clk->enable_shift); - - __raw_writel(reg, clk->enable_reg); -} - -static unsigned long pll_ref_get_rate(void) -{ - unsigned long ccmr; - unsigned int prcs; - - ccmr = __raw_readl(MXC_CCM_CCMR); - prcs = (ccmr & MXC_CCM_CCMR_PRCS_MASK) >> MXC_CCM_CCMR_PRCS_OFFSET; - if (prcs == 0x1) - return CKIL_CLK_FREQ * 1024; - else - return clk_get_rate(&ckih_clk); -} - -static unsigned long usb_pll_get_rate(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(MXC_CCM_UPCTL); - - return mxc_decode_pll(reg, pll_ref_get_rate()); -} - -static unsigned long serial_pll_get_rate(struct clk *clk) -{ - unsigned long reg; - - reg = __raw_readl(MXC_CCM_SRPCTL); - - return mxc_decode_pll(reg, pll_ref_get_rate()); -} - -static unsigned long mcu_pll_get_rate(struct clk *clk) -{ - unsigned long reg, ccmr; - - ccmr = __raw_readl(MXC_CCM_CCMR); - - if (!(ccmr & MXC_CCM_CCMR_MPE) || (ccmr & MXC_CCM_CCMR_MDS)) - return clk_get_rate(&ckih_clk); - - reg = __raw_readl(MXC_CCM_MPCTL); - - return mxc_decode_pll(reg, pll_ref_get_rate()); -} - -static int usb_pll_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg |= MXC_CCM_CCMR_UPE; - __raw_writel(reg, MXC_CCM_CCMR); - - /* No lock bit on MX31, so using max time from spec */ - udelay(80); - - return 0; -} - -static void usb_pll_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg &= ~MXC_CCM_CCMR_UPE; - __raw_writel(reg, MXC_CCM_CCMR); -} - -static int serial_pll_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg |= MXC_CCM_CCMR_SPE; - __raw_writel(reg, MXC_CCM_CCMR); - - /* No lock bit on MX31, so using max time from spec */ - udelay(80); - - return 0; -} - -static void serial_pll_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCMR); - reg &= ~MXC_CCM_CCMR_SPE; - __raw_writel(reg, MXC_CCM_CCMR); -} - -#define PDR0(mask, off) ((__raw_readl(MXC_CCM_PDR0) & mask) >> off) -#define PDR1(mask, off) ((__raw_readl(MXC_CCM_PDR1) & mask) >> off) -#define PDR2(mask, off) ((__raw_readl(MXC_CCM_PDR2) & mask) >> off) - -static unsigned long mcu_main_get_rate(struct clk *clk) -{ - u32 pmcr0 = __raw_readl(MXC_CCM_PMCR0); - - if ((pmcr0 & MXC_CCM_PMCR0_DFSUP1) == MXC_CCM_PMCR0_DFSUP1_SPLL) - return clk_get_rate(&serial_pll_clk); - else - return clk_get_rate(&mcu_pll_clk); -} - -static unsigned long ahb_get_rate(struct clk *clk) -{ - unsigned long max_pdf; - - max_pdf = PDR0(MXC_CCM_PDR0_MAX_PODF_MASK, - MXC_CCM_PDR0_MAX_PODF_OFFSET); - return clk_get_rate(clk->parent) / (max_pdf + 1); -} - -static unsigned long ipg_get_rate(struct clk *clk) -{ - unsigned long ipg_pdf; - - ipg_pdf = PDR0(MXC_CCM_PDR0_IPG_PODF_MASK, - MXC_CCM_PDR0_IPG_PODF_OFFSET); - return clk_get_rate(clk->parent) / (ipg_pdf + 1); -} - -static unsigned long nfc_get_rate(struct clk *clk) -{ - unsigned long nfc_pdf; - - nfc_pdf = PDR0(MXC_CCM_PDR0_NFC_PODF_MASK, - MXC_CCM_PDR0_NFC_PODF_OFFSET); - return clk_get_rate(clk->parent) / (nfc_pdf + 1); -} - -static unsigned long hsp_get_rate(struct clk *clk) -{ - unsigned long hsp_pdf; - - hsp_pdf = PDR0(MXC_CCM_PDR0_HSP_PODF_MASK, - MXC_CCM_PDR0_HSP_PODF_OFFSET); - return clk_get_rate(clk->parent) / (hsp_pdf + 1); -} - -static unsigned long usb_get_rate(struct clk *clk) -{ - unsigned long usb_pdf, usb_prepdf; - - usb_pdf = PDR1(MXC_CCM_PDR1_USB_PODF_MASK, - MXC_CCM_PDR1_USB_PODF_OFFSET); - usb_prepdf = PDR1(MXC_CCM_PDR1_USB_PRDF_MASK, - MXC_CCM_PDR1_USB_PRDF_OFFSET); - return clk_get_rate(clk->parent) / (usb_prepdf + 1) / (usb_pdf + 1); -} - -static unsigned long csi_get_rate(struct clk *clk) -{ - u32 reg, pre, post; - - reg = __raw_readl(MXC_CCM_PDR0); - pre = (reg & MXC_CCM_PDR0_CSI_PRDF_MASK) >> - MXC_CCM_PDR0_CSI_PRDF_OFFSET; - pre++; - post = (reg & MXC_CCM_PDR0_CSI_PODF_MASK) >> - MXC_CCM_PDR0_CSI_PODF_OFFSET; - post++; - return clk_get_rate(clk->parent) / (pre * post); -} - -static unsigned long csi_round_rate(struct clk *clk, unsigned long rate) -{ - u32 pre, post, parent = clk_get_rate(clk->parent); - u32 div = parent / rate; - - if (parent % rate) - div++; - - __calc_pre_post_dividers(div, &pre, &post); - - return parent / (pre * post); -} - -static int csi_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div, pre, post, parent = clk_get_rate(clk->parent); - - div = parent / rate; - - if ((parent / div) != rate) - return -EINVAL; - - __calc_pre_post_dividers(div, &pre, &post); - - /* Set CSI clock divider */ - reg = __raw_readl(MXC_CCM_PDR0) & - ~(MXC_CCM_PDR0_CSI_PODF_MASK | MXC_CCM_PDR0_CSI_PRDF_MASK); - reg |= (post - 1) << MXC_CCM_PDR0_CSI_PODF_OFFSET; - reg |= (pre - 1) << MXC_CCM_PDR0_CSI_PRDF_OFFSET; - __raw_writel(reg, MXC_CCM_PDR0); - - return 0; -} - -static unsigned long ssi1_get_rate(struct clk *clk) -{ - unsigned long ssi1_pdf, ssi1_prepdf; - - ssi1_pdf = PDR1(MXC_CCM_PDR1_SSI1_PODF_MASK, - MXC_CCM_PDR1_SSI1_PODF_OFFSET); - ssi1_prepdf = PDR1(MXC_CCM_PDR1_SSI1_PRE_PODF_MASK, - MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET); - return clk_get_rate(clk->parent) / (ssi1_prepdf + 1) / (ssi1_pdf + 1); -} - -static unsigned long ssi2_get_rate(struct clk *clk) -{ - unsigned long ssi2_pdf, ssi2_prepdf; - - ssi2_pdf = PDR1(MXC_CCM_PDR1_SSI2_PODF_MASK, - MXC_CCM_PDR1_SSI2_PODF_OFFSET); - ssi2_prepdf = PDR1(MXC_CCM_PDR1_SSI2_PRE_PODF_MASK, - MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET); - return clk_get_rate(clk->parent) / (ssi2_prepdf + 1) / (ssi2_pdf + 1); -} - -static unsigned long firi_get_rate(struct clk *clk) -{ - unsigned long firi_pdf, firi_prepdf; - - firi_pdf = PDR1(MXC_CCM_PDR1_FIRI_PODF_MASK, - MXC_CCM_PDR1_FIRI_PODF_OFFSET); - firi_prepdf = PDR1(MXC_CCM_PDR1_FIRI_PRE_PODF_MASK, - MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET); - return clk_get_rate(clk->parent) / (firi_prepdf + 1) / (firi_pdf + 1); -} - -static unsigned long firi_round_rate(struct clk *clk, unsigned long rate) -{ - u32 pre, post; - u32 parent = clk_get_rate(clk->parent); - u32 div = parent / rate; - - if (parent % rate) - div++; - - __calc_pre_post_dividers(div, &pre, &post); - - return parent / (pre * post); - -} - -static int firi_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div, pre, post, parent = clk_get_rate(clk->parent); - - div = parent / rate; - - if ((parent / div) != rate) - return -EINVAL; - - __calc_pre_post_dividers(div, &pre, &post); - - /* Set FIRI clock divider */ - reg = __raw_readl(MXC_CCM_PDR1) & - ~(MXC_CCM_PDR1_FIRI_PODF_MASK | MXC_CCM_PDR1_FIRI_PRE_PODF_MASK); - reg |= (pre - 1) << MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET; - reg |= (post - 1) << MXC_CCM_PDR1_FIRI_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_PDR1); - - return 0; -} - -static unsigned long mbx_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 2; -} - -static unsigned long mstick1_get_rate(struct clk *clk) -{ - unsigned long msti_pdf; - - msti_pdf = PDR2(MXC_CCM_PDR2_MST1_PDF_MASK, - MXC_CCM_PDR2_MST1_PDF_OFFSET); - return clk_get_rate(clk->parent) / (msti_pdf + 1); -} - -static unsigned long mstick2_get_rate(struct clk *clk) -{ - unsigned long msti_pdf; - - msti_pdf = PDR2(MXC_CCM_PDR2_MST2_PDF_MASK, - MXC_CCM_PDR2_MST2_PDF_OFFSET); - return clk_get_rate(clk->parent) / (msti_pdf + 1); -} - -static unsigned long ckih_rate; - -static unsigned long clk_ckih_get_rate(struct clk *clk) -{ - return ckih_rate; -} - -static unsigned long clk_ckil_get_rate(struct clk *clk) -{ - return CKIL_CLK_FREQ; -} - -static struct clk ckih_clk = { - .get_rate = clk_ckih_get_rate, -}; - -static struct clk mcu_pll_clk = { - .parent = &ckih_clk, - .get_rate = mcu_pll_get_rate, -}; - -static struct clk mcu_main_clk = { - .parent = &mcu_pll_clk, - .get_rate = mcu_main_get_rate, -}; - -static struct clk serial_pll_clk = { - .parent = &ckih_clk, - .get_rate = serial_pll_get_rate, - .enable = serial_pll_enable, - .disable = serial_pll_disable, -}; - -static struct clk usb_pll_clk = { - .parent = &ckih_clk, - .get_rate = usb_pll_get_rate, - .enable = usb_pll_enable, - .disable = usb_pll_disable, -}; - -static struct clk ahb_clk = { - .parent = &mcu_main_clk, - .get_rate = ahb_get_rate, -}; - -#define DEFINE_CLOCK(name, i, er, es, gr, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .enable = cgr_enable, \ - .disable = cgr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = getsetround##_get_rate, \ - .set_rate = getsetround##_set_rate, \ - .round_rate = getsetround##_round_rate, \ - .enable = cgr_enable, \ - .disable = cgr_disable, \ - .secondary = s, \ - .parent = p, \ - } - -DEFINE_CLOCK(perclk_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ckil_clk, 0, NULL, 0, clk_ckil_get_rate, NULL, NULL); - -DEFINE_CLOCK(sdhc1_clk, 0, MXC_CCM_CGR0, 0, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(sdhc2_clk, 1, MXC_CCM_CGR0, 2, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CGR0, 4, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(epit1_clk, 0, MXC_CCM_CGR0, 6, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(epit2_clk, 1, MXC_CCM_CGR0, 8, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(iim_clk, 0, MXC_CCM_CGR0, 10, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(pata_clk, 0, MXC_CCM_CGR0, 12, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(sdma_clk1, 0, MXC_CCM_CGR0, 14, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(cspi3_clk, 2, MXC_CCM_CGR0, 16, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(rng_clk, 0, MXC_CCM_CGR0, 18, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CGR0, 20, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CGR0, 22, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CGR0, 24, ssi1_get_rate, NULL, &serial_pll_clk); -DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CGR0, 26, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CGR0, 28, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(i2c3_clk, 2, MXC_CCM_CGR0, 30, NULL, NULL, &perclk_clk); - -DEFINE_CLOCK(mpeg4_clk, 0, MXC_CCM_CGR1, 0, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1, 2, mstick1_get_rate, NULL, &usb_pll_clk); -DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1, 4, mstick2_get_rate, NULL, &usb_pll_clk); -DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &serial_pll_clk); -DEFINE_CLOCK(rtc_clk, 0, MXC_CCM_CGR1, 8, NULL, NULL, &ckil_clk); -DEFINE_CLOCK(wdog_clk, 0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(pwm_clk, 0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(usb_clk2, 0, MXC_CCM_CGR1, 18, usb_get_rate, NULL, &ahb_clk); -DEFINE_CLOCK(kpp_clk, 0, MXC_CCM_CGR1, 20, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ipu_clk, 0, MXC_CCM_CGR1, 22, hsp_get_rate, NULL, &mcu_main_clk); -DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CGR1, 24, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(uart4_clk, 3, MXC_CCM_CGR1, 26, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(uart5_clk, 4, MXC_CCM_CGR1, 28, NULL, NULL, &perclk_clk); -DEFINE_CLOCK(owire_clk, 0, MXC_CCM_CGR1, 30, NULL, NULL, &perclk_clk); - -DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CGR2, 0, ssi2_get_rate, NULL, &serial_pll_clk); -DEFINE_CLOCK(cspi1_clk, 0, MXC_CCM_CGR2, 2, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(cspi2_clk, 1, MXC_CCM_CGR2, 4, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(mbx_clk, 0, MXC_CCM_CGR2, 6, mbx_get_rate, NULL, &ahb_clk); -DEFINE_CLOCK(emi_clk, 0, MXC_CCM_CGR2, 8, NULL, NULL, &ahb_clk); -DEFINE_CLOCK(rtic_clk, 0, MXC_CCM_CGR2, 10, NULL, NULL, &ahb_clk); -DEFINE_CLOCK1(firi_clk, 0, MXC_CCM_CGR2, 12, firi, NULL, &usb_pll_clk); - -DEFINE_CLOCK(sdma_clk2, 0, NULL, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(usb_clk1, 0, NULL, 0, usb_get_rate, NULL, &usb_pll_clk); -DEFINE_CLOCK(nfc_clk, 0, NULL, 0, nfc_get_rate, NULL, &ahb_clk); -DEFINE_CLOCK(scc_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); -DEFINE_CLOCK(ipg_clk, 0, NULL, 0, ipg_get_rate, NULL, &ahb_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - _REGISTER_CLOCK(NULL, "emi", emi_clk) - _REGISTER_CLOCK("imx31-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx31-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK("imx31-cspi.2", NULL, cspi3_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - _REGISTER_CLOCK(NULL, "pwm", pwm_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) - _REGISTER_CLOCK(NULL, "epit", epit1_clk) - _REGISTER_CLOCK(NULL, "epit", epit2_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) - _REGISTER_CLOCK("ipu-core", NULL, ipu_clk) - _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk) - _REGISTER_CLOCK(NULL, "kpp", kpp_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk1) - _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2) - _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk) - /* i.mx31 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) - _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk) - _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk) - _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK(NULL, "firi", firi_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK(NULL, "rtic", rtic_clk) - _REGISTER_CLOCK(NULL, "rng", rng_clk) - _REGISTER_CLOCK("imx31-sdma", NULL, sdma_clk1) - _REGISTER_CLOCK(NULL, "sdma_ipg", sdma_clk2) - _REGISTER_CLOCK(NULL, "mstick", mstick1_clk) - _REGISTER_CLOCK(NULL, "mstick", mstick2_clk) - _REGISTER_CLOCK(NULL, "scc", scc_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) - _REGISTER_CLOCK(NULL, "mpeg4", mpeg4_clk) - _REGISTER_CLOCK(NULL, "mbx", mbx_clk) -}; - -int __init mx31_clocks_init(unsigned long fref) -{ - u32 reg; - - ckih_rate = fref; - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* change the csi_clk parent if necessary */ - reg = __raw_readl(MXC_CCM_CCMR); - if (!(reg & MXC_CCM_CCMR_CSCS)) - if (clk_set_parent(&csi_clk, &usb_pll_clk)) - pr_err("%s: error changing csi_clk parent\n", __func__); - - - /* Turn off all possible clocks */ - __raw_writel((3 << 4), MXC_CCM_CGR0); - __raw_writel(0, MXC_CCM_CGR1); - __raw_writel((3 << 8) | (3 << 14) | (3 << 16)| - 1 << 27 | 1 << 28, /* Bit 27 and 28 are not defined for - MX32, but still required to be set */ - MXC_CCM_CGR2); - - /* - * Before turning off usb_pll make sure ipg_per_clk is generated - * by ipg_clk and not usb_pll. - */ - __raw_writel(__raw_readl(MXC_CCM_CCMR) | (1 << 24), MXC_CCM_CCMR); - - usb_pll_disable(&usb_pll_clk); - - pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk)); - - clk_enable(&gpt_clk); - clk_enable(&emi_clk); - clk_enable(&iim_clk); - mx31_revision(); - clk_disable(&iim_clk); - - clk_enable(&serial_pll_clk); - - if (mx31_revision() >= IMX_CHIP_REVISION_2_0) { - reg = __raw_readl(MXC_CCM_PMCR1); - /* No PLL restart on DVFS switch; enable auto EMI handshake */ - reg |= MXC_CCM_PMCR1_PLLRDIS | MXC_CCM_PMCR1_EMIRQ_EN; - __raw_writel(reg, MXC_CCM_PMCR1); - } - - mxc_timer_init(&ipg_clk, MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), - MX31_INT_GPT); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx35.c b/arch/arm/mach-imx/clock-imx35.c deleted file mode 100644 index e56c1a83eee3..000000000000 --- a/arch/arm/mach-imx/clock-imx35.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (C) 2009 by Sascha Hauer, Pengutronix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> - -#include <mach/clock.h> -#include <mach/hardware.h> -#include <mach/common.h> - -#include "crmregs-imx3.h" - -#ifdef HAVE_SET_RATE_SUPPORT -static void calc_dividers(u32 div, u32 *pre, u32 *post, u32 maxpost) -{ - u32 min_pre, temp_pre, old_err, err; - - min_pre = (div - 1) / maxpost + 1; - old_err = 8; - - for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { - if (div > (temp_pre * maxpost)) - break; - - if (div < (temp_pre * temp_pre)) - continue; - - err = div % temp_pre; - - if (err == 0) { - *pre = temp_pre; - break; - } - - err = temp_pre - err; - - if (err < old_err) { - old_err = err; - *pre = temp_pre; - } - } - - *post = (div + *pre - 1) / *pre; -} - -/* get the best values for a 3-bit divider combined with a 6-bit divider */ -static void calc_dividers_3_6(u32 div, u32 *pre, u32 *post) -{ - if (div >= 512) { - *pre = 8; - *post = 64; - } else if (div >= 64) { - calc_dividers(div, pre, post, 64); - } else if (div <= 8) { - *pre = div; - *post = 1; - } else { - *pre = 1; - *post = div; - } -} - -/* get the best values for two cascaded 3-bit dividers */ -static void calc_dividers_3_3(u32 div, u32 *pre, u32 *post) -{ - if (div >= 64) { - *pre = *post = 8; - } else if (div > 8) { - calc_dividers(div, pre, post, 8); - } else { - *pre = 1; - *post = div; - } -} -#endif - -static unsigned long get_rate_mpll(void) -{ - ulong mpctl = __raw_readl(MX35_CCM_MPCTL); - - return mxc_decode_pll(mpctl, 24000000); -} - -static unsigned long get_rate_ppll(void) -{ - ulong ppctl = __raw_readl(MX35_CCM_PPCTL); - - return mxc_decode_pll(ppctl, 24000000); -} - -struct arm_ahb_div { - unsigned char arm, ahb, sel; -}; - -static struct arm_ahb_div clk_consumer[] = { - { .arm = 1, .ahb = 4, .sel = 0}, - { .arm = 1, .ahb = 3, .sel = 1}, - { .arm = 2, .ahb = 2, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 4, .ahb = 1, .sel = 0}, - { .arm = 1, .ahb = 5, .sel = 0}, - { .arm = 1, .ahb = 8, .sel = 0}, - { .arm = 1, .ahb = 6, .sel = 1}, - { .arm = 2, .ahb = 4, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 4, .ahb = 2, .sel = 0}, - { .arm = 0, .ahb = 0, .sel = 0}, -}; - -static unsigned long get_rate_arm(void) -{ - unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0); - struct arm_ahb_div *aad; - unsigned long fref = get_rate_mpll(); - - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - if (aad->sel) - fref = fref * 3 / 4; - - return fref / aad->arm; -} - -static unsigned long get_rate_ahb(struct clk *clk) -{ - unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0); - struct arm_ahb_div *aad; - unsigned long fref = get_rate_arm(); - - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - - return fref / aad->ahb; -} - -static unsigned long get_rate_ipg(struct clk *clk) -{ - return get_rate_ahb(NULL) >> 1; -} - -static unsigned long get_rate_uart(struct clk *clk) -{ - unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3); - unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4); - unsigned long div = ((pdr4 >> 10) & 0x3f) + 1; - - if (pdr3 & (1 << 14)) - return get_rate_arm() / div; - else - return get_rate_ppll() / div; -} - -static unsigned long get_rate_sdhc(struct clk *clk) -{ - unsigned long pdr3 = __raw_readl(MX35_CCM_PDR3); - unsigned long div, rate; - - if (pdr3 & (1 << 6)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - switch (clk->id) { - default: - case 0: - div = pdr3 & 0x3f; - break; - case 1: - div = (pdr3 >> 8) & 0x3f; - break; - case 2: - div = (pdr3 >> 16) & 0x3f; - break; - } - - return rate / (div + 1); -} - -static unsigned long get_rate_mshc(struct clk *clk) -{ - unsigned long pdr1 = __raw_readl(MXC_CCM_PDR1); - unsigned long div1, div2, rate; - - if (pdr1 & (1 << 7)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - div1 = (pdr1 >> 29) & 0x7; - div2 = (pdr1 >> 22) & 0x3f; - - return rate / ((div1 + 1) * (div2 + 1)); -} - -static unsigned long get_rate_ssi(struct clk *clk) -{ - unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2); - unsigned long div1, div2, rate; - - if (pdr2 & (1 << 6)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - switch (clk->id) { - default: - case 0: - div1 = pdr2 & 0x3f; - div2 = (pdr2 >> 24) & 0x7; - break; - case 1: - div1 = (pdr2 >> 8) & 0x3f; - div2 = (pdr2 >> 27) & 0x7; - break; - } - - return rate / ((div1 + 1) * (div2 + 1)); -} - -static unsigned long get_rate_csi(struct clk *clk) -{ - unsigned long pdr2 = __raw_readl(MX35_CCM_PDR2); - unsigned long rate; - - if (pdr2 & (1 << 7)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - return rate / (((pdr2 >> 16) & 0x3f) + 1); -} - -static unsigned long get_rate_otg(struct clk *clk) -{ - unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4); - unsigned long rate; - - if (pdr4 & (1 << 9)) - rate = get_rate_arm(); - else - rate = get_rate_ppll(); - - return rate / (((pdr4 >> 22) & 0x3f) + 1); -} - -static unsigned long get_rate_ipg_per(struct clk *clk) -{ - unsigned long pdr0 = __raw_readl(MXC_CCM_PDR0); - unsigned long pdr4 = __raw_readl(MX35_CCM_PDR4); - unsigned long div; - - if (pdr0 & (1 << 26)) { - div = (pdr4 >> 16) & 0x3f; - return get_rate_arm() / (div + 1); - } else { - div = (pdr0 >> 12) & 0x7; - return get_rate_ahb(NULL) / (div + 1); - } -} - -static unsigned long get_rate_hsp(struct clk *clk) -{ - unsigned long hsp_podf = (__raw_readl(MXC_CCM_PDR0) >> 20) & 0x03; - unsigned long fref = get_rate_mpll(); - - if (fref > 400 * 1000 * 1000) { - switch (hsp_podf) { - case 0: - return fref >> 2; - case 1: - return fref >> 3; - case 2: - return fref / 3; - } - } else { - switch (hsp_podf) { - case 0: - case 2: - return fref / 3; - case 1: - return fref / 6; - } - } - - return 0; -} - -static int clk_cgr_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= 3 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; -} - -static void clk_cgr_disable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(3 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); -} - -#define DEFINE_CLOCK(name, i, er, es, gr, sr) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = clk_cgr_enable, \ - .disable = clk_cgr_disable, \ - } - -DEFINE_CLOCK(asrc_clk, 0, MX35_CCM_CGR0, 0, NULL, NULL); -DEFINE_CLOCK(pata_clk, 0, MX35_CCM_CGR0, 2, get_rate_ipg, NULL); -/* DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR0, 4, NULL, NULL); */ -DEFINE_CLOCK(can1_clk, 0, MX35_CCM_CGR0, 6, get_rate_ipg, NULL); -DEFINE_CLOCK(can2_clk, 1, MX35_CCM_CGR0, 8, get_rate_ipg, NULL); -DEFINE_CLOCK(cspi1_clk, 0, MX35_CCM_CGR0, 10, get_rate_ipg, NULL); -DEFINE_CLOCK(cspi2_clk, 1, MX35_CCM_CGR0, 12, get_rate_ipg, NULL); -DEFINE_CLOCK(ect_clk, 0, MX35_CCM_CGR0, 14, get_rate_ipg, NULL); -DEFINE_CLOCK(edio_clk, 0, MX35_CCM_CGR0, 16, NULL, NULL); -DEFINE_CLOCK(emi_clk, 0, MX35_CCM_CGR0, 18, get_rate_ipg, NULL); -DEFINE_CLOCK(epit1_clk, 0, MX35_CCM_CGR0, 20, get_rate_ipg, NULL); -DEFINE_CLOCK(epit2_clk, 1, MX35_CCM_CGR0, 22, get_rate_ipg, NULL); -DEFINE_CLOCK(esai_clk, 0, MX35_CCM_CGR0, 24, NULL, NULL); -DEFINE_CLOCK(esdhc1_clk, 0, MX35_CCM_CGR0, 26, get_rate_sdhc, NULL); -DEFINE_CLOCK(esdhc2_clk, 1, MX35_CCM_CGR0, 28, get_rate_sdhc, NULL); -DEFINE_CLOCK(esdhc3_clk, 2, MX35_CCM_CGR0, 30, get_rate_sdhc, NULL); - -DEFINE_CLOCK(fec_clk, 0, MX35_CCM_CGR1, 0, get_rate_ipg, NULL); -DEFINE_CLOCK(gpio1_clk, 0, MX35_CCM_CGR1, 2, NULL, NULL); -DEFINE_CLOCK(gpio2_clk, 1, MX35_CCM_CGR1, 4, NULL, NULL); -DEFINE_CLOCK(gpio3_clk, 2, MX35_CCM_CGR1, 6, NULL, NULL); -DEFINE_CLOCK(gpt_clk, 0, MX35_CCM_CGR1, 8, get_rate_ipg, NULL); -DEFINE_CLOCK(i2c1_clk, 0, MX35_CCM_CGR1, 10, get_rate_ipg_per, NULL); -DEFINE_CLOCK(i2c2_clk, 1, MX35_CCM_CGR1, 12, get_rate_ipg_per, NULL); -DEFINE_CLOCK(i2c3_clk, 2, MX35_CCM_CGR1, 14, get_rate_ipg_per, NULL); -DEFINE_CLOCK(iomuxc_clk, 0, MX35_CCM_CGR1, 16, NULL, NULL); -DEFINE_CLOCK(ipu_clk, 0, MX35_CCM_CGR1, 18, get_rate_hsp, NULL); -DEFINE_CLOCK(kpp_clk, 0, MX35_CCM_CGR1, 20, get_rate_ipg, NULL); -DEFINE_CLOCK(mlb_clk, 0, MX35_CCM_CGR1, 22, get_rate_ahb, NULL); -DEFINE_CLOCK(mshc_clk, 0, MX35_CCM_CGR1, 24, get_rate_mshc, NULL); -DEFINE_CLOCK(owire_clk, 0, MX35_CCM_CGR1, 26, get_rate_ipg_per, NULL); -DEFINE_CLOCK(pwm_clk, 0, MX35_CCM_CGR1, 28, get_rate_ipg_per, NULL); -DEFINE_CLOCK(rngc_clk, 0, MX35_CCM_CGR1, 30, get_rate_ipg, NULL); - -DEFINE_CLOCK(rtc_clk, 0, MX35_CCM_CGR2, 0, get_rate_ipg, NULL); -DEFINE_CLOCK(rtic_clk, 0, MX35_CCM_CGR2, 2, get_rate_ahb, NULL); -DEFINE_CLOCK(scc_clk, 0, MX35_CCM_CGR2, 4, get_rate_ipg, NULL); -DEFINE_CLOCK(sdma_clk, 0, MX35_CCM_CGR2, 6, NULL, NULL); -DEFINE_CLOCK(spba_clk, 0, MX35_CCM_CGR2, 8, get_rate_ipg, NULL); -DEFINE_CLOCK(spdif_clk, 0, MX35_CCM_CGR2, 10, NULL, NULL); -DEFINE_CLOCK(ssi1_clk, 0, MX35_CCM_CGR2, 12, get_rate_ssi, NULL); -DEFINE_CLOCK(ssi2_clk, 1, MX35_CCM_CGR2, 14, get_rate_ssi, NULL); -DEFINE_CLOCK(uart1_clk, 0, MX35_CCM_CGR2, 16, get_rate_uart, NULL); -DEFINE_CLOCK(uart2_clk, 1, MX35_CCM_CGR2, 18, get_rate_uart, NULL); -DEFINE_CLOCK(uart3_clk, 2, MX35_CCM_CGR2, 20, get_rate_uart, NULL); -DEFINE_CLOCK(usbotg_clk, 0, MX35_CCM_CGR2, 22, get_rate_otg, NULL); -DEFINE_CLOCK(wdog_clk, 0, MX35_CCM_CGR2, 24, NULL, NULL); -DEFINE_CLOCK(max_clk, 0, MX35_CCM_CGR2, 26, NULL, NULL); -DEFINE_CLOCK(audmux_clk, 0, MX35_CCM_CGR2, 30, NULL, NULL); - -DEFINE_CLOCK(csi_clk, 0, MX35_CCM_CGR3, 0, get_rate_csi, NULL); -DEFINE_CLOCK(iim_clk, 0, MX35_CCM_CGR3, 2, NULL, NULL); -DEFINE_CLOCK(gpu2d_clk, 0, MX35_CCM_CGR3, 4, NULL, NULL); - -DEFINE_CLOCK(usbahb_clk, 0, 0, 0, get_rate_ahb, NULL); - -static int clk_dummy_enable(struct clk *clk) -{ - return 0; -} - -static void clk_dummy_disable(struct clk *clk) -{ -} - -static unsigned long get_rate_nfc(struct clk *clk) -{ - unsigned long div1; - - div1 = (__raw_readl(MX35_CCM_PDR4) >> 28) + 1; - - return get_rate_ahb(NULL) / div1; -} - -/* NAND Controller: It seems it can't be disabled */ -static struct clk nfc_clk = { - .id = 0, - .enable_reg = 0, - .enable_shift = 0, - .get_rate = get_rate_nfc, - .set_rate = NULL, /* set_rate_nfc, */ - .enable = clk_dummy_enable, - .disable = clk_dummy_disable -}; - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - _REGISTER_CLOCK(NULL, "asrc", asrc_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK("flexcan.0", NULL, can1_clk) - _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk) - _REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk) - _REGISTER_CLOCK(NULL, "ect", ect_clk) - _REGISTER_CLOCK(NULL, "edio", edio_clk) - _REGISTER_CLOCK(NULL, "emi", emi_clk) - _REGISTER_CLOCK("imx-epit.0", NULL, epit1_clk) - _REGISTER_CLOCK("imx-epit.1", NULL, epit2_clk) - _REGISTER_CLOCK(NULL, "esai", esai_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx35.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx35.1", NULL, esdhc2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx35.2", NULL, esdhc3_clk) - /* i.mx35 has the i.mx27 type fec */ - _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio1_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio2_clk) - _REGISTER_CLOCK(NULL, "gpio", gpio3_clk) - _REGISTER_CLOCK("gpt.0", NULL, gpt_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) - _REGISTER_CLOCK(NULL, "iomuxc", iomuxc_clk) - _REGISTER_CLOCK("ipu-core", NULL, ipu_clk) - _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk) - _REGISTER_CLOCK(NULL, "kpp", kpp_clk) - _REGISTER_CLOCK(NULL, "mlb", mlb_clk) - _REGISTER_CLOCK(NULL, "mshc", mshc_clk) - _REGISTER_CLOCK("mxc_w1", NULL, owire_clk) - _REGISTER_CLOCK(NULL, "pwm", pwm_clk) - _REGISTER_CLOCK(NULL, "rngc", rngc_clk) - _REGISTER_CLOCK(NULL, "rtc", rtc_clk) - _REGISTER_CLOCK(NULL, "rtic", rtic_clk) - _REGISTER_CLOCK(NULL, "scc", scc_clk) - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK(NULL, "spba", spba_clk) - _REGISTER_CLOCK(NULL, "spdif", spdif_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - /* i.mx35 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usbahb_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) - _REGISTER_CLOCK(NULL, "max", max_clk) - _REGISTER_CLOCK(NULL, "audmux", audmux_clk) - _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk) - _REGISTER_CLOCK(NULL, "iim", iim_clk) - _REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk) - _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) -}; - -int __init mx35_clocks_init() -{ - unsigned int cgr2 = 3 << 26; - -#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) - cgr2 |= 3 << 16; -#endif - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - /* Turn off all clocks except the ones we need to survive, namely: - * EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart - */ - __raw_writel((3 << 18), MX35_CCM_CGR0); - __raw_writel((3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 16), - MX35_CCM_CGR1); - __raw_writel(cgr2, MX35_CCM_CGR2); - __raw_writel(0, MX35_CCM_CGR3); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX35", mx35_revision()); - clk_disable(&iim_clk); - - /* - * Check if we came up in internal boot mode. If yes, we need some - * extra clocks turned on, otherwise the MX35 boot ROM code will - * hang after a watchdog reset. - */ - if (!(__raw_readl(MX35_CCM_RCSR) & (3 << 10))) { - /* Additionally turn on UART1, SCC, and IIM clocks */ - clk_enable(&iim_clk); - clk_enable(&uart1_clk); - clk_enable(&scc_clk); - } - -#ifdef CONFIG_MXC_USE_EPIT - epit_timer_init(&epit1_clk, - MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1); -#else - mxc_timer_init(&gpt_clk, - MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT); -#endif - - return 0; -} diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c deleted file mode 100644 index 111c328f5420..000000000000 --- a/arch/arm/mach-imx/clock-imx6q.c +++ /dev/null @@ -1,2111 +0,0 @@ -/* - * Copyright 2011 Freescale Semiconductor, Inc. - * Copyright 2011 Linaro Ltd. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include <linux/init.h> -#include <linux/types.h> -#include <linux/clk.h> -#include <linux/clkdev.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <asm/div64.h> -#include <asm/mach/map.h> -#include <mach/clock.h> -#include <mach/common.h> -#include <mach/hardware.h> - -#define PLL_BASE IMX_IO_ADDRESS(MX6Q_ANATOP_BASE_ADDR) -#define PLL1_SYS (PLL_BASE + 0x000) -#define PLL2_BUS (PLL_BASE + 0x030) -#define PLL3_USB_OTG (PLL_BASE + 0x010) -#define PLL4_AUDIO (PLL_BASE + 0x070) -#define PLL5_VIDEO (PLL_BASE + 0x0a0) -#define PLL6_MLB (PLL_BASE + 0x0d0) -#define PLL7_USB_HOST (PLL_BASE + 0x020) -#define PLL8_ENET (PLL_BASE + 0x0e0) -#define PFD_480 (PLL_BASE + 0x0f0) -#define PFD_528 (PLL_BASE + 0x100) -#define PLL_NUM_OFFSET 0x010 -#define PLL_DENOM_OFFSET 0x020 - -#define PFD0 7 -#define PFD1 15 -#define PFD2 23 -#define PFD3 31 -#define PFD_FRAC_MASK 0x3f - -#define BM_PLL_BYPASS (0x1 << 16) -#define BM_PLL_ENABLE (0x1 << 13) -#define BM_PLL_POWER_DOWN (0x1 << 12) -#define BM_PLL_LOCK (0x1 << 31) -#define BP_PLL_SYS_DIV_SELECT 0 -#define BM_PLL_SYS_DIV_SELECT (0x7f << 0) -#define BP_PLL_BUS_DIV_SELECT 0 -#define BM_PLL_BUS_DIV_SELECT (0x1 << 0) -#define BP_PLL_USB_DIV_SELECT 0 -#define BM_PLL_USB_DIV_SELECT (0x3 << 0) -#define BP_PLL_AV_DIV_SELECT 0 -#define BM_PLL_AV_DIV_SELECT (0x7f << 0) -#define BP_PLL_ENET_DIV_SELECT 0 -#define BM_PLL_ENET_DIV_SELECT (0x3 << 0) -#define BM_PLL_ENET_EN_PCIE (0x1 << 19) -#define BM_PLL_ENET_EN_SATA (0x1 << 20) - -#define CCM_BASE IMX_IO_ADDRESS(MX6Q_CCM_BASE_ADDR) -#define CCR (CCM_BASE + 0x00) -#define CCDR (CCM_BASE + 0x04) -#define CSR (CCM_BASE + 0x08) -#define CCSR (CCM_BASE + 0x0c) -#define CACRR (CCM_BASE + 0x10) -#define CBCDR (CCM_BASE + 0x14) -#define CBCMR (CCM_BASE + 0x18) -#define CSCMR1 (CCM_BASE + 0x1c) -#define CSCMR2 (CCM_BASE + 0x20) -#define CSCDR1 (CCM_BASE + 0x24) -#define CS1CDR (CCM_BASE + 0x28) -#define CS2CDR (CCM_BASE + 0x2c) -#define CDCDR (CCM_BASE + 0x30) -#define CHSCCDR (CCM_BASE + 0x34) -#define CSCDR2 (CCM_BASE + 0x38) -#define CSCDR3 (CCM_BASE + 0x3c) -#define CSCDR4 (CCM_BASE + 0x40) -#define CWDR (CCM_BASE + 0x44) -#define CDHIPR (CCM_BASE + 0x48) -#define CDCR (CCM_BASE + 0x4c) -#define CTOR (CCM_BASE + 0x50) -#define CLPCR (CCM_BASE + 0x54) -#define CISR (CCM_BASE + 0x58) -#define CIMR (CCM_BASE + 0x5c) -#define CCOSR (CCM_BASE + 0x60) -#define CGPR (CCM_BASE + 0x64) -#define CCGR0 (CCM_BASE + 0x68) -#define CCGR1 (CCM_BASE + 0x6c) -#define CCGR2 (CCM_BASE + 0x70) -#define CCGR3 (CCM_BASE + 0x74) -#define CCGR4 (CCM_BASE + 0x78) -#define CCGR5 (CCM_BASE + 0x7c) -#define CCGR6 (CCM_BASE + 0x80) -#define CCGR7 (CCM_BASE + 0x84) -#define CMEOR (CCM_BASE + 0x88) - -#define CG0 0 -#define CG1 2 -#define CG2 4 -#define CG3 6 -#define CG4 8 -#define CG5 10 -#define CG6 12 -#define CG7 14 -#define CG8 16 -#define CG9 18 -#define CG10 20 -#define CG11 22 -#define CG12 24 -#define CG13 26 -#define CG14 28 -#define CG15 30 - -#define BM_CCSR_PLL1_SW_SEL (0x1 << 2) -#define BM_CCSR_STEP_SEL (0x1 << 8) - -#define BP_CACRR_ARM_PODF 0 -#define BM_CACRR_ARM_PODF (0x7 << 0) - -#define BP_CBCDR_PERIPH2_CLK2_PODF 0 -#define BM_CBCDR_PERIPH2_CLK2_PODF (0x7 << 0) -#define BP_CBCDR_MMDC_CH1_AXI_PODF 3 -#define BM_CBCDR_MMDC_CH1_AXI_PODF (0x7 << 3) -#define BP_CBCDR_AXI_SEL 6 -#define BM_CBCDR_AXI_SEL (0x3 << 6) -#define BP_CBCDR_IPG_PODF 8 -#define BM_CBCDR_IPG_PODF (0x3 << 8) -#define BP_CBCDR_AHB_PODF 10 -#define BM_CBCDR_AHB_PODF (0x7 << 10) -#define BP_CBCDR_AXI_PODF 16 -#define BM_CBCDR_AXI_PODF (0x7 << 16) -#define BP_CBCDR_MMDC_CH0_AXI_PODF 19 -#define BM_CBCDR_MMDC_CH0_AXI_PODF (0x7 << 19) -#define BP_CBCDR_PERIPH_CLK_SEL 25 -#define BM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) -#define BP_CBCDR_PERIPH2_CLK_SEL 26 -#define BM_CBCDR_PERIPH2_CLK_SEL (0x1 << 26) -#define BP_CBCDR_PERIPH_CLK2_PODF 27 -#define BM_CBCDR_PERIPH_CLK2_PODF (0x7 << 27) - -#define BP_CBCMR_GPU2D_AXI_SEL 0 -#define BM_CBCMR_GPU2D_AXI_SEL (0x1 << 0) -#define BP_CBCMR_GPU3D_AXI_SEL 1 -#define BM_CBCMR_GPU3D_AXI_SEL (0x1 << 1) -#define BP_CBCMR_GPU3D_CORE_SEL 4 -#define BM_CBCMR_GPU3D_CORE_SEL (0x3 << 4) -#define BP_CBCMR_GPU3D_SHADER_SEL 8 -#define BM_CBCMR_GPU3D_SHADER_SEL (0x3 << 8) -#define BP_CBCMR_PCIE_AXI_SEL 10 -#define BM_CBCMR_PCIE_AXI_SEL (0x1 << 10) -#define BP_CBCMR_VDO_AXI_SEL 11 -#define BM_CBCMR_VDO_AXI_SEL (0x1 << 11) -#define BP_CBCMR_PERIPH_CLK2_SEL 12 -#define BM_CBCMR_PERIPH_CLK2_SEL (0x3 << 12) -#define BP_CBCMR_VPU_AXI_SEL 14 -#define BM_CBCMR_VPU_AXI_SEL (0x3 << 14) -#define BP_CBCMR_GPU2D_CORE_SEL 16 -#define BM_CBCMR_GPU2D_CORE_SEL (0x3 << 16) -#define BP_CBCMR_PRE_PERIPH_CLK_SEL 18 -#define BM_CBCMR_PRE_PERIPH_CLK_SEL (0x3 << 18) -#define BP_CBCMR_PERIPH2_CLK2_SEL 20 -#define BM_CBCMR_PERIPH2_CLK2_SEL (0x1 << 20) -#define BP_CBCMR_PRE_PERIPH2_CLK_SEL 21 -#define BM_CBCMR_PRE_PERIPH2_CLK_SEL (0x3 << 21) -#define BP_CBCMR_GPU2D_CORE_PODF 23 -#define BM_CBCMR_GPU2D_CORE_PODF (0x7 << 23) -#define BP_CBCMR_GPU3D_CORE_PODF 26 -#define BM_CBCMR_GPU3D_CORE_PODF (0x7 << 26) -#define BP_CBCMR_GPU3D_SHADER_PODF 29 -#define BM_CBCMR_GPU3D_SHADER_PODF (0x7 << 29) - -#define BP_CSCMR1_PERCLK_PODF 0 -#define BM_CSCMR1_PERCLK_PODF (0x3f << 0) -#define BP_CSCMR1_SSI1_SEL 10 -#define BM_CSCMR1_SSI1_SEL (0x3 << 10) -#define BP_CSCMR1_SSI2_SEL 12 -#define BM_CSCMR1_SSI2_SEL (0x3 << 12) -#define BP_CSCMR1_SSI3_SEL 14 -#define BM_CSCMR1_SSI3_SEL (0x3 << 14) -#define BP_CSCMR1_USDHC1_SEL 16 -#define BM_CSCMR1_USDHC1_SEL (0x1 << 16) -#define BP_CSCMR1_USDHC2_SEL 17 -#define BM_CSCMR1_USDHC2_SEL (0x1 << 17) -#define BP_CSCMR1_USDHC3_SEL 18 -#define BM_CSCMR1_USDHC3_SEL (0x1 << 18) -#define BP_CSCMR1_USDHC4_SEL 19 -#define BM_CSCMR1_USDHC4_SEL (0x1 << 19) -#define BP_CSCMR1_EMI_PODF 20 -#define BM_CSCMR1_EMI_PODF (0x7 << 20) -#define BP_CSCMR1_EMI_SLOW_PODF 23 -#define BM_CSCMR1_EMI_SLOW_PODF (0x7 << 23) -#define BP_CSCMR1_EMI_SEL 27 -#define BM_CSCMR1_EMI_SEL (0x3 << 27) -#define BP_CSCMR1_EMI_SLOW_SEL 29 -#define BM_CSCMR1_EMI_SLOW_SEL (0x3 << 29) - -#define BP_CSCMR2_CAN_PODF 2 -#define BM_CSCMR2_CAN_PODF (0x3f << 2) -#define BM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10) -#define BM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11) -#define BP_CSCMR2_ESAI_SEL 19 -#define BM_CSCMR2_ESAI_SEL (0x3 << 19) - -#define BP_CSCDR1_UART_PODF 0 -#define BM_CSCDR1_UART_PODF (0x3f << 0) -#define BP_CSCDR1_USDHC1_PODF 11 -#define BM_CSCDR1_USDHC1_PODF (0x7 << 11) -#define BP_CSCDR1_USDHC2_PODF 16 -#define BM_CSCDR1_USDHC2_PODF (0x7 << 16) -#define BP_CSCDR1_USDHC3_PODF 19 -#define BM_CSCDR1_USDHC3_PODF (0x7 << 19) -#define BP_CSCDR1_USDHC4_PODF 22 -#define BM_CSCDR1_USDHC4_PODF (0x7 << 22) -#define BP_CSCDR1_VPU_AXI_PODF 25 -#define BM_CSCDR1_VPU_AXI_PODF (0x7 << 25) - -#define BP_CS1CDR_SSI1_PODF 0 -#define BM_CS1CDR_SSI1_PODF (0x3f << 0) -#define BP_CS1CDR_SSI1_PRED 6 -#define BM_CS1CDR_SSI1_PRED (0x7 << 6) -#define BP_CS1CDR_ESAI_PRED 9 -#define BM_CS1CDR_ESAI_PRED (0x7 << 9) -#define BP_CS1CDR_SSI3_PODF 16 -#define BM_CS1CDR_SSI3_PODF (0x3f << 16) -#define BP_CS1CDR_SSI3_PRED 22 -#define BM_CS1CDR_SSI3_PRED (0x7 << 22) -#define BP_CS1CDR_ESAI_PODF 25 -#define BM_CS1CDR_ESAI_PODF (0x7 << 25) - -#define BP_CS2CDR_SSI2_PODF 0 -#define BM_CS2CDR_SSI2_PODF (0x3f << 0) -#define BP_CS2CDR_SSI2_PRED 6 -#define BM_CS2CDR_SSI2_PRED (0x7 << 6) -#define BP_CS2CDR_LDB_DI0_SEL 9 -#define BM_CS2CDR_LDB_DI0_SEL (0x7 << 9) -#define BP_CS2CDR_LDB_DI1_SEL 12 -#define BM_CS2CDR_LDB_DI1_SEL (0x7 << 12) -#define BP_CS2CDR_ENFC_SEL 16 -#define BM_CS2CDR_ENFC_SEL (0x3 << 16) -#define BP_CS2CDR_ENFC_PRED 18 -#define BM_CS2CDR_ENFC_PRED (0x7 << 18) -#define BP_CS2CDR_ENFC_PODF 21 -#define BM_CS2CDR_ENFC_PODF (0x3f << 21) - -#define BP_CDCDR_ASRC_SERIAL_SEL 7 -#define BM_CDCDR_ASRC_SERIAL_SEL (0x3 << 7) -#define BP_CDCDR_ASRC_SERIAL_PODF 9 -#define BM_CDCDR_ASRC_SERIAL_PODF (0x7 << 9) -#define BP_CDCDR_ASRC_SERIAL_PRED 12 -#define BM_CDCDR_ASRC_SERIAL_PRED (0x7 << 12) -#define BP_CDCDR_SPDIF_SEL 20 -#define BM_CDCDR_SPDIF_SEL (0x3 << 20) -#define BP_CDCDR_SPDIF_PODF 22 -#define BM_CDCDR_SPDIF_PODF (0x7 << 22) -#define BP_CDCDR_SPDIF_PRED 25 -#define BM_CDCDR_SPDIF_PRED (0x7 << 25) -#define BP_CDCDR_HSI_TX_PODF 29 -#define BM_CDCDR_HSI_TX_PODF (0x7 << 29) -#define BP_CDCDR_HSI_TX_SEL 28 -#define BM_CDCDR_HSI_TX_SEL (0x1 << 28) - -#define BP_CHSCCDR_IPU1_DI0_SEL 0 -#define BM_CHSCCDR_IPU1_DI0_SEL (0x7 << 0) -#define BP_CHSCCDR_IPU1_DI0_PRE_PODF 3 -#define BM_CHSCCDR_IPU1_DI0_PRE_PODF (0x7 << 3) -#define BP_CHSCCDR_IPU1_DI0_PRE_SEL 6 -#define BM_CHSCCDR_IPU1_DI0_PRE_SEL (0x7 << 6) -#define BP_CHSCCDR_IPU1_DI1_SEL 9 -#define BM_CHSCCDR_IPU1_DI1_SEL (0x7 << 9) -#define BP_CHSCCDR_IPU1_DI1_PRE_PODF 12 -#define BM_CHSCCDR_IPU1_DI1_PRE_PODF (0x7 << 12) -#define BP_CHSCCDR_IPU1_DI1_PRE_SEL 15 -#define BM_CHSCCDR_IPU1_DI1_PRE_SEL (0x7 << 15) - -#define BP_CSCDR2_IPU2_DI0_SEL 0 -#define BM_CSCDR2_IPU2_DI0_SEL (0x7) -#define BP_CSCDR2_IPU2_DI0_PRE_PODF 3 -#define BM_CSCDR2_IPU2_DI0_PRE_PODF (0x7 << 3) -#define BP_CSCDR2_IPU2_DI0_PRE_SEL 6 -#define BM_CSCDR2_IPU2_DI0_PRE_SEL (0x7 << 6) -#define BP_CSCDR2_IPU2_DI1_SEL 9 -#define BM_CSCDR2_IPU2_DI1_SEL (0x7 << 9) -#define BP_CSCDR2_IPU2_DI1_PRE_PODF 12 -#define BM_CSCDR2_IPU2_DI1_PRE_PODF (0x7 << 12) -#define BP_CSCDR2_IPU2_DI1_PRE_SEL 15 -#define BM_CSCDR2_IPU2_DI1_PRE_SEL (0x7 << 15) -#define BP_CSCDR2_ECSPI_CLK_PODF 19 -#define BM_CSCDR2_ECSPI_CLK_PODF (0x3f << 19) - -#define BP_CSCDR3_IPU1_HSP_SEL 9 -#define BM_CSCDR3_IPU1_HSP_SEL (0x3 << 9) -#define BP_CSCDR3_IPU1_HSP_PODF 11 -#define BM_CSCDR3_IPU1_HSP_PODF (0x7 << 11) -#define BP_CSCDR3_IPU2_HSP_SEL 14 -#define BM_CSCDR3_IPU2_HSP_SEL (0x3 << 14) -#define BP_CSCDR3_IPU2_HSP_PODF 16 -#define BM_CSCDR3_IPU2_HSP_PODF (0x7 << 16) - -#define BM_CDHIPR_AXI_PODF_BUSY (0x1 << 0) -#define BM_CDHIPR_AHB_PODF_BUSY (0x1 << 1) -#define BM_CDHIPR_MMDC_CH1_PODF_BUSY (0x1 << 2) -#define BM_CDHIPR_PERIPH2_SEL_BUSY (0x1 << 3) -#define BM_CDHIPR_MMDC_CH0_PODF_BUSY (0x1 << 4) -#define BM_CDHIPR_PERIPH_SEL_BUSY (0x1 << 5) -#define BM_CDHIPR_ARM_PODF_BUSY (0x1 << 16) - -#define BP_CLPCR_LPM 0 -#define BM_CLPCR_LPM (0x3 << 0) -#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) -#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) -#define BM_CLPCR_SBYOS (0x1 << 6) -#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) -#define BM_CLPCR_VSTBY (0x1 << 8) -#define BP_CLPCR_STBY_COUNT 9 -#define BM_CLPCR_STBY_COUNT (0x3 << 9) -#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) -#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) -#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) -#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) -#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) -#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) -#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) -#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) -#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) -#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) -#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) - -#define BP_CCOSR_CKO1_EN 7 -#define BP_CCOSR_CKO1_PODF 4 -#define BM_CCOSR_CKO1_PODF (0x7 << 4) -#define BP_CCOSR_CKO1_SEL 0 -#define BM_CCOSR_CKO1_SEL (0xf << 0) - -#define FREQ_480M 480000000 -#define FREQ_528M 528000000 -#define FREQ_594M 594000000 -#define FREQ_650M 650000000 -#define FREQ_1300M 1300000000 - -static struct clk pll1_sys; -static struct clk pll2_bus; -static struct clk pll3_usb_otg; -static struct clk pll4_audio; -static struct clk pll5_video; -static struct clk pll6_mlb; -static struct clk pll7_usb_host; -static struct clk pll8_enet; -static struct clk apbh_dma_clk; -static struct clk arm_clk; -static struct clk ipg_clk; -static struct clk ahb_clk; -static struct clk axi_clk; -static struct clk mmdc_ch0_axi_clk; -static struct clk mmdc_ch1_axi_clk; -static struct clk periph_clk; -static struct clk periph_pre_clk; -static struct clk periph_clk2_clk; -static struct clk periph2_clk; -static struct clk periph2_pre_clk; -static struct clk periph2_clk2_clk; -static struct clk gpu2d_core_clk; -static struct clk gpu3d_core_clk; -static struct clk gpu3d_shader_clk; -static struct clk ipg_perclk; -static struct clk emi_clk; -static struct clk emi_slow_clk; -static struct clk can1_clk; -static struct clk uart_clk; -static struct clk usdhc1_clk; -static struct clk usdhc2_clk; -static struct clk usdhc3_clk; -static struct clk usdhc4_clk; -static struct clk vpu_clk; -static struct clk hsi_tx_clk; -static struct clk ipu1_di0_pre_clk; -static struct clk ipu1_di1_pre_clk; -static struct clk ipu2_di0_pre_clk; -static struct clk ipu2_di1_pre_clk; -static struct clk ipu1_clk; -static struct clk ipu2_clk; -static struct clk ssi1_clk; -static struct clk ssi3_clk; -static struct clk esai_clk; -static struct clk ssi2_clk; -static struct clk spdif_clk; -static struct clk asrc_serial_clk; -static struct clk gpu2d_axi_clk; -static struct clk gpu3d_axi_clk; -static struct clk pcie_clk; -static struct clk vdo_axi_clk; -static struct clk ldb_di0_clk; -static struct clk ldb_di1_clk; -static struct clk ipu1_di0_clk; -static struct clk ipu1_di1_clk; -static struct clk ipu2_di0_clk; -static struct clk ipu2_di1_clk; -static struct clk enfc_clk; -static struct clk cko1_clk; -static struct clk dummy_clk = {}; - -static unsigned long external_high_reference; -static unsigned long external_low_reference; -static unsigned long oscillator_reference; - -static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) -{ - return oscillator_reference; -} - -static unsigned long get_high_reference_clock_rate(struct clk *clk) -{ - return external_high_reference; -} - -static unsigned long get_low_reference_clock_rate(struct clk *clk) -{ - return external_low_reference; -} - -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static struct clk osc_clk = { - .get_rate = get_oscillator_reference_clock_rate, -}; - -static inline void __iomem *pll_get_reg_addr(struct clk *pll) -{ - if (pll == &pll1_sys) - return PLL1_SYS; - else if (pll == &pll2_bus) - return PLL2_BUS; - else if (pll == &pll3_usb_otg) - return PLL3_USB_OTG; - else if (pll == &pll4_audio) - return PLL4_AUDIO; - else if (pll == &pll5_video) - return PLL5_VIDEO; - else if (pll == &pll6_mlb) - return PLL6_MLB; - else if (pll == &pll7_usb_host) - return PLL7_USB_HOST; - else if (pll == &pll8_enet) - return PLL8_ENET; - else - BUG(); - - return NULL; -} - -static int pll_enable(struct clk *clk) -{ - int timeout = 0x100000; - void __iomem *reg; - u32 val; - - reg = pll_get_reg_addr(clk); - val = readl_relaxed(reg); - val &= ~BM_PLL_BYPASS; - val &= ~BM_PLL_POWER_DOWN; - /* 480MHz PLLs have the opposite definition for power bit */ - if (clk == &pll3_usb_otg || clk == &pll7_usb_host) - val |= BM_PLL_POWER_DOWN; - writel_relaxed(val, reg); - - /* Wait for PLL to lock */ - while (!(readl_relaxed(reg) & BM_PLL_LOCK) && --timeout) - cpu_relax(); - - if (unlikely(!timeout)) - return -EBUSY; - - /* Enable the PLL output now */ - val = readl_relaxed(reg); - val |= BM_PLL_ENABLE; - writel_relaxed(val, reg); - - return 0; -} - -static void pll_disable(struct clk *clk) -{ - void __iomem *reg; - u32 val; - - reg = pll_get_reg_addr(clk); - val = readl_relaxed(reg); - val &= ~BM_PLL_ENABLE; - val |= BM_PLL_BYPASS; - val |= BM_PLL_POWER_DOWN; - if (clk == &pll3_usb_otg || clk == &pll7_usb_host) - val &= ~BM_PLL_POWER_DOWN; - writel_relaxed(val, reg); -} - -static unsigned long pll1_sys_get_rate(struct clk *clk) -{ - u32 div = (readl_relaxed(PLL1_SYS) & BM_PLL_SYS_DIV_SELECT) >> - BP_PLL_SYS_DIV_SELECT; - - return clk_get_rate(clk->parent) * div / 2; -} - -static int pll1_sys_set_rate(struct clk *clk, unsigned long rate) -{ - u32 val, div; - - if (rate < FREQ_650M || rate > FREQ_1300M) - return -EINVAL; - - div = rate * 2 / clk_get_rate(clk->parent); - val = readl_relaxed(PLL1_SYS); - val &= ~BM_PLL_SYS_DIV_SELECT; - val |= div << BP_PLL_SYS_DIV_SELECT; - writel_relaxed(val, PLL1_SYS); - - return 0; -} - -static unsigned long pll8_enet_get_rate(struct clk *clk) -{ - u32 div = (readl_relaxed(PLL8_ENET) & BM_PLL_ENET_DIV_SELECT) >> - BP_PLL_ENET_DIV_SELECT; - - switch (div) { - case 0: - return 25000000; - case 1: - return 50000000; - case 2: - return 100000000; - case 3: - return 125000000; - } - - return 0; -} - -static int pll8_enet_set_rate(struct clk *clk, unsigned long rate) -{ - u32 val, div; - - switch (rate) { - case 25000000: - div = 0; - break; - case 50000000: - div = 1; - break; - case 100000000: - div = 2; - break; - case 125000000: - div = 3; - break; - default: - return -EINVAL; - } - - val = readl_relaxed(PLL8_ENET); - val &= ~BM_PLL_ENET_DIV_SELECT; - val |= div << BP_PLL_ENET_DIV_SELECT; - writel_relaxed(val, PLL8_ENET); - - return 0; -} - -static unsigned long pll_av_get_rate(struct clk *clk) -{ - void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; - unsigned long parent_rate = clk_get_rate(clk->parent); - u32 mfn = readl_relaxed(reg + PLL_NUM_OFFSET); - u32 mfd = readl_relaxed(reg + PLL_DENOM_OFFSET); - u32 div = (readl_relaxed(reg) & BM_PLL_AV_DIV_SELECT) >> - BP_PLL_AV_DIV_SELECT; - - return (parent_rate * div) + ((parent_rate / mfd) * mfn); -} - -static int pll_av_set_rate(struct clk *clk, unsigned long rate) -{ - void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO; - unsigned int parent_rate = clk_get_rate(clk->parent); - u32 val, div; - u32 mfn, mfd = 1000000; - s64 temp64; - - if (rate < FREQ_650M || rate > FREQ_1300M) - return -EINVAL; - - div = rate / parent_rate; - temp64 = (u64) (rate - div * parent_rate); - temp64 *= mfd; - do_div(temp64, parent_rate); - mfn = temp64; - - val = readl_relaxed(reg); - val &= ~BM_PLL_AV_DIV_SELECT; - val |= div << BP_PLL_AV_DIV_SELECT; - writel_relaxed(val, reg); - writel_relaxed(mfn, reg + PLL_NUM_OFFSET); - writel_relaxed(mfd, reg + PLL_DENOM_OFFSET); - - return 0; -} - -static void __iomem *pll_get_div_reg_bit(struct clk *clk, u32 *bp, u32 *bm) -{ - void __iomem *reg; - - if (clk == &pll2_bus) { - reg = PLL2_BUS; - *bp = BP_PLL_BUS_DIV_SELECT; - *bm = BM_PLL_BUS_DIV_SELECT; - } else if (clk == &pll3_usb_otg) { - reg = PLL3_USB_OTG; - *bp = BP_PLL_USB_DIV_SELECT; - *bm = BM_PLL_USB_DIV_SELECT; - } else if (clk == &pll7_usb_host) { - reg = PLL7_USB_HOST; - *bp = BP_PLL_USB_DIV_SELECT; - *bm = BM_PLL_USB_DIV_SELECT; - } else { - BUG(); - } - - return reg; -} - -static unsigned long pll_get_rate(struct clk *clk) -{ - void __iomem *reg; - u32 div, bp, bm; - - reg = pll_get_div_reg_bit(clk, &bp, &bm); - div = (readl_relaxed(reg) & bm) >> bp; - - return (div == 1) ? clk_get_rate(clk->parent) * 22 : - clk_get_rate(clk->parent) * 20; -} - -static int pll_set_rate(struct clk *clk, unsigned long rate) -{ - void __iomem *reg; - u32 val, div, bp, bm; - - if (rate == FREQ_528M) - div = 1; - else if (rate == FREQ_480M) - div = 0; - else - return -EINVAL; - - reg = pll_get_div_reg_bit(clk, &bp, &bm); - val = readl_relaxed(reg); - val &= ~bm; - val |= div << bp; - writel_relaxed(val, reg); - - return 0; -} - -#define pll2_bus_get_rate pll_get_rate -#define pll2_bus_set_rate pll_set_rate -#define pll3_usb_otg_get_rate pll_get_rate -#define pll3_usb_otg_set_rate pll_set_rate -#define pll7_usb_host_get_rate pll_get_rate -#define pll7_usb_host_set_rate pll_set_rate -#define pll4_audio_get_rate pll_av_get_rate -#define pll4_audio_set_rate pll_av_set_rate -#define pll5_video_get_rate pll_av_get_rate -#define pll5_video_set_rate pll_av_set_rate -#define pll6_mlb_get_rate NULL -#define pll6_mlb_set_rate NULL - -#define DEF_PLL(name) \ - static struct clk name = { \ - .enable = pll_enable, \ - .disable = pll_disable, \ - .get_rate = name##_get_rate, \ - .set_rate = name##_set_rate, \ - .parent = &osc_clk, \ - } - -DEF_PLL(pll1_sys); -DEF_PLL(pll2_bus); -DEF_PLL(pll3_usb_otg); -DEF_PLL(pll4_audio); -DEF_PLL(pll5_video); -DEF_PLL(pll6_mlb); -DEF_PLL(pll7_usb_host); -DEF_PLL(pll8_enet); - -static unsigned long pfd_get_rate(struct clk *clk) -{ - u64 tmp = (u64) clk_get_rate(clk->parent) * 18; - u32 frac, bp_frac; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - bp_frac = clk->enable_shift - 7; - frac = readl_relaxed(clk->enable_reg) >> bp_frac & PFD_FRAC_MASK; - do_div(tmp, frac); - - return tmp; -} - -static int pfd_set_rate(struct clk *clk, unsigned long rate) -{ - u32 val, frac, bp_frac; - u64 tmp = (u64) clk_get_rate(clk->parent) * 18; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - /* - * Round up the divider so that we don't set a rate - * higher than what is requested - */ - tmp += rate / 2; - do_div(tmp, rate); - frac = tmp; - frac = (frac < 12) ? 12 : frac; - frac = (frac > 35) ? 35 : frac; - - /* - * The frac field always starts from 7 bits lower - * position of enable bit - */ - bp_frac = clk->enable_shift - 7; - val = readl_relaxed(clk->enable_reg); - val &= ~(PFD_FRAC_MASK << bp_frac); - val |= frac << bp_frac; - writel_relaxed(val, clk->enable_reg); - - tmp = (u64) clk_get_rate(clk->parent) * 18; - do_div(tmp, frac); - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.disable(&apbh_dma_clk); - - return 0; -} - -static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) -{ - u32 frac; - u64 tmp; - - tmp = (u64) clk_get_rate(clk->parent) * 18; - tmp += rate / 2; - do_div(tmp, rate); - frac = tmp; - frac = (frac < 12) ? 12 : frac; - frac = (frac > 35) ? 35 : frac; - tmp = (u64) clk_get_rate(clk->parent) * 18; - do_div(tmp, frac); - - return tmp; -} - -static int pfd_enable(struct clk *clk) -{ - u32 val; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - val = readl_relaxed(clk->enable_reg); - val &= ~(1 << clk->enable_shift); - writel_relaxed(val, clk->enable_reg); - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.disable(&apbh_dma_clk); - - return 0; -} - -static void pfd_disable(struct clk *clk) -{ - u32 val; - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.enable(&apbh_dma_clk); - - val = readl_relaxed(clk->enable_reg); - val |= 1 << clk->enable_shift; - writel_relaxed(val, clk->enable_reg); - - if (apbh_dma_clk.usecount == 0) - apbh_dma_clk.disable(&apbh_dma_clk); -} - -#define DEF_PFD(name, er, es, p) \ - static struct clk name = { \ - .enable_reg = er, \ - .enable_shift = es, \ - .enable = pfd_enable, \ - .disable = pfd_disable, \ - .get_rate = pfd_get_rate, \ - .set_rate = pfd_set_rate, \ - .round_rate = pfd_round_rate, \ - .parent = p, \ - } - -DEF_PFD(pll2_pfd_352m, PFD_528, PFD0, &pll2_bus); -DEF_PFD(pll2_pfd_594m, PFD_528, PFD1, &pll2_bus); -DEF_PFD(pll2_pfd_400m, PFD_528, PFD2, &pll2_bus); -DEF_PFD(pll3_pfd_720m, PFD_480, PFD0, &pll3_usb_otg); -DEF_PFD(pll3_pfd_540m, PFD_480, PFD1, &pll3_usb_otg); -DEF_PFD(pll3_pfd_508m, PFD_480, PFD2, &pll3_usb_otg); -DEF_PFD(pll3_pfd_454m, PFD_480, PFD3, &pll3_usb_otg); - -static unsigned long twd_clk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 2; -} - -static struct clk twd_clk = { - .parent = &arm_clk, - .get_rate = twd_clk_get_rate, -}; - -static unsigned long pll2_200m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 2; -} - -static struct clk pll2_200m = { - .parent = &pll2_pfd_400m, - .get_rate = pll2_200m_get_rate, -}; - -static unsigned long pll3_120m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 4; -} - -static struct clk pll3_120m = { - .parent = &pll3_usb_otg, - .get_rate = pll3_120m_get_rate, -}; - -static unsigned long pll3_80m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 6; -} - -static struct clk pll3_80m = { - .parent = &pll3_usb_otg, - .get_rate = pll3_80m_get_rate, -}; - -static unsigned long pll3_60m_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 8; -} - -static struct clk pll3_60m = { - .parent = &pll3_usb_otg, - .get_rate = pll3_60m_get_rate, -}; - -static int pll1_sw_clk_set_parent(struct clk *clk, struct clk *parent) -{ - u32 val = readl_relaxed(CCSR); - - if (parent == &pll1_sys) { - val &= ~BM_CCSR_PLL1_SW_SEL; - val &= ~BM_CCSR_STEP_SEL; - } else if (parent == &osc_clk) { - val |= BM_CCSR_PLL1_SW_SEL; - val &= ~BM_CCSR_STEP_SEL; - } else if (parent == &pll2_pfd_400m) { - val |= BM_CCSR_PLL1_SW_SEL; - val |= BM_CCSR_STEP_SEL; - } else { - return -EINVAL; - } - - writel_relaxed(val, CCSR); - - return 0; -} - -static struct clk pll1_sw_clk = { - .parent = &pll1_sys, - .set_parent = pll1_sw_clk_set_parent, -}; - -static void calc_pred_podf_dividers(u32 div, u32 *pred, u32 *podf) -{ - u32 min_pred, temp_pred, old_err, err; - - if (div >= 512) { - *pred = 8; - *podf = 64; - } else if (div >= 8) { - min_pred = (div - 1) / 64 + 1; - old_err = 8; - for (temp_pred = 8; temp_pred >= min_pred; temp_pred--) { - err = div % temp_pred; - if (err == 0) { - *pred = temp_pred; - break; - } - err = temp_pred - err; - if (err < old_err) { - old_err = err; - *pred = temp_pred; - } - } - *podf = (div + *pred - 1) / *pred; - } else if (div < 8) { - *pred = div; - *podf = 1; - } -} - -static int _clk_enable(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg |= 0x3 << clk->enable_shift; - writel_relaxed(reg, clk->enable_reg); - - return 0; -} - -static void _clk_disable(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg &= ~(0x3 << clk->enable_shift); - writel_relaxed(reg, clk->enable_reg); -} - -static int _clk_enable_1b(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg |= 0x1 << clk->enable_shift; - writel_relaxed(reg, clk->enable_reg); - - return 0; -} - -static void _clk_disable_1b(struct clk *clk) -{ - u32 reg; - reg = readl_relaxed(clk->enable_reg); - reg &= ~(0x1 << clk->enable_shift); - writel_relaxed(reg, clk->enable_reg); -} - -struct divider { - struct clk *clk; - void __iomem *reg; - u32 bp_pred; - u32 bm_pred; - u32 bp_podf; - u32 bm_podf; -}; - -#define DEF_CLK_DIV1(d, c, r, b) \ - static struct divider d = { \ - .clk = c, \ - .reg = r, \ - .bp_podf = BP_##r##_##b##_PODF, \ - .bm_podf = BM_##r##_##b##_PODF, \ - } - -DEF_CLK_DIV1(arm_div, &arm_clk, CACRR, ARM); -DEF_CLK_DIV1(ipg_div, &ipg_clk, CBCDR, IPG); -DEF_CLK_DIV1(ahb_div, &ahb_clk, CBCDR, AHB); -DEF_CLK_DIV1(axi_div, &axi_clk, CBCDR, AXI); -DEF_CLK_DIV1(mmdc_ch0_axi_div, &mmdc_ch0_axi_clk, CBCDR, MMDC_CH0_AXI); -DEF_CLK_DIV1(mmdc_ch1_axi_div, &mmdc_ch1_axi_clk, CBCDR, MMDC_CH1_AXI); -DEF_CLK_DIV1(periph_clk2_div, &periph_clk2_clk, CBCDR, PERIPH_CLK2); -DEF_CLK_DIV1(periph2_clk2_div, &periph2_clk2_clk, CBCDR, PERIPH2_CLK2); -DEF_CLK_DIV1(gpu2d_core_div, &gpu2d_core_clk, CBCMR, GPU2D_CORE); -DEF_CLK_DIV1(gpu3d_core_div, &gpu3d_core_clk, CBCMR, GPU3D_CORE); -DEF_CLK_DIV1(gpu3d_shader_div, &gpu3d_shader_clk, CBCMR, GPU3D_SHADER); -DEF_CLK_DIV1(ipg_perclk_div, &ipg_perclk, CSCMR1, PERCLK); -DEF_CLK_DIV1(emi_div, &emi_clk, CSCMR1, EMI); -DEF_CLK_DIV1(emi_slow_div, &emi_slow_clk, CSCMR1, EMI_SLOW); -DEF_CLK_DIV1(can_div, &can1_clk, CSCMR2, CAN); -DEF_CLK_DIV1(uart_div, &uart_clk, CSCDR1, UART); -DEF_CLK_DIV1(usdhc1_div, &usdhc1_clk, CSCDR1, USDHC1); -DEF_CLK_DIV1(usdhc2_div, &usdhc2_clk, CSCDR1, USDHC2); -DEF_CLK_DIV1(usdhc3_div, &usdhc3_clk, CSCDR1, USDHC3); -DEF_CLK_DIV1(usdhc4_div, &usdhc4_clk, CSCDR1, USDHC4); -DEF_CLK_DIV1(vpu_div, &vpu_clk, CSCDR1, VPU_AXI); -DEF_CLK_DIV1(hsi_tx_div, &hsi_tx_clk, CDCDR, HSI_TX); -DEF_CLK_DIV1(ipu1_di0_pre_div, &ipu1_di0_pre_clk, CHSCCDR, IPU1_DI0_PRE); -DEF_CLK_DIV1(ipu1_di1_pre_div, &ipu1_di1_pre_clk, CHSCCDR, IPU1_DI1_PRE); -DEF_CLK_DIV1(ipu2_di0_pre_div, &ipu2_di0_pre_clk, CSCDR2, IPU2_DI0_PRE); -DEF_CLK_DIV1(ipu2_di1_pre_div, &ipu2_di1_pre_clk, CSCDR2, IPU2_DI1_PRE); -DEF_CLK_DIV1(ipu1_div, &ipu1_clk, CSCDR3, IPU1_HSP); -DEF_CLK_DIV1(ipu2_div, &ipu2_clk, CSCDR3, IPU2_HSP); -DEF_CLK_DIV1(cko1_div, &cko1_clk, CCOSR, CKO1); - -#define DEF_CLK_DIV2(d, c, r, b) \ - static struct divider d = { \ - .clk = c, \ - .reg = r, \ - .bp_pred = BP_##r##_##b##_PRED, \ - .bm_pred = BM_##r##_##b##_PRED, \ - .bp_podf = BP_##r##_##b##_PODF, \ - .bm_podf = BM_##r##_##b##_PODF, \ - } - -DEF_CLK_DIV2(ssi1_div, &ssi1_clk, CS1CDR, SSI1); -DEF_CLK_DIV2(ssi3_div, &ssi3_clk, CS1CDR, SSI3); -DEF_CLK_DIV2(esai_div, &esai_clk, CS1CDR, ESAI); -DEF_CLK_DIV2(ssi2_div, &ssi2_clk, CS2CDR, SSI2); -DEF_CLK_DIV2(enfc_div, &enfc_clk, CS2CDR, ENFC); -DEF_CLK_DIV2(spdif_div, &spdif_clk, CDCDR, SPDIF); -DEF_CLK_DIV2(asrc_serial_div, &asrc_serial_clk, CDCDR, ASRC_SERIAL); - -static struct divider *dividers[] = { - &arm_div, - &ipg_div, - &ahb_div, - &axi_div, - &mmdc_ch0_axi_div, - &mmdc_ch1_axi_div, - &periph_clk2_div, - &periph2_clk2_div, - &gpu2d_core_div, - &gpu3d_core_div, - &gpu3d_shader_div, - &ipg_perclk_div, - &emi_div, - &emi_slow_div, - &can_div, - &uart_div, - &usdhc1_div, - &usdhc2_div, - &usdhc3_div, - &usdhc4_div, - &vpu_div, - &hsi_tx_div, - &ipu1_di0_pre_div, - &ipu1_di1_pre_div, - &ipu2_di0_pre_div, - &ipu2_di1_pre_div, - &ipu1_div, - &ipu2_div, - &ssi1_div, - &ssi3_div, - &esai_div, - &ssi2_div, - &enfc_div, - &spdif_div, - &asrc_serial_div, - &cko1_div, -}; - -static unsigned long ldb_di_clk_get_rate(struct clk *clk) -{ - u32 val = readl_relaxed(CSCMR2); - - val &= (clk == &ldb_di0_clk) ? BM_CSCMR2_LDB_DI0_IPU_DIV : - BM_CSCMR2_LDB_DI1_IPU_DIV; - if (val) - return clk_get_rate(clk->parent) / 7; - else - return clk_get_rate(clk->parent) * 2 / 7; -} - -static int ldb_di_clk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - u32 val = readl_relaxed(CSCMR2); - - if (rate * 7 <= parent_rate + parent_rate / 20) - val |= BM_CSCMR2_LDB_DI0_IPU_DIV; - else - val &= ~BM_CSCMR2_LDB_DI0_IPU_DIV; - - writel_relaxed(val, CSCMR2); - - return 0; -} - -static unsigned long ldb_di_clk_round_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - - if (rate * 7 <= parent_rate + parent_rate / 20) - return parent_rate / 7; - else - return 2 * parent_rate / 7; -} - -static unsigned long _clk_get_rate(struct clk *clk) -{ - struct divider *d; - u32 val, pred, podf; - int i, num; - - if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) - return ldb_di_clk_get_rate(clk); - - num = ARRAY_SIZE(dividers); - for (i = 0; i < num; i++) - if (dividers[i]->clk == clk) { - d = dividers[i]; - break; - } - if (i == num) - return clk_get_rate(clk->parent); - - val = readl_relaxed(d->reg); - pred = ((val & d->bm_pred) >> d->bp_pred) + 1; - podf = ((val & d->bm_podf) >> d->bp_podf) + 1; - - return clk_get_rate(clk->parent) / (pred * podf); -} - -static int clk_busy_wait(struct clk *clk) -{ - int timeout = 0x100000; - u32 bm; - - if (clk == &axi_clk) - bm = BM_CDHIPR_AXI_PODF_BUSY; - else if (clk == &ahb_clk) - bm = BM_CDHIPR_AHB_PODF_BUSY; - else if (clk == &mmdc_ch0_axi_clk) - bm = BM_CDHIPR_MMDC_CH0_PODF_BUSY; - else if (clk == &periph_clk) - bm = BM_CDHIPR_PERIPH_SEL_BUSY; - else if (clk == &arm_clk) - bm = BM_CDHIPR_ARM_PODF_BUSY; - else - return -EINVAL; - - while ((readl_relaxed(CDHIPR) & bm) && --timeout) - cpu_relax(); - - if (unlikely(!timeout)) - return -EBUSY; - - return 0; -} - -static int _clk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - struct divider *d; - u32 val, div, max_div, pred = 0, podf; - int i, num; - - if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) - return ldb_di_clk_set_rate(clk, rate); - - num = ARRAY_SIZE(dividers); - for (i = 0; i < num; i++) - if (dividers[i]->clk == clk) { - d = dividers[i]; - break; - } - if (i == num) - return -EINVAL; - - max_div = ((d->bm_pred >> d->bp_pred) + 1) * - ((d->bm_podf >> d->bp_podf) + 1); - - div = parent_rate / rate; - if (div == 0) - div++; - - if ((parent_rate / div != rate) || div > max_div) - return -EINVAL; - - if (d->bm_pred) { - calc_pred_podf_dividers(div, &pred, &podf); - } else { - pred = 1; - podf = div; - } - - val = readl_relaxed(d->reg); - val &= ~(d->bm_pred | d->bm_podf); - val |= (pred - 1) << d->bp_pred | (podf - 1) << d->bp_podf; - writel_relaxed(val, d->reg); - - if (clk == &axi_clk || clk == &ahb_clk || - clk == &mmdc_ch0_axi_clk || clk == &arm_clk) - return clk_busy_wait(clk); - - return 0; -} - -static unsigned long _clk_round_rate(struct clk *clk, unsigned long rate) -{ - unsigned long parent_rate = clk_get_rate(clk->parent); - u32 div = parent_rate / rate; - u32 div_max, pred = 0, podf; - struct divider *d; - int i, num; - - if (clk == &ldb_di0_clk || clk == &ldb_di1_clk) - return ldb_di_clk_round_rate(clk, rate); - - num = ARRAY_SIZE(dividers); - for (i = 0; i < num; i++) - if (dividers[i]->clk == clk) { - d = dividers[i]; - break; - } - if (i == num) - return -EINVAL; - - if (div == 0 || parent_rate % rate) - div++; - - if (d->bm_pred) { - calc_pred_podf_dividers(div, &pred, &podf); - div = pred * podf; - } else { - div_max = (d->bm_podf >> d->bp_podf) + 1; - if (div > div_max) - div = div_max; - } - - return parent_rate / div; -} - -struct multiplexer { - struct clk *clk; - void __iomem *reg; - u32 bp; - u32 bm; - int pnum; - struct clk *parents[]; -}; - -static struct multiplexer axi_mux = { - .clk = &axi_clk, - .reg = CBCDR, - .bp = BP_CBCDR_AXI_SEL, - .bm = BM_CBCDR_AXI_SEL, - .parents = { - &periph_clk, - &pll2_pfd_400m, - &pll3_pfd_540m, - NULL - }, -}; - -static struct multiplexer periph_mux = { - .clk = &periph_clk, - .reg = CBCDR, - .bp = BP_CBCDR_PERIPH_CLK_SEL, - .bm = BM_CBCDR_PERIPH_CLK_SEL, - .parents = { - &periph_pre_clk, - &periph_clk2_clk, - NULL - }, -}; - -static struct multiplexer periph_pre_mux = { - .clk = &periph_pre_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PRE_PERIPH_CLK_SEL, - .bm = BM_CBCMR_PRE_PERIPH_CLK_SEL, - .parents = { - &pll2_bus, - &pll2_pfd_400m, - &pll2_pfd_352m, - &pll2_200m, - NULL - }, -}; - -static struct multiplexer periph_clk2_mux = { - .clk = &periph_clk2_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PERIPH_CLK2_SEL, - .bm = BM_CBCMR_PERIPH_CLK2_SEL, - .parents = { - &pll3_usb_otg, - &osc_clk, - NULL - }, -}; - -static struct multiplexer periph2_mux = { - .clk = &periph2_clk, - .reg = CBCDR, - .bp = BP_CBCDR_PERIPH2_CLK_SEL, - .bm = BM_CBCDR_PERIPH2_CLK_SEL, - .parents = { - &periph2_pre_clk, - &periph2_clk2_clk, - NULL - }, -}; - -static struct multiplexer periph2_pre_mux = { - .clk = &periph2_pre_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PRE_PERIPH2_CLK_SEL, - .bm = BM_CBCMR_PRE_PERIPH2_CLK_SEL, - .parents = { - &pll2_bus, - &pll2_pfd_400m, - &pll2_pfd_352m, - &pll2_200m, - NULL - }, -}; - -static struct multiplexer periph2_clk2_mux = { - .clk = &periph2_clk2_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PERIPH2_CLK2_SEL, - .bm = BM_CBCMR_PERIPH2_CLK2_SEL, - .parents = { - &pll3_usb_otg, - &osc_clk, - NULL - }, -}; - -static struct multiplexer gpu2d_axi_mux = { - .clk = &gpu2d_axi_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU2D_AXI_SEL, - .bm = BM_CBCMR_GPU2D_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer gpu3d_axi_mux = { - .clk = &gpu3d_axi_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU3D_AXI_SEL, - .bm = BM_CBCMR_GPU3D_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer gpu3d_core_mux = { - .clk = &gpu3d_core_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU3D_CORE_SEL, - .bm = BM_CBCMR_GPU3D_CORE_SEL, - .parents = { - &mmdc_ch0_axi_clk, - &pll3_usb_otg, - &pll2_pfd_594m, - &pll2_pfd_400m, - NULL - }, -}; - -static struct multiplexer gpu3d_shader_mux = { - .clk = &gpu3d_shader_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU3D_SHADER_SEL, - .bm = BM_CBCMR_GPU3D_SHADER_SEL, - .parents = { - &mmdc_ch0_axi_clk, - &pll3_usb_otg, - &pll2_pfd_594m, - &pll3_pfd_720m, - NULL - }, -}; - -static struct multiplexer pcie_axi_mux = { - .clk = &pcie_clk, - .reg = CBCMR, - .bp = BP_CBCMR_PCIE_AXI_SEL, - .bm = BM_CBCMR_PCIE_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer vdo_axi_mux = { - .clk = &vdo_axi_clk, - .reg = CBCMR, - .bp = BP_CBCMR_VDO_AXI_SEL, - .bm = BM_CBCMR_VDO_AXI_SEL, - .parents = { - &axi_clk, - &ahb_clk, - NULL - }, -}; - -static struct multiplexer vpu_axi_mux = { - .clk = &vpu_clk, - .reg = CBCMR, - .bp = BP_CBCMR_VPU_AXI_SEL, - .bm = BM_CBCMR_VPU_AXI_SEL, - .parents = { - &axi_clk, - &pll2_pfd_400m, - &pll2_pfd_352m, - NULL - }, -}; - -static struct multiplexer gpu2d_core_mux = { - .clk = &gpu2d_core_clk, - .reg = CBCMR, - .bp = BP_CBCMR_GPU2D_CORE_SEL, - .bm = BM_CBCMR_GPU2D_CORE_SEL, - .parents = { - &axi_clk, - &pll3_usb_otg, - &pll2_pfd_352m, - &pll2_pfd_400m, - NULL - }, -}; - -#define DEF_SSI_MUX(id) \ - static struct multiplexer ssi##id##_mux = { \ - .clk = &ssi##id##_clk, \ - .reg = CSCMR1, \ - .bp = BP_CSCMR1_SSI##id##_SEL, \ - .bm = BM_CSCMR1_SSI##id##_SEL, \ - .parents = { \ - &pll3_pfd_508m, \ - &pll3_pfd_454m, \ - &pll4_audio, \ - NULL \ - }, \ - } - -DEF_SSI_MUX(1); -DEF_SSI_MUX(2); -DEF_SSI_MUX(3); - -#define DEF_USDHC_MUX(id) \ - static struct multiplexer usdhc##id##_mux = { \ - .clk = &usdhc##id##_clk, \ - .reg = CSCMR1, \ - .bp = BP_CSCMR1_USDHC##id##_SEL, \ - .bm = BM_CSCMR1_USDHC##id##_SEL, \ - .parents = { \ - &pll2_pfd_400m, \ - &pll2_pfd_352m, \ - NULL \ - }, \ - } - -DEF_USDHC_MUX(1); -DEF_USDHC_MUX(2); -DEF_USDHC_MUX(3); -DEF_USDHC_MUX(4); - -static struct multiplexer emi_mux = { - .clk = &emi_clk, - .reg = CSCMR1, - .bp = BP_CSCMR1_EMI_SEL, - .bm = BM_CSCMR1_EMI_SEL, - .parents = { - &axi_clk, - &pll3_usb_otg, - &pll2_pfd_400m, - &pll2_pfd_352m, - NULL - }, -}; - -static struct multiplexer emi_slow_mux = { - .clk = &emi_slow_clk, - .reg = CSCMR1, - .bp = BP_CSCMR1_EMI_SLOW_SEL, - .bm = BM_CSCMR1_EMI_SLOW_SEL, - .parents = { - &axi_clk, - &pll3_usb_otg, - &pll2_pfd_400m, - &pll2_pfd_352m, - NULL - }, -}; - -static struct multiplexer esai_mux = { - .clk = &esai_clk, - .reg = CSCMR2, - .bp = BP_CSCMR2_ESAI_SEL, - .bm = BM_CSCMR2_ESAI_SEL, - .parents = { - &pll4_audio, - &pll3_pfd_508m, - &pll3_pfd_454m, - &pll3_usb_otg, - NULL - }, -}; - -#define DEF_LDB_DI_MUX(id) \ - static struct multiplexer ldb_di##id##_mux = { \ - .clk = &ldb_di##id##_clk, \ - .reg = CS2CDR, \ - .bp = BP_CS2CDR_LDB_DI##id##_SEL, \ - .bm = BM_CS2CDR_LDB_DI##id##_SEL, \ - .parents = { \ - &pll5_video, \ - &pll2_pfd_352m, \ - &pll2_pfd_400m, \ - &pll3_pfd_540m, \ - &pll3_usb_otg, \ - NULL \ - }, \ - } - -DEF_LDB_DI_MUX(0); -DEF_LDB_DI_MUX(1); - -static struct multiplexer enfc_mux = { - .clk = &enfc_clk, - .reg = CS2CDR, - .bp = BP_CS2CDR_ENFC_SEL, - .bm = BM_CS2CDR_ENFC_SEL, - .parents = { - &pll2_pfd_352m, - &pll2_bus, - &pll3_usb_otg, - &pll2_pfd_400m, - NULL - }, -}; - -static struct multiplexer spdif_mux = { - .clk = &spdif_clk, - .reg = CDCDR, - .bp = BP_CDCDR_SPDIF_SEL, - .bm = BM_CDCDR_SPDIF_SEL, - .parents = { - &pll4_audio, - &pll3_pfd_508m, - &pll3_pfd_454m, - &pll3_usb_otg, - NULL - }, -}; - -static struct multiplexer asrc_serial_mux = { - .clk = &asrc_serial_clk, - .reg = CDCDR, - .bp = BP_CDCDR_ASRC_SERIAL_SEL, - .bm = BM_CDCDR_ASRC_SERIAL_SEL, - .parents = { - &pll4_audio, - &pll3_pfd_508m, - &pll3_pfd_454m, - &pll3_usb_otg, - NULL - }, -}; - -static struct multiplexer hsi_tx_mux = { - .clk = &hsi_tx_clk, - .reg = CDCDR, - .bp = BP_CDCDR_HSI_TX_SEL, - .bm = BM_CDCDR_HSI_TX_SEL, - .parents = { - &pll3_120m, - &pll2_pfd_400m, - NULL - }, -}; - -#define DEF_IPU_DI_PRE_MUX(r, i, d) \ - static struct multiplexer ipu##i##_di##d##_pre_mux = { \ - .clk = &ipu##i##_di##d##_pre_clk, \ - .reg = r, \ - .bp = BP_##r##_IPU##i##_DI##d##_PRE_SEL, \ - .bm = BM_##r##_IPU##i##_DI##d##_PRE_SEL, \ - .parents = { \ - &mmdc_ch0_axi_clk, \ - &pll3_usb_otg, \ - &pll5_video, \ - &pll2_pfd_352m, \ - &pll2_pfd_400m, \ - &pll3_pfd_540m, \ - NULL \ - }, \ - } - -DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 0); -DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 1); -DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 0); -DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 1); - -#define DEF_IPU_DI_MUX(r, i, d) \ - static struct multiplexer ipu##i##_di##d##_mux = { \ - .clk = &ipu##i##_di##d##_clk, \ - .reg = r, \ - .bp = BP_##r##_IPU##i##_DI##d##_SEL, \ - .bm = BM_##r##_IPU##i##_DI##d##_SEL, \ - .parents = { \ - &ipu##i##_di##d##_pre_clk, \ - &dummy_clk, \ - &dummy_clk, \ - &ldb_di0_clk, \ - &ldb_di1_clk, \ - NULL \ - }, \ - } - -DEF_IPU_DI_MUX(CHSCCDR, 1, 0); -DEF_IPU_DI_MUX(CHSCCDR, 1, 1); -DEF_IPU_DI_MUX(CSCDR2, 2, 0); -DEF_IPU_DI_MUX(CSCDR2, 2, 1); - -#define DEF_IPU_MUX(id) \ - static struct multiplexer ipu##id##_mux = { \ - .clk = &ipu##id##_clk, \ - .reg = CSCDR3, \ - .bp = BP_CSCDR3_IPU##id##_HSP_SEL, \ - .bm = BM_CSCDR3_IPU##id##_HSP_SEL, \ - .parents = { \ - &mmdc_ch0_axi_clk, \ - &pll2_pfd_400m, \ - &pll3_120m, \ - &pll3_pfd_540m, \ - NULL \ - }, \ - } - -DEF_IPU_MUX(1); -DEF_IPU_MUX(2); - -static struct multiplexer cko1_mux = { - .clk = &cko1_clk, - .reg = CCOSR, - .bp = BP_CCOSR_CKO1_SEL, - .bm = BM_CCOSR_CKO1_SEL, - .parents = { - &pll3_usb_otg, - &pll2_bus, - &pll1_sys, - &pll5_video, - &dummy_clk, - &axi_clk, - &enfc_clk, - &ipu1_di0_clk, - &ipu1_di1_clk, - &ipu2_di0_clk, - &ipu2_di1_clk, - &ahb_clk, - &ipg_clk, - &ipg_perclk, - &ckil_clk, - &pll4_audio, - NULL - }, -}; - -static struct multiplexer *multiplexers[] = { - &axi_mux, - &periph_mux, - &periph_pre_mux, - &periph_clk2_mux, - &periph2_mux, - &periph2_pre_mux, - &periph2_clk2_mux, - &gpu2d_axi_mux, - &gpu3d_axi_mux, - &gpu3d_core_mux, - &gpu3d_shader_mux, - &pcie_axi_mux, - &vdo_axi_mux, - &vpu_axi_mux, - &gpu2d_core_mux, - &ssi1_mux, - &ssi2_mux, - &ssi3_mux, - &usdhc1_mux, - &usdhc2_mux, - &usdhc3_mux, - &usdhc4_mux, - &emi_mux, - &emi_slow_mux, - &esai_mux, - &ldb_di0_mux, - &ldb_di1_mux, - &enfc_mux, - &spdif_mux, - &asrc_serial_mux, - &hsi_tx_mux, - &ipu1_di0_pre_mux, - &ipu1_di0_mux, - &ipu1_di1_pre_mux, - &ipu1_di1_mux, - &ipu2_di0_pre_mux, - &ipu2_di0_mux, - &ipu2_di1_pre_mux, - &ipu2_di1_mux, - &ipu1_mux, - &ipu2_mux, - &cko1_mux, -}; - -static int _clk_set_parent(struct clk *clk, struct clk *parent) -{ - struct multiplexer *m; - int i, num; - u32 val; - - num = ARRAY_SIZE(multiplexers); - for (i = 0; i < num; i++) - if (multiplexers[i]->clk == clk) { - m = multiplexers[i]; - break; - } - if (i == num) - return -EINVAL; - - i = 0; - while (m->parents[i]) { - if (parent == m->parents[i]) - break; - i++; - } - if (!m->parents[i] || m->parents[i] == &dummy_clk) - return -EINVAL; - - val = readl_relaxed(m->reg); - val &= ~m->bm; - val |= i << m->bp; - writel_relaxed(val, m->reg); - - if (clk == &periph_clk) - return clk_busy_wait(clk); - - return 0; -} - -#define DEF_NG_CLK(name, p) \ - static struct clk name = { \ - .get_rate = _clk_get_rate, \ - .set_rate = _clk_set_rate, \ - .round_rate = _clk_round_rate, \ - .set_parent = _clk_set_parent, \ - .parent = p, \ - } - -DEF_NG_CLK(periph_clk2_clk, &osc_clk); -DEF_NG_CLK(periph_pre_clk, &pll2_bus); -DEF_NG_CLK(periph_clk, &periph_pre_clk); -DEF_NG_CLK(periph2_clk2_clk, &osc_clk); -DEF_NG_CLK(periph2_pre_clk, &pll2_bus); -DEF_NG_CLK(periph2_clk, &periph2_pre_clk); -DEF_NG_CLK(axi_clk, &periph_clk); -DEF_NG_CLK(emi_clk, &axi_clk); -DEF_NG_CLK(arm_clk, &pll1_sw_clk); -DEF_NG_CLK(ahb_clk, &periph_clk); -DEF_NG_CLK(ipg_clk, &ahb_clk); -DEF_NG_CLK(ipg_perclk, &ipg_clk); -DEF_NG_CLK(ipu1_di0_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(ipu1_di1_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(ipu2_di0_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(ipu2_di1_pre_clk, &pll3_pfd_540m); -DEF_NG_CLK(asrc_serial_clk, &pll3_usb_otg); - -#define DEF_CLK(name, er, es, p, s) \ - static struct clk name = { \ - .enable_reg = er, \ - .enable_shift = es, \ - .enable = _clk_enable, \ - .disable = _clk_disable, \ - .get_rate = _clk_get_rate, \ - .set_rate = _clk_set_rate, \ - .round_rate = _clk_round_rate, \ - .set_parent = _clk_set_parent, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEF_CLK_1B(name, er, es, p, s) \ - static struct clk name = { \ - .enable_reg = er, \ - .enable_shift = es, \ - .enable = _clk_enable_1b, \ - .disable = _clk_disable_1b, \ - .get_rate = _clk_get_rate, \ - .set_rate = _clk_set_rate, \ - .round_rate = _clk_round_rate, \ - .set_parent = _clk_set_parent, \ - .parent = p, \ - .secondary = s, \ - } - -DEF_CLK(aips_tz1_clk, CCGR0, CG0, &ahb_clk, NULL); -DEF_CLK(aips_tz2_clk, CCGR0, CG1, &ahb_clk, NULL); -DEF_CLK(apbh_dma_clk, CCGR0, CG2, &ahb_clk, NULL); -DEF_CLK(asrc_clk, CCGR0, CG3, &pll4_audio, NULL); -DEF_CLK(can1_serial_clk, CCGR0, CG8, &pll3_usb_otg, NULL); -DEF_CLK(can1_clk, CCGR0, CG7, &pll3_usb_otg, &can1_serial_clk); -DEF_CLK(can2_serial_clk, CCGR0, CG10, &pll3_usb_otg, NULL); -DEF_CLK(can2_clk, CCGR0, CG9, &pll3_usb_otg, &can2_serial_clk); -DEF_CLK(ecspi1_clk, CCGR1, CG0, &pll3_60m, NULL); -DEF_CLK(ecspi2_clk, CCGR1, CG1, &pll3_60m, NULL); -DEF_CLK(ecspi3_clk, CCGR1, CG2, &pll3_60m, NULL); -DEF_CLK(ecspi4_clk, CCGR1, CG3, &pll3_60m, NULL); -DEF_CLK(ecspi5_clk, CCGR1, CG4, &pll3_60m, NULL); -DEF_CLK(enet_clk, CCGR1, CG5, &ipg_clk, NULL); -DEF_CLK(esai_clk, CCGR1, CG8, &pll3_usb_otg, NULL); -DEF_CLK(gpt_serial_clk, CCGR1, CG11, &ipg_perclk, NULL); -DEF_CLK(gpt_clk, CCGR1, CG10, &ipg_perclk, &gpt_serial_clk); -DEF_CLK(gpu2d_core_clk, CCGR1, CG12, &pll2_pfd_352m, &gpu2d_axi_clk); -DEF_CLK(gpu3d_core_clk, CCGR1, CG13, &pll2_pfd_594m, &gpu3d_axi_clk); -DEF_CLK(gpu3d_shader_clk, CCGR1, CG13, &pll3_pfd_720m, &gpu3d_axi_clk); -DEF_CLK(hdmi_iahb_clk, CCGR2, CG0, &ahb_clk, NULL); -DEF_CLK(hdmi_isfr_clk, CCGR2, CG2, &pll3_pfd_540m, &hdmi_iahb_clk); -DEF_CLK(i2c1_clk, CCGR2, CG3, &ipg_perclk, NULL); -DEF_CLK(i2c2_clk, CCGR2, CG4, &ipg_perclk, NULL); -DEF_CLK(i2c3_clk, CCGR2, CG5, &ipg_perclk, NULL); -DEF_CLK(iim_clk, CCGR2, CG6, &ipg_clk, NULL); -DEF_CLK(enfc_clk, CCGR2, CG7, &pll2_pfd_352m, NULL); -DEF_CLK(ipu1_clk, CCGR3, CG0, &mmdc_ch0_axi_clk, NULL); -DEF_CLK(ipu1_di0_clk, CCGR3, CG1, &ipu1_di0_pre_clk, NULL); -DEF_CLK(ipu1_di1_clk, CCGR3, CG2, &ipu1_di1_pre_clk, NULL); -DEF_CLK(ipu2_clk, CCGR3, CG3, &mmdc_ch0_axi_clk, NULL); -DEF_CLK(ipu2_di0_clk, CCGR3, CG4, &ipu2_di0_pre_clk, NULL); -DEF_CLK(ipu2_di1_clk, CCGR3, CG5, &ipu2_di1_pre_clk, NULL); -DEF_CLK(ldb_di0_clk, CCGR3, CG6, &pll3_pfd_540m, NULL); -DEF_CLK(ldb_di1_clk, CCGR3, CG7, &pll3_pfd_540m, NULL); -DEF_CLK(hsi_tx_clk, CCGR3, CG8, &pll2_pfd_400m, NULL); -DEF_CLK(mlb_clk, CCGR3, CG9, &pll6_mlb, NULL); -DEF_CLK(mmdc_ch0_ipg_clk, CCGR3, CG12, &ipg_clk, NULL); -DEF_CLK(mmdc_ch0_axi_clk, CCGR3, CG10, &periph_clk, &mmdc_ch0_ipg_clk); -DEF_CLK(mmdc_ch1_ipg_clk, CCGR3, CG13, &ipg_clk, NULL); -DEF_CLK(mmdc_ch1_axi_clk, CCGR3, CG11, &periph2_clk, &mmdc_ch1_ipg_clk); -DEF_CLK(openvg_axi_clk, CCGR3, CG13, &axi_clk, NULL); -DEF_CLK(pwm1_clk, CCGR4, CG8, &ipg_perclk, NULL); -DEF_CLK(pwm2_clk, CCGR4, CG9, &ipg_perclk, NULL); -DEF_CLK(pwm3_clk, CCGR4, CG10, &ipg_perclk, NULL); -DEF_CLK(pwm4_clk, CCGR4, CG11, &ipg_perclk, NULL); -DEF_CLK(gpmi_bch_apb_clk, CCGR4, CG12, &usdhc3_clk, NULL); -DEF_CLK(gpmi_bch_clk, CCGR4, CG13, &usdhc4_clk, &gpmi_bch_apb_clk); -DEF_CLK(gpmi_apb_clk, CCGR4, CG15, &usdhc3_clk, &gpmi_bch_clk); -DEF_CLK(gpmi_io_clk, CCGR4, CG14, &enfc_clk, &gpmi_apb_clk); -DEF_CLK(sdma_clk, CCGR5, CG3, &ahb_clk, NULL); -DEF_CLK(spba_clk, CCGR5, CG6, &ipg_clk, NULL); -DEF_CLK(spdif_clk, CCGR5, CG7, &pll3_usb_otg, &spba_clk); -DEF_CLK(ssi1_clk, CCGR5, CG9, &pll3_pfd_508m, NULL); -DEF_CLK(ssi2_clk, CCGR5, CG10, &pll3_pfd_508m, NULL); -DEF_CLK(ssi3_clk, CCGR5, CG11, &pll3_pfd_508m, NULL); -DEF_CLK(uart_serial_clk, CCGR5, CG13, &pll3_usb_otg, NULL); -DEF_CLK(uart_clk, CCGR5, CG12, &pll3_80m, &uart_serial_clk); -DEF_CLK(usboh3_clk, CCGR6, CG0, &ipg_clk, NULL); -DEF_CLK(usdhc1_clk, CCGR6, CG1, &pll2_pfd_400m, NULL); -DEF_CLK(usdhc2_clk, CCGR6, CG2, &pll2_pfd_400m, NULL); -DEF_CLK(usdhc3_clk, CCGR6, CG3, &pll2_pfd_400m, NULL); -DEF_CLK(usdhc4_clk, CCGR6, CG4, &pll2_pfd_400m, NULL); -DEF_CLK(emi_slow_clk, CCGR6, CG5, &axi_clk, NULL); -DEF_CLK(vdo_axi_clk, CCGR6, CG6, &axi_clk, NULL); -DEF_CLK(vpu_clk, CCGR6, CG7, &axi_clk, NULL); -DEF_CLK_1B(cko1_clk, CCOSR, BP_CCOSR_CKO1_EN, &pll2_bus, NULL); - -static int pcie_clk_enable(struct clk *clk) -{ - u32 val; - - val = readl_relaxed(PLL8_ENET); - val |= BM_PLL_ENET_EN_PCIE; - writel_relaxed(val, PLL8_ENET); - - return _clk_enable(clk); -} - -static void pcie_clk_disable(struct clk *clk) -{ - u32 val; - - _clk_disable(clk); - - val = readl_relaxed(PLL8_ENET); - val &= BM_PLL_ENET_EN_PCIE; - writel_relaxed(val, PLL8_ENET); -} - -static struct clk pcie_clk = { - .enable_reg = CCGR4, - .enable_shift = CG0, - .enable = pcie_clk_enable, - .disable = pcie_clk_disable, - .set_parent = _clk_set_parent, - .parent = &axi_clk, - .secondary = &pll8_enet, -}; - -static int sata_clk_enable(struct clk *clk) -{ - u32 val; - - val = readl_relaxed(PLL8_ENET); - val |= BM_PLL_ENET_EN_SATA; - writel_relaxed(val, PLL8_ENET); - - return _clk_enable(clk); -} - -static void sata_clk_disable(struct clk *clk) -{ - u32 val; - - _clk_disable(clk); - - val = readl_relaxed(PLL8_ENET); - val &= BM_PLL_ENET_EN_SATA; - writel_relaxed(val, PLL8_ENET); -} - -static struct clk sata_clk = { - .enable_reg = CCGR5, - .enable_shift = CG2, - .enable = sata_clk_enable, - .disable = sata_clk_disable, - .parent = &ipg_clk, - .secondary = &pll8_enet, -}; - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - } - -static struct clk_lookup lookups[] = { - _REGISTER_CLOCK("2020000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21e8000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21ec000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21f0000.uart", NULL, uart_clk), - _REGISTER_CLOCK("21f4000.uart", NULL, uart_clk), - _REGISTER_CLOCK("2188000.enet", NULL, enet_clk), - _REGISTER_CLOCK("2190000.usdhc", NULL, usdhc1_clk), - _REGISTER_CLOCK("2194000.usdhc", NULL, usdhc2_clk), - _REGISTER_CLOCK("2198000.usdhc", NULL, usdhc3_clk), - _REGISTER_CLOCK("219c000.usdhc", NULL, usdhc4_clk), - _REGISTER_CLOCK("21a0000.i2c", NULL, i2c1_clk), - _REGISTER_CLOCK("21a4000.i2c", NULL, i2c2_clk), - _REGISTER_CLOCK("21a8000.i2c", NULL, i2c3_clk), - _REGISTER_CLOCK("2008000.ecspi", NULL, ecspi1_clk), - _REGISTER_CLOCK("200c000.ecspi", NULL, ecspi2_clk), - _REGISTER_CLOCK("2010000.ecspi", NULL, ecspi3_clk), - _REGISTER_CLOCK("2014000.ecspi", NULL, ecspi4_clk), - _REGISTER_CLOCK("2018000.ecspi", NULL, ecspi5_clk), - _REGISTER_CLOCK("20ec000.sdma", NULL, sdma_clk), - _REGISTER_CLOCK("20bc000.wdog", NULL, dummy_clk), - _REGISTER_CLOCK("20c0000.wdog", NULL, dummy_clk), - _REGISTER_CLOCK("smp_twd", NULL, twd_clk), - _REGISTER_CLOCK(NULL, "ckih", ckih_clk), - _REGISTER_CLOCK(NULL, "ckil_clk", ckil_clk), - _REGISTER_CLOCK(NULL, "aips_tz1_clk", aips_tz1_clk), - _REGISTER_CLOCK(NULL, "aips_tz2_clk", aips_tz2_clk), - _REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk), - _REGISTER_CLOCK(NULL, "can2_clk", can2_clk), - _REGISTER_CLOCK(NULL, "hdmi_isfr_clk", hdmi_isfr_clk), - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), - _REGISTER_CLOCK(NULL, "mlb_clk", mlb_clk), - _REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk), - _REGISTER_CLOCK(NULL, "pwm1_clk", pwm1_clk), - _REGISTER_CLOCK(NULL, "pwm2_clk", pwm2_clk), - _REGISTER_CLOCK(NULL, "pwm3_clk", pwm3_clk), - _REGISTER_CLOCK(NULL, "pwm4_clk", pwm4_clk), - _REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk), - _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk), - _REGISTER_CLOCK(NULL, "sata_clk", sata_clk), - _REGISTER_CLOCK(NULL, "cko1_clk", cko1_clk), -}; - -int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) -{ - u32 val = readl_relaxed(CLPCR); - - val &= ~BM_CLPCR_LPM; - switch (mode) { - case WAIT_CLOCKED: - break; - case WAIT_UNCLOCKED: - val |= 0x1 << BP_CLPCR_LPM; - break; - case STOP_POWER_ON: - val |= 0x2 << BP_CLPCR_LPM; - break; - case WAIT_UNCLOCKED_POWER_OFF: - val |= 0x1 << BP_CLPCR_LPM; - val &= ~BM_CLPCR_VSTBY; - val &= ~BM_CLPCR_SBYOS; - break; - case STOP_POWER_OFF: - val |= 0x2 << BP_CLPCR_LPM; - val |= 0x3 << BP_CLPCR_STBY_COUNT; - val |= BM_CLPCR_VSTBY; - val |= BM_CLPCR_SBYOS; - break; - default: - return -EINVAL; - } - writel_relaxed(val, CLPCR); - - return 0; -} - -static struct map_desc imx6q_clock_desc[] = { - imx_map_entry(MX6Q, CCM, MT_DEVICE), - imx_map_entry(MX6Q, ANATOP, MT_DEVICE), -}; - -void __init imx6q_clock_map_io(void) -{ - iotable_init(imx6q_clock_desc, ARRAY_SIZE(imx6q_clock_desc)); -} - -int __init mx6q_clocks_init(void) -{ - struct device_node *np; - void __iomem *base; - int i, irq; - - /* retrieve the freqency of fixed clocks from device tree */ - for_each_compatible_node(np, NULL, "fixed-clock") { - u32 rate; - if (of_property_read_u32(np, "clock-frequency", &rate)) - continue; - - if (of_device_is_compatible(np, "fsl,imx-ckil")) - external_low_reference = rate; - else if (of_device_is_compatible(np, "fsl,imx-ckih1")) - external_high_reference = rate; - else if (of_device_is_compatible(np, "fsl,imx-osc")) - oscillator_reference = rate; - } - - for (i = 0; i < ARRAY_SIZE(lookups); i++) - clkdev_add(&lookups[i]); - - /* only keep necessary clocks on */ - writel_relaxed(0x3 << CG0 | 0x3 << CG1 | 0x3 << CG2, CCGR0); - writel_relaxed(0x3 << CG8 | 0x3 << CG9 | 0x3 << CG10, CCGR2); - writel_relaxed(0x3 << CG10 | 0x3 << CG12, CCGR3); - writel_relaxed(0x3 << CG4 | 0x3 << CG6 | 0x3 << CG7, CCGR4); - writel_relaxed(0x3 << CG0, CCGR5); - writel_relaxed(0, CCGR6); - writel_relaxed(0, CCGR7); - - clk_enable(&uart_clk); - clk_enable(&mmdc_ch0_axi_clk); - - clk_set_rate(&pll4_audio, FREQ_650M); - clk_set_rate(&pll5_video, FREQ_650M); - clk_set_parent(&ipu1_di0_clk, &ipu1_di0_pre_clk); - clk_set_parent(&ipu1_di0_pre_clk, &pll5_video); - clk_set_parent(&gpu3d_shader_clk, &pll2_pfd_594m); - clk_set_rate(&gpu3d_shader_clk, FREQ_594M); - clk_set_parent(&gpu3d_core_clk, &mmdc_ch0_axi_clk); - clk_set_rate(&gpu3d_core_clk, FREQ_528M); - clk_set_parent(&asrc_serial_clk, &pll3_usb_otg); - clk_set_rate(&asrc_serial_clk, 1500000); - clk_set_rate(&enfc_clk, 11000000); - - /* - * Before pinctrl API is available, we have to rely on the pad - * configuration set up by bootloader. For usdhc example here, - * u-boot sets up the pads for 49.5 MHz case, and we have to lower - * the usdhc clock from 198 to 49.5 MHz to match the pad configuration. - * - * FIXME: This is should be removed after pinctrl API is available. - * At that time, usdhc driver can call pinctrl API to change pad - * configuration dynamically per different usdhc clock settings. - */ - clk_set_rate(&usdhc1_clk, 49500000); - clk_set_rate(&usdhc2_clk, 49500000); - clk_set_rate(&usdhc3_clk, 49500000); - clk_set_rate(&usdhc4_clk, 49500000); - - clk_set_parent(&cko1_clk, &ahb_clk); - - np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); - base = of_iomap(np, 0); - WARN_ON(!base); - irq = irq_of_parse_and_map(np, 0); - mxc_timer_init(&gpt_clk, base, irq); - - return 0; -} diff --git a/arch/arm/mach-imx/clock-mx51-mx53.c b/arch/arm/mach-imx/clock-mx51-mx53.c deleted file mode 100644 index 08470504a088..000000000000 --- a/arch/arm/mach-imx/clock-mx51-mx53.c +++ /dev/null @@ -1,1675 +0,0 @@ -/* - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/clkdev.h> -#include <linux/of.h> - -#include <asm/div64.h> - -#include <mach/hardware.h> -#include <mach/common.h> -#include <mach/clock.h> - -#include "crm-regs-imx5.h" - -/* External clock values passed-in by the board code */ -static unsigned long external_high_reference, external_low_reference; -static unsigned long oscillator_reference, ckih2_reference; - -static struct clk osc_clk; -static struct clk pll1_main_clk; -static struct clk pll1_sw_clk; -static struct clk pll2_sw_clk; -static struct clk pll3_sw_clk; -static struct clk mx53_pll4_sw_clk; -static struct clk lp_apm_clk; -static struct clk periph_apm_clk; -static struct clk ahb_clk; -static struct clk ipg_clk; -static struct clk usboh3_clk; -static struct clk emi_fast_clk; -static struct clk ipu_clk; -static struct clk mipi_hsc1_clk; -static struct clk esdhc1_clk; -static struct clk esdhc2_clk; -static struct clk esdhc3_mx53_clk; - -#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ - -/* calculate best pre and post dividers to get the required divider */ -static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post, - u32 max_pre, u32 max_post) -{ - if (div >= max_pre * max_post) { - *pre = max_pre; - *post = max_post; - } else if (div >= max_pre) { - u32 min_pre, temp_pre, old_err, err; - min_pre = DIV_ROUND_UP(div, max_post); - old_err = max_pre; - for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) { - err = div % temp_pre; - if (err == 0) { - *pre = temp_pre; - break; - } - err = temp_pre - err; - if (err < old_err) { - old_err = err; - *pre = temp_pre; - } - } - *post = DIV_ROUND_UP(div, *pre); - } else { - *pre = div; - *post = 1; - } -} - -static void _clk_ccgr_setclk(struct clk *clk, unsigned mode) -{ - u32 reg = __raw_readl(clk->enable_reg); - - reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); - reg |= mode << clk->enable_shift; - - __raw_writel(reg, clk->enable_reg); -} - -static int _clk_ccgr_enable(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_ON); - return 0; -} - -static void _clk_ccgr_disable(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_OFF); -} - -static int _clk_ccgr_enable_inrun(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); - return 0; -} - -static void _clk_ccgr_disable_inwait(struct clk *clk) -{ - _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); -} - -/* - * For the 4-to-1 muxed input clock - */ -static inline u32 _get_mux(struct clk *parent, struct clk *m0, - struct clk *m1, struct clk *m2, struct clk *m3) -{ - if (parent == m0) - return 0; - else if (parent == m1) - return 1; - else if (parent == m2) - return 2; - else if (parent == m3) - return 3; - else - BUG(); - - return -EINVAL; -} - -static inline void __iomem *_mx51_get_pll_base(struct clk *pll) -{ - if (pll == &pll1_main_clk) - return MX51_DPLL1_BASE; - else if (pll == &pll2_sw_clk) - return MX51_DPLL2_BASE; - else if (pll == &pll3_sw_clk) - return MX51_DPLL3_BASE; - else - BUG(); - - return NULL; -} - -static inline void __iomem *_mx53_get_pll_base(struct clk *pll) -{ - if (pll == &pll1_main_clk) - return MX53_DPLL1_BASE; - else if (pll == &pll2_sw_clk) - return MX53_DPLL2_BASE; - else if (pll == &pll3_sw_clk) - return MX53_DPLL3_BASE; - else if (pll == &mx53_pll4_sw_clk) - return MX53_DPLL4_BASE; - else - BUG(); - - return NULL; -} - -static inline void __iomem *_get_pll_base(struct clk *pll) -{ - if (cpu_is_mx51()) - return _mx51_get_pll_base(pll); - else - return _mx53_get_pll_base(pll); -} - -static unsigned long clk_pll_get_rate(struct clk *clk) -{ - long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; - unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; - void __iomem *pllbase; - s64 temp; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - pllbase = _get_pll_base(clk); - - dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); - pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; - dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; - - if (pll_hfsm == 0) { - dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); - dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); - dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); - } else { - dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); - dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); - dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); - } - pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; - mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; - mfi = (mfi <= 5) ? 5 : mfi; - mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; - mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; - /* Sign extend to 32-bits */ - if (mfn >= 0x04000000) { - mfn |= 0xFC000000; - mfn_abs = -mfn; - } - - ref_clk = 2 * parent_rate; - if (dbl != 0) - ref_clk *= 2; - - ref_clk /= (pdf + 1); - temp = (u64) ref_clk * mfn_abs; - do_div(temp, mfd + 1); - if (mfn < 0) - temp = -temp; - temp = (ref_clk * mfi) + temp; - - return temp; -} - -static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg; - void __iomem *pllbase; - - long mfi, pdf, mfn, mfd = 999999; - s64 temp64; - unsigned long quad_parent_rate; - unsigned long pll_hfsm, dp_ctl; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - pllbase = _get_pll_base(clk); - - quad_parent_rate = 4 * parent_rate; - pdf = mfi = -1; - while (++pdf < 16 && mfi < 5) - mfi = rate * (pdf+1) / quad_parent_rate; - if (mfi > 15) - return -EINVAL; - pdf--; - - temp64 = rate * (pdf+1) - quad_parent_rate * mfi; - do_div(temp64, quad_parent_rate/1000000); - mfn = (long)temp64; - - dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); - /* use dpdck0_2 */ - __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); - pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; - if (pll_hfsm == 0) { - reg = mfi << 4 | pdf; - __raw_writel(reg, pllbase + MXC_PLL_DP_OP); - __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); - __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); - } else { - reg = mfi << 4 | pdf; - __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); - __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); - __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); - } - - return 0; -} - -static int _clk_pll_enable(struct clk *clk) -{ - u32 reg; - void __iomem *pllbase; - int i = 0; - - pllbase = _get_pll_base(clk); - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); - if (reg & MXC_PLL_DP_CTL_UPEN) - return 0; - - reg |= MXC_PLL_DP_CTL_UPEN; - __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); - - /* Wait for lock */ - do { - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); - if (reg & MXC_PLL_DP_CTL_LRF) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: pll locking failed\n"); - return -EINVAL; - } - - return 0; -} - -static void _clk_pll_disable(struct clk *clk) -{ - u32 reg; - void __iomem *pllbase; - - pllbase = _get_pll_base(clk); - reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; - __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); -} - -static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, step; - - reg = __raw_readl(MXC_CCM_CCSR); - - /* When switching from pll_main_clk to a bypass clock, first select a - * multiplexed clock in 'step_sel', then shift the glitchless mux - * 'pll1_sw_clk_sel'. - * - * When switching back, do it in reverse order - */ - if (parent == &pll1_main_clk) { - /* Switch to pll1_main_clk */ - reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - __raw_writel(reg, MXC_CCM_CCSR); - /* step_clk mux switched to lp_apm, to save power. */ - reg = __raw_readl(MXC_CCM_CCSR); - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; - reg |= (MXC_CCM_CCSR_STEP_SEL_LP_APM << - MXC_CCM_CCSR_STEP_SEL_OFFSET); - } else { - if (parent == &lp_apm_clk) { - step = MXC_CCM_CCSR_STEP_SEL_LP_APM; - } else if (parent == &pll2_sw_clk) { - step = MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED; - } else if (parent == &pll3_sw_clk) { - step = MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED; - } else - return -EINVAL; - - reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; - reg |= (step << MXC_CCM_CCSR_STEP_SEL_OFFSET); - - __raw_writel(reg, MXC_CCM_CCSR); - /* Switch to step_clk */ - reg = __raw_readl(MXC_CCM_CCSR); - reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; - } - __raw_writel(reg, MXC_CCM_CCSR); - return 0; -} - -static unsigned long clk_pll1_sw_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CCSR); - - if (clk->parent == &pll2_sw_clk) { - div = ((reg & MXC_CCM_CCSR_PLL2_PODF_MASK) >> - MXC_CCM_CCSR_PLL2_PODF_OFFSET) + 1; - } else if (clk->parent == &pll3_sw_clk) { - div = ((reg & MXC_CCM_CCSR_PLL3_PODF_MASK) >> - MXC_CCM_CCSR_PLL3_PODF_OFFSET) + 1; - } else - div = 1; - return parent_rate / div; -} - -static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CCSR); - - if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; - else - reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; - - __raw_writel(reg, MXC_CCM_CCSR); - return 0; -} - -static int _clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - if (parent == &osc_clk) - reg = __raw_readl(MXC_CCM_CCSR) & ~MXC_CCM_CCSR_LP_APM_SEL; - else - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CCSR); - - return 0; -} - -static unsigned long clk_cpu_get_rate(struct clk *clk) -{ - u32 cacrr, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - cacrr = __raw_readl(MXC_CCM_CACRR); - div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; - - return parent_rate / div; -} - -static int clk_cpu_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, cpu_podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - cpu_podf = parent_rate / rate - 1; - /* use post divider to change freq */ - reg = __raw_readl(MXC_CCM_CACRR); - reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; - reg |= cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_CACRR); - - return 0; -} - -static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, mux; - int i = 0; - - mux = _get_mux(parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk, NULL); - - reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK; - reg |= mux << MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET; - __raw_writel(reg, MXC_CCM_CBCMR); - - /* Wait for lock */ - do { - reg = __raw_readl(MXC_CCM_CDHIPR); - if (!(reg & MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY)) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: Set parent for periph_apm clock failed\n"); - return -EINVAL; - } - - return 0; -} - -static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CBCDR); - - if (parent == &pll2_sw_clk) - reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; - else if (parent == &periph_apm_clk) - reg |= MXC_CCM_CBCDR_PERIPH_CLK_SEL; - else - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CBCDR); - - return 0; -} - -static struct clk main_bus_clk = { - .parent = &pll2_sw_clk, - .set_parent = _clk_main_bus_set_parent, -}; - -static unsigned long clk_ahb_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> - MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; - return parent_rate / div; -} - - -static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div; - unsigned long parent_rate; - int i = 0; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8 || div < 1 || ((parent_rate / div) != rate)) - return -EINVAL; - - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; - reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_CBCDR); - - /* Wait for lock */ - do { - reg = __raw_readl(MXC_CCM_CDHIPR); - if (!(reg & MXC_CCM_CDHIPR_AHB_PODF_BUSY)) - break; - - udelay(1); - } while (++i < MAX_DPLL_WAIT_TRIES); - - if (i == MAX_DPLL_WAIT_TRIES) { - pr_err("MX5: clk_ahb_set_rate failed\n"); - return -EINVAL; - } - - return 0; -} - -static unsigned long _clk_ahb_round_rate(struct clk *clk, - unsigned long rate) -{ - u32 div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - div = parent_rate / rate; - if (div > 8) - div = 8; - else if (div == 0) - div++; - return parent_rate / div; -} - - -static int _clk_max_enable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_enable(clk); - - /* Handshake with MAX when LPM is entered. */ - reg = __raw_readl(MXC_CCM_CLPCR); - if (cpu_is_mx51()) - reg &= ~MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS; - else if (cpu_is_mx53()) - reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); - - return 0; -} - -static void _clk_max_disable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_disable_inwait(clk); - - /* No Handshake with MAX when LPM is entered as its disabled. */ - reg = __raw_readl(MXC_CCM_CLPCR); - if (cpu_is_mx51()) - reg |= MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS; - else if (cpu_is_mx53()) - reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); -} - -static unsigned long clk_ipg_get_rate(struct clk *clk) -{ - u32 reg, div; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> - MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; - - return parent_rate / div; -} - -static unsigned long clk_ipg_per_get_rate(struct clk *clk) -{ - u32 reg, prediv1, prediv2, podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->parent == &main_bus_clk || clk->parent == &lp_apm_clk) { - /* the main_bus_clk is the one before the DVFS engine */ - reg = __raw_readl(MXC_CCM_CBCDR); - prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> - MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; - prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> - MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; - podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> - MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; - return parent_rate / (prediv1 * prediv2 * podf); - } else if (clk->parent == &ipg_clk) - return parent_rate; - else - BUG(); -} - -static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CBCMR); - - reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; - reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; - - if (parent == &ipg_clk) - reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; - else if (parent == &lp_apm_clk) - reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; - else if (parent != &main_bus_clk) - return -EINVAL; - - __raw_writel(reg, MXC_CCM_CBCMR); - - return 0; -} - -#define clk_nfc_set_parent NULL - -static unsigned long clk_nfc_get_rate(struct clk *clk) -{ - unsigned long rate; - u32 reg, div; - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_NFC_PODF_MASK) >> - MXC_CCM_CBCDR_NFC_PODF_OFFSET) + 1; - rate = clk_get_rate(clk->parent) / div; - WARN_ON(rate == 0); - return rate; -} - -static unsigned long clk_nfc_round_rate(struct clk *clk, - unsigned long rate) -{ - u32 div; - unsigned long parent_rate = clk_get_rate(clk->parent); - - if (!rate) - return -EINVAL; - - div = parent_rate / rate; - - if (parent_rate % rate) - div++; - - if (div > 8) - return -EINVAL; - - return parent_rate / div; - -} - -static int clk_nfc_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, div; - - div = clk_get_rate(clk->parent) / rate; - if (div == 0) - div++; - if (((clk_get_rate(clk->parent) / div) != rate) || (div > 8)) - return -EINVAL; - - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK; - reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET; - __raw_writel(reg, MXC_CCM_CBCDR); - - while (__raw_readl(MXC_CCM_CDHIPR) & - MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY){ - } - - return 0; -} - -static unsigned long get_high_reference_clock_rate(struct clk *clk) -{ - return external_high_reference; -} - -static unsigned long get_low_reference_clock_rate(struct clk *clk) -{ - return external_low_reference; -} - -static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) -{ - return oscillator_reference; -} - -static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) -{ - return ckih2_reference; -} - -static unsigned long clk_emi_slow_get_rate(struct clk *clk) -{ - u32 reg, div; - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_EMI_PODF_MASK) >> - MXC_CCM_CBCDR_EMI_PODF_OFFSET) + 1; - - return clk_get_rate(clk->parent) / div; -} - -static unsigned long _clk_ddr_hf_get_rate(struct clk *clk) -{ - unsigned long rate; - u32 reg, div; - - reg = __raw_readl(MXC_CCM_CBCDR); - div = ((reg & MXC_CCM_CBCDR_DDR_PODF_MASK) >> - MXC_CCM_CBCDR_DDR_PODF_OFFSET) + 1; - rate = clk_get_rate(clk->parent) / div; - - return rate; -} - -/* External high frequency clock */ -static struct clk ckih_clk = { - .get_rate = get_high_reference_clock_rate, -}; - -static struct clk ckih2_clk = { - .get_rate = get_ckih2_reference_clock_rate, -}; - -static struct clk osc_clk = { - .get_rate = get_oscillator_reference_clock_rate, -}; - -/* External low frequency (32kHz) clock */ -static struct clk ckil_clk = { - .get_rate = get_low_reference_clock_rate, -}; - -static struct clk pll1_main_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Clock tree block diagram (WIP): - * CCM: Clock Controller Module - * - * PLL output -> | - * | CCM Switcher -> CCM_CLK_ROOT_GEN -> - * PLL bypass -> | - * - */ - -/* PLL1 SW supplies to ARM core */ -static struct clk pll1_sw_clk = { - .parent = &pll1_main_clk, - .set_parent = _clk_pll1_sw_set_parent, - .get_rate = clk_pll1_sw_get_rate, -}; - -/* PLL2 SW supplies to AXI/AHB/IP buses */ -static struct clk pll2_sw_clk = { - .parent = &osc_clk, - .get_rate = clk_pll_get_rate, - .set_rate = _clk_pll_set_rate, - .set_parent = _clk_pll2_sw_set_parent, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* PLL3 SW supplies to serial clocks like USB, SSI, etc. */ -static struct clk pll3_sw_clk = { - .parent = &osc_clk, - .set_rate = _clk_pll_set_rate, - .get_rate = clk_pll_get_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* PLL4 SW supplies to LVDS Display Bridge(LDB) */ -static struct clk mx53_pll4_sw_clk = { - .parent = &osc_clk, - .set_rate = _clk_pll_set_rate, - .enable = _clk_pll_enable, - .disable = _clk_pll_disable, -}; - -/* Low-power Audio Playback Mode clock */ -static struct clk lp_apm_clk = { - .parent = &osc_clk, - .set_parent = _clk_lp_apm_set_parent, -}; - -static struct clk periph_apm_clk = { - .parent = &pll1_sw_clk, - .set_parent = _clk_periph_apm_set_parent, -}; - -static struct clk cpu_clk = { - .parent = &pll1_sw_clk, - .get_rate = clk_cpu_get_rate, - .set_rate = clk_cpu_set_rate, -}; - -static struct clk ahb_clk = { - .parent = &main_bus_clk, - .get_rate = clk_ahb_get_rate, - .set_rate = _clk_ahb_set_rate, - .round_rate = _clk_ahb_round_rate, -}; - -static struct clk iim_clk = { - .parent = &ipg_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, -}; - -/* Main IP interface clock for access to registers */ -static struct clk ipg_clk = { - .parent = &ahb_clk, - .get_rate = clk_ipg_get_rate, -}; - -static struct clk ipg_perclk = { - .parent = &lp_apm_clk, - .get_rate = clk_ipg_per_get_rate, - .set_parent = _clk_ipg_per_set_parent, -}; - -static struct clk ahb_max_clk = { - .parent = &ahb_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, -}; - -static struct clk aips_tz1_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk aips_tz2_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk gpc_dvfs_clk = { - .enable_reg = MXC_CCM_CCGR5, - .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, -}; - -static struct clk gpt_32k_clk = { - .id = 0, - .parent = &ckil_clk, -}; - -static struct clk dummy_clk = { - .id = 0, -}; - -static struct clk emi_slow_clk = { - .parent = &pll2_sw_clk, - .enable_reg = MXC_CCM_CCGR5, - .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, - .get_rate = clk_emi_slow_get_rate, -}; - -static int clk_ipu_enable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_enable(clk); - - /* Enable handshake with IPU when certain clock rates are changed */ - reg = __raw_readl(MXC_CCM_CCDR); - reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - /* Enable handshake with IPU when LPM is entered */ - reg = __raw_readl(MXC_CCM_CLPCR); - reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); - - return 0; -} - -static void clk_ipu_disable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_disable(clk); - - /* Disable handshake with IPU whe dividers are changed */ - reg = __raw_readl(MXC_CCM_CCDR); - reg |= MXC_CCM_CCDR_IPU_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - /* Disable handshake with IPU when LPM is entered */ - reg = __raw_readl(MXC_CCM_CLPCR); - reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); -} - -static struct clk ahbmux1_clk = { - .parent = &ahb_clk, - .secondary = &ahb_max_clk, - .enable_reg = MXC_CCM_CCGR0, - .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable_inwait, -}; - -static struct clk ipu_sec_clk = { - .parent = &emi_fast_clk, - .secondary = &ahbmux1_clk, -}; - -static struct clk ddr_hf_clk = { - .parent = &pll1_sw_clk, - .get_rate = _clk_ddr_hf_get_rate, -}; - -static struct clk ddr_clk = { - .parent = &ddr_hf_clk, -}; - -/* clock definitions for MIPI HSC unit which has been removed - * from documentation, but not from hardware - */ -static int _clk_hsc_enable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_enable(clk); - /* Handshake with IPU when certain clock rates are changed. */ - reg = __raw_readl(MXC_CCM_CCDR); - reg &= ~MXC_CCM_CCDR_HSC_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - reg = __raw_readl(MXC_CCM_CLPCR); - reg &= ~MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); - - return 0; -} - -static void _clk_hsc_disable(struct clk *clk) -{ - u32 reg; - - _clk_ccgr_disable(clk); - /* No handshake with HSC as its not enabled. */ - reg = __raw_readl(MXC_CCM_CCDR); - reg |= MXC_CCM_CCDR_HSC_HS_MASK; - __raw_writel(reg, MXC_CCM_CCDR); - - reg = __raw_readl(MXC_CCM_CLPCR); - reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; - __raw_writel(reg, MXC_CCM_CLPCR); -} - -static struct clk mipi_hsp_clk = { - .parent = &ipu_clk, - .enable_reg = MXC_CCM_CCGR4, - .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, - .enable = _clk_hsc_enable, - .disable = _clk_hsc_disable, - .secondary = &mipi_hsc1_clk, -}; - -#define DEFINE_CLOCK_CCGR(name, i, er, es, pfx, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = pfx##_get_rate, \ - .set_rate = pfx##_set_rate, \ - .round_rate = pfx##_round_rate, \ - .set_parent = pfx##_set_parent, \ - .enable = _clk_ccgr_enable, \ - .disable = _clk_ccgr_disable, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = pfx##_get_rate, \ - .set_rate = pfx##_set_rate, \ - .set_parent = pfx##_set_parent, \ - .enable = _clk_max_enable, \ - .disable = _clk_max_disable, \ - .parent = p, \ - .secondary = s, \ - } - -#define CLK_GET_RATE(name, nr, bitsname) \ -static unsigned long clk_##name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, pred, podf; \ - \ - reg = __raw_readl(MXC_CCM_CSCDR##nr); \ - pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK) \ - >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ - podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK) \ - >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ - \ - return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent), \ - (pred + 1) * (podf + 1)); \ -} - -#define CLK_SET_PARENT(name, nr, bitsname) \ -static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - u32 reg, mux; \ - \ - mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, \ - &pll3_sw_clk, &lp_apm_clk); \ - reg = __raw_readl(MXC_CCM_CSCMR##nr) & \ - ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK; \ - reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET; \ - __raw_writel(reg, MXC_CCM_CSCMR##nr); \ - \ - return 0; \ -} - -#define CLK_SET_RATE(name, nr, bitsname) \ -static int clk_##name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, div, parent_rate; \ - u32 pre = 0, post = 0; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - div = parent_rate / rate; \ - \ - if ((parent_rate / div) != rate) \ - return -EINVAL; \ - \ - __calc_pre_post_dividers(div, &pre, &post, \ - (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >> \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1, \ - (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >> \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\ - \ - /* Set sdhc1 clock divider */ \ - reg = __raw_readl(MXC_CCM_CSCDR##nr) & \ - ~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK \ - | MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK); \ - reg |= (post - 1) << \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ - reg |= (pre - 1) << \ - MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ - __raw_writel(reg, MXC_CCM_CSCDR##nr); \ - \ - return 0; \ -} - -/* UART */ -CLK_GET_RATE(uart, 1, UART) -CLK_SET_PARENT(uart, 1, UART) - -static struct clk uart_root_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_uart_get_rate, - .set_parent = clk_uart_set_parent, -}; - -/* USBOH3 */ -CLK_GET_RATE(usboh3, 1, USBOH3) -CLK_SET_PARENT(usboh3, 1, USBOH3) - -static struct clk usboh3_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_usboh3_get_rate, - .set_parent = clk_usboh3_set_parent, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, - .enable_reg = MXC_CCM_CCGR2, - .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, -}; - -static struct clk usb_ahb_clk = { - .parent = &ipg_clk, - .enable = _clk_ccgr_enable, - .disable = _clk_ccgr_disable, - .enable_reg = MXC_CCM_CCGR2, - .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, -}; - -static int clk_usb_phy1_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; - - if (parent == &pll3_sw_clk) - reg |= 1 << MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET; - - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -static struct clk usb_phy1_clk = { - .parent = &pll3_sw_clk, - .set_parent = clk_usb_phy1_set_parent, - .enable = _clk_ccgr_enable, - .enable_reg = MXC_CCM_CCGR2, - .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, - .disable = _clk_ccgr_disable, -}; - -/* eCSPI */ -CLK_GET_RATE(ecspi, 2, CSPI) -CLK_SET_PARENT(ecspi, 1, CSPI) - -static struct clk ecspi_main_clk = { - .parent = &pll3_sw_clk, - .get_rate = clk_ecspi_get_rate, - .set_parent = clk_ecspi_set_parent, -}; - -/* eSDHC */ -CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1) -CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1) -CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1) - -/* mx51 specific */ -CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2) -CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2) -CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2) - -static int clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; - else if (parent == &esdhc2_clk) - reg |= MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -static int clk_esdhc4_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else if (parent == &esdhc2_clk) - reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -/* mx53 specific */ -static int clk_esdhc2_mx53_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL; - else if (parent == &esdhc3_mx53_clk) - reg |= MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -CLK_GET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) -CLK_SET_PARENT(esdhc3_mx53, 1, ESDHC3_MX53) -CLK_SET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) - -static int clk_esdhc4_mx53_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg; - - reg = __raw_readl(MXC_CCM_CSCMR1); - if (parent == &esdhc1_clk) - reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else if (parent == &esdhc3_mx53_clk) - reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; - else - return -EINVAL; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s) \ - static struct clk name = { \ - .id = i, \ - .enable_reg = er, \ - .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = e, \ - .disable = d, \ - .parent = p, \ - .secondary = s, \ - } - -#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \ - DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable, _clk_ccgr_disable, p, s) - -/* Shared peripheral bus arbiter */ -DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET, - NULL, NULL, &ipg_clk, NULL); - -/* UART */ -DEFINE_CLOCK(uart1_ipg_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG3_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK(uart2_ipg_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz1_clk); -DEFINE_CLOCK(uart3_ipg_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG7_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); -DEFINE_CLOCK(uart4_ipg_clk, 3, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG4_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); -DEFINE_CLOCK(uart5_ipg_clk, 4, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); -DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET, - NULL, NULL, &uart_root_clk, &uart1_ipg_clk); -DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &uart_root_clk, &uart2_ipg_clk); -DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET, - NULL, NULL, &uart_root_clk, &uart3_ipg_clk); -DEFINE_CLOCK(uart4_clk, 3, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, &uart_root_clk, &uart4_ipg_clk); -DEFINE_CLOCK(uart5_clk, 4, MXC_CCM_CCGR7, MXC_CCM_CCGRx_CG7_OFFSET, - NULL, NULL, &uart_root_clk, &uart5_ipg_clk); - -/* GPT */ -DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_clk, &gpt_ipg_clk); - -DEFINE_CLOCK(pwm1_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &ipg_perclk, NULL); -DEFINE_CLOCK(pwm2_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG8_OFFSET, - NULL, NULL, &ipg_perclk, NULL); - -/* I2C */ -DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_perclk, NULL); -DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ipg_perclk, NULL); -DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(i2c3_mx53_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, &ipg_perclk, NULL); - -/* FEC */ -DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET, - NULL, NULL, &ipg_clk, NULL); - -/* NFC */ -DEFINE_CLOCK_CCGR(nfc_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG10_OFFSET, - clk_nfc, &emi_slow_clk, NULL); - -/* SSI */ -DEFINE_CLOCK(ssi1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG8_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &pll3_sw_clk, &ssi1_ipg_clk); -DEFINE_CLOCK(ssi2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, &pll3_sw_clk, &ssi2_ipg_clk); -DEFINE_CLOCK(ssi3_ipg_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG12_OFFSET, - NULL, NULL, &ipg_clk, NULL); -DEFINE_CLOCK(ssi3_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG13_OFFSET, - NULL, NULL, &pll3_sw_clk, &ssi3_ipg_clk); - -/* eCSPI */ -DEFINE_CLOCK_FULL(ecspi1_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable, - &ipg_clk, &spba_clk); -DEFINE_CLOCK(ecspi1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG10_OFFSET, - NULL, NULL, &ecspi_main_clk, &ecspi1_ipg_clk); -DEFINE_CLOCK_FULL(ecspi2_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG11_OFFSET, - NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable, - &ipg_clk, &aips_tz2_clk); -DEFINE_CLOCK(ecspi2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG12_OFFSET, - NULL, NULL, &ecspi_main_clk, &ecspi2_ipg_clk); - -/* CSPI */ -DEFINE_CLOCK(cspi_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET, - NULL, NULL, &ipg_clk, &aips_tz2_clk); -DEFINE_CLOCK(cspi_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG13_OFFSET, - NULL, NULL, &ipg_clk, &cspi_ipg_clk); - -/* SDMA */ -DEFINE_CLOCK(sdma_clk, 1, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG15_OFFSET, - NULL, NULL, &ahb_clk, NULL); - -/* eSDHC */ -DEFINE_CLOCK_FULL(esdhc1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG0_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); -DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET, - clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk); -DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); -DEFINE_CLOCK_FULL(esdhc3_ipg_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG4_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); -DEFINE_CLOCK_FULL(esdhc4_ipg_clk, 3, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); - -/* mx51 specific */ -DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET, - clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk); - -static struct clk esdhc3_clk = { - .id = 2, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc3_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc3_ipg_clk, -}; -static struct clk esdhc4_clk = { - .id = 3, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc4_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc4_ipg_clk, -}; - -/* mx53 specific */ -static struct clk esdhc2_mx53_clk = { - .id = 2, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc2_mx53_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc3_ipg_clk, -}; - -DEFINE_CLOCK_MAX(esdhc3_mx53_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG5_OFFSET, - clk_esdhc3_mx53, &pll2_sw_clk, &esdhc2_ipg_clk); - -static struct clk esdhc4_mx53_clk = { - .id = 3, - .parent = &esdhc1_clk, - .set_parent = clk_esdhc4_mx53_set_parent, - .enable_reg = MXC_CCM_CCGR3, - .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, - .enable = _clk_max_enable, - .disable = _clk_max_disable, - .secondary = &esdhc4_ipg_clk, -}; - -static struct clk sata_clk = { - .parent = &ipg_clk, - .enable = _clk_max_enable, - .enable_reg = MXC_CCM_CCGR4, - .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, - .disable = _clk_max_disable, -}; - -static struct clk ahci_phy_clk = { - .parent = &usb_phy1_clk, -}; - -static struct clk ahci_dma_clk = { - .parent = &ahb_clk, -}; - -DEFINE_CLOCK(mipi_esc_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG5_OFFSET, NULL, NULL, NULL, &pll2_sw_clk); -DEFINE_CLOCK(mipi_hsc2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG4_OFFSET, NULL, NULL, &mipi_esc_clk, &pll2_sw_clk); -DEFINE_CLOCK(mipi_hsc1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG3_OFFSET, NULL, NULL, &mipi_hsc2_clk, &pll2_sw_clk); - -/* IPU */ -DEFINE_CLOCK_FULL(ipu_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, clk_ipu_enable, clk_ipu_disable, &ahb_clk, &ipu_sec_clk); - -DEFINE_CLOCK_FULL(emi_fast_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG7_OFFSET, - NULL, NULL, _clk_ccgr_enable, _clk_ccgr_disable_inwait, - &ddr_clk, NULL); - -DEFINE_CLOCK(ipu_di0_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG5_OFFSET, - NULL, NULL, &pll3_sw_clk, NULL); -DEFINE_CLOCK(ipu_di1_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG6_OFFSET, - NULL, NULL, &pll3_sw_clk, NULL); - -/* PATA */ -DEFINE_CLOCK(pata_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG0_OFFSET, - NULL, NULL, &ipg_clk, &spba_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup mx51_lookups[] = { - /* i.mx51 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - /* i.mx51 has the i.mx27 type fec */ - _REGISTER_CLOCK("imx27-fec.0", NULL, fec_clk) - _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk) - _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_phy1", usb_phy1_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) - _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) - _REGISTER_CLOCK("imx-keypad", NULL, dummy_clk) - _REGISTER_CLOCK("mxc_nand", NULL, nfc_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk) - /* i.mx51 has the i.mx35 type sdma */ - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK(NULL, "ckih", ckih_clk) - _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk) - _REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk) - _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk) - _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk) - /* i.mx51 has the i.mx35 type cspi */ - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.1", NULL, esdhc2_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.2", NULL, esdhc3_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx51.3", NULL, esdhc4_clk) - _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk) - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) - _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk) - _REGISTER_CLOCK(NULL, "mipi_hsp", mipi_hsp_clk) - _REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk) - _REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk) - _REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk) - _REGISTER_CLOCK(NULL, "gpc_dvfs", gpc_dvfs_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) -}; - -static struct clk_lookup mx53_lookups[] = { - /* i.mx53 has the i.mx21 type uart */ - _REGISTER_CLOCK("imx21-uart.0", NULL, uart1_clk) - _REGISTER_CLOCK("imx21-uart.1", NULL, uart2_clk) - _REGISTER_CLOCK("imx21-uart.2", NULL, uart3_clk) - _REGISTER_CLOCK("imx21-uart.3", NULL, uart4_clk) - _REGISTER_CLOCK("imx21-uart.4", NULL, uart5_clk) - _REGISTER_CLOCK(NULL, "gpt", gpt_clk) - /* i.mx53 has the i.mx25 type fec */ - _REGISTER_CLOCK("imx25-fec.0", NULL, fec_clk) - _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) - _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) - _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) - _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_mx53_clk) - /* i.mx53 has the i.mx51 type ecspi */ - _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk) - _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk) - /* i.mx53 has the i.mx25 type cspi */ - _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.0", NULL, esdhc1_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.1", NULL, esdhc2_mx53_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.2", NULL, esdhc3_mx53_clk) - _REGISTER_CLOCK("sdhci-esdhc-imx53.3", NULL, esdhc4_mx53_clk) - _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) - _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk) - /* i.mx53 has the i.mx35 type sdma */ - _REGISTER_CLOCK("imx35-sdma", NULL, sdma_clk) - _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) - _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) - _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk) - _REGISTER_CLOCK("imx-keypad", NULL, dummy_clk) - _REGISTER_CLOCK("pata_imx", NULL, pata_clk) - _REGISTER_CLOCK("imx53-ahci.0", "ahci", sata_clk) - _REGISTER_CLOCK("imx53-ahci.0", "ahci_phy", ahci_phy_clk) - _REGISTER_CLOCK("imx53-ahci.0", "ahci_dma", ahci_dma_clk) -}; - -static void clk_tree_init(void) -{ - u32 reg; - - ipg_perclk.set_parent(&ipg_perclk, &lp_apm_clk); - - /* - * Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at - * 8MHz, its derived from lp_apm. - * - * FIXME: Verify if true for all boards - */ - reg = __raw_readl(MXC_CCM_CBCDR); - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; - reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; - reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; - reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); - __raw_writel(reg, MXC_CCM_CBCDR); -} - -int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, - unsigned long ckih1, unsigned long ckih2) -{ - int i; - - external_low_reference = ckil; - external_high_reference = ckih1; - ckih2_reference = ckih2; - oscillator_reference = osc; - - for (i = 0; i < ARRAY_SIZE(mx51_lookups); i++) - clkdev_add(&mx51_lookups[i]); - - clk_tree_init(); - - clk_enable(&cpu_clk); - clk_enable(&main_bus_clk); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX51", mx51_revision()); - clk_disable(&iim_clk); - - /* move usb_phy_clk to 24MHz */ - clk_set_parent(&usb_phy1_clk, &osc_clk); - - /* set the usboh3_clk parent to pll2_sw_clk */ - clk_set_parent(&usboh3_clk, &pll2_sw_clk); - - /* Set SDHC parents to be PLL2 */ - clk_set_parent(&esdhc1_clk, &pll2_sw_clk); - clk_set_parent(&esdhc2_clk, &pll2_sw_clk); - - /* set SDHC root clock as 166.25MHZ*/ - clk_set_rate(&esdhc1_clk, 166250000); - clk_set_rate(&esdhc2_clk, 166250000); - - /* System timer */ - mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), - MX51_INT_GPT); - return 0; -} - -int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, - unsigned long ckih1, unsigned long ckih2) -{ - int i; - - external_low_reference = ckil; - external_high_reference = ckih1; - ckih2_reference = ckih2; - oscillator_reference = osc; - - for (i = 0; i < ARRAY_SIZE(mx53_lookups); i++) - clkdev_add(&mx53_lookups[i]); - - clk_tree_init(); - - clk_set_parent(&uart_root_clk, &pll3_sw_clk); - clk_enable(&cpu_clk); - clk_enable(&main_bus_clk); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX53", mx53_revision()); - clk_disable(&iim_clk); - - /* Set SDHC parents to be PLL2 */ - clk_set_parent(&esdhc1_clk, &pll2_sw_clk); - clk_set_parent(&esdhc3_mx53_clk, &pll2_sw_clk); - - /* set SDHC root clock as 200MHZ*/ - clk_set_rate(&esdhc1_clk, 200000000); - clk_set_rate(&esdhc3_mx53_clk, 200000000); - - /* System timer */ - mxc_timer_init(&gpt_clk, MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), - MX53_INT_GPT); - return 0; -} - -#ifdef CONFIG_OF -static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc, - unsigned long *ckih1, unsigned long *ckih2) -{ - struct device_node *np; - - /* retrieve the freqency of fixed clocks from device tree */ - for_each_compatible_node(np, NULL, "fixed-clock") { - u32 rate; - if (of_property_read_u32(np, "clock-frequency", &rate)) - continue; - - if (of_device_is_compatible(np, "fsl,imx-ckil")) - *ckil = rate; - else if (of_device_is_compatible(np, "fsl,imx-osc")) - *osc = rate; - else if (of_device_is_compatible(np, "fsl,imx-ckih1")) - *ckih1 = rate; - else if (of_device_is_compatible(np, "fsl,imx-ckih2")) - *ckih2 = rate; - } -} - -int __init mx51_clocks_init_dt(void) -{ - unsigned long ckil, osc, ckih1, ckih2; - - clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); - return mx51_clocks_init(ckil, osc, ckih1, ckih2); -} - -int __init mx53_clocks_init_dt(void) -{ - unsigned long ckil, osc, ckih1, ckih2; - - clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); - return mx53_clocks_init(ckil, osc, ckih1, ckih2); -} -#endif diff --git a/arch/arm/mach-imx/cpu-imx5.c b/arch/arm/mach-imx/cpu-imx5.c index aa15c517d06e..8eb15a2fcaf9 100644 --- a/arch/arm/mach-imx/cpu-imx5.c +++ b/arch/arm/mach-imx/cpu-imx5.c @@ -62,11 +62,8 @@ EXPORT_SYMBOL(mx51_revision); * Dependent on link order - so the assumption is that vfp_init is called * before us. */ -static int __init mx51_neon_fixup(void) +int __init mx51_neon_fixup(void) { - if (!cpu_is_mx51()) - return 0; - if (mx51_revision() < IMX_CHIP_REVISION_3_0 && (elf_hwcap & HWCAP_NEON)) { elf_hwcap &= ~HWCAP_NEON; @@ -75,7 +72,6 @@ static int __init mx51_neon_fixup(void) return 0; } -late_initcall(mx51_neon_fixup); #endif static int get_mx53_srev(void) diff --git a/arch/arm/mach-imx/crmregs-imx3.h b/arch/arm/mach-imx/crmregs-imx3.h index 53141273df45..a1dfde53e335 100644 --- a/arch/arm/mach-imx/crmregs-imx3.h +++ b/arch/arm/mach-imx/crmregs-imx3.h @@ -24,48 +24,47 @@ #define CKIH_CLK_FREQ_27MHZ 27000000 #define CKIL_CLK_FREQ 32768 -#define MXC_CCM_BASE (cpu_is_mx31() ? \ -MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR) : MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR)) +extern void __iomem *mx3_ccm_base; /* Register addresses */ -#define MXC_CCM_CCMR (MXC_CCM_BASE + 0x00) -#define MXC_CCM_PDR0 (MXC_CCM_BASE + 0x04) -#define MXC_CCM_PDR1 (MXC_CCM_BASE + 0x08) -#define MX35_CCM_PDR2 (MXC_CCM_BASE + 0x0C) -#define MXC_CCM_RCSR (MXC_CCM_BASE + 0x0C) -#define MX35_CCM_PDR3 (MXC_CCM_BASE + 0x10) -#define MXC_CCM_MPCTL (MXC_CCM_BASE + 0x10) -#define MX35_CCM_PDR4 (MXC_CCM_BASE + 0x14) -#define MXC_CCM_UPCTL (MXC_CCM_BASE + 0x14) -#define MX35_CCM_RCSR (MXC_CCM_BASE + 0x18) -#define MXC_CCM_SRPCTL (MXC_CCM_BASE + 0x18) -#define MX35_CCM_MPCTL (MXC_CCM_BASE + 0x1C) -#define MXC_CCM_COSR (MXC_CCM_BASE + 0x1C) -#define MX35_CCM_PPCTL (MXC_CCM_BASE + 0x20) -#define MXC_CCM_CGR0 (MXC_CCM_BASE + 0x20) -#define MX35_CCM_ACMR (MXC_CCM_BASE + 0x24) -#define MXC_CCM_CGR1 (MXC_CCM_BASE + 0x24) -#define MX35_CCM_COSR (MXC_CCM_BASE + 0x28) -#define MXC_CCM_CGR2 (MXC_CCM_BASE + 0x28) -#define MX35_CCM_CGR0 (MXC_CCM_BASE + 0x2C) -#define MXC_CCM_WIMR (MXC_CCM_BASE + 0x2C) -#define MX35_CCM_CGR1 (MXC_CCM_BASE + 0x30) -#define MXC_CCM_LDC (MXC_CCM_BASE + 0x30) -#define MX35_CCM_CGR2 (MXC_CCM_BASE + 0x34) -#define MXC_CCM_DCVR0 (MXC_CCM_BASE + 0x34) -#define MX35_CCM_CGR3 (MXC_CCM_BASE + 0x38) -#define MXC_CCM_DCVR1 (MXC_CCM_BASE + 0x38) -#define MXC_CCM_DCVR2 (MXC_CCM_BASE + 0x3C) -#define MXC_CCM_DCVR3 (MXC_CCM_BASE + 0x40) -#define MXC_CCM_LTR0 (MXC_CCM_BASE + 0x44) -#define MXC_CCM_LTR1 (MXC_CCM_BASE + 0x48) -#define MXC_CCM_LTR2 (MXC_CCM_BASE + 0x4C) -#define MXC_CCM_LTR3 (MXC_CCM_BASE + 0x50) -#define MXC_CCM_LTBR0 (MXC_CCM_BASE + 0x54) -#define MXC_CCM_LTBR1 (MXC_CCM_BASE + 0x58) -#define MXC_CCM_PMCR0 (MXC_CCM_BASE + 0x5C) -#define MXC_CCM_PMCR1 (MXC_CCM_BASE + 0x60) -#define MXC_CCM_PDR2 (MXC_CCM_BASE + 0x64) +#define MXC_CCM_CCMR 0x00 +#define MXC_CCM_PDR0 0x04 +#define MXC_CCM_PDR1 0x08 +#define MX35_CCM_PDR2 0x0C +#define MXC_CCM_RCSR 0x0C +#define MX35_CCM_PDR3 0x10 +#define MXC_CCM_MPCTL 0x10 +#define MX35_CCM_PDR4 0x14 +#define MXC_CCM_UPCTL 0x14 +#define MX35_CCM_RCSR 0x18 +#define MXC_CCM_SRPCTL 0x18 +#define MX35_CCM_MPCTL 0x1C +#define MXC_CCM_COSR 0x1C +#define MX35_CCM_PPCTL 0x20 +#define MXC_CCM_CGR0 0x20 +#define MX35_CCM_ACMR 0x24 +#define MXC_CCM_CGR1 0x24 +#define MX35_CCM_COSR 0x28 +#define MXC_CCM_CGR2 0x28 +#define MX35_CCM_CGR0 0x2C +#define MXC_CCM_WIMR 0x2C +#define MX35_CCM_CGR1 0x30 +#define MXC_CCM_LDC 0x30 +#define MX35_CCM_CGR2 0x34 +#define MXC_CCM_DCVR0 0x34 +#define MX35_CCM_CGR3 0x38 +#define MXC_CCM_DCVR1 0x38 +#define MXC_CCM_DCVR2 0x3C +#define MXC_CCM_DCVR3 0x40 +#define MXC_CCM_LTR0 0x44 +#define MXC_CCM_LTR1 0x48 +#define MXC_CCM_LTR2 0x4C +#define MXC_CCM_LTR3 0x50 +#define MXC_CCM_LTBR0 0x54 +#define MXC_CCM_LTBR1 0x58 +#define MXC_CCM_PMCR0 0x5C +#define MXC_CCM_PMCR1 0x60 +#define MXC_CCM_PDR2 0x64 /* Register bit definitions */ #define MXC_CCM_CCMR_WBEN (1 << 27) diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c index 5f577fbda2c8..18e78dba4298 100644 --- a/arch/arm/mach-imx/imx51-dt.c +++ b/arch/arm/mach-imx/imx51-dt.c @@ -118,6 +118,7 @@ DT_MACHINE_START(IMX51_DT, "Freescale i.MX51 (Device Tree Support)") .handle_irq = imx51_handle_irq, .timer = &imx51_timer, .init_machine = imx51_dt_init, + .init_late = imx51_init_late, .dt_compat = imx51_dt_board_compat, .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c index 574eca4b89a5..eb04b6248e48 100644 --- a/arch/arm/mach-imx/imx53-dt.c +++ b/arch/arm/mach-imx/imx53-dt.c @@ -10,6 +10,9 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/irqdomain.h> @@ -81,6 +84,19 @@ static const struct of_device_id imx53_iomuxc_of_match[] __initconst = { { /* sentinel */ } }; +static void __init imx53_qsb_init(void) +{ + struct clk *clk; + + clk = clk_get_sys(NULL, "ssi_ext1"); + if (IS_ERR(clk)) { + pr_err("failed to get clk ssi_ext1\n"); + return; + } + + clk_register_clkdev(clk, NULL, "0-000a"); +} + static void __init imx53_dt_init(void) { struct device_node *node; @@ -99,6 +115,9 @@ static void __init imx53_dt_init(void) of_node_put(node); } + if (of_machine_is_compatible("fsl,imx53-qsb")) + imx53_qsb_init(); + of_platform_populate(NULL, of_default_bus_match_table, imx53_auxdata_lookup, NULL); } diff --git a/arch/arm/mach-imx/lluart.c b/arch/arm/mach-imx/lluart.c index 0213f8dcee81..c40a34c00489 100644 --- a/arch/arm/mach-imx/lluart.c +++ b/arch/arm/mach-imx/lluart.c @@ -17,6 +17,12 @@ #include <mach/hardware.h> static struct map_desc imx_lluart_desc = { +#ifdef CONFIG_DEBUG_IMX6Q_UART2 + .virtual = MX6Q_IO_P2V(MX6Q_UART2_BASE_ADDR), + .pfn = __phys_to_pfn(MX6Q_UART2_BASE_ADDR), + .length = MX6Q_UART2_SIZE, + .type = MT_DEVICE, +#endif #ifdef CONFIG_DEBUG_IMX6Q_UART4 .virtual = MX6Q_IO_P2V(MX6Q_UART4_BASE_ADDR), .pfn = __phys_to_pfn(MX6Q_UART4_BASE_ADDR), diff --git a/arch/arm/mach-imx/mach-cpuimx51sd.c b/arch/arm/mach-imx/mach-cpuimx51sd.c index ce341a6874fc..ac50f1671e38 100644 --- a/arch/arm/mach-imx/mach-cpuimx51sd.c +++ b/arch/arm/mach-imx/mach-cpuimx51sd.c @@ -369,5 +369,6 @@ MACHINE_START(EUKREA_CPUIMX51SD, "Eukrea CPUIMX51SD") .handle_irq = imx51_handle_irq, .timer = &mxc_timer, .init_machine = eukrea_cpuimx51sd_init, + .init_late = imx51_init_late, .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 3df360a52c17..b47e98b7d539 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -10,6 +10,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#include <linux/clk.h> +#include <linux/clkdev.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/io.h> @@ -64,18 +66,53 @@ soft: /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ static int ksz9021rn_phy_fixup(struct phy_device *phydev) { - /* min rx data delay */ - phy_write(phydev, 0x0b, 0x8105); - phy_write(phydev, 0x0c, 0x0000); + if (IS_ENABLED(CONFIG_PHYLIB)) { + /* min rx data delay */ + phy_write(phydev, 0x0b, 0x8105); + phy_write(phydev, 0x0c, 0x0000); - /* max rx/tx clock delay, min rx/tx control delay */ - phy_write(phydev, 0x0b, 0x8104); - phy_write(phydev, 0x0c, 0xf0f0); - phy_write(phydev, 0x0b, 0x104); + /* max rx/tx clock delay, min rx/tx control delay */ + phy_write(phydev, 0x0b, 0x8104); + phy_write(phydev, 0x0c, 0xf0f0); + phy_write(phydev, 0x0b, 0x104); + } return 0; } +static void __init imx6q_sabrelite_cko1_setup(void) +{ + struct clk *cko1_sel, *ahb, *cko1; + unsigned long rate; + + cko1_sel = clk_get_sys(NULL, "cko1_sel"); + ahb = clk_get_sys(NULL, "ahb"); + cko1 = clk_get_sys(NULL, "cko1"); + if (IS_ERR(cko1_sel) || IS_ERR(ahb) || IS_ERR(cko1)) { + pr_err("cko1 setup failed!\n"); + goto put_clk; + } + clk_set_parent(cko1_sel, ahb); + rate = clk_round_rate(cko1, 16000000); + clk_set_rate(cko1, rate); + clk_register_clkdev(cko1, NULL, "0-000a"); +put_clk: + if (!IS_ERR(cko1_sel)) + clk_put(cko1_sel); + if (!IS_ERR(ahb)) + clk_put(ahb); + if (!IS_ERR(cko1)) + clk_put(cko1); +} + +static void __init imx6q_sabrelite_init(void) +{ + if (IS_ENABLED(CONFIG_PHYLIB)) + phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, + ksz9021rn_phy_fixup); + imx6q_sabrelite_cko1_setup(); +} + static void __init imx6q_init_machine(void) { /* @@ -85,8 +122,7 @@ static void __init imx6q_init_machine(void) pinctrl_provide_dummies(); if (of_machine_is_compatible("fsl,imx6q-sabrelite")) - phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, - ksz9021rn_phy_fixup); + imx6q_sabrelite_init(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); @@ -139,6 +175,7 @@ static struct sys_timer imx6q_timer = { static const char *imx6q_dt_compat[] __initdata = { "fsl,imx6q-arm2", "fsl,imx6q-sabrelite", + "fsl,imx6q-sabresd", "fsl,imx6q", NULL, }; diff --git a/arch/arm/mach-imx/mach-mx51_3ds.c b/arch/arm/mach-imx/mach-mx51_3ds.c index 83eab4176ca4..3c5b163923f6 100644 --- a/arch/arm/mach-imx/mach-mx51_3ds.c +++ b/arch/arm/mach-imx/mach-mx51_3ds.c @@ -175,5 +175,6 @@ MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board") .handle_irq = imx51_handle_irq, .timer = &mx51_3ds_timer, .init_machine = mx51_3ds_init, + .init_late = imx51_init_late, .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx51_babbage.c b/arch/arm/mach-imx/mach-mx51_babbage.c index e4b822e9f719..dde397014d4b 100644 --- a/arch/arm/mach-imx/mach-mx51_babbage.c +++ b/arch/arm/mach-imx/mach-mx51_babbage.c @@ -163,6 +163,12 @@ static iomux_v3_cfg_t mx51babbage_pads[] = { MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK, MX51_PAD_CSPI1_SS0__GPIO4_24, MX51_PAD_CSPI1_SS1__GPIO4_25, + + /* Audio */ + MX51_PAD_AUD3_BB_TXD__AUD3_TXD, + MX51_PAD_AUD3_BB_RXD__AUD3_RXD, + MX51_PAD_AUD3_BB_CK__AUD3_TXC, + MX51_PAD_AUD3_BB_FS__AUD3_TXFS, }; /* Serial ports */ @@ -426,5 +432,6 @@ MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board") .handle_irq = imx51_handle_irq, .timer = &mx51_babbage_timer, .init_machine = mx51_babbage_init, + .init_late = imx51_init_late, .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx51_efikamx.c b/arch/arm/mach-imx/mach-mx51_efikamx.c index 86e96ef11f9d..8d09c0126cab 100644 --- a/arch/arm/mach-imx/mach-mx51_efikamx.c +++ b/arch/arm/mach-imx/mach-mx51_efikamx.c @@ -207,29 +207,32 @@ static void mx51_efikamx_power_off(void) static int __init mx51_efikamx_power_init(void) { - if (machine_is_mx51_efikamx()) { - pwgt1 = regulator_get(NULL, "pwgt1"); - pwgt2 = regulator_get(NULL, "pwgt2"); - if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { - regulator_enable(pwgt1); - regulator_enable(pwgt2); - } - gpio_request(EFIKAMX_POWEROFF, "poweroff"); - pm_power_off = mx51_efikamx_power_off; - - /* enable coincell charger. maybe need a small power driver ? */ - coincell = regulator_get(NULL, "coincell"); - if (!IS_ERR(coincell)) { - regulator_set_voltage(coincell, 3000000, 3000000); - regulator_enable(coincell); - } - - regulator_has_full_constraints(); + pwgt1 = regulator_get(NULL, "pwgt1"); + pwgt2 = regulator_get(NULL, "pwgt2"); + if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { + regulator_enable(pwgt1); + regulator_enable(pwgt2); + } + gpio_request(EFIKAMX_POWEROFF, "poweroff"); + pm_power_off = mx51_efikamx_power_off; + + /* enable coincell charger. maybe need a small power driver ? */ + coincell = regulator_get(NULL, "coincell"); + if (!IS_ERR(coincell)) { + regulator_set_voltage(coincell, 3000000, 3000000); + regulator_enable(coincell); } + regulator_has_full_constraints(); + return 0; } -late_initcall(mx51_efikamx_power_init); + +static void __init mx51_efikamx_init_late(void) +{ + imx51_init_late(); + mx51_efikamx_power_init(); +} static void __init mx51_efikamx_init(void) { @@ -292,5 +295,6 @@ MACHINE_START(MX51_EFIKAMX, "Genesi Efika MX (Smarttop)") .handle_irq = imx51_handle_irq, .timer = &mx51_efikamx_timer, .init_machine = mx51_efikamx_init, + .init_late = mx51_efikamx_init_late, .restart = mx51_efikamx_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx51_efikasb.c b/arch/arm/mach-imx/mach-mx51_efikasb.c index 88f837a6cc76..fdbd181b97ef 100644 --- a/arch/arm/mach-imx/mach-mx51_efikasb.c +++ b/arch/arm/mach-imx/mach-mx51_efikasb.c @@ -211,22 +211,25 @@ static void mx51_efikasb_power_off(void) static int __init mx51_efikasb_power_init(void) { - if (machine_is_mx51_efikasb()) { - pwgt1 = regulator_get(NULL, "pwgt1"); - pwgt2 = regulator_get(NULL, "pwgt2"); - if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { - regulator_enable(pwgt1); - regulator_enable(pwgt2); - } - gpio_request(EFIKASB_POWEROFF, "poweroff"); - pm_power_off = mx51_efikasb_power_off; - - regulator_has_full_constraints(); + pwgt1 = regulator_get(NULL, "pwgt1"); + pwgt2 = regulator_get(NULL, "pwgt2"); + if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { + regulator_enable(pwgt1); + regulator_enable(pwgt2); } + gpio_request(EFIKASB_POWEROFF, "poweroff"); + pm_power_off = mx51_efikasb_power_off; + + regulator_has_full_constraints(); return 0; } -late_initcall(mx51_efikasb_power_init); + +static void __init mx51_efikasb_init_late(void) +{ + imx51_init_late(); + mx51_efikasb_power_init(); +} /* 01 R1.3 board 10 R2.0 board */ @@ -287,6 +290,7 @@ MACHINE_START(MX51_EFIKASB, "Genesi Efika MX (Smartbook)") .init_irq = mx51_init_irq, .handle_irq = imx51_handle_irq, .init_machine = efikasb_board_init, + .init_late = mx51_efikasb_init_late, .timer = &mx51_efikasb_timer, .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c index 10c9795934a3..0a40004154f2 100644 --- a/arch/arm/mach-imx/mach-pcm037.c +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -694,6 +694,11 @@ static void __init pcm037_reserve(void) MX3_CAMERA_BUF_SIZE); } +static void __init pcm037_init_late(void) +{ + pcm037_eet_init_devices(); +} + MACHINE_START(PCM037, "Phytec Phycore pcm037") /* Maintainer: Pengutronix */ .atag_offset = 0x100, @@ -704,5 +709,6 @@ MACHINE_START(PCM037, "Phytec Phycore pcm037") .handle_irq = imx31_handle_irq, .timer = &pcm037_timer, .init_machine = pcm037_init, + .init_late = pcm037_init_late, .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm037_eet.c b/arch/arm/mach-imx/mach-pcm037_eet.c index 1b7606bef8f4..11ffa81ad17d 100644 --- a/arch/arm/mach-imx/mach-pcm037_eet.c +++ b/arch/arm/mach-imx/mach-pcm037_eet.c @@ -160,9 +160,9 @@ static const struct gpio_keys_platform_data .rep = 0, /* No auto-repeat */ }; -static int __init eet_init_devices(void) +int __init pcm037_eet_init_devices(void) { - if (!machine_is_pcm037() || pcm037_variant() != PCM037_EET) + if (pcm037_variant() != PCM037_EET) return 0; mxc_iomux_setup_multiple_pins(pcm037_eet_pins, @@ -176,4 +176,3 @@ static int __init eet_init_devices(void) return 0; } -late_initcall(eet_init_devices); diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c index 9128d15b1eb7..967ed5b35a45 100644 --- a/arch/arm/mach-imx/mm-imx3.c +++ b/arch/arm/mach-imx/mm-imx3.c @@ -32,6 +32,10 @@ #include <mach/iomux-v3.h> #include <mach/irqs.h> +#include "crmregs-imx3.h" + +void __iomem *mx3_ccm_base; + static void imx3_idle(void) { unsigned long reg = 0; @@ -138,6 +142,7 @@ void __init imx31_init_early(void) mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); arch_ioremap_caller = imx3_ioremap_caller; arm_pm_idle = imx3_idle; + mx3_ccm_base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); } void __init mx31_init_irq(void) @@ -211,6 +216,7 @@ void __init imx35_init_early(void) mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); arm_pm_idle = imx3_idle; arch_ioremap_caller = imx3_ioremap_caller; + mx3_ccm_base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR); } void __init mx35_init_irq(void) diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c index ba91e6b31cf4..feeee17da96b 100644 --- a/arch/arm/mach-imx/mm-imx5.c +++ b/arch/arm/mach-imx/mm-imx5.c @@ -33,6 +33,7 @@ static void imx5_idle(void) gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); if (IS_ERR(gpc_dvfs_clk)) return; + clk_prepare(gpc_dvfs_clk); } clk_enable(gpc_dvfs_clk); mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); @@ -236,3 +237,8 @@ void __init imx53_soc_init(void) platform_device_register_simple("imx31-audmux", 0, imx53_audmux_res, ARRAY_SIZE(imx53_audmux_res)); } + +void __init imx51_init_late(void) +{ + mx51_neon_fixup(); +} diff --git a/arch/arm/mach-imx/pcm037.h b/arch/arm/mach-imx/pcm037.h index d6929721a5fd..7d167690e17d 100644 --- a/arch/arm/mach-imx/pcm037.h +++ b/arch/arm/mach-imx/pcm037.h @@ -8,4 +8,10 @@ enum pcm037_board_variant { extern enum pcm037_board_variant pcm037_variant(void); +#ifdef CONFIG_MACH_PCM037_EET +int pcm037_eet_init_devices(void); +#else +static inline int pcm037_eet_init_devices(void) { return 0; } +#endif + #endif diff --git a/arch/arm/mach-imx/pm-imx3.c b/arch/arm/mach-imx/pm-imx3.c index b3752439632e..822103bdb709 100644 --- a/arch/arm/mach-imx/pm-imx3.c +++ b/arch/arm/mach-imx/pm-imx3.c @@ -21,14 +21,14 @@ */ void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode) { - int reg = __raw_readl(MXC_CCM_CCMR); + int reg = __raw_readl(mx3_ccm_base + MXC_CCM_CCMR); reg &= ~MXC_CCM_CCMR_LPM_MASK; switch (mode) { case MX3_WAIT: if (cpu_is_mx35()) reg |= MXC_CCM_CCMR_LPM_WAIT_MX35; - __raw_writel(reg, MXC_CCM_CCMR); + __raw_writel(reg, mx3_ccm_base + MXC_CCM_CCMR); break; default: pr_err("Unknown cpu power mode: %d\n", mode); diff --git a/arch/arm/mach-kirkwood/board-dreamplug.c b/arch/arm/mach-kirkwood/board-dreamplug.c index 985453994dd3..55e357ab2923 100644 --- a/arch/arm/mach-kirkwood/board-dreamplug.c +++ b/arch/arm/mach-kirkwood/board-dreamplug.c @@ -27,7 +27,6 @@ #include <linux/mtd/physmap.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c index 10d1969b9e3a..edc3f8a9d45e 100644 --- a/arch/arm/mach-kirkwood/board-dt.c +++ b/arch/arm/mach-kirkwood/board-dt.c @@ -43,6 +43,9 @@ static void __init kirkwood_dt_init(void) kirkwood_l2_init(); #endif + /* Setup root of clk tree */ + kirkwood_clk_init(); + /* internal devices that every board has */ kirkwood_wdt_init(); kirkwood_xor0_init(); diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index 3ad037385a5e..25fb3fd418ef 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -15,7 +15,8 @@ #include <linux/ata_platform.h> #include <linux/mtd/nand.h> #include <linux/dma-mapping.h> -#include <linux/of.h> +#include <linux/clk-provider.h> +#include <linux/spinlock.h> #include <net/dsa.h> #include <asm/page.h> #include <asm/timex.h> @@ -32,6 +33,7 @@ #include <plat/common.h> #include <plat/time.h> #include <plat/addr-map.h> +#include <plat/mv_xor.h> #include "common.h" /***************************************************************************** @@ -61,20 +63,188 @@ void __init kirkwood_map_io(void) iotable_init(kirkwood_io_desc, ARRAY_SIZE(kirkwood_io_desc)); } -/* - * Default clock control bits. Any bit _not_ set in this variable - * will be cleared from the hardware after platform devices have been - * registered. Some reserved bits must be set to 1. - */ -unsigned int kirkwood_clk_ctrl = CGC_DUNIT | CGC_RESERVED; +/***************************************************************************** + * CLK tree + ****************************************************************************/ + +static void disable_sata0(void) +{ + /* Disable PLL and IVREF */ + writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2); + /* Disable PHY */ + writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL); +} + +static void disable_sata1(void) +{ + /* Disable PLL and IVREF */ + writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2); + /* Disable PHY */ + writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL); +} + +static void disable_pcie0(void) +{ + writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL); + while (1) + if (readl(PCIE_STATUS) & 0x1) + break; + writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL); +} + +static void disable_pcie1(void) +{ + u32 dev, rev; + + kirkwood_pcie_id(&dev, &rev); + + if (dev == MV88F6282_DEV_ID) { + writel(readl(PCIE1_LINK_CTRL) | 0x10, PCIE1_LINK_CTRL); + while (1) + if (readl(PCIE1_STATUS) & 0x1) + break; + writel(readl(PCIE1_LINK_CTRL) & ~0x10, PCIE1_LINK_CTRL); + } +} + +/* An extended version of the gated clk. This calls fn() before + * disabling the clock. We use this to turn off PHYs etc. */ +struct clk_gate_fn { + struct clk_gate gate; + void (*fn)(void); +}; + +#define to_clk_gate_fn(_gate) container_of(_gate, struct clk_gate_fn, gate) +#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) + +static void clk_gate_fn_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct clk_gate_fn *gate_fn = to_clk_gate_fn(gate); + + if (gate_fn->fn) + gate_fn->fn(); + + clk_gate_ops.disable(hw); +} + +static struct clk_ops clk_gate_fn_ops; + +static struct clk __init *clk_register_gate_fn(struct device *dev, + const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock, + void (*fn)(void)) +{ + struct clk_gate_fn *gate_fn; + struct clk *clk; + struct clk_init_data init; + + gate_fn = kzalloc(sizeof(struct clk_gate_fn), GFP_KERNEL); + if (!gate_fn) { + pr_err("%s: could not allocate gated clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &clk_gate_fn_ops; + init.flags = flags; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + /* struct clk_gate assignments */ + gate_fn->gate.reg = reg; + gate_fn->gate.bit_idx = bit_idx; + gate_fn->gate.flags = clk_gate_flags; + gate_fn->gate.lock = lock; + gate_fn->gate.hw.init = &init; + + /* ops is the gate ops, but with our disable function */ + if (clk_gate_fn_ops.disable != clk_gate_fn_disable) { + clk_gate_fn_ops = clk_gate_ops; + clk_gate_fn_ops.disable = clk_gate_fn_disable; + } + clk = clk_register(dev, &gate_fn->gate.hw); + + if (IS_ERR(clk)) + kfree(gate_fn); + + return clk; +} + +static DEFINE_SPINLOCK(gating_lock); +static struct clk *tclk; + +static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx) +{ + return clk_register_gate(NULL, name, "tclk", 0, + (void __iomem *)CLOCK_GATING_CTRL, + bit_idx, 0, &gating_lock); +} + +static struct clk __init *kirkwood_register_gate_fn(const char *name, + u8 bit_idx, + void (*fn)(void)) +{ + return clk_register_gate_fn(NULL, name, "tclk", 0, + (void __iomem *)CLOCK_GATING_CTRL, + bit_idx, 0, &gating_lock, fn); +} + +void __init kirkwood_clk_init(void) +{ + struct clk *runit, *ge0, *ge1, *sata0, *sata1, *usb0, *sdio; + struct clk *crypto, *xor0, *xor1, *pex0, *pex1, *audio; + + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, + CLK_IS_ROOT, kirkwood_tclk); + + runit = kirkwood_register_gate("runit", CGC_BIT_RUNIT); + ge0 = kirkwood_register_gate("ge0", CGC_BIT_GE0); + ge1 = kirkwood_register_gate("ge1", CGC_BIT_GE1); + sata0 = kirkwood_register_gate_fn("sata0", CGC_BIT_SATA0, + disable_sata0); + sata1 = kirkwood_register_gate_fn("sata1", CGC_BIT_SATA1, + disable_sata1); + usb0 = kirkwood_register_gate("usb0", CGC_BIT_USB0); + sdio = kirkwood_register_gate("sdio", CGC_BIT_SDIO); + crypto = kirkwood_register_gate("crypto", CGC_BIT_CRYPTO); + xor0 = kirkwood_register_gate("xor0", CGC_BIT_XOR0); + xor1 = kirkwood_register_gate("xor1", CGC_BIT_XOR1); + pex0 = kirkwood_register_gate_fn("pex0", CGC_BIT_PEX0, + disable_pcie0); + pex1 = kirkwood_register_gate_fn("pex1", CGC_BIT_PEX1, + disable_pcie1); + audio = kirkwood_register_gate("audio", CGC_BIT_AUDIO); + kirkwood_register_gate("tdm", CGC_BIT_TDM); + kirkwood_register_gate("tsu", CGC_BIT_TSU); + + /* clkdev entries, mapping clks to devices */ + orion_clkdev_add(NULL, "orion_spi.0", runit); + orion_clkdev_add(NULL, "orion_spi.1", runit); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", ge0); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", ge1); + orion_clkdev_add(NULL, "orion_wdt", tclk); + orion_clkdev_add("0", "sata_mv.0", sata0); + orion_clkdev_add("1", "sata_mv.0", sata1); + orion_clkdev_add(NULL, "orion-ehci.0", usb0); + orion_clkdev_add(NULL, "orion_nand", runit); + orion_clkdev_add(NULL, "mvsdio", sdio); + orion_clkdev_add(NULL, "mv_crypto", crypto); + orion_clkdev_add(NULL, MV_XOR_SHARED_NAME ".0", xor0); + orion_clkdev_add(NULL, MV_XOR_SHARED_NAME ".1", xor1); + orion_clkdev_add("0", "pcie", pex0); + orion_clkdev_add("1", "pcie", pex1); + orion_clkdev_add(NULL, "kirkwood-i2s", audio); +} /***************************************************************************** * EHCI0 ****************************************************************************/ void __init kirkwood_ehci_init(void) { - kirkwood_clk_ctrl |= CGC_USB0; orion_ehci_init(USB_PHYS_BASE, IRQ_KIRKWOOD_USB, EHCI_PHY_NA); } @@ -84,11 +254,9 @@ void __init kirkwood_ehci_init(void) ****************************************************************************/ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) { - kirkwood_clk_ctrl |= CGC_GE0; - orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM, - IRQ_KIRKWOOD_GE00_ERR, kirkwood_tclk); + IRQ_KIRKWOOD_GE00_ERR); } @@ -97,12 +265,9 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) ****************************************************************************/ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data) { - - kirkwood_clk_ctrl |= CGC_GE1; - orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM, - IRQ_KIRKWOOD_GE01_ERR, kirkwood_tclk); + IRQ_KIRKWOOD_GE01_ERR); } @@ -144,7 +309,6 @@ static struct platform_device kirkwood_nand_flash = { void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int chip_delay) { - kirkwood_clk_ctrl |= CGC_RUNIT; kirkwood_nand_data.parts = parts; kirkwood_nand_data.nr_parts = nr_parts; kirkwood_nand_data.chip_delay = chip_delay; @@ -154,7 +318,6 @@ void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, void __init kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *)) { - kirkwood_clk_ctrl |= CGC_RUNIT; kirkwood_nand_data.parts = parts; kirkwood_nand_data.nr_parts = nr_parts; kirkwood_nand_data.dev_ready = dev_ready; @@ -175,10 +338,6 @@ static void __init kirkwood_rtc_init(void) ****************************************************************************/ void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data) { - kirkwood_clk_ctrl |= CGC_SATA0; - if (sata_data->n_ports > 1) - kirkwood_clk_ctrl |= CGC_SATA1; - orion_sata_init(sata_data, SATA_PHYS_BASE, IRQ_KIRKWOOD_SATA); } @@ -221,7 +380,6 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data) mvsdio_data->clock = 100000000; else mvsdio_data->clock = 200000000; - kirkwood_clk_ctrl |= CGC_SDIO; kirkwood_sdio.dev.platform_data = mvsdio_data; platform_device_register(&kirkwood_sdio); } @@ -232,8 +390,7 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data) ****************************************************************************/ void __init kirkwood_spi_init() { - kirkwood_clk_ctrl |= CGC_RUNIT; - orion_spi_init(SPI_PHYS_BASE, kirkwood_tclk); + orion_spi_init(SPI_PHYS_BASE); } @@ -253,7 +410,7 @@ void __init kirkwood_i2c_init(void) void __init kirkwood_uart0_init(void) { orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE, - IRQ_KIRKWOOD_UART_0, kirkwood_tclk); + IRQ_KIRKWOOD_UART_0, tclk); } @@ -263,7 +420,7 @@ void __init kirkwood_uart0_init(void) void __init kirkwood_uart1_init(void) { orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE, - IRQ_KIRKWOOD_UART_1, kirkwood_tclk); + IRQ_KIRKWOOD_UART_1, tclk); } /***************************************************************************** @@ -271,7 +428,6 @@ void __init kirkwood_uart1_init(void) ****************************************************************************/ void __init kirkwood_crypto_init(void) { - kirkwood_clk_ctrl |= CGC_CRYPTO; orion_crypto_init(CRYPTO_PHYS_BASE, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE, IRQ_KIRKWOOD_CRYPTO); } @@ -282,8 +438,6 @@ void __init kirkwood_crypto_init(void) ****************************************************************************/ void __init kirkwood_xor0_init(void) { - kirkwood_clk_ctrl |= CGC_XOR0; - orion_xor0_init(XOR0_PHYS_BASE, XOR0_HIGH_PHYS_BASE, IRQ_KIRKWOOD_XOR_00, IRQ_KIRKWOOD_XOR_01); } @@ -294,8 +448,6 @@ void __init kirkwood_xor0_init(void) ****************************************************************************/ void __init kirkwood_xor1_init(void) { - kirkwood_clk_ctrl |= CGC_XOR1; - orion_xor1_init(XOR1_PHYS_BASE, XOR1_HIGH_PHYS_BASE, IRQ_KIRKWOOD_XOR_10, IRQ_KIRKWOOD_XOR_11); } @@ -306,7 +458,7 @@ void __init kirkwood_xor1_init(void) ****************************************************************************/ void __init kirkwood_wdt_init(void) { - orion_wdt_init(kirkwood_tclk); + orion_wdt_init(); } @@ -382,7 +534,6 @@ static struct platform_device kirkwood_pcm_device = { void __init kirkwood_audio_init(void) { - kirkwood_clk_ctrl |= CGC_AUDIO; platform_device_register(&kirkwood_i2s_device); platform_device_register(&kirkwood_pcm_device); } @@ -466,6 +617,9 @@ void __init kirkwood_init(void) kirkwood_l2_init(); #endif + /* Setup root of clk tree */ + kirkwood_clk_init(); + /* internal devices that every board has */ kirkwood_rtc_init(); kirkwood_wdt_init(); @@ -478,72 +632,6 @@ void __init kirkwood_init(void) #endif } -static int __init kirkwood_clock_gate(void) -{ - unsigned int curr = readl(CLOCK_GATING_CTRL); - u32 dev, rev; - -#ifdef CONFIG_OF - struct device_node *np; -#endif - kirkwood_pcie_id(&dev, &rev); - printk(KERN_DEBUG "Gating clock of unused units\n"); - printk(KERN_DEBUG "before: 0x%08x\n", curr); - - /* Make sure those units are accessible */ - writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0 | CGC_PEX1, CLOCK_GATING_CTRL); - -#ifdef CONFIG_OF - np = of_find_compatible_node(NULL, NULL, "mrvl,orion-nand"); - if (np && of_device_is_available(np)) { - kirkwood_clk_ctrl |= CGC_RUNIT; - of_node_put(np); - } -#endif - - /* For SATA: first shutdown the phy */ - if (!(kirkwood_clk_ctrl & CGC_SATA0)) { - /* Disable PLL and IVREF */ - writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2); - /* Disable PHY */ - writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL); - } - if (!(kirkwood_clk_ctrl & CGC_SATA1)) { - /* Disable PLL and IVREF */ - writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2); - /* Disable PHY */ - writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL); - } - - /* For PCIe: first shutdown the phy */ - if (!(kirkwood_clk_ctrl & CGC_PEX0)) { - writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL); - while (1) - if (readl(PCIE_STATUS) & 0x1) - break; - writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL); - } - - /* For PCIe 1: first shutdown the phy */ - if (dev == MV88F6282_DEV_ID) { - if (!(kirkwood_clk_ctrl & CGC_PEX1)) { - writel(readl(PCIE1_LINK_CTRL) | 0x10, PCIE1_LINK_CTRL); - while (1) - if (readl(PCIE1_STATUS) & 0x1) - break; - writel(readl(PCIE1_LINK_CTRL) & ~0x10, PCIE1_LINK_CTRL); - } - } else /* keep this bit set for devices that don't have PCIe1 */ - kirkwood_clk_ctrl |= CGC_PEX1; - - /* Now gate clock the required units */ - writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL); - printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL)); - - return 0; -} -late_initcall(kirkwood_clock_gate); - void kirkwood_restart(char mode, const char *cmd) { /* diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h index a34c41a5172e..9248fa2c165b 100644 --- a/arch/arm/mach-kirkwood/common.h +++ b/arch/arm/mach-kirkwood/common.h @@ -50,6 +50,7 @@ void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay); void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *)); void kirkwood_audio_init(void); void kirkwood_restart(char, const char *); +void kirkwood_clk_init(void); /* board init functions for boards not fully converted to fdt */ #ifdef CONFIG_MACH_DREAMPLUG_DT diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h index 957bd7997d7e..3eee37a3b501 100644 --- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h +++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h @@ -43,6 +43,22 @@ #define L2_WRITETHROUGH 0x00000010 #define CLOCK_GATING_CTRL (BRIDGE_VIRT_BASE | 0x11c) +#define CGC_BIT_GE0 (0) +#define CGC_BIT_PEX0 (2) +#define CGC_BIT_USB0 (3) +#define CGC_BIT_SDIO (4) +#define CGC_BIT_TSU (5) +#define CGC_BIT_DUNIT (6) +#define CGC_BIT_RUNIT (7) +#define CGC_BIT_XOR0 (8) +#define CGC_BIT_AUDIO (9) +#define CGC_BIT_SATA0 (14) +#define CGC_BIT_SATA1 (15) +#define CGC_BIT_XOR1 (16) +#define CGC_BIT_CRYPTO (17) +#define CGC_BIT_PEX1 (18) +#define CGC_BIT_GE1 (19) +#define CGC_BIT_TDM (20) #define CGC_GE0 (1 << 0) #define CGC_PEX0 (1 << 2) #define CGC_USB0 (1 << 3) diff --git a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c index 85f6169c2484..6d8364a97810 100644 --- a/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c +++ b/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c @@ -23,7 +23,6 @@ #include <linux/gpio_keys.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <net/dsa.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c index de373176ee67..6e8b2efa3c35 100644 --- a/arch/arm/mach-kirkwood/pcie.c +++ b/arch/arm/mach-kirkwood/pcie.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/slab.h> +#include <linux/clk.h> #include <video/vga.h> #include <asm/irq.h> #include <asm/mach/pci.h> @@ -19,6 +20,23 @@ #include <plat/addr-map.h> #include "common.h" +static void kirkwood_enable_pcie_clk(const char *port) +{ + struct clk *clk; + + clk = clk_get_sys("pcie", port); + if (IS_ERR(clk)) { + printk(KERN_ERR "PCIE clock %s missing\n", port); + return; + } + clk_prepare_enable(clk); + clk_put(clk); +} + +/* This function is called very early in the boot when probing the + hardware to determine what we actually are, and what rate tclk is + ticking at. Hence calling kirkwood_enable_pcie_clk() is not + possible since the clk tree has not been created yet. */ void kirkwood_enable_pcie(void) { u32 curr = readl(CLOCK_GATING_CTRL); @@ -26,7 +44,7 @@ void kirkwood_enable_pcie(void) writel(curr | CGC_PEX0, CLOCK_GATING_CTRL); } -void __init kirkwood_pcie_id(u32 *dev, u32 *rev) +void kirkwood_pcie_id(u32 *dev, u32 *rev) { kirkwood_enable_pcie(); *dev = orion_pcie_dev_id((void __iomem *)PCIE_VIRT_BASE); @@ -159,7 +177,6 @@ static void __init pcie1_ioresources_init(struct pcie_port *pp) static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys) { - extern unsigned int kirkwood_clk_ctrl; struct pcie_port *pp; int index; @@ -178,11 +195,11 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys) switch (index) { case 0: - kirkwood_clk_ctrl |= CGC_PEX0; + kirkwood_enable_pcie_clk("0"); pcie0_ioresources_init(pp); break; case 1: - kirkwood_clk_ctrl |= CGC_PEX1; + kirkwood_enable_pcie_clk("1"); pcie1_ioresources_init(pp); break; default: diff --git a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c index fd2c9c8b6831..f742a66a7045 100644 --- a/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c +++ b/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c @@ -16,7 +16,6 @@ #include <linux/gpio.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <mach/kirkwood.h> diff --git a/arch/arm/mach-kirkwood/t5325-setup.c b/arch/arm/mach-kirkwood/t5325-setup.c index f9d2a11b7f96..bad738e44044 100644 --- a/arch/arm/mach-kirkwood/t5325-setup.c +++ b/arch/arm/mach-kirkwood/t5325-setup.c @@ -16,7 +16,6 @@ #include <linux/mtd/physmap.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/i2c.h> #include <linux/mv643xx_eth.h> #include <linux/ata_platform.h> diff --git a/arch/arm/mach-kirkwood/tsx1x-common.c b/arch/arm/mach-kirkwood/tsx1x-common.c index 24294b2bc469..8943ede29b44 100644 --- a/arch/arm/mach-kirkwood/tsx1x-common.c +++ b/arch/arm/mach-kirkwood/tsx1x-common.c @@ -4,7 +4,6 @@ #include <linux/mtd/physmap.h> #include <linux/spi/flash.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/serial_reg.h> #include <mach/kirkwood.h> #include "common.h" diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 26aac363a064..4fa3e99d9a62 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -94,6 +94,11 @@ static void __init halibut_map_io(void) msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } +static void __init halibut_init_late(void) +{ + smd_debugfs_init(); +} + MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") .atag_offset = 0x100, .fixup = halibut_fixup, @@ -101,5 +106,6 @@ MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)") .init_early = halibut_init_early, .init_irq = halibut_init_irq, .init_machine = halibut_init, + .init_late = halibut_init_late, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c index 5a4882fc6f7a..cf1f89a5dc62 100644 --- a/arch/arm/mach-msm/board-mahimahi.c +++ b/arch/arm/mach-msm/board-mahimahi.c @@ -71,6 +71,11 @@ static void __init mahimahi_map_io(void) msm_clock_init(); } +static void __init mahimahi_init_late(void) +{ + smd_debugfs_init(); +} + extern struct sys_timer msm_timer; MACHINE_START(MAHIMAHI, "mahimahi") @@ -79,5 +84,6 @@ MACHINE_START(MAHIMAHI, "mahimahi") .map_io = mahimahi_map_io, .init_irq = msm_init_irq, .init_machine = mahimahi_init, + .init_late = mahimahi_init_late, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c index 6d84ee740df4..451ab1d43c92 100644 --- a/arch/arm/mach-msm/board-msm7x27.c +++ b/arch/arm/mach-msm/board-msm7x27.c @@ -128,11 +128,17 @@ static void __init msm7x2x_map_io(void) #endif } +static void __init msm7x2x_init_late(void) +{ + smd_debugfs_init(); +} + MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF") .atag_offset = 0x100, .map_io = msm7x2x_map_io, .init_irq = msm7x2x_init_irq, .init_machine = msm7x2x_init, + .init_late = msm7x2x_init_late, .timer = &msm_timer, MACHINE_END @@ -141,6 +147,7 @@ MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA") .map_io = msm7x2x_map_io, .init_irq = msm7x2x_init_irq, .init_machine = msm7x2x_init, + .init_late = msm7x2x_init_late, .timer = &msm_timer, MACHINE_END @@ -149,6 +156,7 @@ MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF") .map_io = msm7x2x_map_io, .init_irq = msm7x2x_init_irq, .init_machine = msm7x2x_init, + .init_late = msm7x2x_init_late, .timer = &msm_timer, MACHINE_END @@ -157,5 +165,6 @@ MACHINE_START(MSM7X25_FFA, "QCT MSM7x25 FFA") .map_io = msm7x2x_map_io, .init_irq = msm7x2x_init_irq, .init_machine = msm7x2x_init, + .init_late = msm7x2x_init_late, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c index 75b3cfcada6d..a5001378135d 100644 --- a/arch/arm/mach-msm/board-msm7x30.c +++ b/arch/arm/mach-msm/board-msm7x30.c @@ -119,6 +119,11 @@ static void __init msm7x30_map_io(void) msm_clock_init(msm_clocks_7x30, msm_num_clocks_7x30); } +static void __init msm7x30_init_late(void) +{ + smd_debugfs_init(); +} + MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF") .atag_offset = 0x100, .fixup = msm7x30_fixup, @@ -126,6 +131,7 @@ MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF") .map_io = msm7x30_map_io, .init_irq = msm7x30_init_irq, .init_machine = msm7x30_init, + .init_late = msm7x30_init_late, .timer = &msm_timer, MACHINE_END @@ -136,6 +142,7 @@ MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA") .map_io = msm7x30_map_io, .init_irq = msm7x30_init_irq, .init_machine = msm7x30_init, + .init_late = msm7x30_init_late, .timer = &msm_timer, MACHINE_END @@ -146,5 +153,6 @@ MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID") .map_io = msm7x30_map_io, .init_irq = msm7x30_init_irq, .init_machine = msm7x30_init, + .init_late = msm7x30_init_late, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c index ed3598128530..65f4a1daa2e5 100644 --- a/arch/arm/mach-msm/board-msm8960.c +++ b/arch/arm/mach-msm/board-msm8960.c @@ -93,6 +93,11 @@ static void __init msm8960_rumi3_init(void) platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices)); } +static void __init msm8960_init_late(void) +{ + smd_debugfs_init(); +} + MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR") .fixup = msm8960_fixup, .reserve = msm8960_reserve, @@ -101,6 +106,7 @@ MACHINE_START(MSM8960_SIM, "QCT MSM8960 SIMULATOR") .timer = &msm_timer, .handle_irq = gic_handle_irq, .init_machine = msm8960_sim_init, + .init_late = msm8960_init_late, MACHINE_END MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3") @@ -111,5 +117,6 @@ MACHINE_START(MSM8960_RUMI3, "QCT MSM8960 RUMI3") .timer = &msm_timer, .handle_irq = gic_handle_irq, .init_machine = msm8960_rumi3_init, + .init_late = msm8960_init_late, MACHINE_END diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c index fb3496a52ef4..e37a724cd1eb 100644 --- a/arch/arm/mach-msm/board-msm8x60.c +++ b/arch/arm/mach-msm/board-msm8x60.c @@ -81,6 +81,11 @@ static void __init msm8x60_init(void) { } +static void __init msm8x60_init_late(void) +{ + smd_debugfs_init(); +} + #ifdef CONFIG_OF static struct of_dev_auxdata msm_auxdata_lookup[] __initdata = { {} @@ -111,6 +116,7 @@ MACHINE_START(MSM8X60_RUMI3, "QCT MSM8X60 RUMI3") .init_irq = msm8x60_init_irq, .handle_irq = gic_handle_irq, .init_machine = msm8x60_init, + .init_late = msm8x60_init_late, .timer = &msm_timer, MACHINE_END @@ -121,6 +127,7 @@ MACHINE_START(MSM8X60_SURF, "QCT MSM8X60 SURF") .init_irq = msm8x60_init_irq, .handle_irq = gic_handle_irq, .init_machine = msm8x60_init, + .init_late = msm8x60_init_late, .timer = &msm_timer, MACHINE_END @@ -131,6 +138,7 @@ MACHINE_START(MSM8X60_SIM, "QCT MSM8X60 SIMULATOR") .init_irq = msm8x60_init_irq, .handle_irq = gic_handle_irq, .init_machine = msm8x60_init, + .init_late = msm8x60_init_late, .timer = &msm_timer, MACHINE_END @@ -141,6 +149,7 @@ MACHINE_START(MSM8X60_FFA, "QCT MSM8X60 FFA") .init_irq = msm8x60_init_irq, .handle_irq = gic_handle_irq, .init_machine = msm8x60_init, + .init_late = msm8x60_init_late, .timer = &msm_timer, MACHINE_END @@ -150,6 +159,7 @@ DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)") .map_io = msm8x60_map_io, .init_irq = msm8x60_init_irq, .init_machine = msm8x60_dt_init, + .init_late = msm8x60_init_late, .timer = &msm_timer, .dt_compat = msm8x60_fluid_match, MACHINE_END diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c index fbaa4ed95a3c..c8fe0edb9761 100644 --- a/arch/arm/mach-msm/board-qsd8x50.c +++ b/arch/arm/mach-msm/board-qsd8x50.c @@ -190,11 +190,17 @@ static void __init qsd8x50_init(void) qsd8x50_init_mmc(); } +static void __init qsd8x50_init_late(void) +{ + smd_debugfs_init(); +} + MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF") .atag_offset = 0x100, .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, + .init_late = qsd8x50_init_late, .timer = &msm_timer, MACHINE_END @@ -203,5 +209,6 @@ MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5") .map_io = qsd8x50_map_io, .init_irq = qsd8x50_init_irq, .init_machine = qsd8x50_init, + .init_late = qsd8x50_init_late, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c index 4a8ea0d40b6f..2e569ab10eef 100644 --- a/arch/arm/mach-msm/board-sapphire.c +++ b/arch/arm/mach-msm/board-sapphire.c @@ -101,6 +101,11 @@ static void __init sapphire_map_io(void) msm_clock_init(); } +static void __init sapphire_init_late(void) +{ + smd_debugfs_init(); +} + MACHINE_START(SAPPHIRE, "sapphire") /* Maintainer: Brian Swetland <swetland@google.com> */ .atag_offset = 0x100, @@ -108,5 +113,6 @@ MACHINE_START(SAPPHIRE, "sapphire") .map_io = sapphire_map_io, .init_irq = sapphire_init_irq, .init_machine = sapphire_init, + .init_late = sapphire_init_late, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index d4060a37e23d..bbe13f12fa01 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -98,6 +98,11 @@ static void __init trout_map_io(void) msm_clock_init(msm_clocks_7x01a, msm_num_clocks_7x01a); } +static void __init trout_init_late(void) +{ + smd_debugfs_init(); +} + MACHINE_START(TROUT, "HTC Dream") .atag_offset = 0x100, .fixup = trout_fixup, @@ -105,5 +110,6 @@ MACHINE_START(TROUT, "HTC Dream") .init_early = trout_init_early, .init_irq = trout_init_irq, .init_machine = trout_init, + .init_late = trout_init_late, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h index 2ce8f1f2fc4d..435f8edfafd1 100644 --- a/arch/arm/mach-msm/include/mach/board.h +++ b/arch/arm/mach-msm/include/mach/board.h @@ -47,4 +47,10 @@ int __init msm_add_sdcc(unsigned int controller, struct msm_mmc_platform_data *plat, unsigned int stat_irq, unsigned long stat_irq_flags); +#if defined(CONFIG_MSM_SMD) && defined(CONFIG_DEBUG_FS) +int smd_debugfs_init(void); +#else +static inline int smd_debugfs_init(void) { return 0; } +#endif + #endif diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c index c56df9e932ae..8056b3e5590f 100644 --- a/arch/arm/mach-msm/smd_debug.c +++ b/arch/arm/mach-msm/smd_debug.c @@ -216,7 +216,7 @@ static void debug_create(const char *name, umode_t mode, debugfs_create_file(name, mode, dent, fill, &debug_ops); } -static int smd_debugfs_init(void) +int __init smd_debugfs_init(void) { struct dentry *dent; @@ -234,7 +234,6 @@ static int smd_debugfs_init(void) return 0; } -late_initcall(smd_debugfs_init); #endif diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index a5dcf766a3f9..b4c53b846c9c 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -13,6 +13,7 @@ #include <linux/platform_device.h> #include <linux/serial_8250.h> #include <linux/ata_platform.h> +#include <linux/clk-provider.h> #include <linux/ethtool.h> #include <asm/mach/map.h> #include <asm/mach/time.h> @@ -103,24 +104,24 @@ static void get_pclk_l2clk(int hclk, int core_index, int *pclk, int *l2clk) static int get_tclk(void) { - int tclk; + int tclk_freq; /* * TCLK tick rate is configured by DEV_A[2:0] strap pins. */ switch ((readl(SAMPLE_AT_RESET_HIGH) >> 6) & 7) { case 1: - tclk = 166666667; + tclk_freq = 166666667; break; case 3: - tclk = 200000000; + tclk_freq = 200000000; break; default: panic("unknown TCLK PLL setting: %.8x\n", readl(SAMPLE_AT_RESET_HIGH)); } - return tclk; + return tclk_freq; } @@ -166,6 +167,19 @@ void __init mv78xx0_map_io(void) /***************************************************************************** + * CLK tree + ****************************************************************************/ +static struct clk *tclk; + +static void __init clk_init(void) +{ + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, + get_tclk()); + + orion_clkdev_init(tclk); +} + +/***************************************************************************** * EHCI ****************************************************************************/ void __init mv78xx0_ehci0_init(void) @@ -199,7 +213,7 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM, - IRQ_MV78XX0_GE_ERR, get_tclk()); + IRQ_MV78XX0_GE_ERR); } @@ -210,7 +224,7 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } @@ -234,7 +248,7 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data) orion_ge10_init(eth_data, GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } @@ -258,7 +272,7 @@ void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data) orion_ge11_init(eth_data, GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM, - NO_IRQ, get_tclk()); + NO_IRQ); } /***************************************************************************** @@ -285,7 +299,7 @@ void __init mv78xx0_sata_init(struct mv_sata_platform_data *sata_data) void __init mv78xx0_uart0_init(void) { orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE, - IRQ_MV78XX0_UART_0, get_tclk()); + IRQ_MV78XX0_UART_0, tclk); } @@ -295,7 +309,7 @@ void __init mv78xx0_uart0_init(void) void __init mv78xx0_uart1_init(void) { orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE, - IRQ_MV78XX0_UART_1, get_tclk()); + IRQ_MV78XX0_UART_1, tclk); } @@ -305,7 +319,7 @@ void __init mv78xx0_uart1_init(void) void __init mv78xx0_uart2_init(void) { orion_uart2_init(UART2_VIRT_BASE, UART2_PHYS_BASE, - IRQ_MV78XX0_UART_2, get_tclk()); + IRQ_MV78XX0_UART_2, tclk); } /***************************************************************************** @@ -314,7 +328,7 @@ void __init mv78xx0_uart2_init(void) void __init mv78xx0_uart3_init(void) { orion_uart3_init(UART3_VIRT_BASE, UART3_PHYS_BASE, - IRQ_MV78XX0_UART_3, get_tclk()); + IRQ_MV78XX0_UART_3, tclk); } /***************************************************************************** @@ -378,25 +392,26 @@ void __init mv78xx0_init(void) int hclk; int pclk; int l2clk; - int tclk; core_index = mv78xx0_core_index(); hclk = get_hclk(); get_pclk_l2clk(hclk, core_index, &pclk, &l2clk); - tclk = get_tclk(); printk(KERN_INFO "%s ", mv78xx0_id()); printk("core #%d, ", core_index); printk("PCLK = %dMHz, ", (pclk + 499999) / 1000000); printk("L2 = %dMHz, ", (l2clk + 499999) / 1000000); printk("HCLK = %dMHz, ", (hclk + 499999) / 1000000); - printk("TCLK = %dMHz\n", (tclk + 499999) / 1000000); + printk("TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000); mv78xx0_setup_cpu_mbus(); #ifdef CONFIG_CACHE_FEROCEON_L2 feroceon_l2_init(is_l2_writethrough()); #endif + + /* Setup root of clk tree */ + clk_init(); } void mv78xx0_restart(char mode, const char *cmd) diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig index 07d5383d68ee..91cf0625819c 100644 --- a/arch/arm/mach-mxs/Kconfig +++ b/arch/arm/mach-mxs/Kconfig @@ -7,18 +7,28 @@ config MXS_OCOTP config SOC_IMX23 bool + select ARM_AMBA select CPU_ARM926T select HAVE_PWM select PINCTRL_IMX23 config SOC_IMX28 bool + select ARM_AMBA select CPU_ARM926T select HAVE_PWM select PINCTRL_IMX28 comment "MXS platforms:" +config MACH_MXS_DT + bool "Support MXS platforms from device tree" + select SOC_IMX23 + select SOC_IMX28 + help + Include support for Freescale MXS platforms(i.MX23 and i.MX28) + using the device tree for discovery + config MACH_STMP378X_DEVB bool "Support STMP378x_devb Platform" select SOC_IMX23 diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile index 908bf9a567f1..e41590ccb437 100644 --- a/arch/arm/mach-mxs/Makefile +++ b/arch/arm/mach-mxs/Makefile @@ -1,12 +1,10 @@ # Common support -obj-y := clock.o devices.o icoll.o iomux.o system.o timer.o mm.o +obj-y := devices.o icoll.o iomux.o system.o timer.o mm.o obj-$(CONFIG_MXS_OCOTP) += ocotp.o obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_SOC_IMX23) += clock-mx23.o -obj-$(CONFIG_SOC_IMX28) += clock-mx28.o - +obj-$(CONFIG_MACH_MXS_DT) += mach-mxs.o obj-$(CONFIG_MACH_STMP378X_DEVB) += mach-stmp378x_devb.o obj-$(CONFIG_MACH_MX23EVK) += mach-mx23evk.o obj-$(CONFIG_MACH_MX28EVK) += mach-mx28evk.o diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c deleted file mode 100644 index e3ac52c34019..000000000000 --- a/arch/arm/mach-mxs/clock-mx23.c +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/clkdev.h> - -#include <asm/clkdev.h> -#include <asm/div64.h> - -#include <mach/mx23.h> -#include <mach/common.h> -#include <mach/clock.h> - -#include "regs-clkctrl-mx23.h" - -#define CLKCTRL_BASE_ADDR MX23_IO_ADDRESS(MX23_CLKCTRL_BASE_ADDR) -#define DIGCTRL_BASE_ADDR MX23_IO_ADDRESS(MX23_DIGCTL_BASE_ADDR) - -#define PARENT_RATE_SHIFT 8 - -static int _raw_clk_enable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); - } - - return 0; -} - -static void _raw_clk_disable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - } -} - -/* - * ref_xtal_clk - */ -static unsigned long ref_xtal_clk_get_rate(struct clk *clk) -{ - return 24000000; -} - -static struct clk ref_xtal_clk = { - .get_rate = ref_xtal_clk_get_rate, -}; - -/* - * pll_clk - */ -static unsigned long pll_clk_get_rate(struct clk *clk) -{ - return 480000000; -} - -static int pll_clk_enable(struct clk *clk) -{ - __raw_writel(BM_CLKCTRL_PLLCTRL0_POWER | - BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_SET); - - /* Only a 10us delay is need. PLLCTRL1 LOCK bitfied is only a timer - * and is incorrect (excessive). Per definition of the PLLCTRL0 - * POWER field, waiting at least 10us. - */ - udelay(10); - - return 0; -} - -static void pll_clk_disable(struct clk *clk) -{ - __raw_writel(BM_CLKCTRL_PLLCTRL0_POWER | - BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_PLLCTRL0_CLR); -} - -static struct clk pll_clk = { - .get_rate = pll_clk_get_rate, - .enable = pll_clk_enable, - .disable = pll_clk_disable, - .parent = &ref_xtal_clk, -}; - -/* - * ref_clk - */ -#define _CLK_GET_RATE_REF(name, sr, ss) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - unsigned long parent_rate; \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##sr); \ - div = (reg >> BP_CLKCTRL_##sr##_##ss##FRAC) & 0x3f; \ - parent_rate = clk_get_rate(clk->parent); \ - \ - return SH_DIV((parent_rate >> PARENT_RATE_SHIFT) * 18, \ - div, PARENT_RATE_SHIFT); \ -} - -_CLK_GET_RATE_REF(ref_cpu_clk, FRAC, CPU) -_CLK_GET_RATE_REF(ref_emi_clk, FRAC, EMI) -_CLK_GET_RATE_REF(ref_pix_clk, FRAC, PIX) -_CLK_GET_RATE_REF(ref_io_clk, FRAC, IO) - -#define _DEFINE_CLOCK_REF(name, er, es) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_CLKGATE##es, \ - .get_rate = name##_get_rate, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = &pll_clk, \ - } - -_DEFINE_CLOCK_REF(ref_cpu_clk, FRAC, CPU); -_DEFINE_CLOCK_REF(ref_emi_clk, FRAC, EMI); -_DEFINE_CLOCK_REF(ref_pix_clk, FRAC, PIX); -_DEFINE_CLOCK_REF(ref_io_clk, FRAC, IO); - -/* - * General clocks - * - * clk_get_rate - */ -static unsigned long rtc_clk_get_rate(struct clk *clk) -{ - /* ref_xtal_clk is implemented as the only parent */ - return clk_get_rate(clk->parent) / 768; -} - -static unsigned long clk32k_clk_get_rate(struct clk *clk) -{ - return clk->parent->get_rate(clk->parent) / 750; -} - -#define _CLK_GET_RATE(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - \ - if (clk->parent == &ref_xtal_clk) \ - div = (reg & BM_CLKCTRL_##rs##_DIV_XTAL) >> \ - BP_CLKCTRL_##rs##_DIV_XTAL; \ - else \ - div = (reg & BM_CLKCTRL_##rs##_DIV_##rs) >> \ - BP_CLKCTRL_##rs##_DIV_##rs; \ - \ - if (!div) \ - return -EINVAL; \ - \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE(cpu_clk, CPU) -_CLK_GET_RATE(emi_clk, EMI) - -#define _CLK_GET_RATE1(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - div = (reg & BM_CLKCTRL_##rs##_DIV) >> BP_CLKCTRL_##rs##_DIV; \ - \ - if (!div) \ - return -EINVAL; \ - \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE1(hbus_clk, HBUS) -_CLK_GET_RATE1(xbus_clk, XBUS) -_CLK_GET_RATE1(ssp_clk, SSP) -_CLK_GET_RATE1(gpmi_clk, GPMI) -_CLK_GET_RATE1(lcdif_clk, PIX) - -#define _CLK_GET_RATE_STUB(name) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - return clk_get_rate(clk->parent); \ -} - -_CLK_GET_RATE_STUB(uart_clk) -_CLK_GET_RATE_STUB(audio_clk) -_CLK_GET_RATE_STUB(pwm_clk) - -/* - * clk_set_rate - */ -static int cpu_clk_set_rate(struct clk *clk, unsigned long rate) -{ - u32 reg, bm_busy, div_max, d, f, div, frac; - unsigned long diff, parent_rate, calc_rate; - - parent_rate = clk_get_rate(clk->parent); - - if (clk->parent == &ref_xtal_clk) { - div_max = BM_CLKCTRL_CPU_DIV_XTAL >> BP_CLKCTRL_CPU_DIV_XTAL; - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_XTAL; - div = DIV_ROUND_UP(parent_rate, rate); - if (div == 0 || div > div_max) - return -EINVAL; - } else { - div_max = BM_CLKCTRL_CPU_DIV_CPU >> BP_CLKCTRL_CPU_DIV_CPU; - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_CPU; - rate >>= PARENT_RATE_SHIFT; - parent_rate >>= PARENT_RATE_SHIFT; - diff = parent_rate; - div = frac = 1; - for (d = 1; d <= div_max; d++) { - f = parent_rate * 18 / d / rate; - if ((parent_rate * 18 / d) % rate) - f++; - if (f < 18 || f > 35) - continue; - - calc_rate = parent_rate * 18 / f / d; - if (calc_rate > rate) - continue; - - if (rate - calc_rate < diff) { - frac = f; - div = d; - diff = rate - calc_rate; - } - - if (diff == 0) - break; - } - - if (diff == parent_rate) - return -EINVAL; - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - reg &= ~BM_CLKCTRL_FRAC_CPUFRAC; - reg |= frac; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - } - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - reg &= ~BM_CLKCTRL_CPU_DIV_CPU; - reg |= div << BP_CLKCTRL_CPU_DIV_CPU; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); - - mxs_clkctrl_timeout(HW_CLKCTRL_CPU, bm_busy); - - return 0; -} - -#define _CLK_SET_RATE(name, dr) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, div_max, div; \ - unsigned long parent_rate; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ - \ - div = DIV_ROUND_UP(parent_rate, rate); \ - if (div == 0 || div > div_max) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - reg &= ~BM_CLKCTRL_##dr##_DIV; \ - reg |= div << BP_CLKCTRL_##dr##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - \ - mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY); \ - return 0; \ -} - -_CLK_SET_RATE(xbus_clk, XBUS) -_CLK_SET_RATE(ssp_clk, SSP) -_CLK_SET_RATE(gpmi_clk, GPMI) -_CLK_SET_RATE(lcdif_clk, PIX) - -#define _CLK_SET_RATE_STUB(name) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - return -EINVAL; \ -} - -_CLK_SET_RATE_STUB(emi_clk) -_CLK_SET_RATE_STUB(uart_clk) -_CLK_SET_RATE_STUB(audio_clk) -_CLK_SET_RATE_STUB(pwm_clk) -_CLK_SET_RATE_STUB(clk32k_clk) - -/* - * clk_set_parent - */ -#define _CLK_SET_PARENT(name, bit) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) { \ - __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG); \ - clk->parent = parent; \ - } \ - \ - return 0; \ -} - -_CLK_SET_PARENT(cpu_clk, CPU) -_CLK_SET_PARENT(emi_clk, EMI) -_CLK_SET_PARENT(ssp_clk, SSP) -_CLK_SET_PARENT(gpmi_clk, GPMI) -_CLK_SET_PARENT(lcdif_clk, PIX) - -#define _CLK_SET_PARENT_STUB(name) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) \ - return -EINVAL; \ - else \ - return 0; \ -} - -_CLK_SET_PARENT_STUB(uart_clk) -_CLK_SET_PARENT_STUB(audio_clk) -_CLK_SET_PARENT_STUB(pwm_clk) -_CLK_SET_PARENT_STUB(clk32k_clk) - -/* - * clk definition - */ -static struct clk cpu_clk = { - .get_rate = cpu_clk_get_rate, - .set_rate = cpu_clk_set_rate, - .set_parent = cpu_clk_set_parent, - .parent = &ref_cpu_clk, -}; - -static struct clk hbus_clk = { - .get_rate = hbus_clk_get_rate, - .parent = &cpu_clk, -}; - -static struct clk xbus_clk = { - .get_rate = xbus_clk_get_rate, - .set_rate = xbus_clk_set_rate, - .parent = &ref_xtal_clk, -}; - -static struct clk rtc_clk = { - .get_rate = rtc_clk_get_rate, - .parent = &ref_xtal_clk, -}; - -/* usb_clk gate is controlled in DIGCTRL other than CLKCTRL */ -static struct clk usb_clk = { - .enable_reg = DIGCTRL_BASE_ADDR, - .enable_shift = 2, - .enable = _raw_clk_enable, - .disable = _raw_clk_disable, - .parent = &pll_clk, -}; - -#define _DEFINE_CLOCK(name, er, es, p) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_##es, \ - .get_rate = name##_get_rate, \ - .set_rate = name##_set_rate, \ - .set_parent = name##_set_parent, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = p, \ - } - -_DEFINE_CLOCK(emi_clk, EMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp_clk, SSP, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(gpmi_clk, GPMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(lcdif_clk, PIX, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(uart_clk, XTAL, UART_CLK_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(audio_clk, XTAL, FILT_CLK24M_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(pwm_clk, XTAL, PWM_CLK24M_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(clk32k_clk, XTAL, TIMROT_CLK32K_GATE, &ref_xtal_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* for amba bus driver */ - _REGISTER_CLOCK("duart", "apb_pclk", xbus_clk) - /* for amba-pl011 driver */ - _REGISTER_CLOCK("duart", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk) - _REGISTER_CLOCK("rtc", NULL, rtc_clk) - _REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk) - _REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk) - _REGISTER_CLOCK("mxs-mmc.0", NULL, ssp_clk) - _REGISTER_CLOCK("mxs-mmc.1", NULL, ssp_clk) - _REGISTER_CLOCK(NULL, "usb", usb_clk) - _REGISTER_CLOCK(NULL, "audio", audio_clk) - _REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.1", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.2", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk) - _REGISTER_CLOCK("imx23-fb", NULL, lcdif_clk) - _REGISTER_CLOCK("imx23-gpmi-nand", NULL, gpmi_clk) -}; - -static int clk_misc_init(void) -{ - u32 reg; - int ret; - - /* Fix up parent per register setting */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); - cpu_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) ? - &ref_xtal_clk : &ref_cpu_clk; - emi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) ? - &ref_xtal_clk : &ref_emi_clk; - ssp_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP) ? - &ref_xtal_clk : &ref_io_clk; - gpmi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) ? - &ref_xtal_clk : &ref_io_clk; - lcdif_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_PIX) ? - &ref_xtal_clk : &ref_pix_clk; - - /* Use int div over frac when both are available */ - __raw_writel(BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_HBUS_DIV_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - reg &= ~BM_CLKCTRL_XBUS_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP); - reg &= ~BM_CLKCTRL_SSP_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - reg &= ~BM_CLKCTRL_GPMI_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_PIX); - reg &= ~BM_CLKCTRL_PIX_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_PIX); - - /* - * Set safe hbus clock divider. A divider of 3 ensure that - * the Vddd voltage required for the cpu clock is sufficiently - * high for the hbus clock. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - reg &= BM_CLKCTRL_HBUS_DIV; - reg |= 3 << BP_CLKCTRL_HBUS_DIV; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - - ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_BUSY); - - /* Gate off cpu clock in WFI for power saving */ - __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_SET); - - /* - * 480 MHz seems too high to be ssp clock source directly, - * so set frac to get a 288 MHz ref_io. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - reg &= ~BM_CLKCTRL_FRAC_IOFRAC; - reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC); - - return ret; -} - -int __init mx23_clocks_init(void) -{ - clk_misc_init(); - - /* - * source ssp clock from ref_io than ref_xtal, - * as ref_xtal only provides 24 MHz as maximum. - */ - clk_set_parent(&ssp_clk, &ref_io_clk); - - clk_prepare_enable(&cpu_clk); - clk_prepare_enable(&hbus_clk); - clk_prepare_enable(&xbus_clk); - clk_prepare_enable(&emi_clk); - clk_prepare_enable(&uart_clk); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - mxs_timer_init(&clk32k_clk, MX23_INT_TIMER0); - - return 0; -} diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c deleted file mode 100644 index cea29c99e214..000000000000 --- a/arch/arm/mach-mxs/clock-mx28.c +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/mm.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/clkdev.h> -#include <linux/spinlock.h> - -#include <asm/clkdev.h> -#include <asm/div64.h> - -#include <mach/mx28.h> -#include <mach/common.h> -#include <mach/clock.h> -#include <mach/digctl.h> - -#include "regs-clkctrl-mx28.h" - -#define CLKCTRL_BASE_ADDR MX28_IO_ADDRESS(MX28_CLKCTRL_BASE_ADDR) -#define DIGCTRL_BASE_ADDR MX28_IO_ADDRESS(MX28_DIGCTL_BASE_ADDR) - -#define PARENT_RATE_SHIFT 8 - -static struct clk pll2_clk; -static struct clk cpu_clk; -static struct clk emi_clk; -static struct clk saif0_clk; -static struct clk saif1_clk; -static struct clk clk32k_clk; -static DEFINE_SPINLOCK(clkmux_lock); - -/* - * HW_SAIF_CLKMUX_SEL: - * DIRECT(0x0): SAIF0 clock pins selected for SAIF0 input clocks, and SAIF1 - * clock pins selected for SAIF1 input clocks. - * CROSSINPUT(0x1): SAIF1 clock inputs selected for SAIF0 input clocks, and - * SAIF0 clock inputs selected for SAIF1 input clocks. - * EXTMSTR0(0x2): SAIF0 clock pin selected for both SAIF0 and SAIF1 input - * clocks. - * EXTMSTR1(0x3): SAIF1 clock pin selected for both SAIF0 and SAIF1 input - * clocks. - */ -int mxs_saif_clkmux_select(unsigned int clkmux) -{ - if (clkmux > 0x3) - return -EINVAL; - - spin_lock(&clkmux_lock); - __raw_writel(BM_DIGCTL_CTRL_SAIF_CLKMUX, - DIGCTRL_BASE_ADDR + HW_DIGCTL_CTRL + MXS_CLR_ADDR); - __raw_writel(clkmux << BP_DIGCTL_CTRL_SAIF_CLKMUX, - DIGCTRL_BASE_ADDR + HW_DIGCTL_CTRL + MXS_SET_ADDR); - spin_unlock(&clkmux_lock); - - return 0; -} - -static int _raw_clk_enable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg &= ~(1 << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); - } - - return 0; -} - -static void _raw_clk_disable(struct clk *clk) -{ - u32 reg; - - if (clk->enable_reg) { - reg = __raw_readl(clk->enable_reg); - reg |= 1 << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - } -} - -/* - * ref_xtal_clk - */ -static unsigned long ref_xtal_clk_get_rate(struct clk *clk) -{ - return 24000000; -} - -static struct clk ref_xtal_clk = { - .get_rate = ref_xtal_clk_get_rate, -}; - -/* - * pll_clk - */ -static unsigned long pll0_clk_get_rate(struct clk *clk) -{ - return 480000000; -} - -static unsigned long pll1_clk_get_rate(struct clk *clk) -{ - return 480000000; -} - -static unsigned long pll2_clk_get_rate(struct clk *clk) -{ - return 50000000; -} - -#define _CLK_ENABLE_PLL(name, r, g) \ -static int name##_enable(struct clk *clk) \ -{ \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_POWER, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_SET); \ - udelay(10); \ - \ - if (clk == &pll2_clk) \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_CLR); \ - else \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_SET); \ - \ - return 0; \ -} - -_CLK_ENABLE_PLL(pll0_clk, PLL0, EN_USB_CLKS) -_CLK_ENABLE_PLL(pll1_clk, PLL1, EN_USB_CLKS) -_CLK_ENABLE_PLL(pll2_clk, PLL2, CLKGATE) - -#define _CLK_DISABLE_PLL(name, r, g) \ -static void name##_disable(struct clk *clk) \ -{ \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_POWER, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_CLR); \ - \ - if (clk == &pll2_clk) \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_SET); \ - else \ - __raw_writel(BM_CLKCTRL_##r##CTRL0_##g, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_##r##CTRL0_CLR); \ - \ -} - -_CLK_DISABLE_PLL(pll0_clk, PLL0, EN_USB_CLKS) -_CLK_DISABLE_PLL(pll1_clk, PLL1, EN_USB_CLKS) -_CLK_DISABLE_PLL(pll2_clk, PLL2, CLKGATE) - -#define _DEFINE_CLOCK_PLL(name) \ - static struct clk name = { \ - .get_rate = name##_get_rate, \ - .enable = name##_enable, \ - .disable = name##_disable, \ - .parent = &ref_xtal_clk, \ - } - -_DEFINE_CLOCK_PLL(pll0_clk); -_DEFINE_CLOCK_PLL(pll1_clk); -_DEFINE_CLOCK_PLL(pll2_clk); - -/* - * ref_clk - */ -#define _CLK_GET_RATE_REF(name, sr, ss) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - unsigned long parent_rate; \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##sr); \ - div = (reg >> BP_CLKCTRL_##sr##_##ss##FRAC) & 0x3f; \ - parent_rate = clk_get_rate(clk->parent); \ - \ - return SH_DIV((parent_rate >> PARENT_RATE_SHIFT) * 18, \ - div, PARENT_RATE_SHIFT); \ -} - -_CLK_GET_RATE_REF(ref_cpu_clk, FRAC0, CPU) -_CLK_GET_RATE_REF(ref_emi_clk, FRAC0, EMI) -_CLK_GET_RATE_REF(ref_io0_clk, FRAC0, IO0) -_CLK_GET_RATE_REF(ref_io1_clk, FRAC0, IO1) -_CLK_GET_RATE_REF(ref_pix_clk, FRAC1, PIX) -_CLK_GET_RATE_REF(ref_gpmi_clk, FRAC1, GPMI) - -#define _DEFINE_CLOCK_REF(name, er, es) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_CLKGATE##es, \ - .get_rate = name##_get_rate, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = &pll0_clk, \ - } - -_DEFINE_CLOCK_REF(ref_cpu_clk, FRAC0, CPU); -_DEFINE_CLOCK_REF(ref_emi_clk, FRAC0, EMI); -_DEFINE_CLOCK_REF(ref_io0_clk, FRAC0, IO0); -_DEFINE_CLOCK_REF(ref_io1_clk, FRAC0, IO1); -_DEFINE_CLOCK_REF(ref_pix_clk, FRAC1, PIX); -_DEFINE_CLOCK_REF(ref_gpmi_clk, FRAC1, GPMI); - -/* - * General clocks - * - * clk_get_rate - */ -static unsigned long lradc_clk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 16; -} - -static unsigned long rtc_clk_get_rate(struct clk *clk) -{ - /* ref_xtal_clk is implemented as the only parent */ - return clk_get_rate(clk->parent) / 768; -} - -static unsigned long clk32k_clk_get_rate(struct clk *clk) -{ - return clk->parent->get_rate(clk->parent) / 750; -} - -static unsigned long spdif_clk_get_rate(struct clk *clk) -{ - return clk_get_rate(clk->parent) / 4; -} - -#define _CLK_GET_RATE(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - \ - if (clk->parent == &ref_xtal_clk) \ - div = (reg & BM_CLKCTRL_##rs##_DIV_XTAL) >> \ - BP_CLKCTRL_##rs##_DIV_XTAL; \ - else \ - div = (reg & BM_CLKCTRL_##rs##_DIV_##rs) >> \ - BP_CLKCTRL_##rs##_DIV_##rs; \ - \ - if (!div) \ - return -EINVAL; \ - \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE(cpu_clk, CPU) -_CLK_GET_RATE(emi_clk, EMI) - -#define _CLK_GET_RATE1(name, rs) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - u32 reg, div; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - div = (reg & BM_CLKCTRL_##rs##_DIV) >> BP_CLKCTRL_##rs##_DIV; \ - \ - if (!div) \ - return -EINVAL; \ - \ - if (clk == &saif0_clk || clk == &saif1_clk) \ - return clk_get_rate(clk->parent) >> 16 * div; \ - else \ - return clk_get_rate(clk->parent) / div; \ -} - -_CLK_GET_RATE1(hbus_clk, HBUS) -_CLK_GET_RATE1(xbus_clk, XBUS) -_CLK_GET_RATE1(ssp0_clk, SSP0) -_CLK_GET_RATE1(ssp1_clk, SSP1) -_CLK_GET_RATE1(ssp2_clk, SSP2) -_CLK_GET_RATE1(ssp3_clk, SSP3) -_CLK_GET_RATE1(gpmi_clk, GPMI) -_CLK_GET_RATE1(lcdif_clk, DIS_LCDIF) -_CLK_GET_RATE1(saif0_clk, SAIF0) -_CLK_GET_RATE1(saif1_clk, SAIF1) - -#define _CLK_GET_RATE_STUB(name) \ -static unsigned long name##_get_rate(struct clk *clk) \ -{ \ - return clk_get_rate(clk->parent); \ -} - -_CLK_GET_RATE_STUB(uart_clk) -_CLK_GET_RATE_STUB(pwm_clk) -_CLK_GET_RATE_STUB(can0_clk) -_CLK_GET_RATE_STUB(can1_clk) -_CLK_GET_RATE_STUB(fec_clk) - -/* - * clk_set_rate - */ -/* fool compiler */ -#define BM_CLKCTRL_CPU_DIV 0 -#define BP_CLKCTRL_CPU_DIV 0 -#define BM_CLKCTRL_CPU_BUSY 0 - -#define _CLK_SET_RATE(name, dr, fr, fs) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, bm_busy, div_max, d, f, div, frac; \ - unsigned long diff, parent_rate, calc_rate; \ - \ - div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ - bm_busy = BM_CLKCTRL_##dr##_BUSY; \ - \ - if (clk->parent == &ref_xtal_clk) { \ - parent_rate = clk_get_rate(clk->parent); \ - div = DIV_ROUND_UP(parent_rate, rate); \ - if (clk == &cpu_clk) { \ - div_max = BM_CLKCTRL_CPU_DIV_XTAL >> \ - BP_CLKCTRL_CPU_DIV_XTAL; \ - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_XTAL; \ - } \ - if (div == 0 || div > div_max) \ - return -EINVAL; \ - } else { \ - /* \ - * hack alert: this block modifies clk->parent, too, \ - * so the base to use it the grand parent. \ - */ \ - parent_rate = clk_get_rate(clk->parent->parent); \ - rate >>= PARENT_RATE_SHIFT; \ - parent_rate >>= PARENT_RATE_SHIFT; \ - diff = parent_rate; \ - div = frac = 1; \ - if (clk == &cpu_clk) { \ - div_max = BM_CLKCTRL_CPU_DIV_CPU >> \ - BP_CLKCTRL_CPU_DIV_CPU; \ - bm_busy = BM_CLKCTRL_CPU_BUSY_REF_CPU; \ - } \ - for (d = 1; d <= div_max; d++) { \ - f = parent_rate * 18 / d / rate; \ - if ((parent_rate * 18 / d) % rate) \ - f++; \ - if (f < 18 || f > 35) \ - continue; \ - \ - calc_rate = parent_rate * 18 / f / d; \ - if (calc_rate > rate) \ - continue; \ - \ - if (rate - calc_rate < diff) { \ - frac = f; \ - div = d; \ - diff = rate - calc_rate; \ - } \ - \ - if (diff == 0) \ - break; \ - } \ - \ - if (diff == parent_rate) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##fr); \ - reg &= ~BM_CLKCTRL_##fr##_##fs##FRAC; \ - reg |= frac << BP_CLKCTRL_##fr##_##fs##FRAC; \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##fr); \ - } \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - if (clk == &cpu_clk) { \ - reg &= ~BM_CLKCTRL_CPU_DIV_CPU; \ - reg |= div << BP_CLKCTRL_CPU_DIV_CPU; \ - } else { \ - reg &= ~BM_CLKCTRL_##dr##_DIV; \ - reg |= div << BP_CLKCTRL_##dr##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - \ - return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, bm_busy); \ -} - -_CLK_SET_RATE(cpu_clk, CPU, FRAC0, CPU) -_CLK_SET_RATE(ssp0_clk, SSP0, FRAC0, IO0) -_CLK_SET_RATE(ssp1_clk, SSP1, FRAC0, IO0) -_CLK_SET_RATE(ssp2_clk, SSP2, FRAC0, IO1) -_CLK_SET_RATE(ssp3_clk, SSP3, FRAC0, IO1) -_CLK_SET_RATE(lcdif_clk, DIS_LCDIF, FRAC1, PIX) -_CLK_SET_RATE(gpmi_clk, GPMI, FRAC1, GPMI) - -#define _CLK_SET_RATE1(name, dr) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u32 reg, div_max, div; \ - unsigned long parent_rate; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \ - \ - div = DIV_ROUND_UP(parent_rate, rate); \ - if (div == 0 || div > div_max) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - reg &= ~BM_CLKCTRL_##dr##_DIV; \ - reg |= div << BP_CLKCTRL_##dr##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ - \ - return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);\ -} - -_CLK_SET_RATE1(xbus_clk, XBUS) - -/* saif clock uses 16 bits frac div */ -#define _CLK_SET_RATE_SAIF(name, rs) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - u16 div; \ - u32 reg; \ - u64 lrate; \ - unsigned long parent_rate; \ - \ - parent_rate = clk_get_rate(clk->parent); \ - if (rate > parent_rate) \ - return -EINVAL; \ - \ - lrate = (u64)rate << 16; \ - do_div(lrate, parent_rate); \ - div = (u16)lrate; \ - \ - if (!div) \ - return -EINVAL; \ - \ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - reg &= ~BM_CLKCTRL_##rs##_DIV; \ - reg |= div << BP_CLKCTRL_##rs##_DIV; \ - if (reg & (1 << clk->enable_shift)) { \ - pr_err("%s: clock is gated\n", __func__); \ - return -EINVAL; \ - } \ - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \ - \ - return mxs_clkctrl_timeout(HW_CLKCTRL_##rs, BM_CLKCTRL_##rs##_BUSY);\ -} - -_CLK_SET_RATE_SAIF(saif0_clk, SAIF0) -_CLK_SET_RATE_SAIF(saif1_clk, SAIF1) - -#define _CLK_SET_RATE_STUB(name) \ -static int name##_set_rate(struct clk *clk, unsigned long rate) \ -{ \ - return -EINVAL; \ -} - -_CLK_SET_RATE_STUB(emi_clk) -_CLK_SET_RATE_STUB(uart_clk) -_CLK_SET_RATE_STUB(pwm_clk) -_CLK_SET_RATE_STUB(spdif_clk) -_CLK_SET_RATE_STUB(clk32k_clk) -_CLK_SET_RATE_STUB(can0_clk) -_CLK_SET_RATE_STUB(can1_clk) -_CLK_SET_RATE_STUB(fec_clk) - -/* - * clk_set_parent - */ -#define _CLK_SET_PARENT(name, bit) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) { \ - __raw_writel(BM_CLKCTRL_CLKSEQ_BYPASS_##bit, \ - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ_TOG); \ - clk->parent = parent; \ - } \ - \ - return 0; \ -} - -_CLK_SET_PARENT(cpu_clk, CPU) -_CLK_SET_PARENT(emi_clk, EMI) -_CLK_SET_PARENT(ssp0_clk, SSP0) -_CLK_SET_PARENT(ssp1_clk, SSP1) -_CLK_SET_PARENT(ssp2_clk, SSP2) -_CLK_SET_PARENT(ssp3_clk, SSP3) -_CLK_SET_PARENT(lcdif_clk, DIS_LCDIF) -_CLK_SET_PARENT(gpmi_clk, GPMI) -_CLK_SET_PARENT(saif0_clk, SAIF0) -_CLK_SET_PARENT(saif1_clk, SAIF1) - -#define _CLK_SET_PARENT_STUB(name) \ -static int name##_set_parent(struct clk *clk, struct clk *parent) \ -{ \ - if (parent != clk->parent) \ - return -EINVAL; \ - else \ - return 0; \ -} - -_CLK_SET_PARENT_STUB(pwm_clk) -_CLK_SET_PARENT_STUB(uart_clk) -_CLK_SET_PARENT_STUB(clk32k_clk) -_CLK_SET_PARENT_STUB(spdif_clk) -_CLK_SET_PARENT_STUB(fec_clk) -_CLK_SET_PARENT_STUB(can0_clk) -_CLK_SET_PARENT_STUB(can1_clk) - -/* - * clk definition - */ -static struct clk cpu_clk = { - .get_rate = cpu_clk_get_rate, - .set_rate = cpu_clk_set_rate, - .set_parent = cpu_clk_set_parent, - .parent = &ref_cpu_clk, -}; - -static struct clk hbus_clk = { - .get_rate = hbus_clk_get_rate, - .parent = &cpu_clk, -}; - -static struct clk xbus_clk = { - .get_rate = xbus_clk_get_rate, - .set_rate = xbus_clk_set_rate, - .parent = &ref_xtal_clk, -}; - -static struct clk lradc_clk = { - .get_rate = lradc_clk_get_rate, - .parent = &clk32k_clk, -}; - -static struct clk rtc_clk = { - .get_rate = rtc_clk_get_rate, - .parent = &ref_xtal_clk, -}; - -/* usb_clk gate is controlled in DIGCTRL other than CLKCTRL */ -static struct clk usb0_clk = { - .enable_reg = DIGCTRL_BASE_ADDR, - .enable_shift = 2, - .enable = _raw_clk_enable, - .disable = _raw_clk_disable, - .parent = &pll0_clk, -}; - -static struct clk usb1_clk = { - .enable_reg = DIGCTRL_BASE_ADDR, - .enable_shift = 16, - .enable = _raw_clk_enable, - .disable = _raw_clk_disable, - .parent = &pll1_clk, -}; - -#define _DEFINE_CLOCK(name, er, es, p) \ - static struct clk name = { \ - .enable_reg = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er, \ - .enable_shift = BP_CLKCTRL_##er##_##es, \ - .get_rate = name##_get_rate, \ - .set_rate = name##_set_rate, \ - .set_parent = name##_set_parent, \ - .enable = _raw_clk_enable, \ - .disable = _raw_clk_disable, \ - .parent = p, \ - } - -_DEFINE_CLOCK(emi_clk, EMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp0_clk, SSP0, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp1_clk, SSP1, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp2_clk, SSP2, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(ssp3_clk, SSP3, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(lcdif_clk, DIS_LCDIF, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(gpmi_clk, GPMI, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(saif0_clk, SAIF0, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(saif1_clk, SAIF1, CLKGATE, &ref_xtal_clk); -_DEFINE_CLOCK(can0_clk, FLEXCAN, STOP_CAN0, &ref_xtal_clk); -_DEFINE_CLOCK(can1_clk, FLEXCAN, STOP_CAN1, &ref_xtal_clk); -_DEFINE_CLOCK(pwm_clk, XTAL, PWM_CLK24M_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(uart_clk, XTAL, UART_CLK_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(clk32k_clk, XTAL, TIMROT_CLK32K_GATE, &ref_xtal_clk); -_DEFINE_CLOCK(spdif_clk, SPDIF, CLKGATE, &pll0_clk); -_DEFINE_CLOCK(fec_clk, ENET, DISABLE, &hbus_clk); - -#define _REGISTER_CLOCK(d, n, c) \ - { \ - .dev_id = d, \ - .con_id = n, \ - .clk = &c, \ - }, - -static struct clk_lookup lookups[] = { - /* for amba bus driver */ - _REGISTER_CLOCK("duart", "apb_pclk", xbus_clk) - /* for amba-pl011 driver */ - _REGISTER_CLOCK("duart", NULL, uart_clk) - _REGISTER_CLOCK("imx28-fec.0", NULL, fec_clk) - _REGISTER_CLOCK("imx28-fec.1", NULL, fec_clk) - _REGISTER_CLOCK("imx28-gpmi-nand", NULL, gpmi_clk) - _REGISTER_CLOCK("mxs-auart.0", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.1", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.2", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.3", NULL, uart_clk) - _REGISTER_CLOCK("mxs-auart.4", NULL, uart_clk) - _REGISTER_CLOCK("rtc", NULL, rtc_clk) - _REGISTER_CLOCK("pll2", NULL, pll2_clk) - _REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk) - _REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk) - _REGISTER_CLOCK("mxs-mmc.0", NULL, ssp0_clk) - _REGISTER_CLOCK("mxs-mmc.1", NULL, ssp1_clk) - _REGISTER_CLOCK("mxs-mmc.2", NULL, ssp2_clk) - _REGISTER_CLOCK("mxs-mmc.3", NULL, ssp3_clk) - _REGISTER_CLOCK("flexcan.0", NULL, can0_clk) - _REGISTER_CLOCK("flexcan.1", NULL, can1_clk) - _REGISTER_CLOCK(NULL, "usb0", usb0_clk) - _REGISTER_CLOCK(NULL, "usb1", usb1_clk) - _REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.1", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.2", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.3", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.4", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.5", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.6", NULL, pwm_clk) - _REGISTER_CLOCK("mxs-pwm.7", NULL, pwm_clk) - _REGISTER_CLOCK(NULL, "lradc", lradc_clk) - _REGISTER_CLOCK(NULL, "spdif", spdif_clk) - _REGISTER_CLOCK("imx28-fb", NULL, lcdif_clk) - _REGISTER_CLOCK("mxs-saif.0", NULL, saif0_clk) - _REGISTER_CLOCK("mxs-saif.1", NULL, saif1_clk) -}; - -static int clk_misc_init(void) -{ - u32 reg; - int ret; - - /* Fix up parent per register setting */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ); - cpu_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_CPU) ? - &ref_xtal_clk : &ref_cpu_clk; - emi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_EMI) ? - &ref_xtal_clk : &ref_emi_clk; - ssp0_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP0) ? - &ref_xtal_clk : &ref_io0_clk; - ssp1_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP1) ? - &ref_xtal_clk : &ref_io0_clk; - ssp2_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP2) ? - &ref_xtal_clk : &ref_io1_clk; - ssp3_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SSP3) ? - &ref_xtal_clk : &ref_io1_clk; - lcdif_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF) ? - &ref_xtal_clk : &ref_pix_clk; - gpmi_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_GPMI) ? - &ref_xtal_clk : &ref_gpmi_clk; - saif0_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SAIF0) ? - &ref_xtal_clk : &pll0_clk; - saif1_clk.parent = (reg & BM_CLKCTRL_CLKSEQ_BYPASS_SAIF1) ? - &ref_xtal_clk : &pll0_clk; - - /* Use int div over frac when both are available */ - __raw_writel(BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_CLR); - __raw_writel(BM_CLKCTRL_HBUS_DIV_FRAC_EN, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS_CLR); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - reg &= ~BM_CLKCTRL_XBUS_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_XBUS); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP0); - reg &= ~BM_CLKCTRL_SSP0_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP0); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP1); - reg &= ~BM_CLKCTRL_SSP1_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP1); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP2); - reg &= ~BM_CLKCTRL_SSP2_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP2); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP3); - reg &= ~BM_CLKCTRL_SSP3_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SSP3); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - reg &= ~BM_CLKCTRL_GPMI_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_GPMI); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_DIS_LCDIF); - reg &= ~BM_CLKCTRL_DIS_LCDIF_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_DIS_LCDIF); - - /* SAIF has to use frac div for functional operation */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0); - reg |= BM_CLKCTRL_SAIF0_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF0); - - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1); - reg |= BM_CLKCTRL_SAIF1_DIV_FRAC_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_SAIF1); - - /* - * Set safe hbus clock divider. A divider of 3 ensure that - * the Vddd voltage required for the cpu clock is sufficiently - * high for the hbus clock. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - reg &= BM_CLKCTRL_HBUS_DIV; - reg |= 3 << BP_CLKCTRL_HBUS_DIV; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); - - ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_ASM_BUSY); - - /* Gate off cpu clock in WFI for power saving */ - __raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT, - CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU_SET); - - /* - * Extra fec clock setting - * The DENX M28 uses an external clock source - * and the clock output must not be enabled - */ - if (!machine_is_m28evk()) { - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_ENET); - reg &= ~BM_CLKCTRL_ENET_SLEEP; - reg |= BM_CLKCTRL_ENET_CLK_OUT_EN; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_ENET); - } - - /* - * 480 MHz seems too high to be ssp clock source directly, - * so set frac0 to get a 288 MHz ref_io0. - */ - reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); - reg &= ~BM_CLKCTRL_FRAC0_IO0FRAC; - reg |= 30 << BP_CLKCTRL_FRAC0_IO0FRAC; - __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); - - return ret; -} - -int __init mx28_clocks_init(void) -{ - clk_misc_init(); - - /* - * source ssp clock from ref_io0 than ref_xtal, - * as ref_xtal only provides 24 MHz as maximum. - */ - clk_set_parent(&ssp0_clk, &ref_io0_clk); - clk_set_parent(&ssp1_clk, &ref_io0_clk); - clk_set_parent(&ssp2_clk, &ref_io1_clk); - clk_set_parent(&ssp3_clk, &ref_io1_clk); - - clk_prepare_enable(&cpu_clk); - clk_prepare_enable(&hbus_clk); - clk_prepare_enable(&xbus_clk); - clk_prepare_enable(&emi_clk); - clk_prepare_enable(&uart_clk); - - clk_set_parent(&lcdif_clk, &ref_pix_clk); - clk_set_parent(&saif0_clk, &pll0_clk); - clk_set_parent(&saif1_clk, &pll0_clk); - - /* - * Set an initial clock rate for the saif internal logic to work - * properly. This is important when working in EXTMASTER mode that - * uses the other saif's BITCLK&LRCLK but it still needs a basic - * clock which should be fast enough for the internal logic. - */ - clk_set_rate(&saif0_clk, 24000000); - clk_set_rate(&saif1_clk, 24000000); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - mxs_timer_init(&clk32k_clk, MX28_INT_TIMER0); - - return 0; -} diff --git a/arch/arm/mach-mxs/clock.c b/arch/arm/mach-mxs/clock.c deleted file mode 100644 index 97a6f4acc6cc..000000000000 --- a/arch/arm/mach-mxs/clock.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Based on arch/arm/plat-omap/clock.c - * - * Copyright (C) 2004 - 2005 Nokia corporation - * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> - * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> - * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -/* #define DEBUG */ - -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/proc_fs.h> -#include <linux/semaphore.h> -#include <linux/string.h> - -#include <mach/clock.h> - -static LIST_HEAD(clocks); -static DEFINE_MUTEX(clocks_mutex); - -/*------------------------------------------------------------------------- - * Standard clock functions defined in include/linux/clk.h - *-------------------------------------------------------------------------*/ - -static void __clk_disable(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return; - WARN_ON(!clk->usecount); - - if (!(--clk->usecount)) { - if (clk->disable) - clk->disable(clk); - __clk_disable(clk->parent); - } -} - -static int __clk_enable(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return -EINVAL; - - if (clk->usecount++ == 0) { - __clk_enable(clk->parent); - - if (clk->enable) - clk->enable(clk); - } - return 0; -} - -/* - * The clk_enable/clk_disable could be called by drivers in atomic context, - * so they should not really hold mutex. Instead, clk_prepare/clk_unprepare - * can hold a mutex, as the pair will only be called in non-atomic context. - * Before migrating to common clk framework, we can have __clk_enable and - * __clk_disable called in clk_prepare/clk_unprepare with mutex held and - * leave clk_enable/clk_disable as the dummy functions. - */ -int clk_prepare(struct clk *clk) -{ - int ret = 0; - - if (clk == NULL || IS_ERR(clk)) - return -EINVAL; - - mutex_lock(&clocks_mutex); - ret = __clk_enable(clk); - mutex_unlock(&clocks_mutex); - - return ret; -} -EXPORT_SYMBOL(clk_prepare); - -void clk_unprepare(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return; - - mutex_lock(&clocks_mutex); - __clk_disable(clk); - mutex_unlock(&clocks_mutex); -} -EXPORT_SYMBOL(clk_unprepare); - -int clk_enable(struct clk *clk) -{ - return 0; -} -EXPORT_SYMBOL(clk_enable); - -void clk_disable(struct clk *clk) -{ - /* nothing to do */ -} -EXPORT_SYMBOL(clk_disable); - -/* Retrieve the *current* clock rate. If the clock itself - * does not provide a special calculation routine, ask - * its parent and so on, until one is able to return - * a valid clock rate - */ -unsigned long clk_get_rate(struct clk *clk) -{ - if (clk == NULL || IS_ERR(clk)) - return 0UL; - - if (clk->get_rate) - return clk->get_rate(clk); - - return clk_get_rate(clk->parent); -} -EXPORT_SYMBOL(clk_get_rate); - -/* Round the requested clock rate to the nearest supported - * rate that is less than or equal to the requested rate. - * This is dependent on the clock's current parent. - */ -long clk_round_rate(struct clk *clk, unsigned long rate) -{ - if (clk == NULL || IS_ERR(clk) || !clk->round_rate) - return 0; - - return clk->round_rate(clk, rate); -} -EXPORT_SYMBOL(clk_round_rate); - -/* Set the clock to the requested clock rate. The rate must - * match a supported rate exactly based on what clk_round_rate returns - */ -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - int ret = -EINVAL; - - if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0) - return ret; - - mutex_lock(&clocks_mutex); - ret = clk->set_rate(clk, rate); - mutex_unlock(&clocks_mutex); - - return ret; -} -EXPORT_SYMBOL(clk_set_rate); - -/* Set the clock's parent to another clock source */ -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - int ret = -EINVAL; - struct clk *old; - - if (clk == NULL || IS_ERR(clk) || parent == NULL || - IS_ERR(parent) || clk->set_parent == NULL) - return ret; - - if (clk->usecount) - clk_prepare_enable(parent); - - mutex_lock(&clocks_mutex); - ret = clk->set_parent(clk, parent); - if (ret == 0) { - old = clk->parent; - clk->parent = parent; - } else { - old = parent; - } - mutex_unlock(&clocks_mutex); - - if (clk->usecount) - clk_disable(old); - - return ret; -} -EXPORT_SYMBOL(clk_set_parent); - -/* Retrieve the clock's parent clock source */ -struct clk *clk_get_parent(struct clk *clk) -{ - struct clk *ret = NULL; - - if (clk == NULL || IS_ERR(clk)) - return ret; - - return clk->parent; -} -EXPORT_SYMBOL(clk_get_parent); diff --git a/arch/arm/mach-mxs/devices/Kconfig b/arch/arm/mach-mxs/devices/Kconfig index b8913df4cfa2..19659de1c4e8 100644 --- a/arch/arm/mach-mxs/devices/Kconfig +++ b/arch/arm/mach-mxs/devices/Kconfig @@ -1,6 +1,5 @@ config MXS_HAVE_AMBA_DUART bool - select ARM_AMBA config MXS_HAVE_PLATFORM_AUART bool diff --git a/arch/arm/mach-mxs/devices/platform-dma.c b/arch/arm/mach-mxs/devices/platform-dma.c index 6a0202b1016c..46824501de00 100644 --- a/arch/arm/mach-mxs/devices/platform-dma.c +++ b/arch/arm/mach-mxs/devices/platform-dma.c @@ -14,7 +14,7 @@ #include <mach/mx28.h> #include <mach/devices-common.h> -static struct platform_device *__init mxs_add_dma(const char *devid, +struct platform_device *__init mxs_add_dma(const char *devid, resource_size_t base) { struct resource res[] = { @@ -29,22 +29,3 @@ static struct platform_device *__init mxs_add_dma(const char *devid, res, ARRAY_SIZE(res), NULL, 0, DMA_BIT_MASK(32)); } - -static int __init mxs_add_mxs_dma(void) -{ - char *apbh = "mxs-dma-apbh"; - char *apbx = "mxs-dma-apbx"; - - if (cpu_is_mx23()) { - mxs_add_dma(apbh, MX23_APBH_DMA_BASE_ADDR); - mxs_add_dma(apbx, MX23_APBX_DMA_BASE_ADDR); - } - - if (cpu_is_mx28()) { - mxs_add_dma(apbh, MX28_APBH_DMA_BASE_ADDR); - mxs_add_dma(apbx, MX28_APBX_DMA_BASE_ADDR); - } - - return 0; -} -arch_initcall(mxs_add_mxs_dma); diff --git a/arch/arm/mach-mxs/devices/platform-gpio-mxs.c b/arch/arm/mach-mxs/devices/platform-gpio-mxs.c index ed0885e414e0..cd99f19ec637 100644 --- a/arch/arm/mach-mxs/devices/platform-gpio-mxs.c +++ b/arch/arm/mach-mxs/devices/platform-gpio-mxs.c @@ -14,7 +14,7 @@ #include <mach/devices-common.h> struct platform_device *__init mxs_add_gpio( - int id, resource_size_t iobase, int irq) + char *name, int id, resource_size_t iobase, int irq) { struct resource res[] = { { @@ -29,25 +29,5 @@ struct platform_device *__init mxs_add_gpio( }; return platform_device_register_resndata(&mxs_apbh_bus, - "gpio-mxs", id, res, ARRAY_SIZE(res), NULL, 0); + name, id, res, ARRAY_SIZE(res), NULL, 0); } - -static int __init mxs_add_mxs_gpio(void) -{ - if (cpu_is_mx23()) { - mxs_add_gpio(0, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO0); - mxs_add_gpio(1, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO1); - mxs_add_gpio(2, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO2); - } - - if (cpu_is_mx28()) { - mxs_add_gpio(0, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO0); - mxs_add_gpio(1, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO1); - mxs_add_gpio(2, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO2); - mxs_add_gpio(3, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO3); - mxs_add_gpio(4, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO4); - } - - return 0; -} -postcore_initcall(mxs_add_mxs_gpio); diff --git a/arch/arm/mach-mxs/devices/platform-mxs-mmc.c b/arch/arm/mach-mxs/devices/platform-mxs-mmc.c index bef9d923f54e..b33c9d05c552 100644 --- a/arch/arm/mach-mxs/devices/platform-mxs-mmc.c +++ b/arch/arm/mach-mxs/devices/platform-mxs-mmc.c @@ -17,8 +17,9 @@ #include <mach/mx28.h> #include <mach/devices-common.h> -#define mxs_mxs_mmc_data_entry_single(soc, _id, hwid) \ +#define mxs_mxs_mmc_data_entry_single(soc, _devid, _id, hwid) \ { \ + .devid = _devid, \ .id = _id, \ .iobase = soc ## _SSP ## hwid ## _BASE_ADDR, \ .dma = soc ## _DMA_SSP ## hwid, \ @@ -26,23 +27,23 @@ .irq_dma = soc ## _INT_SSP ## hwid ## _DMA, \ } -#define mxs_mxs_mmc_data_entry(soc, _id, hwid) \ - [_id] = mxs_mxs_mmc_data_entry_single(soc, _id, hwid) +#define mxs_mxs_mmc_data_entry(soc, _devid, _id, hwid) \ + [_id] = mxs_mxs_mmc_data_entry_single(soc, _devid, _id, hwid) #ifdef CONFIG_SOC_IMX23 const struct mxs_mxs_mmc_data mx23_mxs_mmc_data[] __initconst = { - mxs_mxs_mmc_data_entry(MX23, 0, 1), - mxs_mxs_mmc_data_entry(MX23, 1, 2), + mxs_mxs_mmc_data_entry(MX23, "imx23-mmc", 0, 1), + mxs_mxs_mmc_data_entry(MX23, "imx23-mmc", 1, 2), }; #endif #ifdef CONFIG_SOC_IMX28 const struct mxs_mxs_mmc_data mx28_mxs_mmc_data[] __initconst = { - mxs_mxs_mmc_data_entry(MX28, 0, 0), - mxs_mxs_mmc_data_entry(MX28, 1, 1), - mxs_mxs_mmc_data_entry(MX28, 2, 2), - mxs_mxs_mmc_data_entry(MX28, 3, 3), + mxs_mxs_mmc_data_entry(MX28, "imx28-mmc", 0, 0), + mxs_mxs_mmc_data_entry(MX28, "imx28-mmc", 1, 1), + mxs_mxs_mmc_data_entry(MX28, "imx28-mmc", 2, 2), + mxs_mxs_mmc_data_entry(MX28, "imx28-mmc", 3, 3), }; #endif @@ -70,6 +71,6 @@ struct platform_device *__init mxs_add_mxs_mmc( }, }; - return mxs_add_platform_device("mxs-mmc", data->id, + return mxs_add_platform_device(data->devid, data->id, res, ARRAY_SIZE(res), pdata, sizeof(*pdata)); } diff --git a/arch/arm/mach-mxs/include/mach/clock.h b/arch/arm/mach-mxs/include/mach/clock.h deleted file mode 100644 index 592c9ab5d760..000000000000 --- a/arch/arm/mach-mxs/include/mach/clock.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Juergen Beisert, kernel@pengutronix.de - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#ifndef __MACH_MXS_CLOCK_H__ -#define __MACH_MXS_CLOCK_H__ - -#ifndef __ASSEMBLY__ -#include <linux/list.h> - -struct module; - -struct clk { - int id; - /* Source clock this clk depends on */ - struct clk *parent; - /* Reference count of clock enable/disable */ - __s8 usecount; - /* Register bit position for clock's enable/disable control. */ - u8 enable_shift; - /* Register address for clock's enable/disable control. */ - void __iomem *enable_reg; - u32 flags; - /* get the current clock rate (always a fresh value) */ - unsigned long (*get_rate) (struct clk *); - /* Function ptr to set the clock to a new rate. The rate must match a - supported rate returned from round_rate. Leave blank if clock is not - programmable */ - int (*set_rate) (struct clk *, unsigned long); - /* Function ptr to round the requested clock rate to the nearest - supported rate that is less than or equal to the requested rate. */ - unsigned long (*round_rate) (struct clk *, unsigned long); - /* Function ptr to enable the clock. Leave blank if clock can not - be gated. */ - int (*enable) (struct clk *); - /* Function ptr to disable the clock. Leave blank if clock can not - be gated. */ - void (*disable) (struct clk *); - /* Function ptr to set the parent clock of the clock. */ - int (*set_parent) (struct clk *, struct clk *); -}; - -int clk_register(struct clk *clk); -void clk_unregister(struct clk *clk); - -#endif /* __ASSEMBLY__ */ -#endif /* __MACH_MXS_CLOCK_H__ */ diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h index 8d88399b73ef..de6c7ba42544 100644 --- a/arch/arm/mach-mxs/include/mach/common.h +++ b/arch/arm/mach-mxs/include/mach/common.h @@ -11,28 +11,27 @@ #ifndef __MACH_MXS_COMMON_H__ #define __MACH_MXS_COMMON_H__ -struct clk; - extern const u32 *mxs_get_ocotp(void); extern int mxs_reset_block(void __iomem *); -extern void mxs_timer_init(struct clk *, int); +extern void mxs_timer_init(int); extern void mxs_restart(char, const char *); extern int mxs_saif_clkmux_select(unsigned int clkmux); extern void mx23_soc_init(void); -extern int mx23_register_gpios(void); extern int mx23_clocks_init(void); extern void mx23_map_io(void); extern void mx23_init_irq(void); extern void mx28_soc_init(void); -extern int mx28_register_gpios(void); extern int mx28_clocks_init(void); extern void mx28_map_io(void); extern void mx28_init_irq(void); extern void icoll_init_irq(void); -extern int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask); +extern struct platform_device *mxs_add_dma(const char *devid, + resource_size_t base); +extern struct platform_device *mxs_add_gpio(char *name, int id, + resource_size_t iobase, int irq); #endif /* __MACH_MXS_COMMON_H__ */ diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h index 21e45a70d344..e8b1d958240b 100644 --- a/arch/arm/mach-mxs/include/mach/devices-common.h +++ b/arch/arm/mach-mxs/include/mach/devices-common.h @@ -82,8 +82,9 @@ struct platform_device * __init mxs_add_mxs_i2c( const struct mxs_mxs_i2c_data *data); /* mmc */ -#include <mach/mmc.h> +#include <linux/mmc/mxs-mmc.h> struct mxs_mxs_mmc_data { + const char *devid; int id; resource_size_t iobase; resource_size_t dma; diff --git a/arch/arm/mach-mxs/include/mach/mmc.h b/arch/arm/mach-mxs/include/mach/mmc.h deleted file mode 100644 index 211547a05564..000000000000 --- a/arch/arm/mach-mxs/include/mach/mmc.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __MACH_MXS_MMC_H__ -#define __MACH_MXS_MMC_H__ - -struct mxs_mmc_platform_data { - int wp_gpio; /* write protect pin */ - unsigned int flags; -#define SLOTF_4_BIT_CAPABLE (1 << 0) -#define SLOTF_8_BIT_CAPABLE (1 << 1) -}; -#endif /* __MACH_MXS_MMC_H__ */ diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c index da4610ebe9e6..dafd48e86c8c 100644 --- a/arch/arm/mach-mxs/mach-mx28evk.c +++ b/arch/arm/mach-mxs/mach-mx28evk.c @@ -226,7 +226,7 @@ static void __init mx28evk_fec_reset(void) struct clk *clk; /* Enable fec phy clock */ - clk = clk_get_sys("pll2", NULL); + clk = clk_get_sys("enet_out", NULL); if (!IS_ERR(clk)) clk_prepare_enable(clk); diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c new file mode 100644 index 000000000000..8cac94b33020 --- /dev/null +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -0,0 +1,121 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/init.h> +#include <linux/irqdomain.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/common.h> + +static int __init mxs_icoll_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL); + + return 0; +} + +static int __init mxs_gpio_add_irq_domain(struct device_node *np, + struct device_node *interrupt_parent) +{ + static int gpio_irq_base = MXS_GPIO_IRQ_START; + + irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL); + gpio_irq_base += 32; + + return 0; +} + +static const struct of_device_id mxs_irq_match[] __initconst = { + { .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, }, + { .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, }, + { /* sentinel */ } +}; + +static void __init mxs_dt_init_irq(void) +{ + icoll_init_irq(); + of_irq_init(mxs_irq_match); +} + +static void __init imx23_timer_init(void) +{ + mx23_clocks_init(); +} + +static struct sys_timer imx23_timer = { + .init = imx23_timer_init, +}; + +static void __init imx28_timer_init(void) +{ + mx28_clocks_init(); +} + +static struct sys_timer imx28_timer = { + .init = imx28_timer_init, +}; + +static void __init imx28_evk_init(void) +{ + struct clk *clk; + + /* Enable fec phy clock */ + clk = clk_get_sys("enet_out", NULL); + if (!IS_ERR(clk)) + clk_prepare_enable(clk); +} + +static void __init mxs_machine_init(void) +{ + if (of_machine_is_compatible("fsl,imx28-evk")) + imx28_evk_init(); + + of_platform_populate(NULL, of_default_bus_match_table, + NULL, NULL); +} + +static const char *imx23_dt_compat[] __initdata = { + "fsl,imx23-evk", + "fsl,imx23", + NULL, +}; + +static const char *imx28_dt_compat[] __initdata = { + "fsl,imx28-evk", + "fsl,imx28", + NULL, +}; + +DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)") + .map_io = mx23_map_io, + .init_irq = mxs_dt_init_irq, + .timer = &imx23_timer, + .init_machine = mxs_machine_init, + .dt_compat = imx23_dt_compat, + .restart = mxs_restart, +MACHINE_END + +DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)") + .map_io = mx28_map_io, + .init_irq = mxs_dt_init_irq, + .timer = &imx28_timer, + .init_machine = mxs_machine_init, + .dt_compat = imx28_dt_compat, + .restart = mxs_restart, +MACHINE_END diff --git a/arch/arm/mach-mxs/mm.c b/arch/arm/mach-mxs/mm.c index 67a384edcf5b..dccb67a9e7c4 100644 --- a/arch/arm/mach-mxs/mm.c +++ b/arch/arm/mach-mxs/mm.c @@ -66,9 +66,25 @@ void __init mx28_init_irq(void) void __init mx23_soc_init(void) { pinctrl_provide_dummies(); + + mxs_add_dma("imx23-dma-apbh", MX23_APBH_DMA_BASE_ADDR); + mxs_add_dma("imx23-dma-apbx", MX23_APBX_DMA_BASE_ADDR); + + mxs_add_gpio("imx23-gpio", 0, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO0); + mxs_add_gpio("imx23-gpio", 1, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO1); + mxs_add_gpio("imx23-gpio", 2, MX23_PINCTRL_BASE_ADDR, MX23_INT_GPIO2); } void __init mx28_soc_init(void) { pinctrl_provide_dummies(); + + mxs_add_dma("imx28-dma-apbh", MX23_APBH_DMA_BASE_ADDR); + mxs_add_dma("imx28-dma-apbx", MX23_APBX_DMA_BASE_ADDR); + + mxs_add_gpio("imx28-gpio", 0, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO0); + mxs_add_gpio("imx28-gpio", 1, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO1); + mxs_add_gpio("imx28-gpio", 2, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO2); + mxs_add_gpio("imx28-gpio", 3, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO3); + mxs_add_gpio("imx28-gpio", 4, MX28_PINCTRL_BASE_ADDR, MX28_INT_GPIO4); } diff --git a/arch/arm/mach-mxs/regs-clkctrl-mx23.h b/arch/arm/mach-mxs/regs-clkctrl-mx23.h deleted file mode 100644 index 0ea5c9d0e2b2..000000000000 --- a/arch/arm/mach-mxs/regs-clkctrl-mx23.h +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Freescale CLKCTRL Register Definitions - * - * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. - * Copyright 2008-2010 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This file is created by xml file. Don't Edit it. - * - * Xml Revision: 1.48 - * Template revision: 26195 - */ - -#ifndef __REGS_CLKCTRL_MX23_H__ -#define __REGS_CLKCTRL_MX23_H__ - - -#define HW_CLKCTRL_PLLCTRL0 (0x00000000) -#define HW_CLKCTRL_PLLCTRL0_SET (0x00000004) -#define HW_CLKCTRL_PLLCTRL0_CLR (0x00000008) -#define HW_CLKCTRL_PLLCTRL0_TOG (0x0000000c) - -#define BP_CLKCTRL_PLLCTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLLCTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLLCTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLLCTRL0_LFR_SEL) -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLLCTRL0_LFR_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLLCTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLLCTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLLCTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLLCTRL0_CP_SEL) -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLLCTRL0_CP_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLLCTRL0_DIV_SEL 20 -#define BM_CLKCTRL_PLLCTRL0_DIV_SEL 0x00300000 -#define BF_CLKCTRL_PLLCTRL0_DIV_SEL(v) \ - (((v) << 20) & BM_CLKCTRL_PLLCTRL0_DIV_SEL) -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWER 0x1 -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__LOWEST 0x2 -#define BV_CLKCTRL_PLLCTRL0_DIV_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS 0x00040000 -#define BM_CLKCTRL_PLLCTRL0_POWER 0x00010000 - -#define HW_CLKCTRL_PLLCTRL1 (0x00000010) - -#define BM_CLKCTRL_PLLCTRL1_LOCK 0x80000000 -#define BM_CLKCTRL_PLLCTRL1_FORCE_LOCK 0x40000000 -#define BP_CLKCTRL_PLLCTRL1_LOCK_COUNT 0 -#define BM_CLKCTRL_PLLCTRL1_LOCK_COUNT 0x0000FFFF -#define BF_CLKCTRL_PLLCTRL1_LOCK_COUNT(v) \ - (((v) << 0) & BM_CLKCTRL_PLLCTRL1_LOCK_COUNT) - -#define HW_CLKCTRL_CPU (0x00000020) -#define HW_CLKCTRL_CPU_SET (0x00000024) -#define HW_CLKCTRL_CPU_CLR (0x00000028) -#define HW_CLKCTRL_CPU_TOG (0x0000002c) - -#define BM_CLKCTRL_CPU_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_CPU_BUSY_REF_CPU 0x10000000 -#define BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN 0x04000000 -#define BP_CLKCTRL_CPU_DIV_XTAL 16 -#define BM_CLKCTRL_CPU_DIV_XTAL 0x03FF0000 -#define BF_CLKCTRL_CPU_DIV_XTAL(v) \ - (((v) << 16) & BM_CLKCTRL_CPU_DIV_XTAL) -#define BM_CLKCTRL_CPU_INTERRUPT_WAIT 0x00001000 -#define BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN 0x00000400 -#define BP_CLKCTRL_CPU_DIV_CPU 0 -#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F -#define BF_CLKCTRL_CPU_DIV_CPU(v) \ - (((v) << 0) & BM_CLKCTRL_CPU_DIV_CPU) - -#define HW_CLKCTRL_HBUS (0x00000030) -#define HW_CLKCTRL_HBUS_SET (0x00000034) -#define HW_CLKCTRL_HBUS_CLR (0x00000038) -#define HW_CLKCTRL_HBUS_TOG (0x0000003c) - -#define BM_CLKCTRL_HBUS_BUSY 0x20000000 -#define BM_CLKCTRL_HBUS_DCP_AS_ENABLE 0x10000000 -#define BM_CLKCTRL_HBUS_PXP_AS_ENABLE 0x08000000 -#define BM_CLKCTRL_HBUS_APBHDMA_AS_ENABLE 0x04000000 -#define BM_CLKCTRL_HBUS_APBXDMA_AS_ENABLE 0x02000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE 0x01000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_AS_ENABLE 0x00800000 -#define BM_CLKCTRL_HBUS_CPU_DATA_AS_ENABLE 0x00400000 -#define BM_CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE 0x00200000 -#define BM_CLKCTRL_HBUS_AUTO_SLOW_MODE 0x00100000 -#define BP_CLKCTRL_HBUS_SLOW_DIV 16 -#define BM_CLKCTRL_HBUS_SLOW_DIV 0x00070000 -#define BF_CLKCTRL_HBUS_SLOW_DIV(v) \ - (((v) << 16) & BM_CLKCTRL_HBUS_SLOW_DIV) -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY1 0x0 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY2 0x1 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY4 0x2 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY8 0x3 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY16 0x4 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY32 0x5 -#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020 -#define BP_CLKCTRL_HBUS_DIV 0 -#define BM_CLKCTRL_HBUS_DIV 0x0000001F -#define BF_CLKCTRL_HBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_HBUS_DIV) - -#define HW_CLKCTRL_XBUS (0x00000040) - -#define BM_CLKCTRL_XBUS_BUSY 0x80000000 -#define BM_CLKCTRL_XBUS_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_XBUS_DIV 0 -#define BM_CLKCTRL_XBUS_DIV 0x000003FF -#define BF_CLKCTRL_XBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_XBUS_DIV) - -#define HW_CLKCTRL_XTAL (0x00000050) -#define HW_CLKCTRL_XTAL_SET (0x00000054) -#define HW_CLKCTRL_XTAL_CLR (0x00000058) -#define HW_CLKCTRL_XTAL_TOG (0x0000005c) - -#define BP_CLKCTRL_XTAL_UART_CLK_GATE 31 -#define BM_CLKCTRL_XTAL_UART_CLK_GATE 0x80000000 -#define BP_CLKCTRL_XTAL_FILT_CLK24M_GATE 30 -#define BM_CLKCTRL_XTAL_FILT_CLK24M_GATE 0x40000000 -#define BP_CLKCTRL_XTAL_PWM_CLK24M_GATE 29 -#define BM_CLKCTRL_XTAL_PWM_CLK24M_GATE 0x20000000 -#define BM_CLKCTRL_XTAL_DRI_CLK24M_GATE 0x10000000 -#define BM_CLKCTRL_XTAL_DIGCTRL_CLK1M_GATE 0x08000000 -#define BP_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 26 -#define BM_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 0x04000000 -#define BP_CLKCTRL_XTAL_DIV_UART 0 -#define BM_CLKCTRL_XTAL_DIV_UART 0x00000003 -#define BF_CLKCTRL_XTAL_DIV_UART(v) \ - (((v) << 0) & BM_CLKCTRL_XTAL_DIV_UART) - -#define HW_CLKCTRL_PIX (0x00000060) - -#define BP_CLKCTRL_PIX_CLKGATE 31 -#define BM_CLKCTRL_PIX_CLKGATE 0x80000000 -#define BM_CLKCTRL_PIX_BUSY 0x20000000 -#define BM_CLKCTRL_PIX_DIV_FRAC_EN 0x00001000 -#define BP_CLKCTRL_PIX_DIV 0 -#define BM_CLKCTRL_PIX_DIV 0x00000FFF -#define BF_CLKCTRL_PIX_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_PIX_DIV) - -#define HW_CLKCTRL_SSP (0x00000070) - -#define BP_CLKCTRL_SSP_CLKGATE 31 -#define BM_CLKCTRL_SSP_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP_BUSY 0x20000000 -#define BM_CLKCTRL_SSP_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP_DIV 0 -#define BM_CLKCTRL_SSP_DIV 0x000001FF -#define BF_CLKCTRL_SSP_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP_DIV) - -#define HW_CLKCTRL_GPMI (0x00000080) - -#define BP_CLKCTRL_GPMI_CLKGATE 31 -#define BM_CLKCTRL_GPMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_GPMI_BUSY 0x20000000 -#define BM_CLKCTRL_GPMI_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_GPMI_DIV 0 -#define BM_CLKCTRL_GPMI_DIV 0x000003FF -#define BF_CLKCTRL_GPMI_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_GPMI_DIV) - -#define HW_CLKCTRL_SPDIF (0x00000090) - -#define BM_CLKCTRL_SPDIF_CLKGATE 0x80000000 - -#define HW_CLKCTRL_EMI (0x000000a0) - -#define BP_CLKCTRL_EMI_CLKGATE 31 -#define BM_CLKCTRL_EMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_EMI_SYNC_MODE_EN 0x40000000 -#define BM_CLKCTRL_EMI_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000 -#define BM_CLKCTRL_EMI_BUSY_REF_CPU 0x08000000 -#define BM_CLKCTRL_EMI_BUSY_SYNC_MODE 0x04000000 -#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000 -#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000 -#define BP_CLKCTRL_EMI_DIV_XTAL 8 -#define BM_CLKCTRL_EMI_DIV_XTAL 0x00000F00 -#define BF_CLKCTRL_EMI_DIV_XTAL(v) \ - (((v) << 8) & BM_CLKCTRL_EMI_DIV_XTAL) -#define BP_CLKCTRL_EMI_DIV_EMI 0 -#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F -#define BF_CLKCTRL_EMI_DIV_EMI(v) \ - (((v) << 0) & BM_CLKCTRL_EMI_DIV_EMI) - -#define HW_CLKCTRL_IR (0x000000b0) - -#define BM_CLKCTRL_IR_CLKGATE 0x80000000 -#define BM_CLKCTRL_IR_AUTO_DIV 0x20000000 -#define BM_CLKCTRL_IR_IR_BUSY 0x10000000 -#define BM_CLKCTRL_IR_IROV_BUSY 0x08000000 -#define BP_CLKCTRL_IR_IROV_DIV 16 -#define BM_CLKCTRL_IR_IROV_DIV 0x01FF0000 -#define BF_CLKCTRL_IR_IROV_DIV(v) \ - (((v) << 16) & BM_CLKCTRL_IR_IROV_DIV) -#define BP_CLKCTRL_IR_IR_DIV 0 -#define BM_CLKCTRL_IR_IR_DIV 0x000003FF -#define BF_CLKCTRL_IR_IR_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_IR_IR_DIV) - -#define HW_CLKCTRL_SAIF (0x000000c0) - -#define BM_CLKCTRL_SAIF_CLKGATE 0x80000000 -#define BM_CLKCTRL_SAIF_BUSY 0x20000000 -#define BM_CLKCTRL_SAIF_DIV_FRAC_EN 0x00010000 -#define BP_CLKCTRL_SAIF_DIV 0 -#define BM_CLKCTRL_SAIF_DIV 0x0000FFFF -#define BF_CLKCTRL_SAIF_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SAIF_DIV) - -#define HW_CLKCTRL_TV (0x000000d0) - -#define BM_CLKCTRL_TV_CLK_TV108M_GATE 0x80000000 -#define BM_CLKCTRL_TV_CLK_TV_GATE 0x40000000 - -#define HW_CLKCTRL_ETM (0x000000e0) - -#define BM_CLKCTRL_ETM_CLKGATE 0x80000000 -#define BM_CLKCTRL_ETM_BUSY 0x20000000 -#define BM_CLKCTRL_ETM_DIV_FRAC_EN 0x00000040 -#define BP_CLKCTRL_ETM_DIV 0 -#define BM_CLKCTRL_ETM_DIV 0x0000003F -#define BF_CLKCTRL_ETM_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_ETM_DIV) - -#define HW_CLKCTRL_FRAC (0x000000f0) -#define HW_CLKCTRL_FRAC_SET (0x000000f4) -#define HW_CLKCTRL_FRAC_CLR (0x000000f8) -#define HW_CLKCTRL_FRAC_TOG (0x000000fc) - -#define BP_CLKCTRL_FRAC_CLKGATEIO 31 -#define BM_CLKCTRL_FRAC_CLKGATEIO 0x80000000 -#define BM_CLKCTRL_FRAC_IO_STABLE 0x40000000 -#define BP_CLKCTRL_FRAC_IOFRAC 24 -#define BM_CLKCTRL_FRAC_IOFRAC 0x3F000000 -#define BF_CLKCTRL_FRAC_IOFRAC(v) \ - (((v) << 24) & BM_CLKCTRL_FRAC_IOFRAC) -#define BP_CLKCTRL_FRAC_CLKGATEPIX 23 -#define BM_CLKCTRL_FRAC_CLKGATEPIX 0x00800000 -#define BM_CLKCTRL_FRAC_PIX_STABLE 0x00400000 -#define BP_CLKCTRL_FRAC_PIXFRAC 16 -#define BM_CLKCTRL_FRAC_PIXFRAC 0x003F0000 -#define BF_CLKCTRL_FRAC_PIXFRAC(v) \ - (((v) << 16) & BM_CLKCTRL_FRAC_PIXFRAC) -#define BP_CLKCTRL_FRAC_CLKGATEEMI 15 -#define BM_CLKCTRL_FRAC_CLKGATEEMI 0x00008000 -#define BM_CLKCTRL_FRAC_EMI_STABLE 0x00004000 -#define BP_CLKCTRL_FRAC_EMIFRAC 8 -#define BM_CLKCTRL_FRAC_EMIFRAC 0x00003F00 -#define BF_CLKCTRL_FRAC_EMIFRAC(v) \ - (((v) << 8) & BM_CLKCTRL_FRAC_EMIFRAC) -#define BP_CLKCTRL_FRAC_CLKGATECPU 7 -#define BM_CLKCTRL_FRAC_CLKGATECPU 0x00000080 -#define BM_CLKCTRL_FRAC_CPU_STABLE 0x00000040 -#define BP_CLKCTRL_FRAC_CPUFRAC 0 -#define BM_CLKCTRL_FRAC_CPUFRAC 0x0000003F -#define BF_CLKCTRL_FRAC_CPUFRAC(v) \ - (((v) << 0) & BM_CLKCTRL_FRAC_CPUFRAC) - -#define HW_CLKCTRL_FRAC1 (0x00000100) -#define HW_CLKCTRL_FRAC1_SET (0x00000104) -#define HW_CLKCTRL_FRAC1_CLR (0x00000108) -#define HW_CLKCTRL_FRAC1_TOG (0x0000010c) - -#define BM_CLKCTRL_FRAC1_CLKGATEVID 0x80000000 -#define BM_CLKCTRL_FRAC1_VID_STABLE 0x40000000 - -#define HW_CLKCTRL_CLKSEQ (0x00000110) -#define HW_CLKCTRL_CLKSEQ_SET (0x00000114) -#define HW_CLKCTRL_CLKSEQ_CLR (0x00000118) -#define HW_CLKCTRL_CLKSEQ_TOG (0x0000011c) - -#define BM_CLKCTRL_CLKSEQ_BYPASS_ETM 0x00000100 -#define BM_CLKCTRL_CLKSEQ_BYPASS_CPU 0x00000080 -#define BM_CLKCTRL_CLKSEQ_BYPASS_EMI 0x00000040 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP 0x00000020 -#define BM_CLKCTRL_CLKSEQ_BYPASS_GPMI 0x00000010 -#define BM_CLKCTRL_CLKSEQ_BYPASS_IR 0x00000008 -#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX 0x00000002 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF 0x00000001 - -#define HW_CLKCTRL_RESET (0x00000120) - -#define BM_CLKCTRL_RESET_CHIP 0x00000002 -#define BM_CLKCTRL_RESET_DIG 0x00000001 - -#define HW_CLKCTRL_STATUS (0x00000130) - -#define BP_CLKCTRL_STATUS_CPU_LIMIT 30 -#define BM_CLKCTRL_STATUS_CPU_LIMIT 0xC0000000 -#define BF_CLKCTRL_STATUS_CPU_LIMIT(v) \ - (((v) << 30) & BM_CLKCTRL_STATUS_CPU_LIMIT) - -#define HW_CLKCTRL_VERSION (0x00000140) - -#define BP_CLKCTRL_VERSION_MAJOR 24 -#define BM_CLKCTRL_VERSION_MAJOR 0xFF000000 -#define BF_CLKCTRL_VERSION_MAJOR(v) \ - (((v) << 24) & BM_CLKCTRL_VERSION_MAJOR) -#define BP_CLKCTRL_VERSION_MINOR 16 -#define BM_CLKCTRL_VERSION_MINOR 0x00FF0000 -#define BF_CLKCTRL_VERSION_MINOR(v) \ - (((v) << 16) & BM_CLKCTRL_VERSION_MINOR) -#define BP_CLKCTRL_VERSION_STEP 0 -#define BM_CLKCTRL_VERSION_STEP 0x0000FFFF -#define BF_CLKCTRL_VERSION_STEP(v) \ - (((v) << 0) & BM_CLKCTRL_VERSION_STEP) - -#endif /* __REGS_CLKCTRL_MX23_H__ */ diff --git a/arch/arm/mach-mxs/regs-clkctrl-mx28.h b/arch/arm/mach-mxs/regs-clkctrl-mx28.h deleted file mode 100644 index 7d1b061d7943..000000000000 --- a/arch/arm/mach-mxs/regs-clkctrl-mx28.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Freescale CLKCTRL Register Definitions - * - * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This file is created by xml file. Don't Edit it. - * - * Xml Revision: 1.48 - * Template revision: 26195 - */ - -#ifndef __REGS_CLKCTRL_MX28_H__ -#define __REGS_CLKCTRL_MX28_H__ - -#define HW_CLKCTRL_PLL0CTRL0 (0x00000000) -#define HW_CLKCTRL_PLL0CTRL0_SET (0x00000004) -#define HW_CLKCTRL_PLL0CTRL0_CLR (0x00000008) -#define HW_CLKCTRL_PLL0CTRL0_TOG (0x0000000c) - -#define BP_CLKCTRL_PLL0CTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLL0CTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLL0CTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLL0CTRL0_LFR_SEL) -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL0CTRL0_LFR_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL0CTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLL0CTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLL0CTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLL0CTRL0_CP_SEL) -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL0CTRL0_CP_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL0CTRL0_DIV_SEL 20 -#define BM_CLKCTRL_PLL0CTRL0_DIV_SEL 0x00300000 -#define BF_CLKCTRL_PLL0CTRL0_DIV_SEL(v) \ - (((v) << 20) & BM_CLKCTRL_PLL0CTRL0_DIV_SEL) -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__LOWER 0x1 -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__LOWEST 0x2 -#define BV_CLKCTRL_PLL0CTRL0_DIV_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_PLL0CTRL0_EN_USB_CLKS 0x00040000 -#define BM_CLKCTRL_PLL0CTRL0_POWER 0x00020000 - -#define HW_CLKCTRL_PLL0CTRL1 (0x00000010) - -#define BM_CLKCTRL_PLL0CTRL1_LOCK 0x80000000 -#define BM_CLKCTRL_PLL0CTRL1_FORCE_LOCK 0x40000000 -#define BP_CLKCTRL_PLL0CTRL1_LOCK_COUNT 0 -#define BM_CLKCTRL_PLL0CTRL1_LOCK_COUNT 0x0000FFFF -#define BF_CLKCTRL_PLL0CTRL1_LOCK_COUNT(v) \ - (((v) << 0) & BM_CLKCTRL_PLL0CTRL1_LOCK_COUNT) - -#define HW_CLKCTRL_PLL1CTRL0 (0x00000020) -#define HW_CLKCTRL_PLL1CTRL0_SET (0x00000024) -#define HW_CLKCTRL_PLL1CTRL0_CLR (0x00000028) -#define HW_CLKCTRL_PLL1CTRL0_TOG (0x0000002c) - -#define BM_CLKCTRL_PLL1CTRL0_CLKGATEEMI 0x80000000 -#define BP_CLKCTRL_PLL1CTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLL1CTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLL1CTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLL1CTRL0_LFR_SEL) -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL1CTRL0_LFR_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL1CTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLL1CTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLL1CTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLL1CTRL0_CP_SEL) -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__TIMES_2 0x1 -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__TIMES_05 0x2 -#define BV_CLKCTRL_PLL1CTRL0_CP_SEL__UNDEFINED 0x3 -#define BP_CLKCTRL_PLL1CTRL0_DIV_SEL 20 -#define BM_CLKCTRL_PLL1CTRL0_DIV_SEL 0x00300000 -#define BF_CLKCTRL_PLL1CTRL0_DIV_SEL(v) \ - (((v) << 20) & BM_CLKCTRL_PLL1CTRL0_DIV_SEL) -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__DEFAULT 0x0 -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__LOWER 0x1 -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__LOWEST 0x2 -#define BV_CLKCTRL_PLL1CTRL0_DIV_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_PLL1CTRL0_EN_USB_CLKS 0x00040000 -#define BM_CLKCTRL_PLL1CTRL0_POWER 0x00020000 - -#define HW_CLKCTRL_PLL1CTRL1 (0x00000030) - -#define BM_CLKCTRL_PLL1CTRL1_LOCK 0x80000000 -#define BM_CLKCTRL_PLL1CTRL1_FORCE_LOCK 0x40000000 -#define BP_CLKCTRL_PLL1CTRL1_LOCK_COUNT 0 -#define BM_CLKCTRL_PLL1CTRL1_LOCK_COUNT 0x0000FFFF -#define BF_CLKCTRL_PLL1CTRL1_LOCK_COUNT(v) \ - (((v) << 0) & BM_CLKCTRL_PLL1CTRL1_LOCK_COUNT) - -#define HW_CLKCTRL_PLL2CTRL0 (0x00000040) -#define HW_CLKCTRL_PLL2CTRL0_SET (0x00000044) -#define HW_CLKCTRL_PLL2CTRL0_CLR (0x00000048) -#define HW_CLKCTRL_PLL2CTRL0_TOG (0x0000004c) - -#define BM_CLKCTRL_PLL2CTRL0_CLKGATE 0x80000000 -#define BP_CLKCTRL_PLL2CTRL0_LFR_SEL 28 -#define BM_CLKCTRL_PLL2CTRL0_LFR_SEL 0x30000000 -#define BF_CLKCTRL_PLL2CTRL0_LFR_SEL(v) \ - (((v) << 28) & BM_CLKCTRL_PLL2CTRL0_LFR_SEL) -#define BM_CLKCTRL_PLL2CTRL0_HOLD_RING_OFF_B 0x04000000 -#define BP_CLKCTRL_PLL2CTRL0_CP_SEL 24 -#define BM_CLKCTRL_PLL2CTRL0_CP_SEL 0x03000000 -#define BF_CLKCTRL_PLL2CTRL0_CP_SEL(v) \ - (((v) << 24) & BM_CLKCTRL_PLL2CTRL0_CP_SEL) -#define BM_CLKCTRL_PLL2CTRL0_POWER 0x00800000 - -#define HW_CLKCTRL_CPU (0x00000050) -#define HW_CLKCTRL_CPU_SET (0x00000054) -#define HW_CLKCTRL_CPU_CLR (0x00000058) -#define HW_CLKCTRL_CPU_TOG (0x0000005c) - -#define BM_CLKCTRL_CPU_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_CPU_BUSY_REF_CPU 0x10000000 -#define BM_CLKCTRL_CPU_DIV_XTAL_FRAC_EN 0x04000000 -#define BP_CLKCTRL_CPU_DIV_XTAL 16 -#define BM_CLKCTRL_CPU_DIV_XTAL 0x03FF0000 -#define BF_CLKCTRL_CPU_DIV_XTAL(v) \ - (((v) << 16) & BM_CLKCTRL_CPU_DIV_XTAL) -#define BM_CLKCTRL_CPU_INTERRUPT_WAIT 0x00001000 -#define BM_CLKCTRL_CPU_DIV_CPU_FRAC_EN 0x00000400 -#define BP_CLKCTRL_CPU_DIV_CPU 0 -#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F -#define BF_CLKCTRL_CPU_DIV_CPU(v) \ - (((v) << 0) & BM_CLKCTRL_CPU_DIV_CPU) - -#define HW_CLKCTRL_HBUS (0x00000060) -#define HW_CLKCTRL_HBUS_SET (0x00000064) -#define HW_CLKCTRL_HBUS_CLR (0x00000068) -#define HW_CLKCTRL_HBUS_TOG (0x0000006c) - -#define BM_CLKCTRL_HBUS_ASM_BUSY 0x80000000 -#define BM_CLKCTRL_HBUS_DCP_AS_ENABLE 0x40000000 -#define BM_CLKCTRL_HBUS_PXP_AS_ENABLE 0x20000000 -#define BM_CLKCTRL_HBUS_ASM_EMIPORT_AS_ENABLE 0x08000000 -#define BM_CLKCTRL_HBUS_APBHDMA_AS_ENABLE 0x04000000 -#define BM_CLKCTRL_HBUS_APBXDMA_AS_ENABLE 0x02000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE 0x01000000 -#define BM_CLKCTRL_HBUS_TRAFFIC_AS_ENABLE 0x00800000 -#define BM_CLKCTRL_HBUS_CPU_DATA_AS_ENABLE 0x00400000 -#define BM_CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE 0x00200000 -#define BM_CLKCTRL_HBUS_ASM_ENABLE 0x00100000 -#define BM_CLKCTRL_HBUS_AUTO_CLEAR_DIV_ENABLE 0x00080000 -#define BP_CLKCTRL_HBUS_SLOW_DIV 16 -#define BM_CLKCTRL_HBUS_SLOW_DIV 0x00070000 -#define BF_CLKCTRL_HBUS_SLOW_DIV(v) \ - (((v) << 16) & BM_CLKCTRL_HBUS_SLOW_DIV) -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY1 0x0 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY2 0x1 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY4 0x2 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY8 0x3 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY16 0x4 -#define BV_CLKCTRL_HBUS_SLOW_DIV__BY32 0x5 -#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020 -#define BP_CLKCTRL_HBUS_DIV 0 -#define BM_CLKCTRL_HBUS_DIV 0x0000001F -#define BF_CLKCTRL_HBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_HBUS_DIV) - -#define HW_CLKCTRL_XBUS (0x00000070) - -#define BM_CLKCTRL_XBUS_BUSY 0x80000000 -#define BM_CLKCTRL_XBUS_AUTO_CLEAR_DIV_ENABLE 0x00000800 -#define BM_CLKCTRL_XBUS_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_XBUS_DIV 0 -#define BM_CLKCTRL_XBUS_DIV 0x000003FF -#define BF_CLKCTRL_XBUS_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_XBUS_DIV) - -#define HW_CLKCTRL_XTAL (0x00000080) -#define HW_CLKCTRL_XTAL_SET (0x00000084) -#define HW_CLKCTRL_XTAL_CLR (0x00000088) -#define HW_CLKCTRL_XTAL_TOG (0x0000008c) - -#define BP_CLKCTRL_XTAL_UART_CLK_GATE 31 -#define BM_CLKCTRL_XTAL_UART_CLK_GATE 0x80000000 -#define BP_CLKCTRL_XTAL_PWM_CLK24M_GATE 29 -#define BM_CLKCTRL_XTAL_PWM_CLK24M_GATE 0x20000000 -#define BP_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 26 -#define BM_CLKCTRL_XTAL_TIMROT_CLK32K_GATE 0x04000000 -#define BP_CLKCTRL_XTAL_DIV_UART 0 -#define BM_CLKCTRL_XTAL_DIV_UART 0x00000003 -#define BF_CLKCTRL_XTAL_DIV_UART(v) \ - (((v) << 0) & BM_CLKCTRL_XTAL_DIV_UART) - -#define HW_CLKCTRL_SSP0 (0x00000090) - -#define BP_CLKCTRL_SSP0_CLKGATE 31 -#define BM_CLKCTRL_SSP0_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP0_BUSY 0x20000000 -#define BM_CLKCTRL_SSP0_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP0_DIV 0 -#define BM_CLKCTRL_SSP0_DIV 0x000001FF -#define BF_CLKCTRL_SSP0_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP0_DIV) - -#define HW_CLKCTRL_SSP1 (0x000000a0) - -#define BP_CLKCTRL_SSP1_CLKGATE 31 -#define BM_CLKCTRL_SSP1_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP1_BUSY 0x20000000 -#define BM_CLKCTRL_SSP1_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP1_DIV 0 -#define BM_CLKCTRL_SSP1_DIV 0x000001FF -#define BF_CLKCTRL_SSP1_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP1_DIV) - -#define HW_CLKCTRL_SSP2 (0x000000b0) - -#define BP_CLKCTRL_SSP2_CLKGATE 31 -#define BM_CLKCTRL_SSP2_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP2_BUSY 0x20000000 -#define BM_CLKCTRL_SSP2_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP2_DIV 0 -#define BM_CLKCTRL_SSP2_DIV 0x000001FF -#define BF_CLKCTRL_SSP2_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP2_DIV) - -#define HW_CLKCTRL_SSP3 (0x000000c0) - -#define BP_CLKCTRL_SSP3_CLKGATE 31 -#define BM_CLKCTRL_SSP3_CLKGATE 0x80000000 -#define BM_CLKCTRL_SSP3_BUSY 0x20000000 -#define BM_CLKCTRL_SSP3_DIV_FRAC_EN 0x00000200 -#define BP_CLKCTRL_SSP3_DIV 0 -#define BM_CLKCTRL_SSP3_DIV 0x000001FF -#define BF_CLKCTRL_SSP3_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SSP3_DIV) - -#define HW_CLKCTRL_GPMI (0x000000d0) - -#define BP_CLKCTRL_GPMI_CLKGATE 31 -#define BM_CLKCTRL_GPMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_GPMI_BUSY 0x20000000 -#define BM_CLKCTRL_GPMI_DIV_FRAC_EN 0x00000400 -#define BP_CLKCTRL_GPMI_DIV 0 -#define BM_CLKCTRL_GPMI_DIV 0x000003FF -#define BF_CLKCTRL_GPMI_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_GPMI_DIV) - -#define HW_CLKCTRL_SPDIF (0x000000e0) - -#define BP_CLKCTRL_SPDIF_CLKGATE 31 -#define BM_CLKCTRL_SPDIF_CLKGATE 0x80000000 - -#define HW_CLKCTRL_EMI (0x000000f0) - -#define BP_CLKCTRL_EMI_CLKGATE 31 -#define BM_CLKCTRL_EMI_CLKGATE 0x80000000 -#define BM_CLKCTRL_EMI_SYNC_MODE_EN 0x40000000 -#define BM_CLKCTRL_EMI_BUSY_REF_XTAL 0x20000000 -#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000 -#define BM_CLKCTRL_EMI_BUSY_REF_CPU 0x08000000 -#define BM_CLKCTRL_EMI_BUSY_SYNC_MODE 0x04000000 -#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000 -#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000 -#define BP_CLKCTRL_EMI_DIV_XTAL 8 -#define BM_CLKCTRL_EMI_DIV_XTAL 0x00000F00 -#define BF_CLKCTRL_EMI_DIV_XTAL(v) \ - (((v) << 8) & BM_CLKCTRL_EMI_DIV_XTAL) -#define BP_CLKCTRL_EMI_DIV_EMI 0 -#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F -#define BF_CLKCTRL_EMI_DIV_EMI(v) \ - (((v) << 0) & BM_CLKCTRL_EMI_DIV_EMI) - -#define HW_CLKCTRL_SAIF0 (0x00000100) - -#define BP_CLKCTRL_SAIF0_CLKGATE 31 -#define BM_CLKCTRL_SAIF0_CLKGATE 0x80000000 -#define BM_CLKCTRL_SAIF0_BUSY 0x20000000 -#define BM_CLKCTRL_SAIF0_DIV_FRAC_EN 0x00010000 -#define BP_CLKCTRL_SAIF0_DIV 0 -#define BM_CLKCTRL_SAIF0_DIV 0x0000FFFF -#define BF_CLKCTRL_SAIF0_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SAIF0_DIV) - -#define HW_CLKCTRL_SAIF1 (0x00000110) - -#define BP_CLKCTRL_SAIF1_CLKGATE 31 -#define BM_CLKCTRL_SAIF1_CLKGATE 0x80000000 -#define BM_CLKCTRL_SAIF1_BUSY 0x20000000 -#define BM_CLKCTRL_SAIF1_DIV_FRAC_EN 0x00010000 -#define BP_CLKCTRL_SAIF1_DIV 0 -#define BM_CLKCTRL_SAIF1_DIV 0x0000FFFF -#define BF_CLKCTRL_SAIF1_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_SAIF1_DIV) - -#define HW_CLKCTRL_DIS_LCDIF (0x00000120) - -#define BP_CLKCTRL_DIS_LCDIF_CLKGATE 31 -#define BM_CLKCTRL_DIS_LCDIF_CLKGATE 0x80000000 -#define BM_CLKCTRL_DIS_LCDIF_BUSY 0x20000000 -#define BM_CLKCTRL_DIS_LCDIF_DIV_FRAC_EN 0x00002000 -#define BP_CLKCTRL_DIS_LCDIF_DIV 0 -#define BM_CLKCTRL_DIS_LCDIF_DIV 0x00001FFF -#define BF_CLKCTRL_DIS_LCDIF_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_DIS_LCDIF_DIV) - -#define HW_CLKCTRL_ETM (0x00000130) - -#define BM_CLKCTRL_ETM_CLKGATE 0x80000000 -#define BM_CLKCTRL_ETM_BUSY 0x20000000 -#define BM_CLKCTRL_ETM_DIV_FRAC_EN 0x00000080 -#define BP_CLKCTRL_ETM_DIV 0 -#define BM_CLKCTRL_ETM_DIV 0x0000007F -#define BF_CLKCTRL_ETM_DIV(v) \ - (((v) << 0) & BM_CLKCTRL_ETM_DIV) - -#define HW_CLKCTRL_ENET (0x00000140) - -#define BM_CLKCTRL_ENET_SLEEP 0x80000000 -#define BP_CLKCTRL_ENET_DISABLE 30 -#define BM_CLKCTRL_ENET_DISABLE 0x40000000 -#define BM_CLKCTRL_ENET_STATUS 0x20000000 -#define BM_CLKCTRL_ENET_BUSY_TIME 0x08000000 -#define BP_CLKCTRL_ENET_DIV_TIME 21 -#define BM_CLKCTRL_ENET_DIV_TIME 0x07E00000 -#define BF_CLKCTRL_ENET_DIV_TIME(v) \ - (((v) << 21) & BM_CLKCTRL_ENET_DIV_TIME) -#define BM_CLKCTRL_ENET_BUSY 0x08000000 -#define BP_CLKCTRL_ENET_DIV 21 -#define BM_CLKCTRL_ENET_DIV 0x07E00000 -#define BF_CLKCTRL_ENET_DIV(v) \ - (((v) << 21) & BM_CLKCTRL_ENET_DIV) -#define BP_CLKCTRL_ENET_TIME_SEL 19 -#define BM_CLKCTRL_ENET_TIME_SEL 0x00180000 -#define BF_CLKCTRL_ENET_TIME_SEL(v) \ - (((v) << 19) & BM_CLKCTRL_ENET_TIME_SEL) -#define BV_CLKCTRL_ENET_TIME_SEL__XTAL 0x0 -#define BV_CLKCTRL_ENET_TIME_SEL__PLL 0x1 -#define BV_CLKCTRL_ENET_TIME_SEL__RMII_CLK 0x2 -#define BV_CLKCTRL_ENET_TIME_SEL__UNDEFINED 0x3 -#define BM_CLKCTRL_ENET_CLK_OUT_EN 0x00040000 -#define BM_CLKCTRL_ENET_RESET_BY_SW_CHIP 0x00020000 -#define BM_CLKCTRL_ENET_RESET_BY_SW 0x00010000 - -#define HW_CLKCTRL_HSADC (0x00000150) - -#define BM_CLKCTRL_HSADC_RESETB 0x40000000 -#define BP_CLKCTRL_HSADC_FREQDIV 28 -#define BM_CLKCTRL_HSADC_FREQDIV 0x30000000 -#define BF_CLKCTRL_HSADC_FREQDIV(v) \ - (((v) << 28) & BM_CLKCTRL_HSADC_FREQDIV) - -#define HW_CLKCTRL_FLEXCAN (0x00000160) - -#define BP_CLKCTRL_FLEXCAN_STOP_CAN0 30 -#define BM_CLKCTRL_FLEXCAN_STOP_CAN0 0x40000000 -#define BM_CLKCTRL_FLEXCAN_CAN0_STATUS 0x20000000 -#define BP_CLKCTRL_FLEXCAN_STOP_CAN1 28 -#define BM_CLKCTRL_FLEXCAN_STOP_CAN1 0x10000000 -#define BM_CLKCTRL_FLEXCAN_CAN1_STATUS 0x08000000 - -#define HW_CLKCTRL_FRAC0 (0x000001b0) -#define HW_CLKCTRL_FRAC0_SET (0x000001b4) -#define HW_CLKCTRL_FRAC0_CLR (0x000001b8) -#define HW_CLKCTRL_FRAC0_TOG (0x000001bc) - -#define BP_CLKCTRL_FRAC0_CLKGATEIO0 31 -#define BM_CLKCTRL_FRAC0_CLKGATEIO0 0x80000000 -#define BM_CLKCTRL_FRAC0_IO0_STABLE 0x40000000 -#define BP_CLKCTRL_FRAC0_IO0FRAC 24 -#define BM_CLKCTRL_FRAC0_IO0FRAC 0x3F000000 -#define BF_CLKCTRL_FRAC0_IO0FRAC(v) \ - (((v) << 24) & BM_CLKCTRL_FRAC0_IO0FRAC) -#define BP_CLKCTRL_FRAC0_CLKGATEIO1 23 -#define BM_CLKCTRL_FRAC0_CLKGATEIO1 0x00800000 -#define BM_CLKCTRL_FRAC0_IO1_STABLE 0x00400000 -#define BP_CLKCTRL_FRAC0_IO1FRAC 16 -#define BM_CLKCTRL_FRAC0_IO1FRAC 0x003F0000 -#define BF_CLKCTRL_FRAC0_IO1FRAC(v) \ - (((v) << 16) & BM_CLKCTRL_FRAC0_IO1FRAC) -#define BP_CLKCTRL_FRAC0_CLKGATEEMI 15 -#define BM_CLKCTRL_FRAC0_CLKGATEEMI 0x00008000 -#define BM_CLKCTRL_FRAC0_EMI_STABLE 0x00004000 -#define BP_CLKCTRL_FRAC0_EMIFRAC 8 -#define BM_CLKCTRL_FRAC0_EMIFRAC 0x00003F00 -#define BF_CLKCTRL_FRAC0_EMIFRAC(v) \ - (((v) << 8) & BM_CLKCTRL_FRAC0_EMIFRAC) -#define BP_CLKCTRL_FRAC0_CLKGATECPU 7 -#define BM_CLKCTRL_FRAC0_CLKGATECPU 0x00000080 -#define BM_CLKCTRL_FRAC0_CPU_STABLE 0x00000040 -#define BP_CLKCTRL_FRAC0_CPUFRAC 0 -#define BM_CLKCTRL_FRAC0_CPUFRAC 0x0000003F -#define BF_CLKCTRL_FRAC0_CPUFRAC(v) \ - (((v) << 0) & BM_CLKCTRL_FRAC0_CPUFRAC) - -#define HW_CLKCTRL_FRAC1 (0x000001c0) -#define HW_CLKCTRL_FRAC1_SET (0x000001c4) -#define HW_CLKCTRL_FRAC1_CLR (0x000001c8) -#define HW_CLKCTRL_FRAC1_TOG (0x000001cc) - -#define BP_CLKCTRL_FRAC1_CLKGATEGPMI 23 -#define BM_CLKCTRL_FRAC1_CLKGATEGPMI 0x00800000 -#define BM_CLKCTRL_FRAC1_GPMI_STABLE 0x00400000 -#define BP_CLKCTRL_FRAC1_GPMIFRAC 16 -#define BM_CLKCTRL_FRAC1_GPMIFRAC 0x003F0000 -#define BF_CLKCTRL_FRAC1_GPMIFRAC(v) \ - (((v) << 16) & BM_CLKCTRL_FRAC1_GPMIFRAC) -#define BP_CLKCTRL_FRAC1_CLKGATEHSADC 15 -#define BM_CLKCTRL_FRAC1_CLKGATEHSADC 0x00008000 -#define BM_CLKCTRL_FRAC1_HSADC_STABLE 0x00004000 -#define BP_CLKCTRL_FRAC1_HSADCFRAC 8 -#define BM_CLKCTRL_FRAC1_HSADCFRAC 0x00003F00 -#define BF_CLKCTRL_FRAC1_HSADCFRAC(v) \ - (((v) << 8) & BM_CLKCTRL_FRAC1_HSADCFRAC) -#define BP_CLKCTRL_FRAC1_CLKGATEPIX 7 -#define BM_CLKCTRL_FRAC1_CLKGATEPIX 0x00000080 -#define BM_CLKCTRL_FRAC1_PIX_STABLE 0x00000040 -#define BP_CLKCTRL_FRAC1_PIXFRAC 0 -#define BM_CLKCTRL_FRAC1_PIXFRAC 0x0000003F -#define BF_CLKCTRL_FRAC1_PIXFRAC(v) \ - (((v) << 0) & BM_CLKCTRL_FRAC1_PIXFRAC) - -#define HW_CLKCTRL_CLKSEQ (0x000001d0) -#define HW_CLKCTRL_CLKSEQ_SET (0x000001d4) -#define HW_CLKCTRL_CLKSEQ_CLR (0x000001d8) -#define HW_CLKCTRL_CLKSEQ_TOG (0x000001dc) - -#define BM_CLKCTRL_CLKSEQ_BYPASS_CPU 0x00040000 -#define BM_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF 0x00004000 -#define BV_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF__BYPASS 0x1 -#define BV_CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF__PFD 0x0 -#define BM_CLKCTRL_CLKSEQ_BYPASS_ETM 0x00000100 -#define BM_CLKCTRL_CLKSEQ_BYPASS_EMI 0x00000080 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP3 0x00000040 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP2 0x00000020 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP1 0x00000010 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SSP0 0x00000008 -#define BM_CLKCTRL_CLKSEQ_BYPASS_GPMI 0x00000004 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF1 0x00000002 -#define BM_CLKCTRL_CLKSEQ_BYPASS_SAIF0 0x00000001 - -#define HW_CLKCTRL_RESET (0x000001e0) - -#define BM_CLKCTRL_RESET_WDOG_POR_DISABLE 0x00000020 -#define BM_CLKCTRL_RESET_EXTERNAL_RESET_ENABLE 0x00000010 -#define BM_CLKCTRL_RESET_THERMAL_RESET_ENABLE 0x00000008 -#define BM_CLKCTRL_RESET_THERMAL_RESET_DEFAULT 0x00000004 -#define BM_CLKCTRL_RESET_CHIP 0x00000002 -#define BM_CLKCTRL_RESET_DIG 0x00000001 - -#define HW_CLKCTRL_STATUS (0x000001f0) - -#define BP_CLKCTRL_STATUS_CPU_LIMIT 30 -#define BM_CLKCTRL_STATUS_CPU_LIMIT 0xC0000000 -#define BF_CLKCTRL_STATUS_CPU_LIMIT(v) \ - (((v) << 30) & BM_CLKCTRL_STATUS_CPU_LIMIT) - -#define HW_CLKCTRL_VERSION (0x00000200) - -#define BP_CLKCTRL_VERSION_MAJOR 24 -#define BM_CLKCTRL_VERSION_MAJOR 0xFF000000 -#define BF_CLKCTRL_VERSION_MAJOR(v) \ - (((v) << 24) & BM_CLKCTRL_VERSION_MAJOR) -#define BP_CLKCTRL_VERSION_MINOR 16 -#define BM_CLKCTRL_VERSION_MINOR 0x00FF0000 -#define BF_CLKCTRL_VERSION_MINOR(v) \ - (((v) << 16) & BM_CLKCTRL_VERSION_MINOR) -#define BP_CLKCTRL_VERSION_STEP 0 -#define BM_CLKCTRL_VERSION_STEP 0x0000FFFF -#define BF_CLKCTRL_VERSION_STEP(v) \ - (((v) << 0) & BM_CLKCTRL_VERSION_STEP) - -#endif /* __REGS_CLKCTRL_MX28_H__ */ diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c index 80ac1fca8a00..30042e23bfa7 100644 --- a/arch/arm/mach-mxs/system.c +++ b/arch/arm/mach-mxs/system.c @@ -37,8 +37,6 @@ #define MXS_MODULE_CLKGATE (1 << 30) #define MXS_MODULE_SFTRST (1 << 31) -#define CLKCTRL_TIMEOUT 10 /* 10 ms */ - static void __iomem *mxs_clkctrl_reset_addr; /* @@ -139,17 +137,3 @@ error: return -ETIMEDOUT; } EXPORT_SYMBOL(mxs_reset_block); - -int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(CLKCTRL_TIMEOUT); - while (readl_relaxed(MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR) - + reg_offset) & mask) { - if (time_after(jiffies, timeout)) { - pr_err("Timeout at CLKCTRL + 0x%x\n", reg_offset); - return -ETIMEDOUT; - } - } - - return 0; -} diff --git a/arch/arm/mach-mxs/timer.c b/arch/arm/mach-mxs/timer.c index 564a63279f18..02d36de9c4e8 100644 --- a/arch/arm/mach-mxs/timer.c +++ b/arch/arm/mach-mxs/timer.c @@ -20,6 +20,7 @@ * MA 02110-1301, USA. */ +#include <linux/err.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/clockchips.h> @@ -243,8 +244,16 @@ static int __init mxs_clocksource_init(struct clk *timer_clk) return 0; } -void __init mxs_timer_init(struct clk *timer_clk, int irq) +void __init mxs_timer_init(int irq) { + struct clk *timer_clk; + + timer_clk = clk_get_sys("timrot", NULL); + if (IS_ERR(timer_clk)) { + pr_err("%s: failed to get clk\n", __func__); + return; + } + clk_prepare_enable(timer_clk); /* diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index c1b681ef4cba..f2f8a5847018 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -595,7 +595,12 @@ gpio_free: gpio_free(AMS_DELTA_GPIO_PIN_MODEM_IRQ); return err; } -late_initcall(late_init); + +static void __init ams_delta_init_late(void) +{ + omap1_init_late(); + late_init(); +} static void __init ams_delta_map_io(void) { @@ -611,6 +616,7 @@ MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = ams_delta_init, + .init_late = ams_delta_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c index 4a4afb371022..c7364fdbda05 100644 --- a/arch/arm/mach-omap1/board-fsample.c +++ b/arch/arm/mach-omap1/board-fsample.c @@ -369,6 +369,7 @@ MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_fsample_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c index 9a5fe581bc1c..e75e2d55a2d7 100644 --- a/arch/arm/mach-omap1/board-generic.c +++ b/arch/arm/mach-omap1/board-generic.c @@ -88,6 +88,7 @@ MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_generic_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 057ec13f0649..7e503686f7af 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -431,6 +431,7 @@ MACHINE_START(OMAP_H2, "TI-H2") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = h2_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index f6ddf8759657..9fb03f189d93 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -425,6 +425,7 @@ MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = h3_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-htcherald.c b/arch/arm/mach-omap1/board-htcherald.c index 60c06ee23855..118a9d4a4c54 100644 --- a/arch/arm/mach-omap1/board-htcherald.c +++ b/arch/arm/mach-omap1/board-htcherald.c @@ -605,6 +605,7 @@ MACHINE_START(HERALD, "HTC Herald") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = htcherald_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index 67d7fd57a692..7970223a559d 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -457,6 +457,7 @@ MACHINE_START(OMAP_INNOVATOR, "TI-Innovator") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = innovator_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index d21dcc2fbc5a..7212ae97f44a 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -255,6 +255,7 @@ MACHINE_START(NOKIA770, "Nokia 770") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_nokia770_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index a5f85dda3f69..da8d872d3d1c 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -574,6 +574,7 @@ MACHINE_START(OMAP_OSK, "TI-OSK") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = osk_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c index a60e6c22f816..949b62a73693 100644 --- a/arch/arm/mach-omap1/board-palmte.c +++ b/arch/arm/mach-omap1/board-palmte.c @@ -267,6 +267,7 @@ MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_palmte_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-palmtt.c b/arch/arm/mach-omap1/board-palmtt.c index 8d854878547b..7f1e1cf2bf46 100644 --- a/arch/arm/mach-omap1/board-palmtt.c +++ b/arch/arm/mach-omap1/board-palmtt.c @@ -313,6 +313,7 @@ MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_palmtt_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c index 61ed4f0247ce..3c71c6bace2c 100644 --- a/arch/arm/mach-omap1/board-palmz71.c +++ b/arch/arm/mach-omap1/board-palmz71.c @@ -330,6 +330,7 @@ MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_palmz71_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index a2c88890e767..f2cb24387c22 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -331,6 +331,7 @@ MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_perseus2_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c index f34cb74a9f41..3b7b82b13684 100644 --- a/arch/arm/mach-omap1/board-sx1.c +++ b/arch/arm/mach-omap1/board-sx1.c @@ -407,6 +407,7 @@ MACHINE_START(SX1, "OMAP310 based Siemens SX1") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = omap_sx1_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = omap1_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index 37232d04233f..afd67f0ec495 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -294,6 +294,7 @@ MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910") .reserve = omap_reserve, .init_irq = omap1_init_irq, .init_machine = voiceblue_init, + .init_late = omap1_init_late, .timer = &omap1_timer, .restart = voiceblue_restart, MACHINE_END diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h index bb7779b57795..c2552b24f9f2 100644 --- a/arch/arm/mach-omap1/common.h +++ b/arch/arm/mach-omap1/common.h @@ -53,8 +53,18 @@ static inline void omap16xx_map_io(void) } #endif +#ifdef CONFIG_OMAP_SERIAL_WAKE +int omap_serial_wakeup_init(void); +#else +static inline int omap_serial_wakeup_init(void) +{ + return 0; +} +#endif + void omap1_init_early(void); void omap1_init_irq(void); +void omap1_init_late(void); void omap1_restart(char, const char *); extern void __init omap_check_revision(void); @@ -63,7 +73,14 @@ extern void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl); extern struct sys_timer omap1_timer; -extern bool omap_32k_timer_init(void); +#ifdef CONFIG_OMAP_32K_TIMER +extern int omap_32k_timer_init(void); +#else +static inline int __init omap_32k_timer_init(void) +{ + return -ENODEV; +} +#endif extern u32 omap_irq_flags; diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index dcd8ddbec2bb..fa1fa4deb6aa 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -22,6 +22,7 @@ #include <plat/tc.h> #include <plat/board.h> #include <plat/mux.h> +#include <plat/dma.h> #include <plat/mmc.h> #include <plat/omap7xx.h> @@ -31,6 +32,22 @@ #include "common.h" #include "clock.h" +#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE) + +static struct platform_device omap_pcm = { + .name = "omap-pcm-audio", + .id = -1, +}; + +static void omap_init_audio(void) +{ + platform_device_register(&omap_pcm); +} + +#else +static inline void omap_init_audio(void) {} +#endif + /*-------------------------------------------------------------------------*/ #if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE) @@ -128,6 +145,56 @@ static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller, } } +#define OMAP_MMC_NR_RES 4 + +/* + * Register MMC devices. + */ +static int __init omap_mmc_add(const char *name, int id, unsigned long base, + unsigned long size, unsigned int irq, + unsigned rx_req, unsigned tx_req, + struct omap_mmc_platform_data *data) +{ + struct platform_device *pdev; + struct resource res[OMAP_MMC_NR_RES]; + int ret; + + pdev = platform_device_alloc(name, id); + if (!pdev) + return -ENOMEM; + + memset(res, 0, OMAP_MMC_NR_RES * sizeof(struct resource)); + res[0].start = base; + res[0].end = base + size - 1; + res[0].flags = IORESOURCE_MEM; + res[1].start = res[1].end = irq; + res[1].flags = IORESOURCE_IRQ; + res[2].start = rx_req; + res[2].name = "rx"; + res[2].flags = IORESOURCE_DMA; + res[3].start = tx_req; + res[3].name = "tx"; + res[3].flags = IORESOURCE_DMA; + + ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); + if (ret == 0) + ret = platform_device_add_data(pdev, data, sizeof(*data)); + if (ret) + goto fail; + + ret = platform_device_add(pdev); + if (ret) + goto fail; + + /* return device handle to board setup code */ + data->dev = &pdev->dev; + return 0; + +fail: + platform_device_put(pdev); + return ret; +} + void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, int nr_controllers) { @@ -135,6 +202,7 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, for (i = 0; i < nr_controllers; i++) { unsigned long base, size; + unsigned rx_req, tx_req; unsigned int irq = 0; if (!mmc_data[i]) @@ -146,19 +214,24 @@ void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, case 0: base = OMAP1_MMC1_BASE; irq = INT_MMC; + rx_req = OMAP_DMA_MMC_RX; + tx_req = OMAP_DMA_MMC_TX; break; case 1: if (!cpu_is_omap16xx()) return; base = OMAP1_MMC2_BASE; irq = INT_1610_MMC2; + rx_req = OMAP_DMA_MMC2_RX; + tx_req = OMAP_DMA_MMC2_TX; break; default: continue; } size = OMAP1_MMC_SIZE; - omap_mmc_add("mmci-omap", i, base, size, irq, mmc_data[i]); + omap_mmc_add("mmci-omap", i, base, size, irq, + rx_req, tx_req, mmc_data[i]); }; } @@ -242,23 +315,48 @@ void __init omap1_camera_init(void *info) static inline void omap_init_sti(void) {} -#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE) +/* Numbering for the SPI-capable controllers when used for SPI: + * spi = 1 + * uwire = 2 + * mmc1..2 = 3..4 + * mcbsp1..3 = 5..7 + */ -static struct platform_device omap_pcm = { - .name = "omap-pcm-audio", - .id = -1, +#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE) + +#define OMAP_UWIRE_BASE 0xfffb3000 + +static struct resource uwire_resources[] = { + { + .start = OMAP_UWIRE_BASE, + .end = OMAP_UWIRE_BASE + 0x20, + .flags = IORESOURCE_MEM, + }, }; -static void omap_init_audio(void) +static struct platform_device omap_uwire_device = { + .name = "omap_uwire", + .id = -1, + .num_resources = ARRAY_SIZE(uwire_resources), + .resource = uwire_resources, +}; + +static void omap_init_uwire(void) { - platform_device_register(&omap_pcm); -} + /* FIXME define and use a boot tag; not all boards will be hooking + * up devices to the microwire controller, and multi-board configs + * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway... + */ + /* board-specific code must configure chipselects (only a few + * are normally used) and SCLK/SDI/SDO (each has two choices). + */ + (void) platform_device_register(&omap_uwire_device); +} #else -static inline void omap_init_audio(void) {} +static inline void omap_init_uwire(void) {} #endif -/*-------------------------------------------------------------------------*/ /* * This gets called after board-specific INIT_MACHINE, and initializes most @@ -292,11 +390,12 @@ static int __init omap1_init_devices(void) * in alphabetical order so they're easier to sort through. */ + omap_init_audio(); omap_init_mbox(); omap_init_rtc(); omap_init_spi100k(); omap_init_sti(); - omap_init_audio(); + omap_init_uwire(); return 0; } diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index 71ce017bf5d8..6c95a59f0f16 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c @@ -137,6 +137,11 @@ void __init omap1_init_early(void) omap_init_consistent_dma_size(); } +void __init omap1_init_late(void) +{ + omap_serial_wakeup_init(); +} + /* * NOTE: Please use ioremap + __raw_read/write where possible instead of these */ diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index 93ae8f29727e..6809c9e56c93 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -237,7 +237,7 @@ static void __init omap_serial_set_port_wakeup(int gpio_nr) enable_irq_wake(gpio_to_irq(gpio_nr)); } -static int __init omap_serial_wakeup_init(void) +int __init omap_serial_wakeup_init(void) { if (!cpu_is_omap16xx()) return 0; @@ -251,7 +251,6 @@ static int __init omap_serial_wakeup_init(void) return 0; } -late_initcall(omap_serial_wakeup_init); #endif /* CONFIG_OMAP_SERIAL_WAKE */ diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index 4d8dd9a1b04c..4062480bfec7 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -232,20 +232,6 @@ static inline void omap_mpu_timer_init(void) } #endif /* CONFIG_OMAP_MPU_TIMER */ -static inline int omap_32k_timer_usable(void) -{ - int res = false; - - if (cpu_is_omap730() || cpu_is_omap15xx()) - return res; - -#ifdef CONFIG_OMAP_32K_TIMER - res = omap_32k_timer_init(); -#endif - - return res; -} - /* * --------------------------------------------------------------------------- * Timer initialization @@ -253,7 +239,7 @@ static inline int omap_32k_timer_usable(void) */ static void __init omap1_timer_init(void) { - if (!omap_32k_timer_usable()) + if (omap_32k_timer_init() != 0) omap_mpu_timer_init(); } diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c index 325b9a0aa4a0..eae49c3980c9 100644 --- a/arch/arm/mach-omap1/timer32k.c +++ b/arch/arm/mach-omap1/timer32k.c @@ -71,6 +71,7 @@ /* 16xx specific defines */ #define OMAP1_32K_TIMER_BASE 0xfffb9000 +#define OMAP1_32KSYNC_TIMER_BASE 0xfffbc400 #define OMAP1_32K_TIMER_CR 0x08 #define OMAP1_32K_TIMER_TVR 0x00 #define OMAP1_32K_TIMER_TCR 0x04 @@ -182,10 +183,29 @@ static __init void omap_init_32k_timer(void) * Timer initialization * --------------------------------------------------------------------------- */ -bool __init omap_32k_timer_init(void) +int __init omap_32k_timer_init(void) { - omap_init_clocksource_32k(); - omap_init_32k_timer(); + int ret = -ENODEV; - return true; + if (cpu_is_omap16xx()) { + void __iomem *base; + struct clk *sync32k_ick; + + base = ioremap(OMAP1_32KSYNC_TIMER_BASE, SZ_1K); + if (!base) { + pr_err("32k_counter: failed to map base addr\n"); + return -ENODEV; + } + + sync32k_ick = clk_get(NULL, "omap_32ksync_ick"); + if (!IS_ERR(sync32k_ick)) + clk_enable(sync32k_ick); + + ret = omap_init_clocksource_32k(base); + } + + if (!ret) + omap_init_32k_timer(); + + return ret; } diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 964ee67a3b77..4cf5142f22cc 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -78,12 +78,12 @@ config SOC_OMAP3430 default y select ARCH_OMAP_OTG -config SOC_OMAPTI81XX +config SOC_TI81XX bool "TI81XX support" depends on ARCH_OMAP3 default y -config SOC_OMAPAM33XX +config SOC_AM33XX bool "AM33XX support" depends on ARCH_OMAP3 default y @@ -320,12 +320,12 @@ config MACH_OMAP_3630SDP config MACH_TI8168EVM bool "TI8168 Evaluation Module" - depends on SOC_OMAPTI81XX + depends on SOC_TI81XX default y config MACH_TI8148EVM bool "TI8148 Evaluation Module" - depends on SOC_OMAPTI81XX + depends on SOC_TI81XX default y config MACH_OMAP_4430SDP diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 385c083d24b2..fa742f3c2629 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -24,10 +24,11 @@ endif obj-$(CONFIG_TWL4030_CORE) += omap_twl.o # SMP support ONLY available for OMAP4 + obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o -obj-$(CONFIG_ARCH_OMAP4) += omap4-common.o omap-wakeupgen.o \ - sleep44xx.o +obj-$(CONFIG_ARCH_OMAP4) += omap4-common.o omap-wakeupgen.o +obj-$(CONFIG_ARCH_OMAP4) += sleep44xx.o plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec) @@ -64,10 +65,10 @@ endif ifeq ($(CONFIG_PM),y) obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o -obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \ - cpuidle34xx.o -obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o \ - cpuidle44xx.o +obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o +obj-$(CONFIG_ARCH_OMAP3) += cpuidle34xx.o +obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o +obj-$(CONFIG_ARCH_OMAP4) += cpuidle44xx.o obj-$(CONFIG_PM_DEBUG) += pm-debug.o obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o @@ -84,90 +85,86 @@ endif # PRCM obj-y += prm_common.o obj-$(CONFIG_ARCH_OMAP2) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o -obj-$(CONFIG_ARCH_OMAP3) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \ - vc3xxx_data.o vp3xxx_data.o -# XXX The presence of cm2xxx_3xxx.o on the line below is temporary and -# will be removed once the OMAP4 part of the codebase is converted to -# use OMAP4-specific PRCM functions. -obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \ - cm44xx.o prcm_mpu44xx.o \ - prminst44xx.o vc44xx_data.o \ - vp44xx_data.o prm44xx.o +obj-$(CONFIG_ARCH_OMAP3) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o +obj-$(CONFIG_ARCH_OMAP3) += vc3xxx_data.o vp3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += prcm.o cminst44xx.o cm44xx.o +obj-$(CONFIG_ARCH_OMAP4) += prcm_mpu44xx.o prminst44xx.o +obj-$(CONFIG_ARCH_OMAP4) += vc44xx_data.o vp44xx_data.o prm44xx.o # OMAP voltage domains voltagedomain-common := voltage.o vc.o vp.o -obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) \ - voltagedomains2xxx_data.o -obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \ - voltagedomains3xxx_data.o -obj-$(CONFIG_ARCH_OMAP4) += $(voltagedomain-common) \ - voltagedomains44xx_data.o +obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) +obj-$(CONFIG_ARCH_OMAP2) += voltagedomains2xxx_data.o +obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) +obj-$(CONFIG_ARCH_OMAP3) += voltagedomains3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += $(voltagedomain-common) +obj-$(CONFIG_ARCH_OMAP4) += voltagedomains44xx_data.o # OMAP powerdomain framework powerdomain-common += powerdomain.o powerdomain-common.o -obj-$(CONFIG_ARCH_OMAP2) += $(powerdomain-common) \ - powerdomain2xxx_3xxx.o \ - powerdomains2xxx_data.o \ - powerdomains2xxx_3xxx_data.o -obj-$(CONFIG_ARCH_OMAP3) += $(powerdomain-common) \ - powerdomain2xxx_3xxx.o \ - powerdomains3xxx_data.o \ - powerdomains2xxx_3xxx_data.o -obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) \ - powerdomain44xx.o \ - powerdomains44xx_data.o +obj-$(CONFIG_ARCH_OMAP2) += $(powerdomain-common) +obj-$(CONFIG_ARCH_OMAP2) += powerdomains2xxx_data.o +obj-$(CONFIG_ARCH_OMAP2) += powerdomain2xxx_3xxx.o +obj-$(CONFIG_ARCH_OMAP2) += powerdomains2xxx_3xxx_data.o +obj-$(CONFIG_ARCH_OMAP3) += $(powerdomain-common) +obj-$(CONFIG_ARCH_OMAP3) += powerdomain2xxx_3xxx.o +obj-$(CONFIG_ARCH_OMAP3) += powerdomains3xxx_data.o +obj-$(CONFIG_ARCH_OMAP3) += powerdomains2xxx_3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) +obj-$(CONFIG_ARCH_OMAP4) += powerdomain44xx.o +obj-$(CONFIG_ARCH_OMAP4) += powerdomains44xx_data.o # PRCM clockdomain control -clockdomain-common += clockdomain.o \ - clockdomains_common_data.o -obj-$(CONFIG_ARCH_OMAP2) += $(clockdomain-common) \ - clockdomain2xxx_3xxx.o \ - clockdomains2xxx_3xxx_data.o +clockdomain-common += clockdomain.o +clockdomain-common += clockdomains_common_data.o +obj-$(CONFIG_ARCH_OMAP2) += $(clockdomain-common) +obj-$(CONFIG_ARCH_OMAP2) += clockdomain2xxx_3xxx.o +obj-$(CONFIG_ARCH_OMAP2) += clockdomains2xxx_3xxx_data.o obj-$(CONFIG_SOC_OMAP2420) += clockdomains2420_data.o obj-$(CONFIG_SOC_OMAP2430) += clockdomains2430_data.o -obj-$(CONFIG_ARCH_OMAP3) += $(clockdomain-common) \ - clockdomain2xxx_3xxx.o \ - clockdomains2xxx_3xxx_data.o \ - clockdomains3xxx_data.o -obj-$(CONFIG_ARCH_OMAP4) += $(clockdomain-common) \ - clockdomain44xx.o \ - clockdomains44xx_data.o +obj-$(CONFIG_ARCH_OMAP3) += $(clockdomain-common) +obj-$(CONFIG_ARCH_OMAP3) += clockdomain2xxx_3xxx.o +obj-$(CONFIG_ARCH_OMAP3) += clockdomains2xxx_3xxx_data.o +obj-$(CONFIG_ARCH_OMAP3) += clockdomains3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += $(clockdomain-common) +obj-$(CONFIG_ARCH_OMAP4) += clockdomain44xx.o +obj-$(CONFIG_ARCH_OMAP4) += clockdomains44xx_data.o # Clock framework -obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \ - clkt2xxx_sys.o \ - clkt2xxx_dpllcore.o \ - clkt2xxx_virt_prcm_set.o \ - clkt2xxx_apll.o clkt2xxx_osc.o \ - clkt2xxx_dpll.o clkt_iclk.o +obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o +obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_sys.o +obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o +obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o +obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_apll.o clkt2xxx_osc.o +obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o clkt_iclk.o obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o -obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \ - clock34xx.o clkt34xx_dpll3m2.o \ - clock3517.o clock36xx.o \ - dpll3xxx.o clock3xxx_data.o \ - clkt_iclk.o -obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o \ - dpll3xxx.o dpll44xx.o +obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o +obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o +obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o +obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o clock3xxx_data.o +obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o +obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o +obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o # OMAP2 clock rate set data (old "OPP" data) obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o obj-$(CONFIG_SOC_OMAP2430) += opp2430_data.o # hwmod data -obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2xxx_ipblock_data.o \ - omap_hwmod_2xxx_3xxx_ipblock_data.o \ - omap_hwmod_2xxx_interconnect_data.o \ - omap_hwmod_2xxx_3xxx_interconnect_data.o \ - omap_hwmod_2420_data.o -obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2xxx_ipblock_data.o \ - omap_hwmod_2xxx_3xxx_ipblock_data.o \ - omap_hwmod_2xxx_interconnect_data.o \ - omap_hwmod_2xxx_3xxx_interconnect_data.o \ - omap_hwmod_2430_data.o -obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_2xxx_3xxx_ipblock_data.o \ - omap_hwmod_2xxx_3xxx_interconnect_data.o \ - omap_hwmod_3xxx_data.o +obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2xxx_ipblock_data.o +obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2xxx_3xxx_ipblock_data.o +obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2xxx_interconnect_data.o +obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2xxx_3xxx_interconnect_data.o +obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2xxx_ipblock_data.o +obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2xxx_3xxx_ipblock_data.o +obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2xxx_interconnect_data.o +obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2xxx_3xxx_interconnect_data.o +obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2430_data.o +obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_2xxx_3xxx_ipblock_data.o +obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_2xxx_3xxx_interconnect_data.o +obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_3xxx_data.o obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o # EMU peripherals @@ -208,23 +205,19 @@ obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o -obj-$(CONFIG_MACH_NOKIA_RM680) += board-rm680.o \ - sdram-nokia.o -obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \ - sdram-nokia.o \ - board-rx51-peripherals.o \ - board-rx51-video.o -obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom.o \ - board-zoom-peripherals.o \ - board-zoom-display.o \ - board-zoom-debugboard.o -obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom.o \ - board-zoom-peripherals.o \ - board-zoom-display.o \ - board-zoom-debugboard.o -obj-$(CONFIG_MACH_OMAP_3630SDP) += board-3630sdp.o \ - board-zoom-peripherals.o \ - board-zoom-display.o +obj-$(CONFIG_MACH_NOKIA_RM680) += board-rm680.o sdram-nokia.o +obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o sdram-nokia.o +obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51-peripherals.o +obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51-video.o +obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom.o board-zoom-peripherals.o +obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom-display.o +obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom-debugboard.o +obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom.o board-zoom-peripherals.o +obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom-display.o +obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom-debugboard.o +obj-$(CONFIG_MACH_OMAP_3630SDP) += board-3630sdp.o +obj-$(CONFIG_MACH_OMAP_3630SDP) += board-zoom-peripherals.o +obj-$(CONFIG_MACH_OMAP_3630SDP) += board-zoom-display.o obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o obj-$(CONFIG_MACH_CM_T3517) += board-cm-t3517.o obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index e658f835d0de..99ca6bad5c30 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -303,6 +303,7 @@ MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board") .init_irq = omap2_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = omap_2430sdp_init, + .init_late = omap2430_init_late, .timer = &omap2_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index 37abb0d49b51..a98c688058a9 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -605,6 +605,7 @@ MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap_3430sdp_init, + .init_late = omap3430_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c index 6ef350d1ae4f..2dc9ba523c7a 100644 --- a/arch/arm/mach-omap2/board-3630sdp.c +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -217,6 +217,7 @@ MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap_sdp_init, + .init_late = omap3630_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 94af6cde2e36..8e17284a803f 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -912,6 +912,7 @@ MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board") .init_irq = gic_init_irq, .handle_irq = gic_handle_irq, .init_machine = omap_4430sdp_init, + .init_late = omap4430_init_late, .timer = &omap4_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c index 3b8a53c1f2a8..92432c28673d 100644 --- a/arch/arm/mach-omap2/board-am3517crane.c +++ b/arch/arm/mach-omap2/board-am3517crane.c @@ -102,6 +102,7 @@ MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = am3517_crane_init, + .init_late = am35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 99790eb646e8..18f601096ce1 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -385,6 +385,7 @@ MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = am3517_evm_init, + .init_late = am35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index 768ece2e9c3b..502c31e123be 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -356,6 +356,7 @@ MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon") .init_irq = omap2_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = omap_apollon_init, + .init_late = omap2420_init_late, .timer = &omap2_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index c03df142ea67..ded100c80a91 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -669,6 +669,7 @@ MACHINE_START(CM_T35, "Compulab CM-T35") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = cm_t35_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END @@ -681,6 +682,7 @@ MACHINE_START(CM_T3730, "Compulab CM-T3730") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = cm_t3730_init, + .init_late = omap3630_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c index 9e66e167e4f3..a33ad4641d9a 100644 --- a/arch/arm/mach-omap2/board-cm-t3517.c +++ b/arch/arm/mach-omap2/board-cm-t3517.c @@ -303,6 +303,7 @@ MACHINE_START(CM_T3517, "Compulab CM-T3517") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = cm_t3517_init, + .init_late = am35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c index b063f0d2faa6..6567c1cd5572 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -644,6 +644,7 @@ MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = devkit8000_init, + .init_late = omap35xx_init_late, .timer = &omap3_secure_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 7302ba7ff1b9..202934657867 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -125,6 +125,7 @@ DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") .init_irq = omap_init_irq, .handle_irq = gic_handle_irq, .init_machine = omap_generic_init, + .init_late = omap4430_init_late, .timer = &omap4_timer, .dt_compat = omap4_boards_compat, .restart = omap_prcm_restart, diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 0bbbabe28fcc..876becf8205a 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -398,6 +398,7 @@ MACHINE_START(OMAP_H4, "OMAP2420 H4 board") .init_irq = omap2_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = omap_h4_init, + .init_late = omap2420_init_late, .timer = &omap2_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 7a274098f67b..74915295482e 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -650,6 +650,7 @@ MACHINE_START(IGEP0020, "IGEP v2 board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = igep_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END @@ -662,6 +663,7 @@ MACHINE_START(IGEP0030, "IGEP OMAP3 module") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = igep_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index 1b6049567ab4..ef9e82977499 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -442,6 +442,7 @@ MACHINE_START(OMAP_LDP, "OMAP LDP board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap_ldp_init, + .init_late = omap3430_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 518091c5f77c..8ca14e88a31a 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -694,6 +694,7 @@ MACHINE_START(NOKIA_N800, "Nokia N800") .init_irq = omap2_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = n8x0_init_machine, + .init_late = omap2420_init_late, .timer = &omap2_timer, .restart = omap_prcm_restart, MACHINE_END @@ -706,6 +707,7 @@ MACHINE_START(NOKIA_N810, "Nokia N810") .init_irq = omap2_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = n8x0_init_machine, + .init_late = omap2420_init_late, .timer = &omap2_timer, .restart = omap_prcm_restart, MACHINE_END @@ -718,6 +720,7 @@ MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX") .init_irq = omap2_init_irq, .handle_irq = omap2_intc_handle_irq, .init_machine = n8x0_init_machine, + .init_late = omap2420_init_late, .timer = &omap2_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 2a7b9a9da1db..79c6909eeb78 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -543,6 +543,7 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3_beagle_init, + .init_late = omap3_init_late, .timer = &omap3_secure_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index ace3c675e9c2..639bd07ea38a 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -671,6 +671,7 @@ MACHINE_START(OMAP3EVM, "OMAP3 EVM") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3_evm_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c index c008bf8e1c36..932e1778aff9 100644 --- a/arch/arm/mach-omap2/board-omap3logic.c +++ b/arch/arm/mach-omap2/board-omap3logic.c @@ -242,6 +242,7 @@ MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3logic_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END @@ -254,6 +255,7 @@ MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3logic_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 33d995d0f075..57aebee44fd0 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -622,6 +622,7 @@ MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3pandora_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c index 4396bae91677..b318f5602e36 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -436,6 +436,7 @@ MACHINE_START(SBC3530, "OMAP3 STALKER") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3_stalker_init, + .init_late = omap35xx_init_late, .timer = &omap3_secure_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c index ae2251fa4a69..485d14d6a8cd 100644 --- a/arch/arm/mach-omap2/board-omap3touchbook.c +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -387,6 +387,7 @@ MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap3_touchbook_init, + .init_late = omap3430_init_late, .timer = &omap3_secure_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 68b8fc9ff010..982fb2622ab8 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -521,6 +521,7 @@ MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") .init_irq = gic_init_irq, .handle_irq = gic_handle_irq, .init_machine = omap4_panda_init, + .init_late = omap4430_init_late, .timer = &omap4_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 5527c1979a16..8fa2fc3a4c3c 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -554,6 +554,7 @@ MACHINE_START(OVERO, "Gumstix Overo") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = overo_init, + .init_late = omap35xx_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c index ae53d71f0ce0..0ad1bb3bdb98 100644 --- a/arch/arm/mach-omap2/board-rm680.c +++ b/arch/arm/mach-omap2/board-rm680.c @@ -151,6 +151,7 @@ MACHINE_START(NOKIA_RM680, "Nokia RM-680 board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = rm680_init, + .init_late = omap3630_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END @@ -163,6 +164,7 @@ MACHINE_START(NOKIA_RM696, "Nokia RM-696 board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = rm680_init, + .init_late = omap3630_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c index 2da92a6ba40a..345dd931f76f 100644 --- a/arch/arm/mach-omap2/board-rx51.c +++ b/arch/arm/mach-omap2/board-rx51.c @@ -127,6 +127,7 @@ MACHINE_START(NOKIA_RX51, "Nokia RX-51 board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = rx51_init, + .init_late = omap3430_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-ti8168evm.c b/arch/arm/mach-omap2/board-ti8168evm.c index ab9a7a9e9d64..d4c8392cadb6 100644 --- a/arch/arm/mach-omap2/board-ti8168evm.c +++ b/arch/arm/mach-omap2/board-ti8168evm.c @@ -52,6 +52,7 @@ MACHINE_START(TI8168EVM, "ti8168evm") .init_irq = ti81xx_init_irq, .timer = &omap3_timer, .init_machine = ti81xx_evm_init, + .init_late = ti81xx_init_late, .restart = omap_prcm_restart, MACHINE_END @@ -63,5 +64,6 @@ MACHINE_START(TI8148EVM, "ti8148evm") .init_irq = ti81xx_init_irq, .timer = &omap3_timer, .init_machine = ti81xx_evm_init, + .init_late = ti81xx_init_late, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/board-zoom.c b/arch/arm/mach-omap2/board-zoom.c index 5c20bcc57f2b..4e7e56142e6f 100644 --- a/arch/arm/mach-omap2/board-zoom.c +++ b/arch/arm/mach-omap2/board-zoom.c @@ -137,6 +137,7 @@ MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap_zoom_init, + .init_late = omap3430_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END @@ -149,6 +150,7 @@ MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board") .init_irq = omap3_init_irq, .handle_irq = omap3_intc_handle_irq, .init_machine = omap_zoom_init, + .init_late = omap3630_init_late, .timer = &omap3_timer, .restart = omap_prcm_restart, MACHINE_END diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index d6c9e6180318..be9dfd1abe60 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -55,7 +55,7 @@ static inline void omap34xx_map_common_io(void) } #endif -#ifdef CONFIG_SOC_OMAPTI81XX +#ifdef CONFIG_SOC_TI81XX extern void omapti81xx_map_common_io(void); #else static inline void omapti81xx_map_common_io(void) @@ -63,7 +63,7 @@ static inline void omapti81xx_map_common_io(void) } #endif -#ifdef CONFIG_SOC_OMAPAM33XX +#ifdef CONFIG_SOC_AM33XX extern void omapam33xx_map_common_io(void); #else static inline void omapam33xx_map_common_io(void) @@ -79,6 +79,42 @@ static inline void omap44xx_map_common_io(void) } #endif +#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP2) +int omap2_pm_init(void); +#else +static inline int omap2_pm_init(void) +{ + return 0; +} +#endif + +#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3) +int omap3_pm_init(void); +#else +static inline int omap3_pm_init(void) +{ + return 0; +} +#endif + +#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP4) +int omap4_pm_init(void); +#else +static inline int omap4_pm_init(void) +{ + return 0; +} +#endif + +#ifdef CONFIG_OMAP_MUX +int omap_mux_late_init(void); +#else +static inline int omap_mux_late_init(void) +{ + return 0; +} +#endif + extern void omap2_init_common_infrastructure(void); extern struct sys_timer omap2_timer; @@ -95,6 +131,17 @@ void omap3_init_early(void); /* Do not use this one */ void am35xx_init_early(void); void ti81xx_init_early(void); void omap4430_init_early(void); +void omap3_init_late(void); /* Do not use this one */ +void omap4430_init_late(void); +void omap2420_init_late(void); +void omap2430_init_late(void); +void omap3430_init_late(void); +void omap35xx_init_late(void); +void omap3630_init_late(void); +void am35xx_init_late(void); +void ti81xx_init_late(void); +void omap4430_init_late(void); +int omap2_common_pm_late_init(void); void omap_prcm_restart(char, const char *); /* diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index ae62ece04ef9..7b4b9327e543 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -645,7 +645,11 @@ static inline void omap242x_mmc_mux(struct omap_mmc_platform_data void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data) { - char *name = "mmci-omap"; + struct platform_device *pdev; + struct omap_hwmod *oh; + int id = 0; + char *oh_name = "msdi1"; + char *dev_name = "mmci-omap"; if (!mmc_data[0]) { pr_err("%s fails: Incomplete platform data\n", __func__); @@ -653,8 +657,17 @@ void __init omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data) } omap242x_mmc_mux(mmc_data[0]); - omap_mmc_add(name, 0, OMAP2_MMC1_BASE, OMAP2420_MMC_SIZE, - INT_24XX_MMC_IRQ, mmc_data[0]); + + oh = omap_hwmod_lookup(oh_name); + if (!oh) { + pr_err("Could not look up %s\n", oh_name); + return; + } + pdev = omap_device_build(dev_name, id, oh, mmc_data[0], + sizeof(struct omap_mmc_platform_data), NULL, 0, 0); + if (IS_ERR(pdev)) + WARN(1, "Can'd build omap_device for %s:%s.\n", + dev_name, oh->name); } #endif diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c index b19d8496c16e..ff75abe60af2 100644 --- a/arch/arm/mach-omap2/dma.c +++ b/arch/arm/mach-omap2/dma.c @@ -227,10 +227,6 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) dma_stride = OMAP2_DMA_STRIDE; dma_common_ch_start = CSDP; - if (cpu_is_omap3630() || cpu_is_omap44xx()) - dma_common_ch_end = CCDN; - else - dma_common_ch_end = CCFN; p = kzalloc(sizeof(struct omap_system_dma_plat_info), GFP_KERNEL); if (!p) { @@ -277,6 +273,13 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) dev_err(&pdev->dev, "%s: kzalloc fail\n", __func__); return -ENOMEM; } + + /* Check the capabilities register for descriptor loading feature */ + if (dma_read(CAPS_0, 0) & DMA_HAS_DESCRIPTOR_CAPS) + dma_common_ch_end = CCDN; + else + dma_common_ch_end = CCFN; + return 0; } diff --git a/arch/arm/mach-omap2/dsp.c b/arch/arm/mach-omap2/dsp.c index 3376388b317a..845309f146fe 100644 --- a/arch/arm/mach-omap2/dsp.c +++ b/arch/arm/mach-omap2/dsp.c @@ -28,8 +28,6 @@ #include <plat/dsp.h> -extern phys_addr_t omap_dsp_get_mempool_base(void); - static struct platform_device *omap_dsp_pdev; static struct omap_dsp_platform_data omap_dsp_pdata __initdata = { @@ -47,6 +45,31 @@ static struct omap_dsp_platform_data omap_dsp_pdata __initdata = { .dsp_cm_rmw_bits = omap2_cm_rmw_mod_reg_bits, }; +static phys_addr_t omap_dsp_phys_mempool_base; + +void __init omap_dsp_reserve_sdram_memblock(void) +{ + phys_addr_t size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE; + phys_addr_t paddr; + + if (!size) + return; + + paddr = arm_memblock_steal(size, SZ_1M); + if (!paddr) { + pr_err("%s: failed to reserve %llx bytes\n", + __func__, (unsigned long long)size); + return; + } + + omap_dsp_phys_mempool_base = paddr; +} + +static phys_addr_t omap_dsp_get_mempool_base(void) +{ + return omap_dsp_phys_mempool_base; +} + static int __init omap_dsp_init(void) { struct platform_device *pdev; diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 580e684e8825..46b09dae770e 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -50,6 +50,19 @@ #define GPMC_ECC_SIZE_CONFIG 0x1fc #define GPMC_ECC1_RESULT 0x200 +/* GPMC ECC control settings */ +#define GPMC_ECC_CTRL_ECCCLEAR 0x100 +#define GPMC_ECC_CTRL_ECCDISABLE 0x000 +#define GPMC_ECC_CTRL_ECCREG1 0x001 +#define GPMC_ECC_CTRL_ECCREG2 0x002 +#define GPMC_ECC_CTRL_ECCREG3 0x003 +#define GPMC_ECC_CTRL_ECCREG4 0x004 +#define GPMC_ECC_CTRL_ECCREG5 0x005 +#define GPMC_ECC_CTRL_ECCREG6 0x006 +#define GPMC_ECC_CTRL_ECCREG7 0x007 +#define GPMC_ECC_CTRL_ECCREG8 0x008 +#define GPMC_ECC_CTRL_ECCREG9 0x009 + #define GPMC_CS0_OFFSET 0x60 #define GPMC_CS_SIZE 0x30 @@ -860,8 +873,9 @@ int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size) gpmc_ecc_used = cs; /* clear ecc and enable bits */ - val = ((0x00000001<<8) | 0x00000001); - gpmc_write_reg(GPMC_ECC_CONTROL, val); + gpmc_write_reg(GPMC_ECC_CONTROL, + GPMC_ECC_CTRL_ECCCLEAR | + GPMC_ECC_CTRL_ECCREG1); /* program ecc and result sizes */ val = ((((ecc_size >> 1) - 1) << 22) | (0x0000000F)); @@ -869,13 +883,15 @@ int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size) switch (mode) { case GPMC_ECC_READ: - gpmc_write_reg(GPMC_ECC_CONTROL, 0x101); + case GPMC_ECC_WRITE: + gpmc_write_reg(GPMC_ECC_CONTROL, + GPMC_ECC_CTRL_ECCCLEAR | + GPMC_ECC_CTRL_ECCREG1); break; case GPMC_ECC_READSYN: - gpmc_write_reg(GPMC_ECC_CONTROL, 0x100); - break; - case GPMC_ECC_WRITE: - gpmc_write_reg(GPMC_ECC_CONTROL, 0x101); + gpmc_write_reg(GPMC_ECC_CONTROL, + GPMC_ECC_CTRL_ECCCLEAR | + GPMC_ECC_CTRL_ECCDISABLE); break; default: printk(KERN_INFO "Error: Unrecognized Mode[%d]!\n", mode); diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index b0268eaffe13..be697d4e0843 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -355,7 +355,7 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, * * temporary HACK: ocr_mask instead of fixed supply */ - if (cpu_is_omap3505() || cpu_is_omap3517()) + if (soc_is_am35xx()) mmc->slots[0].ocr_mask = MMC_VDD_165_195 | MMC_VDD_26_27 | MMC_VDD_27_28 | @@ -365,7 +365,7 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, else mmc->slots[0].ocr_mask = c->ocr_mask; - if (!cpu_is_omap3517() && !cpu_is_omap3505()) + if (!soc_is_am35xx()) mmc->slots[0].features |= HSMMC_HAS_PBIAS; if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0)) @@ -388,7 +388,7 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, } } - if (cpu_is_omap3517() || cpu_is_omap3505()) + if (soc_is_am35xx()) mmc->slots[0].set_power = nop_mmc_set_power; /* OMAP3630 HSMMC1 supports only 4-bit */ @@ -400,7 +400,7 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, } break; case 2: - if (cpu_is_omap3517() || cpu_is_omap3505()) + if (soc_is_am35xx()) mmc->slots[0].set_power = am35x_hsmmc2_set_power; if (c->ext_clock) diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index f1398171d8a2..0389b3264abe 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -185,8 +185,7 @@ static void __init omap3_cpuinfo(void) */ if (cpu_is_omap3630()) { cpu_name = "OMAP3630"; - } else if (cpu_is_omap3517()) { - /* AM35xx devices */ + } else if (soc_is_am35xx()) { cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505"; } else if (cpu_is_ti816x()) { cpu_name = "TI816X"; @@ -352,13 +351,13 @@ void __init omap3xxx_check_revision(void) */ switch (rev) { case 0: - omap_revision = OMAP3517_REV_ES1_0; + omap_revision = AM35XX_REV_ES1_0; cpu_rev = "1.0"; break; case 1: /* FALLTHROUGH */ default: - omap_revision = OMAP3517_REV_ES1_1; + omap_revision = AM35XX_REV_ES1_1; cpu_rev = "1.1"; } break; diff --git a/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h b/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h index d79321b0f2a2..548de90b58c2 100644 --- a/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h +++ b/arch/arm/mach-omap2/include/mach/omap-wakeupgen.h @@ -16,18 +16,10 @@ #define OMAP_WKG_ENB_B_0 0x14 #define OMAP_WKG_ENB_C_0 0x18 #define OMAP_WKG_ENB_D_0 0x1c -#define OMAP_WKG_ENB_SECURE_A_0 0x20 -#define OMAP_WKG_ENB_SECURE_B_0 0x24 -#define OMAP_WKG_ENB_SECURE_C_0 0x28 -#define OMAP_WKG_ENB_SECURE_D_0 0x2c #define OMAP_WKG_ENB_A_1 0x410 #define OMAP_WKG_ENB_B_1 0x414 #define OMAP_WKG_ENB_C_1 0x418 #define OMAP_WKG_ENB_D_1 0x41c -#define OMAP_WKG_ENB_SECURE_A_1 0x420 -#define OMAP_WKG_ENB_SECURE_B_1 0x424 -#define OMAP_WKG_ENB_SECURE_C_1 0x428 -#define OMAP_WKG_ENB_SECURE_D_1 0x42c #define OMAP_AUX_CORE_BOOT_0 0x800 #define OMAP_AUX_CORE_BOOT_1 0x804 #define OMAP_PTMSYNCREQ_MASK 0xc00 diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 4b9491aa36fa..8d014ba04abc 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -173,7 +173,7 @@ static struct map_desc omap34xx_io_desc[] __initdata = { }; #endif -#ifdef CONFIG_SOC_OMAPTI81XX +#ifdef CONFIG_SOC_TI81XX static struct map_desc omapti81xx_io_desc[] __initdata = { { .virtual = L4_34XX_VIRT, @@ -184,7 +184,7 @@ static struct map_desc omapti81xx_io_desc[] __initdata = { }; #endif -#ifdef CONFIG_SOC_OMAPAM33XX +#ifdef CONFIG_SOC_AM33XX static struct map_desc omapam33xx_io_desc[] __initdata = { { .virtual = L4_34XX_VIRT, @@ -216,41 +216,11 @@ static struct map_desc omap44xx_io_desc[] __initdata = { .type = MT_DEVICE, }, { - .virtual = OMAP44XX_GPMC_VIRT, - .pfn = __phys_to_pfn(OMAP44XX_GPMC_PHYS), - .length = OMAP44XX_GPMC_SIZE, - .type = MT_DEVICE, - }, - { - .virtual = OMAP44XX_EMIF1_VIRT, - .pfn = __phys_to_pfn(OMAP44XX_EMIF1_PHYS), - .length = OMAP44XX_EMIF1_SIZE, - .type = MT_DEVICE, - }, - { - .virtual = OMAP44XX_EMIF2_VIRT, - .pfn = __phys_to_pfn(OMAP44XX_EMIF2_PHYS), - .length = OMAP44XX_EMIF2_SIZE, - .type = MT_DEVICE, - }, - { - .virtual = OMAP44XX_DMM_VIRT, - .pfn = __phys_to_pfn(OMAP44XX_DMM_PHYS), - .length = OMAP44XX_DMM_SIZE, - .type = MT_DEVICE, - }, - { .virtual = L4_PER_44XX_VIRT, .pfn = __phys_to_pfn(L4_PER_44XX_PHYS), .length = L4_PER_44XX_SIZE, .type = MT_DEVICE, }, - { - .virtual = L4_EMU_44XX_VIRT, - .pfn = __phys_to_pfn(L4_EMU_44XX_PHYS), - .length = L4_EMU_44XX_SIZE, - .type = MT_DEVICE, - }, #ifdef CONFIG_OMAP4_ERRATA_I688 { .virtual = OMAP4_SRAM_VA, @@ -286,14 +256,14 @@ void __init omap34xx_map_common_io(void) } #endif -#ifdef CONFIG_SOC_OMAPTI81XX +#ifdef CONFIG_SOC_TI81XX void __init omapti81xx_map_common_io(void) { iotable_init(omapti81xx_io_desc, ARRAY_SIZE(omapti81xx_io_desc)); } #endif -#ifdef CONFIG_SOC_OMAPAM33XX +#ifdef CONFIG_SOC_AM33XX void __init omapam33xx_map_common_io(void) { iotable_init(omapam33xx_io_desc, ARRAY_SIZE(omapam33xx_io_desc)); @@ -380,6 +350,13 @@ void __init omap2420_init_early(void) omap_hwmod_init_postsetup(); omap2420_clk_init(); } + +void __init omap2420_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap2_pm_init(); +} #endif #ifdef CONFIG_SOC_OMAP2430 @@ -395,6 +372,13 @@ void __init omap2430_init_early(void) omap_hwmod_init_postsetup(); omap2430_clk_init(); } + +void __init omap2430_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap2_pm_init(); +} #endif /* @@ -449,6 +433,48 @@ void __init ti81xx_init_early(void) omap_hwmod_init_postsetup(); omap3xxx_clk_init(); } + +void __init omap3_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap3_pm_init(); +} + +void __init omap3430_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap3_pm_init(); +} + +void __init omap35xx_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap3_pm_init(); +} + +void __init omap3630_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap3_pm_init(); +} + +void __init am35xx_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap3_pm_init(); +} + +void __init ti81xx_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap3_pm_init(); +} #endif #ifdef CONFIG_ARCH_OMAP4 @@ -465,6 +491,13 @@ void __init omap4430_init_early(void) omap_hwmod_init_postsetup(); omap4xxx_clk_init(); } + +void __init omap4430_init_late(void) +{ + omap_mux_late_init(); + omap2_common_pm_late_init(); + omap4_pm_init(); +} #endif void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0, diff --git a/arch/arm/mach-omap2/iomap.h b/arch/arm/mach-omap2/iomap.h index 0812b154f5b5..80b88921faba 100644 --- a/arch/arm/mach-omap2/iomap.h +++ b/arch/arm/mach-omap2/iomap.h @@ -37,9 +37,6 @@ #define OMAP4_L3_PER_IO_OFFSET 0xb1100000 #define OMAP4_L3_PER_IO_ADDRESS(pa) IOMEM((pa) + OMAP4_L3_PER_IO_OFFSET) -#define OMAP4_GPMC_IO_OFFSET 0xa9000000 -#define OMAP4_GPMC_IO_ADDRESS(pa) IOMEM((pa) + OMAP4_GPMC_IO_OFFSET) - #define OMAP2_EMU_IO_OFFSET 0xaa800000 /* Emulation */ #define OMAP2_EMU_IO_ADDRESS(pa) IOMEM((pa) + OMAP2_EMU_IO_OFFSET) @@ -170,28 +167,3 @@ #define L4_ABE_44XX_VIRT (L4_ABE_44XX_PHYS + OMAP2_L4_IO_OFFSET) #define L4_ABE_44XX_SIZE SZ_1M -#define L4_EMU_44XX_PHYS L4_EMU_44XX_BASE - /* 0x54000000 --> 0xfe800000 */ -#define L4_EMU_44XX_VIRT (L4_EMU_44XX_PHYS + OMAP2_EMU_IO_OFFSET) -#define L4_EMU_44XX_SIZE SZ_8M - -#define OMAP44XX_GPMC_PHYS OMAP44XX_GPMC_BASE - /* 0x50000000 --> 0xf9000000 */ -#define OMAP44XX_GPMC_VIRT (OMAP44XX_GPMC_PHYS + OMAP4_GPMC_IO_OFFSET) -#define OMAP44XX_GPMC_SIZE SZ_1M - - -#define OMAP44XX_EMIF1_PHYS OMAP44XX_EMIF1_BASE - /* 0x4c000000 --> 0xfd100000 */ -#define OMAP44XX_EMIF1_VIRT (OMAP44XX_EMIF1_PHYS + OMAP4_L3_PER_IO_OFFSET) -#define OMAP44XX_EMIF1_SIZE SZ_1M - -#define OMAP44XX_EMIF2_PHYS OMAP44XX_EMIF2_BASE - /* 0x4d000000 --> 0xfd200000 */ -#define OMAP44XX_EMIF2_SIZE SZ_1M -#define OMAP44XX_EMIF2_VIRT (OMAP44XX_EMIF1_VIRT + OMAP44XX_EMIF1_SIZE) - -#define OMAP44XX_DMM_PHYS OMAP44XX_DMM_BASE - /* 0x4e000000 --> 0xfd300000 */ -#define OMAP44XX_DMM_SIZE SZ_1M -#define OMAP44XX_DMM_VIRT (OMAP44XX_EMIF2_VIRT + OMAP44XX_EMIF2_SIZE) diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index 1ecf54565fe2..fdc4303be563 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -231,7 +231,7 @@ static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs goto out; irqnr = readl_relaxed(base_addr + 0xd8); -#ifdef CONFIG_SOC_OMAPTI81XX +#ifdef CONFIG_SOC_TI81XX if (irqnr) goto out; irqnr = readl_relaxed(base_addr + 0xf8); diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 3268ee24eada..80e55c5c9998 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -788,7 +788,7 @@ static void __init omap_mux_free_names(struct omap_mux *m) } /* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */ -static int __init omap_mux_late_init(void) +int __init omap_mux_late_init(void) { struct omap_mux_partition *partition; int ret; @@ -823,7 +823,6 @@ static int __init omap_mux_late_init(void) return 0; } -late_initcall(omap_mux_late_init); static void __init omap_mux_package_fixup(struct omap_mux *p, struct omap_mux *superset) diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index fd48797fa95a..b26d3c9bca16 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -3306,7 +3306,7 @@ int __init omap3xxx_hwmod_init(void) rev == OMAP3430_REV_ES2_1 || rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2) { h = omap34xx_hwmod_ocp_ifs; - } else if (rev == OMAP3517_REV_ES1_0 || rev == OMAP3517_REV_ES1_1) { + } else if (rev == AM35XX_REV_ES1_0 || rev == AM35XX_REV_ES1_1) { h = am35xx_hwmod_ocp_ifs; } else if (rev == OMAP3630_REV_ES1_0 || rev == OMAP3630_REV_ES1_1 || rev == OMAP3630_REV_ES1_2) { diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index d0c1c9695996..9cb5cede0f50 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -295,7 +295,7 @@ static int __init omap2_common_pm_init(void) } postcore_initcall(omap2_common_pm_init); -static int __init omap2_common_pm_late_init(void) +int __init omap2_common_pm_late_init(void) { /* * In the case of DT, the PMIC and SR initialization will be done using @@ -322,4 +322,3 @@ static int __init omap2_common_pm_late_init(void) return 0; } -late_initcall(omap2_common_pm_late_init); diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index facfffca9eac..2edeffc923a6 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c @@ -298,13 +298,10 @@ static void __init prcm_setup_regs(void) WKUP_MOD, PM_WKEN); } -static int __init omap2_pm_init(void) +int __init omap2_pm_init(void) { u32 l; - if (!cpu_is_omap24xx()) - return -ENODEV; - printk(KERN_INFO "Power Management for OMAP2 initializing\n"); l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET); printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f); @@ -370,17 +367,13 @@ static int __init omap2_pm_init(void) * These routines need to be in SRAM as that's the only * memory the MPU can see when it wakes up. */ - if (cpu_is_omap24xx()) { - omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, - omap24xx_idle_loop_suspend_sz); + omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, + omap24xx_idle_loop_suspend_sz); - omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, - omap24xx_cpu_suspend_sz); - } + omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, + omap24xx_cpu_suspend_sz); arm_pm_idle = omap2_pm_idle; return 0; } - -late_initcall(omap2_pm_init); diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 8b43aefba0ea..a34023d0ca7c 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -697,15 +697,12 @@ static void __init pm_errata_configure(void) } } -static int __init omap3_pm_init(void) +int __init omap3_pm_init(void) { struct power_state *pwrst, *tmp; struct clockdomain *neon_clkdm, *mpu_clkdm; int ret; - if (!cpu_is_omap34xx()) - return -ENODEV; - if (!omap3_has_io_chain_ctrl()) pr_warning("PM: no software I/O chain control; some wakeups may be lost\n"); @@ -804,5 +801,3 @@ err2: err1: return ret; } - -late_initcall(omap3_pm_init); diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 885625352429..ea24174f5707 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -141,15 +141,12 @@ static void omap_default_idle(void) * Initializes all powerdomain and clockdomain target states * and all PRCM settings. */ -static int __init omap4_pm_init(void) +int __init omap4_pm_init(void) { int ret; struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm, *l4wkup; struct clockdomain *ducati_clkdm, *l3_2_clkdm, *l4_per_clkdm; - if (!cpu_is_omap44xx()) - return -ENODEV; - if (omap_rev() == OMAP4430_REV_ES1_0) { WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); return -ENODEV; @@ -217,4 +214,3 @@ static int __init omap4_pm_init(void) err2: return ret; } -late_initcall(omap4_pm_init); diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c index b7ea468eea32..fb0a0a6869d1 100644 --- a/arch/arm/mach-omap2/powerdomains3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c @@ -311,7 +311,7 @@ void __init omap3xxx_powerdomains_init(void) rev == OMAP3430_REV_ES3_0 || rev == OMAP3630_REV_ES1_0) pwrdm_register_pwrdms(powerdomains_omap3430es2_es3_0); else if (rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2 || - rev == OMAP3517_REV_ES1_0 || rev == OMAP3517_REV_ES1_1 || + rev == AM35XX_REV_ES1_0 || rev == AM35XX_REV_ES1_1 || rev == OMAP3630_REV_ES1_1 || rev == OMAP3630_REV_ES1_2) pwrdm_register_pwrdms(powerdomains_omap3430es3_1plus); else diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 1b7835865c83..840929bd9dae 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -90,7 +90,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) } static struct irqaction omap2_gp_timer_irq = { - .name = "gp timer", + .name = "gp_timer", .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .handler = omap2_gp_timer_interrupt, }; @@ -132,7 +132,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, } static struct clock_event_device clockevent_gpt = { - .name = "gp timer", + .name = "gp_timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .shift = 32, .set_next_event = omap2_gp_timer_set_next_event, @@ -236,22 +236,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, } /* Clocksource code */ - -#ifdef CONFIG_OMAP_32K_TIMER -/* - * When 32k-timer is enabled, don't use GPTimer for clocksource - * instead, just leave default clocksource which uses the 32k - * sync counter. See clocksource setup in plat-omap/counter_32k.c - */ - -static void __init omap2_gp_clocksource_init(int unused, const char *dummy) -{ - omap_init_clocksource_32k(); -} - -#else - static struct omap_dm_timer clksrc; +static bool use_gptimer_clksrc; /* * clocksource @@ -262,7 +248,7 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs) } static struct clocksource clocksource_gpt = { - .name = "gp timer", + .name = "gp_timer", .rating = 300, .read = clocksource_read_cycles, .mask = CLOCKSOURCE_MASK(32), @@ -278,7 +264,46 @@ static u32 notrace dmtimer_read_sched_clock(void) } /* Setup free-running counter for clocksource */ -static void __init omap2_gp_clocksource_init(int gptimer_id, +static int __init omap2_sync32k_clocksource_init(void) +{ + int ret; + struct omap_hwmod *oh; + void __iomem *vbase; + const char *oh_name = "counter_32k"; + + /* + * First check hwmod data is available for sync32k counter + */ + oh = omap_hwmod_lookup(oh_name); + if (!oh || oh->slaves_cnt == 0) + return -ENODEV; + + omap_hwmod_setup_one(oh_name); + + vbase = omap_hwmod_get_mpu_rt_va(oh); + if (!vbase) { + pr_warn("%s: failed to get counter_32k resource\n", __func__); + return -ENXIO; + } + + ret = omap_hwmod_enable(oh); + if (ret) { + pr_warn("%s: failed to enable counter_32k module (%d)\n", + __func__, ret); + return ret; + } + + ret = omap_init_clocksource_32k(vbase); + if (ret) { + pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n", + __func__, ret); + omap_hwmod_idle(oh); + } + + return ret; +} + +static void __init omap2_gptimer_clocksource_init(int gptimer_id, const char *fck_source) { int res; @@ -286,9 +311,6 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); BUG_ON(res); - pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n", - gptimer_id, clksrc.rate); - __omap_dm_timer_load_start(&clksrc, OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); @@ -296,15 +318,36 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) pr_err("Could not register clocksource %s\n", clocksource_gpt.name); + else + pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n", + gptimer_id, clksrc.rate); +} + +static void __init omap2_clocksource_init(int gptimer_id, + const char *fck_source) +{ + /* + * First give preference to kernel parameter configuration + * by user (clocksource="gp_timer"). + * + * In case of missing kernel parameter for clocksource, + * first check for availability for 32k-sync timer, in case + * of failure in finding 32k_counter module or registering + * it as clocksource, execution will fallback to gp-timer. + */ + if (use_gptimer_clksrc == true) + omap2_gptimer_clocksource_init(gptimer_id, fck_source); + else if (omap2_sync32k_clocksource_init()) + /* Fall back to gp-timer code */ + omap2_gptimer_clocksource_init(gptimer_id, fck_source); } -#endif #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ clksrc_nr, clksrc_src) \ static void __init omap##name##_timer_init(void) \ { \ omap2_gp_clockevent_init((clkev_nr), clkev_src); \ - omap2_gp_clocksource_init((clksrc_nr), clksrc_src); \ + omap2_clocksource_init((clksrc_nr), clksrc_src); \ } #define OMAP_SYS_TIMER(name) \ @@ -335,7 +378,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, static void __init omap4_timer_init(void) { omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); - omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE); + omap2_clocksource_init(2, OMAP4_MPU_SOURCE); #ifdef CONFIG_LOCAL_TIMERS /* Local timers are not supprted on OMAP4430 ES1.0 */ if (omap_rev() != OMAP4430_REV_ES1_0) { @@ -503,3 +546,28 @@ static int __init omap2_dm_timer_init(void) return 0; } arch_initcall(omap2_dm_timer_init); + +/** + * omap2_override_clocksource - clocksource override with user configuration + * + * Allows user to override default clocksource, using kernel parameter + * clocksource="gp_timer" (For all OMAP2PLUS architectures) + * + * Note that, here we are using same standard kernel parameter "clocksource=", + * and not introducing any OMAP specific interface. + */ +static int __init omap2_override_clocksource(char *str) +{ + if (!str) + return 0; + /* + * For OMAP architecture, we only have two options + * - sync_32k (default) + * - gp_timer (sys_clk based) + */ + if (!strcmp(str, "gp_timer")) + use_gptimer_clksrc = true; + + return 0; +} +early_param("clocksource", omap2_override_clocksource); diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c index 8d5ed775dd56..b19d1b43c12e 100644 --- a/arch/arm/mach-omap2/usb-musb.c +++ b/arch/arm/mach-omap2/usb-musb.c @@ -90,7 +90,7 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data) musb_plat.mode = board_data->mode; musb_plat.extvbus = board_data->extvbus; - if (cpu_is_omap3517() || cpu_is_omap3505()) { + if (soc_is_am35xx()) { oh_name = "am35x_otg_hs"; name = "musb-am35x"; } else if (cpu_is_ti81xx()) { diff --git a/arch/arm/mach-omap2/voltagedomains3xxx_data.c b/arch/arm/mach-omap2/voltagedomains3xxx_data.c index 57db2038b23c..d0103c80d040 100644 --- a/arch/arm/mach-omap2/voltagedomains3xxx_data.c +++ b/arch/arm/mach-omap2/voltagedomains3xxx_data.c @@ -118,7 +118,7 @@ void __init omap3xxx_voltagedomains_init(void) } #endif - if (cpu_is_omap3517() || cpu_is_omap3505()) + if (soc_is_am35xx()) voltdms = voltagedomains_am35xx; else voltdms = voltagedomains_omap3; diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index e2e9db492d0c..9148b229d0de 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -18,6 +18,7 @@ #include <linux/mv643xx_i2c.h> #include <linux/ata_platform.h> #include <linux/delay.h> +#include <linux/clk-provider.h> #include <net/dsa.h> #include <asm/page.h> #include <asm/setup.h> @@ -70,6 +71,19 @@ void __init orion5x_map_io(void) /***************************************************************************** + * CLK tree + ****************************************************************************/ +static struct clk *tclk; + +static void __init clk_init(void) +{ + tclk = clk_register_fixed_rate(NULL, "tclk", NULL, CLK_IS_ROOT, + orion5x_tclk); + + orion_clkdev_init(tclk); +} + +/***************************************************************************** * EHCI0 ****************************************************************************/ void __init orion5x_ehci0_init(void) @@ -95,7 +109,7 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM, - IRQ_ORION5X_ETH_ERR, orion5x_tclk); + IRQ_ORION5X_ETH_ERR); } @@ -132,7 +146,7 @@ void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) ****************************************************************************/ void __init orion5x_spi_init() { - orion_spi_init(SPI_PHYS_BASE, orion5x_tclk); + orion_spi_init(SPI_PHYS_BASE); } @@ -142,7 +156,7 @@ void __init orion5x_spi_init() void __init orion5x_uart0_init(void) { orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE, - IRQ_ORION5X_UART0, orion5x_tclk); + IRQ_ORION5X_UART0, tclk); } /***************************************************************************** @@ -151,7 +165,7 @@ void __init orion5x_uart0_init(void) void __init orion5x_uart1_init(void) { orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE, - IRQ_ORION5X_UART1, orion5x_tclk); + IRQ_ORION5X_UART1, tclk); } /***************************************************************************** @@ -179,7 +193,7 @@ static void __init orion5x_crypto_init(void) ****************************************************************************/ void __init orion5x_wdt_init(void) { - orion_wdt_init(orion5x_tclk); + orion_wdt_init(); } @@ -276,6 +290,9 @@ void __init orion5x_init(void) */ orion5x_setup_cpu_mbus_bridge(); + /* Setup root of clk tree */ + clk_init(); + /* * Don't issue "Wait for Interrupt" instruction if we are * running on D0 5281 silicon. diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c index e91bf0ba4e8e..92df49c1b62a 100644 --- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c @@ -16,7 +16,6 @@ #include <linux/mtd/physmap.h> #include <linux/mv643xx_eth.h> #include <linux/spi/spi.h> -#include <linux/spi/orion_spi.h> #include <linux/spi/flash.h> #include <linux/ethtool.h> #include <net/dsa.h> diff --git a/arch/arm/mach-pnx4008/core.c b/arch/arm/mach-pnx4008/core.c index be4c92858509..a00d2f1254ed 100644 --- a/arch/arm/mach-pnx4008/core.c +++ b/arch/arm/mach-pnx4008/core.c @@ -265,6 +265,17 @@ static void pnx4008_restart(char mode, const char *cmd) soft_restart(0); } +#ifdef CONFIG_PM +extern int pnx4008_pm_init(void); +#else +static inline int pnx4008_pm_init(void) { return 0; } +#endif + +void __init pnx4008_init_late(void) +{ + pnx4008_pm_init(); +} + extern struct sys_timer pnx4008_timer; MACHINE_START(PNX4008, "Philips PNX4008") @@ -273,6 +284,7 @@ MACHINE_START(PNX4008, "Philips PNX4008") .map_io = pnx4008_map_io, .init_irq = pnx4008_init_irq, .init_machine = pnx4008_init, + .init_late = pnx4008_init_late, .timer = &pnx4008_timer, .restart = pnx4008_restart, MACHINE_END diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c index f3e60a049f98..26f8d06b142a 100644 --- a/arch/arm/mach-pnx4008/pm.c +++ b/arch/arm/mach-pnx4008/pm.c @@ -124,7 +124,7 @@ static const struct platform_suspend_ops pnx4008_pm_ops = { .valid = pnx4008_pm_valid, }; -static int __init pnx4008_pm_init(void) +int __init pnx4008_pm_init(void) { u32 sram_size_to_allocate; @@ -151,5 +151,3 @@ static int __init pnx4008_pm_init(void) suspend_set_ops(&pnx4008_pm_ops); return 0; } - -late_initcall(pnx4008_pm_init); diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h index b28a930d4f8a..60d826fc2185 100644 --- a/arch/arm/mach-prima2/common.h +++ b/arch/arm/mach-prima2/common.h @@ -24,4 +24,10 @@ static inline void sirfsoc_map_lluart(void) {} extern void __init sirfsoc_map_lluart(void); #endif +#ifdef CONFIG_SUSPEND +extern int sirfsoc_pm_init(void); +#else +static inline int sirfsoc_pm_init(void) { return 0; } +#endif + #endif diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c index 26ebb57719df..fb5a7910af35 100644 --- a/arch/arm/mach-prima2/pm.c +++ b/arch/arm/mach-prima2/pm.c @@ -85,12 +85,11 @@ static const struct platform_suspend_ops sirfsoc_pm_ops = { .valid = suspend_valid_only_mem, }; -static int __init sirfsoc_pm_init(void) +int __init sirfsoc_pm_init(void) { suspend_set_ops(&sirfsoc_pm_ops); return 0; } -late_initcall(sirfsoc_pm_init); static const struct of_device_id pwrc_ids[] = { { .compatible = "sirf,prima2-pwrc" }, diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c index 02b9c05ff990..8f0429d4b79f 100644 --- a/arch/arm/mach-prima2/prima2.c +++ b/arch/arm/mach-prima2/prima2.c @@ -25,6 +25,11 @@ void __init sirfsoc_mach_init(void) of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL); } +void __init sirfsoc_init_late(void) +{ + sirfsoc_pm_init(); +} + static const char *prima2cb_dt_match[] __initdata = { "sirf,prima2-cb", NULL @@ -39,6 +44,7 @@ MACHINE_START(PRIMA2_EVB, "prima2cb") .timer = &sirfsoc_timer, .dma_zone_size = SZ_256M, .init_machine = sirfsoc_mach_init, + .init_late = sirfsoc_init_late, .dt_compat = prima2cb_dt_match, .restart = sirfsoc_restart, MACHINE_END diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index b34287ab5afd..e24961109b70 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -518,6 +518,11 @@ config S3C2443_DMA help Internal config node for S3C2443 DMA support +config S3C2443_SETUP_SPI + bool + help + Common setup code for SPI GPIO configurations + endif # CPU_S3C2443 || CPU_S3C2416 if CPU_S3C2443 diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile index 3518fe812d5f..0ab6ab15da4c 100644 --- a/arch/arm/mach-s3c24xx/Makefile +++ b/arch/arm/mach-s3c24xx/Makefile @@ -14,6 +14,8 @@ obj- := # core +obj-y += common.o + obj-$(CONFIG_CPU_S3C2410) += s3c2410.o obj-$(CONFIG_S3C2410_DMA) += dma-s3c2410.o obj-$(CONFIG_S3C2410_PM) += pm-s3c2410.o sleep-s3c2410.o @@ -33,6 +35,10 @@ obj-$(CONFIG_S3C2440_DMA) += dma-s3c2440.o obj-$(CONFIG_CPU_S3C2443) += s3c2443.o irq-s3c2443.o clock-s3c2443.o +# PM + +obj-$(CONFIG_PM) += pm.o irq-pm.o sleep.o + # common code obj-$(CONFIG_S3C2443_COMMON) += common-s3c2443.o @@ -91,5 +97,6 @@ obj-$(CONFIG_MACH_OSIRIS_DVS) += mach-osiris-dvs.o # device setup obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o +obj-$(CONFIG_S3C2443_SETUP_SPI) += setup-spi.o obj-$(CONFIG_ARCH_S3C24XX) += setup-i2c.o obj-$(CONFIG_S3C24XX_SETUP_TS) += setup-ts.o diff --git a/arch/arm/mach-s3c24xx/clock-s3c2416.c b/arch/arm/mach-s3c24xx/clock-s3c2416.c index dbc9ab4aaca2..8702ecfaab30 100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2416.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2416.c @@ -144,6 +144,7 @@ static struct clk_lookup s3c2416_clk_lookup[] = { CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk), CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk), CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk), + CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk2", &hsspi_mux.clk), }; void __init s3c2416_init_clocks(int xtal) diff --git a/arch/arm/mach-s3c24xx/clock-s3c2443.c b/arch/arm/mach-s3c24xx/clock-s3c2443.c index efb3ac359566..a4c5a520d994 100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2443.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2443.c @@ -179,6 +179,11 @@ static struct clk *clks[] __initdata = { &clk_hsmmc, }; +static struct clk_lookup s3c2443_clk_lookup[] = { + CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_hsmmc), + CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk2", &clk_hsspi.clk), +}; + void __init s3c2443_init_clocks(int xtal) { unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); @@ -210,6 +215,7 @@ void __init s3c2443_init_clocks(int xtal) s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup)); s3c_pwmclk_init(); } diff --git a/arch/arm/mach-s3c24xx/common-s3c2443.c b/arch/arm/mach-s3c24xx/common-s3c2443.c index 460431589f39..aeeb2be283fa 100644 --- a/arch/arm/mach-s3c24xx/common-s3c2443.c +++ b/arch/arm/mach-s3c24xx/common-s3c2443.c @@ -424,11 +424,6 @@ static struct clk init_clocks_off[] = { .enable = s3c2443_clkcon_enable_p, .ctrlbit = S3C2443_PCLKCON_IIS, }, { - .name = "hsspi", - .parent = &clk_p, - .enable = s3c2443_clkcon_enable_p, - .ctrlbit = S3C2443_PCLKCON_HSSPI, - }, { .name = "adc", .parent = &clk_p, .enable = s3c2443_clkcon_enable_p, @@ -562,6 +557,14 @@ static struct clk hsmmc1_clk = { .ctrlbit = S3C2443_HCLKCON_HSMMC, }; +static struct clk hsspi_clk = { + .name = "spi", + .devname = "s3c64xx-spi.0", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_HSSPI, +}; + /* EPLLCON compatible enough to get on/off information */ void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll) @@ -612,6 +615,7 @@ static struct clk *clks[] __initdata = { &clk_usb_bus, &clk_armdiv, &hsmmc1_clk, + &hsspi_clk, }; static struct clksrc_clk *clksrcs[] __initdata = { @@ -629,6 +633,7 @@ static struct clk_lookup s3c2443_clk_lookup[] = { CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk), CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk), + CLKDEV_INIT("s3c64xx-spi.0", "spi_busclk0", &hsspi_clk), }; void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/mach-s3c24xx/common.c index 290942d9adda..56cdd34cce41 100644 --- a/arch/arm/plat-s3c24xx/cpu.c +++ b/arch/arm/mach-s3c24xx/common.c @@ -4,7 +4,7 @@ * http://www.simtec.co.uk/products/SWLINUX/ * Ben Dooks <ben@simtec.co.uk> * - * S3C24XX CPU Support + * Common code for S3C24XX machines * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,6 +41,7 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <plat/regs-serial.h> @@ -52,6 +53,8 @@ #include <plat/s3c2416.h> #include <plat/s3c244x.h> #include <plat/s3c2443.h> +#include <plat/cpu-freq.h> +#include <plat/pll.h> /* table of supported CPUs */ @@ -234,3 +237,67 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); } + +/* Serial port registrations */ + +static struct resource s3c2410_uart0_resource[] = { + [0] = DEFINE_RES_MEM(S3C2410_PA_UART0, SZ_16K), + [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX0, \ + IRQ_S3CUART_ERR0 - IRQ_S3CUART_RX0 + 1, \ + NULL, IORESOURCE_IRQ) +}; + +static struct resource s3c2410_uart1_resource[] = { + [0] = DEFINE_RES_MEM(S3C2410_PA_UART1, SZ_16K), + [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX1, \ + IRQ_S3CUART_ERR1 - IRQ_S3CUART_RX1 + 1, \ + NULL, IORESOURCE_IRQ) +}; + +static struct resource s3c2410_uart2_resource[] = { + [0] = DEFINE_RES_MEM(S3C2410_PA_UART2, SZ_16K), + [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX2, \ + IRQ_S3CUART_ERR2 - IRQ_S3CUART_RX2 + 1, \ + NULL, IORESOURCE_IRQ) +}; + +static struct resource s3c2410_uart3_resource[] = { + [0] = DEFINE_RES_MEM(S3C2443_PA_UART3, SZ_16K), + [1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX3, \ + IRQ_S3CUART_ERR3 - IRQ_S3CUART_RX3 + 1, \ + NULL, IORESOURCE_IRQ) +}; + +struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = { + [0] = { + .resources = s3c2410_uart0_resource, + .nr_resources = ARRAY_SIZE(s3c2410_uart0_resource), + }, + [1] = { + .resources = s3c2410_uart1_resource, + .nr_resources = ARRAY_SIZE(s3c2410_uart1_resource), + }, + [2] = { + .resources = s3c2410_uart2_resource, + .nr_resources = ARRAY_SIZE(s3c2410_uart2_resource), + }, + [3] = { + .resources = s3c2410_uart3_resource, + .nr_resources = ARRAY_SIZE(s3c2410_uart3_resource), + }, +}; + +/* initialise all the clocks */ + +void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk, + unsigned long hclk, + unsigned long pclk) +{ + clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON), + clk_xtal.rate); + + clk_mpll.rate = fclk; + clk_h.rate = hclk; + clk_p.rate = pclk; + clk_f.rate = fclk; +} diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c index e227c472a40a..2d94228d2866 100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2443.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2443.c @@ -55,12 +55,20 @@ static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = { .name = "sdi", .channels = MAP(S3C2443_DMAREQSEL_SDI), }, - [DMACH_SPI0] = { - .name = "spi0", + [DMACH_SPI0_RX] = { + .name = "spi0-rx", + .channels = MAP(S3C2443_DMAREQSEL_SPI0RX), + }, + [DMACH_SPI0_TX] = { + .name = "spi0-tx", .channels = MAP(S3C2443_DMAREQSEL_SPI0TX), }, - [DMACH_SPI1] = { /* only on S3C2443/S3C2450 */ - .name = "spi1", + [DMACH_SPI1_RX] = { /* only on S3C2443/S3C2450 */ + .name = "spi1-rx", + .channels = MAP(S3C2443_DMAREQSEL_SPI1RX), + }, + [DMACH_SPI1_TX] = { /* only on S3C2443/S3C2450 */ + .name = "spi1-tx", .channels = MAP(S3C2443_DMAREQSEL_SPI1TX), }, [DMACH_UART0] = { diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h index acbdfecd4186..454831b66037 100644 --- a/arch/arm/mach-s3c24xx/include/mach/dma.h +++ b/arch/arm/mach-s3c24xx/include/mach/dma.h @@ -47,6 +47,10 @@ enum dma_ch { DMACH_UART2_SRC2, DMACH_UART3, /* s3c2443 has extra uart */ DMACH_UART3_SRC2, + DMACH_SPI0_TX, /* s3c2443/2416/2450 hsspi0 */ + DMACH_SPI0_RX, /* s3c2443/2416/2450 hsspi0 */ + DMACH_SPI1_TX, /* s3c2443/2450 hsspi1 */ + DMACH_SPI1_RX, /* s3c2443/2450 hsspi1 */ DMACH_MAX, /* the end entry */ }; diff --git a/arch/arm/mach-s3c24xx/include/mach/map.h b/arch/arm/mach-s3c24xx/include/mach/map.h index 78ae807f1281..8ba381f2dbe1 100644 --- a/arch/arm/mach-s3c24xx/include/mach/map.h +++ b/arch/arm/mach-s3c24xx/include/mach/map.h @@ -98,6 +98,8 @@ /* SPI */ #define S3C2410_PA_SPI (0x59000000) +#define S3C2443_PA_SPI0 (0x52000000) +#define S3C2443_PA_SPI1 S3C2410_PA_SPI /* SDI */ #define S3C2410_PA_SDI (0x5A000000) @@ -162,4 +164,7 @@ #define S3C_PA_WDT S3C2410_PA_WATCHDOG #define S3C_PA_NAND S3C24XX_PA_NAND +#define S3C_PA_SPI0 S3C2443_PA_SPI0 +#define S3C_PA_SPI1 S3C2443_PA_SPI1 + #endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/plat-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c index 0efb2e2848c8..0efb2e2848c8 100644 --- a/arch/arm/plat-s3c24xx/irq-pm.c +++ b/arch/arm/mach-s3c24xx/irq-pm.c diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/mach-s3c24xx/pm.c index 60627e63a254..60627e63a254 100644 --- a/arch/arm/plat-s3c24xx/pm.c +++ b/arch/arm/mach-s3c24xx/pm.c diff --git a/arch/arm/mach-s3c24xx/setup-spi.c b/arch/arm/mach-s3c24xx/setup-spi.c new file mode 100644 index 000000000000..5712c85f39b1 --- /dev/null +++ b/arch/arm/mach-s3c24xx/setup-spi.c @@ -0,0 +1,39 @@ +/* + * HS-SPI device setup for S3C2443/S3C2416 + * + * Copyright (C) 2011 Samsung Electronics 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/gpio.h> +#include <linux/platform_device.h> + +#include <plat/gpio-cfg.h> +#include <plat/s3c64xx-spi.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> + +#ifdef CONFIG_S3C64XX_DEV_SPI0 +struct s3c64xx_spi_info s3c64xx_spi0_pdata __initdata = { + .fifo_lvl_mask = 0x7f, + .rx_lvl_offset = 13, + .tx_st_done = 21, + .high_speed = 1, +}; + +int s3c64xx_spi0_cfg_gpio(struct platform_device *pdev) +{ + /* enable hsspi bit in misccr */ + s3c2410_modify_misccr(S3C2416_MISCCR_HSSPI_EN2, 1); + + s3c_gpio_cfgall_range(S3C2410_GPE(11), 3, + S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); + + return 0; +} +#endif diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/mach-s3c24xx/sleep.S index c56612569b40..c56612569b40 100644 --- a/arch/arm/plat-s3c24xx/sleep.S +++ b/arch/arm/mach-s3c24xx/sleep.S diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c index b313380342a5..be746e33e86c 100644 --- a/arch/arm/mach-s3c64xx/common.c +++ b/arch/arm/mach-s3c64xx/common.c @@ -384,3 +384,8 @@ void s3c64xx_restart(char mode, const char *cmd) /* if all else fails, or mode was for soft, jump to 0 */ soft_restart(0); } + +void __init s3c64xx_init_late(void) +{ + s3c64xx_pm_late_initcall(); +} diff --git a/arch/arm/mach-s3c64xx/common.h b/arch/arm/mach-s3c64xx/common.h index 7a10be629aba..6cfc99bdfb37 100644 --- a/arch/arm/mach-s3c64xx/common.h +++ b/arch/arm/mach-s3c64xx/common.h @@ -24,6 +24,7 @@ void s3c64xx_register_clocks(unsigned long xtal, unsigned armclk_limit); void s3c64xx_setup_clocks(void); void s3c64xx_restart(char mode, const char *cmd); +void s3c64xx_init_late(void); #ifdef CONFIG_CPU_S3C6400 @@ -51,4 +52,10 @@ extern void s3c6410_init_clocks(int xtal); #define s3c6410_init NULL #endif +#ifdef CONFIG_PM +int __init s3c64xx_pm_late_initcall(void); +#else +static inline int s3c64xx_pm_late_initcall(void) { return 0; } +#endif + #endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */ diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c index f252691fb209..314df0518afd 100644 --- a/arch/arm/mach-s3c64xx/mach-anw6410.c +++ b/arch/arm/mach-s3c64xx/mach-anw6410.c @@ -230,6 +230,7 @@ MACHINE_START(ANW6410, "A&W6410") .handle_irq = vic_handle_irq, .map_io = anw6410_map_io, .init_machine = anw6410_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index aa1137fb47e6..eda5e027b109 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -813,6 +813,7 @@ MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410") .handle_irq = vic_handle_irq, .map_io = crag6410_map_io, .init_machine = crag6410_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c index 521e07b8501b..1bf6b9da20fc 100644 --- a/arch/arm/mach-s3c64xx/mach-hmt.c +++ b/arch/arm/mach-s3c64xx/mach-hmt.c @@ -272,6 +272,7 @@ MACHINE_START(HMT, "Airgoo-HMT") .handle_irq = vic_handle_irq, .map_io = hmt_map_io, .init_machine = hmt_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c index b2166d4a5538..f8ea61ea3b33 100644 --- a/arch/arm/mach-s3c64xx/mach-mini6410.c +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c @@ -339,6 +339,7 @@ MACHINE_START(MINI6410, "MINI6410") .handle_irq = vic_handle_irq, .map_io = mini6410_map_io, .init_machine = mini6410_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-ncp.c b/arch/arm/mach-s3c64xx/mach-ncp.c index 0efa2ba783b2..cad2e05eddf7 100644 --- a/arch/arm/mach-s3c64xx/mach-ncp.c +++ b/arch/arm/mach-s3c64xx/mach-ncp.c @@ -104,6 +104,7 @@ MACHINE_START(NCP, "NCP") .handle_irq = vic_handle_irq, .map_io = ncp_map_io, .init_machine = ncp_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index 5c08266cea21..b92d8e17d502 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -320,6 +320,7 @@ MACHINE_START(REAL6410, "REAL6410") .handle_irq = vic_handle_irq, .map_io = real6410_map_io, .init_machine = real6410_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smartq5.c b/arch/arm/mach-s3c64xx/mach-smartq5.c index 3f42431d4dda..c5021d0335c6 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq5.c +++ b/arch/arm/mach-s3c64xx/mach-smartq5.c @@ -152,6 +152,7 @@ MACHINE_START(SMARTQ5, "SmartQ 5") .handle_irq = vic_handle_irq, .map_io = smartq_map_io, .init_machine = smartq5_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smartq7.c b/arch/arm/mach-s3c64xx/mach-smartq7.c index e5c09b6db967..aa9072a4cbef 100644 --- a/arch/arm/mach-s3c64xx/mach-smartq7.c +++ b/arch/arm/mach-s3c64xx/mach-smartq7.c @@ -168,6 +168,7 @@ MACHINE_START(SMARTQ7, "SmartQ 7") .handle_irq = vic_handle_irq, .map_io = smartq_map_io, .init_machine = smartq7_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smdk6400.c b/arch/arm/mach-s3c64xx/mach-smdk6400.c index 5f096534f4c4..b0f4525c66bd 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6400.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6400.c @@ -93,6 +93,7 @@ MACHINE_START(SMDK6400, "SMDK6400") .handle_irq = vic_handle_irq, .map_io = smdk6400_map_io, .init_machine = smdk6400_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c index 7da044f738ac..d44319b09412 100644 --- a/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -702,6 +702,7 @@ MACHINE_START(SMDK6410, "SMDK6410") .handle_irq = vic_handle_irq, .map_io = smdk6410_map_io, .init_machine = smdk6410_machine_init, + .init_late = s3c64xx_init_late, .timer = &s3c24xx_timer, .restart = s3c64xx_restart, MACHINE_END diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index 7d3e81b9dd06..7feb426fc202 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -365,10 +365,9 @@ static __init int s3c64xx_pm_initcall(void) } arch_initcall(s3c64xx_pm_initcall); -static __init int s3c64xx_pm_late_initcall(void) +int __init s3c64xx_pm_late_initcall(void) { pm_genpd_poweroff_unused(); return 0; } -late_initcall(s3c64xx_pm_late_initcall); diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index 375d3f779a88..d1dc7f1a239c 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -538,6 +538,7 @@ MACHINE_START(ASSABET, "Intel-Assabet") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = assabet_init, + .init_late = sa11x0_init_late, #ifdef CONFIG_SA1111 .dma_zone_size = SZ_1M, #endif diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c index e0f0c030258c..b30fb99b587c 100644 --- a/arch/arm/mach-sa1100/badge4.c +++ b/arch/arm/mach-sa1100/badge4.c @@ -305,6 +305,7 @@ MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4") .map_io = badge4_map_io, .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, + .init_late = sa11x0_init_late, .timer = &sa1100_timer, #ifdef CONFIG_SA1111 .dma_zone_size = SZ_1M, diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c index 4a61f60e0502..09d7f4b4b354 100644 --- a/arch/arm/mach-sa1100/cerf.c +++ b/arch/arm/mach-sa1100/cerf.c @@ -134,5 +134,6 @@ MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube") .init_irq = cerf_init_irq, .timer = &sa1100_timer, .init_machine = cerf_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index c7f418b0cde9..ea5cff38745c 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -401,5 +401,6 @@ MACHINE_START(COLLIE, "Sharp-Collie") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = collie_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 16be4c56abe3..9db3e98e8b85 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -359,6 +359,10 @@ static int __init sa1100_init(void) arch_initcall(sa1100_init); +void __init sa11x0_init_late(void) +{ + sa11x0_pm_init(); +} /* * Common I/O mapping: diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 9eb3b3cd5a63..a5b7c13da3e3 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -11,6 +11,7 @@ extern void __init sa1100_map_io(void); extern void __init sa1100_init_irq(void); extern void __init sa1100_init_gpio(void); extern void sa11x0_restart(char, const char *); +extern void sa11x0_init_late(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ @@ -41,3 +42,9 @@ void sa11x0_register_mcp(struct mcp_plat_data *data); struct sa1100fb_mach_info; void sa11x0_register_lcd(struct sa1100fb_mach_info *inf); + +#ifdef CONFIG_PM +int sa11x0_pm_init(void); +#else +static inline int sa11x0_pm_init(void) { return 0; } +#endif diff --git a/arch/arm/mach-sa1100/h3100.c b/arch/arm/mach-sa1100/h3100.c index b2e8d0f418e0..e1571eab08ae 100644 --- a/arch/arm/mach-sa1100/h3100.c +++ b/arch/arm/mach-sa1100/h3100.c @@ -110,6 +110,7 @@ MACHINE_START(H3100, "Compaq iPAQ H3100") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = h3100_mach_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c index cb6659f294fe..ba7a2901ab88 100644 --- a/arch/arm/mach-sa1100/h3600.c +++ b/arch/arm/mach-sa1100/h3600.c @@ -160,6 +160,7 @@ MACHINE_START(H3600, "Compaq iPAQ H3600") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = h3600_mach_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c index 5535475bf583..7f86bd911826 100644 --- a/arch/arm/mach-sa1100/hackkit.c +++ b/arch/arm/mach-sa1100/hackkit.c @@ -199,5 +199,6 @@ MACHINE_START(HACKKIT, "HackKit Cpu Board") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = hackkit_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c index ca7a7e834720..e3084f47027d 100644 --- a/arch/arm/mach-sa1100/jornada720.c +++ b/arch/arm/mach-sa1100/jornada720.c @@ -348,6 +348,7 @@ MACHINE_START(JORNADA720, "HP Jornada 720") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = jornada720_mach_init, + .init_late = sa11x0_init_late, #ifdef CONFIG_SA1111 .dma_zone_size = SZ_1M, #endif diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c index eb6534e0b0d0..b775a0abec0a 100644 --- a/arch/arm/mach-sa1100/lart.c +++ b/arch/arm/mach-sa1100/lart.c @@ -147,6 +147,7 @@ MACHINE_START(LART, "LART") .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, .init_machine = lart_init, + .init_late = sa11x0_init_late, .timer = &sa1100_timer, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c index 8f6446b9f025..41f69d97066f 100644 --- a/arch/arm/mach-sa1100/nanoengine.c +++ b/arch/arm/mach-sa1100/nanoengine.c @@ -112,5 +112,6 @@ MACHINE_START(NANOENGINE, "BSE nanoEngine") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = nanoengine_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c index 1602575a0d5c..37fe0a0a5369 100644 --- a/arch/arm/mach-sa1100/pleb.c +++ b/arch/arm/mach-sa1100/pleb.c @@ -135,5 +135,6 @@ MACHINE_START(PLEB, "PLEB") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = pleb_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 2fa499ec6afe..690cf0ce5c0c 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -117,10 +117,8 @@ static const struct platform_suspend_ops sa11x0_pm_ops = { .valid = suspend_valid_only_mem, }; -static int __init sa11x0_pm_init(void) +int __init sa11x0_pm_init(void) { suspend_set_ops(&sa11x0_pm_ops); return 0; } - -late_initcall(sa11x0_pm_init); diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c index ca8bf59b9047..5d33fc3108ef 100644 --- a/arch/arm/mach-sa1100/shannon.c +++ b/arch/arm/mach-sa1100/shannon.c @@ -104,5 +104,6 @@ MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)") .init_irq = sa1100_init_irq, .timer = &sa1100_timer, .init_machine = shannon_init, + .init_late = sa11x0_init_late, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c index 3efae03cb3d7..fbd53593be54 100644 --- a/arch/arm/mach-sa1100/simpad.c +++ b/arch/arm/mach-sa1100/simpad.c @@ -395,6 +395,7 @@ MACHINE_START(SIMPAD, "Simpad") .map_io = simpad_map_io, .nr_irqs = SA1100_NR_IRQS, .init_irq = sa1100_init_irq, + .init_late = sa11x0_init_late, .timer = &sa1100_timer, .restart = sa11x0_restart, MACHINE_END diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index e6b177bc9410..8aa1962c22a2 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -3,7 +3,7 @@ # # Common objects -obj-y := timer.o console.o clock.o +obj-y := timer.o console.o clock.o common.o # CPU objects obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 0891ec6e27f5..5a6f22f05e99 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -580,5 +580,6 @@ MACHINE_START(AG5EVM, "ag5evm") .init_irq = sh73a0_init_irq, .handle_irq = gic_handle_irq, .init_machine = ag5evm_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index b540b8eb20ca..ace60246a5df 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -1469,5 +1469,6 @@ MACHINE_START(AP4EVB, "ap4evb") .init_irq = sh7372_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = ap4evb_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c index 63ab7062bee3..e9b32cfbf741 100644 --- a/arch/arm/mach-shmobile/board-bonito.c +++ b/arch/arm/mach-shmobile/board-bonito.c @@ -500,5 +500,6 @@ MACHINE_START(BONITO, "bonito") .init_irq = r8a7740_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = bonito_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c index 39b6cf85ced6..796fa00ad3c4 100644 --- a/arch/arm/mach-shmobile/board-g3evm.c +++ b/arch/arm/mach-shmobile/board-g3evm.c @@ -338,5 +338,6 @@ MACHINE_START(G3EVM, "g3evm") .init_irq = sh7367_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = g3evm_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c index 0e5a39c670bc..f1257321999a 100644 --- a/arch/arm/mach-shmobile/board-g4evm.c +++ b/arch/arm/mach-shmobile/board-g4evm.c @@ -381,5 +381,6 @@ MACHINE_START(G4EVM, "g4evm") .init_irq = sh7377_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = g4evm_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c index 200dcd42a3a0..f60f1b281cc4 100644 --- a/arch/arm/mach-shmobile/board-kota2.c +++ b/arch/arm/mach-shmobile/board-kota2.c @@ -521,5 +521,6 @@ MACHINE_START(KOTA2, "kota2") .init_irq = sh73a0_init_irq, .handle_irq = gic_handle_irq, .init_machine = kota2_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 50c67b22d087..b577f7c44678 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -1638,5 +1638,6 @@ MACHINE_START(MACKEREL, "mackerel") .init_irq = sh7372_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = mackerel_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index ef0e13bf0b3a..14de3787cafc 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -98,5 +98,6 @@ MACHINE_START(MARZEN, "marzen") .init_irq = r8a7779_init_irq, .handle_irq = gic_handle_irq, .init_machine = marzen_init, + .init_late = shmobile_init_late, .timer = &shmobile_timer, MACHINE_END diff --git a/arch/arm/mach-shmobile/common.c b/arch/arm/mach-shmobile/common.c new file mode 100644 index 000000000000..608aba9d60d7 --- /dev/null +++ b/arch/arm/mach-shmobile/common.c @@ -0,0 +1,24 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <mach/common.h> + +void __init shmobile_init_late(void) +{ + shmobile_suspend_init(); + shmobile_cpuidle_init(); +} diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c index 7e6559105d40..7b541e911ab4 100644 --- a/arch/arm/mach-shmobile/cpuidle.c +++ b/arch/arm/mach-shmobile/cpuidle.c @@ -46,7 +46,7 @@ static struct cpuidle_driver shmobile_cpuidle_driver = { void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv); -static int shmobile_cpuidle_init(void) +int shmobile_cpuidle_init(void) { struct cpuidle_device *dev = &shmobile_cpuidle_dev; struct cpuidle_driver *drv = &shmobile_cpuidle_driver; @@ -65,4 +65,3 @@ static int shmobile_cpuidle_init(void) return 0; } -late_initcall(shmobile_cpuidle_init); diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index ff5f12fd742f..01e2bc014f15 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -85,4 +85,18 @@ extern int r8a7779_boot_secondary(unsigned int cpu); extern void r8a7779_smp_prepare_cpus(void); extern void r8a7779_register_twd(void); +extern void shmobile_init_late(void); + +#ifdef CONFIG_SUSPEND +int shmobile_suspend_init(void); +#else +static inline int shmobile_suspend_init(void) { return 0; } +#endif + +#ifdef CONFIG_CPU_IDLE +int shmobile_cpuidle_init(void); +#else +static inline int shmobile_cpuidle_init(void) { return 0; } +#endif + #endif /* __ARCH_MACH_COMMON_H */ diff --git a/arch/arm/mach-shmobile/suspend.c b/arch/arm/mach-shmobile/suspend.c index 4d1b86a49923..47d83f7a70b6 100644 --- a/arch/arm/mach-shmobile/suspend.c +++ b/arch/arm/mach-shmobile/suspend.c @@ -39,9 +39,8 @@ struct platform_suspend_ops shmobile_suspend_ops = { .valid = suspend_valid_only_mem, }; -static int __init shmobile_suspend_init(void) +int __init shmobile_suspend_init(void) { suspend_set_ops(&shmobile_suspend_ops); return 0; } -late_initcall(shmobile_suspend_init); diff --git a/arch/arm/mach-spear13xx/Kconfig b/arch/arm/mach-spear13xx/Kconfig new file mode 100644 index 000000000000..eaadc66d96b3 --- /dev/null +++ b/arch/arm/mach-spear13xx/Kconfig @@ -0,0 +1,20 @@ +# +# SPEAr13XX Machine configuration file +# + +if ARCH_SPEAR13XX + +menu "SPEAr13xx Implementations" +config MACH_SPEAR1310 + bool "SPEAr1310 Machine support with Device Tree" + select PINCTRL_SPEAR1310 + help + Supports ST SPEAr1310 machine configured via the device-tree + +config MACH_SPEAR1340 + bool "SPEAr1340 Machine support with Device Tree" + select PINCTRL_SPEAR1340 + help + Supports ST SPEAr1340 machine configured via the device-tree +endmenu +endif #ARCH_SPEAR13XX diff --git a/arch/arm/mach-spear13xx/Makefile b/arch/arm/mach-spear13xx/Makefile new file mode 100644 index 000000000000..3435ea78c15d --- /dev/null +++ b/arch/arm/mach-spear13xx/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for SPEAr13XX machine series +# + +obj-$(CONFIG_SMP) += headsmp.o platsmp.o +obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o + +obj-$(CONFIG_ARCH_SPEAR13XX) += spear13xx.o +obj-$(CONFIG_MACH_SPEAR1310) += spear1310.o +obj-$(CONFIG_MACH_SPEAR1340) += spear1340.o diff --git a/arch/arm/mach-spear13xx/Makefile.boot b/arch/arm/mach-spear13xx/Makefile.boot new file mode 100644 index 000000000000..403efd7e6d27 --- /dev/null +++ b/arch/arm/mach-spear13xx/Makefile.boot @@ -0,0 +1,6 @@ +zreladdr-y += 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 + +dtb-$(CONFIG_MACH_SPEAR1310) += spear1310-evb.dtb +dtb-$(CONFIG_MACH_SPEAR1340) += spear1340-evb.dtb diff --git a/arch/arm/mach-spear13xx/headsmp.S b/arch/arm/mach-spear13xx/headsmp.S new file mode 100644 index 000000000000..ed85473a047f --- /dev/null +++ b/arch/arm/mach-spear13xx/headsmp.S @@ -0,0 +1,47 @@ +/* + * arch/arm/mach-spear13XX/headsmp.S + * + * Picked from realview + * Copyright (c) 2012 ST Microelectronics Limited + * Shiraz Hashim <shiraz.hashim@st.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/linkage.h> +#include <linux/init.h> + + __INIT + +/* + * spear13xx specific entry point for secondary CPUs. This provides + * a "holding pen" into which all secondary cores are held until we're + * ready for them to initialise. + */ +ENTRY(spear13xx_secondary_startup) + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #15 + adr r4, 1f + ldmia r4, {r5, r6} + sub r4, r4, r5 + add r6, r6, r4 +pen: ldr r7, [r6] + cmp r7, r0 + bne pen + + /* re-enable coherency */ + mrc p15, 0, r0, c1, c0, 1 + orr r0, r0, #(1 << 6) | (1 << 0) + mcr p15, 0, r0, c1, c0, 1 + /* + * we've been released from the holding pen: secondary_stack + * should now contain the SVC stack for this core + */ + b secondary_startup + + .align +1: .long . + .long pen_release +ENDPROC(spear13xx_secondary_startup) diff --git a/arch/arm/mach-spear13xx/hotplug.c b/arch/arm/mach-spear13xx/hotplug.c new file mode 100644 index 000000000000..5c6867b46d09 --- /dev/null +++ b/arch/arm/mach-spear13xx/hotplug.c @@ -0,0 +1,119 @@ +/* + * linux/arch/arm/mach-spear13xx/hotplug.c + * + * Copyright (C) 2012 ST Microelectronics Ltd. + * Deepak Sikri <deepak.sikri@st.com> + * + * based upon linux/arch/arm/mach-realview/hotplug.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <asm/cacheflush.h> +#include <asm/cp15.h> +#include <asm/smp_plat.h> + +extern volatile int pen_release; + +static inline void cpu_enter_lowpower(void) +{ + unsigned int v; + + flush_cache_all(); + asm volatile( + " mcr p15, 0, %1, c7, c5, 0\n" + " dsb\n" + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" + " bic %0, %0, #0x20\n" + " mcr p15, 0, %0, c1, c0, 1\n" + " mrc p15, 0, %0, c1, c0, 0\n" + " bic %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "r" (0), "Ir" (CR_C) + : "cc", "memory"); +} + +static inline void cpu_leave_lowpower(void) +{ + unsigned int v; + + asm volatile("mrc p15, 0, %0, c1, c0, 0\n" + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" + " orr %0, %0, #0x20\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (CR_C) + : "cc"); +} + +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +{ + for (;;) { + wfi(); + + if (pen_release == cpu) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * Getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * Just note it happening - when we're woken, we can report + * its occurrence. + */ + (*spurious)++; + } +} + +int platform_cpu_kill(unsigned int cpu) +{ + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void __cpuinit platform_cpu_die(unsigned int cpu) +{ + int spurious = 0; + + /* + * we're ready for shutdown now, so do it + */ + cpu_enter_lowpower(); + platform_do_lowpower(cpu, &spurious); + + /* + * bring this CPU back into the world of cache + * coherency, and then restore interrupts + */ + cpu_leave_lowpower(); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-spear13xx/include/mach/debug-macro.S b/arch/arm/mach-spear13xx/include/mach/debug-macro.S new file mode 100644 index 000000000000..ea1564609bd4 --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/debug-macro.S @@ -0,0 +1,14 @@ +/* + * arch/arm/mach-spear13xx/include/mach/debug-macro.S + * + * Debugging macro include header spear13xx machine family + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <plat/debug-macro.S> diff --git a/arch/arm/mach-spear13xx/include/mach/dma.h b/arch/arm/mach-spear13xx/include/mach/dma.h new file mode 100644 index 000000000000..383ab04dc6c9 --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/dma.h @@ -0,0 +1,128 @@ +/* + * arch/arm/mach-spear13xx/include/mach/dma.h + * + * DMA information for SPEAr13xx machine family + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MACH_DMA_H +#define __MACH_DMA_H + +/* request id of all the peripherals */ +enum dma_master_info { + /* Accessible from only one master */ + DMA_MASTER_MCIF = 0, + DMA_MASTER_FSMC = 1, + /* Accessible from both 0 & 1 */ + DMA_MASTER_MEMORY = 0, + DMA_MASTER_ADC = 0, + DMA_MASTER_UART0 = 0, + DMA_MASTER_SSP0 = 0, + DMA_MASTER_I2C0 = 0, + +#ifdef CONFIG_MACH_SPEAR1310 + /* Accessible from only one master */ + SPEAR1310_DMA_MASTER_JPEG = 1, + + /* Accessible from both 0 & 1 */ + SPEAR1310_DMA_MASTER_I2S = 0, + SPEAR1310_DMA_MASTER_UART1 = 0, + SPEAR1310_DMA_MASTER_UART2 = 0, + SPEAR1310_DMA_MASTER_UART3 = 0, + SPEAR1310_DMA_MASTER_UART4 = 0, + SPEAR1310_DMA_MASTER_UART5 = 0, + SPEAR1310_DMA_MASTER_I2C1 = 0, + SPEAR1310_DMA_MASTER_I2C2 = 0, + SPEAR1310_DMA_MASTER_I2C3 = 0, + SPEAR1310_DMA_MASTER_I2C4 = 0, + SPEAR1310_DMA_MASTER_I2C5 = 0, + SPEAR1310_DMA_MASTER_I2C6 = 0, + SPEAR1310_DMA_MASTER_I2C7 = 0, + SPEAR1310_DMA_MASTER_SSP1 = 0, +#endif + +#ifdef CONFIG_MACH_SPEAR1340 + /* Accessible from only one master */ + SPEAR1340_DMA_MASTER_I2S_PLAY = 1, + SPEAR1340_DMA_MASTER_I2S_REC = 1, + SPEAR1340_DMA_MASTER_I2C1 = 1, + SPEAR1340_DMA_MASTER_UART1 = 1, + + /* following are accessible from both master 0 & 1 */ + SPEAR1340_DMA_MASTER_SPDIF = 0, + SPEAR1340_DMA_MASTER_CAM = 1, + SPEAR1340_DMA_MASTER_VIDEO_IN = 0, + SPEAR1340_DMA_MASTER_MALI = 0, +#endif +}; + +enum request_id { + DMA_REQ_ADC = 0, + DMA_REQ_SSP0_TX = 4, + DMA_REQ_SSP0_RX = 5, + DMA_REQ_UART0_TX = 6, + DMA_REQ_UART0_RX = 7, + DMA_REQ_I2C0_TX = 8, + DMA_REQ_I2C0_RX = 9, + +#ifdef CONFIG_MACH_SPEAR1310 + SPEAR1310_DMA_REQ_FROM_JPEG = 2, + SPEAR1310_DMA_REQ_TO_JPEG = 3, + SPEAR1310_DMA_REQ_I2S_TX = 10, + SPEAR1310_DMA_REQ_I2S_RX = 11, + + SPEAR1310_DMA_REQ_I2C1_RX = 0, + SPEAR1310_DMA_REQ_I2C1_TX = 1, + SPEAR1310_DMA_REQ_I2C2_RX = 2, + SPEAR1310_DMA_REQ_I2C2_TX = 3, + SPEAR1310_DMA_REQ_I2C3_RX = 4, + SPEAR1310_DMA_REQ_I2C3_TX = 5, + SPEAR1310_DMA_REQ_I2C4_RX = 6, + SPEAR1310_DMA_REQ_I2C4_TX = 7, + SPEAR1310_DMA_REQ_I2C5_RX = 8, + SPEAR1310_DMA_REQ_I2C5_TX = 9, + SPEAR1310_DMA_REQ_I2C6_RX = 10, + SPEAR1310_DMA_REQ_I2C6_TX = 11, + SPEAR1310_DMA_REQ_UART1_RX = 12, + SPEAR1310_DMA_REQ_UART1_TX = 13, + SPEAR1310_DMA_REQ_UART2_RX = 14, + SPEAR1310_DMA_REQ_UART2_TX = 15, + SPEAR1310_DMA_REQ_UART5_RX = 16, + SPEAR1310_DMA_REQ_UART5_TX = 17, + SPEAR1310_DMA_REQ_SSP1_RX = 18, + SPEAR1310_DMA_REQ_SSP1_TX = 19, + SPEAR1310_DMA_REQ_I2C7_RX = 20, + SPEAR1310_DMA_REQ_I2C7_TX = 21, + SPEAR1310_DMA_REQ_UART3_RX = 28, + SPEAR1310_DMA_REQ_UART3_TX = 29, + SPEAR1310_DMA_REQ_UART4_RX = 30, + SPEAR1310_DMA_REQ_UART4_TX = 31, +#endif + +#ifdef CONFIG_MACH_SPEAR1340 + SPEAR1340_DMA_REQ_SPDIF_TX = 2, + SPEAR1340_DMA_REQ_SPDIF_RX = 3, + SPEAR1340_DMA_REQ_I2S_TX = 10, + SPEAR1340_DMA_REQ_I2S_RX = 11, + SPEAR1340_DMA_REQ_UART1_TX = 12, + SPEAR1340_DMA_REQ_UART1_RX = 13, + SPEAR1340_DMA_REQ_I2C1_TX = 14, + SPEAR1340_DMA_REQ_I2C1_RX = 15, + SPEAR1340_DMA_REQ_CAM0_EVEN = 0, + SPEAR1340_DMA_REQ_CAM0_ODD = 1, + SPEAR1340_DMA_REQ_CAM1_EVEN = 2, + SPEAR1340_DMA_REQ_CAM1_ODD = 3, + SPEAR1340_DMA_REQ_CAM2_EVEN = 4, + SPEAR1340_DMA_REQ_CAM2_ODD = 5, + SPEAR1340_DMA_REQ_CAM3_EVEN = 6, + SPEAR1340_DMA_REQ_CAM3_ODD = 7, +#endif +}; + +#endif /* __MACH_DMA_H */ diff --git a/arch/arm/mach-spear13xx/include/mach/generic.h b/arch/arm/mach-spear13xx/include/mach/generic.h new file mode 100644 index 000000000000..6d8c45b9f298 --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/generic.h @@ -0,0 +1,49 @@ +/* + * arch/arm/mach-spear13xx/include/mach/generic.h + * + * spear13xx machine family generic header file + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MACH_GENERIC_H +#define __MACH_GENERIC_H + +#include <linux/dmaengine.h> +#include <asm/mach/time.h> + +/* Add spear13xx structure declarations here */ +extern struct sys_timer spear13xx_timer; +extern struct pl022_ssp_controller pl022_plat_data; +extern struct dw_dma_platform_data dmac_plat_data; +extern struct dw_dma_slave cf_dma_priv; +extern struct dw_dma_slave nand_read_dma_priv; +extern struct dw_dma_slave nand_write_dma_priv; + +/* Add spear13xx family function declarations here */ +void __init spear_setup_of_timer(void); +void __init spear13xx_map_io(void); +void __init spear13xx_dt_init_irq(void); +void __init spear13xx_l2x0_init(void); +bool dw_dma_filter(struct dma_chan *chan, void *slave); +void spear_restart(char, const char *); +void spear13xx_secondary_startup(void); + +#ifdef CONFIG_MACH_SPEAR1310 +void __init spear1310_clk_init(void); +#else +static inline void spear1310_clk_init(void) {} +#endif + +#ifdef CONFIG_MACH_SPEAR1340 +void __init spear1340_clk_init(void); +#else +static inline void spear1340_clk_init(void) {} +#endif + +#endif /* __MACH_GENERIC_H */ diff --git a/arch/arm/mach-spear13xx/include/mach/gpio.h b/arch/arm/mach-spear13xx/include/mach/gpio.h new file mode 100644 index 000000000000..cd6f4f86a56b --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/gpio.h @@ -0,0 +1,19 @@ +/* + * arch/arm/mach-spear13xx/include/mach/gpio.h + * + * GPIO macros for SPEAr13xx machine family + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MACH_GPIO_H +#define __MACH_GPIO_H + +#include <plat/gpio.h> + +#endif /* __MACH_GPIO_H */ diff --git a/arch/arm/mach-spear13xx/include/mach/hardware.h b/arch/arm/mach-spear13xx/include/mach/hardware.h new file mode 100644 index 000000000000..40a8c178f10d --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/hardware.h @@ -0,0 +1 @@ +/* empty */ diff --git a/arch/arm/mach-spear13xx/include/mach/irqs.h b/arch/arm/mach-spear13xx/include/mach/irqs.h new file mode 100644 index 000000000000..f542a24aa5f2 --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/irqs.h @@ -0,0 +1,20 @@ +/* + * arch/arm/mach-spear13xx/include/mach/irqs.h + * + * IRQ helper macros for spear13xx machine family + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MACH_IRQS_H +#define __MACH_IRQS_H + +#define IRQ_GIC_END 160 +#define NR_IRQS IRQ_GIC_END + +#endif /* __MACH_IRQS_H */ diff --git a/arch/arm/mach-spear13xx/include/mach/spear.h b/arch/arm/mach-spear13xx/include/mach/spear.h new file mode 100644 index 000000000000..30c57ef72686 --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/spear.h @@ -0,0 +1,62 @@ +/* + * arch/arm/mach-spear13xx/include/mach/spear.h + * + * spear13xx Machine family specific definition + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MACH_SPEAR13XX_H +#define __MACH_SPEAR13XX_H + +#include <asm/memory.h> + +#define PERIP_GRP2_BASE UL(0xB3000000) +#define VA_PERIP_GRP2_BASE UL(0xFE000000) +#define MCIF_SDHCI_BASE UL(0xB3000000) +#define SYSRAM0_BASE UL(0xB3800000) +#define VA_SYSRAM0_BASE UL(0xFE800000) +#define SYS_LOCATION (VA_SYSRAM0_BASE + 0x600) + +#define PERIP_GRP1_BASE UL(0xE0000000) +#define VA_PERIP_GRP1_BASE UL(0xFD000000) +#define UART_BASE UL(0xE0000000) +#define VA_UART_BASE UL(0xFD000000) +#define SSP_BASE UL(0xE0100000) +#define MISC_BASE UL(0xE0700000) +#define VA_MISC_BASE IOMEM(UL(0xFD700000)) + +#define A9SM_AND_MPMC_BASE UL(0xEC000000) +#define VA_A9SM_AND_MPMC_BASE UL(0xFC000000) + +/* A9SM peripheral offsets */ +#define A9SM_PERIP_BASE UL(0xEC800000) +#define VA_A9SM_PERIP_BASE UL(0xFC800000) +#define VA_SCU_BASE (VA_A9SM_PERIP_BASE + 0x00) + +#define L2CC_BASE UL(0xED000000) +#define VA_L2CC_BASE IOMEM(UL(0xFB000000)) + +/* others */ +#define DMAC0_BASE UL(0xEA800000) +#define DMAC1_BASE UL(0xEB000000) +#define MCIF_CF_BASE UL(0xB2800000) + +/* Devices present in SPEAr1310 */ +#ifdef CONFIG_MACH_SPEAR1310 +#define SPEAR1310_RAS_GRP1_BASE UL(0xD8000000) +#define VA_SPEAR1310_RAS_GRP1_BASE UL(0xFA000000) +#define SPEAR1310_RAS_BASE UL(0xD8400000) +#define VA_SPEAR1310_RAS_BASE IOMEM(UL(0xFA400000)) +#endif /* CONFIG_MACH_SPEAR1310 */ + +/* Debug uart for linux, will be used for debug and uncompress messages */ +#define SPEAR_DBG_UART_BASE UART_BASE +#define VA_SPEAR_DBG_UART_BASE VA_UART_BASE + +#endif /* __MACH_SPEAR13XX_H */ diff --git a/arch/arm/mach-spear13xx/include/mach/spear1310_misc_regs.h b/arch/arm/mach-spear13xx/include/mach/spear1310_misc_regs.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/spear1310_misc_regs.h diff --git a/arch/arm/mach-spear13xx/include/mach/spear1340_misc_regs.h b/arch/arm/mach-spear13xx/include/mach/spear1340_misc_regs.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/spear1340_misc_regs.h diff --git a/arch/arm/mach-spear13xx/include/mach/timex.h b/arch/arm/mach-spear13xx/include/mach/timex.h new file mode 100644 index 000000000000..31af3e8d976e --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/timex.h @@ -0,0 +1,19 @@ +/* + * arch/arm/mach-spear3xx/include/mach/timex.h + * + * SPEAr3XX machine family specific timex definitions + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MACH_TIMEX_H +#define __MACH_TIMEX_H + +#include <plat/timex.h> + +#endif /* __MACH_TIMEX_H */ diff --git a/arch/arm/mach-spear13xx/include/mach/uncompress.h b/arch/arm/mach-spear13xx/include/mach/uncompress.h new file mode 100644 index 000000000000..c7840896ae6e --- /dev/null +++ b/arch/arm/mach-spear13xx/include/mach/uncompress.h @@ -0,0 +1,19 @@ +/* + * arch/arm/mach-spear13xx/include/mach/uncompress.h + * + * Serial port stubs for kernel decompress status messages + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __MACH_UNCOMPRESS_H +#define __MACH_UNCOMPRESS_H + +#include <plat/uncompress.h> + +#endif /* __MACH_UNCOMPRESS_H */ diff --git a/arch/arm/mach-spear13xx/platsmp.c b/arch/arm/mach-spear13xx/platsmp.c new file mode 100644 index 000000000000..f5d07f2663d7 --- /dev/null +++ b/arch/arm/mach-spear13xx/platsmp.c @@ -0,0 +1,127 @@ +/* + * arch/arm/mach-spear13xx/platsmp.c + * + * based upon linux/arch/arm/mach-realview/platsmp.c + * + * Copyright (C) 2012 ST Microelectronics Ltd. + * Shiraz Hashim <shiraz.hashim@st.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/delay.h> +#include <linux/jiffies.h> +#include <linux/io.h> +#include <linux/smp.h> +#include <asm/cacheflush.h> +#include <asm/hardware/gic.h> +#include <asm/smp_scu.h> +#include <mach/spear.h> + +/* + * control for which core is the next to come out of the secondary + * boot "holding pen" + */ +volatile int __cpuinitdata pen_release = -1; +static DEFINE_SPINLOCK(boot_lock); + +static void __iomem *scu_base = IOMEM(VA_SCU_BASE); +extern void spear13xx_secondary_startup(void); + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); + + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + pen_release = -1; + smp_wmb(); + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + + /* + * set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* + * The secondary processor is waiting to be released from + * the holding pen - release it, then wait for it to flag + * that it has been released by resetting pen_release. + * + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ + pen_release = cpu; + flush_cache_all(); + outer_flush_all(); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + smp_rmb(); + if (pen_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return pen_release != -1 ? -ENOSYS : 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +void __init smp_init_cpus(void) +{ + unsigned int i, ncores = scu_get_core_count(scu_base); + + if (ncores > nr_cpu_ids) { + pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", + ncores, nr_cpu_ids); + ncores = nr_cpu_ids; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} + +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + + scu_enable(scu_base); + + /* + * Write the address of secondary startup into the system-wide location + * (presently it is in SRAM). The BootMonitor waits until it receives a + * soft interrupt, and then the secondary CPU branches to this address. + */ + __raw_writel(virt_to_phys(spear13xx_secondary_startup), SYS_LOCATION); +} diff --git a/arch/arm/mach-spear13xx/spear1310.c b/arch/arm/mach-spear13xx/spear1310.c new file mode 100644 index 000000000000..fefd15b2f380 --- /dev/null +++ b/arch/arm/mach-spear13xx/spear1310.c @@ -0,0 +1,88 @@ +/* + * arch/arm/mach-spear13xx/spear1310.c + * + * SPEAr1310 machine source file + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) "SPEAr1310: " fmt + +#include <linux/amba/pl022.h> +#include <linux/of_platform.h> +#include <asm/hardware/gic.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <mach/generic.h> +#include <mach/spear.h> + +/* Base addresses */ +#define SPEAR1310_SSP1_BASE UL(0x5D400000) +#define SPEAR1310_SATA0_BASE UL(0xB1000000) +#define SPEAR1310_SATA1_BASE UL(0xB1800000) +#define SPEAR1310_SATA2_BASE UL(0xB4000000) + +/* ssp device registration */ +static struct pl022_ssp_controller ssp1_plat_data = { + .bus_id = 0, + .enable_dma = 0, + .num_chipselect = 3, +}; + +/* Add SPEAr1310 auxdata to pass platform data */ +static struct of_dev_auxdata spear1310_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arasan,cf-spear1340", MCIF_CF_BASE, NULL, &cf_dma_priv), + OF_DEV_AUXDATA("snps,dma-spear1340", DMAC0_BASE, NULL, &dmac_plat_data), + OF_DEV_AUXDATA("snps,dma-spear1340", DMAC1_BASE, NULL, &dmac_plat_data), + OF_DEV_AUXDATA("arm,pl022", SSP_BASE, NULL, &pl022_plat_data), + + OF_DEV_AUXDATA("arm,pl022", SPEAR1310_SSP1_BASE, NULL, &ssp1_plat_data), + {} +}; + +static void __init spear1310_dt_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, + spear1310_auxdata_lookup, NULL); +} + +static const char * const spear1310_dt_board_compat[] = { + "st,spear1310", + "st,spear1310-evb", + NULL, +}; + +/* + * Following will create 16MB static virtual/physical mappings + * PHYSICAL VIRTUAL + * 0xD8000000 0xFA000000 + */ +struct map_desc spear1310_io_desc[] __initdata = { + { + .virtual = VA_SPEAR1310_RAS_GRP1_BASE, + .pfn = __phys_to_pfn(SPEAR1310_RAS_GRP1_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, +}; + +static void __init spear1310_map_io(void) +{ + iotable_init(spear1310_io_desc, ARRAY_SIZE(spear1310_io_desc)); + spear13xx_map_io(); +} + +DT_MACHINE_START(SPEAR1310_DT, "ST SPEAr1310 SoC with Flattened Device Tree") + .map_io = spear1310_map_io, + .init_irq = spear13xx_dt_init_irq, + .handle_irq = gic_handle_irq, + .timer = &spear13xx_timer, + .init_machine = spear1310_dt_init, + .restart = spear_restart, + .dt_compat = spear1310_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-spear13xx/spear1340.c b/arch/arm/mach-spear13xx/spear1340.c new file mode 100644 index 000000000000..ee38cbc56869 --- /dev/null +++ b/arch/arm/mach-spear13xx/spear1340.c @@ -0,0 +1,192 @@ +/* + * arch/arm/mach-spear13xx/spear1340.c + * + * SPEAr1340 machine source file + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) "SPEAr1340: " fmt + +#include <linux/ahci_platform.h> +#include <linux/amba/serial.h> +#include <linux/delay.h> +#include <linux/dw_dmac.h> +#include <linux/of_platform.h> +#include <asm/hardware/gic.h> +#include <asm/mach/arch.h> +#include <mach/dma.h> +#include <mach/generic.h> +#include <mach/spear.h> + +/* Base addresses */ +#define SPEAR1340_SATA_BASE UL(0xB1000000) +#define SPEAR1340_UART1_BASE UL(0xB4100000) + +/* Power Management Registers */ +#define SPEAR1340_PCM_CFG (VA_MISC_BASE + 0x100) +#define SPEAR1340_PCM_WKUP_CFG (VA_MISC_BASE + 0x104) +#define SPEAR1340_SWITCH_CTR (VA_MISC_BASE + 0x108) + +#define SPEAR1340_PERIP1_SW_RST (VA_MISC_BASE + 0x318) +#define SPEAR1340_PERIP2_SW_RST (VA_MISC_BASE + 0x31C) +#define SPEAR1340_PERIP3_SW_RST (VA_MISC_BASE + 0x320) + +/* PCIE - SATA configuration registers */ +#define SPEAR1340_PCIE_SATA_CFG (VA_MISC_BASE + 0x424) + /* PCIE CFG MASks */ + #define SPEAR1340_PCIE_CFG_DEVICE_PRESENT (1 << 11) + #define SPEAR1340_PCIE_CFG_POWERUP_RESET (1 << 10) + #define SPEAR1340_PCIE_CFG_CORE_CLK_EN (1 << 9) + #define SPEAR1340_PCIE_CFG_AUX_CLK_EN (1 << 8) + #define SPEAR1340_SATA_CFG_TX_CLK_EN (1 << 4) + #define SPEAR1340_SATA_CFG_RX_CLK_EN (1 << 3) + #define SPEAR1340_SATA_CFG_POWERUP_RESET (1 << 2) + #define SPEAR1340_SATA_CFG_PM_CLK_EN (1 << 1) + #define SPEAR1340_PCIE_SATA_SEL_PCIE (0) + #define SPEAR1340_PCIE_SATA_SEL_SATA (1) + #define SPEAR1340_SATA_PCIE_CFG_MASK 0xF1F + #define SPEAR1340_PCIE_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_PCIE | \ + SPEAR1340_PCIE_CFG_AUX_CLK_EN | \ + SPEAR1340_PCIE_CFG_CORE_CLK_EN | \ + SPEAR1340_PCIE_CFG_POWERUP_RESET | \ + SPEAR1340_PCIE_CFG_DEVICE_PRESENT) + #define SPEAR1340_SATA_CFG_VAL (SPEAR1340_PCIE_SATA_SEL_SATA | \ + SPEAR1340_SATA_CFG_PM_CLK_EN | \ + SPEAR1340_SATA_CFG_POWERUP_RESET | \ + SPEAR1340_SATA_CFG_RX_CLK_EN | \ + SPEAR1340_SATA_CFG_TX_CLK_EN) + +#define SPEAR1340_PCIE_MIPHY_CFG (VA_MISC_BASE + 0x428) + #define SPEAR1340_MIPHY_OSC_BYPASS_EXT (1 << 31) + #define SPEAR1340_MIPHY_CLK_REF_DIV2 (1 << 27) + #define SPEAR1340_MIPHY_CLK_REF_DIV4 (2 << 27) + #define SPEAR1340_MIPHY_CLK_REF_DIV8 (3 << 27) + #define SPEAR1340_MIPHY_PLL_RATIO_TOP(x) (x << 0) + #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA \ + (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ + SPEAR1340_MIPHY_CLK_REF_DIV2 | \ + SPEAR1340_MIPHY_PLL_RATIO_TOP(60)) + #define SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK \ + (SPEAR1340_MIPHY_PLL_RATIO_TOP(120)) + #define SPEAR1340_PCIE_SATA_MIPHY_CFG_PCIE \ + (SPEAR1340_MIPHY_OSC_BYPASS_EXT | \ + SPEAR1340_MIPHY_PLL_RATIO_TOP(25)) + +static struct dw_dma_slave uart1_dma_param[] = { + { + /* Tx */ + .cfg_hi = DWC_CFGH_DST_PER(SPEAR1340_DMA_REQ_UART1_TX), + .cfg_lo = 0, + .src_master = DMA_MASTER_MEMORY, + .dst_master = SPEAR1340_DMA_MASTER_UART1, + }, { + /* Rx */ + .cfg_hi = DWC_CFGH_SRC_PER(SPEAR1340_DMA_REQ_UART1_RX), + .cfg_lo = 0, + .src_master = SPEAR1340_DMA_MASTER_UART1, + .dst_master = DMA_MASTER_MEMORY, + } +}; + +static struct amba_pl011_data uart1_data = { + .dma_filter = dw_dma_filter, + .dma_tx_param = &uart1_dma_param[0], + .dma_rx_param = &uart1_dma_param[1], +}; + +/* SATA device registration */ +static int sata_miphy_init(struct device *dev, void __iomem *addr) +{ + writel(SPEAR1340_SATA_CFG_VAL, SPEAR1340_PCIE_SATA_CFG); + writel(SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK, + SPEAR1340_PCIE_MIPHY_CFG); + /* Switch on sata power domain */ + writel((readl(SPEAR1340_PCM_CFG) | (0x800)), SPEAR1340_PCM_CFG); + msleep(20); + /* Disable PCIE SATA Controller reset */ + writel((readl(SPEAR1340_PERIP1_SW_RST) & (~0x1000)), + SPEAR1340_PERIP1_SW_RST); + msleep(20); + + return 0; +} + +void sata_miphy_exit(struct device *dev) +{ + writel(0, SPEAR1340_PCIE_SATA_CFG); + writel(0, SPEAR1340_PCIE_MIPHY_CFG); + + /* Enable PCIE SATA Controller reset */ + writel((readl(SPEAR1340_PERIP1_SW_RST) | (0x1000)), + SPEAR1340_PERIP1_SW_RST); + msleep(20); + /* Switch off sata power domain */ + writel((readl(SPEAR1340_PCM_CFG) & (~0x800)), SPEAR1340_PCM_CFG); + msleep(20); +} + +int sata_suspend(struct device *dev) +{ + if (dev->power.power_state.event == PM_EVENT_FREEZE) + return 0; + + sata_miphy_exit(dev); + + return 0; +} + +int sata_resume(struct device *dev) +{ + if (dev->power.power_state.event == PM_EVENT_THAW) + return 0; + + return sata_miphy_init(dev, NULL); +} + +static struct ahci_platform_data sata_pdata = { + .init = sata_miphy_init, + .exit = sata_miphy_exit, + .suspend = sata_suspend, + .resume = sata_resume, +}; + +/* Add SPEAr1340 auxdata to pass platform data */ +static struct of_dev_auxdata spear1340_auxdata_lookup[] __initdata = { + OF_DEV_AUXDATA("arasan,cf-spear1340", MCIF_CF_BASE, NULL, &cf_dma_priv), + OF_DEV_AUXDATA("snps,dma-spear1340", DMAC0_BASE, NULL, &dmac_plat_data), + OF_DEV_AUXDATA("snps,dma-spear1340", DMAC1_BASE, NULL, &dmac_plat_data), + OF_DEV_AUXDATA("arm,pl022", SSP_BASE, NULL, &pl022_plat_data), + + OF_DEV_AUXDATA("snps,spear-ahci", SPEAR1340_SATA_BASE, NULL, + &sata_pdata), + OF_DEV_AUXDATA("arm,pl011", SPEAR1340_UART1_BASE, NULL, &uart1_data), + {} +}; + +static void __init spear1340_dt_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, + spear1340_auxdata_lookup, NULL); +} + +static const char * const spear1340_dt_board_compat[] = { + "st,spear1340", + "st,spear1340-evb", + NULL, +}; + +DT_MACHINE_START(SPEAR1340_DT, "ST SPEAr1340 SoC with Flattened Device Tree") + .map_io = spear13xx_map_io, + .init_irq = spear13xx_dt_init_irq, + .handle_irq = gic_handle_irq, + .timer = &spear13xx_timer, + .init_machine = spear1340_dt_init, + .restart = spear_restart, + .dt_compat = spear1340_dt_board_compat, +MACHINE_END diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c new file mode 100644 index 000000000000..50b349ae863d --- /dev/null +++ b/arch/arm/mach-spear13xx/spear13xx.c @@ -0,0 +1,197 @@ +/* + * arch/arm/mach-spear13xx/spear13xx.c + * + * SPEAr13XX machines common source file + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) "SPEAr13xx: " fmt + +#include <linux/amba/pl022.h> +#include <linux/clk.h> +#include <linux/dw_dmac.h> +#include <linux/err.h> +#include <linux/of_irq.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/hardware/gic.h> +#include <asm/mach/map.h> +#include <asm/smp_twd.h> +#include <mach/dma.h> +#include <mach/generic.h> +#include <mach/spear.h> + +/* common dw_dma filter routine to be used by peripherals */ +bool dw_dma_filter(struct dma_chan *chan, void *slave) +{ + struct dw_dma_slave *dws = (struct dw_dma_slave *)slave; + + if (chan->device->dev == dws->dma_dev) { + chan->private = slave; + return true; + } else { + return false; + } +} + +/* ssp device registration */ +static struct dw_dma_slave ssp_dma_param[] = { + { + /* Tx */ + .cfg_hi = DWC_CFGH_DST_PER(DMA_REQ_SSP0_TX), + .cfg_lo = 0, + .src_master = DMA_MASTER_MEMORY, + .dst_master = DMA_MASTER_SSP0, + }, { + /* Rx */ + .cfg_hi = DWC_CFGH_SRC_PER(DMA_REQ_SSP0_RX), + .cfg_lo = 0, + .src_master = DMA_MASTER_SSP0, + .dst_master = DMA_MASTER_MEMORY, + } +}; + +struct pl022_ssp_controller pl022_plat_data = { + .bus_id = 0, + .enable_dma = 1, + .dma_filter = dw_dma_filter, + .dma_rx_param = &ssp_dma_param[1], + .dma_tx_param = &ssp_dma_param[0], + .num_chipselect = 3, +}; + +/* CF device registration */ +struct dw_dma_slave cf_dma_priv = { + .cfg_hi = 0, + .cfg_lo = 0, + .src_master = 0, + .dst_master = 0, +}; + +/* dmac device registeration */ +struct dw_dma_platform_data dmac_plat_data = { + .nr_channels = 8, + .chan_allocation_order = CHAN_ALLOCATION_DESCENDING, + .chan_priority = CHAN_PRIORITY_DESCENDING, +}; + +void __init spear13xx_l2x0_init(void) +{ + /* + * 512KB (64KB/way), 8-way associativity, parity supported + * + * FIXME: 9th bit, of Auxillary Controller register must be set + * for some spear13xx devices for stable L2 operation. + * + * Enable Early BRESP, L2 prefetch for Instruction and Data, + * write alloc and 'Full line of zero' options + * + */ + + writel_relaxed(0x06, VA_L2CC_BASE + L2X0_PREFETCH_CTRL); + + /* + * Program following latencies in order to make + * SPEAr1340 work at 600 MHz + */ + writel_relaxed(0x221, VA_L2CC_BASE + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(0x441, VA_L2CC_BASE + L2X0_DATA_LATENCY_CTRL); + l2x0_init(VA_L2CC_BASE, 0x70A60001, 0xfe00ffff); +} + +/* + * Following will create 16MB static virtual/physical mappings + * PHYSICAL VIRTUAL + * 0xB3000000 0xFE000000 + * 0xE0000000 0xFD000000 + * 0xEC000000 0xFC000000 + * 0xED000000 0xFB000000 + */ +struct map_desc spear13xx_io_desc[] __initdata = { + { + .virtual = VA_PERIP_GRP2_BASE, + .pfn = __phys_to_pfn(PERIP_GRP2_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = VA_PERIP_GRP1_BASE, + .pfn = __phys_to_pfn(PERIP_GRP1_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = VA_A9SM_AND_MPMC_BASE, + .pfn = __phys_to_pfn(A9SM_AND_MPMC_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, { + .virtual = (unsigned long)VA_L2CC_BASE, + .pfn = __phys_to_pfn(L2CC_BASE), + .length = SZ_4K, + .type = MT_DEVICE + }, +}; + +/* This will create static memory mapping for selected devices */ +void __init spear13xx_map_io(void) +{ + iotable_init(spear13xx_io_desc, ARRAY_SIZE(spear13xx_io_desc)); +} + +static void __init spear13xx_clk_init(void) +{ + if (of_machine_is_compatible("st,spear1310")) + spear1310_clk_init(); + else if (of_machine_is_compatible("st,spear1340")) + spear1340_clk_init(); + else + pr_err("%s: Unknown machine\n", __func__); +} + +static void __init spear13xx_timer_init(void) +{ + char pclk_name[] = "osc_24m_clk"; + struct clk *gpt_clk, *pclk; + + spear13xx_clk_init(); + + /* get the system timer clock */ + gpt_clk = clk_get_sys("gpt0", NULL); + if (IS_ERR(gpt_clk)) { + pr_err("%s:couldn't get clk for gpt\n", __func__); + BUG(); + } + + /* get the suitable parent clock for timer*/ + pclk = clk_get(NULL, pclk_name); + if (IS_ERR(pclk)) { + pr_err("%s:couldn't get %s as parent for gpt\n", __func__, + pclk_name); + BUG(); + } + + clk_set_parent(gpt_clk, pclk); + clk_put(gpt_clk); + clk_put(pclk); + + spear_setup_of_timer(); + twd_local_timer_of_register(); +} + +struct sys_timer spear13xx_timer = { + .init = spear13xx_timer_init, +}; + +static const struct of_device_id gic_of_match[] __initconst = { + { .compatible = "arm,cortex-a9-gic", .data = gic_of_init }, + { /* Sentinel */ } +}; + +void __init spear13xx_dt_init_irq(void) +{ + of_irq_init(gic_of_match); +} diff --git a/arch/arm/mach-spear3xx/Makefile b/arch/arm/mach-spear3xx/Makefile index 17b5d83cf2d5..8d12faa178fd 100644 --- a/arch/arm/mach-spear3xx/Makefile +++ b/arch/arm/mach-spear3xx/Makefile @@ -3,7 +3,7 @@ # # common files -obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx.o clock.o +obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx.o # spear300 specific files obj-$(CONFIG_MACH_SPEAR300) += spear300.o diff --git a/arch/arm/mach-spear3xx/clock.c b/arch/arm/mach-spear3xx/clock.c deleted file mode 100644 index cd6c11099083..000000000000 --- a/arch/arm/mach-spear3xx/clock.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * arch/arm/mach-spear3xx/clock.c - * - * SPEAr3xx machines clock framework source file - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/clkdev.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/of_platform.h> -#include <asm/mach-types.h> -#include <plat/clock.h> -#include <mach/misc_regs.h> -#include <mach/spear.h> - -#define PLL1_CTR (MISC_BASE + 0x008) -#define PLL1_FRQ (MISC_BASE + 0x00C) -#define PLL1_MOD (MISC_BASE + 0x010) -#define PLL2_CTR (MISC_BASE + 0x014) -/* PLL_CTR register masks */ -#define PLL_ENABLE 2 -#define PLL_MODE_SHIFT 4 -#define PLL_MODE_MASK 0x3 -#define PLL_MODE_NORMAL 0 -#define PLL_MODE_FRACTION 1 -#define PLL_MODE_DITH_DSB 2 -#define PLL_MODE_DITH_SSB 3 - -#define PLL2_FRQ (MISC_BASE + 0x018) -/* PLL FRQ register masks */ -#define PLL_DIV_N_SHIFT 0 -#define PLL_DIV_N_MASK 0xFF -#define PLL_DIV_P_SHIFT 8 -#define PLL_DIV_P_MASK 0x7 -#define PLL_NORM_FDBK_M_SHIFT 24 -#define PLL_NORM_FDBK_M_MASK 0xFF -#define PLL_DITH_FDBK_M_SHIFT 16 -#define PLL_DITH_FDBK_M_MASK 0xFFFF - -#define PLL2_MOD (MISC_BASE + 0x01C) -#define PLL_CLK_CFG (MISC_BASE + 0x020) -#define CORE_CLK_CFG (MISC_BASE + 0x024) -/* CORE CLK CFG register masks */ -#define PLL_HCLK_RATIO_SHIFT 10 -#define PLL_HCLK_RATIO_MASK 0x3 -#define HCLK_PCLK_RATIO_SHIFT 8 -#define HCLK_PCLK_RATIO_MASK 0x3 - -#define PERIP_CLK_CFG (MISC_BASE + 0x028) -/* PERIP_CLK_CFG register masks */ -#define UART_CLK_SHIFT 4 -#define UART_CLK_MASK 0x1 -#define FIRDA_CLK_SHIFT 5 -#define FIRDA_CLK_MASK 0x3 -#define GPT0_CLK_SHIFT 8 -#define GPT1_CLK_SHIFT 11 -#define GPT2_CLK_SHIFT 12 -#define GPT_CLK_MASK 0x1 -#define AUX_CLK_PLL3_VAL 0 -#define AUX_CLK_PLL1_VAL 1 - -#define PERIP1_CLK_ENB (MISC_BASE + 0x02C) -/* PERIP1_CLK_ENB register masks */ -#define UART_CLK_ENB 3 -#define SSP_CLK_ENB 5 -#define I2C_CLK_ENB 7 -#define JPEG_CLK_ENB 8 -#define FIRDA_CLK_ENB 10 -#define GPT1_CLK_ENB 11 -#define GPT2_CLK_ENB 12 -#define ADC_CLK_ENB 15 -#define RTC_CLK_ENB 17 -#define GPIO_CLK_ENB 18 -#define DMA_CLK_ENB 19 -#define SMI_CLK_ENB 21 -#define GMAC_CLK_ENB 23 -#define USBD_CLK_ENB 24 -#define USBH_CLK_ENB 25 -#define C3_CLK_ENB 31 - -#define RAS_CLK_ENB (MISC_BASE + 0x034) - -#define PRSC1_CLK_CFG (MISC_BASE + 0x044) -#define PRSC2_CLK_CFG (MISC_BASE + 0x048) -#define PRSC3_CLK_CFG (MISC_BASE + 0x04C) -/* gpt synthesizer register masks */ -#define GPT_MSCALE_SHIFT 0 -#define GPT_MSCALE_MASK 0xFFF -#define GPT_NSCALE_SHIFT 12 -#define GPT_NSCALE_MASK 0xF - -#define AMEM_CLK_CFG (MISC_BASE + 0x050) -#define EXPI_CLK_CFG (MISC_BASE + 0x054) -#define CLCD_CLK_SYNT (MISC_BASE + 0x05C) -#define FIRDA_CLK_SYNT (MISC_BASE + 0x060) -#define UART_CLK_SYNT (MISC_BASE + 0x064) -#define GMAC_CLK_SYNT (MISC_BASE + 0x068) -#define RAS1_CLK_SYNT (MISC_BASE + 0x06C) -#define RAS2_CLK_SYNT (MISC_BASE + 0x070) -#define RAS3_CLK_SYNT (MISC_BASE + 0x074) -#define RAS4_CLK_SYNT (MISC_BASE + 0x078) -/* aux clk synthesiser register masks for irda to ras4 */ -#define AUX_SYNT_ENB 31 -#define AUX_EQ_SEL_SHIFT 30 -#define AUX_EQ_SEL_MASK 1 -#define AUX_EQ1_SEL 0 -#define AUX_EQ2_SEL 1 -#define AUX_XSCALE_SHIFT 16 -#define AUX_XSCALE_MASK 0xFFF -#define AUX_YSCALE_SHIFT 0 -#define AUX_YSCALE_MASK 0xFFF - -/* root clks */ -/* 32 KHz oscillator clock */ -static struct clk osc_32k_clk = { - .flags = ALWAYS_ENABLED, - .rate = 32000, -}; - -/* 24 MHz oscillator clock */ -static struct clk osc_24m_clk = { - .flags = ALWAYS_ENABLED, - .rate = 24000000, -}; - -/* clock derived from 32 KHz osc clk */ -/* rtc clock */ -static struct clk rtc_clk = { - .pclk = &osc_32k_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = RTC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from 24 MHz osc clk */ -/* pll masks structure */ -static struct pll_clk_masks pll1_masks = { - .mode_mask = PLL_MODE_MASK, - .mode_shift = PLL_MODE_SHIFT, - .norm_fdbk_m_mask = PLL_NORM_FDBK_M_MASK, - .norm_fdbk_m_shift = PLL_NORM_FDBK_M_SHIFT, - .dith_fdbk_m_mask = PLL_DITH_FDBK_M_MASK, - .dith_fdbk_m_shift = PLL_DITH_FDBK_M_SHIFT, - .div_p_mask = PLL_DIV_P_MASK, - .div_p_shift = PLL_DIV_P_SHIFT, - .div_n_mask = PLL_DIV_N_MASK, - .div_n_shift = PLL_DIV_N_SHIFT, -}; - -/* pll1 configuration structure */ -static struct pll_clk_config pll1_config = { - .mode_reg = PLL1_CTR, - .cfg_reg = PLL1_FRQ, - .masks = &pll1_masks, -}; - -/* pll rate configuration table, in ascending order of rates */ -struct pll_rate_tbl pll_rtbl[] = { - {.mode = 0, .m = 0x85, .n = 0x0C, .p = 0x1}, /* 266 MHz */ - {.mode = 0, .m = 0xA6, .n = 0x0C, .p = 0x1}, /* 332 MHz */ -}; - -/* PLL1 clock */ -static struct clk pll1_clk = { - .flags = ENABLED_ON_INIT, - .pclk = &osc_24m_clk, - .en_reg = PLL1_CTR, - .en_reg_bit = PLL_ENABLE, - .calc_rate = &pll_calc_rate, - .recalc = &pll_clk_recalc, - .set_rate = &pll_clk_set_rate, - .rate_config = {pll_rtbl, ARRAY_SIZE(pll_rtbl), 1}, - .private_data = &pll1_config, -}; - -/* PLL3 48 MHz clock */ -static struct clk pll3_48m_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_24m_clk, - .rate = 48000000, -}; - -/* watch dog timer clock */ -static struct clk wdt_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_24m_clk, - .recalc = &follow_parent, -}; - -/* clock derived from pll1 clk */ -/* cpu clock */ -static struct clk cpu_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .recalc = &follow_parent, -}; - -/* ahb masks structure */ -static struct bus_clk_masks ahb_masks = { - .mask = PLL_HCLK_RATIO_MASK, - .shift = PLL_HCLK_RATIO_SHIFT, -}; - -/* ahb configuration structure */ -static struct bus_clk_config ahb_config = { - .reg = CORE_CLK_CFG, - .masks = &ahb_masks, -}; - -/* ahb rate configuration table, in ascending order of rates */ -struct bus_rate_tbl bus_rtbl[] = { - {.div = 3}, /* == parent divided by 4 */ - {.div = 2}, /* == parent divided by 3 */ - {.div = 1}, /* == parent divided by 2 */ - {.div = 0}, /* == parent divided by 1 */ -}; - -/* ahb clock */ -static struct clk ahb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &ahb_config, -}; - -/* auxiliary synthesizers masks */ -static struct aux_clk_masks aux_masks = { - .eq_sel_mask = AUX_EQ_SEL_MASK, - .eq_sel_shift = AUX_EQ_SEL_SHIFT, - .eq1_mask = AUX_EQ1_SEL, - .eq2_mask = AUX_EQ2_SEL, - .xscale_sel_mask = AUX_XSCALE_MASK, - .xscale_sel_shift = AUX_XSCALE_SHIFT, - .yscale_sel_mask = AUX_YSCALE_MASK, - .yscale_sel_shift = AUX_YSCALE_SHIFT, -}; - -/* uart synth configurations */ -static struct aux_clk_config uart_synth_config = { - .synth_reg = UART_CLK_SYNT, - .masks = &aux_masks, -}; - -/* aux rate configuration table, in ascending order of rates */ -struct aux_rate_tbl aux_rtbl[] = { - /* For PLL1 = 332 MHz */ - {.xscale = 1, .yscale = 8, .eq = 1}, /* 41.5 MHz */ - {.xscale = 1, .yscale = 4, .eq = 1}, /* 83 MHz */ - {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ -}; - -/* uart synth clock */ -static struct clk uart_synth_clk = { - .en_reg = UART_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 1}, - .private_data = &uart_synth_config, -}; - -/* uart parents */ -static struct pclk_info uart_pclk_info[] = { - { - .pclk = &uart_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* uart parent select structure */ -static struct pclk_sel uart_pclk_sel = { - .pclk_info = uart_pclk_info, - .pclk_count = ARRAY_SIZE(uart_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = UART_CLK_MASK, -}; - -/* uart clock */ -static struct clk uart_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = UART_CLK_ENB, - .pclk_sel = &uart_pclk_sel, - .pclk_sel_shift = UART_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* firda configurations */ -static struct aux_clk_config firda_synth_config = { - .synth_reg = FIRDA_CLK_SYNT, - .masks = &aux_masks, -}; - -/* firda synth clock */ -static struct clk firda_synth_clk = { - .en_reg = FIRDA_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 1}, - .private_data = &firda_synth_config, -}; - -/* firda parents */ -static struct pclk_info firda_pclk_info[] = { - { - .pclk = &firda_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* firda parent select structure */ -static struct pclk_sel firda_pclk_sel = { - .pclk_info = firda_pclk_info, - .pclk_count = ARRAY_SIZE(firda_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = FIRDA_CLK_MASK, -}; - -/* firda clock */ -static struct clk firda_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = FIRDA_CLK_ENB, - .pclk_sel = &firda_pclk_sel, - .pclk_sel_shift = FIRDA_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt synthesizer masks */ -static struct gpt_clk_masks gpt_masks = { - .mscale_sel_mask = GPT_MSCALE_MASK, - .mscale_sel_shift = GPT_MSCALE_SHIFT, - .nscale_sel_mask = GPT_NSCALE_MASK, - .nscale_sel_shift = GPT_NSCALE_SHIFT, -}; - -/* gpt rate configuration table, in ascending order of rates */ -struct gpt_rate_tbl gpt_rtbl[] = { - /* For pll1 = 332 MHz */ - {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ - {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ - {.mscale = 1, .nscale = 0}, /* 83 MHz */ -}; - -/* gpt0 synth clk config*/ -static struct gpt_clk_config gpt0_synth_config = { - .synth_reg = PRSC1_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt0_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt0_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt0_pclk_info[] = { - { - .pclk = &gpt0_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt0_pclk_sel = { - .pclk_info = gpt0_pclk_info, - .pclk_count = ARRAY_SIZE(gpt0_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt0 timer clock */ -static struct clk gpt0_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt0_pclk_sel, - .pclk_sel_shift = GPT0_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt1 synth clk configurations */ -static struct gpt_clk_config gpt1_synth_config = { - .synth_reg = PRSC2_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt1 synth clock */ -static struct clk gpt1_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt1_synth_config, -}; - -static struct pclk_info gpt1_pclk_info[] = { - { - .pclk = &gpt1_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt1_pclk_sel = { - .pclk_info = gpt1_pclk_info, - .pclk_count = ARRAY_SIZE(gpt1_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt1 timer clock */ -static struct clk gpt1_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPT1_CLK_ENB, - .pclk_sel = &gpt1_pclk_sel, - .pclk_sel_shift = GPT1_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt2 synth clk configurations */ -static struct gpt_clk_config gpt2_synth_config = { - .synth_reg = PRSC3_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt1 synth clock */ -static struct clk gpt2_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt2_synth_config, -}; - -static struct pclk_info gpt2_pclk_info[] = { - { - .pclk = &gpt2_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt2_pclk_sel = { - .pclk_info = gpt2_pclk_info, - .pclk_count = ARRAY_SIZE(gpt2_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt2 timer clock */ -static struct clk gpt2_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPT2_CLK_ENB, - .pclk_sel = &gpt2_pclk_sel, - .pclk_sel_shift = GPT2_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* clock derived from pll3 clk */ -/* usbh clock */ -static struct clk usbh_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBH_CLK_ENB, - .recalc = &follow_parent, -}; - -/* usbd clock */ -static struct clk usbd_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBD_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from usbh clk */ -/* usbh0 clock */ -static struct clk usbh0_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &usbh_clk, - .recalc = &follow_parent, -}; - -/* usbh1 clock */ -static struct clk usbh1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &usbh_clk, - .recalc = &follow_parent, -}; - -/* clock derived from ahb clk */ -/* apb masks structure */ -static struct bus_clk_masks apb_masks = { - .mask = HCLK_PCLK_RATIO_MASK, - .shift = HCLK_PCLK_RATIO_SHIFT, -}; - -/* apb configuration structure */ -static struct bus_clk_config apb_config = { - .reg = CORE_CLK_CFG, - .masks = &apb_masks, -}; - -/* apb clock */ -static struct clk apb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &apb_config, -}; - -/* i2c clock */ -static struct clk i2c_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = I2C_CLK_ENB, - .recalc = &follow_parent, -}; - -/* dma clock */ -static struct clk dma_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = DMA_CLK_ENB, - .recalc = &follow_parent, -}; - -/* jpeg clock */ -static struct clk jpeg_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = JPEG_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gmac clock */ -static struct clk gmac_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GMAC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* smi clock */ -static struct clk smi_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SMI_CLK_ENB, - .recalc = &follow_parent, -}; - -/* c3 clock */ -static struct clk c3_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = C3_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from apb clk */ -/* adc clock */ -static struct clk adc_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = ADC_CLK_ENB, - .recalc = &follow_parent, -}; - -#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320) -/* emi clock */ -static struct clk emi_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; -#endif - -/* ssp clock */ -static struct clk ssp0_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gpio clock */ -static struct clk gpio_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPIO_CLK_ENB, - .recalc = &follow_parent, -}; - -static struct clk dummy_apb_pclk; - -#if defined(CONFIG_MACH_SPEAR300) || defined(CONFIG_MACH_SPEAR310) || \ - defined(CONFIG_MACH_SPEAR320) -/* fsmc clock */ -static struct clk fsmc_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; -#endif - -/* common clocks to spear310 and spear320 */ -#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320) -/* uart1 clock */ -static struct clk uart1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* uart2 clock */ -static struct clk uart2_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; -#endif /* CONFIG_MACH_SPEAR310 || CONFIG_MACH_SPEAR320 */ - -/* common clocks to spear300 and spear320 */ -#if defined(CONFIG_MACH_SPEAR300) || defined(CONFIG_MACH_SPEAR320) -/* clcd clock */ -static struct clk clcd_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll3_48m_clk, - .recalc = &follow_parent, -}; - -/* sdhci clock */ -static struct clk sdhci_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; -#endif /* CONFIG_MACH_SPEAR300 || CONFIG_MACH_SPEAR320 */ - -/* spear300 machine specific clock structures */ -#ifdef CONFIG_MACH_SPEAR300 -/* gpio1 clock */ -static struct clk gpio1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* keyboard clock */ -static struct clk kbd_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -#endif - -/* spear310 machine specific clock structures */ -#ifdef CONFIG_MACH_SPEAR310 -/* uart3 clock */ -static struct clk uart3_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* uart4 clock */ -static struct clk uart4_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* uart5 clock */ -static struct clk uart5_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; -#endif - -/* spear320 machine specific clock structures */ -#ifdef CONFIG_MACH_SPEAR320 -/* can0 clock */ -static struct clk can0_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* can1 clock */ -static struct clk can1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* i2c1 clock */ -static struct clk i2c1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .recalc = &follow_parent, -}; - -/* ssp1 clock */ -static struct clk ssp1_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* ssp2 clock */ -static struct clk ssp2_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* pwm clock */ -static struct clk pwm_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; -#endif - -/* array of all spear 3xx clock lookups */ -static struct clk_lookup spear_clk_lookups[] = { - CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk), - /* root clks */ - CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk), - CLKDEV_INIT(NULL, "osc_24m_clk", &osc_24m_clk), - /* clock derived from 32 KHz osc clk */ - CLKDEV_INIT("fc900000.rtc", NULL, &rtc_clk), - /* clock derived from 24 MHz osc clk */ - CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk), - CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk), - CLKDEV_INIT("fc880000.wdt", NULL, &wdt_clk), - /* clock derived from pll1 clk */ - CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk), - CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk), - CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk), - CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk), - CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk), - CLKDEV_INIT(NULL, "gpt1_synth_clk", &gpt1_synth_clk), - CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk), - CLKDEV_INIT("d0000000.serial", NULL, &uart_clk), - CLKDEV_INIT("firda", NULL, &firda_clk), - CLKDEV_INIT("gpt0", NULL, &gpt0_clk), - CLKDEV_INIT("gpt1", NULL, &gpt1_clk), - CLKDEV_INIT("gpt2", NULL, &gpt2_clk), - /* clock derived from pll3 clk */ - CLKDEV_INIT("designware_udc", NULL, &usbd_clk), - CLKDEV_INIT(NULL, "usbh_clk", &usbh_clk), - /* clock derived from usbh clk */ - CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk), - CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk), - /* clock derived from ahb clk */ - CLKDEV_INIT(NULL, "apb_clk", &apb_clk), - CLKDEV_INIT("d0180000.i2c", NULL, &i2c_clk), - CLKDEV_INIT("fc400000.dma", NULL, &dma_clk), - CLKDEV_INIT("jpeg", NULL, &jpeg_clk), - CLKDEV_INIT("e0800000.eth", NULL, &gmac_clk), - CLKDEV_INIT("fc000000.flash", NULL, &smi_clk), - CLKDEV_INIT("c3", NULL, &c3_clk), - /* clock derived from apb clk */ - CLKDEV_INIT("adc", NULL, &adc_clk), - CLKDEV_INIT("d0100000.spi", NULL, &ssp0_clk), - CLKDEV_INIT("fc980000.gpio", NULL, &gpio_clk), -}; - -/* array of all spear 300 clock lookups */ -#ifdef CONFIG_MACH_SPEAR300 -static struct clk_lookup spear300_clk_lookups[] = { - CLKDEV_INIT("60000000.clcd", NULL, &clcd_clk), - CLKDEV_INIT("94000000.flash", NULL, &fsmc_clk), - CLKDEV_INIT("a9000000.gpio", NULL, &gpio1_clk), - CLKDEV_INIT("a0000000.kbd", NULL, &kbd_clk), - CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk), -}; - -void __init spear300_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - for (i = 0; i < ARRAY_SIZE(spear300_clk_lookups); i++) - clk_register(&spear300_clk_lookups[i]); - - clk_init(); -} -#endif - -/* array of all spear 310 clock lookups */ -#ifdef CONFIG_MACH_SPEAR310 -static struct clk_lookup spear310_clk_lookups[] = { - CLKDEV_INIT("44000000.flash", NULL, &fsmc_clk), - CLKDEV_INIT(NULL, "emi", &emi_clk), - CLKDEV_INIT("b2000000.serial", NULL, &uart1_clk), - CLKDEV_INIT("b2080000.serial", NULL, &uart2_clk), - CLKDEV_INIT("b2100000.serial", NULL, &uart3_clk), - CLKDEV_INIT("b2180000.serial", NULL, &uart4_clk), - CLKDEV_INIT("b2200000.serial", NULL, &uart5_clk), -}; - -void __init spear310_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - for (i = 0; i < ARRAY_SIZE(spear310_clk_lookups); i++) - clk_register(&spear310_clk_lookups[i]); - - clk_init(); -} -#endif - -/* array of all spear 320 clock lookups */ -#ifdef CONFIG_MACH_SPEAR320 -static struct clk_lookup spear320_clk_lookups[] = { - CLKDEV_INIT("90000000.clcd", NULL, &clcd_clk), - CLKDEV_INIT("4c000000.flash", NULL, &fsmc_clk), - CLKDEV_INIT("a7000000.i2c", NULL, &i2c1_clk), - CLKDEV_INIT(NULL, "emi", &emi_clk), - CLKDEV_INIT("pwm", NULL, &pwm_clk), - CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk), - CLKDEV_INIT("c_can_platform.0", NULL, &can0_clk), - CLKDEV_INIT("c_can_platform.1", NULL, &can1_clk), - CLKDEV_INIT("a5000000.spi", NULL, &ssp1_clk), - CLKDEV_INIT("a6000000.spi", NULL, &ssp2_clk), - CLKDEV_INIT("a3000000.serial", NULL, &uart1_clk), - CLKDEV_INIT("a4000000.serial", NULL, &uart2_clk), -}; - -void __init spear320_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - for (i = 0; i < ARRAY_SIZE(spear320_clk_lookups); i++) - clk_register(&spear320_clk_lookups[i]); - - clk_init(); -} -#endif diff --git a/arch/arm/mach-spear3xx/include/mach/generic.h b/arch/arm/mach-spear3xx/include/mach/generic.h index bdb304551caf..4a95b9453c2a 100644 --- a/arch/arm/mach-spear3xx/include/mach/generic.h +++ b/arch/arm/mach-spear3xx/include/mach/generic.h @@ -27,28 +27,11 @@ extern struct pl022_ssp_controller pl022_plat_data; extern struct pl08x_platform_data pl080_plat_data; /* Add spear3xx family function declarations here */ -void __init spear_setup_timer(resource_size_t base, int irq); +void __init spear_setup_of_timer(void); +void __init spear3xx_clk_init(void); void __init spear3xx_map_io(void); void __init spear3xx_dt_init_irq(void); void spear_restart(char, const char *); -/* spear300 declarations */ -#ifdef CONFIG_MACH_SPEAR300 -void __init spear300_clk_init(void); - -#endif /* CONFIG_MACH_SPEAR300 */ - -/* spear310 declarations */ -#ifdef CONFIG_MACH_SPEAR310 -void __init spear310_clk_init(void); - -#endif /* CONFIG_MACH_SPEAR310 */ - -/* spear320 declarations */ -#ifdef CONFIG_MACH_SPEAR320 -void __init spear320_clk_init(void); - -#endif /* CONFIG_MACH_SPEAR320 */ - #endif /* __MACH_GENERIC_H */ diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h index 319620a1afb4..51bd62a0254c 100644 --- a/arch/arm/mach-spear3xx/include/mach/irqs.h +++ b/arch/arm/mach-spear3xx/include/mach/irqs.h @@ -16,7 +16,6 @@ /* FIXME: probe all these from DT */ #define SPEAR3XX_IRQ_INTRCOMM_RAS_ARM 1 -#define SPEAR3XX_IRQ_CPU_GPT1_1 2 #define SPEAR3XX_IRQ_GEN_RAS_1 28 #define SPEAR3XX_IRQ_GEN_RAS_2 29 #define SPEAR3XX_IRQ_GEN_RAS_3 30 diff --git a/arch/arm/mach-spear3xx/include/mach/misc_regs.h b/arch/arm/mach-spear3xx/include/mach/misc_regs.h index e0ab72e61507..18e2ac576f25 100644 --- a/arch/arm/mach-spear3xx/include/mach/misc_regs.h +++ b/arch/arm/mach-spear3xx/include/mach/misc_regs.h @@ -14,6 +14,8 @@ #ifndef __MACH_MISC_REGS_H #define __MACH_MISC_REGS_H +#include <mach/spear.h> + #define MISC_BASE IOMEM(VA_SPEAR3XX_ICM3_MISC_REG_BASE) #define DMA_CHN_CFG (MISC_BASE + 0x0A0) diff --git a/arch/arm/mach-spear3xx/include/mach/spear.h b/arch/arm/mach-spear3xx/include/mach/spear.h index 6d4dadc67633..51eb953148a9 100644 --- a/arch/arm/mach-spear3xx/include/mach/spear.h +++ b/arch/arm/mach-spear3xx/include/mach/spear.h @@ -26,7 +26,6 @@ /* ML1 - Multi Layer CPU Subsystem */ #define SPEAR3XX_ICM3_ML1_2_BASE UL(0xF0000000) #define VA_SPEAR6XX_ML_CPU_BASE UL(0xF0000000) -#define SPEAR3XX_CPU_TMR_BASE UL(0xF0000000) /* ICM3 - Basic Subsystem */ #define SPEAR3XX_ICM3_SMI_CTRL_BASE UL(0xFC000000) @@ -45,4 +44,17 @@ #define SPEAR_SYS_CTRL_BASE SPEAR3XX_ICM3_SYS_CTRL_BASE #define VA_SPEAR_SYS_CTRL_BASE VA_SPEAR3XX_ICM3_SYS_CTRL_BASE +/* SPEAr320 Macros */ +#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000) +#define VA_SPEAR320_SOC_CONFIG_BASE UL(0xFE000000) +#define SPEAR320_CONTROL_REG IOMEM(VA_SPEAR320_SOC_CONFIG_BASE) +#define SPEAR320_EXT_CTRL_REG IOMEM(VA_SPEAR320_SOC_CONFIG_BASE + 0x0018) + #define SPEAR320_UARTX_PCLK_MASK 0x1 + #define SPEAR320_UART2_PCLK_SHIFT 8 + #define SPEAR320_UART3_PCLK_SHIFT 9 + #define SPEAR320_UART4_PCLK_SHIFT 10 + #define SPEAR320_UART5_PCLK_SHIFT 11 + #define SPEAR320_UART6_PCLK_SHIFT 12 + #define SPEAR320_RS485_PCLK_SHIFT 13 + #endif /* __MACH_SPEAR3XX_H */ diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index f75fe25a620c..f74a05bdb829 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -337,7 +337,6 @@ static const char * const spear300_dt_board_compat[] = { static void __init spear300_map_io(void) { spear3xx_map_io(); - spear300_clk_init(); } DT_MACHINE_START(SPEAR300_DT, "ST SPEAr300 SoC with Flattened Device Tree") diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index f0842a58dc02..84dfb0900747 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -478,7 +478,6 @@ static const char * const spear310_dt_board_compat[] = { static void __init spear310_map_io(void) { spear3xx_map_io(); - spear310_clk_init(); } DT_MACHINE_START(SPEAR310_DT, "ST SPEAr310 SoC with Flattened Device Tree") diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index e8caeef50a5c..a88fa841d29d 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -27,7 +27,6 @@ #define SPEAR320_UART2_BASE UL(0xA4000000) #define SPEAR320_SSP0_BASE UL(0xA5000000) #define SPEAR320_SSP1_BASE UL(0xA6000000) -#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000) /* Interrupt registers offsets and masks */ #define SPEAR320_INT_STS_MASK_REG 0x04 @@ -481,10 +480,19 @@ static const char * const spear320_dt_board_compat[] = { NULL, }; +struct map_desc spear320_io_desc[] __initdata = { + { + .virtual = VA_SPEAR320_SOC_CONFIG_BASE, + .pfn = __phys_to_pfn(SPEAR320_SOC_CONFIG_BASE), + .length = SZ_16M, + .type = MT_DEVICE + }, +}; + static void __init spear320_map_io(void) { + iotable_init(spear320_io_desc, ARRAY_SIZE(spear320_io_desc)); spear3xx_map_io(); - spear320_clk_init(); } DT_MACHINE_START(SPEAR320_DT, "ST SPEAr320 SoC with Flattened Device Tree") diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c index 826ac20ef1e7..f22419ed74a8 100644 --- a/arch/arm/mach-spear3xx/spear3xx.c +++ b/arch/arm/mach-spear3xx/spear3xx.c @@ -90,6 +90,8 @@ static void __init spear3xx_timer_init(void) char pclk_name[] = "pll3_48m_clk"; struct clk *gpt_clk, *pclk; + spear3xx_clk_init(); + /* get the system timer clock */ gpt_clk = clk_get_sys("gpt0", NULL); if (IS_ERR(gpt_clk)) { @@ -109,7 +111,7 @@ static void __init spear3xx_timer_init(void) clk_put(gpt_clk); clk_put(pclk); - spear_setup_timer(SPEAR3XX_CPU_TMR_BASE, SPEAR3XX_IRQ_CPU_GPT1_1); + spear_setup_of_timer(); } struct sys_timer spear3xx_timer = { diff --git a/arch/arm/mach-spear6xx/Makefile b/arch/arm/mach-spear6xx/Makefile index 76e5750552fc..898831d93f37 100644 --- a/arch/arm/mach-spear6xx/Makefile +++ b/arch/arm/mach-spear6xx/Makefile @@ -3,4 +3,4 @@ # # common files -obj-y += clock.o spear6xx.o +obj-y += spear6xx.o diff --git a/arch/arm/mach-spear6xx/clock.c b/arch/arm/mach-spear6xx/clock.c deleted file mode 100644 index bef77d43db87..000000000000 --- a/arch/arm/mach-spear6xx/clock.c +++ /dev/null @@ -1,789 +0,0 @@ -/* - * arch/arm/mach-spear6xx/clock.c - * - * SPEAr6xx machines clock framework source file - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/init.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <plat/clock.h> -#include <mach/misc_regs.h> -#include <mach/spear.h> - -#define PLL1_CTR (MISC_BASE + 0x008) -#define PLL1_FRQ (MISC_BASE + 0x00C) -#define PLL1_MOD (MISC_BASE + 0x010) -#define PLL2_CTR (MISC_BASE + 0x014) -/* PLL_CTR register masks */ -#define PLL_ENABLE 2 -#define PLL_MODE_SHIFT 4 -#define PLL_MODE_MASK 0x3 -#define PLL_MODE_NORMAL 0 -#define PLL_MODE_FRACTION 1 -#define PLL_MODE_DITH_DSB 2 -#define PLL_MODE_DITH_SSB 3 - -#define PLL2_FRQ (MISC_BASE + 0x018) -/* PLL FRQ register masks */ -#define PLL_DIV_N_SHIFT 0 -#define PLL_DIV_N_MASK 0xFF -#define PLL_DIV_P_SHIFT 8 -#define PLL_DIV_P_MASK 0x7 -#define PLL_NORM_FDBK_M_SHIFT 24 -#define PLL_NORM_FDBK_M_MASK 0xFF -#define PLL_DITH_FDBK_M_SHIFT 16 -#define PLL_DITH_FDBK_M_MASK 0xFFFF - -#define PLL2_MOD (MISC_BASE + 0x01C) -#define PLL_CLK_CFG (MISC_BASE + 0x020) -#define CORE_CLK_CFG (MISC_BASE + 0x024) -/* CORE CLK CFG register masks */ -#define PLL_HCLK_RATIO_SHIFT 10 -#define PLL_HCLK_RATIO_MASK 0x3 -#define HCLK_PCLK_RATIO_SHIFT 8 -#define HCLK_PCLK_RATIO_MASK 0x3 - -#define PERIP_CLK_CFG (MISC_BASE + 0x028) -/* PERIP_CLK_CFG register masks */ -#define CLCD_CLK_SHIFT 2 -#define CLCD_CLK_MASK 0x3 -#define UART_CLK_SHIFT 4 -#define UART_CLK_MASK 0x1 -#define FIRDA_CLK_SHIFT 5 -#define FIRDA_CLK_MASK 0x3 -#define GPT0_CLK_SHIFT 8 -#define GPT1_CLK_SHIFT 10 -#define GPT2_CLK_SHIFT 11 -#define GPT3_CLK_SHIFT 12 -#define GPT_CLK_MASK 0x1 -#define AUX_CLK_PLL3_VAL 0 -#define AUX_CLK_PLL1_VAL 1 - -#define PERIP1_CLK_ENB (MISC_BASE + 0x02C) -/* PERIP1_CLK_ENB register masks */ -#define UART0_CLK_ENB 3 -#define UART1_CLK_ENB 4 -#define SSP0_CLK_ENB 5 -#define SSP1_CLK_ENB 6 -#define I2C_CLK_ENB 7 -#define JPEG_CLK_ENB 8 -#define FSMC_CLK_ENB 9 -#define FIRDA_CLK_ENB 10 -#define GPT2_CLK_ENB 11 -#define GPT3_CLK_ENB 12 -#define GPIO2_CLK_ENB 13 -#define SSP2_CLK_ENB 14 -#define ADC_CLK_ENB 15 -#define GPT1_CLK_ENB 11 -#define RTC_CLK_ENB 17 -#define GPIO1_CLK_ENB 18 -#define DMA_CLK_ENB 19 -#define SMI_CLK_ENB 21 -#define CLCD_CLK_ENB 22 -#define GMAC_CLK_ENB 23 -#define USBD_CLK_ENB 24 -#define USBH0_CLK_ENB 25 -#define USBH1_CLK_ENB 26 - -#define PRSC1_CLK_CFG (MISC_BASE + 0x044) -#define PRSC2_CLK_CFG (MISC_BASE + 0x048) -#define PRSC3_CLK_CFG (MISC_BASE + 0x04C) -/* gpt synthesizer register masks */ -#define GPT_MSCALE_SHIFT 0 -#define GPT_MSCALE_MASK 0xFFF -#define GPT_NSCALE_SHIFT 12 -#define GPT_NSCALE_MASK 0xF - -#define AMEM_CLK_CFG (MISC_BASE + 0x050) -#define EXPI_CLK_CFG (MISC_BASE + 0x054) -#define CLCD_CLK_SYNT (MISC_BASE + 0x05C) -#define FIRDA_CLK_SYNT (MISC_BASE + 0x060) -#define UART_CLK_SYNT (MISC_BASE + 0x064) -#define GMAC_CLK_SYNT (MISC_BASE + 0x068) -#define RAS1_CLK_SYNT (MISC_BASE + 0x06C) -#define RAS2_CLK_SYNT (MISC_BASE + 0x070) -#define RAS3_CLK_SYNT (MISC_BASE + 0x074) -#define RAS4_CLK_SYNT (MISC_BASE + 0x078) -/* aux clk synthesiser register masks for irda to ras4 */ -#define AUX_SYNT_ENB 31 -#define AUX_EQ_SEL_SHIFT 30 -#define AUX_EQ_SEL_MASK 1 -#define AUX_EQ1_SEL 0 -#define AUX_EQ2_SEL 1 -#define AUX_XSCALE_SHIFT 16 -#define AUX_XSCALE_MASK 0xFFF -#define AUX_YSCALE_SHIFT 0 -#define AUX_YSCALE_MASK 0xFFF - -/* root clks */ -/* 32 KHz oscillator clock */ -static struct clk osc_32k_clk = { - .flags = ALWAYS_ENABLED, - .rate = 32000, -}; - -/* 30 MHz oscillator clock */ -static struct clk osc_30m_clk = { - .flags = ALWAYS_ENABLED, - .rate = 30000000, -}; - -/* clock derived from 32 KHz osc clk */ -/* rtc clock */ -static struct clk rtc_clk = { - .pclk = &osc_32k_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = RTC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from 30 MHz osc clk */ -/* pll masks structure */ -static struct pll_clk_masks pll1_masks = { - .mode_mask = PLL_MODE_MASK, - .mode_shift = PLL_MODE_SHIFT, - .norm_fdbk_m_mask = PLL_NORM_FDBK_M_MASK, - .norm_fdbk_m_shift = PLL_NORM_FDBK_M_SHIFT, - .dith_fdbk_m_mask = PLL_DITH_FDBK_M_MASK, - .dith_fdbk_m_shift = PLL_DITH_FDBK_M_SHIFT, - .div_p_mask = PLL_DIV_P_MASK, - .div_p_shift = PLL_DIV_P_SHIFT, - .div_n_mask = PLL_DIV_N_MASK, - .div_n_shift = PLL_DIV_N_SHIFT, -}; - -/* pll1 configuration structure */ -static struct pll_clk_config pll1_config = { - .mode_reg = PLL1_CTR, - .cfg_reg = PLL1_FRQ, - .masks = &pll1_masks, -}; - -/* pll rate configuration table, in ascending order of rates */ -struct pll_rate_tbl pll_rtbl[] = { - {.mode = 0, .m = 0x85, .n = 0x0C, .p = 0x1}, /* 266 MHz */ - {.mode = 0, .m = 0xA6, .n = 0x0C, .p = 0x1}, /* 332 MHz */ -}; - -/* PLL1 clock */ -static struct clk pll1_clk = { - .flags = ENABLED_ON_INIT, - .pclk = &osc_30m_clk, - .en_reg = PLL1_CTR, - .en_reg_bit = PLL_ENABLE, - .calc_rate = &pll_calc_rate, - .recalc = &pll_clk_recalc, - .set_rate = &pll_clk_set_rate, - .rate_config = {pll_rtbl, ARRAY_SIZE(pll_rtbl), 1}, - .private_data = &pll1_config, -}; - -/* PLL3 48 MHz clock */ -static struct clk pll3_48m_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_30m_clk, - .rate = 48000000, -}; - -/* watch dog timer clock */ -static struct clk wdt_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &osc_30m_clk, - .recalc = &follow_parent, -}; - -/* clock derived from pll1 clk */ -/* cpu clock */ -static struct clk cpu_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .recalc = &follow_parent, -}; - -/* ahb masks structure */ -static struct bus_clk_masks ahb_masks = { - .mask = PLL_HCLK_RATIO_MASK, - .shift = PLL_HCLK_RATIO_SHIFT, -}; - -/* ahb configuration structure */ -static struct bus_clk_config ahb_config = { - .reg = CORE_CLK_CFG, - .masks = &ahb_masks, -}; - -/* ahb rate configuration table, in ascending order of rates */ -struct bus_rate_tbl bus_rtbl[] = { - {.div = 3}, /* == parent divided by 4 */ - {.div = 2}, /* == parent divided by 3 */ - {.div = 1}, /* == parent divided by 2 */ - {.div = 0}, /* == parent divided by 1 */ -}; - -/* ahb clock */ -static struct clk ahb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &ahb_config, -}; - -/* auxiliary synthesizers masks */ -static struct aux_clk_masks aux_masks = { - .eq_sel_mask = AUX_EQ_SEL_MASK, - .eq_sel_shift = AUX_EQ_SEL_SHIFT, - .eq1_mask = AUX_EQ1_SEL, - .eq2_mask = AUX_EQ2_SEL, - .xscale_sel_mask = AUX_XSCALE_MASK, - .xscale_sel_shift = AUX_XSCALE_SHIFT, - .yscale_sel_mask = AUX_YSCALE_MASK, - .yscale_sel_shift = AUX_YSCALE_SHIFT, -}; - -/* uart configurations */ -static struct aux_clk_config uart_synth_config = { - .synth_reg = UART_CLK_SYNT, - .masks = &aux_masks, -}; - -/* aux rate configuration table, in ascending order of rates */ -struct aux_rate_tbl aux_rtbl[] = { - /* For PLL1 = 332 MHz */ - {.xscale = 1, .yscale = 8, .eq = 1}, /* 41.5 MHz */ - {.xscale = 1, .yscale = 4, .eq = 1}, /* 83 MHz */ - {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ -}; - -/* uart synth clock */ -static struct clk uart_synth_clk = { - .en_reg = UART_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 2}, - .private_data = &uart_synth_config, -}; - -/* uart parents */ -static struct pclk_info uart_pclk_info[] = { - { - .pclk = &uart_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* uart parent select structure */ -static struct pclk_sel uart_pclk_sel = { - .pclk_info = uart_pclk_info, - .pclk_count = ARRAY_SIZE(uart_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = UART_CLK_MASK, -}; - -/* uart0 clock */ -static struct clk uart0_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = UART0_CLK_ENB, - .pclk_sel = &uart_pclk_sel, - .pclk_sel_shift = UART_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* uart1 clock */ -static struct clk uart1_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = UART1_CLK_ENB, - .pclk_sel = &uart_pclk_sel, - .pclk_sel_shift = UART_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* firda configurations */ -static struct aux_clk_config firda_synth_config = { - .synth_reg = FIRDA_CLK_SYNT, - .masks = &aux_masks, -}; - -/* firda synth clock */ -static struct clk firda_synth_clk = { - .en_reg = FIRDA_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 2}, - .private_data = &firda_synth_config, -}; - -/* firda parents */ -static struct pclk_info firda_pclk_info[] = { - { - .pclk = &firda_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* firda parent select structure */ -static struct pclk_sel firda_pclk_sel = { - .pclk_info = firda_pclk_info, - .pclk_count = ARRAY_SIZE(firda_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = FIRDA_CLK_MASK, -}; - -/* firda clock */ -static struct clk firda_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = FIRDA_CLK_ENB, - .pclk_sel = &firda_pclk_sel, - .pclk_sel_shift = FIRDA_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* clcd configurations */ -static struct aux_clk_config clcd_synth_config = { - .synth_reg = CLCD_CLK_SYNT, - .masks = &aux_masks, -}; - -/* firda synth clock */ -static struct clk clcd_synth_clk = { - .en_reg = CLCD_CLK_SYNT, - .en_reg_bit = AUX_SYNT_ENB, - .pclk = &pll1_clk, - .calc_rate = &aux_calc_rate, - .recalc = &aux_clk_recalc, - .set_rate = &aux_clk_set_rate, - .rate_config = {aux_rtbl, ARRAY_SIZE(aux_rtbl), 2}, - .private_data = &clcd_synth_config, -}; - -/* clcd parents */ -static struct pclk_info clcd_pclk_info[] = { - { - .pclk = &clcd_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* clcd parent select structure */ -static struct pclk_sel clcd_pclk_sel = { - .pclk_info = clcd_pclk_info, - .pclk_count = ARRAY_SIZE(clcd_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = CLCD_CLK_MASK, -}; - -/* clcd clock */ -static struct clk clcd_clk = { - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = CLCD_CLK_ENB, - .pclk_sel = &clcd_pclk_sel, - .pclk_sel_shift = CLCD_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt synthesizer masks */ -static struct gpt_clk_masks gpt_masks = { - .mscale_sel_mask = GPT_MSCALE_MASK, - .mscale_sel_shift = GPT_MSCALE_SHIFT, - .nscale_sel_mask = GPT_NSCALE_MASK, - .nscale_sel_shift = GPT_NSCALE_SHIFT, -}; - -/* gpt rate configuration table, in ascending order of rates */ -struct gpt_rate_tbl gpt_rtbl[] = { - /* For pll1 = 332 MHz */ - {.mscale = 4, .nscale = 0}, /* 41.5 MHz */ - {.mscale = 2, .nscale = 0}, /* 55.3 MHz */ - {.mscale = 1, .nscale = 0}, /* 83 MHz */ -}; - -/* gpt0 synth clk config*/ -static struct gpt_clk_config gpt0_synth_config = { - .synth_reg = PRSC1_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt0_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt0_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt0_pclk_info[] = { - { - .pclk = &gpt0_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt0_pclk_sel = { - .pclk_info = gpt0_pclk_info, - .pclk_count = ARRAY_SIZE(gpt0_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt0 ARM1 subsystem timer clock */ -static struct clk gpt0_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt0_pclk_sel, - .pclk_sel_shift = GPT0_CLK_SHIFT, - .recalc = &follow_parent, -}; - - -/* Note: gpt0 and gpt1 share same parent clocks */ -/* gpt parent select structure */ -static struct pclk_sel gpt1_pclk_sel = { - .pclk_info = gpt0_pclk_info, - .pclk_count = ARRAY_SIZE(gpt0_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt1 timer clock */ -static struct clk gpt1_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt1_pclk_sel, - .pclk_sel_shift = GPT1_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt2 synth clk config*/ -static struct gpt_clk_config gpt2_synth_config = { - .synth_reg = PRSC2_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt2_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt2_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt2_pclk_info[] = { - { - .pclk = &gpt2_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt2_pclk_sel = { - .pclk_info = gpt2_pclk_info, - .pclk_count = ARRAY_SIZE(gpt2_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt2 timer clock */ -static struct clk gpt2_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt2_pclk_sel, - .pclk_sel_shift = GPT2_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* gpt3 synth clk config*/ -static struct gpt_clk_config gpt3_synth_config = { - .synth_reg = PRSC3_CLK_CFG, - .masks = &gpt_masks, -}; - -/* gpt synth clock */ -static struct clk gpt3_synth_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &pll1_clk, - .calc_rate = &gpt_calc_rate, - .recalc = &gpt_clk_recalc, - .set_rate = &gpt_clk_set_rate, - .rate_config = {gpt_rtbl, ARRAY_SIZE(gpt_rtbl), 2}, - .private_data = &gpt3_synth_config, -}; - -/* gpt parents */ -static struct pclk_info gpt3_pclk_info[] = { - { - .pclk = &gpt3_synth_clk, - .pclk_val = AUX_CLK_PLL1_VAL, - }, { - .pclk = &pll3_48m_clk, - .pclk_val = AUX_CLK_PLL3_VAL, - }, -}; - -/* gpt parent select structure */ -static struct pclk_sel gpt3_pclk_sel = { - .pclk_info = gpt3_pclk_info, - .pclk_count = ARRAY_SIZE(gpt3_pclk_info), - .pclk_sel_reg = PERIP_CLK_CFG, - .pclk_sel_mask = GPT_CLK_MASK, -}; - -/* gpt3 timer clock */ -static struct clk gpt3_clk = { - .flags = ALWAYS_ENABLED, - .pclk_sel = &gpt3_pclk_sel, - .pclk_sel_shift = GPT3_CLK_SHIFT, - .recalc = &follow_parent, -}; - -/* clock derived from pll3 clk */ -/* usbh0 clock */ -static struct clk usbh0_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBH0_CLK_ENB, - .recalc = &follow_parent, -}; - -/* usbh1 clock */ -static struct clk usbh1_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBH1_CLK_ENB, - .recalc = &follow_parent, -}; - -/* usbd clock */ -static struct clk usbd_clk = { - .pclk = &pll3_48m_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = USBD_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from ahb clk */ -/* apb masks structure */ -static struct bus_clk_masks apb_masks = { - .mask = HCLK_PCLK_RATIO_MASK, - .shift = HCLK_PCLK_RATIO_SHIFT, -}; - -/* apb configuration structure */ -static struct bus_clk_config apb_config = { - .reg = CORE_CLK_CFG, - .masks = &apb_masks, -}; - -/* apb clock */ -static struct clk apb_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &ahb_clk, - .calc_rate = &bus_calc_rate, - .recalc = &bus_clk_recalc, - .set_rate = &bus_clk_set_rate, - .rate_config = {bus_rtbl, ARRAY_SIZE(bus_rtbl), 2}, - .private_data = &apb_config, -}; - -/* i2c clock */ -static struct clk i2c_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = I2C_CLK_ENB, - .recalc = &follow_parent, -}; - -/* dma clock */ -static struct clk dma_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = DMA_CLK_ENB, - .recalc = &follow_parent, -}; - -/* jpeg clock */ -static struct clk jpeg_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = JPEG_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gmac clock */ -static struct clk gmac_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GMAC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* smi clock */ -static struct clk smi_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SMI_CLK_ENB, - .recalc = &follow_parent, -}; - -/* fsmc clock */ -static struct clk fsmc_clk = { - .pclk = &ahb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = FSMC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* clock derived from apb clk */ -/* adc clock */ -static struct clk adc_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = ADC_CLK_ENB, - .recalc = &follow_parent, -}; - -/* ssp0 clock */ -static struct clk ssp0_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP0_CLK_ENB, - .recalc = &follow_parent, -}; - -/* ssp1 clock */ -static struct clk ssp1_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP1_CLK_ENB, - .recalc = &follow_parent, -}; - -/* ssp2 clock */ -static struct clk ssp2_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = SSP2_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gpio0 ARM subsystem clock */ -static struct clk gpio0_clk = { - .flags = ALWAYS_ENABLED, - .pclk = &apb_clk, - .recalc = &follow_parent, -}; - -/* gpio1 clock */ -static struct clk gpio1_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPIO1_CLK_ENB, - .recalc = &follow_parent, -}; - -/* gpio2 clock */ -static struct clk gpio2_clk = { - .pclk = &apb_clk, - .en_reg = PERIP1_CLK_ENB, - .en_reg_bit = GPIO2_CLK_ENB, - .recalc = &follow_parent, -}; - -static struct clk dummy_apb_pclk; - -/* array of all spear 6xx clock lookups */ -static struct clk_lookup spear_clk_lookups[] = { - CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk), - /* root clks */ - CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk), - CLKDEV_INIT(NULL, "osc_30m_clk", &osc_30m_clk), - /* clock derived from 32 KHz os clk */ - CLKDEV_INIT("rtc-spear", NULL, &rtc_clk), - /* clock derived from 30 MHz os clk */ - CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk), - CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk), - CLKDEV_INIT("wdt", NULL, &wdt_clk), - /* clock derived from pll1 clk */ - CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk), - CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk), - CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk), - CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk), - CLKDEV_INIT(NULL, "clcd_synth_clk", &clcd_synth_clk), - CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk), - CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk), - CLKDEV_INIT(NULL, "gpt3_synth_clk", &gpt3_synth_clk), - CLKDEV_INIT("d0000000.serial", NULL, &uart0_clk), - CLKDEV_INIT("d0080000.serial", NULL, &uart1_clk), - CLKDEV_INIT("firda", NULL, &firda_clk), - CLKDEV_INIT("clcd", NULL, &clcd_clk), - CLKDEV_INIT("gpt0", NULL, &gpt0_clk), - CLKDEV_INIT("gpt1", NULL, &gpt1_clk), - CLKDEV_INIT("gpt2", NULL, &gpt2_clk), - CLKDEV_INIT("gpt3", NULL, &gpt3_clk), - /* clock derived from pll3 clk */ - CLKDEV_INIT("designware_udc", NULL, &usbd_clk), - CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk), - CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk), - /* clock derived from ahb clk */ - CLKDEV_INIT(NULL, "apb_clk", &apb_clk), - CLKDEV_INIT("d0200000.i2c", NULL, &i2c_clk), - CLKDEV_INIT("fc400000.dma", NULL, &dma_clk), - CLKDEV_INIT("jpeg", NULL, &jpeg_clk), - CLKDEV_INIT("gmac", NULL, &gmac_clk), - CLKDEV_INIT("fc000000.flash", NULL, &smi_clk), - CLKDEV_INIT("d1800000.flash", NULL, &fsmc_clk), - /* clock derived from apb clk */ - CLKDEV_INIT("adc", NULL, &adc_clk), - CLKDEV_INIT("ssp-pl022.0", NULL, &ssp0_clk), - CLKDEV_INIT("ssp-pl022.1", NULL, &ssp1_clk), - CLKDEV_INIT("ssp-pl022.2", NULL, &ssp2_clk), - CLKDEV_INIT("f0100000.gpio", NULL, &gpio0_clk), - CLKDEV_INIT("fc980000.gpio", NULL, &gpio1_clk), - CLKDEV_INIT("d8100000.gpio", NULL, &gpio2_clk), -}; - -void __init spear6xx_clk_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++) - clk_register(&spear_clk_lookups[i]); - - clk_init(); -} diff --git a/arch/arm/mach-spear6xx/include/mach/generic.h b/arch/arm/mach-spear6xx/include/mach/generic.h index 7167fd331d86..65514b159370 100644 --- a/arch/arm/mach-spear6xx/include/mach/generic.h +++ b/arch/arm/mach-spear6xx/include/mach/generic.h @@ -16,7 +16,7 @@ #include <linux/init.h> -void __init spear_setup_timer(resource_size_t base, int irq); +void __init spear_setup_of_timer(void); void spear_restart(char, const char *); void __init spear6xx_clk_init(void); diff --git a/arch/arm/mach-spear6xx/include/mach/irqs.h b/arch/arm/mach-spear6xx/include/mach/irqs.h index 2b735389e74b..37a5c411a866 100644 --- a/arch/arm/mach-spear6xx/include/mach/irqs.h +++ b/arch/arm/mach-spear6xx/include/mach/irqs.h @@ -16,9 +16,6 @@ /* IRQ definitions */ /* VIC 1 */ -/* FIXME: probe this from DT */ -#define IRQ_CPU_GPT1_1 16 - #define IRQ_VIC_END 64 /* GPIO pins virtual irqs */ diff --git a/arch/arm/mach-spear6xx/include/mach/misc_regs.h b/arch/arm/mach-spear6xx/include/mach/misc_regs.h index 2b9aaa6cdd11..179e45774b3a 100644 --- a/arch/arm/mach-spear6xx/include/mach/misc_regs.h +++ b/arch/arm/mach-spear6xx/include/mach/misc_regs.h @@ -14,6 +14,8 @@ #ifndef __MACH_MISC_REGS_H #define __MACH_MISC_REGS_H +#include <mach/spear.h> + #define MISC_BASE IOMEM(VA_SPEAR6XX_ICM3_MISC_REG_BASE) #define DMA_CHN_CFG (MISC_BASE + 0x0A0) diff --git a/arch/arm/mach-spear6xx/include/mach/spear.h b/arch/arm/mach-spear6xx/include/mach/spear.h index d278ed047a53..cb8ed2f4dc85 100644 --- a/arch/arm/mach-spear6xx/include/mach/spear.h +++ b/arch/arm/mach-spear6xx/include/mach/spear.h @@ -25,7 +25,6 @@ /* ML-1, 2 - Multi Layer CPU Subsystem */ #define SPEAR6XX_ML_CPU_BASE UL(0xF0000000) #define VA_SPEAR6XX_ML_CPU_BASE UL(0xF0000000) -#define SPEAR6XX_CPU_TMR_BASE UL(0xF0000000) /* ICM3 - Basic Subsystem */ #define SPEAR6XX_ICM3_SMI_CTRL_BASE UL(0xFC000000) diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c index de194dbb8371..2e2e3596583e 100644 --- a/arch/arm/mach-spear6xx/spear6xx.c +++ b/arch/arm/mach-spear6xx/spear6xx.c @@ -419,9 +419,6 @@ struct map_desc spear6xx_io_desc[] __initdata = { void __init spear6xx_map_io(void) { iotable_init(spear6xx_io_desc, ARRAY_SIZE(spear6xx_io_desc)); - - /* This will initialize clock framework */ - spear6xx_clk_init(); } static void __init spear6xx_timer_init(void) @@ -429,6 +426,8 @@ static void __init spear6xx_timer_init(void) char pclk_name[] = "pll3_48m_clk"; struct clk *gpt_clk, *pclk; + spear6xx_clk_init(); + /* get the system timer clock */ gpt_clk = clk_get_sys("gpt0", NULL); if (IS_ERR(gpt_clk)) { @@ -448,7 +447,7 @@ static void __init spear6xx_timer_init(void) clk_put(gpt_clk); clk_put(pclk); - spear_setup_timer(SPEAR6XX_CPU_TMR_BASE, IRQ_CPU_GPT1_1); + spear_setup_of_timer(); } struct sys_timer spear6xx_timer = { 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-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c index fac3eb1af17e..eb7249db50a5 100644 --- a/arch/arm/mach-tegra/board-dt-tegra20.c +++ b/arch/arm/mach-tegra/board-dt-tegra20.c @@ -110,6 +110,7 @@ DT_MACHINE_START(TEGRA_DT, "nVidia Tegra20 (Flattened Device Tree)") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra_dt_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, .dt_compat = tegra20_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 5f7c03e972f3..4f76fa7a5da3 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}, }; @@ -80,6 +90,7 @@ DT_MACHINE_START(TEGRA30_DT, "NVIDIA Tegra30 (Flattened Device Tree)") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra30_dt_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, .dt_compat = tegra30_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c index b906b3b6077b..e65e837f4013 100644 --- a/arch/arm/mach-tegra/board-harmony.c +++ b/arch/arm/mach-tegra/board-harmony.c @@ -192,5 +192,6 @@ MACHINE_START(HARMONY, "harmony") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra_harmony_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, MACHINE_END diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c index d0735c70d688..bbc1907e98a6 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 }, @@ -224,5 +225,6 @@ MACHINE_START(PAZ00, "Toshiba AC100 / Dynabook AZ") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra_paz00_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, MACHINE_END diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c index 79064c7a7907..71e9f3fc7fba 100644 --- a/arch/arm/mach-tegra/board-seaboard.c +++ b/arch/arm/mach-tegra/board-seaboard.c @@ -277,6 +277,7 @@ MACHINE_START(SEABOARD, "seaboard") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra_seaboard_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, MACHINE_END @@ -288,6 +289,7 @@ MACHINE_START(KAEN, "kaen") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra_kaen_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, MACHINE_END @@ -299,5 +301,6 @@ MACHINE_START(WARIO, "wario") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra_wario_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, MACHINE_END diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c index bc59b379c6fe..776aa9564d5d 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); @@ -176,5 +178,6 @@ MACHINE_START(TRIMSLICE, "trimslice") .handle_irq = gic_handle_irq, .timer = &tegra_timer, .init_machine = tegra_trimslice_init, + .init_late = tegra_init_late, .restart = tegra_assert_system_reset, MACHINE_END diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h index 75d1543d77c0..65014968fc6c 100644 --- a/arch/arm/mach-tegra/board.h +++ b/arch/arm/mach-tegra/board.h @@ -32,5 +32,19 @@ void __init tegra_init_irq(void); void __init tegra_dt_init_irq(void); int __init tegra_pcie_init(bool init_port0, bool init_port1); +void tegra_init_late(void); + +#ifdef CONFIG_DEBUG_FS +int tegra_clk_debugfs_init(void); +#else +static inline int tegra_clk_debugfs_init(void) { return 0; } +#endif + +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) && defined(CONFIG_DEBUG_FS) +int __init tegra_powergate_debugfs_init(void); +#else +static inline int tegra_powergate_debugfs_init(void) { return 0; } +#endif + extern struct sys_timer tegra_timer; #endif diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 8dad8d18cb49..58f981c0819c 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -642,7 +642,7 @@ static int clk_debugfs_register(struct clk *c) return 0; } -static int __init clk_debugfs_init(void) +int __init tegra_clk_debugfs_init(void) { struct clk *c; struct dentry *d; @@ -669,5 +669,4 @@ err_out: return err; } -late_initcall(clk_debugfs_init); #endif diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 22df10fb9972..204a5c8b0b57 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,8 +140,15 @@ 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(); } #endif + +void __init tegra_init_late(void) +{ + tegra_clk_debugfs_init(); + tegra_powergate_debugfs_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/powergate.c b/arch/arm/mach-tegra/powergate.c index c238699ae86f..f5b12fb4ff12 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -234,7 +234,7 @@ static const struct file_operations powergate_fops = { .release = single_release, }; -static int __init powergate_debugfs_init(void) +int __init tegra_powergate_debugfs_init(void) { struct dentry *d; int err = -ENOMEM; @@ -247,6 +247,4 @@ static int __init powergate_debugfs_init(void) return err; } -late_initcall(powergate_debugfs_init); - #endif 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/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index f943687acaf0..b23a643f03f4 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -785,6 +785,7 @@ MACHINE_START(U8500, "ST-Ericsson MOP500 platform") .timer = &ux500_timer, .handle_irq = gic_handle_irq, .init_machine = mop500_init_machine, + .init_late = ux500_init_late, MACHINE_END MACHINE_START(HREFV60, "ST-Ericsson U8500 Platform HREFv60+") @@ -794,6 +795,7 @@ MACHINE_START(HREFV60, "ST-Ericsson U8500 Platform HREFv60+") .timer = &ux500_timer, .handle_irq = gic_handle_irq, .init_machine = hrefv60_init_machine, + .init_late = ux500_init_late, MACHINE_END MACHINE_START(SNOWBALL, "Calao Systems Snowball platform") @@ -804,6 +806,7 @@ MACHINE_START(SNOWBALL, "Calao Systems Snowball platform") .timer = &ux500_timer, .handle_irq = gic_handle_irq, .init_machine = snowball_init_machine, + .init_late = ux500_init_late, MACHINE_END #ifdef CONFIG_MACH_UX500_DT @@ -918,6 +921,7 @@ DT_MACHINE_START(U8500_DT, "ST-Ericsson U8500 platform (Device Tree Support)") .timer = &ux500_timer, .handle_irq = gic_handle_irq, .init_machine = u8500_init_machine, + .init_late = ux500_init_late, .dt_compat = u8500_dt_board_compat, MACHINE_END #endif diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 1762c4728f1e..8d73b066a18d 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c @@ -635,7 +635,7 @@ static int clk_debugfs_register(struct clk *c) return 0; } -static int __init clk_debugfs_init(void) +int __init clk_debugfs_init(void) { struct clk *c; struct dentry *d; @@ -657,7 +657,6 @@ err_out: return err; } -late_initcall(clk_debugfs_init); #endif /* defined(CONFIG_DEBUG_FS) */ unsigned long clk_smp_twd_rate = 500000000; @@ -696,12 +695,11 @@ static struct notifier_block clk_twd_cpufreq_nb = { .notifier_call = clk_twd_cpufreq_transition, }; -static int clk_init_smp_twd_cpufreq(void) +int clk_init_smp_twd_cpufreq(void) { return cpufreq_register_notifier(&clk_twd_cpufreq_nb, CPUFREQ_TRANSITION_NOTIFIER); } -late_initcall(clk_init_smp_twd_cpufreq); #endif diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h index d776ada08dbf..65d27a13f46d 100644 --- a/arch/arm/mach-ux500/clock.h +++ b/arch/arm/mach-ux500/clock.h @@ -150,3 +150,15 @@ struct clk clk_##_name = { \ int __init clk_db8500_ed_fixup(void); int __init clk_init(void); + +#ifdef CONFIG_DEBUG_FS +int clk_debugfs_init(void); +#else +static inline int clk_debugfs_init(void) { return 0; } +#endif + +#ifdef CONFIG_CPU_FREQ +int clk_init_smp_twd_cpufreq(void); +#else +static inline int clk_init_smp_twd_cpufreq(void) { return 0; } +#endif diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index a29a0e3adcf9..e2360e7c770d 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -73,6 +73,12 @@ void __init ux500_init_irq(void) clk_init(); } +void __init ux500_init_late(void) +{ + clk_debugfs_init(); + clk_init_smp_twd_cpufreq(); +} + static const char * __init ux500_get_machine(void) { return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber()); diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h index 4e369f1645ec..8b7ed82a2866 100644 --- a/arch/arm/mach-ux500/include/mach/setup.h +++ b/arch/arm/mach-ux500/include/mach/setup.h @@ -20,6 +20,7 @@ extern void __init u8500_map_io(void); extern struct device * __init u8500_init_devices(void); extern void __init ux500_init_irq(void); +extern void __init ux500_init_late(void); extern struct device *ux500_soc_device_init(const char *soc_id); diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index db23ae4aaaab..ea6b43154090 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -17,8 +17,12 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/dma-mapping.h> +#include <linux/dma-contiguous.h> #include <linux/highmem.h> +#include <linux/memblock.h> #include <linux/slab.h> +#include <linux/iommu.h> +#include <linux/vmalloc.h> #include <asm/memory.h> #include <asm/highmem.h> @@ -26,9 +30,112 @@ #include <asm/tlbflush.h> #include <asm/sizes.h> #include <asm/mach/arch.h> +#include <asm/dma-iommu.h> +#include <asm/mach/map.h> +#include <asm/system_info.h> +#include <asm/dma-contiguous.h> #include "mm.h" +/* + * The DMA API is built upon the notion of "buffer ownership". A buffer + * is either exclusively owned by the CPU (and therefore may be accessed + * by it) or exclusively owned by the DMA device. These helper functions + * represent the transitions between these two ownership states. + * + * Note, however, that on later ARMs, this notion does not work due to + * speculative prefetches. We model our approach on the assumption that + * the CPU does do speculative prefetches, which means we clean caches + * before transfers and delay cache invalidation until transfer completion. + * + */ +static void __dma_page_cpu_to_dev(struct page *, unsigned long, + size_t, enum dma_data_direction); +static void __dma_page_dev_to_cpu(struct page *, unsigned long, + size_t, enum dma_data_direction); + +/** + * arm_dma_map_page - map a portion of a page for streaming DMA + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @page: page that buffer resides in + * @offset: offset into page for start of buffer + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * Ensure that any data held in the cache is appropriately discarded + * or written back. + * + * The device owns this memory once this call has completed. The CPU + * can regain ownership by calling dma_unmap_page(). + */ +static dma_addr_t arm_dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + if (!arch_is_coherent()) + __dma_page_cpu_to_dev(page, offset, size, dir); + return pfn_to_dma(dev, page_to_pfn(page)) + offset; +} + +/** + * arm_dma_unmap_page - unmap a buffer previously mapped through dma_map_page() + * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices + * @handle: DMA address of buffer + * @size: size of buffer (same as passed to dma_map_page) + * @dir: DMA transfer direction (same as passed to dma_map_page) + * + * Unmap a page streaming mode DMA translation. The handle and size + * must match what was provided in the previous dma_map_page() call. + * All other usages are undefined. + * + * After this call, reads by the CPU to the buffer are guaranteed to see + * whatever the device wrote there. + */ +static void arm_dma_unmap_page(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + if (!arch_is_coherent()) + __dma_page_dev_to_cpu(pfn_to_page(dma_to_pfn(dev, handle)), + handle & ~PAGE_MASK, size, dir); +} + +static void arm_dma_sync_single_for_cpu(struct device *dev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + unsigned int offset = handle & (PAGE_SIZE - 1); + struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset)); + if (!arch_is_coherent()) + __dma_page_dev_to_cpu(page, offset, size, dir); +} + +static void arm_dma_sync_single_for_device(struct device *dev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + unsigned int offset = handle & (PAGE_SIZE - 1); + struct page *page = pfn_to_page(dma_to_pfn(dev, handle-offset)); + if (!arch_is_coherent()) + __dma_page_cpu_to_dev(page, offset, size, dir); +} + +static int arm_dma_set_mask(struct device *dev, u64 dma_mask); + +struct dma_map_ops arm_dma_ops = { + .alloc = arm_dma_alloc, + .free = arm_dma_free, + .mmap = arm_dma_mmap, + .map_page = arm_dma_map_page, + .unmap_page = arm_dma_unmap_page, + .map_sg = arm_dma_map_sg, + .unmap_sg = arm_dma_unmap_sg, + .sync_single_for_cpu = arm_dma_sync_single_for_cpu, + .sync_single_for_device = arm_dma_sync_single_for_device, + .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, + .sync_sg_for_device = arm_dma_sync_sg_for_device, + .set_dma_mask = arm_dma_set_mask, +}; +EXPORT_SYMBOL(arm_dma_ops); + static u64 get_coherent_dma_mask(struct device *dev) { u64 mask = (u64)arm_dma_limit; @@ -56,6 +163,21 @@ static u64 get_coherent_dma_mask(struct device *dev) return mask; } +static void __dma_clear_buffer(struct page *page, size_t size) +{ + void *ptr; + /* + * Ensure that the allocated pages are zeroed, and that any data + * lurking in the kernel direct-mapped region is invalidated. + */ + ptr = page_address(page); + if (ptr) { + memset(ptr, 0, size); + dmac_flush_range(ptr, ptr + size); + outer_flush_range(__pa(ptr), __pa(ptr) + size); + } +} + /* * Allocate a DMA buffer for 'dev' of size 'size' using the * specified gfp mask. Note that 'size' must be page aligned. @@ -64,23 +186,6 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gf { unsigned long order = get_order(size); struct page *page, *p, *e; - void *ptr; - u64 mask = get_coherent_dma_mask(dev); - -#ifdef CONFIG_DMA_API_DEBUG - u64 limit = (mask + 1) & ~mask; - if (limit && size >= limit) { - dev_warn(dev, "coherent allocation too big (requested %#x mask %#llx)\n", - size, mask); - return NULL; - } -#endif - - if (!mask) - return NULL; - - if (mask < 0xffffffffULL) - gfp |= GFP_DMA; page = alloc_pages(gfp, order); if (!page) @@ -93,14 +198,7 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gf for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++) __free_page(p); - /* - * Ensure that the allocated pages are zeroed, and that any data - * lurking in the kernel direct-mapped region is invalidated. - */ - ptr = page_address(page); - memset(ptr, 0, size); - dmac_flush_range(ptr, ptr + size); - outer_flush_range(__pa(ptr), __pa(ptr) + size); + __dma_clear_buffer(page, size); return page; } @@ -170,6 +268,11 @@ static int __init consistent_init(void) unsigned long base = consistent_base; unsigned long num_ptes = (CONSISTENT_END - base) >> PMD_SHIFT; +#ifndef CONFIG_ARM_DMA_USE_IOMMU + if (cpu_architecture() >= CPU_ARCH_ARMv6) + return 0; +#endif + consistent_pte = kmalloc(num_ptes * sizeof(pte_t), GFP_KERNEL); if (!consistent_pte) { pr_err("%s: no memory\n", __func__); @@ -184,14 +287,14 @@ static int __init consistent_init(void) pud = pud_alloc(&init_mm, pgd, base); if (!pud) { - printk(KERN_ERR "%s: no pud tables\n", __func__); + pr_err("%s: no pud tables\n", __func__); ret = -ENOMEM; break; } pmd = pmd_alloc(&init_mm, pud, base); if (!pmd) { - printk(KERN_ERR "%s: no pmd tables\n", __func__); + pr_err("%s: no pmd tables\n", __func__); ret = -ENOMEM; break; } @@ -199,7 +302,7 @@ static int __init consistent_init(void) pte = pte_alloc_kernel(pmd, base); if (!pte) { - printk(KERN_ERR "%s: no pte tables\n", __func__); + pr_err("%s: no pte tables\n", __func__); ret = -ENOMEM; break; } @@ -210,9 +313,101 @@ static int __init consistent_init(void) return ret; } - core_initcall(consistent_init); +static void *__alloc_from_contiguous(struct device *dev, size_t size, + pgprot_t prot, struct page **ret_page); + +static struct arm_vmregion_head coherent_head = { + .vm_lock = __SPIN_LOCK_UNLOCKED(&coherent_head.vm_lock), + .vm_list = LIST_HEAD_INIT(coherent_head.vm_list), +}; + +size_t coherent_pool_size = DEFAULT_CONSISTENT_DMA_SIZE / 8; + +static int __init early_coherent_pool(char *p) +{ + coherent_pool_size = memparse(p, &p); + return 0; +} +early_param("coherent_pool", early_coherent_pool); + +/* + * Initialise the coherent pool for atomic allocations. + */ +static int __init coherent_init(void) +{ + pgprot_t prot = pgprot_dmacoherent(pgprot_kernel); + size_t size = coherent_pool_size; + struct page *page; + void *ptr; + + if (cpu_architecture() < CPU_ARCH_ARMv6) + return 0; + + ptr = __alloc_from_contiguous(NULL, size, prot, &page); + if (ptr) { + coherent_head.vm_start = (unsigned long) ptr; + coherent_head.vm_end = (unsigned long) ptr + size; + printk(KERN_INFO "DMA: preallocated %u KiB pool for atomic coherent allocations\n", + (unsigned)size / 1024); + return 0; + } + printk(KERN_ERR "DMA: failed to allocate %u KiB pool for atomic coherent allocation\n", + (unsigned)size / 1024); + return -ENOMEM; +} +/* + * CMA is activated by core_initcall, so we must be called after it. + */ +postcore_initcall(coherent_init); + +struct dma_contig_early_reserve { + phys_addr_t base; + unsigned long size; +}; + +static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS] __initdata; + +static int dma_mmu_remap_num __initdata; + +void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) +{ + dma_mmu_remap[dma_mmu_remap_num].base = base; + dma_mmu_remap[dma_mmu_remap_num].size = size; + dma_mmu_remap_num++; +} + +void __init dma_contiguous_remap(void) +{ + int i; + for (i = 0; i < dma_mmu_remap_num; i++) { + phys_addr_t start = dma_mmu_remap[i].base; + phys_addr_t end = start + dma_mmu_remap[i].size; + struct map_desc map; + unsigned long addr; + + if (end > arm_lowmem_limit) + end = arm_lowmem_limit; + if (start >= end) + return; + + map.pfn = __phys_to_pfn(start); + map.virtual = __phys_to_virt(start); + map.length = end - start; + map.type = MT_MEMORY_DMA_READY; + + /* + * Clear previous low-memory mapping + */ + for (addr = __phys_to_virt(start); addr < __phys_to_virt(end); + addr += PMD_SIZE) + pmd_clear(pmd_off_k(addr)); + + iotable_init(&map, 1); + } +} + static void * __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, const void *caller) @@ -222,7 +417,7 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, int bit; if (!consistent_pte) { - printk(KERN_ERR "%s: not initialised\n", __func__); + pr_err("%s: not initialised\n", __func__); dump_stack(); return NULL; } @@ -249,7 +444,7 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot, u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); pte = consistent_pte[idx] + off; - c->vm_pages = page; + c->priv = page; do { BUG_ON(!pte_none(*pte)); @@ -281,14 +476,14 @@ static void __dma_free_remap(void *cpu_addr, size_t size) c = arm_vmregion_find_remove(&consistent_head, (unsigned long)cpu_addr); if (!c) { - printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n", + pr_err("%s: trying to free invalid coherent area: %p\n", __func__, cpu_addr); dump_stack(); return; } if ((c->vm_end - c->vm_start) != size) { - printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", + pr_err("%s: freeing wrong coherent size (%ld != %d)\n", __func__, c->vm_end - c->vm_start, size); dump_stack(); size = c->vm_end - c->vm_start; @@ -310,8 +505,8 @@ static void __dma_free_remap(void *cpu_addr, size_t size) } if (pte_none(pte) || !pte_present(pte)) - printk(KERN_CRIT "%s: bad page in kernel page table\n", - __func__); + pr_crit("%s: bad page in kernel page table\n", + __func__); } while (size -= PAGE_SIZE); flush_tlb_kernel_range(c->vm_start, c->vm_end); @@ -319,20 +514,182 @@ static void __dma_free_remap(void *cpu_addr, size_t size) arm_vmregion_free(&consistent_head, c); } +static int __dma_update_pte(pte_t *pte, pgtable_t token, unsigned long addr, + void *data) +{ + struct page *page = virt_to_page(addr); + pgprot_t prot = *(pgprot_t *)data; + + set_pte_ext(pte, mk_pte(page, prot), 0); + return 0; +} + +static void __dma_remap(struct page *page, size_t size, pgprot_t prot) +{ + unsigned long start = (unsigned long) page_address(page); + unsigned end = start + size; + + apply_to_page_range(&init_mm, start, size, __dma_update_pte, &prot); + dsb(); + flush_tlb_kernel_range(start, end); +} + +static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp, + pgprot_t prot, struct page **ret_page, + const void *caller) +{ + struct page *page; + void *ptr; + page = __dma_alloc_buffer(dev, size, gfp); + if (!page) + return NULL; + + ptr = __dma_alloc_remap(page, size, gfp, prot, caller); + if (!ptr) { + __dma_free_buffer(page, size); + return NULL; + } + + *ret_page = page; + return ptr; +} + +static void *__alloc_from_pool(struct device *dev, size_t size, + struct page **ret_page, const void *caller) +{ + struct arm_vmregion *c; + size_t align; + + if (!coherent_head.vm_start) { + printk(KERN_ERR "%s: coherent pool not initialised!\n", + __func__); + dump_stack(); + return NULL; + } + + /* + * Align the region allocation - allocations from pool are rather + * small, so align them to their order in pages, minimum is a page + * size. This helps reduce fragmentation of the DMA space. + */ + align = PAGE_SIZE << get_order(size); + c = arm_vmregion_alloc(&coherent_head, align, size, 0, caller); + if (c) { + void *ptr = (void *)c->vm_start; + struct page *page = virt_to_page(ptr); + *ret_page = page; + return ptr; + } + return NULL; +} + +static int __free_from_pool(void *cpu_addr, size_t size) +{ + unsigned long start = (unsigned long)cpu_addr; + unsigned long end = start + size; + struct arm_vmregion *c; + + if (start < coherent_head.vm_start || end > coherent_head.vm_end) + return 0; + + c = arm_vmregion_find_remove(&coherent_head, (unsigned long)start); + + if ((c->vm_end - c->vm_start) != size) { + printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", + __func__, c->vm_end - c->vm_start, size); + dump_stack(); + size = c->vm_end - c->vm_start; + } + + arm_vmregion_free(&coherent_head, c); + return 1; +} + +static void *__alloc_from_contiguous(struct device *dev, size_t size, + pgprot_t prot, struct page **ret_page) +{ + unsigned long order = get_order(size); + size_t count = size >> PAGE_SHIFT; + struct page *page; + + page = dma_alloc_from_contiguous(dev, count, order); + if (!page) + return NULL; + + __dma_clear_buffer(page, size); + __dma_remap(page, size, prot); + + *ret_page = page; + return page_address(page); +} + +static void __free_from_contiguous(struct device *dev, struct page *page, + size_t size) +{ + __dma_remap(page, size, pgprot_kernel); + dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); +} + +static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot) +{ + prot = dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs) ? + pgprot_writecombine(prot) : + pgprot_dmacoherent(prot); + return prot; +} + +#define nommu() 0 + #else /* !CONFIG_MMU */ -#define __dma_alloc_remap(page, size, gfp, prot, c) page_address(page) -#define __dma_free_remap(addr, size) do { } while (0) +#define nommu() 1 + +#define __get_dma_pgprot(attrs, prot) __pgprot(0) +#define __alloc_remap_buffer(dev, size, gfp, prot, ret, c) NULL +#define __alloc_from_pool(dev, size, ret_page, c) NULL +#define __alloc_from_contiguous(dev, size, prot, ret) NULL +#define __free_from_pool(cpu_addr, size) 0 +#define __free_from_contiguous(dev, page, size) do { } while (0) +#define __dma_free_remap(cpu_addr, size) do { } while (0) #endif /* CONFIG_MMU */ -static void * -__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, - pgprot_t prot, const void *caller) +static void *__alloc_simple_buffer(struct device *dev, size_t size, gfp_t gfp, + struct page **ret_page) +{ + struct page *page; + page = __dma_alloc_buffer(dev, size, gfp); + if (!page) + return NULL; + + *ret_page = page; + return page_address(page); +} + + + +static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, + gfp_t gfp, pgprot_t prot, const void *caller) { + u64 mask = get_coherent_dma_mask(dev); struct page *page; void *addr; +#ifdef CONFIG_DMA_API_DEBUG + u64 limit = (mask + 1) & ~mask; + if (limit && size >= limit) { + dev_warn(dev, "coherent allocation too big (requested %#x mask %#llx)\n", + size, mask); + return NULL; + } +#endif + + if (!mask) + return NULL; + + if (mask < 0xffffffffULL) + gfp |= GFP_DMA; + /* * Following is a work-around (a.k.a. hack) to prevent pages * with __GFP_COMP being passed to split_page() which cannot @@ -342,22 +699,20 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, */ gfp &= ~(__GFP_COMP); - *handle = ~0; + *handle = DMA_ERROR_CODE; size = PAGE_ALIGN(size); - page = __dma_alloc_buffer(dev, size, gfp); - if (!page) - return NULL; - - if (!arch_is_coherent()) - addr = __dma_alloc_remap(page, size, gfp, prot, caller); + if (arch_is_coherent() || nommu()) + addr = __alloc_simple_buffer(dev, size, gfp, &page); + else if (cpu_architecture() < CPU_ARCH_ARMv6) + addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); + else if (gfp & GFP_ATOMIC) + addr = __alloc_from_pool(dev, size, &page, caller); else - addr = page_address(page); + addr = __alloc_from_contiguous(dev, size, prot, &page); if (addr) *handle = pfn_to_dma(dev, page_to_pfn(page)); - else - __dma_free_buffer(page, size); return addr; } @@ -366,138 +721,71 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, * Allocate DMA-coherent memory space and return both the kernel remapped * virtual and bus address for that space. */ -void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) +void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, + gfp_t gfp, struct dma_attrs *attrs) { + pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel); void *memory; if (dma_alloc_from_coherent(dev, size, handle, &memory)) return memory; - return __dma_alloc(dev, size, handle, gfp, - pgprot_dmacoherent(pgprot_kernel), + return __dma_alloc(dev, size, handle, gfp, prot, __builtin_return_address(0)); } -EXPORT_SYMBOL(dma_alloc_coherent); /* - * Allocate a writecombining region, in much the same way as - * dma_alloc_coherent above. + * Create userspace mapping for the DMA-coherent memory. */ -void * -dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) -{ - return __dma_alloc(dev, size, handle, gfp, - pgprot_writecombine(pgprot_kernel), - __builtin_return_address(0)); -} -EXPORT_SYMBOL(dma_alloc_writecombine); - -static int dma_mmap(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size) +int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) { int ret = -ENXIO; #ifdef CONFIG_MMU - unsigned long user_size, kern_size; - struct arm_vmregion *c; + unsigned long pfn = dma_to_pfn(dev, dma_addr); + vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); - user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) + return ret; - c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr); - if (c) { - unsigned long off = vma->vm_pgoff; - - kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT; - - if (off < kern_size && - user_size <= (kern_size - off)) { - ret = remap_pfn_range(vma, vma->vm_start, - page_to_pfn(c->vm_pages) + off, - user_size << PAGE_SHIFT, - vma->vm_page_prot); - } - } + ret = remap_pfn_range(vma, vma->vm_start, + pfn + vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); #endif /* CONFIG_MMU */ return ret; } -int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size) -{ - vma->vm_page_prot = pgprot_dmacoherent(vma->vm_page_prot); - return dma_mmap(dev, vma, cpu_addr, dma_addr, size); -} -EXPORT_SYMBOL(dma_mmap_coherent); - -int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size) -{ - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - return dma_mmap(dev, vma, cpu_addr, dma_addr, size); -} -EXPORT_SYMBOL(dma_mmap_writecombine); - /* - * free a page as defined by the above mapping. - * Must not be called with IRQs disabled. + * Free a buffer as defined by the above mapping. */ -void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle) +void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle, struct dma_attrs *attrs) { - WARN_ON(irqs_disabled()); + struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); if (dma_release_from_coherent(dev, get_order(size), cpu_addr)) return; size = PAGE_ALIGN(size); - if (!arch_is_coherent()) + if (arch_is_coherent() || nommu()) { + __dma_free_buffer(page, size); + } else if (cpu_architecture() < CPU_ARCH_ARMv6) { __dma_free_remap(cpu_addr, size); - - __dma_free_buffer(pfn_to_page(dma_to_pfn(dev, handle)), size); -} -EXPORT_SYMBOL(dma_free_coherent); - -/* - * Make an area consistent for devices. - * Note: Drivers should NOT use this function directly, as it will break - * platforms with CONFIG_DMABOUNCE. - * Use the driver DMA support - see dma-mapping.h (dma_sync_*) - */ -void ___dma_single_cpu_to_dev(const void *kaddr, size_t size, - enum dma_data_direction dir) -{ - unsigned long paddr; - - BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); - - dmac_map_area(kaddr, size, dir); - - paddr = __pa(kaddr); - if (dir == DMA_FROM_DEVICE) { - outer_inv_range(paddr, paddr + size); + __dma_free_buffer(page, size); } else { - outer_clean_range(paddr, paddr + size); - } - /* FIXME: non-speculating: flush on bidirectional mappings? */ -} -EXPORT_SYMBOL(___dma_single_cpu_to_dev); - -void ___dma_single_dev_to_cpu(const void *kaddr, size_t size, - enum dma_data_direction dir) -{ - BUG_ON(!virt_addr_valid(kaddr) || !virt_addr_valid(kaddr + size - 1)); - - /* FIXME: non-speculating: not required */ - /* don't bother invalidating if DMA to device */ - if (dir != DMA_TO_DEVICE) { - unsigned long paddr = __pa(kaddr); - outer_inv_range(paddr, paddr + size); + if (__free_from_pool(cpu_addr, size)) + return; + /* + * Non-atomic allocations cannot be freed with IRQs disabled + */ + WARN_ON(irqs_disabled()); + __free_from_contiguous(dev, page, size); } - - dmac_unmap_area(kaddr, size, dir); } -EXPORT_SYMBOL(___dma_single_dev_to_cpu); static void dma_cache_maint_page(struct page *page, unsigned long offset, size_t size, enum dma_data_direction dir, @@ -543,7 +831,13 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, } while (left); } -void ___dma_page_cpu_to_dev(struct page *page, unsigned long off, +/* + * Make an area consistent for devices. + * Note: Drivers should NOT use this function directly, as it will break + * platforms with CONFIG_DMABOUNCE. + * Use the driver DMA support - see dma-mapping.h (dma_sync_*) + */ +static void __dma_page_cpu_to_dev(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { unsigned long paddr; @@ -558,9 +852,8 @@ void ___dma_page_cpu_to_dev(struct page *page, unsigned long off, } /* FIXME: non-speculating: flush on bidirectional mappings? */ } -EXPORT_SYMBOL(___dma_page_cpu_to_dev); -void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, +static void __dma_page_dev_to_cpu(struct page *page, unsigned long off, size_t size, enum dma_data_direction dir) { unsigned long paddr = page_to_phys(page) + off; @@ -578,10 +871,9 @@ void ___dma_page_dev_to_cpu(struct page *page, unsigned long off, if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE) set_bit(PG_dcache_clean, &page->flags); } -EXPORT_SYMBOL(___dma_page_dev_to_cpu); /** - * dma_map_sg - map a set of SG buffers for streaming mode DMA + * arm_dma_map_sg - map a set of SG buffers for streaming mode DMA * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @sg: list of buffers * @nents: number of buffers to map @@ -596,32 +888,32 @@ EXPORT_SYMBOL(___dma_page_dev_to_cpu); * Device ownership issues as mentioned for dma_map_single are the same * here. */ -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) +int arm_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) { + struct dma_map_ops *ops = get_dma_ops(dev); struct scatterlist *s; int i, j; - BUG_ON(!valid_dma_direction(dir)); - for_each_sg(sg, s, nents, i) { - s->dma_address = __dma_map_page(dev, sg_page(s), s->offset, - s->length, dir); +#ifdef CONFIG_NEED_SG_DMA_LENGTH + s->dma_length = s->length; +#endif + s->dma_address = ops->map_page(dev, sg_page(s), s->offset, + s->length, dir, attrs); if (dma_mapping_error(dev, s->dma_address)) goto bad_mapping; } - debug_dma_map_sg(dev, sg, nents, nents, dir); return nents; bad_mapping: for_each_sg(sg, s, i, j) - __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); + ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs); return 0; } -EXPORT_SYMBOL(dma_map_sg); /** - * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg + * arm_dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @sg: list of buffers * @nents: number of buffers to unmap (same as was passed to dma_map_sg) @@ -630,70 +922,55 @@ EXPORT_SYMBOL(dma_map_sg); * Unmap a set of streaming mode DMA translations. Again, CPU access * rules concerning calls here are the same as for dma_unmap_single(). */ -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) +void arm_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) { + struct dma_map_ops *ops = get_dma_ops(dev); struct scatterlist *s; - int i; - debug_dma_unmap_sg(dev, sg, nents, dir); + int i; for_each_sg(sg, s, nents, i) - __dma_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir); + ops->unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, attrs); } -EXPORT_SYMBOL(dma_unmap_sg); /** - * dma_sync_sg_for_cpu + * arm_dma_sync_sg_for_cpu * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @sg: list of buffers * @nents: number of buffers to map (returned from dma_map_sg) * @dir: DMA transfer direction (same as was passed to dma_map_sg) */ -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, +void arm_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir) { + struct dma_map_ops *ops = get_dma_ops(dev); struct scatterlist *s; int i; - for_each_sg(sg, s, nents, i) { - if (!dmabounce_sync_for_cpu(dev, sg_dma_address(s), 0, - sg_dma_len(s), dir)) - continue; - - __dma_page_dev_to_cpu(sg_page(s), s->offset, - s->length, dir); - } - - debug_dma_sync_sg_for_cpu(dev, sg, nents, dir); + for_each_sg(sg, s, nents, i) + ops->sync_single_for_cpu(dev, sg_dma_address(s), s->length, + dir); } -EXPORT_SYMBOL(dma_sync_sg_for_cpu); /** - * dma_sync_sg_for_device + * arm_dma_sync_sg_for_device * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @sg: list of buffers * @nents: number of buffers to map (returned from dma_map_sg) * @dir: DMA transfer direction (same as was passed to dma_map_sg) */ -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, +void arm_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir) { + struct dma_map_ops *ops = get_dma_ops(dev); struct scatterlist *s; int i; - for_each_sg(sg, s, nents, i) { - if (!dmabounce_sync_for_device(dev, sg_dma_address(s), 0, - sg_dma_len(s), dir)) - continue; - - __dma_page_cpu_to_dev(sg_page(s), s->offset, - s->length, dir); - } - - debug_dma_sync_sg_for_device(dev, sg, nents, dir); + for_each_sg(sg, s, nents, i) + ops->sync_single_for_device(dev, sg_dma_address(s), s->length, + dir); } -EXPORT_SYMBOL(dma_sync_sg_for_device); /* * Return whether the given device DMA address mask can be supported @@ -709,18 +986,15 @@ int dma_supported(struct device *dev, u64 mask) } EXPORT_SYMBOL(dma_supported); -int dma_set_mask(struct device *dev, u64 dma_mask) +static int arm_dma_set_mask(struct device *dev, u64 dma_mask) { if (!dev->dma_mask || !dma_supported(dev, dma_mask)) return -EIO; -#ifndef CONFIG_DMABOUNCE *dev->dma_mask = dma_mask; -#endif return 0; } -EXPORT_SYMBOL(dma_set_mask); #define PREALLOC_DMA_DEBUG_ENTRIES 4096 @@ -733,3 +1007,679 @@ static int __init dma_debug_do_init(void) return 0; } fs_initcall(dma_debug_do_init); + +#ifdef CONFIG_ARM_DMA_USE_IOMMU + +/* IOMMU */ + +static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, + size_t size) +{ + unsigned int order = get_order(size); + unsigned int align = 0; + unsigned int count, start; + unsigned long flags; + + count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) + + (1 << mapping->order) - 1) >> mapping->order; + + if (order > mapping->order) + align = (1 << (order - mapping->order)) - 1; + + spin_lock_irqsave(&mapping->lock, flags); + start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0, + count, align); + if (start > mapping->bits) { + spin_unlock_irqrestore(&mapping->lock, flags); + return DMA_ERROR_CODE; + } + + bitmap_set(mapping->bitmap, start, count); + spin_unlock_irqrestore(&mapping->lock, flags); + + return mapping->base + (start << (mapping->order + PAGE_SHIFT)); +} + +static inline void __free_iova(struct dma_iommu_mapping *mapping, + dma_addr_t addr, size_t size) +{ + unsigned int start = (addr - mapping->base) >> + (mapping->order + PAGE_SHIFT); + unsigned int count = ((size >> PAGE_SHIFT) + + (1 << mapping->order) - 1) >> mapping->order; + unsigned long flags; + + spin_lock_irqsave(&mapping->lock, flags); + bitmap_clear(mapping->bitmap, start, count); + spin_unlock_irqrestore(&mapping->lock, flags); +} + +static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, gfp_t gfp) +{ + struct page **pages; + int count = size >> PAGE_SHIFT; + int array_size = count * sizeof(struct page *); + int i = 0; + + if (array_size <= PAGE_SIZE) + pages = kzalloc(array_size, gfp); + else + pages = vzalloc(array_size); + if (!pages) + return NULL; + + while (count) { + int j, order = __ffs(count); + + pages[i] = alloc_pages(gfp | __GFP_NOWARN, order); + while (!pages[i] && order) + pages[i] = alloc_pages(gfp | __GFP_NOWARN, --order); + if (!pages[i]) + goto error; + + if (order) + split_page(pages[i], order); + j = 1 << order; + while (--j) + pages[i + j] = pages[i] + j; + + __dma_clear_buffer(pages[i], PAGE_SIZE << order); + i += 1 << order; + count -= 1 << order; + } + + return pages; +error: + while (--i) + if (pages[i]) + __free_pages(pages[i], 0); + if (array_size < PAGE_SIZE) + kfree(pages); + else + vfree(pages); + return NULL; +} + +static int __iommu_free_buffer(struct device *dev, struct page **pages, size_t size) +{ + int count = size >> PAGE_SHIFT; + int array_size = count * sizeof(struct page *); + int i; + for (i = 0; i < count; i++) + if (pages[i]) + __free_pages(pages[i], 0); + if (array_size < PAGE_SIZE) + kfree(pages); + else + vfree(pages); + return 0; +} + +/* + * Create a CPU mapping for a specified pages + */ +static void * +__iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot) +{ + struct arm_vmregion *c; + size_t align; + size_t count = size >> PAGE_SHIFT; + int bit; + + if (!consistent_pte[0]) { + pr_err("%s: not initialised\n", __func__); + dump_stack(); + return NULL; + } + + /* + * Align the virtual region allocation - maximum alignment is + * a section size, minimum is a page size. This helps reduce + * fragmentation of the DMA space, and also prevents allocations + * smaller than a section from crossing a section boundary. + */ + bit = fls(size - 1); + if (bit > SECTION_SHIFT) + bit = SECTION_SHIFT; + align = 1 << bit; + + /* + * Allocate a virtual address in the consistent mapping region. + */ + c = arm_vmregion_alloc(&consistent_head, align, size, + gfp & ~(__GFP_DMA | __GFP_HIGHMEM), NULL); + if (c) { + pte_t *pte; + int idx = CONSISTENT_PTE_INDEX(c->vm_start); + int i = 0; + u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1); + + pte = consistent_pte[idx] + off; + c->priv = pages; + + do { + BUG_ON(!pte_none(*pte)); + + set_pte_ext(pte, mk_pte(pages[i], prot), 0); + pte++; + off++; + i++; + if (off >= PTRS_PER_PTE) { + off = 0; + pte = consistent_pte[++idx]; + } + } while (i < count); + + dsb(); + + return (void *)c->vm_start; + } + return NULL; +} + +/* + * Create a mapping in device IO address space for specified pages + */ +static dma_addr_t +__iommu_create_mapping(struct device *dev, struct page **pages, size_t size) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + dma_addr_t dma_addr, iova; + int i, ret = DMA_ERROR_CODE; + + dma_addr = __alloc_iova(mapping, size); + if (dma_addr == DMA_ERROR_CODE) + return dma_addr; + + iova = dma_addr; + for (i = 0; i < count; ) { + unsigned int next_pfn = page_to_pfn(pages[i]) + 1; + phys_addr_t phys = page_to_phys(pages[i]); + unsigned int len, j; + + for (j = i + 1; j < count; j++, next_pfn++) + if (page_to_pfn(pages[j]) != next_pfn) + break; + + len = (j - i) << PAGE_SHIFT; + ret = iommu_map(mapping->domain, iova, phys, len, 0); + if (ret < 0) + goto fail; + iova += len; + i = j; + } + return dma_addr; +fail: + iommu_unmap(mapping->domain, dma_addr, iova-dma_addr); + __free_iova(mapping, dma_addr, size); + return DMA_ERROR_CODE; +} + +static int __iommu_remove_mapping(struct device *dev, dma_addr_t iova, size_t size) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + + /* + * add optional in-page offset from iova to size and align + * result to page size + */ + size = PAGE_ALIGN((iova & ~PAGE_MASK) + size); + iova &= PAGE_MASK; + + iommu_unmap(mapping->domain, iova, size); + __free_iova(mapping, iova, size); + return 0; +} + +static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, + dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) +{ + pgprot_t prot = __get_dma_pgprot(attrs, pgprot_kernel); + struct page **pages; + void *addr = NULL; + + *handle = DMA_ERROR_CODE; + size = PAGE_ALIGN(size); + + pages = __iommu_alloc_buffer(dev, size, gfp); + if (!pages) + return NULL; + + *handle = __iommu_create_mapping(dev, pages, size); + if (*handle == DMA_ERROR_CODE) + goto err_buffer; + + addr = __iommu_alloc_remap(pages, size, gfp, prot); + if (!addr) + goto err_mapping; + + return addr; + +err_mapping: + __iommu_remove_mapping(dev, *handle, size); +err_buffer: + __iommu_free_buffer(dev, pages, size); + return NULL; +} + +static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) +{ + struct arm_vmregion *c; + + vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot); + c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr); + + if (c) { + struct page **pages = c->priv; + + unsigned long uaddr = vma->vm_start; + unsigned long usize = vma->vm_end - vma->vm_start; + int i = 0; + + do { + int ret; + + ret = vm_insert_page(vma, uaddr, pages[i++]); + if (ret) { + pr_err("Remapping memory, error: %d\n", ret); + return ret; + } + + uaddr += PAGE_SIZE; + usize -= PAGE_SIZE; + } while (usize > 0); + } + return 0; +} + +/* + * free a page as defined by the above mapping. + * Must not be called with IRQs disabled. + */ +void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle, struct dma_attrs *attrs) +{ + struct arm_vmregion *c; + size = PAGE_ALIGN(size); + + c = arm_vmregion_find(&consistent_head, (unsigned long)cpu_addr); + if (c) { + struct page **pages = c->priv; + __dma_free_remap(cpu_addr, size); + __iommu_remove_mapping(dev, handle, size); + __iommu_free_buffer(dev, pages, size); + } +} + +/* + * Map a part of the scatter-gather list into contiguous io address space + */ +static int __map_sg_chunk(struct device *dev, struct scatterlist *sg, + size_t size, dma_addr_t *handle, + enum dma_data_direction dir) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + dma_addr_t iova, iova_base; + int ret = 0; + unsigned int count; + struct scatterlist *s; + + size = PAGE_ALIGN(size); + *handle = DMA_ERROR_CODE; + + iova_base = iova = __alloc_iova(mapping, size); + if (iova == DMA_ERROR_CODE) + return -ENOMEM; + + for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) { + phys_addr_t phys = page_to_phys(sg_page(s)); + unsigned int len = PAGE_ALIGN(s->offset + s->length); + + if (!arch_is_coherent()) + __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); + + ret = iommu_map(mapping->domain, iova, phys, len, 0); + if (ret < 0) + goto fail; + count += len >> PAGE_SHIFT; + iova += len; + } + *handle = iova_base; + + return 0; +fail: + iommu_unmap(mapping->domain, iova_base, count * PAGE_SIZE); + __free_iova(mapping, iova_base, size); + return ret; +} + +/** + * arm_iommu_map_sg - map a set of SG buffers for streaming mode DMA + * @dev: valid struct device pointer + * @sg: list of buffers + * @nents: number of buffers to map + * @dir: DMA transfer direction + * + * Map a set of buffers described by scatterlist in streaming mode for DMA. + * The scatter gather list elements are merged together (if possible) and + * tagged with the appropriate dma address and length. They are obtained via + * sg_dma_{address,length}. + */ +int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + struct scatterlist *s = sg, *dma = sg, *start = sg; + int i, count = 0; + unsigned int offset = s->offset; + unsigned int size = s->offset + s->length; + unsigned int max = dma_get_max_seg_size(dev); + + for (i = 1; i < nents; i++) { + s = sg_next(s); + + s->dma_address = DMA_ERROR_CODE; + s->dma_length = 0; + + if (s->offset || (size & ~PAGE_MASK) || size + s->length > max) { + if (__map_sg_chunk(dev, start, size, &dma->dma_address, + dir) < 0) + goto bad_mapping; + + dma->dma_address += offset; + dma->dma_length = size - offset; + + size = offset = s->offset; + start = s; + dma = sg_next(dma); + count += 1; + } + size += s->length; + } + if (__map_sg_chunk(dev, start, size, &dma->dma_address, dir) < 0) + goto bad_mapping; + + dma->dma_address += offset; + dma->dma_length = size - offset; + + return count+1; + +bad_mapping: + for_each_sg(sg, s, count, i) + __iommu_remove_mapping(dev, sg_dma_address(s), sg_dma_len(s)); + return 0; +} + +/** + * arm_iommu_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg + * @dev: valid struct device pointer + * @sg: list of buffers + * @nents: number of buffers to unmap (same as was passed to dma_map_sg) + * @dir: DMA transfer direction (same as was passed to dma_map_sg) + * + * Unmap a set of streaming mode DMA translations. Again, CPU access + * rules concerning calls here are the same as for dma_unmap_single(). + */ +void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) { + if (sg_dma_len(s)) + __iommu_remove_mapping(dev, sg_dma_address(s), + sg_dma_len(s)); + if (!arch_is_coherent()) + __dma_page_dev_to_cpu(sg_page(s), s->offset, + s->length, dir); + } +} + +/** + * arm_iommu_sync_sg_for_cpu + * @dev: valid struct device pointer + * @sg: list of buffers + * @nents: number of buffers to map (returned from dma_map_sg) + * @dir: DMA transfer direction (same as was passed to dma_map_sg) + */ +void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) + if (!arch_is_coherent()) + __dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir); + +} + +/** + * arm_iommu_sync_sg_for_device + * @dev: valid struct device pointer + * @sg: list of buffers + * @nents: number of buffers to map (returned from dma_map_sg) + * @dir: DMA transfer direction (same as was passed to dma_map_sg) + */ +void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) + if (!arch_is_coherent()) + __dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir); +} + + +/** + * arm_iommu_map_page + * @dev: valid struct device pointer + * @page: page that buffer resides in + * @offset: offset into page for start of buffer + * @size: size of buffer to map + * @dir: DMA transfer direction + * + * IOMMU aware version of arm_dma_map_page() + */ +static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + dma_addr_t dma_addr; + int ret, len = PAGE_ALIGN(size + offset); + + if (!arch_is_coherent()) + __dma_page_cpu_to_dev(page, offset, size, dir); + + dma_addr = __alloc_iova(mapping, len); + if (dma_addr == DMA_ERROR_CODE) + return dma_addr; + + ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, 0); + if (ret < 0) + goto fail; + + return dma_addr + offset; +fail: + __free_iova(mapping, dma_addr, len); + return DMA_ERROR_CODE; +} + +/** + * arm_iommu_unmap_page + * @dev: valid struct device pointer + * @handle: DMA address of buffer + * @size: size of buffer (same as passed to dma_map_page) + * @dir: DMA transfer direction (same as passed to dma_map_page) + * + * IOMMU aware version of arm_dma_unmap_page() + */ +static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + dma_addr_t iova = handle & PAGE_MASK; + struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); + int offset = handle & ~PAGE_MASK; + int len = PAGE_ALIGN(size + offset); + + if (!iova) + return; + + if (!arch_is_coherent()) + __dma_page_dev_to_cpu(page, offset, size, dir); + + iommu_unmap(mapping->domain, iova, len); + __free_iova(mapping, iova, len); +} + +static void arm_iommu_sync_single_for_cpu(struct device *dev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + dma_addr_t iova = handle & PAGE_MASK; + struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); + unsigned int offset = handle & ~PAGE_MASK; + + if (!iova) + return; + + if (!arch_is_coherent()) + __dma_page_dev_to_cpu(page, offset, size, dir); +} + +static void arm_iommu_sync_single_for_device(struct device *dev, + dma_addr_t handle, size_t size, enum dma_data_direction dir) +{ + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + dma_addr_t iova = handle & PAGE_MASK; + struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova)); + unsigned int offset = handle & ~PAGE_MASK; + + if (!iova) + return; + + __dma_page_cpu_to_dev(page, offset, size, dir); +} + +struct dma_map_ops iommu_ops = { + .alloc = arm_iommu_alloc_attrs, + .free = arm_iommu_free_attrs, + .mmap = arm_iommu_mmap_attrs, + + .map_page = arm_iommu_map_page, + .unmap_page = arm_iommu_unmap_page, + .sync_single_for_cpu = arm_iommu_sync_single_for_cpu, + .sync_single_for_device = arm_iommu_sync_single_for_device, + + .map_sg = arm_iommu_map_sg, + .unmap_sg = arm_iommu_unmap_sg, + .sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu, + .sync_sg_for_device = arm_iommu_sync_sg_for_device, +}; + +/** + * arm_iommu_create_mapping + * @bus: pointer to the bus holding the client device (for IOMMU calls) + * @base: start address of the valid IO address space + * @size: size of the valid IO address space + * @order: accuracy of the IO addresses allocations + * + * Creates a mapping structure which holds information about used/unused + * IO address ranges, which is required to perform memory allocation and + * mapping with IOMMU aware functions. + * + * The client device need to be attached to the mapping with + * arm_iommu_attach_device function. + */ +struct dma_iommu_mapping * +arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size, + int order) +{ + unsigned int count = size >> (PAGE_SHIFT + order); + unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long); + struct dma_iommu_mapping *mapping; + int err = -ENOMEM; + + if (!count) + return ERR_PTR(-EINVAL); + + mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL); + if (!mapping) + goto err; + + mapping->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!mapping->bitmap) + goto err2; + + mapping->base = base; + mapping->bits = BITS_PER_BYTE * bitmap_size; + mapping->order = order; + spin_lock_init(&mapping->lock); + + mapping->domain = iommu_domain_alloc(bus); + if (!mapping->domain) + goto err3; + + kref_init(&mapping->kref); + return mapping; +err3: + kfree(mapping->bitmap); +err2: + kfree(mapping); +err: + return ERR_PTR(err); +} + +static void release_iommu_mapping(struct kref *kref) +{ + struct dma_iommu_mapping *mapping = + container_of(kref, struct dma_iommu_mapping, kref); + + iommu_domain_free(mapping->domain); + kfree(mapping->bitmap); + kfree(mapping); +} + +void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping) +{ + if (mapping) + kref_put(&mapping->kref, release_iommu_mapping); +} + +/** + * arm_iommu_attach_device + * @dev: valid struct device pointer + * @mapping: io address space mapping structure (returned from + * arm_iommu_create_mapping) + * + * Attaches specified io address space mapping to the provided device, + * this replaces the dma operations (dma_map_ops pointer) with the + * IOMMU aware version. More than one client might be attached to + * the same io address space mapping. + */ +int arm_iommu_attach_device(struct device *dev, + struct dma_iommu_mapping *mapping) +{ + int err; + + err = iommu_attach_device(mapping->domain, dev); + if (err) + return err; + + kref_get(&mapping->kref); + dev->archdata.mapping = mapping; + set_dma_ops(dev, &iommu_ops); + + pr_info("Attached IOMMU controller to %s device.\n", dev_name(dev)); + return 0; +} + +#endif diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 8f5813bbffb5..c21d06c7dd7e 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -20,6 +20,7 @@ #include <linux/highmem.h> #include <linux/gfp.h> #include <linux/memblock.h> +#include <linux/dma-contiguous.h> #include <asm/mach-types.h> #include <asm/memblock.h> @@ -226,6 +227,17 @@ static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole, } #endif +void __init setup_dma_zone(struct machine_desc *mdesc) +{ +#ifdef CONFIG_ZONE_DMA + if (mdesc->dma_zone_size) { + arm_dma_zone_size = mdesc->dma_zone_size; + arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1; + } else + arm_dma_limit = 0xffffffff; +#endif +} + static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, unsigned long max_high) { @@ -273,12 +285,9 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, * Adjust the sizes according to any special requirements for * this machine type. */ - if (arm_dma_zone_size) { + if (arm_dma_zone_size) arm_adjust_dma_zone(zone_size, zhole_size, arm_dma_zone_size >> PAGE_SHIFT); - arm_dma_limit = PHYS_OFFSET + arm_dma_zone_size - 1; - } else - arm_dma_limit = 0xffffffff; #endif free_area_init_node(0, zone_size, min, zhole_size); @@ -364,6 +373,12 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) if (mdesc->reserve) mdesc->reserve(); + /* + * reserve memory for DMA contigouos allocations, + * must come from DMA area inside low memory + */ + dma_contiguous_reserve(min(arm_dma_limit, arm_lowmem_limit)); + arm_memblock_steal_permitted = false; memblock_allow_resize(); memblock_dump_all(); diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index 27f4a619b35d..93dc0c17cdcb 100644 --- a/arch/arm/mm/mm.h +++ b/arch/arm/mm/mm.h @@ -67,5 +67,8 @@ extern u32 arm_dma_limit; #define arm_dma_limit ((u32)~0) #endif +extern phys_addr_t arm_lowmem_limit; + void __init bootmem_init(void); void arm_mm_memblock_reserve(void); +void dma_contiguous_remap(void); diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index aa78de8bfdd3..e5dad60b558b 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -288,6 +288,11 @@ static struct mem_type mem_types[] = { PMD_SECT_UNCACHED | PMD_SECT_XN, .domain = DOMAIN_KERNEL, }, + [MT_MEMORY_DMA_READY] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY, + .prot_l1 = PMD_TYPE_TABLE, + .domain = DOMAIN_KERNEL, + }, }; const struct mem_type *get_mem_type(unsigned int type) @@ -429,6 +434,7 @@ static void __init build_mem_type_table(void) if (arch_is_coherent() && cpu_is_xsc3()) { mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED; + mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED; mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED; } @@ -460,6 +466,7 @@ static void __init build_mem_type_table(void) mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED; mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED; + mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED; mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S; mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED; } @@ -512,6 +519,7 @@ static void __init build_mem_type_table(void) mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask; mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd; mem_types[MT_MEMORY].prot_pte |= kern_pgprot; + mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot; mem_types[MT_MEMORY_NONCACHED].prot_sect |= ecc_mask; mem_types[MT_ROM].prot_sect |= cp->pmd; @@ -596,7 +604,7 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr, * L1 entries, whereas PGDs refer to a group of L1 entries making * up one logical pointer to an L2 table. */ - if (((addr | end | phys) & ~SECTION_MASK) == 0) { + if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) { pmd_t *p = pmd; #ifndef CONFIG_ARM_LPAE @@ -814,7 +822,7 @@ static int __init early_vmalloc(char *arg) } early_param("vmalloc", early_vmalloc); -static phys_addr_t lowmem_limit __initdata = 0; +phys_addr_t arm_lowmem_limit __initdata = 0; void __init sanity_check_meminfo(void) { @@ -897,8 +905,8 @@ void __init sanity_check_meminfo(void) bank->size = newsize; } #endif - if (!bank->highmem && bank->start + bank->size > lowmem_limit) - lowmem_limit = bank->start + bank->size; + if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit) + arm_lowmem_limit = bank->start + bank->size; j++; } @@ -923,8 +931,8 @@ void __init sanity_check_meminfo(void) } #endif meminfo.nr_banks = j; - high_memory = __va(lowmem_limit - 1) + 1; - memblock_set_current_limit(lowmem_limit); + high_memory = __va(arm_lowmem_limit - 1) + 1; + memblock_set_current_limit(arm_lowmem_limit); } static inline void prepare_page_table(void) @@ -949,8 +957,8 @@ static inline void prepare_page_table(void) * Find the end of the first block of lowmem. */ end = memblock.memory.regions[0].base + memblock.memory.regions[0].size; - if (end >= lowmem_limit) - end = lowmem_limit; + if (end >= arm_lowmem_limit) + end = arm_lowmem_limit; /* * Clear out all the kernel space mappings, except for the first @@ -1093,8 +1101,8 @@ static void __init map_lowmem(void) phys_addr_t end = start + reg->size; struct map_desc map; - if (end > lowmem_limit) - end = lowmem_limit; + if (end > arm_lowmem_limit) + end = arm_lowmem_limit; if (start >= end) break; @@ -1115,11 +1123,12 @@ void __init paging_init(struct machine_desc *mdesc) { void *zero_page; - memblock_set_current_limit(lowmem_limit); + memblock_set_current_limit(arm_lowmem_limit); build_mem_type_table(); prepare_page_table(); map_lowmem(); + dma_contiguous_remap(); devicemaps_init(mdesc); kmap_init(); diff --git a/arch/arm/mm/vmregion.h b/arch/arm/mm/vmregion.h index 162be662c088..bf312c354a21 100644 --- a/arch/arm/mm/vmregion.h +++ b/arch/arm/mm/vmregion.h @@ -17,7 +17,7 @@ struct arm_vmregion { struct list_head vm_list; unsigned long vm_start; unsigned long vm_end; - struct page *vm_pages; + void *priv; int vm_active; const void *caller; }; diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index 2ed3ab173add..5079787273d2 100644 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -41,6 +41,7 @@ #include <mach/clock.h> #include <mach/hardware.h> +#ifndef CONFIG_COMMON_CLK static LIST_HEAD(clocks); static DEFINE_MUTEX(clocks_mutex); @@ -200,6 +201,16 @@ struct clk *clk_get_parent(struct clk *clk) } EXPORT_SYMBOL(clk_get_parent); +#else + +/* + * Lock to protect the clock module (ccm) registers. Used + * on all i.MXs + */ +DEFINE_SPINLOCK(imx_ccm_lock); + +#endif /* CONFIG_COMMON_CLK */ + /* * Get the resulting clock rate from a PLL register value and the input * frequency. PLLs with this register layout can at least be found on diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h index 753a5988d85c..bd940c795cbb 100644 --- a/arch/arm/plat-mxc/include/mach/clock.h +++ b/arch/arm/plat-mxc/include/mach/clock.h @@ -23,6 +23,7 @@ #ifndef __ASSEMBLY__ #include <linux/list.h> +#ifndef CONFIG_COMMON_CLK struct module; struct clk { @@ -59,6 +60,9 @@ struct clk { int clk_register(struct clk *clk); void clk_unregister(struct clk *clk); +#endif /* CONFIG_COMMON_CLK */ + +extern spinlock_t imx_ccm_lock; unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref); diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 0319c4a0cafa..cf663d84e7c1 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -53,6 +53,7 @@ extern void imx35_soc_init(void); extern void imx50_soc_init(void); extern void imx51_soc_init(void); extern void imx53_soc_init(void); +extern void imx51_init_late(void); extern void epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq); extern void mxc_timer_init(struct clk *timer_clk, void __iomem *, int); extern int mx1_clocks_init(unsigned long fref); @@ -149,4 +150,10 @@ extern void imx6q_pm_init(void); static inline void imx6q_pm_init(void) {} #endif +#ifdef CONFIG_NEON +extern int mx51_neon_fixup(void); +#else +static inline int mx51_neon_fixup(void) { return 0; } +#endif + #endif diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S index 8ddda365f1a0..761e45f9456f 100644 --- a/arch/arm/plat-mxc/include/mach/debug-macro.S +++ b/arch/arm/plat-mxc/include/mach/debug-macro.S @@ -24,6 +24,8 @@ #define UART_PADDR MX51_UART1_BASE_ADDR #elif defined (CONFIG_DEBUG_IMX50_IMX53_UART) #define UART_PADDR MX53_UART1_BASE_ADDR +#elif defined (CONFIG_DEBUG_IMX6Q_UART2) +#define UART_PADDR MX6Q_UART2_BASE_ADDR #elif defined (CONFIG_DEBUG_IMX6Q_UART4) #define UART_PADDR MX6Q_UART4_BASE_ADDR #endif diff --git a/arch/arm/plat-mxc/include/mach/mx6q.h b/arch/arm/plat-mxc/include/mach/mx6q.h index 254a561a2799..f7e7dbac8f4b 100644 --- a/arch/arm/plat-mxc/include/mach/mx6q.h +++ b/arch/arm/plat-mxc/include/mach/mx6q.h @@ -27,6 +27,8 @@ #define MX6Q_CCM_SIZE 0x4000 #define MX6Q_ANATOP_BASE_ADDR 0x020c8000 #define MX6Q_ANATOP_SIZE 0x1000 +#define MX6Q_UART2_BASE_ADDR 0x021e8000 +#define MX6Q_UART2_SIZE 0x4000 #define MX6Q_UART4_BASE_ADDR 0x021f0000 #define MX6Q_UART4_SIZE 0x4000 diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c index 7daf7c9a413b..99f958ca6cb8 100644 --- a/arch/arm/plat-mxc/time.c +++ b/arch/arm/plat-mxc/time.c @@ -25,6 +25,7 @@ #include <linux/irq.h> #include <linux/clockchips.h> #include <linux/clk.h> +#include <linux/err.h> #include <mach/hardware.h> #include <asm/sched_clock.h> @@ -282,6 +283,19 @@ static int __init mxc_clockevent_init(struct clk *timer_clk) void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq) { uint32_t tctl_val; + struct clk *timer_ipg_clk; + + if (!timer_clk) { + timer_clk = clk_get_sys("imx-gpt.0", "per"); + if (IS_ERR(timer_clk)) { + pr_err("i.MX timer: unable to get clk\n"); + return; + } + + timer_ipg_clk = clk_get_sys("imx-gpt.0", "ipg"); + if (!IS_ERR(timer_ipg_clk)) + clk_prepare_enable(timer_ipg_clk); + } clk_prepare_enable(timer_clk); diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index 44ae077dbc28..2132c4f389e1 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c @@ -28,19 +28,20 @@ #include <plat/clock.h> +/* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */ +#define OMAP2_32KSYNCNT_CR_OFF 0x10 + /* * 32KHz clocksource ... always available, on pretty most chips except * OMAP 730 and 1510. Other timers could be used as clocksources, with * higher resolution in free-running counter modes (e.g. 12 MHz xtal), * but systems won't necessarily want to spend resources that way. */ -static void __iomem *timer_32k_base; - -#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 +static void __iomem *sync32k_cnt_reg; static u32 notrace omap_32k_read_sched_clock(void) { - return timer_32k_base ? __raw_readl(timer_32k_base) : 0; + return sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0; } /** @@ -60,7 +61,7 @@ static void omap_read_persistent_clock(struct timespec *ts) struct timespec *tsp = &persistent_ts; last_cycles = cycles; - cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; + cycles = sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0; delta = cycles - last_cycles; nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); @@ -69,55 +70,41 @@ static void omap_read_persistent_clock(struct timespec *ts) *ts = *tsp; } -int __init omap_init_clocksource_32k(void) +/** + * omap_init_clocksource_32k - setup and register counter 32k as a + * kernel clocksource + * @pbase: base addr of counter_32k module + * @size: size of counter_32k to map + * + * Returns 0 upon success or negative error code upon failure. + * + */ +int __init omap_init_clocksource_32k(void __iomem *vbase) { - static char err[] __initdata = KERN_ERR - "%s: can't register clocksource!\n"; - - if (cpu_is_omap16xx() || cpu_class_is_omap2()) { - u32 pbase; - unsigned long size = SZ_4K; - void __iomem *base; - struct clk *sync_32k_ick; - - if (cpu_is_omap16xx()) { - pbase = OMAP16XX_TIMER_32K_SYNCHRONIZED; - size = SZ_1K; - } else if (cpu_is_omap2420()) - pbase = OMAP2420_32KSYNCT_BASE + 0x10; - else if (cpu_is_omap2430()) - pbase = OMAP2430_32KSYNCT_BASE + 0x10; - else if (cpu_is_omap34xx()) - pbase = OMAP3430_32KSYNCT_BASE + 0x10; - else if (cpu_is_omap44xx()) - pbase = OMAP4430_32KSYNCT_BASE + 0x10; - else - return -ENODEV; - - /* For this to work we must have a static mapping in io.c for this area */ - base = ioremap(pbase, size); - if (!base) - return -ENODEV; - - sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); - if (!IS_ERR(sync_32k_ick)) - clk_enable(sync_32k_ick); - - timer_32k_base = base; - - /* - * 120000 rough estimate from the calculations in - * __clocksource_updatefreq_scale. - */ - clocks_calc_mult_shift(&persistent_mult, &persistent_shift, - 32768, NSEC_PER_SEC, 120000); - - if (clocksource_mmio_init(base, "32k_counter", 32768, 250, 32, - clocksource_mmio_readl_up)) - printk(err, "32k_counter"); - - setup_sched_clock(omap_32k_read_sched_clock, 32, 32768); - register_persistent_clock(NULL, omap_read_persistent_clock); + int ret; + + /* + * 32k sync Counter register offset is at 0x10 + */ + sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF; + + /* + * 120000 rough estimate from the calculations in + * __clocksource_updatefreq_scale. + */ + clocks_calc_mult_shift(&persistent_mult, &persistent_shift, + 32768, NSEC_PER_SEC, 120000); + + ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768, + 250, 32, clocksource_mmio_readl_up); + if (ret) { + pr_err("32k_counter: can't register clocksource\n"); + return ret; } + + setup_sched_clock(omap_32k_read_sched_clock, 32, 32768); + register_persistent_clock(NULL, omap_read_persistent_clock); + pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n"); + return 0; } diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 09b07d252892..1cba9273d2cb 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -28,54 +28,6 @@ #include <plat/menelaus.h> #include <plat/omap44xx.h> -#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ - defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) - -#define OMAP_MMC_NR_RES 2 - -/* - * Register MMC devices. Called from mach-omap1 and mach-omap2 device init. - */ -int __init omap_mmc_add(const char *name, int id, unsigned long base, - unsigned long size, unsigned int irq, - struct omap_mmc_platform_data *data) -{ - struct platform_device *pdev; - struct resource res[OMAP_MMC_NR_RES]; - int ret; - - pdev = platform_device_alloc(name, id); - if (!pdev) - return -ENOMEM; - - memset(res, 0, OMAP_MMC_NR_RES * sizeof(struct resource)); - res[0].start = base; - res[0].end = base + size - 1; - res[0].flags = IORESOURCE_MEM; - res[1].start = res[1].end = irq; - res[1].flags = IORESOURCE_IRQ; - - ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); - if (ret == 0) - ret = platform_device_add_data(pdev, data, sizeof(*data)); - if (ret) - goto fail; - - ret = platform_device_add(pdev); - if (ret) - goto fail; - - /* return device handle to board setup code */ - data->dev = &pdev->dev; - return 0; - -fail: - platform_device_put(pdev); - return ret; -} - -#endif - /*-------------------------------------------------------------------------*/ #if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE) @@ -109,79 +61,6 @@ static void omap_init_rng(void) static inline void omap_init_rng(void) {} #endif -/*-------------------------------------------------------------------------*/ - -/* Numbering for the SPI-capable controllers when used for SPI: - * spi = 1 - * uwire = 2 - * mmc1..2 = 3..4 - * mcbsp1..3 = 5..7 - */ - -#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE) - -#define OMAP_UWIRE_BASE 0xfffb3000 - -static struct resource uwire_resources[] = { - { - .start = OMAP_UWIRE_BASE, - .end = OMAP_UWIRE_BASE + 0x20, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device omap_uwire_device = { - .name = "omap_uwire", - .id = -1, - .num_resources = ARRAY_SIZE(uwire_resources), - .resource = uwire_resources, -}; - -static void omap_init_uwire(void) -{ - /* FIXME define and use a boot tag; not all boards will be hooking - * up devices to the microwire controller, and multi-board configs - * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway... - */ - - /* board-specific code must configure chipselects (only a few - * are normally used) and SCLK/SDI/SDO (each has two choices). - */ - (void) platform_device_register(&omap_uwire_device); -} -#else -static inline void omap_init_uwire(void) {} -#endif - -#if defined(CONFIG_TIDSPBRIDGE) || defined(CONFIG_TIDSPBRIDGE_MODULE) - -static phys_addr_t omap_dsp_phys_mempool_base; - -void __init omap_dsp_reserve_sdram_memblock(void) -{ - phys_addr_t size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE; - phys_addr_t paddr; - - if (!size) - return; - - paddr = arm_memblock_steal(size, SZ_1M); - if (!paddr) { - pr_err("%s: failed to reserve %llx bytes\n", - __func__, (unsigned long long)size); - return; - } - - omap_dsp_phys_mempool_base = paddr; -} - -phys_addr_t omap_dsp_get_mempool_base(void) -{ - return omap_dsp_phys_mempool_base; -} -EXPORT_SYMBOL(omap_dsp_get_mempool_base); -#endif - /* * This gets called after board-specific INIT_MACHINE, and initializes most * on-chip peripherals accessible on this board (except for few like USB): @@ -208,7 +87,6 @@ static int __init omap_init_devices(void) * in alphabetical order so they're easier to sort through. */ omap_init_rng(); - omap_init_uwire(); return 0; } arch_initcall(omap_init_devices); diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 987e6101267d..cb16ade437cb 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -852,7 +852,7 @@ omap_dma_set_prio_lch(int lch, unsigned char read_prio, } l = p->dma_read(CCR, lch); l &= ~((1 << 6) | (1 << 26)); - if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) + if (cpu_class_is_omap2() && !cpu_is_omap242x()) l |= ((read_prio & 0x1) << 6) | ((write_prio & 0x1) << 26); else l |= ((read_prio & 0x1) << 6); @@ -2080,7 +2080,7 @@ static int __devinit omap_system_dma_probe(struct platform_device *pdev) } } - if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) + if (cpu_class_is_omap2() && !cpu_is_omap242x()) omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, DMA_DEFAULT_FIFO_DEPTH, 0); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index c4ed35e89fbd..3b0cfeb33d05 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -82,8 +82,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, static void omap_timer_restore_context(struct omap_dm_timer *timer) { - __raw_writel(timer->context.tiocp_cfg, - timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); if (timer->revision == 1) __raw_writel(timer->context.tistat, timer->sys_stat); diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h index a557b8484e6c..d1cb6f527b7e 100644 --- a/arch/arm/plat-omap/include/plat/common.h +++ b/arch/arm/plat-omap/include/plat/common.h @@ -30,7 +30,7 @@ #include <plat/i2c.h> #include <plat/omap_hwmod.h> -extern int __init omap_init_clocksource_32k(void); +extern int __init omap_init_clocksource_32k(void __iomem *vbase); extern void __init omap_check_revision(void); diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index 4bdf14ec6747..297245dba66e 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -121,6 +121,7 @@ IS_OMAP_CLASS(16xx, 0x16) IS_OMAP_CLASS(24xx, 0x24) IS_OMAP_CLASS(34xx, 0x34) IS_OMAP_CLASS(44xx, 0x44) +IS_AM_CLASS(35xx, 0x35) IS_AM_CLASS(33xx, 0x33) IS_TI_CLASS(81xx, 0x81) @@ -148,6 +149,7 @@ IS_AM_SUBCLASS(335x, 0x335) #define cpu_is_ti81xx() 0 #define cpu_is_ti816x() 0 #define cpu_is_ti814x() 0 +#define soc_is_am35xx() 0 #define cpu_is_am33xx() 0 #define cpu_is_am335x() 0 #define cpu_is_omap44xx() 0 @@ -357,6 +359,7 @@ IS_OMAP_TYPE(3517, 0x3517) # undef cpu_is_ti81xx # undef cpu_is_ti816x # undef cpu_is_ti814x +# undef soc_is_am35xx # undef cpu_is_am33xx # undef cpu_is_am335x # define cpu_is_omap3430() is_omap3430() @@ -378,6 +381,7 @@ IS_OMAP_TYPE(3517, 0x3517) # define cpu_is_ti81xx() is_ti81xx() # define cpu_is_ti816x() is_ti816x() # define cpu_is_ti814x() is_ti814x() +# define soc_is_am35xx() is_am35xx() # define cpu_is_am33xx() is_am33xx() # define cpu_is_am335x() is_am335x() #endif @@ -433,6 +437,10 @@ IS_OMAP_TYPE(3517, 0x3517) #define TI8148_REV_ES2_0 (TI814X_CLASS | (0x1 << 8)) #define TI8148_REV_ES2_1 (TI814X_CLASS | (0x2 << 8)) +#define AM35XX_CLASS 0x35170034 +#define AM35XX_REV_ES1_0 AM35XX_CLASS +#define AM35XX_REV_ES1_1 (AM35XX_CLASS | (0x1 << 8)) + #define AM335X_CLASS 0x33500034 #define AM335X_REV_ES1_0 AM335X_CLASS diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h index 42afb4c45517..c5811d4409b0 100644 --- a/arch/arm/plat-omap/include/plat/dma.h +++ b/arch/arm/plat-omap/include/plat/dma.h @@ -312,6 +312,11 @@ #define CLEAR_CSR_ON_READ BIT(0xC) #define IS_WORD_16 BIT(0xD) +/* Defines for DMA Capabilities */ +#define DMA_HAS_TRANSPARENT_CAPS (0x1 << 18) +#define DMA_HAS_CONSTANT_FILL_CAPS (0x1 << 19) +#define DMA_HAS_DESCRIPTOR_CAPS (0x3 << 20) + enum omap_reg_offsets { GCR, GSCR, GRST1, HW_ID, diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index bdf871a84d62..5da73562e486 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -75,7 +75,6 @@ struct clk; struct timer_regs { u32 tidr; - u32 tiocp_cfg; u32 tistat; u32 tisr; u32 tier; diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h index 3e7ae0f0215f..a7754a886d42 100644 --- a/arch/arm/plat-omap/include/plat/mmc.h +++ b/arch/arm/plat-omap/include/plat/mmc.h @@ -177,9 +177,6 @@ extern void omap_mmc_notify_cover_event(struct device *dev, int slot, void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, int nr_controllers); void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data); -int omap_mmc_add(const char *name, int id, unsigned long base, - unsigned long size, unsigned int irq, - struct omap_mmc_platform_data *data); #else static inline void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, int nr_controllers) @@ -188,12 +185,6 @@ static inline void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data, static inline void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data) { } -static inline int omap_mmc_add(const char *name, int id, unsigned long base, - unsigned long size, unsigned int irq, - struct omap_mmc_platform_data *data) -{ - return 0; -} #endif diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 74daf5ed1432..61fd837624a8 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -14,15 +14,41 @@ #include <linux/dma-mapping.h> #include <linux/serial_8250.h> #include <linux/ata_platform.h> +#include <linux/clk.h> +#include <linux/clkdev.h> #include <linux/mv643xx_eth.h> #include <linux/mv643xx_i2c.h> #include <net/dsa.h> -#include <linux/spi/orion_spi.h> -#include <plat/orion_wdt.h> #include <plat/mv_xor.h> #include <plat/ehci-orion.h> #include <mach/bridge-regs.h> +/* Create a clkdev entry for a given device/clk */ +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk) +{ + struct clk_lookup *cl; + + cl = clkdev_alloc(clk, con_id, dev_id); + if (cl) + clkdev_add(cl); +} + +/* Create clkdev entries for all orion platforms except kirkwood. + Kirkwood has gated clocks for some of its peripherals, so creates + its own clkdev entries. For all the other orion devices, create + clkdev entries to the tclk. */ +void __init orion_clkdev_init(struct clk *tclk) +{ + orion_clkdev_add(NULL, "orion_spi.0", tclk); + orion_clkdev_add(NULL, "orion_spi.1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".2", tclk); + orion_clkdev_add(NULL, MV643XX_ETH_NAME ".3", tclk); + orion_clkdev_add(NULL, "orion_wdt", tclk); +} + /* Fill in the resources structure and link it into the platform device structure. There is always a memory region, and nearly always an interrupt.*/ @@ -49,6 +75,12 @@ static void fill_resources(struct platform_device *device, /***************************************************************************** * UART ****************************************************************************/ +static unsigned long __init uart_get_clk_rate(struct clk *clk) +{ + clk_prepare_enable(clk); + return clk_get_rate(clk); +} + static void __init uart_complete( struct platform_device *orion_uart, struct plat_serial8250_port *data, @@ -56,12 +88,12 @@ static void __init uart_complete( unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { data->mapbase = mapbase; data->membase = (void __iomem *)membase; data->irq = irq; - data->uartclk = uartclk; + data->uartclk = uart_get_clk_rate(clk); orion_uart->dev.platform_data = data; fill_resources(orion_uart, resources, mapbase, 0xff, irq); @@ -90,10 +122,10 @@ static struct platform_device orion_uart0 = { void __init orion_uart0_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart0, orion_uart0_data, orion_uart0_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -118,10 +150,10 @@ static struct platform_device orion_uart1 = { void __init orion_uart1_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart1, orion_uart1_data, orion_uart1_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -146,10 +178,10 @@ static struct platform_device orion_uart2 = { void __init orion_uart2_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart2, orion_uart2_data, orion_uart2_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -174,10 +206,10 @@ static struct platform_device orion_uart3 = { void __init orion_uart3_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk) + struct clk *clk) { uart_complete(&orion_uart3, orion_uart3_data, orion_uart3_resources, - membase, mapbase, irq, uartclk); + membase, mapbase, irq, clk); } /***************************************************************************** @@ -203,13 +235,11 @@ void __init orion_rtc_init(unsigned long mapbase, ****************************************************************************/ static __init void ge_complete( struct mv643xx_eth_shared_platform_data *orion_ge_shared_data, - int tclk, struct resource *orion_ge_resource, unsigned long irq, struct platform_device *orion_ge_shared, struct mv643xx_eth_platform_data *eth_data, struct platform_device *orion_ge) { - orion_ge_shared_data->t_clk = tclk; orion_ge_resource->start = irq; orion_ge_resource->end = irq; eth_data->shared = orion_ge_shared; @@ -260,12 +290,11 @@ static struct platform_device orion_ge00 = { void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge00_shared, orion_ge00_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge00_shared_data, tclk, + ge_complete(&orion_ge00_shared_data, orion_ge00_resources, irq, &orion_ge00_shared, eth_data, &orion_ge00); } @@ -313,12 +342,11 @@ static struct platform_device orion_ge01 = { void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge01_shared, orion_ge01_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge01_shared_data, tclk, + ge_complete(&orion_ge01_shared_data, orion_ge01_resources, irq, &orion_ge01_shared, eth_data, &orion_ge01); } @@ -366,12 +394,11 @@ static struct platform_device orion_ge10 = { void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge10_shared, orion_ge10_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge10_shared_data, tclk, + ge_complete(&orion_ge10_shared_data, orion_ge10_resources, irq, &orion_ge10_shared, eth_data, &orion_ge10); } @@ -419,12 +446,11 @@ static struct platform_device orion_ge11 = { void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk) + unsigned long irq_err) { fill_resources(&orion_ge11_shared, orion_ge11_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); - ge_complete(&orion_ge11_shared_data, tclk, + ge_complete(&orion_ge11_shared_data, orion_ge11_resources, irq, &orion_ge11_shared, eth_data, &orion_ge11); } @@ -521,44 +547,32 @@ void __init orion_i2c_1_init(unsigned long mapbase, /***************************************************************************** * SPI ****************************************************************************/ -static struct orion_spi_info orion_spi_plat_data; static struct resource orion_spi_resources; static struct platform_device orion_spi = { .name = "orion_spi", .id = 0, - .dev = { - .platform_data = &orion_spi_plat_data, - }, }; -static struct orion_spi_info orion_spi_1_plat_data; static struct resource orion_spi_1_resources; static struct platform_device orion_spi_1 = { .name = "orion_spi", .id = 1, - .dev = { - .platform_data = &orion_spi_1_plat_data, - }, }; /* Note: The SPI silicon core does have interrupts. However the * current Linux software driver does not use interrupts. */ -void __init orion_spi_init(unsigned long mapbase, - unsigned long tclk) +void __init orion_spi_init(unsigned long mapbase) { - orion_spi_plat_data.tclk = tclk; fill_resources(&orion_spi, &orion_spi_resources, mapbase, SZ_512 - 1, NO_IRQ); platform_device_register(&orion_spi); } -void __init orion_spi_1_init(unsigned long mapbase, - unsigned long tclk) +void __init orion_spi_1_init(unsigned long mapbase) { - orion_spi_1_plat_data.tclk = tclk; fill_resources(&orion_spi_1, &orion_spi_1_resources, mapbase, SZ_512 - 1, NO_IRQ); platform_device_register(&orion_spi_1); @@ -567,24 +581,18 @@ void __init orion_spi_1_init(unsigned long mapbase, /***************************************************************************** * Watchdog ****************************************************************************/ -static struct orion_wdt_platform_data orion_wdt_data; - static struct resource orion_wdt_resource = DEFINE_RES_MEM(TIMER_VIRT_BASE, 0x28); static struct platform_device orion_wdt_device = { .name = "orion_wdt", .id = -1, - .dev = { - .platform_data = &orion_wdt_data, - }, - .resource = &orion_wdt_resource, .num_resources = 1, + .resource = &orion_wdt_resource, }; -void __init orion_wdt_init(unsigned long tclk) +void __init orion_wdt_init(void) { - orion_wdt_data.tclk = tclk; platform_device_register(&orion_wdt_device); } diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h index a7fa005a5a0e..e00fdb213609 100644 --- a/arch/arm/plat-orion/include/plat/common.h +++ b/arch/arm/plat-orion/include/plat/common.h @@ -16,22 +16,22 @@ struct dsa_platform_data; void __init orion_uart0_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_uart1_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_uart2_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_uart3_init(unsigned int membase, resource_size_t mapbase, unsigned int irq, - unsigned int uartclk); + struct clk *clk); void __init orion_rtc_init(unsigned long mapbase, unsigned long irq); @@ -39,29 +39,26 @@ void __init orion_rtc_init(unsigned long mapbase, void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err, - int tclk); + unsigned long irq_err); void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq); + void __init orion_i2c_init(unsigned long mapbase, unsigned long irq, unsigned long freq_m); @@ -70,13 +67,11 @@ void __init orion_i2c_1_init(unsigned long mapbase, unsigned long irq, unsigned long freq_m); -void __init orion_spi_init(unsigned long mapbase, - unsigned long tclk); +void __init orion_spi_init(unsigned long mapbase); -void __init orion_spi_1_init(unsigned long mapbase, - unsigned long tclk); +void __init orion_spi_1_init(unsigned long mapbase); -void __init orion_wdt_init(unsigned long tclk); +void __init orion_wdt_init(void); void __init orion_xor0_init(unsigned long mapbase_low, unsigned long mapbase_high, @@ -106,4 +101,9 @@ void __init orion_crypto_init(unsigned long mapbase, unsigned long srambase, unsigned long sram_size, unsigned long irq); + +void __init orion_clkdev_add(const char *con_id, const char *dev_id, + struct clk *clk); + +void __init orion_clkdev_init(struct clk *tclk); #endif diff --git a/arch/arm/plat-orion/include/plat/orion_wdt.h b/arch/arm/plat-orion/include/plat/orion_wdt.h deleted file mode 100644 index 665c362a2fba..000000000000 --- a/arch/arm/plat-orion/include/plat/orion_wdt.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * arch/arm/plat-orion/include/plat/orion_wdt.h - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __PLAT_ORION_WDT_H -#define __PLAT_ORION_WDT_H - -struct orion_wdt_platform_data { - u32 tclk; /* no <linux/clk.h> support yet */ -}; - - -#endif - diff --git a/arch/arm/plat-orion/pcie.c b/arch/arm/plat-orion/pcie.c index 86dbb5bdb172..f20a321088a2 100644 --- a/arch/arm/plat-orion/pcie.c +++ b/arch/arm/plat-orion/pcie.c @@ -52,12 +52,12 @@ #define PCIE_DEBUG_SOFT_RESET (1<<20) -u32 __init orion_pcie_dev_id(void __iomem *base) +u32 orion_pcie_dev_id(void __iomem *base) { return readl(base + PCIE_DEV_ID_OFF) >> 16; } -u32 __init orion_pcie_rev(void __iomem *base) +u32 orion_pcie_rev(void __iomem *base) { return readl(base + PCIE_DEV_REV_OFF) & 0xff; } 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-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile index 2467b800cc76..9f60549c8da1 100644 --- a/arch/arm/plat-s3c24xx/Makefile +++ b/arch/arm/plat-s3c24xx/Makefile @@ -12,10 +12,7 @@ obj- := # Core files -obj-y += cpu.o obj-y += irq.o -obj-y += dev-uart.o -obj-y += clock.o obj-$(CONFIG_S3C24XX_DCLK) += clock-dclk.o obj-$(CONFIG_CPU_FREQ_S3C24XX) += cpu-freq.o @@ -23,9 +20,6 @@ obj-$(CONFIG_CPU_FREQ_S3C24XX_DEBUGFS) += cpu-freq-debugfs.o # Architecture dependent builds -obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_PM) += irq-pm.o -obj-$(CONFIG_PM) += sleep.o obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o obj-$(CONFIG_S3C24XX_DMA) += dma.o obj-$(CONFIG_S3C2410_IOTIMING) += s3c2410-iotiming.o diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c deleted file mode 100644 index 931d26d1a54b..000000000000 --- a/arch/arm/plat-s3c24xx/clock.c +++ /dev/null @@ -1,59 +0,0 @@ -/* linux/arch/arm/plat-s3c24xx/clock.c - * - * Copyright (c) 2004-2005 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C24XX Core clock control support - * - * Based on, and code from linux/arch/arm/mach-versatile/clock.c - ** - ** Copyright (C) 2004 ARM Limited. - ** Written by Deep Blue Solutions Limited. - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/clk.h> -#include <linux/io.h> - -#include <mach/hardware.h> -#include <asm/irq.h> - -#include <mach/regs-clock.h> -#include <mach/regs-gpio.h> - -#include <plat/cpu-freq.h> - -#include <plat/clock.h> -#include <plat/cpu.h> -#include <plat/pll.h> - -/* initialise all the clocks */ - -void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk, - unsigned long hclk, - unsigned long pclk) -{ - clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON), - clk_xtal.rate); - - clk_mpll.rate = fclk; - clk_h.rate = hclk; - clk_p.rate = pclk; - clk_f.rate = fclk; -} diff --git a/arch/arm/plat-s3c24xx/dev-uart.c b/arch/arm/plat-s3c24xx/dev-uart.c deleted file mode 100644 index 9ab22e662fff..000000000000 --- a/arch/arm/plat-s3c24xx/dev-uart.c +++ /dev/null @@ -1,100 +0,0 @@ -/* linux/arch/arm/plat-s3c24xx/dev-uart.c - * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * Base S3C24XX UART resource and platform device definitions - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/list.h> -#include <linux/serial_core.h> -#include <linux/platform_device.h> - -#include <asm/mach/arch.h> -#include <asm/mach/map.h> -#include <asm/mach/irq.h> -#include <mach/hardware.h> -#include <mach/map.h> - -#include <plat/devs.h> -#include <plat/regs-serial.h> - -/* Serial port registrations */ - -static struct resource s3c2410_uart0_resource[] = { - [0] = { - .start = S3C2410_PA_UART0, - .end = S3C2410_PA_UART0 + 0x3fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_S3CUART_RX0, - .end = IRQ_S3CUART_ERR0, - .flags = IORESOURCE_IRQ, - } -}; - -static struct resource s3c2410_uart1_resource[] = { - [0] = { - .start = S3C2410_PA_UART1, - .end = S3C2410_PA_UART1 + 0x3fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_S3CUART_RX1, - .end = IRQ_S3CUART_ERR1, - .flags = IORESOURCE_IRQ, - } -}; - -static struct resource s3c2410_uart2_resource[] = { - [0] = { - .start = S3C2410_PA_UART2, - .end = S3C2410_PA_UART2 + 0x3fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_S3CUART_RX2, - .end = IRQ_S3CUART_ERR2, - .flags = IORESOURCE_IRQ, - } -}; - -static struct resource s3c2410_uart3_resource[] = { - [0] = { - .start = S3C2443_PA_UART3, - .end = S3C2443_PA_UART3 + 0x3fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_S3CUART_RX3, - .end = IRQ_S3CUART_ERR3, - .flags = IORESOURCE_IRQ, - }, -}; - -struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = { - [0] = { - .resources = s3c2410_uart0_resource, - .nr_resources = ARRAY_SIZE(s3c2410_uart0_resource), - }, - [1] = { - .resources = s3c2410_uart1_resource, - .nr_resources = ARRAY_SIZE(s3c2410_uart1_resource), - }, - [2] = { - .resources = s3c2410_uart2_resource, - .nr_resources = ARRAY_SIZE(s3c2410_uart2_resource), - }, - [3] = { - .resources = s3c2410_uart3_resource, - .nr_resources = ARRAY_SIZE(s3c2410_uart3_resource), - }, -}; diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig deleted file mode 100644 index 96bea3202304..000000000000 --- a/arch/arm/plat-s5p/Kconfig +++ /dev/null @@ -1,140 +0,0 @@ -# arch/arm/plat-s5p/Kconfig -# -# Copyright (c) 2009 Samsung Electronics Co., Ltd. -# http://www.samsung.com/ -# -# Licensed under GPLv2 - -config PLAT_S5P - bool - depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) - default y - select ARM_VIC if !ARCH_EXYNOS - select ARM_GIC if ARCH_EXYNOS - select GIC_NON_BANKED if ARCH_EXYNOS4 - select NO_IOPORT - select ARCH_REQUIRE_GPIOLIB - select S3C_GPIO_TRACK - select S5P_GPIO_DRVSTR - select SAMSUNG_GPIOLIB_4BIT - select PLAT_SAMSUNG - select SAMSUNG_CLKSRC - select SAMSUNG_IRQ_VIC_TIMER - help - Base platform code for Samsung's S5P series SoC. - -config S5P_EXT_INT - bool - help - Use the external interrupts (other than GPIO interrupts.) - Note: Do not choose this for S5P6440 and S5P6450. - -config S5P_GPIO_INT - bool - help - Common code for the GPIO interrupts (other than external interrupts.) - -config S5P_HRT - bool - select SAMSUNG_DEV_PWM - help - Use the High Resolution timer support - -config S5P_DEV_UART - def_bool y - depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) - -config S5P_PM - bool - help - 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 - Internal config node to apply common S5P sleep management code. - Can be selected by S5P and newer SoCs with similar sleep procedure. - -config S5P_DEV_FIMC0 - bool - help - Compile in platform device definitions for FIMC controller 0 - -config S5P_DEV_FIMC1 - bool - help - Compile in platform device definitions for FIMC controller 1 - -config S5P_DEV_FIMC2 - bool - help - Compile in platform device definitions for FIMC controller 2 - -config S5P_DEV_FIMC3 - bool - help - Compile in platform device definitions for FIMC controller 3 - -config S5P_DEV_JPEG - bool - help - Compile in platform device definitions for JPEG codec - -config S5P_DEV_G2D - bool - help - Compile in platform device definitions for G2D device - -config S5P_DEV_FIMD0 - bool - help - Compile in platform device definitions for FIMD controller 0 - -config S5P_DEV_I2C_HDMIPHY - bool - help - Compile in platform device definitions for I2C HDMIPHY controller - -config S5P_DEV_MFC - bool - help - Compile in platform device definitions for MFC - -config S5P_DEV_ONENAND - bool - help - Compile in platform device definition for OneNAND controller - -config S5P_DEV_CSIS0 - bool - help - Compile in platform device definitions for MIPI-CSIS channel 0 - -config S5P_DEV_CSIS1 - bool - help - Compile in platform device definitions for MIPI-CSIS channel 1 - -config S5P_DEV_TV - bool - help - Compile in platform device definition for TV interface - -config S5P_DEV_USB_EHCI - bool - help - Compile in platform device definition for USB EHCI - -config S5P_SETUP_MIPIPHY - bool - help - Compile in common setup code for MIPI-CSIS and MIPI-DSIM devices diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile deleted file mode 100644 index 4bd824136659..000000000000 --- a/arch/arm/plat-s5p/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# arch/arm/plat-s5p/Makefile -# -# Copyright (c) 2009 Samsung Electronics Co., Ltd. -# http://www.samsung.com/ -# -# Licensed under GPLv2 - -obj-y := -obj-m := -obj-n := dummy.o -obj- := - -# Core files - -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 - -# devices - -obj-$(CONFIG_S5P_DEV_UART) += dev-uart.o -obj-$(CONFIG_S5P_DEV_MFC) += dev-mfc.o -obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.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/Kconfig b/arch/arm/plat-samsung/Kconfig index a0ffc77da809..a2fae4ea0936 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -13,6 +13,24 @@ config PLAT_SAMSUNG help Base platform code for all Samsung SoC based systems +config PLAT_S5P + bool + depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) + default y + select ARM_VIC if !ARCH_EXYNOS + select ARM_GIC if ARCH_EXYNOS + select GIC_NON_BANKED if ARCH_EXYNOS4 + select NO_IOPORT + select ARCH_REQUIRE_GPIOLIB + select S3C_GPIO_TRACK + select S5P_GPIO_DRVSTR + select SAMSUNG_GPIOLIB_4BIT + select PLAT_SAMSUNG + select SAMSUNG_CLKSRC + select SAMSUNG_IRQ_VIC_TIMER + help + Base platform code for Samsung's S5P series SoC. + if PLAT_SAMSUNG # boot configurations @@ -50,6 +68,14 @@ config S3C_LOWLEVEL_UART_PORT this configuration should be between zero and two. The port must have been initialised by the boot-loader before use. +# timer options + +config S5P_HRT + bool + select SAMSUNG_DEV_PWM + help + Use the High Resolution timer support + # clock options config SAMSUNG_CLKSRC @@ -58,6 +84,11 @@ config SAMSUNG_CLKSRC Select the clock code for the clksrc implementation used by newer systems such as the S3C64XX. +config S5P_CLOCK + def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) + help + Support common clock part for ARCH_S5P and ARCH_EXYNOS SoCs + # options for IRQ support config SAMSUNG_IRQ_VIC_TIMER @@ -65,6 +96,22 @@ config SAMSUNG_IRQ_VIC_TIMER help Internal configuration to build the VIC timer interrupt code. +config S5P_IRQ + def_bool (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) + help + Support common interrup part for ARCH_S5P and ARCH_EXYNOS SoCs + +config S5P_EXT_INT + bool + help + Use the external interrupts (other than GPIO interrupts.) + Note: Do not choose this for S5P6440 and S5P6450. + +config S5P_GPIO_INT + bool + help + Common code for the GPIO interrupts (other than external interrupts.) + # options for gpio configuration support config SAMSUNG_GPIOLIB_4BIT @@ -117,6 +164,12 @@ config S3C_GPIO_TRACK Internal configuration option to enable the s3c specific gpio chip tracking if the platform requires it. +# uart options + +config S5P_DEV_UART + def_bool y + depends on (ARCH_S5P64X0 || ARCH_S5PC100 || ARCH_S5PV210) + # ADC driver config S3C_ADC @@ -274,6 +327,76 @@ config SAMSUNG_DEV_BACKLIGHT help Compile in platform device definition LCD backlight with PWM Timer +config S5P_DEV_CSIS0 + bool + help + Compile in platform device definitions for MIPI-CSIS channel 0 + +config S5P_DEV_CSIS1 + bool + help + Compile in platform device definitions for MIPI-CSIS channel 1 + +config S5P_DEV_FIMC0 + bool + help + Compile in platform device definitions for FIMC controller 0 + +config S5P_DEV_FIMC1 + bool + help + Compile in platform device definitions for FIMC controller 1 + +config S5P_DEV_FIMC2 + bool + help + Compile in platform device definitions for FIMC controller 2 + +config S5P_DEV_FIMC3 + bool + help + Compile in platform device definitions for FIMC controller 3 + +config S5P_DEV_FIMD0 + bool + help + Compile in platform device definitions for FIMD controller 0 + +config S5P_DEV_G2D + bool + help + Compile in platform device definitions for G2D device + +config S5P_DEV_I2C_HDMIPHY + bool + help + Compile in platform device definitions for I2C HDMIPHY controller + +config S5P_DEV_JPEG + bool + help + Compile in platform device definitions for JPEG codec + +config S5P_DEV_MFC + bool + help + Compile in setup memory (init) code for MFC + +config S5P_DEV_ONENAND + bool + help + Compile in platform device definition for OneNAND controller + +config S5P_DEV_TV + bool + help + Compile in platform device definition for TV interface + +config S5P_DEV_USB_EHCI + bool + help + Compile in platform device definition for USB EHCI + config S3C24XX_PWM bool "PWM device support" select HAVE_PWM @@ -281,6 +404,11 @@ config S3C24XX_PWM Support for exporting the PWM timer blocks via the pwm device system +config S5P_SETUP_MIPIPHY + bool + help + Compile in common setup code for MIPI-CSIS and MIPI-DSIM devices + # DMA config S3C_DMA @@ -291,7 +419,7 @@ config S3C_DMA config SAMSUNG_DMADEV bool select DMADEVICES - select PL330_DMA if (CPU_EXYNOS4210 || CPU_S5PV210 || CPU_S5PC100 || \ + select PL330_DMA if (ARCH_EXYNOS5 || ARCH_EXYNOS4 || CPU_S5PV210 || CPU_S5PC100 || \ CPU_S5P6450 || CPU_S5P6440) select ARM_AMBA help @@ -351,6 +479,18 @@ config SAMSUNG_WAKEMASK and above. This code allows a set of interrupt to wakeup-mask mappings. See <plat/wakeup-mask.h> +config S5P_PM + bool + help + Common code for power management support on S5P and newer SoCs + Note: Do not select this for S5P6440 and S5P6450. + +config S5P_SLEEP + bool + help + Internal config node to apply common S5P sleep management code. + Can be selected by S5P and newer SoCs with similar sleep procedure. + comment "Power Domain" config SAMSUNG_PD diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 6012366f33cb..860b2db4db15 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -13,12 +13,18 @@ obj- := obj-y += init.o cpu.o obj-$(CONFIG_ARCH_USES_GETTIMEOFFSET) += time.o +obj-$(CONFIG_S5P_HRT) += s5p-time.o + obj-y += clock.o obj-y += pwm-clock.o obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o +obj-$(CONFIG_S5P_CLOCK) += s5p-clock.o obj-$(CONFIG_SAMSUNG_IRQ_VIC_TIMER) += irq-vic-timer.o +obj-$(CONFIG_S5P_IRQ) += s5p-irq.o +obj-$(CONFIG_S5P_EXT_INT) += s5p-irq-eint.o +obj-$(CONFIG_S5P_GPIO_INT) += s5p-irq-gpioint.o # ADC @@ -30,9 +36,13 @@ obj-y += platformdata.o obj-y += devs.o obj-y += dev-uart.o +obj-$(CONFIG_S5P_DEV_MFC) += s5p-dev-mfc.o +obj-$(CONFIG_S5P_DEV_UART) += s5p-dev-uart.o obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight.o +obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o + # DMA support obj-$(CONFIG_S3C_DMA) += dma.o s3c-dma-ops.o @@ -47,6 +57,9 @@ obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o +obj-$(CONFIG_S5P_PM) += s5p-pm.o s5p-irq-pm.o +obj-$(CONFIG_S5P_SLEEP) += s5p-sleep.o + # PD support obj-$(CONFIG_SAMSUNG_PD) += pd.o diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h index 787ceaca0be8..0721293fad63 100644 --- a/arch/arm/plat-samsung/include/plat/cpu.h +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -202,7 +202,7 @@ extern struct bus_type s3c2443_subsys; extern struct bus_type s3c6410_subsys; extern struct bus_type s5p64x0_subsys; extern struct bus_type s5pv210_subsys; -extern struct bus_type exynos4_subsys; +extern struct bus_type exynos_subsys; extern void (*s5pc1xx_idle)(void); diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index 2155d4af62a3..61ca2f356c52 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -133,7 +133,8 @@ 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 exynos_device_drm; extern struct platform_device samsung_asoc_dma; extern struct platform_device samsung_asoc_idma; diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index 0670f37aaaed..d384a8016b47 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -90,6 +90,7 @@ enum dma_ch { DMACH_MIPI_HSI5, DMACH_MIPI_HSI6, DMACH_MIPI_HSI7, + DMACH_DISP1, DMACH_MTOM_0, DMACH_MTOM_1, DMACH_MTOM_2, diff --git a/arch/arm/plat-samsung/include/plat/s5p-clock.h b/arch/arm/plat-samsung/include/plat/s5p-clock.h index 1de4b32f98e9..8364b4bea8b8 100644 --- a/arch/arm/plat-samsung/include/plat/s5p-clock.h +++ b/arch/arm/plat-samsung/include/plat/s5p-clock.h @@ -32,8 +32,10 @@ extern struct clk clk_48m; extern struct clk s5p_clk_27m; extern struct clk clk_fout_apll; extern struct clk clk_fout_bpll; +extern struct clk clk_fout_bpll_div2; extern struct clk clk_fout_cpll; extern struct clk clk_fout_mpll; +extern struct clk clk_fout_mpll_div2; extern struct clk clk_fout_epll; extern struct clk clk_fout_dpll; extern struct clk clk_fout_vpll; @@ -42,8 +44,10 @@ extern struct clk clk_vpll; extern struct clksrc_sources clk_src_apll; extern struct clksrc_sources clk_src_bpll; +extern struct clksrc_sources clk_src_bpll_fout; extern struct clksrc_sources clk_src_cpll; extern struct clksrc_sources clk_src_mpll; +extern struct clksrc_sources clk_src_mpll_fout; extern struct clksrc_sources clk_src_epll; extern struct clksrc_sources clk_src_dpll; 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/arm/plat-s5p/clock.c b/arch/arm/plat-samsung/s5p-clock.c index f68a9bb11948..031a61899bef 100644 --- a/arch/arm/plat-s5p/clock.c +++ b/arch/arm/plat-samsung/s5p-clock.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/clock.c - * +/* * Copyright 2009 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * @@ -68,6 +67,11 @@ struct clk clk_fout_bpll = { .id = -1, }; +struct clk clk_fout_bpll_div2 = { + .name = "fout_bpll_div2", + .id = -1, +}; + /* CPLL clock output */ struct clk clk_fout_cpll = { @@ -83,6 +87,11 @@ struct clk clk_fout_mpll = { .id = -1, }; +struct clk clk_fout_mpll_div2 = { + .name = "fout_mpll_div2", + .id = -1, +}; + /* EPLL clock output */ struct clk clk_fout_epll = { .name = "fout_epll", @@ -126,6 +135,16 @@ struct clksrc_sources clk_src_bpll = { .nr_sources = ARRAY_SIZE(clk_src_bpll_list), }; +static struct clk *clk_src_bpll_fout_list[] = { + [0] = &clk_fout_bpll_div2, + [1] = &clk_fout_bpll, +}; + +struct clksrc_sources clk_src_bpll_fout = { + .sources = clk_src_bpll_fout_list, + .nr_sources = ARRAY_SIZE(clk_src_bpll_fout_list), +}; + /* Possible clock sources for CPLL Mux */ static struct clk *clk_src_cpll_list[] = { [0] = &clk_fin_cpll, @@ -148,6 +167,16 @@ struct clksrc_sources clk_src_mpll = { .nr_sources = ARRAY_SIZE(clk_src_mpll_list), }; +static struct clk *clk_src_mpll_fout_list[] = { + [0] = &clk_fout_mpll_div2, + [1] = &clk_fout_mpll, +}; + +struct clksrc_sources clk_src_mpll_fout = { + .sources = clk_src_mpll_fout_list, + .nr_sources = ARRAY_SIZE(clk_src_mpll_fout_list), +}; + /* Possible clock sources for EPLL Mux */ static struct clk *clk_src_epll_list[] = { [0] = &clk_fin_epll, diff --git a/arch/arm/plat-s5p/dev-mfc.c b/arch/arm/plat-samsung/s5p-dev-mfc.c index a30d36b7f61b..ad6089465e2a 100644 --- a/arch/arm/plat-s5p/dev-mfc.c +++ b/arch/arm/plat-samsung/s5p-dev-mfc.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/dev-mfc.c - * +/* * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd * * Base S5P MFC resource and device definitions @@ -9,7 +8,6 @@ * published by the Free Software Foundation. */ - #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/platform_device.h> diff --git a/arch/arm/plat-s5p/dev-uart.c b/arch/arm/plat-samsung/s5p-dev-uart.c index c9308db36183..cafa3deddcc1 100644 --- a/arch/arm/plat-s5p/dev-uart.c +++ b/arch/arm/plat-samsung/s5p-dev-uart.c @@ -1,6 +1,5 @@ -/* linux/arch/arm/plat-s5p/dev-uart.c - * - * Copyright (c) 2009 Samsung Electronics Co., Ltd. +/* + * Copyright (c) 2009,2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * Base S5P UART resource and device definitions @@ -14,6 +13,7 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/list.h> +#include <linux/ioport.h> #include <linux/platform_device.h> #include <asm/mach/arch.h> @@ -26,86 +26,38 @@ /* Serial port registrations */ static struct resource s5p_uart0_resource[] = { - [0] = { - .start = S5P_PA_UART0, - .end = S5P_PA_UART0 + S5P_SZ_UART - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_UART0, - .end = IRQ_UART0, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(S5P_PA_UART0, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART0), }; static struct resource s5p_uart1_resource[] = { - [0] = { - .start = S5P_PA_UART1, - .end = S5P_PA_UART1 + S5P_SZ_UART - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_UART1, - .end = IRQ_UART1, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(S5P_PA_UART1, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART1), }; static struct resource s5p_uart2_resource[] = { - [0] = { - .start = S5P_PA_UART2, - .end = S5P_PA_UART2 + S5P_SZ_UART - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_UART2, - .end = IRQ_UART2, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(S5P_PA_UART2, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART2), }; static struct resource s5p_uart3_resource[] = { #if CONFIG_SERIAL_SAMSUNG_UARTS > 3 - [0] = { - .start = S5P_PA_UART3, - .end = S5P_PA_UART3 + S5P_SZ_UART - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_UART3, - .end = IRQ_UART3, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(S5P_PA_UART3, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART3), #endif }; static struct resource s5p_uart4_resource[] = { #if CONFIG_SERIAL_SAMSUNG_UARTS > 4 - [0] = { - .start = S5P_PA_UART4, - .end = S5P_PA_UART4 + S5P_SZ_UART - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_UART4, - .end = IRQ_UART4, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(S5P_PA_UART4, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART4), #endif }; static struct resource s5p_uart5_resource[] = { #if CONFIG_SERIAL_SAMSUNG_UARTS > 5 - [0] = { - .start = S5P_PA_UART5, - .end = S5P_PA_UART5 + S5P_SZ_UART - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_UART5, - .end = IRQ_UART5, - .flags = IORESOURCE_IRQ, - }, + [0] = DEFINE_RES_MEM(S5P_PA_UART5, S5P_SZ_UART), + [1] = DEFINE_RES_IRQ(IRQ_UART5), #endif }; diff --git a/arch/arm/plat-s5p/irq-eint.c b/arch/arm/plat-samsung/s5p-irq-eint.c index 139c050918c5..33bd3f3d20f5 100644 --- a/arch/arm/plat-s5p/irq-eint.c +++ b/arch/arm/plat-samsung/s5p-irq-eint.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/irq-eint.c - * +/* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com * diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-samsung/s5p-irq-gpioint.c index 82c7311017a2..f9431fe5b06e 100644 --- a/arch/arm/plat-s5p/irq-gpioint.c +++ b/arch/arm/plat-samsung/s5p-irq-gpioint.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/irq-gpioint.c - * +/* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * Author: Kyungmin Park <kyungmin.park@samsung.com> * Author: Joonyoung Shim <jy0922.shim@samsung.com> diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-samsung/s5p-irq-pm.c index d1bfecae6c9f..7c1e3b7072fc 100644 --- a/arch/arm/plat-s5p/irq-pm.c +++ b/arch/arm/plat-samsung/s5p-irq-pm.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/irq-pm.c - * +/* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com * diff --git a/arch/arm/plat-s5p/irq.c b/arch/arm/plat-samsung/s5p-irq.c index afdaa1082b9f..dfb47d638f03 100644 --- a/arch/arm/plat-s5p/irq.c +++ b/arch/arm/plat-samsung/s5p-irq.c @@ -1,5 +1,4 @@ -/* arch/arm/plat-s5p/irq.c - * +/* * Copyright (c) 2009 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * diff --git a/arch/arm/plat-s5p/pm.c b/arch/arm/plat-samsung/s5p-pm.c index d15dc47b0e3d..0747468f0936 100644 --- a/arch/arm/plat-s5p/pm.c +++ b/arch/arm/plat-samsung/s5p-pm.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/pm.c - * +/* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com * diff --git a/arch/arm/plat-s5p/sleep.S b/arch/arm/plat-samsung/s5p-sleep.S index 006bd01eda02..bdf6dadf8790 100644 --- a/arch/arm/plat-s5p/sleep.S +++ b/arch/arm/plat-samsung/s5p-sleep.S @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/sleep.S - * +/* * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-samsung/s5p-time.c index 17c0a2c58dfd..028b6e877eb9 100644 --- a/arch/arm/plat-s5p/s5p-time.c +++ b/arch/arm/plat-samsung/s5p-time.c @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-s5p/s5p-time.c - * +/* * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * diff --git a/arch/arm/plat-s5p/setup-mipiphy.c b/arch/arm/plat-samsung/setup-mipiphy.c index 683c466c0e6a..683c466c0e6a 100644 --- a/arch/arm/plat-s5p/setup-mipiphy.c +++ b/arch/arm/plat-samsung/setup-mipiphy.c diff --git a/arch/arm/plat-spear/Kconfig b/arch/arm/plat-spear/Kconfig index 387655b5ce05..4404f82d5979 100644 --- a/arch/arm/plat-spear/Kconfig +++ b/arch/arm/plat-spear/Kconfig @@ -8,6 +8,17 @@ choice prompt "ST SPEAr Family" default ARCH_SPEAR3XX +config ARCH_SPEAR13XX + bool "ST SPEAr13xx with Device Tree" + select ARM_GIC + select CPU_V7 + select USE_OF + select HAVE_SMP + select MIGHT_HAVE_CACHE_L2X0 + select PINCTRL + help + Supports for ARM's SPEAR13XX family + config ARCH_SPEAR3XX bool "ST SPEAr3xx with Device Tree" select ARM_VIC @@ -27,6 +38,7 @@ config ARCH_SPEAR6XX endchoice # Adding SPEAr machine specific configuration files +source "arch/arm/mach-spear13xx/Kconfig" source "arch/arm/mach-spear3xx/Kconfig" source "arch/arm/mach-spear6xx/Kconfig" diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile index 7744802c83e7..2607bd05c525 100644 --- a/arch/arm/plat-spear/Makefile +++ b/arch/arm/plat-spear/Makefile @@ -3,6 +3,7 @@ # # Common support -obj-y := clock.o restart.o time.o pl080.o +obj-y := restart.o time.o -obj-$(CONFIG_ARCH_SPEAR3XX) += shirq.o +obj-$(CONFIG_ARCH_SPEAR3XX) += pl080.o shirq.o +obj-$(CONFIG_ARCH_SPEAR6XX) += pl080.o diff --git a/arch/arm/plat-spear/clock.c b/arch/arm/plat-spear/clock.c deleted file mode 100644 index 67dd00381ea6..000000000000 --- a/arch/arm/plat-spear/clock.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * arch/arm/plat-spear/clock.c - * - * Clock framework for SPEAr platform - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/bug.h> -#include <linux/clk.h> -#include <linux/debugfs.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <plat/clock.h> - -static DEFINE_SPINLOCK(clocks_lock); -static LIST_HEAD(root_clks); -#ifdef CONFIG_DEBUG_FS -static LIST_HEAD(clocks); -#endif - -static void propagate_rate(struct clk *, int on_init); -#ifdef CONFIG_DEBUG_FS -static int clk_debugfs_reparent(struct clk *); -#endif - -static int generic_clk_enable(struct clk *clk) -{ - unsigned int val; - - if (!clk->en_reg) - return -EFAULT; - - val = readl(clk->en_reg); - if (unlikely(clk->flags & RESET_TO_ENABLE)) - val &= ~(1 << clk->en_reg_bit); - else - val |= 1 << clk->en_reg_bit; - - writel(val, clk->en_reg); - - return 0; -} - -static void generic_clk_disable(struct clk *clk) -{ - unsigned int val; - - if (!clk->en_reg) - return; - - val = readl(clk->en_reg); - if (unlikely(clk->flags & RESET_TO_ENABLE)) - val |= 1 << clk->en_reg_bit; - else - val &= ~(1 << clk->en_reg_bit); - - writel(val, clk->en_reg); -} - -/* generic clk ops */ -static struct clkops generic_clkops = { - .enable = generic_clk_enable, - .disable = generic_clk_disable, -}; - -/* returns current programmed clocks clock info structure */ -static struct pclk_info *pclk_info_get(struct clk *clk) -{ - unsigned int val, i; - struct pclk_info *info = NULL; - - val = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) - & clk->pclk_sel->pclk_sel_mask; - - for (i = 0; i < clk->pclk_sel->pclk_count; i++) { - if (clk->pclk_sel->pclk_info[i].pclk_val == val) - info = &clk->pclk_sel->pclk_info[i]; - } - - return info; -} - -/* - * Set Update pclk, and pclk_info of clk and add clock sibling node to current - * parents children list - */ -static void clk_reparent(struct clk *clk, struct pclk_info *pclk_info) -{ - unsigned long flags; - - spin_lock_irqsave(&clocks_lock, flags); - list_del(&clk->sibling); - list_add(&clk->sibling, &pclk_info->pclk->children); - - clk->pclk = pclk_info->pclk; - spin_unlock_irqrestore(&clocks_lock, flags); - -#ifdef CONFIG_DEBUG_FS - clk_debugfs_reparent(clk); -#endif -} - -static void do_clk_disable(struct clk *clk) -{ - if (!clk) - return; - - if (!clk->usage_count) { - WARN_ON(1); - return; - } - - clk->usage_count--; - - if (clk->usage_count == 0) { - /* - * Surely, there are no active childrens or direct users - * of this clock - */ - if (clk->pclk) - do_clk_disable(clk->pclk); - - if (clk->ops && clk->ops->disable) - clk->ops->disable(clk); - } -} - -static int do_clk_enable(struct clk *clk) -{ - int ret = 0; - - if (!clk) - return -EFAULT; - - if (clk->usage_count == 0) { - if (clk->pclk) { - ret = do_clk_enable(clk->pclk); - if (ret) - goto err; - } - if (clk->ops && clk->ops->enable) { - ret = clk->ops->enable(clk); - if (ret) { - if (clk->pclk) - do_clk_disable(clk->pclk); - goto err; - } - } - /* - * Since the clock is going to be used for the first - * time please reclac - */ - if (clk->recalc) { - ret = clk->recalc(clk); - if (ret) - goto err; - } - } - clk->usage_count++; -err: - return ret; -} - -/* - * clk_enable - inform the system when the clock source should be running. - * @clk: clock source - * - * If the clock can not be enabled/disabled, this should return success. - * - * Returns success (0) or negative errno. - */ -int clk_enable(struct clk *clk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&clocks_lock, flags); - ret = do_clk_enable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); - return ret; -} -EXPORT_SYMBOL(clk_enable); - -/* - * clk_disable - inform the system when the clock source is no longer required. - * @clk: clock source - * - * Inform the system that a clock source is no longer required by - * a driver and may be shut down. - * - * Implementation detail: if the clock source is shared between - * multiple drivers, clk_enable() calls must be balanced by the - * same number of clk_disable() calls for the clock source to be - * disabled. - */ -void clk_disable(struct clk *clk) -{ - unsigned long flags; - - spin_lock_irqsave(&clocks_lock, flags); - do_clk_disable(clk); - spin_unlock_irqrestore(&clocks_lock, flags); -} -EXPORT_SYMBOL(clk_disable); - -/** - * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. - * This is only valid once the clock source has been enabled. - * @clk: clock source - */ -unsigned long clk_get_rate(struct clk *clk) -{ - unsigned long flags, rate; - - spin_lock_irqsave(&clocks_lock, flags); - rate = clk->rate; - spin_unlock_irqrestore(&clocks_lock, flags); - - return rate; -} -EXPORT_SYMBOL(clk_get_rate); - -/** - * clk_set_parent - set the parent clock source for this clock - * @clk: clock source - * @parent: parent clock source - * - * Returns success (0) or negative errno. - */ -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - int i, found = 0, val = 0; - unsigned long flags; - - if (!clk || !parent) - return -EFAULT; - if (clk->pclk == parent) - return 0; - if (!clk->pclk_sel) - return -EPERM; - - /* check if requested parent is in clk parent list */ - for (i = 0; i < clk->pclk_sel->pclk_count; i++) { - if (clk->pclk_sel->pclk_info[i].pclk == parent) { - found = 1; - break; - } - } - - if (!found) - return -EINVAL; - - spin_lock_irqsave(&clocks_lock, flags); - /* reflect parent change in hardware */ - val = readl(clk->pclk_sel->pclk_sel_reg); - val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); - val |= clk->pclk_sel->pclk_info[i].pclk_val << clk->pclk_sel_shift; - writel(val, clk->pclk_sel->pclk_sel_reg); - spin_unlock_irqrestore(&clocks_lock, flags); - - /* reflect parent change in software */ - clk_reparent(clk, &clk->pclk_sel->pclk_info[i]); - - propagate_rate(clk, 0); - return 0; -} -EXPORT_SYMBOL(clk_set_parent); - -/** - * clk_set_rate - set the clock rate for a clock source - * @clk: clock source - * @rate: desired clock rate in Hz - * - * Returns success (0) or negative errno. - */ -int clk_set_rate(struct clk *clk, unsigned long rate) -{ - unsigned long flags; - int ret = -EINVAL; - - if (!clk || !rate) - return -EFAULT; - - if (clk->set_rate) { - spin_lock_irqsave(&clocks_lock, flags); - ret = clk->set_rate(clk, rate); - if (!ret) - /* if successful -> propagate */ - propagate_rate(clk, 0); - spin_unlock_irqrestore(&clocks_lock, flags); - } else if (clk->pclk) { - u32 mult = clk->div_factor ? clk->div_factor : 1; - ret = clk_set_rate(clk->pclk, mult * rate); - } - - return ret; -} -EXPORT_SYMBOL(clk_set_rate); - -/* registers clock in platform clock framework */ -void clk_register(struct clk_lookup *cl) -{ - struct clk *clk; - unsigned long flags; - - if (!cl || !cl->clk) - return; - clk = cl->clk; - - spin_lock_irqsave(&clocks_lock, flags); - - INIT_LIST_HEAD(&clk->children); - if (clk->flags & ALWAYS_ENABLED) - clk->ops = NULL; - else if (!clk->ops) - clk->ops = &generic_clkops; - - /* root clock don't have any parents */ - if (!clk->pclk && !clk->pclk_sel) { - list_add(&clk->sibling, &root_clks); - } else if (clk->pclk && !clk->pclk_sel) { - /* add clocks with only one parent to parent's children list */ - list_add(&clk->sibling, &clk->pclk->children); - } else { - /* clocks with more than one parent */ - struct pclk_info *pclk_info; - - pclk_info = pclk_info_get(clk); - if (!pclk_info) { - pr_err("CLKDEV: invalid pclk info of clk with" - " %s dev_id and %s con_id\n", - cl->dev_id, cl->con_id); - } else { - clk->pclk = pclk_info->pclk; - list_add(&clk->sibling, &pclk_info->pclk->children); - } - } - - spin_unlock_irqrestore(&clocks_lock, flags); - - /* debugfs specific */ -#ifdef CONFIG_DEBUG_FS - list_add(&clk->node, &clocks); - clk->cl = cl; -#endif - - /* add clock to arm clockdev framework */ - clkdev_add(cl); -} - -/** - * propagate_rate - recalculate and propagate all clocks to children - * @pclk: parent clock required to be propogated - * @on_init: flag for enabling clocks which are ENABLED_ON_INIT. - * - * Recalculates all children clocks - */ -void propagate_rate(struct clk *pclk, int on_init) -{ - struct clk *clk, *_temp; - int ret = 0; - - list_for_each_entry_safe(clk, _temp, &pclk->children, sibling) { - if (clk->recalc) { - ret = clk->recalc(clk); - /* - * recalc will return error if clk out is not programmed - * In this case configure default rate. - */ - if (ret && clk->set_rate) - clk->set_rate(clk, 0); - } - propagate_rate(clk, on_init); - - if (!on_init) - continue; - - /* Enable clks enabled on init, in software view */ - if (clk->flags & ENABLED_ON_INIT) - do_clk_enable(clk); - } -} - -/** - * round_rate_index - return closest programmable rate index in rate_config tbl - * @clk: ptr to clock structure - * @drate: desired rate - * @rate: final rate will be returned in this variable only. - * - * Finds index in rate_config for highest clk rate which is less than - * requested rate. If there is no clk rate lesser than requested rate then - * -EINVAL is returned. This routine assumes that rate_config is written - * in incrementing order of clk rates. - * If drate passed is zero then default rate is programmed. - */ -static int -round_rate_index(struct clk *clk, unsigned long drate, unsigned long *rate) -{ - unsigned long tmp = 0, prev_rate = 0; - int index; - - if (!clk->calc_rate) - return -EFAULT; - - if (!drate) - return -EINVAL; - - /* - * This loops ends on two conditions: - * - as soon as clk is found with rate greater than requested rate. - * - if all clks in rate_config are smaller than requested rate. - */ - for (index = 0; index < clk->rate_config.count; index++) { - prev_rate = tmp; - tmp = clk->calc_rate(clk, index); - if (drate < tmp) { - index--; - break; - } - } - /* return if can't find suitable clock */ - if (index < 0) { - index = -EINVAL; - *rate = 0; - } else if (index == clk->rate_config.count) { - /* program with highest clk rate possible */ - index = clk->rate_config.count - 1; - *rate = tmp; - } else - *rate = prev_rate; - - return index; -} - -/** - * clk_round_rate - adjust a rate to the exact rate a clock can provide - * @clk: clock source - * @rate: desired clock rate in Hz - * - * Returns rounded clock rate in Hz, or negative errno. - */ -long clk_round_rate(struct clk *clk, unsigned long drate) -{ - long rate = 0; - int index; - - /* - * propagate call to parent who supports calc_rate. Similar approach is - * used in clk_set_rate. - */ - if (!clk->calc_rate) { - u32 mult; - if (!clk->pclk) - return clk->rate; - - mult = clk->div_factor ? clk->div_factor : 1; - return clk_round_rate(clk->pclk, mult * drate) / mult; - } - - index = round_rate_index(clk, drate, &rate); - if (index >= 0) - return rate; - else - return index; -} -EXPORT_SYMBOL(clk_round_rate); - -/*All below functions are called with lock held */ - -/* - * Calculates pll clk rate for specific value of mode, m, n and p - * - * In normal mode - * rate = (2 * M[15:8] * Fin)/(N * 2^P) - * - * In Dithered mode - * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) - */ -unsigned long pll_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct pll_rate_tbl *tbls = clk->rate_config.tbls; - unsigned int mode; - - mode = tbls[index].mode ? 256 : 1; - return (((2 * rate / 10000) * tbls[index].m) / - (mode * tbls[index].n * (1 << tbls[index].p))) * 10000; -} - -/* - * calculates current programmed rate of pll1 - * - * In normal mode - * rate = (2 * M[15:8] * Fin)/(N * 2^P) - * - * In Dithered mode - * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) - */ -int pll_clk_recalc(struct clk *clk) -{ - struct pll_clk_config *config = clk->private_data; - unsigned int num = 2, den = 0, val, mode = 0; - - mode = (readl(config->mode_reg) >> config->masks->mode_shift) & - config->masks->mode_mask; - - val = readl(config->cfg_reg); - /* calculate denominator */ - den = (val >> config->masks->div_p_shift) & config->masks->div_p_mask; - den = 1 << den; - den *= (val >> config->masks->div_n_shift) & config->masks->div_n_mask; - - /* calculate numerator & denominator */ - if (!mode) { - /* Normal mode */ - num *= (val >> config->masks->norm_fdbk_m_shift) & - config->masks->norm_fdbk_m_mask; - } else { - /* Dithered mode */ - num *= (val >> config->masks->dith_fdbk_m_shift) & - config->masks->dith_fdbk_m_mask; - den *= 256; - } - - if (!den) - return -EINVAL; - - clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; - return 0; -} - -/* - * Configures new clock rate of pll - */ -int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct pll_rate_tbl *tbls = clk->rate_config.tbls; - struct pll_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->mode_reg) & - ~(config->masks->mode_mask << config->masks->mode_shift); - val |= (tbls[i].mode & config->masks->mode_mask) << - config->masks->mode_shift; - writel(val, config->mode_reg); - - val = readl(config->cfg_reg) & - ~(config->masks->div_p_mask << config->masks->div_p_shift); - val |= (tbls[i].p & config->masks->div_p_mask) << - config->masks->div_p_shift; - val &= ~(config->masks->div_n_mask << config->masks->div_n_shift); - val |= (tbls[i].n & config->masks->div_n_mask) << - config->masks->div_n_shift; - val &= ~(config->masks->dith_fdbk_m_mask << - config->masks->dith_fdbk_m_shift); - if (tbls[i].mode) - val |= (tbls[i].m & config->masks->dith_fdbk_m_mask) << - config->masks->dith_fdbk_m_shift; - else - val |= (tbls[i].m & config->masks->norm_fdbk_m_mask) << - config->masks->norm_fdbk_m_shift; - - writel(val, config->cfg_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Calculates ahb, apb clk rate for specific value of div - */ -unsigned long bus_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct bus_rate_tbl *tbls = clk->rate_config.tbls; - - return rate / (tbls[index].div + 1); -} - -/* calculates current programmed rate of ahb or apb bus */ -int bus_clk_recalc(struct clk *clk) -{ - struct bus_clk_config *config = clk->private_data; - unsigned int div; - - div = ((readl(config->reg) >> config->masks->shift) & - config->masks->mask) + 1; - - if (!div) - return -EINVAL; - - clk->rate = (unsigned long)clk->pclk->rate / div; - return 0; -} - -/* Configures new clock rate of AHB OR APB bus */ -int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct bus_rate_tbl *tbls = clk->rate_config.tbls; - struct bus_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->reg) & - ~(config->masks->mask << config->masks->shift); - val |= (tbls[i].div & config->masks->mask) << config->masks->shift; - writel(val, config->reg); - - clk->rate = rate; - - return 0; -} - -/* - * gives rate for different values of eq, x and y - * - * Fout from synthesizer can be given from two equations: - * Fout1 = (Fin * X/Y)/2 EQ1 - * Fout2 = Fin * X/Y EQ2 - */ -unsigned long aux_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct aux_rate_tbl *tbls = clk->rate_config.tbls; - u8 eq = tbls[index].eq ? 1 : 2; - - return (((rate/10000) * tbls[index].xscale) / - (tbls[index].yscale * eq)) * 10000; -} - -/* - * calculates current programmed rate of auxiliary synthesizers - * used by: UART, FIRDA - * - * Fout from synthesizer can be given from two equations: - * Fout1 = (Fin * X/Y)/2 - * Fout2 = Fin * X/Y - * - * Selection of eqn 1 or 2 is programmed in register - */ -int aux_clk_recalc(struct clk *clk) -{ - struct aux_clk_config *config = clk->private_data; - unsigned int num = 1, den = 1, val, eqn; - - val = readl(config->synth_reg); - - eqn = (val >> config->masks->eq_sel_shift) & - config->masks->eq_sel_mask; - if (eqn == config->masks->eq1_mask) - den *= 2; - - /* calculate numerator */ - num = (val >> config->masks->xscale_sel_shift) & - config->masks->xscale_sel_mask; - - /* calculate denominator */ - den *= (val >> config->masks->yscale_sel_shift) & - config->masks->yscale_sel_mask; - - if (!den) - return -EINVAL; - - clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; - return 0; -} - -/* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ -int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct aux_rate_tbl *tbls = clk->rate_config.tbls; - struct aux_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->synth_reg) & - ~(config->masks->eq_sel_mask << config->masks->eq_sel_shift); - val |= (tbls[i].eq & config->masks->eq_sel_mask) << - config->masks->eq_sel_shift; - val &= ~(config->masks->xscale_sel_mask << - config->masks->xscale_sel_shift); - val |= (tbls[i].xscale & config->masks->xscale_sel_mask) << - config->masks->xscale_sel_shift; - val &= ~(config->masks->yscale_sel_mask << - config->masks->yscale_sel_shift); - val |= (tbls[i].yscale & config->masks->yscale_sel_mask) << - config->masks->yscale_sel_shift; - writel(val, config->synth_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Calculates gpt clk rate for different values of mscale and nscale - * - * Fout= Fin/((2 ^ (N+1)) * (M+1)) - */ -unsigned long gpt_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct gpt_rate_tbl *tbls = clk->rate_config.tbls; - - return rate / ((1 << (tbls[index].nscale + 1)) * - (tbls[index].mscale + 1)); -} - -/* - * calculates current programmed rate of gpt synthesizers - * Fout from synthesizer can be given from below equations: - * Fout= Fin/((2 ^ (N+1)) * (M+1)) - */ -int gpt_clk_recalc(struct clk *clk) -{ - struct gpt_clk_config *config = clk->private_data; - unsigned int div = 1, val; - - val = readl(config->synth_reg); - div += (val >> config->masks->mscale_sel_shift) & - config->masks->mscale_sel_mask; - div *= 1 << (((val >> config->masks->nscale_sel_shift) & - config->masks->nscale_sel_mask) + 1); - - if (!div) - return -EINVAL; - - clk->rate = (unsigned long)clk->pclk->rate / div; - return 0; -} - -/* Configures new clock rate of gptiliary synthesizers used by: UART, FIRDA*/ -int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct gpt_rate_tbl *tbls = clk->rate_config.tbls; - struct gpt_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->synth_reg) & ~(config->masks->mscale_sel_mask << - config->masks->mscale_sel_shift); - val |= (tbls[i].mscale & config->masks->mscale_sel_mask) << - config->masks->mscale_sel_shift; - val &= ~(config->masks->nscale_sel_mask << - config->masks->nscale_sel_shift); - val |= (tbls[i].nscale & config->masks->nscale_sel_mask) << - config->masks->nscale_sel_shift; - writel(val, config->synth_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Calculates clcd clk rate for different values of div - * - * Fout from synthesizer can be given from below equation: - * Fout= Fin/2*div (division factor) - * div is 17 bits:- - * 0-13 (fractional part) - * 14-16 (integer part) - * To calculate Fout we left shift val by 14 bits and divide Fin by - * complete div (including fractional part) and then right shift the - * result by 14 places. - */ -unsigned long clcd_calc_rate(struct clk *clk, int index) -{ - unsigned long rate = clk->pclk->rate; - struct clcd_rate_tbl *tbls = clk->rate_config.tbls; - - rate /= 1000; - rate <<= 12; - rate /= (2 * tbls[index].div); - rate >>= 12; - rate *= 1000; - - return rate; -} - -/* - * calculates current programmed rate of clcd synthesizer - * Fout from synthesizer can be given from below equation: - * Fout= Fin/2*div (division factor) - * div is 17 bits:- - * 0-13 (fractional part) - * 14-16 (integer part) - * To calculate Fout we left shift val by 14 bits and divide Fin by - * complete div (including fractional part) and then right shift the - * result by 14 places. - */ -int clcd_clk_recalc(struct clk *clk) -{ - struct clcd_clk_config *config = clk->private_data; - unsigned int div = 1; - unsigned long prate; - unsigned int val; - - val = readl(config->synth_reg); - div = (val >> config->masks->div_factor_shift) & - config->masks->div_factor_mask; - - if (!div) - return -EINVAL; - - prate = clk->pclk->rate / 1000; /* first level division, make it KHz */ - - clk->rate = (((unsigned long)prate << 12) / (2 * div)) >> 12; - clk->rate *= 1000; - return 0; -} - -/* Configures new clock rate of auxiliary synthesizers used by: UART, FIRDA*/ -int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate) -{ - struct clcd_rate_tbl *tbls = clk->rate_config.tbls; - struct clcd_clk_config *config = clk->private_data; - unsigned long val, rate; - int i; - - i = round_rate_index(clk, desired_rate, &rate); - if (i < 0) - return i; - - val = readl(config->synth_reg) & ~(config->masks->div_factor_mask << - config->masks->div_factor_shift); - val |= (tbls[i].div & config->masks->div_factor_mask) << - config->masks->div_factor_shift; - writel(val, config->synth_reg); - - clk->rate = rate; - - return 0; -} - -/* - * Used for clocks that always have value as the parent clock divided by a - * fixed divisor - */ -int follow_parent(struct clk *clk) -{ - unsigned int div_factor = (clk->div_factor < 1) ? 1 : clk->div_factor; - - clk->rate = clk->pclk->rate/div_factor; - return 0; -} - -/** - * recalc_root_clocks - recalculate and propagate all root clocks - * - * Recalculates all root clocks (clocks with no parent), which if the - * clock's .recalc is set correctly, should also propagate their rates. - */ -void recalc_root_clocks(void) -{ - struct clk *pclk; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&clocks_lock, flags); - list_for_each_entry(pclk, &root_clks, sibling) { - if (pclk->recalc) { - ret = pclk->recalc(pclk); - /* - * recalc will return error if clk out is not programmed - * In this case configure default clock. - */ - if (ret && pclk->set_rate) - pclk->set_rate(pclk, 0); - } - propagate_rate(pclk, 1); - /* Enable clks enabled on init, in software view */ - if (pclk->flags & ENABLED_ON_INIT) - do_clk_enable(pclk); - } - spin_unlock_irqrestore(&clocks_lock, flags); -} - -void __init clk_init(void) -{ - recalc_root_clocks(); -} - -#ifdef CONFIG_DEBUG_FS -/* - * debugfs support to trace clock tree hierarchy and attributes - */ -static struct dentry *clk_debugfs_root; -static int clk_debugfs_register_one(struct clk *c) -{ - int err; - struct dentry *d; - struct clk *pa = c->pclk; - char s[255]; - char *p = s; - - if (c) { - if (c->cl->con_id) - p += sprintf(p, "%s", c->cl->con_id); - if (c->cl->dev_id) - p += sprintf(p, "%s", c->cl->dev_id); - } - d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root); - if (!d) - return -ENOMEM; - c->dent = d; - - d = debugfs_create_u32("usage_count", S_IRUGO, c->dent, - (u32 *)&c->usage_count); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags); - if (!d) { - err = -ENOMEM; - goto err_out; - } - return 0; - -err_out: - debugfs_remove_recursive(c->dent); - return err; -} - -static int clk_debugfs_register(struct clk *c) -{ - int err; - struct clk *pa = c->pclk; - - if (pa && !pa->dent) { - err = clk_debugfs_register(pa); - if (err) - return err; - } - - if (!c->dent) { - err = clk_debugfs_register_one(c); - if (err) - return err; - } - return 0; -} - -static int __init clk_debugfs_init(void) -{ - struct clk *c; - struct dentry *d; - int err; - - d = debugfs_create_dir("clock", NULL); - if (!d) - return -ENOMEM; - clk_debugfs_root = d; - - list_for_each_entry(c, &clocks, node) { - err = clk_debugfs_register(c); - if (err) - goto err_out; - } - return 0; -err_out: - debugfs_remove_recursive(clk_debugfs_root); - return err; -} -late_initcall(clk_debugfs_init); - -static int clk_debugfs_reparent(struct clk *c) -{ - debugfs_remove(c->dent); - return clk_debugfs_register_one(c); -} -#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/arm/plat-spear/include/plat/clock.h b/arch/arm/plat-spear/include/plat/clock.h deleted file mode 100644 index 0062bafef12d..000000000000 --- a/arch/arm/plat-spear/include/plat/clock.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * arch/arm/plat-spear/include/plat/clock.h - * - * Clock framework definitions for SPEAr platform - * - * Copyright (C) 2009 ST Microelectronics - * Viresh Kumar<viresh.kumar@st.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef __PLAT_CLOCK_H -#define __PLAT_CLOCK_H - -#include <linux/list.h> -#include <linux/clkdev.h> -#include <linux/types.h> - -/* clk structure flags */ -#define ALWAYS_ENABLED (1 << 0) /* clock always enabled */ -#define RESET_TO_ENABLE (1 << 1) /* reset register bit to enable clk */ -#define ENABLED_ON_INIT (1 << 2) /* clocks enabled at init */ - -/** - * struct clkops - clock operations - * @enable: pointer to clock enable function - * @disable: pointer to clock disable function - */ -struct clkops { - int (*enable) (struct clk *); - void (*disable) (struct clk *); -}; - -/** - * struct pclk_info - parents info - * @pclk: pointer to parent clk - * @pclk_val: value to be written for selecting this parent - */ -struct pclk_info { - struct clk *pclk; - u8 pclk_val; -}; - -/** - * struct pclk_sel - parents selection configuration - * @pclk_info: pointer to array of parent clock info - * @pclk_count: number of parents - * @pclk_sel_reg: register for selecting a parent - * @pclk_sel_mask: mask for selecting parent (can be used to clear bits also) - */ -struct pclk_sel { - struct pclk_info *pclk_info; - u8 pclk_count; - void __iomem *pclk_sel_reg; - unsigned int pclk_sel_mask; -}; - -/** - * struct rate_config - clk rate configurations - * @tbls: array of device specific clk rate tables, in ascending order of rates - * @count: size of tbls array - * @default_index: default setting when originally disabled - */ -struct rate_config { - void *tbls; - u8 count; - u8 default_index; -}; - -/** - * struct clk - clock structure - * @usage_count: num of users who enabled this clock - * @flags: flags for clock properties - * @rate: programmed clock rate in Hz - * @en_reg: clk enable/disable reg - * @en_reg_bit: clk enable/disable bit - * @ops: clk enable/disable ops - generic_clkops selected if NULL - * @recalc: pointer to clock rate recalculate function - * @set_rate: pointer to clock set rate function - * @calc_rate: pointer to clock get rate function for index - * @rate_config: rate configuration information, used by set_rate - * @div_factor: division factor to parent clock. - * @pclk: current parent clk - * @pclk_sel: pointer to parent selection structure - * @pclk_sel_shift: register shift for selecting parent of this clock - * @children: list for childrens or this clock - * @sibling: node for list of clocks having same parents - * @private_data: clock specific private data - * @node: list to maintain clocks linearly - * @cl: clocklook up associated with this clock - * @dent: object for debugfs - */ -struct clk { - unsigned int usage_count; - unsigned int flags; - unsigned long rate; - void __iomem *en_reg; - u8 en_reg_bit; - const struct clkops *ops; - int (*recalc) (struct clk *); - int (*set_rate) (struct clk *, unsigned long rate); - unsigned long (*calc_rate)(struct clk *, int index); - struct rate_config rate_config; - unsigned int div_factor; - - struct clk *pclk; - struct pclk_sel *pclk_sel; - unsigned int pclk_sel_shift; - - struct list_head children; - struct list_head sibling; - void *private_data; -#ifdef CONFIG_DEBUG_FS - struct list_head node; - struct clk_lookup *cl; - struct dentry *dent; -#endif -}; - -/* pll configuration structure */ -struct pll_clk_masks { - u32 mode_mask; - u32 mode_shift; - - u32 norm_fdbk_m_mask; - u32 norm_fdbk_m_shift; - u32 dith_fdbk_m_mask; - u32 dith_fdbk_m_shift; - u32 div_p_mask; - u32 div_p_shift; - u32 div_n_mask; - u32 div_n_shift; -}; - -struct pll_clk_config { - void __iomem *mode_reg; - void __iomem *cfg_reg; - struct pll_clk_masks *masks; -}; - -/* pll clk rate config structure */ -struct pll_rate_tbl { - u8 mode; - u16 m; - u8 n; - u8 p; -}; - -/* ahb and apb bus configuration structure */ -struct bus_clk_masks { - u32 mask; - u32 shift; -}; - -struct bus_clk_config { - void __iomem *reg; - struct bus_clk_masks *masks; -}; - -/* ahb and apb clk bus rate config structure */ -struct bus_rate_tbl { - u8 div; -}; - -/* Aux clk configuration structure: applicable to UART and FIRDA */ -struct aux_clk_masks { - u32 eq_sel_mask; - u32 eq_sel_shift; - u32 eq1_mask; - u32 eq2_mask; - u32 xscale_sel_mask; - u32 xscale_sel_shift; - u32 yscale_sel_mask; - u32 yscale_sel_shift; -}; - -struct aux_clk_config { - void __iomem *synth_reg; - struct aux_clk_masks *masks; -}; - -/* aux clk rate config structure */ -struct aux_rate_tbl { - u16 xscale; - u16 yscale; - u8 eq; -}; - -/* GPT clk configuration structure */ -struct gpt_clk_masks { - u32 mscale_sel_mask; - u32 mscale_sel_shift; - u32 nscale_sel_mask; - u32 nscale_sel_shift; -}; - -struct gpt_clk_config { - void __iomem *synth_reg; - struct gpt_clk_masks *masks; -}; - -/* gpt clk rate config structure */ -struct gpt_rate_tbl { - u16 mscale; - u16 nscale; -}; - -/* clcd clk configuration structure */ -struct clcd_synth_masks { - u32 div_factor_mask; - u32 div_factor_shift; -}; - -struct clcd_clk_config { - void __iomem *synth_reg; - struct clcd_synth_masks *masks; -}; - -/* clcd clk rate config structure */ -struct clcd_rate_tbl { - u16 div; -}; - -/* platform specific clock functions */ -void __init clk_init(void); -void clk_register(struct clk_lookup *cl); -void recalc_root_clocks(void); - -/* clock recalc & set rate functions */ -int follow_parent(struct clk *clk); -unsigned long pll_calc_rate(struct clk *clk, int index); -int pll_clk_recalc(struct clk *clk); -int pll_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long bus_calc_rate(struct clk *clk, int index); -int bus_clk_recalc(struct clk *clk); -int bus_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long gpt_calc_rate(struct clk *clk, int index); -int gpt_clk_recalc(struct clk *clk); -int gpt_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long aux_calc_rate(struct clk *clk, int index); -int aux_clk_recalc(struct clk *clk); -int aux_clk_set_rate(struct clk *clk, unsigned long desired_rate); -unsigned long clcd_calc_rate(struct clk *clk, int index); -int clcd_clk_recalc(struct clk *clk); -int clcd_clk_set_rate(struct clk *clk, unsigned long desired_rate); - -#endif /* __PLAT_CLOCK_H */ diff --git a/arch/arm/plat-spear/restart.c b/arch/arm/plat-spear/restart.c index 4471a232713a..ea0a61302b7e 100644 --- a/arch/arm/plat-spear/restart.c +++ b/arch/arm/plat-spear/restart.c @@ -16,6 +16,7 @@ #include <mach/spear.h> #include <mach/generic.h> +#define SPEAR13XX_SYS_SW_RES (VA_MISC_BASE + 0x204) void spear_restart(char mode, const char *cmd) { if (mode == 's') { @@ -23,6 +24,10 @@ void spear_restart(char mode, const char *cmd) soft_restart(0); } else { /* hardware reset, Use on-chip reset capability */ +#ifdef CONFIG_ARCH_SPEAR13XX + writel_relaxed(0x01, SPEAR13XX_SYS_SW_RES); +#else sysctl_soft_reset((void __iomem *)VA_SPEAR_SYS_CTRL_BASE); +#endif } } diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c index a3164d1647fd..03321af5de9f 100644 --- a/arch/arm/plat-spear/time.c +++ b/arch/arm/plat-spear/time.c @@ -18,6 +18,8 @@ #include <linux/ioport.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> #include <linux/time.h> #include <linux/irq.h> #include <asm/mach/time.h> @@ -197,19 +199,32 @@ static void __init spear_clockevent_init(int irq) setup_irq(irq, &spear_timer_irq); } -void __init spear_setup_timer(resource_size_t base, int irq) +const static struct of_device_id timer_of_match[] __initconst = { + { .compatible = "st,spear-timer", }, + { }, +}; + +void __init spear_setup_of_timer(void) { - int ret; + struct device_node *np; + int irq, ret; + + np = of_find_matching_node(NULL, timer_of_match); + if (!np) { + pr_err("%s: No timer passed via DT\n", __func__); + return; + } - if (!request_mem_region(base, SZ_1K, "gpt0")) { - pr_err("%s:cannot get IO addr\n", __func__); + irq = irq_of_parse_and_map(np, 0); + if (!irq) { + pr_err("%s: No irq passed for timer via DT\n", __func__); return; } - gpt_base = ioremap(base, SZ_1K); + gpt_base = of_iomap(np, 0); if (!gpt_base) { - pr_err("%s:ioremap failed for gpt\n", __func__); - goto err_mem; + pr_err("%s: of iomap failed\n", __func__); + return; } gpt_clk = clk_get_sys("gpt0", NULL); @@ -218,10 +233,10 @@ void __init spear_setup_timer(resource_size_t base, int irq) goto err_iomap; } - ret = clk_enable(gpt_clk); + ret = clk_prepare_enable(gpt_clk); if (ret < 0) { - pr_err("%s:couldn't enable gpt clock\n", __func__); - goto err_clk; + pr_err("%s:couldn't prepare-enable gpt clock\n", __func__); + goto err_prepare_enable_clk; } spear_clockevent_init(irq); @@ -229,10 +244,8 @@ void __init spear_setup_timer(resource_size_t base, int irq) return; -err_clk: +err_prepare_enable_clk: clk_put(gpt_clk); err_iomap: iounmap(gpt_base); -err_mem: - release_mem_region(base, SZ_1K); } diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c deleted file mode 100644 index 74f99c688c8d..000000000000 --- a/arch/cris/arch-v10/drivers/ds1302.c +++ /dev/null @@ -1,515 +0,0 @@ -/*!*************************************************************************** -*! -*! FILE NAME : ds1302.c -*! -*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O -*! -*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init -*! -*! --------------------------------------------------------------------------- -*! -*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN -*! -*!***************************************************************************/ - - -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/miscdevice.h> -#include <linux/delay.h> -#include <linux/mutex.h> -#include <linux/bcd.h> -#include <linux/capability.h> - -#include <asm/uaccess.h> -#include <arch/svinto.h> -#include <asm/io.h> -#include <asm/rtc.h> -#include <arch/io_interface_mux.h> - -#include "i2c.h" - -#define RTC_MAJOR_NR 121 /* local major, change later */ - -static DEFINE_MUTEX(ds1302_mutex); -static const char ds1302_name[] = "ds1302"; - -/* The DS1302 might be connected to different bits on different products. - * It has three signals - SDA, SCL and RST. RST and SCL are always outputs, - * but SDA can have a selected direction. - * For now, only PORT_PB is hardcoded. - */ - -/* The RST bit may be on either the Generic Port or Port PB. */ -#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT -#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) -#define TK_RST_DIR(x) -#else -#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) -#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) -#endif - - -#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) -#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) - -#define TK_SDA_IN() ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1) -/* 1 is out, 0 is in */ -#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) -#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) - - -/* - * The reason for tempudelay and not udelay is that loops_per_usec - * (used in udelay) is not set when functions here are called from time.c - */ - -static void tempudelay(int usecs) -{ - volatile int loops; - - for(loops = usecs * 12; loops > 0; loops--) - /* nothing */; -} - - -/* Send 8 bits. */ -static void -out_byte(unsigned char x) -{ - int i; - TK_SDA_DIR(1); - for (i = 8; i--;) { - /* The chip latches incoming bits on the rising edge of SCL. */ - TK_SCL_OUT(0); - TK_SDA_OUT(x & 1); - tempudelay(1); - TK_SCL_OUT(1); - tempudelay(1); - x >>= 1; - } - TK_SDA_DIR(0); -} - -static unsigned char -in_byte(void) -{ - unsigned char x = 0; - int i; - - /* Read byte. Bits come LSB first, on the falling edge of SCL. - * Assume SDA is in input direction already. - */ - TK_SDA_DIR(0); - - for (i = 8; i--;) { - TK_SCL_OUT(0); - tempudelay(1); - x >>= 1; - x |= (TK_SDA_IN() << 7); - TK_SCL_OUT(1); - tempudelay(1); - } - - return x; -} - -/* Prepares for a transaction by de-activating RST (active-low). */ - -static void -start(void) -{ - TK_SCL_OUT(0); - tempudelay(1); - TK_RST_OUT(0); - tempudelay(5); - TK_RST_OUT(1); -} - -/* Ends a transaction by taking RST active again. */ - -static void -stop(void) -{ - tempudelay(2); - TK_RST_OUT(0); -} - -/* Enable writing. */ - -static void -ds1302_wenable(void) -{ - start(); - out_byte(0x8e); /* Write control register */ - out_byte(0x00); /* Disable write protect bit 7 = 0 */ - stop(); -} - -/* Disable writing. */ - -static void -ds1302_wdisable(void) -{ - start(); - out_byte(0x8e); /* Write control register */ - out_byte(0x80); /* Disable write protect bit 7 = 0 */ - stop(); -} - - - -/* Read a byte from the selected register in the DS1302. */ - -unsigned char -ds1302_readreg(int reg) -{ - unsigned char x; - - start(); - out_byte(0x81 | (reg << 1)); /* read register */ - x = in_byte(); - stop(); - - return x; -} - -/* Write a byte to the selected register. */ - -void -ds1302_writereg(int reg, unsigned char val) -{ -#ifndef CONFIG_ETRAX_RTC_READONLY - int do_writereg = 1; -#else - int do_writereg = 0; - - if (reg == RTC_TRICKLECHARGER) - do_writereg = 1; -#endif - - if (do_writereg) { - ds1302_wenable(); - start(); - out_byte(0x80 | (reg << 1)); /* write register */ - out_byte(val); - stop(); - ds1302_wdisable(); - } -} - -void -get_rtc_time(struct rtc_time *rtc_tm) -{ - unsigned long flags; - - local_irq_save(flags); - - rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); - rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); - rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); - rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); - rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); - rtc_tm->tm_year = CMOS_READ(RTC_YEAR); - - local_irq_restore(flags); - - rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); - rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); - rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); - rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); - rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); - rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); - - /* - * Account for differences between how the RTC uses the values - * and how they are defined in a struct rtc_time; - */ - - if (rtc_tm->tm_year <= 69) - rtc_tm->tm_year += 100; - - rtc_tm->tm_mon--; -} - -static unsigned char days_in_mo[] = - {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */ - -static int rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - - switch(cmd) { - case RTC_RD_TIME: /* read the time/date from RTC */ - { - struct rtc_time rtc_tm; - - memset(&rtc_tm, 0, sizeof (struct rtc_time)); - get_rtc_time(&rtc_tm); - if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) - return -EFAULT; - return 0; - } - - case RTC_SET_TIME: /* set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned int yrs; - - if (!capable(CAP_SYS_TIME)) - return -EPERM; - - if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; - - yrs = rtc_tm.tm_year + 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - - if ((yrs < 1970) || (yrs > 2069)) - return -EINVAL; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if (yrs >= 2000) - yrs -= 2000; /* RTC (0, 1, ... 69) */ - else - yrs -= 1900; /* RTC (70, 71, ... 99) */ - - sec = bin2bcd(sec); - min = bin2bcd(min); - hrs = bin2bcd(hrs); - day = bin2bcd(day); - mon = bin2bcd(mon); - yrs = bin2bcd(yrs); - - local_irq_save(flags); - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); - local_irq_restore(flags); - - /* Notice that at this point, the RTC is updated but - * the kernel is still running with the old time. - * You need to set that separately with settimeofday - * or adjtimex. - */ - return 0; - } - - case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ - { - int tcs_val; - - if (!capable(CAP_SYS_TIME)) - return -EPERM; - - if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) - return -EFAULT; - - tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); - ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); - return 0; - } - case RTC_VL_READ: - { - /* TODO: - * Implement voltage low detection support - */ - printk(KERN_WARNING "DS1302: RTC Voltage Low detection" - " is not supported\n"); - return 0; - } - case RTC_VL_CLR: - { - /* TODO: - * Nothing to do since Voltage Low detection is not supported - */ - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static long rtc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&ds1302_mutex); - ret = rtc_ioctl(file, cmd, arg); - mutex_unlock(&ds1302_mutex); - - return ret; -} - -static void -print_rtc_status(void) -{ - struct rtc_time tm; - - get_rtc_time(&tm); - - /* - * There is no way to tell if the luser has the RTC set for local - * time or for Universal Standard Time (GMT). Probably local though. - */ - - printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec); - printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); -} - -/* The various file operations we support. */ - -static const struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = rtc_unlocked_ioctl, - .llseek = noop_llseek, -}; - -/* Probe for the chip by writing something to its RAM and try reading it back. */ - -#define MAGIC_PATTERN 0x42 - -static int __init -ds1302_probe(void) -{ - int retval, res; - - TK_RST_DIR(1); - TK_SCL_DIR(1); - TK_SDA_DIR(0); - - /* Try to talk to timekeeper. */ - - ds1302_wenable(); - start(); - out_byte(0xc0); /* write RAM byte 0 */ - out_byte(MAGIC_PATTERN); /* write something magic */ - start(); - out_byte(0xc1); /* read RAM byte 0 */ - - if((res = in_byte()) == MAGIC_PATTERN) { - stop(); - ds1302_wdisable(); - printk(KERN_INFO "%s: RTC found.\n", ds1302_name); - printk(KERN_INFO "%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", - ds1302_name, - CONFIG_ETRAX_DS1302_SDABIT, - CONFIG_ETRAX_DS1302_SCLBIT, -#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT - "GENIO", -#else - "PB", -#endif - CONFIG_ETRAX_DS1302_RSTBIT); - print_rtc_status(); - retval = 1; - } else { - stop(); - retval = 0; - } - - return retval; -} - - -/* Just probe for the RTC and register the device to handle the ioctl needed. */ - -int __init -ds1302_init(void) -{ -#ifdef CONFIG_ETRAX_I2C - i2c_init(); -#endif - - if (!ds1302_probe()) { -#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT -#if CONFIG_ETRAX_DS1302_RSTBIT == 27 - /* - * The only way to set g27 to output is to enable ATA. - * - * Make sure that R_GEN_CONFIG is setup correct. - */ - /* Allocating the ATA interface will grab almost all - * pins in I/O groups a, b, c and d. A consequence of - * allocating the ATA interface is that the fixed - * interfaces shared RAM, parallel port 0, parallel - * port 1, parallel port W, SCSI-8 port 0, SCSI-8 port - * 1, SCSI-W, serial port 2, serial port 3, - * synchronous serial port 3 and USB port 2 and almost - * all GPIO pins on port g cannot be used. - */ - if (cris_request_io_interface(if_ata, "ds1302/ATA")) { - printk(KERN_WARNING "ds1302: Failed to get IO interface\n"); - return -1; - } - -#elif CONFIG_ETRAX_DS1302_RSTBIT == 0 - if (cris_io_interface_allocate_pins(if_gpio_grp_a, - 'g', - CONFIG_ETRAX_DS1302_RSTBIT, - CONFIG_ETRAX_DS1302_RSTBIT)) { - printk(KERN_WARNING "ds1302: Failed to get IO interface\n"); - return -1; - } - - /* Set the direction of this bit to out. */ - genconfig_shadow = ((genconfig_shadow & - ~IO_MASK(R_GEN_CONFIG, g0dir)) | - (IO_STATE(R_GEN_CONFIG, g0dir, out))); - *R_GEN_CONFIG = genconfig_shadow; -#endif - if (!ds1302_probe()) { - printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); - return -1; - } -#else - printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); - return -1; -#endif - } - /* Initialise trickle charger */ - ds1302_writereg(RTC_TRICKLECHARGER, - RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F)); - /* Start clock by resetting CLOCK_HALT */ - ds1302_writereg(RTC_SECONDS, (ds1302_readreg(RTC_SECONDS) & 0x7F)); - return 0; -} - -static int __init ds1302_register(void) -{ - ds1302_init(); - if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { - printk(KERN_INFO "%s: unable to get major %d for rtc\n", - ds1302_name, RTC_MAJOR_NR); - return -1; - } - return 0; - -} - -module_init(ds1302_register); diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c deleted file mode 100644 index 9da056860c92..000000000000 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * PCF8563 RTC - * - * From Phillips' datasheet: - * - * The PCF8563 is a CMOS real-time clock/calendar optimized for low power - * consumption. A programmable clock output, interrupt output and voltage - * low detector are also provided. All address and data are transferred - * serially via two-line bidirectional I2C-bus. Maximum bus speed is - * 400 kbits/s. The built-in word address register is incremented - * automatically after each written or read byte. - * - * Copyright (c) 2002-2007, Axis Communications AB - * All rights reserved. - * - * Author: Tobias Anderberg <tobiasa@axis.com>. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/ioctl.h> -#include <linux/delay.h> -#include <linux/bcd.h> -#include <linux/mutex.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/rtc.h> - -#include "i2c.h" - -#define PCF8563_MAJOR 121 /* Local major number. */ -#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ -#define PCF8563_NAME "PCF8563" -#define DRIVER_VERSION "$Revision: 1.24 $" - -/* I2C bus slave registers. */ -#define RTC_I2C_READ 0xa3 -#define RTC_I2C_WRITE 0xa2 - -/* Two simple wrapper macros, saves a few keystrokes. */ -#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) -#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) - -static DEFINE_MUTEX(pcf8563_mutex); -static DEFINE_MUTEX(rtc_lock); /* Protect state etc */ - -static const unsigned char days_in_month[] = - { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -static long pcf8563_unlocked_ioctl(struct file *, unsigned int, unsigned long); - -/* Cache VL bit value read at driver init since writing the RTC_SECOND - * register clears the VL status. - */ -static int voltage_low; - -static const struct file_operations pcf8563_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = pcf8563_unlocked_ioctl, - .llseek = noop_llseek, -}; - -unsigned char -pcf8563_readreg(int reg) -{ - unsigned char res = rtc_read(reg); - - /* The PCF8563 does not return 0 for unimplemented bits. */ - switch (reg) { - case RTC_SECONDS: - case RTC_MINUTES: - res &= 0x7F; - break; - case RTC_HOURS: - case RTC_DAY_OF_MONTH: - res &= 0x3F; - break; - case RTC_WEEKDAY: - res &= 0x07; - break; - case RTC_MONTH: - res &= 0x1F; - break; - case RTC_CONTROL1: - res &= 0xA8; - break; - case RTC_CONTROL2: - res &= 0x1F; - break; - case RTC_CLOCKOUT_FREQ: - case RTC_TIMER_CONTROL: - res &= 0x83; - break; - } - return res; -} - -void -pcf8563_writereg(int reg, unsigned char val) -{ - rtc_write(reg, val); -} - -void -get_rtc_time(struct rtc_time *tm) -{ - tm->tm_sec = rtc_read(RTC_SECONDS); - tm->tm_min = rtc_read(RTC_MINUTES); - tm->tm_hour = rtc_read(RTC_HOURS); - tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH); - tm->tm_wday = rtc_read(RTC_WEEKDAY); - tm->tm_mon = rtc_read(RTC_MONTH); - tm->tm_year = rtc_read(RTC_YEAR); - - if (tm->tm_sec & 0x80) { - printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time " - "information is no longer guaranteed!\n", PCF8563_NAME); - } - - tm->tm_year = bcd2bin(tm->tm_year) + - ((tm->tm_mon & 0x80) ? 100 : 0); - tm->tm_sec &= 0x7F; - tm->tm_min &= 0x7F; - tm->tm_hour &= 0x3F; - tm->tm_mday &= 0x3F; - tm->tm_wday &= 0x07; /* Not coded in BCD. */ - tm->tm_mon &= 0x1F; - - tm->tm_sec = bcd2bin(tm->tm_sec); - tm->tm_min = bcd2bin(tm->tm_min); - tm->tm_hour = bcd2bin(tm->tm_hour); - tm->tm_mday = bcd2bin(tm->tm_mday); - tm->tm_mon = bcd2bin(tm->tm_mon); - tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */ -} - -int __init -pcf8563_init(void) -{ - static int res; - static int first = 1; - - if (!first) - return res; - first = 0; - - /* Initiate the i2c protocol. */ - res = i2c_init(); - if (res < 0) { - printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n"); - return res; - } - - /* - * First of all we need to reset the chip. This is done by - * clearing control1, control2 and clk freq and resetting - * all alarms. - */ - if (rtc_write(RTC_CONTROL1, 0x00) < 0) - goto err; - - if (rtc_write(RTC_CONTROL2, 0x00) < 0) - goto err; - - if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0) - goto err; - - if (rtc_write(RTC_TIMER_CONTROL, 0x03) < 0) - goto err; - - /* Reset the alarms. */ - if (rtc_write(RTC_MINUTE_ALARM, 0x80) < 0) - goto err; - - if (rtc_write(RTC_HOUR_ALARM, 0x80) < 0) - goto err; - - if (rtc_write(RTC_DAY_ALARM, 0x80) < 0) - goto err; - - if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0) - goto err; - - /* Check for low voltage, and warn about it. */ - if (rtc_read(RTC_SECONDS) & 0x80) { - voltage_low = 1; - printk(KERN_WARNING "%s: RTC Voltage Low - reliable " - "date/time information is no longer guaranteed!\n", - PCF8563_NAME); - } - - return res; - -err: - printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); - res = -1; - return res; -} - -void __exit -pcf8563_exit(void) -{ - unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME); -} - -/* - * ioctl calls for this driver. Why return -ENOTTY upon error? Because - * POSIX says so! - */ -static int pcf8563_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - /* Some sanity checks. */ - if (_IOC_TYPE(cmd) != RTC_MAGIC) - return -ENOTTY; - - if (_IOC_NR(cmd) > RTC_MAX_IOCTL) - return -ENOTTY; - - switch (cmd) { - case RTC_RD_TIME: - { - struct rtc_time tm; - - mutex_lock(&rtc_lock); - memset(&tm, 0, sizeof tm); - get_rtc_time(&tm); - - if (copy_to_user((struct rtc_time *) arg, &tm, - sizeof tm)) { - mutex_unlock(&rtc_lock); - return -EFAULT; - } - - mutex_unlock(&rtc_lock); - - return 0; - } - case RTC_SET_TIME: - { - int leap; - int year; - int century; - struct rtc_time tm; - - memset(&tm, 0, sizeof tm); - if (!capable(CAP_SYS_TIME)) - return -EPERM; - - if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof tm)) - return -EFAULT; - - /* Convert from struct tm to struct rtc_time. */ - tm.tm_year += 1900; - tm.tm_mon += 1; - - /* - * Check if tm.tm_year is a leap year. A year is a leap - * year if it is divisible by 4 but not 100, except - * that years divisible by 400 _are_ leap years. - */ - year = tm.tm_year; - leap = (tm.tm_mon == 2) && - ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); - - /* Perform some sanity checks. */ - if ((tm.tm_year < 1970) || - (tm.tm_mon > 12) || - (tm.tm_mday == 0) || - (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || - (tm.tm_wday >= 7) || - (tm.tm_hour >= 24) || - (tm.tm_min >= 60) || - (tm.tm_sec >= 60)) - return -EINVAL; - - century = (tm.tm_year >= 2000) ? 0x80 : 0; - tm.tm_year = tm.tm_year % 100; - - tm.tm_year = bin2bcd(tm.tm_year); - tm.tm_mon = bin2bcd(tm.tm_mon); - tm.tm_mday = bin2bcd(tm.tm_mday); - tm.tm_hour = bin2bcd(tm.tm_hour); - tm.tm_min = bin2bcd(tm.tm_min); - tm.tm_sec = bin2bcd(tm.tm_sec); - tm.tm_mon |= century; - - mutex_lock(&rtc_lock); - - rtc_write(RTC_YEAR, tm.tm_year); - rtc_write(RTC_MONTH, tm.tm_mon); - rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */ - rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); - rtc_write(RTC_HOURS, tm.tm_hour); - rtc_write(RTC_MINUTES, tm.tm_min); - rtc_write(RTC_SECONDS, tm.tm_sec); - - mutex_unlock(&rtc_lock); - - return 0; - } - case RTC_VL_READ: - if (voltage_low) { - printk(KERN_ERR "%s: RTC Voltage Low - " - "reliable date/time information is no " - "longer guaranteed!\n", PCF8563_NAME); - } - - if (copy_to_user((int *) arg, &voltage_low, sizeof(int))) - return -EFAULT; - return 0; - - case RTC_VL_CLR: - { - /* Clear the VL bit in the seconds register in case - * the time has not been set already (which would - * have cleared it). This does not really matter - * because of the cached voltage_low value but do it - * anyway for consistency. */ - - int ret = rtc_read(RTC_SECONDS); - - rtc_write(RTC_SECONDS, (ret & 0x7F)); - - /* Clear the cached value. */ - voltage_low = 0; - - return 0; - } - default: - return -ENOTTY; - } - - return 0; -} - -static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&pcf8563_mutex); - ret = pcf8563_ioctl(filp, cmd, arg); - mutex_unlock(&pcf8563_mutex); - - return ret; -} - -static int __init pcf8563_register(void) -{ - if (pcf8563_init() < 0) { - printk(KERN_INFO "%s: Unable to initialize Real-Time Clock " - "Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); - return -1; - } - - if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { - printk(KERN_INFO "%s: Unable to get major number %d for RTC device.\n", - PCF8563_NAME, PCF8563_MAJOR); - return -1; - } - - printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, - DRIVER_VERSION); - - /* Check for low voltage, and warn about it. */ - if (voltage_low) { - printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time " - "information is no longer guaranteed!\n", PCF8563_NAME); - } - - return 0; -} - -module_init(pcf8563_register); -module_exit(pcf8563_exit); diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c index 8a8196ee8ce8..082f1890bacb 100644 --- a/arch/cris/arch-v10/kernel/fasttimer.c +++ b/arch/cris/arch-v10/kernel/fasttimer.c @@ -21,8 +21,6 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/delay.h> -#include <asm/rtc.h> - #include <arch/svinto.h> #include <asm/fasttimer.h> diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c index b579dd02e098..37e6d2c50b76 100644 --- a/arch/cris/arch-v10/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -264,7 +264,7 @@ static int write_register (int regno, char *val); /* Write a value to a specified register in the stack of a thread other than the current thread. */ -static write_stack_register (int thread_id, int regno, char *valptr); +static int write_stack_register(int thread_id, int regno, char *valptr); /* Read a value from a specified register in the register image. Returns the status of the read operation. The register value is returned in valptr. */ diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c index 20c85b5dc7d0..bcffcb6a9415 100644 --- a/arch/cris/arch-v10/kernel/time.c +++ b/arch/cris/arch-v10/kernel/time.c @@ -19,16 +19,12 @@ #include <asm/signal.h> #include <asm/io.h> #include <asm/delay.h> -#include <asm/rtc.h> #include <asm/irq_regs.h> /* define this if you need to use print_timestamp */ /* it will make jiffies at 96 hz instead of 100 hz though */ #undef USE_CASCADE_TIMERS -extern int set_rtc_mmss(unsigned long nowtime); -extern int have_rtc; - unsigned long get_ns_in_jiffie(void) { unsigned char timer_count, t1; @@ -203,11 +199,6 @@ time_init(void) */ loops_per_usec = 50; - if(RTC_INIT() < 0) - have_rtc = 0; - else - have_rtc = 1; - /* Setup the etrax timers * Base frequency is 25000 hz, divider 250 -> 100 HZ * In normal mode, we use timer0, so timer1 is free. In cascade diff --git a/arch/cris/arch-v10/lib/Makefile b/arch/cris/arch-v10/lib/Makefile index 36e9a9c5239b..725153edb764 100644 --- a/arch/cris/arch-v10/lib/Makefile +++ b/arch/cris/arch-v10/lib/Makefile @@ -2,8 +2,5 @@ # Makefile for Etrax-specific library files.. # - -EXTRA_AFLAGS := -traditional - lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c index 642c6fed43d7..f8476d9e856b 100644 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ b/arch/cris/arch-v32/drivers/cryptocop.c @@ -1394,11 +1394,10 @@ static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, char if (padlen < MD5_MIN_PAD_LENGTH) padlen += MD5_BLOCK_LENGTH; - p = kmalloc(padlen, alloc_flag); + p = kzalloc(padlen, alloc_flag); if (!p) return -ENOMEM; *p = 0x80; - memset(p+1, 0, padlen - 1); DEBUG(printk("create_md5_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length)); @@ -1426,11 +1425,10 @@ static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, cha if (padlen < SHA1_MIN_PAD_LENGTH) padlen += SHA1_BLOCK_LENGTH; - p = kmalloc(padlen, alloc_flag); + p = kzalloc(padlen, alloc_flag); if (!p) return -ENOMEM; *p = 0x80; - memset(p+1, 0, padlen - 1); DEBUG(printk("create_sha1_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length)); diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index f7ad9e8637df..f085229cf870 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c @@ -114,8 +114,6 @@ void user_disable_single_step(struct task_struct *child) void ptrace_disable(struct task_struct *child) { - unsigned long tmp; - /* Deconfigure SPC and S-bit. */ user_disable_single_step(child); put_reg(child, PT_SPC, 0); diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index 6773fc83a670..8c4b45efd7b6 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -18,7 +18,6 @@ #include <asm/signal.h> #include <asm/io.h> #include <asm/delay.h> -#include <asm/rtc.h> #include <asm/irq.h> #include <asm/irq_regs.h> @@ -67,7 +66,6 @@ unsigned long timer_regs[NR_CPUS] = }; extern int set_rtc_mmss(unsigned long nowtime); -extern int have_rtc; #ifdef CONFIG_CPU_FREQ static int @@ -265,11 +263,6 @@ void __init time_init(void) */ loops_per_usec = 50; - if(RTC_INIT() < 0) - have_rtc = 0; - else - have_rtc = 1; - /* Start CPU local timer. */ cris_timer_init(); diff --git a/arch/cris/include/arch-v32/arch/cache.h b/arch/cris/include/arch-v32/arch/cache.h index 1de779f4f240..7caf25d58e6b 100644 --- a/arch/cris/include/arch-v32/arch/cache.h +++ b/arch/cris/include/arch-v32/arch/cache.h @@ -7,7 +7,7 @@ #define L1_CACHE_BYTES 32 #define L1_CACHE_SHIFT 5 -#define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) void flush_dma_list(dma_descr_data *descr); void flush_dma_descr(dma_descr_data *descr, int flush_buf); diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 956eea246b97..04d02a51c5e9 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -6,5 +6,4 @@ header-y += arch-v32/ header-y += ethernet.h header-y += etraxgpio.h header-y += rs485.h -header-y += rtc.h header-y += sync_serial.h diff --git a/arch/cris/include/asm/posix_types.h b/arch/cris/include/asm/posix_types.h index 72b3cd6eda0b..234891c74e2b 100644 --- a/arch/cris/include/asm/posix_types.h +++ b/arch/cris/include/asm/posix_types.h @@ -33,4 +33,6 @@ typedef int __kernel_ptrdiff_t; typedef unsigned short __kernel_old_dev_t; #define __kernel_old_dev_t __kernel_old_dev_t +#include <asm-generic/posix_types.h> + #endif /* __ARCH_CRIS_POSIX_TYPES_H */ diff --git a/arch/cris/include/asm/rtc.h b/arch/cris/include/asm/rtc.h deleted file mode 100644 index 17d3019529e1..000000000000 --- a/arch/cris/include/asm/rtc.h +++ /dev/null @@ -1,107 +0,0 @@ - -#ifndef __RTC_H__ -#define __RTC_H__ - -#ifdef CONFIG_ETRAX_DS1302 - /* Dallas DS1302 clock/calendar register numbers. */ -# define RTC_SECONDS 0 -# define RTC_MINUTES 1 -# define RTC_HOURS 2 -# define RTC_DAY_OF_MONTH 3 -# define RTC_MONTH 4 -# define RTC_WEEKDAY 5 -# define RTC_YEAR 6 -# define RTC_CONTROL 7 - - /* Bits in CONTROL register. */ -# define RTC_CONTROL_WRITEPROTECT 0x80 -# define RTC_TRICKLECHARGER 8 - - /* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS. */ -# define RTC_TCR_PATTERN 0xA0 /* 1010xxxx */ -# define RTC_TCR_1DIOD 0x04 /* xxxx01xx */ -# define RTC_TCR_2DIOD 0x08 /* xxxx10xx */ -# define RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */ -# define RTC_TCR_2KOHM 0x01 /* xxxxxx01 2KOhm */ -# define RTC_TCR_4KOHM 0x02 /* xxxxxx10 4kOhm */ -# define RTC_TCR_8KOHM 0x03 /* xxxxxx11 8kOhm */ - -#elif defined(CONFIG_ETRAX_PCF8563) - /* I2C bus slave registers. */ -# define RTC_I2C_READ 0xa3 -# define RTC_I2C_WRITE 0xa2 - - /* Phillips PCF8563 registers. */ -# define RTC_CONTROL1 0x00 /* Control/Status register 1. */ -# define RTC_CONTROL2 0x01 /* Control/Status register 2. */ -# define RTC_CLOCKOUT_FREQ 0x0d /* CLKOUT frequency. */ -# define RTC_TIMER_CONTROL 0x0e /* Timer control. */ -# define RTC_TIMER_CNTDOWN 0x0f /* Timer countdown. */ - - /* BCD encoded clock registers. */ -# define RTC_SECONDS 0x02 -# define RTC_MINUTES 0x03 -# define RTC_HOURS 0x04 -# define RTC_DAY_OF_MONTH 0x05 -# define RTC_WEEKDAY 0x06 /* Not coded in BCD! */ -# define RTC_MONTH 0x07 -# define RTC_YEAR 0x08 -# define RTC_MINUTE_ALARM 0x09 -# define RTC_HOUR_ALARM 0x0a -# define RTC_DAY_ALARM 0x0b -# define RTC_WEEKDAY_ALARM 0x0c - -#endif - -#ifdef CONFIG_ETRAX_DS1302 -extern unsigned char ds1302_readreg(int reg); -extern void ds1302_writereg(int reg, unsigned char val); -extern int ds1302_init(void); -# define CMOS_READ(x) ds1302_readreg(x) -# define CMOS_WRITE(val,reg) ds1302_writereg(reg,val) -# define RTC_INIT() ds1302_init() -#elif defined(CONFIG_ETRAX_PCF8563) -extern unsigned char pcf8563_readreg(int reg); -extern void pcf8563_writereg(int reg, unsigned char val); -extern int pcf8563_init(void); -# define CMOS_READ(x) pcf8563_readreg(x) -# define CMOS_WRITE(val,reg) pcf8563_writereg(reg,val) -# define RTC_INIT() pcf8563_init() -#else - /* No RTC configured so we shouldn't try to access any. */ -# define CMOS_READ(x) 42 -# define CMOS_WRITE(x,y) -# define RTC_INIT() (-1) -#endif - -/* - * The struct used to pass data via the following ioctl. Similar to the - * struct tm in <time.h>, but it needs to be here so that the kernel - * source is self contained, allowing cross-compiles, etc. etc. - */ -struct rtc_time { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -/* ioctl() calls that are permitted to the /dev/rtc interface. */ -#define RTC_MAGIC 'p' -/* Read RTC time. */ -#define RTC_RD_TIME _IOR(RTC_MAGIC, 0x09, struct rtc_time) -/* Set RTC time. */ -#define RTC_SET_TIME _IOW(RTC_MAGIC, 0x0a, struct rtc_time) -#define RTC_SET_CHARGE _IOW(RTC_MAGIC, 0x0b, int) -/* Voltage low detector */ -#define RTC_VL_READ _IOR(RTC_MAGIC, 0x13, int) -/* Clear voltage low information */ -#define RTC_VL_CLR _IO(RTC_MAGIC, 0x14) -#define RTC_MAX_IOCTL 0x14 - -#endif /* __RTC_H__ */ diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c index 4e73092e85c0..277ffc459e4b 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -21,7 +21,6 @@ * */ -#include <asm/rtc.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/param.h> @@ -32,7 +31,8 @@ #include <linux/profile.h> #include <linux/sched.h> /* just for sched_clock() - funny that */ -int have_rtc; /* used to remember if we have an RTC or not */; + +#define D(x) #define TICK_SIZE tick @@ -50,78 +50,16 @@ u32 arch_gettimeoffset(void) } #endif -/* - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you'll only notice that after reboot! - */ - int set_rtc_mmss(unsigned long nowtime) { - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - - printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime); - - if(!have_rtc) - return 0; - - cmos_minutes = CMOS_READ(RTC_MINUTES); - cmos_minutes = bcd2bin(cmos_minutes); - - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes - */ - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) - real_minutes += 30; /* correct for half hour time zone */ - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - real_seconds = bin2bcd(real_seconds); - real_minutes = bin2bcd(real_minutes); - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk_once(KERN_NOTICE - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - return retval; + D(printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime)); + return 0; } /* grab the time from the RTC chip */ - -unsigned long -get_cmos_time(void) +unsigned long get_cmos_time(void) { - unsigned int year, mon, day, hour, min, sec; - if(!have_rtc) - return 0; - - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - - sec = bcd2bin(sec); - min = bcd2bin(min); - hour = bcd2bin(hour); - day = bcd2bin(day); - mon = bcd2bin(mon); - year = bcd2bin(year); - - if ((year += 1900) < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); + return 0; } @@ -132,7 +70,7 @@ int update_persistent_clock(struct timespec now) void read_persistent_clock(struct timespec *ts) { - ts->tv_sec = get_cmos_time(); + ts->tv_sec = 0; ts->tv_nsec = 0; } diff --git a/arch/cris/kernel/vmlinux.lds.S b/arch/cris/kernel/vmlinux.lds.S index a6990cb0f098..a68b983dcea1 100644 --- a/arch/cris/kernel/vmlinux.lds.S +++ b/arch/cris/kernel/vmlinux.lds.S @@ -52,6 +52,7 @@ SECTIONS EXCEPTION_TABLE(4) + _sdata = .; RODATA . = ALIGN (4); diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c index b4760d86e1bb..45fd542cf173 100644 --- a/arch/cris/mm/fault.c +++ b/arch/cris/mm/fault.c @@ -58,6 +58,8 @@ do_page_fault(unsigned long address, struct pt_regs *regs, struct vm_area_struct * vma; siginfo_t info; int fault; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | + ((writeaccess & 1) ? FAULT_FLAG_WRITE : 0); D(printk(KERN_DEBUG "Page fault for %lX on %X at %lX, prot %d write %d\n", @@ -115,6 +117,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs, if (in_atomic() || !mm) goto no_context; +retry: down_read(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) @@ -163,7 +166,11 @@ do_page_fault(unsigned long address, struct pt_regs *regs, * the fault. */ - fault = handle_mm_fault(mm, vma, address, (writeaccess & 1) ? FAULT_FLAG_WRITE : 0); + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -171,10 +178,24 @@ do_page_fault(unsigned long address, struct pt_regs *regs, goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; + + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) + tsk->maj_flt++; + else + tsk->min_flt++; + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + + /* + * No need to up_read(&mm->mmap_sem) as we would + * have already released it in __lock_page_or_retry + * in mm/filemap.c. + */ + + goto retry; + } + } up_read(&mm->mmap_sem); return; diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 4932247d078a..49765b53f637 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -19,6 +19,8 @@ config OPENRISC select GENERIC_CPU_DEVICES select GENERIC_ATOMIC64 select GENERIC_CLOCKEVENTS + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER config MMU def_bool y diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild index c936483bc8e2..3f35c38d7b64 100644 --- a/arch/openrisc/include/asm/Kbuild +++ b/arch/openrisc/include/asm/Kbuild @@ -66,3 +66,4 @@ generic-y += topology.h generic-y += types.h generic-y += ucontext.h generic-y += user.h +generic-y += word-at-a-time.h diff --git a/arch/openrisc/include/asm/uaccess.h b/arch/openrisc/include/asm/uaccess.h index f5abaa0ffc38..ab2e7a198a4c 100644 --- a/arch/openrisc/include/asm/uaccess.h +++ b/arch/openrisc/include/asm/uaccess.h @@ -313,42 +313,12 @@ clear_user(void *addr, unsigned long size) return size; } -extern int __strncpy_from_user(char *dst, const char *src, long count); +#define user_addr_max() \ + (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL) -static inline long strncpy_from_user(char *dst, const char *src, long count) -{ - if (access_ok(VERIFY_READ, src, 1)) - return __strncpy_from_user(dst, src, count); - return -EFAULT; -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 for error - */ - -extern int __strnlen_user(const char *str, long len, unsigned long top); - -/* - * Returns the length of the string at str (including the null byte), - * or 0 if we hit a page we can't access, - * or something > len if we didn't find a null byte. - * - * The `top' parameter to __strnlen_user is to make sure that - * we can never overflow from the user area into kernel space. - */ -static inline long strnlen_user(const char __user *str, long len) -{ - unsigned long top = (unsigned long)get_fs(); - unsigned long res = 0; - - if (__addr_ok(str)) - res = __strnlen_user(str, len, top); - - return res; -} +extern long strncpy_from_user(char *dest, const char __user *src, long count); -#define strlen_user(str) strnlen_user(str, TASK_SIZE-1) +extern __must_check long strlen_user(const char __user *str); +extern __must_check long strnlen_user(const char __user *str, long n); #endif /* __ASM_OPENRISC_UACCESS_H */ diff --git a/arch/openrisc/lib/string.S b/arch/openrisc/lib/string.S index 465f04bc7deb..c09fee7dec14 100644 --- a/arch/openrisc/lib/string.S +++ b/arch/openrisc/lib/string.S @@ -103,102 +103,3 @@ __clear_user: .section __ex_table, "a" .long 9b, 99b // write fault .previous - -/* - * long strncpy_from_user(char *dst, const char *src, long count) - * - * - */ - .global __strncpy_from_user -__strncpy_from_user: - l.addi r1,r1,-16 - l.sw 0(r1),r6 - l.sw 4(r1),r5 - l.sw 8(r1),r4 - l.sw 12(r1),r3 - - l.addi r11,r5,0 -2: l.sfeq r5,r0 - l.bf 1f - l.addi r5,r5,-1 -8: l.lbz r6,0(r4) - l.sfeq r6,r0 - l.bf 1f -9: l.sb 0(r3),r6 - l.addi r3,r3,1 - l.j 2b - l.addi r4,r4,1 -1: - l.lwz r6,0(r1) - l.addi r5,r5,1 - l.sub r11,r11,r5 // r11 holds the return value - - l.lwz r6,0(r1) - l.lwz r5,4(r1) - l.lwz r4,8(r1) - l.lwz r3,12(r1) - l.jr r9 - l.addi r1,r1,16 - - .section .fixup, "ax" -99: - l.movhi r11,hi(-EFAULT) - l.ori r11,r11,lo(-EFAULT) - - l.lwz r6,0(r1) - l.lwz r5,4(r1) - l.lwz r4,8(r1) - l.lwz r3,12(r1) - l.jr r9 - l.addi r1,r1,16 - .previous - - .section __ex_table, "a" - .long 8b, 99b // read fault - .previous - -/* - * extern int __strnlen_user(const char *str, long len, unsigned long top); - * - * - * RTRN: - length of a string including NUL termination character - * - on page fault 0 - */ - - .global __strnlen_user -__strnlen_user: - l.addi r1,r1,-8 - l.sw 0(r1),r6 - l.sw 4(r1),r3 - - l.addi r11,r0,0 -2: l.sfeq r11,r4 - l.bf 1f - l.addi r11,r11,1 -8: l.lbz r6,0(r3) - l.sfeq r6,r0 - l.bf 1f - l.sfgeu r3,r5 // are we over the top ? - l.bf 99f - l.j 2b - l.addi r3,r3,1 - -1: - l.lwz r6,0(r1) - l.lwz r3,4(r1) - l.jr r9 - l.addi r1,r1,8 - - .section .fixup, "ax" -99: - l.addi r11,r0,0 - - l.lwz r6,0(r1) - l.lwz r3,4(r1) - l.jr r9 - l.addi r1,r1,8 - .previous - - .section __ex_table, "a" - .long 8b, 99b // read fault - .previous diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 00b9874e2240..050cb371a69e 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -135,6 +135,8 @@ config PPC select GENERIC_CMOS_UPDATE select GENERIC_TIME_VSYSCALL select GENERIC_CLOCKEVENTS + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER config EARLY_PRINTK bool 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/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index bd0fb8495154..17bb40cad5bf 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -40,6 +40,8 @@ #define segment_eq(a, b) ((a).seg == (b).seg) +#define user_addr_max() (get_fs().seg) + #ifdef __powerpc64__ /* * This check is sufficient because there is a large enough @@ -453,42 +455,9 @@ static inline unsigned long clear_user(void __user *addr, unsigned long size) return size; } -extern int __strncpy_from_user(char *dst, const char __user *src, long count); - -static inline long strncpy_from_user(char *dst, const char __user *src, - long count) -{ - might_sleep(); - if (likely(access_ok(VERIFY_READ, src, 1))) - return __strncpy_from_user(dst, src, count); - return -EFAULT; -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 for error - */ -extern int __strnlen_user(const char __user *str, long len, unsigned long top); - -/* - * Returns the length of the string at str (including the null byte), - * or 0 if we hit a page we can't access, - * or something > len if we didn't find a null byte. - * - * The `top' parameter to __strnlen_user is to make sure that - * we can never overflow from the user area into kernel space. - */ -static inline int strnlen_user(const char __user *str, long len) -{ - unsigned long top = current->thread.fs.seg; - - if ((unsigned long)str > top) - return 0; - return __strnlen_user(str, len, top); -} - -#define strlen_user(str) strnlen_user((str), 0x7ffffffe) +extern long strncpy_from_user(char *dst, const char __user *src, long count); +extern __must_check long strlen_user(const char __user *str); +extern __must_check long strnlen_user(const char __user *str, long n); #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/word-at-a-time.h b/arch/powerpc/include/asm/word-at-a-time.h new file mode 100644 index 000000000000..d0b6d4ac6dda --- /dev/null +++ b/arch/powerpc/include/asm/word-at-a-time.h @@ -0,0 +1,41 @@ +#ifndef _ASM_WORD_AT_A_TIME_H +#define _ASM_WORD_AT_A_TIME_H + +/* + * Word-at-a-time interfaces for PowerPC. + */ + +#include <linux/kernel.h> +#include <asm/asm-compat.h> + +struct word_at_a_time { + const unsigned long high_bits, low_bits; +}; + +#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) } + +/* Bit set in the bytes that have a zero */ +static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c) +{ + unsigned long mask = (val & c->low_bits) + c->low_bits; + return ~(mask | rhs); +} + +#define create_zero_mask(mask) (mask) + +static inline long find_zero(unsigned long mask) +{ + long leading_zero_bits; + + asm (PPC_CNTLZL "%0,%1" : "=r" (leading_zero_bits) : "r" (mask)); + return leading_zero_bits >> 3; +} + +static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) +{ + unsigned long rhs = val | c->low_bits; + *data = rhs; + return (val + c->high_bits) & ~rhs; +} + +#endif /* _ASM_WORD_AT_A_TIME_H */ diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index d1f2aafcbe8c..3e4031581c65 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c @@ -85,8 +85,6 @@ EXPORT_SYMBOL(csum_tcpudp_magic); EXPORT_SYMBOL(__copy_tofrom_user); EXPORT_SYMBOL(__clear_user); -EXPORT_SYMBOL(__strncpy_from_user); -EXPORT_SYMBOL(__strnlen_user); EXPORT_SYMBOL(copy_page); #if defined(CONFIG_PCI) && defined(CONFIG_PPC32) diff --git a/arch/powerpc/lib/string.S b/arch/powerpc/lib/string.S index 455881a5563f..093d6316435c 100644 --- a/arch/powerpc/lib/string.S +++ b/arch/powerpc/lib/string.S @@ -160,48 +160,3 @@ _GLOBAL(__clear_user) PPC_LONG 1b,91b PPC_LONG 8b,92b .text - -_GLOBAL(__strncpy_from_user) - addi r6,r3,-1 - addi r4,r4,-1 - cmpwi 0,r5,0 - beq 2f - mtctr r5 -1: lbzu r0,1(r4) - cmpwi 0,r0,0 - stbu r0,1(r6) - bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ - beq 3f -2: addi r6,r6,1 -3: subf r3,r3,r6 - blr -99: li r3,-EFAULT - blr - - .section __ex_table,"a" - PPC_LONG 1b,99b - .text - -/* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ -_GLOBAL(__strnlen_user) - addi r7,r3,-1 - subf r6,r7,r5 /* top+1 - str */ - cmplw 0,r4,r6 - bge 0f - mr r6,r4 -0: mtctr r6 /* ctr = min(len, top - str) */ -1: lbzu r0,1(r7) /* get next byte */ - cmpwi 0,r0,0 - bdnzf 2,1b /* loop if --ctr != 0 && byte != 0 */ - addi r7,r7,1 - subf r3,r3,r7 /* number of bytes we have looked at */ - beqlr /* return if we found a 0 byte */ - cmpw 0,r3,r4 /* did we look at all len bytes? */ - blt 99f /* if not, must have hit top */ - addi r3,r4,1 /* return len + 1 to indicate no null found */ - blr -99: li r3,0 /* bad address, return 0 */ - blr - - .section __ex_table,"a" - PPC_LONG 1b,99b diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 15e9e05740da..83bd051754e1 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -35,6 +35,7 @@ config SPARC select GENERIC_CMOS_UPDATE select GENERIC_CLOCKEVENTS select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER config SPARC32 def_bool !64BIT diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild index 2c2e38821f60..67f83e0a0d68 100644 --- a/arch/sparc/include/asm/Kbuild +++ b/arch/sparc/include/asm/Kbuild @@ -21,3 +21,4 @@ generic-y += div64.h generic-y += local64.h generic-y += irq_regs.h generic-y += local.h +generic-y += word-at-a-time.h diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h index 59586b57ef1a..53a28dd59f59 100644 --- a/arch/sparc/include/asm/uaccess_32.h +++ b/arch/sparc/include/asm/uaccess_32.h @@ -16,6 +16,8 @@ #ifndef __ASSEMBLY__ +#include <asm/processor.h> + #define ARCH_HAS_SORT_EXTABLE #define ARCH_HAS_SEARCH_EXTABLE @@ -304,24 +306,8 @@ static inline unsigned long clear_user(void __user *addr, unsigned long n) return n; } -extern long __strlen_user(const char __user *); -extern long __strnlen_user(const char __user *, long len); - -static inline long strlen_user(const char __user *str) -{ - if (!access_ok(VERIFY_READ, str, 0)) - return 0; - else - return __strlen_user(str); -} - -static inline long strnlen_user(const char __user *str, long len) -{ - if (!access_ok(VERIFY_READ, str, 0)) - return 0; - else - return __strnlen_user(str, len); -} +extern __must_check long strlen_user(const char __user *str); +extern __must_check long strnlen_user(const char __user *str, long n); #endif /* __ASSEMBLY__ */ diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h index dcdfb89cbf3f..7c831d848b4e 100644 --- a/arch/sparc/include/asm/uaccess_64.h +++ b/arch/sparc/include/asm/uaccess_64.h @@ -17,6 +17,8 @@ #ifndef __ASSEMBLY__ +#include <asm/processor.h> + /* * Sparc64 is segmented, though more like the M68K than the I386. * We use the secondary ASI to address user memory, which references a @@ -257,11 +259,9 @@ extern unsigned long __must_check __clear_user(void __user *, unsigned long); #define clear_user __clear_user -extern long __strlen_user(const char __user *); -extern long __strnlen_user(const char __user *, long len); +extern __must_check long strlen_user(const char __user *str); +extern __must_check long strnlen_user(const char __user *str, long n); -#define strlen_user __strlen_user -#define strnlen_user __strnlen_user #define __copy_to_user_inatomic ___copy_to_user #define __copy_from_user_inatomic ___copy_from_user diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 943d98dc4cdb..dff4096f3dec 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -10,7 +10,6 @@ lib-y += strlen.o lib-y += checksum_$(BITS).o lib-$(CONFIG_SPARC32) += blockops.o lib-y += memscan_$(BITS).o memcmp.o strncmp_$(BITS).o -lib-y += strlen_user_$(BITS).o lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o lib-$(CONFIG_SPARC32) += copy_user.o locks.o lib-$(CONFIG_SPARC64) += atomic_64.o diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 6b278abdb63d..3b31218cafc6 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c @@ -15,8 +15,6 @@ /* string functions */ EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(__strlen_user); -EXPORT_SYMBOL(__strnlen_user); EXPORT_SYMBOL(strncmp); /* mem* functions */ diff --git a/arch/sparc/lib/strlen_user_32.S b/arch/sparc/lib/strlen_user_32.S deleted file mode 100644 index 8c8a371df3c9..000000000000 --- a/arch/sparc/lib/strlen_user_32.S +++ /dev/null @@ -1,109 +0,0 @@ -/* strlen_user.S: Sparc optimized strlen_user code - * - * Return length of string in userspace including terminating 0 - * or 0 for error - * - * Copyright (C) 1991,1996 Free Software Foundation - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#define LO_MAGIC 0x01010101 -#define HI_MAGIC 0x80808080 - -10: - ldub [%o0], %o5 - cmp %o5, 0 - be 1f - add %o0, 1, %o0 - andcc %o0, 3, %g0 - be 4f - or %o4, %lo(HI_MAGIC), %o3 -11: - ldub [%o0], %o5 - cmp %o5, 0 - be 2f - add %o0, 1, %o0 - andcc %o0, 3, %g0 - be 5f - sethi %hi(LO_MAGIC), %o4 -12: - ldub [%o0], %o5 - cmp %o5, 0 - be 3f - add %o0, 1, %o0 - b 13f - or %o4, %lo(LO_MAGIC), %o2 -1: - retl - mov 1, %o0 -2: - retl - mov 2, %o0 -3: - retl - mov 3, %o0 - - .align 4 - .global __strlen_user, __strnlen_user -__strlen_user: - sethi %hi(32768), %o1 -__strnlen_user: - mov %o1, %g1 - mov %o0, %o1 - andcc %o0, 3, %g0 - bne 10b - sethi %hi(HI_MAGIC), %o4 - or %o4, %lo(HI_MAGIC), %o3 -4: - sethi %hi(LO_MAGIC), %o4 -5: - or %o4, %lo(LO_MAGIC), %o2 -13: - ld [%o0], %o5 -2: - sub %o5, %o2, %o4 - andcc %o4, %o3, %g0 - bne 82f - add %o0, 4, %o0 - sub %o0, %o1, %g2 -81: cmp %g2, %g1 - blu 13b - mov %o0, %o4 - ba,a 1f - - /* Check every byte. */ -82: srl %o5, 24, %g5 - andcc %g5, 0xff, %g0 - be 1f - add %o0, -3, %o4 - srl %o5, 16, %g5 - andcc %g5, 0xff, %g0 - be 1f - add %o4, 1, %o4 - srl %o5, 8, %g5 - andcc %g5, 0xff, %g0 - be 1f - add %o4, 1, %o4 - andcc %o5, 0xff, %g0 - bne 81b - sub %o0, %o1, %g2 - - add %o4, 1, %o4 -1: - retl - sub %o4, %o1, %o0 - - .section .fixup,#alloc,#execinstr - .align 4 -9: - retl - clr %o0 - - .section __ex_table,#alloc - .align 4 - - .word 10b, 9b - .word 11b, 9b - .word 12b, 9b - .word 13b, 9b diff --git a/arch/sparc/lib/strlen_user_64.S b/arch/sparc/lib/strlen_user_64.S deleted file mode 100644 index c3df71fa4928..000000000000 --- a/arch/sparc/lib/strlen_user_64.S +++ /dev/null @@ -1,97 +0,0 @@ -/* strlen_user.S: Sparc64 optimized strlen_user code - * - * Return length of string in userspace including terminating 0 - * or 0 for error - * - * Copyright (C) 1991,1996 Free Software Foundation - * Copyright (C) 1996,1999 David S. Miller (davem@redhat.com) - * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#include <linux/linkage.h> -#include <asm/asi.h> - -#define LO_MAGIC 0x01010101 -#define HI_MAGIC 0x80808080 - - .align 4 -ENTRY(__strlen_user) - sethi %hi(32768), %o1 -ENTRY(__strnlen_user) - mov %o1, %g1 - mov %o0, %o1 - andcc %o0, 3, %g0 - be,pt %icc, 9f - sethi %hi(HI_MAGIC), %o4 -10: lduba [%o0] %asi, %o5 - brz,pn %o5, 21f - add %o0, 1, %o0 - andcc %o0, 3, %g0 - be,pn %icc, 4f - or %o4, %lo(HI_MAGIC), %o3 -11: lduba [%o0] %asi, %o5 - brz,pn %o5, 22f - add %o0, 1, %o0 - andcc %o0, 3, %g0 - be,pt %icc, 13f - srl %o3, 7, %o2 -12: lduba [%o0] %asi, %o5 - brz,pn %o5, 23f - add %o0, 1, %o0 - ba,pt %icc, 2f -15: lda [%o0] %asi, %o5 -9: or %o4, %lo(HI_MAGIC), %o3 -4: srl %o3, 7, %o2 -13: lda [%o0] %asi, %o5 -2: sub %o5, %o2, %o4 - andcc %o4, %o3, %g0 - bne,pn %icc, 82f - add %o0, 4, %o0 - sub %o0, %o1, %g2 -81: cmp %g2, %g1 - blu,pt %icc, 13b - mov %o0, %o4 - ba,a,pt %xcc, 1f - - /* Check every byte. */ -82: srl %o5, 24, %g7 - andcc %g7, 0xff, %g0 - be,pn %icc, 1f - add %o0, -3, %o4 - srl %o5, 16, %g7 - andcc %g7, 0xff, %g0 - be,pn %icc, 1f - add %o4, 1, %o4 - srl %o5, 8, %g7 - andcc %g7, 0xff, %g0 - be,pn %icc, 1f - add %o4, 1, %o4 - andcc %o5, 0xff, %g0 - bne,pt %icc, 81b - sub %o0, %o1, %g2 - add %o4, 1, %o4 -1: retl - sub %o4, %o1, %o0 -21: retl - mov 1, %o0 -22: retl - mov 2, %o0 -23: retl - mov 3, %o0 -ENDPROC(__strlen_user) -ENDPROC(__strnlen_user) - - .section .fixup,#alloc,#execinstr - .align 4 -30: - retl - clr %o0 - - .section __ex_table,"a" - .align 4 - - .word 10b, 30b - .word 11b, 30b - .word 12b, 30b - .word 15b, 30b - .word 13b, 30b diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 6ad6219fc47e..fe128816c448 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -48,6 +48,14 @@ config NEED_PER_CPU_PAGE_FIRST_CHUNK config SYS_SUPPORTS_HUGETLBFS def_bool y +# Support for additional huge page sizes besides HPAGE_SIZE. +# The software support is currently only present in the TILE-Gx +# hypervisor. TILEPro in any case does not support page sizes +# larger than the default HPAGE_SIZE. +config HUGETLB_SUPER_PAGES + depends on HUGETLB_PAGE && TILEGX + def_bool y + # FIXME: tilegx can implement a more efficient rwsem. config RWSEM_GENERIC_SPINLOCK def_bool y @@ -107,16 +115,14 @@ config HVC_TILE select HVC_DRIVER def_bool y -# Please note: TILE-Gx support is not yet finalized; this is -# the preliminary support. TILE-Gx drivers are only provided -# with the alpha or beta test versions for Tilera customers. config TILEGX - depends on EXPERIMENTAL bool "Building with TILE-Gx (64-bit) compiler and toolchain" +config TILEPRO + def_bool !TILEGX + config 64BIT - depends on TILEGX - def_bool y + def_bool TILEGX config ARCH_DEFCONFIG string @@ -137,6 +143,31 @@ config NR_CPUS smaller kernel memory footprint results from using a smaller value on chips with fewer tiles. +if TILEGX + +choice + prompt "Kernel page size" + default PAGE_SIZE_64KB + help + This lets you select the page size of the kernel. For best + performance on memory-intensive applications, a page size of 64KB + is recommended. For workloads involving many small files, many + connections, etc., it may be better to select 16KB, which uses + memory more efficiently at some cost in TLB performance. + + Note that this option is TILE-Gx specific; currently + TILEPro page size is set by rebuilding the hypervisor. + +config PAGE_SIZE_16KB + bool "16KB" + +config PAGE_SIZE_64KB + bool "64KB" + +endchoice + +endif + source "kernel/Kconfig.hz" config KEXEC diff --git a/arch/tile/Makefile b/arch/tile/Makefile index 9520bc5a4b7f..e20b0a0b64a1 100644 --- a/arch/tile/Makefile +++ b/arch/tile/Makefile @@ -34,7 +34,12 @@ LIBGCC_PATH := \ $(shell $(CC) $(KBUILD_CFLAGS) $(KCFLAGS) -print-libgcc-file-name) # Provide the path to use for "make defconfig". -KBUILD_DEFCONFIG := $(ARCH)_defconfig +# We default to the newer TILE-Gx architecture if only "tile" is given. +ifeq ($(ARCH),tile) + KBUILD_DEFCONFIG := tilegx_defconfig +else + KBUILD_DEFCONFIG := $(ARCH)_defconfig +endif # Used as a file extension when useful, e.g. head_$(BITS).o # Not needed for (e.g.) "$(CC) -m32" since the compiler automatically diff --git a/arch/tile/include/arch/spr_def_32.h b/arch/tile/include/arch/spr_def_32.h index bbc1f4c924ee..78bbce2fb19a 100644 --- a/arch/tile/include/arch/spr_def_32.h +++ b/arch/tile/include/arch/spr_def_32.h @@ -65,6 +65,31 @@ #define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1 #define SPR_EX_CONTEXT_2_1__ICS_MASK 0x4 #define SPR_FAIL 0x4e09 +#define SPR_IDN_AVAIL_EN 0x3e05 +#define SPR_IDN_CA_DATA 0x0b00 +#define SPR_IDN_DATA_AVAIL 0x0b03 +#define SPR_IDN_DEADLOCK_TIMEOUT 0x3406 +#define SPR_IDN_DEMUX_CA_COUNT 0x0a05 +#define SPR_IDN_DEMUX_COUNT_0 0x0a06 +#define SPR_IDN_DEMUX_COUNT_1 0x0a07 +#define SPR_IDN_DEMUX_CTL 0x0a08 +#define SPR_IDN_DEMUX_QUEUE_SEL 0x0a0a +#define SPR_IDN_DEMUX_STATUS 0x0a0b +#define SPR_IDN_DEMUX_WRITE_FIFO 0x0a0c +#define SPR_IDN_DIRECTION_PROTECT 0x2e05 +#define SPR_IDN_PENDING 0x0a0e +#define SPR_IDN_REFILL_EN 0x0e05 +#define SPR_IDN_SP_FIFO_DATA 0x0a0f +#define SPR_IDN_SP_FIFO_SEL 0x0a10 +#define SPR_IDN_SP_FREEZE 0x0a11 +#define SPR_IDN_SP_FREEZE__SP_FRZ_MASK 0x1 +#define SPR_IDN_SP_FREEZE__DEMUX_FRZ_MASK 0x2 +#define SPR_IDN_SP_FREEZE__NON_DEST_EXT_MASK 0x4 +#define SPR_IDN_SP_STATE 0x0a12 +#define SPR_IDN_TAG_0 0x0a13 +#define SPR_IDN_TAG_1 0x0a14 +#define SPR_IDN_TAG_VALID 0x0a15 +#define SPR_IDN_TILE_COORD 0x0a16 #define SPR_INTCTRL_0_STATUS 0x4a07 #define SPR_INTCTRL_1_STATUS 0x4807 #define SPR_INTCTRL_2_STATUS 0x4607 @@ -87,12 +112,36 @@ #define SPR_INTERRUPT_MASK_SET_1_1 0x480e #define SPR_INTERRUPT_MASK_SET_2_0 0x460c #define SPR_INTERRUPT_MASK_SET_2_1 0x460d +#define SPR_MPL_AUX_PERF_COUNT_SET_0 0x6000 +#define SPR_MPL_AUX_PERF_COUNT_SET_1 0x6001 +#define SPR_MPL_AUX_PERF_COUNT_SET_2 0x6002 #define SPR_MPL_DMA_CPL_SET_0 0x5800 #define SPR_MPL_DMA_CPL_SET_1 0x5801 #define SPR_MPL_DMA_CPL_SET_2 0x5802 #define SPR_MPL_DMA_NOTIFY_SET_0 0x3800 #define SPR_MPL_DMA_NOTIFY_SET_1 0x3801 #define SPR_MPL_DMA_NOTIFY_SET_2 0x3802 +#define SPR_MPL_IDN_ACCESS_SET_0 0x0a00 +#define SPR_MPL_IDN_ACCESS_SET_1 0x0a01 +#define SPR_MPL_IDN_ACCESS_SET_2 0x0a02 +#define SPR_MPL_IDN_AVAIL_SET_0 0x3e00 +#define SPR_MPL_IDN_AVAIL_SET_1 0x3e01 +#define SPR_MPL_IDN_AVAIL_SET_2 0x3e02 +#define SPR_MPL_IDN_CA_SET_0 0x3a00 +#define SPR_MPL_IDN_CA_SET_1 0x3a01 +#define SPR_MPL_IDN_CA_SET_2 0x3a02 +#define SPR_MPL_IDN_COMPLETE_SET_0 0x1200 +#define SPR_MPL_IDN_COMPLETE_SET_1 0x1201 +#define SPR_MPL_IDN_COMPLETE_SET_2 0x1202 +#define SPR_MPL_IDN_FIREWALL_SET_0 0x2e00 +#define SPR_MPL_IDN_FIREWALL_SET_1 0x2e01 +#define SPR_MPL_IDN_FIREWALL_SET_2 0x2e02 +#define SPR_MPL_IDN_REFILL_SET_0 0x0e00 +#define SPR_MPL_IDN_REFILL_SET_1 0x0e01 +#define SPR_MPL_IDN_REFILL_SET_2 0x0e02 +#define SPR_MPL_IDN_TIMER_SET_0 0x3400 +#define SPR_MPL_IDN_TIMER_SET_1 0x3401 +#define SPR_MPL_IDN_TIMER_SET_2 0x3402 #define SPR_MPL_INTCTRL_0_SET_0 0x4a00 #define SPR_MPL_INTCTRL_0_SET_1 0x4a01 #define SPR_MPL_INTCTRL_0_SET_2 0x4a02 @@ -102,6 +151,9 @@ #define SPR_MPL_INTCTRL_2_SET_0 0x4600 #define SPR_MPL_INTCTRL_2_SET_1 0x4601 #define SPR_MPL_INTCTRL_2_SET_2 0x4602 +#define SPR_MPL_PERF_COUNT_SET_0 0x4200 +#define SPR_MPL_PERF_COUNT_SET_1 0x4201 +#define SPR_MPL_PERF_COUNT_SET_2 0x4202 #define SPR_MPL_SN_ACCESS_SET_0 0x0800 #define SPR_MPL_SN_ACCESS_SET_1 0x0801 #define SPR_MPL_SN_ACCESS_SET_2 0x0802 @@ -181,6 +233,7 @@ #define SPR_UDN_DEMUX_STATUS 0x0c0d #define SPR_UDN_DEMUX_WRITE_FIFO 0x0c0e #define SPR_UDN_DIRECTION_PROTECT 0x3005 +#define SPR_UDN_PENDING 0x0c10 #define SPR_UDN_REFILL_EN 0x1005 #define SPR_UDN_SP_FIFO_DATA 0x0c11 #define SPR_UDN_SP_FIFO_SEL 0x0c12 @@ -195,6 +248,9 @@ #define SPR_UDN_TAG_3 0x0c18 #define SPR_UDN_TAG_VALID 0x0c19 #define SPR_UDN_TILE_COORD 0x0c1a +#define SPR_WATCH_CTL 0x4209 +#define SPR_WATCH_MASK 0x420a +#define SPR_WATCH_VAL 0x420b #endif /* !defined(__ARCH_SPR_DEF_H__) */ diff --git a/arch/tile/include/arch/spr_def_64.h b/arch/tile/include/arch/spr_def_64.h index cd3e5f95d5fd..0da86faa3370 100644 --- a/arch/tile/include/arch/spr_def_64.h +++ b/arch/tile/include/arch/spr_def_64.h @@ -52,6 +52,13 @@ #define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1 #define SPR_EX_CONTEXT_2_1__ICS_MASK 0x4 #define SPR_FAIL 0x2707 +#define SPR_IDN_AVAIL_EN 0x1a05 +#define SPR_IDN_DATA_AVAIL 0x0a80 +#define SPR_IDN_DEADLOCK_TIMEOUT 0x1806 +#define SPR_IDN_DEMUX_COUNT_0 0x0a05 +#define SPR_IDN_DEMUX_COUNT_1 0x0a06 +#define SPR_IDN_DIRECTION_PROTECT 0x1405 +#define SPR_IDN_PENDING 0x0a08 #define SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK 0x1 #define SPR_INTCTRL_0_STATUS 0x2505 #define SPR_INTCTRL_1_STATUS 0x2405 @@ -88,9 +95,27 @@ #define SPR_IPI_MASK_SET_0 0x1f0a #define SPR_IPI_MASK_SET_1 0x1e0a #define SPR_IPI_MASK_SET_2 0x1d0a +#define SPR_MPL_AUX_PERF_COUNT_SET_0 0x2100 +#define SPR_MPL_AUX_PERF_COUNT_SET_1 0x2101 +#define SPR_MPL_AUX_PERF_COUNT_SET_2 0x2102 #define SPR_MPL_AUX_TILE_TIMER_SET_0 0x1700 #define SPR_MPL_AUX_TILE_TIMER_SET_1 0x1701 #define SPR_MPL_AUX_TILE_TIMER_SET_2 0x1702 +#define SPR_MPL_IDN_ACCESS_SET_0 0x0a00 +#define SPR_MPL_IDN_ACCESS_SET_1 0x0a01 +#define SPR_MPL_IDN_ACCESS_SET_2 0x0a02 +#define SPR_MPL_IDN_AVAIL_SET_0 0x1a00 +#define SPR_MPL_IDN_AVAIL_SET_1 0x1a01 +#define SPR_MPL_IDN_AVAIL_SET_2 0x1a02 +#define SPR_MPL_IDN_COMPLETE_SET_0 0x0500 +#define SPR_MPL_IDN_COMPLETE_SET_1 0x0501 +#define SPR_MPL_IDN_COMPLETE_SET_2 0x0502 +#define SPR_MPL_IDN_FIREWALL_SET_0 0x1400 +#define SPR_MPL_IDN_FIREWALL_SET_1 0x1401 +#define SPR_MPL_IDN_FIREWALL_SET_2 0x1402 +#define SPR_MPL_IDN_TIMER_SET_0 0x1800 +#define SPR_MPL_IDN_TIMER_SET_1 0x1801 +#define SPR_MPL_IDN_TIMER_SET_2 0x1802 #define SPR_MPL_INTCTRL_0_SET_0 0x2500 #define SPR_MPL_INTCTRL_0_SET_1 0x2501 #define SPR_MPL_INTCTRL_0_SET_2 0x2502 @@ -100,6 +125,21 @@ #define SPR_MPL_INTCTRL_2_SET_0 0x2300 #define SPR_MPL_INTCTRL_2_SET_1 0x2301 #define SPR_MPL_INTCTRL_2_SET_2 0x2302 +#define SPR_MPL_IPI_0 0x1f04 +#define SPR_MPL_IPI_0_SET_0 0x1f00 +#define SPR_MPL_IPI_0_SET_1 0x1f01 +#define SPR_MPL_IPI_0_SET_2 0x1f02 +#define SPR_MPL_IPI_1 0x1e04 +#define SPR_MPL_IPI_1_SET_0 0x1e00 +#define SPR_MPL_IPI_1_SET_1 0x1e01 +#define SPR_MPL_IPI_1_SET_2 0x1e02 +#define SPR_MPL_IPI_2 0x1d04 +#define SPR_MPL_IPI_2_SET_0 0x1d00 +#define SPR_MPL_IPI_2_SET_1 0x1d01 +#define SPR_MPL_IPI_2_SET_2 0x1d02 +#define SPR_MPL_PERF_COUNT_SET_0 0x2000 +#define SPR_MPL_PERF_COUNT_SET_1 0x2001 +#define SPR_MPL_PERF_COUNT_SET_2 0x2002 #define SPR_MPL_UDN_ACCESS_SET_0 0x0b00 #define SPR_MPL_UDN_ACCESS_SET_1 0x0b01 #define SPR_MPL_UDN_ACCESS_SET_2 0x0b02 @@ -167,6 +207,9 @@ #define SPR_UDN_DEMUX_COUNT_2 0x0b07 #define SPR_UDN_DEMUX_COUNT_3 0x0b08 #define SPR_UDN_DIRECTION_PROTECT 0x1505 +#define SPR_UDN_PENDING 0x0b0a +#define SPR_WATCH_MASK 0x200a +#define SPR_WATCH_VAL 0x200b #endif /* !defined(__ARCH_SPR_DEF_H__) */ diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild index 0bb42642343a..143473e3a0bb 100644 --- a/arch/tile/include/asm/Kbuild +++ b/arch/tile/include/asm/Kbuild @@ -2,6 +2,7 @@ include include/asm-generic/Kbuild.asm header-y += ../arch/ +header-y += cachectl.h header-y += ucontext.h header-y += hardwall.h @@ -21,7 +22,6 @@ generic-y += ipcbuf.h generic-y += irq_regs.h generic-y += kdebug.h generic-y += local.h -generic-y += module.h generic-y += msgbuf.h generic-y += mutex.h generic-y += param.h diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h index 54d1da826f93..e7fb5cfb9597 100644 --- a/arch/tile/include/asm/atomic_32.h +++ b/arch/tile/include/asm/atomic_32.h @@ -303,7 +303,14 @@ void __init_atomic_per_cpu(void); void __atomic_fault_unlock(int *lock_ptr); #endif +/* Return a pointer to the lock for the given address. */ +int *__atomic_hashed_lock(volatile void *v); + /* Private helper routines in lib/atomic_asm_32.S */ +struct __get_user { + unsigned long val; + int err; +}; extern struct __get_user __atomic_cmpxchg(volatile int *p, int *lock, int o, int n); extern struct __get_user __atomic_xchg(volatile int *p, int *lock, int n); @@ -319,6 +326,9 @@ extern u64 __atomic64_xchg_add(volatile u64 *p, int *lock, u64 n); extern u64 __atomic64_xchg_add_unless(volatile u64 *p, int *lock, u64 o, u64 n); +/* Return failure from the atomic wrappers. */ +struct __get_user __atomic_bad_address(int __user *addr); + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_TILE_ATOMIC_32_H */ diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h index 16f1fa51fea1..bd186c4eaa50 100644 --- a/arch/tile/include/asm/bitops.h +++ b/arch/tile/include/asm/bitops.h @@ -77,6 +77,11 @@ static inline int ffs(int x) return __builtin_ffs(x); } +static inline int fls64(__u64 w) +{ + return (sizeof(__u64) * 8) - __builtin_clzll(w); +} + /** * fls - find last set bit in word * @x: the word to search @@ -90,12 +95,7 @@ static inline int ffs(int x) */ static inline int fls(int x) { - return (sizeof(int) * 8) - __builtin_clz(x); -} - -static inline int fls64(__u64 w) -{ - return (sizeof(__u64) * 8) - __builtin_clzll(w); + return fls64((unsigned int) x); } static inline unsigned int __arch_hweight32(unsigned int w) diff --git a/arch/tile/include/asm/byteorder.h b/arch/tile/include/asm/byteorder.h index 9558416d578b..fb72ecf49218 100644 --- a/arch/tile/include/asm/byteorder.h +++ b/arch/tile/include/asm/byteorder.h @@ -1 +1,21 @@ +/* + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#if defined (__BIG_ENDIAN__) +#include <linux/byteorder/big_endian.h> +#elif defined (__LITTLE_ENDIAN__) #include <linux/byteorder/little_endian.h> +#else +#error "__BIG_ENDIAN__ or __LITTLE_ENDIAN__ must be defined." +#endif diff --git a/arch/tile/include/asm/cachectl.h b/arch/tile/include/asm/cachectl.h new file mode 100644 index 000000000000..af4c9f9154d1 --- /dev/null +++ b/arch/tile/include/asm/cachectl.h @@ -0,0 +1,42 @@ +/* + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _ASM_TILE_CACHECTL_H +#define _ASM_TILE_CACHECTL_H + +/* + * Options for cacheflush system call. + * + * The ICACHE flush is performed on all cores currently running the + * current process's address space. The intent is for user + * applications to be able to modify code, invoke the system call, + * then allow arbitrary other threads in the same address space to see + * the newly-modified code. Passing a length of CHIP_L1I_CACHE_SIZE() + * or more invalidates the entire icache on all cores in the address + * spaces. (Note: currently this option invalidates the entire icache + * regardless of the requested address and length, but we may choose + * to honor the arguments at some point.) + * + * Flush and invalidation of memory can normally be performed with the + * __insn_flush(), __insn_inv(), and __insn_finv() instructions from + * userspace. The DCACHE option to the system call allows userspace + * to flush the entire L1+L2 data cache from the core. In this case, + * the address and length arguments are not used. The DCACHE flush is + * restricted to the current core, not all cores in the address space. + */ +#define ICACHE (1<<0) /* invalidate L1 instruction cache */ +#define DCACHE (1<<1) /* flush and invalidate data cache */ +#define BCACHE (ICACHE|DCACHE) /* flush both caches */ + +#endif /* _ASM_TILE_CACHECTL_H */ diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h index 4b4b28969a65..69adc08d36a5 100644 --- a/arch/tile/include/asm/compat.h +++ b/arch/tile/include/asm/compat.h @@ -242,9 +242,6 @@ long compat_sys_fallocate(int fd, int mode, long compat_sys_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval); -/* Tilera Linux syscalls that don't have "compat" versions. */ -#define compat_sys_flush_cache sys_flush_cache - /* These are the intvec_64.S trampolines. */ long _compat_sys_execve(const char __user *path, const compat_uptr_t __user *argv, diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h index 623a6bb741c1..d16d006d660e 100644 --- a/arch/tile/include/asm/elf.h +++ b/arch/tile/include/asm/elf.h @@ -44,7 +44,11 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #else #define ELF_CLASS ELFCLASS32 #endif +#ifdef __BIG_ENDIAN__ +#define ELF_DATA ELFDATA2MSB +#else #define ELF_DATA ELFDATA2LSB +#endif /* * There seems to be a bug in how compat_binfmt_elf.c works: it @@ -59,6 +63,7 @@ enum { ELF_ARCH = CHIP_ELF_TYPE() }; */ #define elf_check_arch(x) \ ((x)->e_ident[EI_CLASS] == ELF_CLASS && \ + (x)->e_ident[EI_DATA] == ELF_DATA && \ (x)->e_machine == CHIP_ELF_TYPE()) /* The module loader only handles a few relocation types. */ diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h index d03ec124a598..5909ac3d7218 100644 --- a/arch/tile/include/asm/futex.h +++ b/arch/tile/include/asm/futex.h @@ -28,29 +28,81 @@ #include <linux/futex.h> #include <linux/uaccess.h> #include <linux/errno.h> +#include <asm/atomic.h> -extern struct __get_user futex_set(u32 __user *v, int i); -extern struct __get_user futex_add(u32 __user *v, int n); -extern struct __get_user futex_or(u32 __user *v, int n); -extern struct __get_user futex_andn(u32 __user *v, int n); -extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n); +/* + * Support macros for futex operations. Do not use these macros directly. + * They assume "ret", "val", "oparg", and "uaddr" in the lexical context. + * __futex_cmpxchg() additionally assumes "oldval". + */ + +#ifdef __tilegx__ + +#define __futex_asm(OP) \ + asm("1: {" #OP " %1, %3, %4; movei %0, 0 }\n" \ + ".pushsection .fixup,\"ax\"\n" \ + "0: { movei %0, %5; j 9f }\n" \ + ".section __ex_table,\"a\"\n" \ + ".quad 1b, 0b\n" \ + ".popsection\n" \ + "9:" \ + : "=r" (ret), "=r" (val), "+m" (*(uaddr)) \ + : "r" (uaddr), "r" (oparg), "i" (-EFAULT)) + +#define __futex_set() __futex_asm(exch4) +#define __futex_add() __futex_asm(fetchadd4) +#define __futex_or() __futex_asm(fetchor4) +#define __futex_andn() ({ oparg = ~oparg; __futex_asm(fetchand4); }) +#define __futex_cmpxchg() \ + ({ __insn_mtspr(SPR_CMPEXCH_VALUE, oldval); __futex_asm(cmpexch4); }) + +#define __futex_xor() \ + ({ \ + u32 oldval, n = oparg; \ + if ((ret = __get_user(oldval, uaddr)) == 0) { \ + do { \ + oparg = oldval ^ n; \ + __futex_cmpxchg(); \ + } while (ret == 0 && oldval != val); \ + } \ + }) + +/* No need to prefetch, since the atomic ops go to the home cache anyway. */ +#define __futex_prolog() -#ifndef __tilegx__ -extern struct __get_user futex_xor(u32 __user *v, int n); #else -static inline struct __get_user futex_xor(u32 __user *uaddr, int n) -{ - struct __get_user asm_ret = __get_user_4(uaddr); - if (!asm_ret.err) { - int oldval, newval; - do { - oldval = asm_ret.val; - newval = oldval ^ n; - asm_ret = futex_cmpxchg(uaddr, oldval, newval); - } while (asm_ret.err == 0 && oldval != asm_ret.val); + +#define __futex_call(FN) \ + { \ + struct __get_user gu = FN((u32 __force *)uaddr, lock, oparg); \ + val = gu.val; \ + ret = gu.err; \ } - return asm_ret; -} + +#define __futex_set() __futex_call(__atomic_xchg) +#define __futex_add() __futex_call(__atomic_xchg_add) +#define __futex_or() __futex_call(__atomic_or) +#define __futex_andn() __futex_call(__atomic_andn) +#define __futex_xor() __futex_call(__atomic_xor) + +#define __futex_cmpxchg() \ + { \ + struct __get_user gu = __atomic_cmpxchg((u32 __force *)uaddr, \ + lock, oldval, oparg); \ + val = gu.val; \ + ret = gu.err; \ + } + +/* + * Find the lock pointer for the atomic calls to use, and issue a + * prefetch to the user address to bring it into cache. Similar to + * __atomic_setup(), but we can't do a read into the L1 since it might + * fault; instead we do a prefetch into the L2. + */ +#define __futex_prolog() \ + int *lock; \ + __insn_prefetch(uaddr); \ + lock = __atomic_hashed_lock((int __force *)uaddr) #endif static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) @@ -59,8 +111,12 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int ret; - struct __get_user asm_ret; + int uninitialized_var(val), ret; + + __futex_prolog(); + + /* The 32-bit futex code makes this assumption, so validate it here. */ + BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int)); if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; @@ -71,46 +127,45 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) pagefault_disable(); switch (op) { case FUTEX_OP_SET: - asm_ret = futex_set(uaddr, oparg); + __futex_set(); break; case FUTEX_OP_ADD: - asm_ret = futex_add(uaddr, oparg); + __futex_add(); break; case FUTEX_OP_OR: - asm_ret = futex_or(uaddr, oparg); + __futex_or(); break; case FUTEX_OP_ANDN: - asm_ret = futex_andn(uaddr, oparg); + __futex_andn(); break; case FUTEX_OP_XOR: - asm_ret = futex_xor(uaddr, oparg); + __futex_xor(); break; default: - asm_ret.err = -ENOSYS; + ret = -ENOSYS; + break; } pagefault_enable(); - ret = asm_ret.err; - if (!ret) { switch (cmp) { case FUTEX_OP_CMP_EQ: - ret = (asm_ret.val == cmparg); + ret = (val == cmparg); break; case FUTEX_OP_CMP_NE: - ret = (asm_ret.val != cmparg); + ret = (val != cmparg); break; case FUTEX_OP_CMP_LT: - ret = (asm_ret.val < cmparg); + ret = (val < cmparg); break; case FUTEX_OP_CMP_GE: - ret = (asm_ret.val >= cmparg); + ret = (val >= cmparg); break; case FUTEX_OP_CMP_LE: - ret = (asm_ret.val <= cmparg); + ret = (val <= cmparg); break; case FUTEX_OP_CMP_GT: - ret = (asm_ret.val > cmparg); + ret = (val > cmparg); break; default: ret = -ENOSYS; @@ -120,22 +175,20 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) } static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, - u32 oldval, u32 newval) + u32 oldval, u32 oparg) { - struct __get_user asm_ret; + int ret, val; + + __futex_prolog(); if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; - asm_ret = futex_cmpxchg(uaddr, oldval, newval); - *uval = asm_ret.val; - return asm_ret.err; -} + __futex_cmpxchg(); -#ifndef __tilegx__ -/* Return failure from the atomic wrappers. */ -struct __get_user __atomic_bad_address(int __user *addr); -#endif + *uval = val; + return ret; +} #endif /* !__ASSEMBLY__ */ diff --git a/arch/tile/include/asm/hardwall.h b/arch/tile/include/asm/hardwall.h index 2ac422848c7d..47514a58d685 100644 --- a/arch/tile/include/asm/hardwall.h +++ b/arch/tile/include/asm/hardwall.h @@ -11,12 +11,14 @@ * NON INFRINGEMENT. See the GNU General Public License for * more details. * - * Provide methods for the HARDWALL_FILE for accessing the UDN. + * Provide methods for access control of per-cpu resources like + * UDN, IDN, or IPI. */ #ifndef _ASM_TILE_HARDWALL_H #define _ASM_TILE_HARDWALL_H +#include <arch/chip.h> #include <linux/ioctl.h> #define HARDWALL_IOCTL_BASE 0xa2 @@ -24,8 +26,9 @@ /* * The HARDWALL_CREATE() ioctl is a macro with a "size" argument. * The resulting ioctl value is passed to the kernel in conjunction - * with a pointer to a little-endian bitmask of cpus, which must be - * physically in a rectangular configuration on the chip. + * with a pointer to a standard kernel bitmask of cpus. + * For network resources (UDN or IDN) the bitmask must physically + * represent a rectangular configuration on the chip. * The "size" is the number of bytes of cpu mask data. */ #define _HARDWALL_CREATE 1 @@ -44,13 +47,7 @@ #define HARDWALL_GET_ID \ _IO(HARDWALL_IOCTL_BASE, _HARDWALL_GET_ID) -#ifndef __KERNEL__ - -/* This is the canonical name expected by userspace. */ -#define HARDWALL_FILE "/dev/hardwall" - -#else - +#ifdef __KERNEL__ /* /proc hooks for hardwall. */ struct proc_dir_entry; #ifdef CONFIG_HARDWALL @@ -59,7 +56,6 @@ int proc_pid_hardwall(struct task_struct *task, char *buffer); #else static inline void proc_tile_hardwall_init(struct proc_dir_entry *root) {} #endif - #endif #endif /* _ASM_TILE_HARDWALL_H */ diff --git a/arch/tile/include/asm/hugetlb.h b/arch/tile/include/asm/hugetlb.h index d396d1805163..b2042380a5aa 100644 --- a/arch/tile/include/asm/hugetlb.h +++ b/arch/tile/include/asm/hugetlb.h @@ -106,4 +106,25 @@ static inline void arch_release_hugepage(struct page *page) { } +#ifdef CONFIG_HUGETLB_SUPER_PAGES +static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma, + struct page *page, int writable) +{ + size_t pagesize = huge_page_size(hstate_vma(vma)); + if (pagesize != PUD_SIZE && pagesize != PMD_SIZE) + entry = pte_mksuper(entry); + return entry; +} +#define arch_make_huge_pte arch_make_huge_pte + +/* Sizes to scale up page size for PTEs with HV_PTE_SUPER bit. */ +enum { + HUGE_SHIFT_PGDIR = 0, + HUGE_SHIFT_PMD = 1, + HUGE_SHIFT_PAGE = 2, + HUGE_SHIFT_ENTRIES +}; +extern int huge_shift[HUGE_SHIFT_ENTRIES]; +#endif + #endif /* _ASM_TILE_HUGETLB_H */ diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h index 5db0ce54284d..b4e96fef2cf8 100644 --- a/arch/tile/include/asm/irqflags.h +++ b/arch/tile/include/asm/irqflags.h @@ -28,10 +28,10 @@ */ #if CHIP_HAS_AUX_PERF_COUNTERS() #define LINUX_MASKABLE_INTERRUPTS_HI \ - (~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT))) + (~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT))) #else #define LINUX_MASKABLE_INTERRUPTS_HI \ - (~(INT_MASK_HI(INT_PERF_COUNT))) + (~(INT_MASK_HI(INT_PERF_COUNT))) #endif #else @@ -90,6 +90,14 @@ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, (unsigned long)(__m)); \ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, (unsigned long)(__m>>32)); \ } while (0) +#define interrupt_mask_save_mask() \ + (__insn_mfspr(SPR_INTERRUPT_MASK_SET_K_0) | \ + (((unsigned long long)__insn_mfspr(SPR_INTERRUPT_MASK_SET_K_1))<<32)) +#define interrupt_mask_restore_mask(mask) do { \ + unsigned long long __m = (mask); \ + __insn_mtspr(SPR_INTERRUPT_MASK_K_0, (unsigned long)(__m)); \ + __insn_mtspr(SPR_INTERRUPT_MASK_K_1, (unsigned long)(__m>>32)); \ +} while (0) #else #define interrupt_mask_set(n) \ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (1UL << (n))) @@ -101,6 +109,10 @@ __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (mask)) #define interrupt_mask_reset_mask(mask) \ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (mask)) +#define interrupt_mask_save_mask() \ + __insn_mfspr(SPR_INTERRUPT_MASK_K) +#define interrupt_mask_restore_mask(mask) \ + __insn_mtspr(SPR_INTERRUPT_MASK_K, (mask)) #endif /* @@ -122,7 +134,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); /* Disable all interrupts, including NMIs. */ #define arch_local_irq_disable_all() \ - interrupt_mask_set_mask(-1UL) + interrupt_mask_set_mask(-1ULL) /* Re-enable all maskable interrupts. */ #define arch_local_irq_enable() \ @@ -179,7 +191,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); #ifdef __tilegx__ #if INT_MEM_ERROR != 0 -# error Fix IRQ_DISABLED() macro +# error Fix IRQS_DISABLED() macro #endif /* Return 0 or 1 to indicate whether interrupts are currently disabled. */ @@ -207,9 +219,10 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); mtspr SPR_INTERRUPT_MASK_SET_K, tmp /* Enable interrupts. */ -#define IRQ_ENABLE(tmp0, tmp1) \ +#define IRQ_ENABLE_LOAD(tmp0, tmp1) \ GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \ - ld tmp0, tmp0; \ + ld tmp0, tmp0 +#define IRQ_ENABLE_APPLY(tmp0, tmp1) \ mtspr SPR_INTERRUPT_MASK_RESET_K, tmp0 #else /* !__tilegx__ */ @@ -253,17 +266,22 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); mtspr SPR_INTERRUPT_MASK_SET_K_1, tmp /* Enable interrupts. */ -#define IRQ_ENABLE(tmp0, tmp1) \ +#define IRQ_ENABLE_LOAD(tmp0, tmp1) \ GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \ { \ lw tmp0, tmp0; \ addi tmp1, tmp0, 4 \ }; \ - lw tmp1, tmp1; \ + lw tmp1, tmp1 +#define IRQ_ENABLE_APPLY(tmp0, tmp1) \ mtspr SPR_INTERRUPT_MASK_RESET_K_0, tmp0; \ mtspr SPR_INTERRUPT_MASK_RESET_K_1, tmp1 #endif +#define IRQ_ENABLE(tmp0, tmp1) \ + IRQ_ENABLE_LOAD(tmp0, tmp1); \ + IRQ_ENABLE_APPLY(tmp0, tmp1) + /* * Do the CPU's IRQ-state tracing from assembly code. We call a * C function, but almost everywhere we do, we don't mind clobbering diff --git a/arch/tile/include/asm/kexec.h b/arch/tile/include/asm/kexec.h index c11a6cc73bb8..fc98ccfc98ac 100644 --- a/arch/tile/include/asm/kexec.h +++ b/arch/tile/include/asm/kexec.h @@ -19,12 +19,24 @@ #include <asm/page.h> +#ifndef __tilegx__ /* Maximum physical address we can use pages from. */ #define KEXEC_SOURCE_MEMORY_LIMIT TASK_SIZE /* Maximum address we can reach in physical address mode. */ #define KEXEC_DESTINATION_MEMORY_LIMIT TASK_SIZE /* Maximum address we can use for the control code buffer. */ #define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE +#else +/* We need to limit the memory below PGDIR_SIZE since + * we only setup page table for [0, PGDIR_SIZE) before final kexec. + */ +/* Maximum physical address we can use pages from. */ +#define KEXEC_SOURCE_MEMORY_LIMIT PGDIR_SIZE +/* Maximum address we can reach in physical address mode. */ +#define KEXEC_DESTINATION_MEMORY_LIMIT PGDIR_SIZE +/* Maximum address we can use for the control code buffer. */ +#define KEXEC_CONTROL_MEMORY_LIMIT PGDIR_SIZE +#endif #define KEXEC_CONTROL_PAGE_SIZE PAGE_SIZE diff --git a/arch/tile/include/asm/mmu.h b/arch/tile/include/asm/mmu.h index 92f94c77b6e4..e2c789096795 100644 --- a/arch/tile/include/asm/mmu.h +++ b/arch/tile/include/asm/mmu.h @@ -21,7 +21,7 @@ struct mm_context { * Written under the mmap_sem semaphore; read without the * semaphore but atomically, but it is conservatively set. */ - unsigned int priority_cached; + unsigned long priority_cached; }; typedef struct mm_context mm_context_t; diff --git a/arch/tile/include/asm/mmu_context.h b/arch/tile/include/asm/mmu_context.h index 15fb24641120..37f0b741dee7 100644 --- a/arch/tile/include/asm/mmu_context.h +++ b/arch/tile/include/asm/mmu_context.h @@ -30,11 +30,15 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) return 0; } -/* Note that arch/tile/kernel/head.S also calls hv_install_context() */ +/* + * Note that arch/tile/kernel/head_NN.S and arch/tile/mm/migrate_NN.S + * also call hv_install_context(). + */ static inline void __install_page_table(pgd_t *pgdir, int asid, pgprot_t prot) { /* FIXME: DIRECTIO should not always be set. FIXME. */ - int rc = hv_install_context(__pa(pgdir), prot, asid, HV_CTX_DIRECTIO); + int rc = hv_install_context(__pa(pgdir), prot, asid, + HV_CTX_DIRECTIO | CTX_PAGE_FLAG); if (rc < 0) panic("hv_install_context failed: %d", rc); } diff --git a/arch/tile/include/asm/module.h b/arch/tile/include/asm/module.h new file mode 100644 index 000000000000..44ed07ccd3d2 --- /dev/null +++ b/arch/tile/include/asm/module.h @@ -0,0 +1,40 @@ +/* + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef _ASM_TILE_MODULE_H +#define _ASM_TILE_MODULE_H + +#include <arch/chip.h> + +#include <asm-generic/module.h> + +/* We can't use modules built with different page sizes. */ +#if defined(CONFIG_PAGE_SIZE_16KB) +# define MODULE_PGSZ " 16KB" +#elif defined(CONFIG_PAGE_SIZE_64KB) +# define MODULE_PGSZ " 64KB" +#else +# define MODULE_PGSZ "" +#endif + +/* We don't really support no-SMP so tag if someone tries. */ +#ifdef CONFIG_SMP +#define MODULE_NOSMP "" +#else +#define MODULE_NOSMP " nosmp" +#endif + +#define MODULE_ARCH_VERMAGIC CHIP_ARCH_NAME MODULE_PGSZ MODULE_NOSMP + +#endif /* _ASM_TILE_MODULE_H */ diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h index db93518fac03..9d9131e5c552 100644 --- a/arch/tile/include/asm/page.h +++ b/arch/tile/include/asm/page.h @@ -20,8 +20,17 @@ #include <arch/chip.h> /* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */ -#define PAGE_SHIFT HV_LOG2_PAGE_SIZE_SMALL -#define HPAGE_SHIFT HV_LOG2_PAGE_SIZE_LARGE +#if defined(CONFIG_PAGE_SIZE_16KB) +#define PAGE_SHIFT 14 +#define CTX_PAGE_FLAG HV_CTX_PG_SM_16K +#elif defined(CONFIG_PAGE_SIZE_64KB) +#define PAGE_SHIFT 16 +#define CTX_PAGE_FLAG HV_CTX_PG_SM_64K +#else +#define PAGE_SHIFT HV_LOG2_DEFAULT_PAGE_SIZE_SMALL +#define CTX_PAGE_FLAG 0 +#endif +#define HPAGE_SHIFT HV_LOG2_DEFAULT_PAGE_SIZE_LARGE #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) @@ -78,8 +87,7 @@ typedef HV_PTE pgprot_t; /* * User L2 page tables are managed as one L2 page table per page, * because we use the page allocator for them. This keeps the allocation - * simple and makes it potentially useful to implement HIGHPTE at some point. - * However, it's also inefficient, since L2 page tables are much smaller + * simple, but it's also inefficient, since L2 page tables are much smaller * than pages (currently 2KB vs 64KB). So we should revisit this. */ typedef struct page *pgtable_t; @@ -128,7 +136,7 @@ static inline __attribute_const__ int get_order(unsigned long size) #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) -#define HUGE_MAX_HSTATE 2 +#define HUGE_MAX_HSTATE 6 #ifdef CONFIG_HUGETLB_PAGE #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA diff --git a/arch/tile/include/asm/pgalloc.h b/arch/tile/include/asm/pgalloc.h index e919c0bdc22d..1b902508b664 100644 --- a/arch/tile/include/asm/pgalloc.h +++ b/arch/tile/include/asm/pgalloc.h @@ -19,24 +19,24 @@ #include <linux/mm.h> #include <linux/mmzone.h> #include <asm/fixmap.h> +#include <asm/page.h> #include <hv/hypervisor.h> /* Bits for the size of the second-level page table. */ -#define L2_KERNEL_PGTABLE_SHIFT \ - (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL + HV_LOG2_PTE_SIZE) +#define L2_KERNEL_PGTABLE_SHIFT _HV_LOG2_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT) + +/* How big is a kernel L2 page table? */ +#define L2_KERNEL_PGTABLE_SIZE (1UL << L2_KERNEL_PGTABLE_SHIFT) /* We currently allocate user L2 page tables by page (unlike kernel L2s). */ -#if L2_KERNEL_PGTABLE_SHIFT < HV_LOG2_PAGE_SIZE_SMALL -#define L2_USER_PGTABLE_SHIFT HV_LOG2_PAGE_SIZE_SMALL +#if L2_KERNEL_PGTABLE_SHIFT < PAGE_SHIFT +#define L2_USER_PGTABLE_SHIFT PAGE_SHIFT #else #define L2_USER_PGTABLE_SHIFT L2_KERNEL_PGTABLE_SHIFT #endif /* How many pages do we need, as an "order", for a user L2 page table? */ -#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - HV_LOG2_PAGE_SIZE_SMALL) - -/* How big is a kernel L2 page table? */ -#define L2_KERNEL_PGTABLE_SIZE (1 << L2_KERNEL_PGTABLE_SHIFT) +#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - PAGE_SHIFT) static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) { @@ -50,14 +50,14 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *ptep) { - set_pmd(pmd, ptfn_pmd(__pa(ptep) >> HV_LOG2_PAGE_TABLE_ALIGN, + set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(__pa(ptep)), __pgprot(_PAGE_PRESENT))); } static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t page) { - set_pmd(pmd, ptfn_pmd(HV_PFN_TO_PTFN(page_to_pfn(page)), + set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(PFN_PHYS(page_to_pfn(page))), __pgprot(_PAGE_PRESENT))); } @@ -68,8 +68,20 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, extern pgd_t *pgd_alloc(struct mm_struct *mm); extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); -extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address); -extern void pte_free(struct mm_struct *mm, struct page *pte); +extern pgtable_t pgtable_alloc_one(struct mm_struct *mm, unsigned long address, + int order); +extern void pgtable_free(struct mm_struct *mm, struct page *pte, int order); + +static inline pgtable_t pte_alloc_one(struct mm_struct *mm, + unsigned long address) +{ + return pgtable_alloc_one(mm, address, L2_USER_PGTABLE_ORDER); +} + +static inline void pte_free(struct mm_struct *mm, struct page *pte) +{ + pgtable_free(mm, pte, L2_USER_PGTABLE_ORDER); +} #define pmd_pgtable(pmd) pmd_page(pmd) @@ -85,8 +97,13 @@ static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) pte_free(mm, virt_to_page(pte)); } -extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte, - unsigned long address); +extern void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte, + unsigned long address, int order); +static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte, + unsigned long address) +{ + __pgtable_free_tlb(tlb, pte, address, L2_USER_PGTABLE_ORDER); +} #define check_pgt_cache() do { } while (0) @@ -104,19 +121,44 @@ void shatter_pmd(pmd_t *pmd); void shatter_huge_page(unsigned long addr); #ifdef __tilegx__ -/* We share a single page allocator for both L1 and L2 page tables. */ -#if HV_L1_SIZE != HV_L2_SIZE -# error Rework assumption that L1 and L2 page tables are same size. -#endif -#define L1_USER_PGTABLE_ORDER L2_USER_PGTABLE_ORDER + #define pud_populate(mm, pud, pmd) \ pmd_populate_kernel((mm), (pmd_t *)(pud), (pte_t *)(pmd)) -#define pmd_alloc_one(mm, addr) \ - ((pmd_t *)page_to_virt(pte_alloc_one((mm), (addr)))) -#define pmd_free(mm, pmdp) \ - pte_free((mm), virt_to_page(pmdp)) -#define __pmd_free_tlb(tlb, pmdp, address) \ - __pte_free_tlb((tlb), virt_to_page(pmdp), (address)) + +/* Bits for the size of the L1 (intermediate) page table. */ +#define L1_KERNEL_PGTABLE_SHIFT _HV_LOG2_L1_SIZE(HPAGE_SHIFT) + +/* How big is a kernel L2 page table? */ +#define L1_KERNEL_PGTABLE_SIZE (1UL << L1_KERNEL_PGTABLE_SHIFT) + +/* We currently allocate L1 page tables by page. */ +#if L1_KERNEL_PGTABLE_SHIFT < PAGE_SHIFT +#define L1_USER_PGTABLE_SHIFT PAGE_SHIFT +#else +#define L1_USER_PGTABLE_SHIFT L1_KERNEL_PGTABLE_SHIFT #endif +/* How many pages do we need, as an "order", for an L1 page table? */ +#define L1_USER_PGTABLE_ORDER (L1_USER_PGTABLE_SHIFT - PAGE_SHIFT) + +static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + struct page *p = pgtable_alloc_one(mm, address, L1_USER_PGTABLE_ORDER); + return (pmd_t *)page_to_virt(p); +} + +static inline void pmd_free(struct mm_struct *mm, pmd_t *pmdp) +{ + pgtable_free(mm, virt_to_page(pmdp), L1_USER_PGTABLE_ORDER); +} + +static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, + unsigned long address) +{ + __pgtable_free_tlb(tlb, virt_to_page(pmdp), address, + L1_USER_PGTABLE_ORDER); +} + +#endif /* __tilegx__ */ + #endif /* _ASM_TILE_PGALLOC_H */ diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h index 67490910774d..73b1a4c9ad03 100644 --- a/arch/tile/include/asm/pgtable.h +++ b/arch/tile/include/asm/pgtable.h @@ -27,8 +27,10 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/spinlock.h> +#include <linux/pfn.h> #include <asm/processor.h> #include <asm/fixmap.h> +#include <asm/page.h> struct mm_struct; struct vm_area_struct; @@ -69,6 +71,7 @@ extern void set_page_homes(void); #define _PAGE_PRESENT HV_PTE_PRESENT #define _PAGE_HUGE_PAGE HV_PTE_PAGE +#define _PAGE_SUPER_PAGE HV_PTE_SUPER #define _PAGE_READABLE HV_PTE_READABLE #define _PAGE_WRITABLE HV_PTE_WRITABLE #define _PAGE_EXECUTABLE HV_PTE_EXECUTABLE @@ -85,6 +88,7 @@ extern void set_page_homes(void); #define _PAGE_ALL (\ _PAGE_PRESENT | \ _PAGE_HUGE_PAGE | \ + _PAGE_SUPER_PAGE | \ _PAGE_READABLE | \ _PAGE_WRITABLE | \ _PAGE_EXECUTABLE | \ @@ -162,7 +166,7 @@ extern void set_page_homes(void); (pgprot_t) { ((oldprot).val & ~_PAGE_ALL) | (newprot).val } /* Just setting the PFN to zero suffices. */ -#define pte_pgprot(x) hv_pte_set_pfn((x), 0) +#define pte_pgprot(x) hv_pte_set_pa((x), 0) /* * For PTEs and PDEs, we must clear the Present bit first when @@ -187,6 +191,7 @@ static inline void __pte_clear(pte_t *ptep) * Undefined behaviour if not.. */ #define pte_present hv_pte_get_present +#define pte_mknotpresent hv_pte_clear_present #define pte_user hv_pte_get_user #define pte_read hv_pte_get_readable #define pte_dirty hv_pte_get_dirty @@ -194,6 +199,7 @@ static inline void __pte_clear(pte_t *ptep) #define pte_write hv_pte_get_writable #define pte_exec hv_pte_get_executable #define pte_huge hv_pte_get_page +#define pte_super hv_pte_get_super #define pte_rdprotect hv_pte_clear_readable #define pte_exprotect hv_pte_clear_executable #define pte_mkclean hv_pte_clear_dirty @@ -206,6 +212,7 @@ static inline void __pte_clear(pte_t *ptep) #define pte_mkyoung hv_pte_set_accessed #define pte_mkwrite hv_pte_set_writable #define pte_mkhuge hv_pte_set_page +#define pte_mksuper hv_pte_set_super #define pte_special(pte) 0 #define pte_mkspecial(pte) (pte) @@ -261,7 +268,7 @@ static inline int pte_none(pte_t pte) static inline unsigned long pte_pfn(pte_t pte) { - return hv_pte_get_pfn(pte); + return PFN_DOWN(hv_pte_get_pa(pte)); } /* Set or get the remote cache cpu in a pgprot with remote caching. */ @@ -270,7 +277,7 @@ extern int get_remote_cache_cpu(pgprot_t prot); static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) { - return hv_pte_set_pfn(prot, pfn); + return hv_pte_set_pa(prot, PFN_PHYS(pfn)); } /* Support for priority mappings. */ @@ -312,7 +319,7 @@ extern void check_mm_caching(struct mm_struct *prev, struct mm_struct *next); */ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { - return pfn_pte(hv_pte_get_pfn(pte), newprot); + return pfn_pte(pte_pfn(pte), newprot); } /* @@ -335,13 +342,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) */ #define pgd_offset_k(address) pgd_offset(&init_mm, address) -#if defined(CONFIG_HIGHPTE) -extern pte_t *pte_offset_map(pmd_t *, unsigned long address); -#define pte_unmap(pte) kunmap_atomic(pte) -#else #define pte_offset_map(dir, address) pte_offset_kernel(dir, address) #define pte_unmap(pte) do { } while (0) -#endif /* Clear a non-executable kernel PTE and flush it from the TLB. */ #define kpte_clear_flush(ptep, vaddr) \ @@ -410,6 +412,46 @@ static inline unsigned long pmd_index(unsigned long address) return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); } +#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG +static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, + pmd_t *pmdp) +{ + return ptep_test_and_clear_young(vma, address, pmdp_ptep(pmdp)); +} + +#define __HAVE_ARCH_PMDP_SET_WRPROTECT +static inline void pmdp_set_wrprotect(struct mm_struct *mm, + unsigned long address, pmd_t *pmdp) +{ + ptep_set_wrprotect(mm, address, pmdp_ptep(pmdp)); +} + + +#define __HAVE_ARCH_PMDP_GET_AND_CLEAR +static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, + unsigned long address, + pmd_t *pmdp) +{ + return pte_pmd(ptep_get_and_clear(mm, address, pmdp_ptep(pmdp))); +} + +static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) +{ + set_pte(pmdp_ptep(pmdp), pmd_pte(pmdval)); +} + +#define set_pmd_at(mm, addr, pmdp, pmdval) __set_pmd(pmdp, pmdval) + +/* Create a pmd from a PTFN. */ +static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) +{ + return pte_pmd(hv_pte_set_ptfn(prot, ptfn)); +} + +/* Return the page-table frame number (ptfn) that a pmd_t points at. */ +#define pmd_ptfn(pmd) hv_pte_get_ptfn(pmd_pte(pmd)) + /* * A given kernel pmd_t maps to a specific virtual address (either a * kernel huge page or a kernel pte_t table). Since kernel pte_t @@ -430,7 +472,48 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd) * OK for pte_lockptr(), since we just end up with potentially one * lock being used for several pte_t arrays. */ -#define pmd_page(pmd) pfn_to_page(HV_PTFN_TO_PFN(pmd_ptfn(pmd))) +#define pmd_page(pmd) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pmd_ptfn(pmd)))) + +static inline void pmd_clear(pmd_t *pmdp) +{ + __pte_clear(pmdp_ptep(pmdp)); +} + +#define pmd_mknotpresent(pmd) pte_pmd(pte_mknotpresent(pmd_pte(pmd))) +#define pmd_young(pmd) pte_young(pmd_pte(pmd)) +#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) +#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) +#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) +#define pmd_write(pmd) pte_write(pmd_pte(pmd)) +#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) +#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) +#define pmd_huge_page(pmd) pte_huge(pmd_pte(pmd)) +#define pmd_mkhuge(pmd) pte_pmd(pte_mkhuge(pmd_pte(pmd))) +#define __HAVE_ARCH_PMD_WRITE + +#define pfn_pmd(pfn, pgprot) pte_pmd(pfn_pte((pfn), (pgprot))) +#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd)) +#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot)) + +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +{ + return pfn_pmd(pmd_pfn(pmd), newprot); +} + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define has_transparent_hugepage() 1 +#define pmd_trans_huge pmd_huge_page + +static inline pmd_t pmd_mksplitting(pmd_t pmd) +{ + return pte_pmd(hv_pte_set_client2(pmd_pte(pmd))); +} + +static inline int pmd_trans_splitting(pmd_t pmd) +{ + return hv_pte_get_client2(pmd_pte(pmd)); +} +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ /* * The pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] @@ -448,17 +531,13 @@ static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address) return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(address); } -static inline int pmd_huge_page(pmd_t pmd) -{ - return pmd_val(pmd) & _PAGE_HUGE_PAGE; -} - #include <asm-generic/pgtable.h> /* Support /proc/NN/pgtable API. */ struct seq_file; int arch_proc_pgtable_show(struct seq_file *m, struct mm_struct *mm, - unsigned long vaddr, pte_t *ptep, void **datap); + unsigned long vaddr, unsigned long pagesize, + pte_t *ptep, void **datap); #endif /* !__ASSEMBLY__ */ diff --git a/arch/tile/include/asm/pgtable_32.h b/arch/tile/include/asm/pgtable_32.h index 9f98529761fd..4ce4a7a99c24 100644 --- a/arch/tile/include/asm/pgtable_32.h +++ b/arch/tile/include/asm/pgtable_32.h @@ -20,11 +20,12 @@ * The level-1 index is defined by the huge page size. A PGD is composed * of PTRS_PER_PGD pgd_t's and is the top level of the page table. */ -#define PGDIR_SHIFT HV_LOG2_PAGE_SIZE_LARGE -#define PGDIR_SIZE HV_PAGE_SIZE_LARGE +#define PGDIR_SHIFT HPAGE_SHIFT +#define PGDIR_SIZE HPAGE_SIZE #define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT)) -#define SIZEOF_PGD (PTRS_PER_PGD * sizeof(pgd_t)) +#define PTRS_PER_PGD _HV_L1_ENTRIES(HPAGE_SHIFT) +#define PGD_INDEX(va) _HV_L1_INDEX(va, HPAGE_SHIFT) +#define SIZEOF_PGD _HV_L1_SIZE(HPAGE_SHIFT) /* * The level-2 index is defined by the difference between the huge @@ -33,8 +34,9 @@ * Note that the hypervisor docs use PTE for what we call pte_t, so * this nomenclature is somewhat confusing. */ -#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL)) -#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t)) +#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT) +#define PTE_INDEX(va) _HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT) +#define SIZEOF_PTE _HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT) #ifndef __ASSEMBLY__ @@ -111,24 +113,14 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, return pte; } -static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) -{ - set_pte(&pmdp->pud.pgd, pmdval.pud.pgd); -} - -/* Create a pmd from a PTFN. */ -static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) -{ - return (pmd_t){ { hv_pte_set_ptfn(prot, ptfn) } }; -} - -/* Return the page-table frame number (ptfn) that a pmd_t points at. */ -#define pmd_ptfn(pmd) hv_pte_get_ptfn((pmd).pud.pgd) - -static inline void pmd_clear(pmd_t *pmdp) -{ - __pte_clear(&pmdp->pud.pgd); -} +/* + * pmds are wrappers around pgds, which are the same as ptes. + * It's often convenient to "cast" back and forth and use the pte methods, + * which are the methods supplied by the hypervisor. + */ +#define pmd_pte(pmd) ((pmd).pud.pgd) +#define pmdp_ptep(pmdp) (&(pmdp)->pud.pgd) +#define pte_pmd(pte) ((pmd_t){ { (pte) } }) #endif /* __ASSEMBLY__ */ diff --git a/arch/tile/include/asm/pgtable_64.h b/arch/tile/include/asm/pgtable_64.h index fd80328523b4..2492fa5478e7 100644 --- a/arch/tile/include/asm/pgtable_64.h +++ b/arch/tile/include/asm/pgtable_64.h @@ -21,17 +21,19 @@ #define PGDIR_SIZE HV_L1_SPAN #define PGDIR_MASK (~(PGDIR_SIZE-1)) #define PTRS_PER_PGD HV_L0_ENTRIES -#define SIZEOF_PGD (PTRS_PER_PGD * sizeof(pgd_t)) +#define PGD_INDEX(va) HV_L0_INDEX(va) +#define SIZEOF_PGD HV_L0_SIZE /* * The level-1 index is defined by the huge page size. A PMD is composed * of PTRS_PER_PMD pgd_t's and is the middle level of the page table. */ -#define PMD_SHIFT HV_LOG2_PAGE_SIZE_LARGE -#define PMD_SIZE HV_PAGE_SIZE_LARGE +#define PMD_SHIFT HPAGE_SHIFT +#define PMD_SIZE HPAGE_SIZE #define PMD_MASK (~(PMD_SIZE-1)) -#define PTRS_PER_PMD (1 << (PGDIR_SHIFT - PMD_SHIFT)) -#define SIZEOF_PMD (PTRS_PER_PMD * sizeof(pmd_t)) +#define PTRS_PER_PMD _HV_L1_ENTRIES(HPAGE_SHIFT) +#define PMD_INDEX(va) _HV_L1_INDEX(va, HPAGE_SHIFT) +#define SIZEOF_PMD _HV_L1_SIZE(HPAGE_SHIFT) /* * The level-2 index is defined by the difference between the huge @@ -40,17 +42,19 @@ * Note that the hypervisor docs use PTE for what we call pte_t, so * this nomenclature is somewhat confusing. */ -#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL)) -#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t)) +#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT) +#define PTE_INDEX(va) _HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT) +#define SIZEOF_PTE _HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT) /* - * Align the vmalloc area to an L2 page table, and leave a guard page - * at the beginning and end. The vmalloc code also puts in an internal + * Align the vmalloc area to an L2 page table. Omit guard pages at + * the beginning and end for simplicity (particularly in the per-cpu + * memory allocation code). The vmalloc code puts in an internal * guard page between each allocation. */ #define _VMALLOC_END HUGE_VMAP_BASE -#define VMALLOC_END (_VMALLOC_END - PAGE_SIZE) -#define VMALLOC_START (_VMALLOC_START + PAGE_SIZE) +#define VMALLOC_END _VMALLOC_END +#define VMALLOC_START _VMALLOC_START #define HUGE_VMAP_END (HUGE_VMAP_BASE + PGDIR_SIZE) @@ -98,7 +102,7 @@ static inline int pud_bad(pud_t pud) * A pud_t points to a pmd_t array. Since we can have multiple per * page, we don't have a one-to-one mapping of pud_t's to pages. */ -#define pud_page(pud) pfn_to_page(HV_PTFN_TO_PFN(pud_ptfn(pud))) +#define pud_page(pud) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pud_ptfn(pud)))) static inline unsigned long pud_index(unsigned long address) { @@ -108,28 +112,6 @@ static inline unsigned long pud_index(unsigned long address) #define pmd_offset(pud, address) \ ((pmd_t *)pud_page_vaddr(*(pud)) + pmd_index(address)) -static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) -{ - set_pte(pmdp, pmdval); -} - -/* Create a pmd from a PTFN and pgprot. */ -static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) -{ - return hv_pte_set_ptfn(prot, ptfn); -} - -/* Return the page-table frame number (ptfn) that a pmd_t points at. */ -static inline unsigned long pmd_ptfn(pmd_t pmd) -{ - return hv_pte_get_ptfn(pmd); -} - -static inline void pmd_clear(pmd_t *pmdp) -{ - __pte_clear(pmdp); -} - /* Normalize an address to having the correct high bits set. */ #define pgd_addr_normalize pgd_addr_normalize static inline unsigned long pgd_addr_normalize(unsigned long addr) @@ -170,6 +152,13 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, return hv_pte(__insn_exch(&ptep->val, 0UL)); } +/* + * pmds are the same as pgds and ptes, so converting is a no-op. + */ +#define pmd_pte(pmd) (pmd) +#define pmdp_ptep(pmdp) (pmdp) +#define pte_pmd(pte) (pte) + #endif /* __ASSEMBLY__ */ #endif /* _ASM_TILE_PGTABLE_64_H */ diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index 15cd8a4a06ce..8c4dd9ff91eb 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h @@ -76,6 +76,17 @@ struct async_tlb { #ifdef CONFIG_HARDWALL struct hardwall_info; +struct hardwall_task { + /* Which hardwall is this task tied to? (or NULL if none) */ + struct hardwall_info *info; + /* Chains this task into the list at info->task_head. */ + struct list_head list; +}; +#ifdef __tilepro__ +#define HARDWALL_TYPES 1 /* udn */ +#else +#define HARDWALL_TYPES 3 /* udn, idn, and ipi */ +#endif #endif struct thread_struct { @@ -116,10 +127,8 @@ struct thread_struct { unsigned long dstream_pf; #endif #ifdef CONFIG_HARDWALL - /* Is this task tied to an activated hardwall? */ - struct hardwall_info *hardwall; - /* Chains this task into the list at hardwall->list. */ - struct list_head hardwall_list; + /* Hardwall information for various resources. */ + struct hardwall_task hardwall[HARDWALL_TYPES]; #endif #if CHIP_HAS_TILE_DMA() /* Async DMA TLB fault information */ diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h index e58613e0752f..c67eb70ea78e 100644 --- a/arch/tile/include/asm/setup.h +++ b/arch/tile/include/asm/setup.h @@ -41,15 +41,15 @@ void restrict_dma_mpls(void); #ifdef CONFIG_HARDWALL /* User-level network management functions */ void reset_network_state(void); -void grant_network_mpls(void); -void restrict_network_mpls(void); struct task_struct; -int hardwall_deactivate(struct task_struct *task); +void hardwall_switch_tasks(struct task_struct *prev, struct task_struct *next); +void hardwall_deactivate_all(struct task_struct *task); +int hardwall_ipi_valid(int cpu); /* Hook hardwall code into changes in affinity. */ #define arch_set_cpus_allowed(p, new_mask) do { \ - if (p->thread.hardwall && !cpumask_equal(&p->cpus_allowed, new_mask)) \ - hardwall_deactivate(p); \ + if (!cpumask_equal(&p->cpus_allowed, new_mask)) \ + hardwall_deactivate_all(p); \ } while (0) #endif diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h index 3b5507c31eae..06f0464cfed9 100644 --- a/arch/tile/include/asm/syscalls.h +++ b/arch/tile/include/asm/syscalls.h @@ -43,7 +43,8 @@ long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi, u32 len, int advice); int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi, u32 len_lo, u32 len_hi, int advice); -long sys_flush_cache(void); +long sys_cacheflush(unsigned long addr, unsigned long len, + unsigned long flags); #ifndef __tilegx__ /* No mmap() in the 32-bit kernel. */ #define sys_mmap sys_mmap #endif diff --git a/arch/tile/include/asm/tlbflush.h b/arch/tile/include/asm/tlbflush.h index 96199d214fb8..dcf91b25a1e5 100644 --- a/arch/tile/include/asm/tlbflush.h +++ b/arch/tile/include/asm/tlbflush.h @@ -38,16 +38,11 @@ DECLARE_PER_CPU(int, current_asid); /* The hypervisor tells us what ASIDs are available to us. */ extern int min_asid, max_asid; -static inline unsigned long hv_page_size(const struct vm_area_struct *vma) -{ - return (vma->vm_flags & VM_HUGETLB) ? HPAGE_SIZE : PAGE_SIZE; -} - /* Pass as vma pointer for non-executable mapping, if no vma available. */ -#define FLUSH_NONEXEC ((const struct vm_area_struct *)-1UL) +#define FLUSH_NONEXEC ((struct vm_area_struct *)-1UL) /* Flush a single user page on this cpu. */ -static inline void local_flush_tlb_page(const struct vm_area_struct *vma, +static inline void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr, unsigned long page_size) { @@ -60,7 +55,7 @@ static inline void local_flush_tlb_page(const struct vm_area_struct *vma, } /* Flush range of user pages on this cpu. */ -static inline void local_flush_tlb_pages(const struct vm_area_struct *vma, +static inline void local_flush_tlb_pages(struct vm_area_struct *vma, unsigned long addr, unsigned long page_size, unsigned long len) @@ -117,10 +112,10 @@ extern void flush_tlb_all(void); extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); extern void flush_tlb_current_task(void); extern void flush_tlb_mm(struct mm_struct *); -extern void flush_tlb_page(const struct vm_area_struct *, unsigned long); -extern void flush_tlb_page_mm(const struct vm_area_struct *, +extern void flush_tlb_page(struct vm_area_struct *, unsigned long); +extern void flush_tlb_page_mm(struct vm_area_struct *, struct mm_struct *, unsigned long); -extern void flush_tlb_range(const struct vm_area_struct *, +extern void flush_tlb_range(struct vm_area_struct *, unsigned long start, unsigned long end); #define flush_tlb() flush_tlb_current_task() diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h index ef34d2caa5b1..c3dd275f25e2 100644 --- a/arch/tile/include/asm/uaccess.h +++ b/arch/tile/include/asm/uaccess.h @@ -114,45 +114,75 @@ struct exception_table_entry { extern int fixup_exception(struct pt_regs *regs); /* - * We return the __get_user_N function results in a structure, - * thus in r0 and r1. If "err" is zero, "val" is the result - * of the read; otherwise, "err" is -EFAULT. - * - * We rarely need 8-byte values on a 32-bit architecture, but - * we size the structure to accommodate. In practice, for the - * the smaller reads, we can zero the high word for free, and - * the caller will ignore it by virtue of casting anyway. + * Support macros for __get_user(). + * + * Implementation note: The "case 8" logic of casting to the type of + * the result of subtracting the value from itself is basically a way + * of keeping all integer types the same, but casting any pointers to + * ptrdiff_t, i.e. also an integer type. This way there are no + * questionable casts seen by the compiler on an ILP32 platform. + * + * Note that __get_user() and __put_user() assume proper alignment. */ -struct __get_user { - unsigned long long val; - int err; -}; -/* - * FIXME: we should express these as inline extended assembler, since - * they're fundamentally just a variable dereference and some - * supporting exception_table gunk. Note that (a la i386) we can - * extend the copy_to_user and copy_from_user routines to call into - * such extended assembler routines, though we will have to use a - * different return code in that case (1, 2, or 4, rather than -EFAULT). - */ -extern struct __get_user __get_user_1(const void __user *); -extern struct __get_user __get_user_2(const void __user *); -extern struct __get_user __get_user_4(const void __user *); -extern struct __get_user __get_user_8(const void __user *); -extern int __put_user_1(long, void __user *); -extern int __put_user_2(long, void __user *); -extern int __put_user_4(long, void __user *); -extern int __put_user_8(long long, void __user *); - -/* Unimplemented routines to cause linker failures */ -extern struct __get_user __get_user_bad(void); -extern int __put_user_bad(void); +#ifdef __LP64__ +#define _ASM_PTR ".quad" +#else +#define _ASM_PTR ".long" +#endif + +#define __get_user_asm(OP, x, ptr, ret) \ + asm volatile("1: {" #OP " %1, %2; movei %0, 0 }\n" \ + ".pushsection .fixup,\"ax\"\n" \ + "0: { movei %1, 0; movei %0, %3 }\n" \ + "j 9f\n" \ + ".section __ex_table,\"a\"\n" \ + _ASM_PTR " 1b, 0b\n" \ + ".popsection\n" \ + "9:" \ + : "=r" (ret), "=r" (x) \ + : "r" (ptr), "i" (-EFAULT)) + +#ifdef __tilegx__ +#define __get_user_1(x, ptr, ret) __get_user_asm(ld1u, x, ptr, ret) +#define __get_user_2(x, ptr, ret) __get_user_asm(ld2u, x, ptr, ret) +#define __get_user_4(x, ptr, ret) __get_user_asm(ld4u, x, ptr, ret) +#define __get_user_8(x, ptr, ret) __get_user_asm(ld, x, ptr, ret) +#else +#define __get_user_1(x, ptr, ret) __get_user_asm(lb_u, x, ptr, ret) +#define __get_user_2(x, ptr, ret) __get_user_asm(lh_u, x, ptr, ret) +#define __get_user_4(x, ptr, ret) __get_user_asm(lw, x, ptr, ret) +#ifdef __LITTLE_ENDIAN +#define __lo32(a, b) a +#define __hi32(a, b) b +#else +#define __lo32(a, b) b +#define __hi32(a, b) a +#endif +#define __get_user_8(x, ptr, ret) \ + ({ \ + unsigned int __a, __b; \ + asm volatile("1: { lw %1, %3; addi %2, %3, 4 }\n" \ + "2: { lw %2, %2; movei %0, 0 }\n" \ + ".pushsection .fixup,\"ax\"\n" \ + "0: { movei %1, 0; movei %2, 0 }\n" \ + "{ movei %0, %4; j 9f }\n" \ + ".section __ex_table,\"a\"\n" \ + ".word 1b, 0b\n" \ + ".word 2b, 0b\n" \ + ".popsection\n" \ + "9:" \ + : "=r" (ret), "=r" (__a), "=&r" (__b) \ + : "r" (ptr), "i" (-EFAULT)); \ + (x) = (__typeof(x))(__typeof((x)-(x))) \ + (((u64)__hi32(__a, __b) << 32) | \ + __lo32(__a, __b)); \ + }) +#endif + +extern int __get_user_bad(void) + __attribute__((warning("sizeof __get_user argument not 1, 2, 4 or 8"))); -/* - * Careful: we have to cast the result to the type of the pointer - * for sign reasons. - */ /** * __get_user: - Get a simple variable from user space, with less checking. * @x: Variable to store result. @@ -174,30 +204,62 @@ extern int __put_user_bad(void); * function. */ #define __get_user(x, ptr) \ -({ struct __get_user __ret; \ - __typeof__(*(ptr)) const __user *__gu_addr = (ptr); \ - __chk_user_ptr(__gu_addr); \ - switch (sizeof(*(__gu_addr))) { \ - case 1: \ - __ret = __get_user_1(__gu_addr); \ - break; \ - case 2: \ - __ret = __get_user_2(__gu_addr); \ - break; \ - case 4: \ - __ret = __get_user_4(__gu_addr); \ - break; \ - case 8: \ - __ret = __get_user_8(__gu_addr); \ - break; \ - default: \ - __ret = __get_user_bad(); \ - break; \ - } \ - (x) = (__typeof__(*__gu_addr)) (__typeof__(*__gu_addr - *__gu_addr)) \ - __ret.val; \ - __ret.err; \ -}) + ({ \ + int __ret; \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: __get_user_1(x, ptr, __ret); break; \ + case 2: __get_user_2(x, ptr, __ret); break; \ + case 4: __get_user_4(x, ptr, __ret); break; \ + case 8: __get_user_8(x, ptr, __ret); break; \ + default: __ret = __get_user_bad(); break; \ + } \ + __ret; \ + }) + +/* Support macros for __put_user(). */ + +#define __put_user_asm(OP, x, ptr, ret) \ + asm volatile("1: {" #OP " %1, %2; movei %0, 0 }\n" \ + ".pushsection .fixup,\"ax\"\n" \ + "0: { movei %0, %3; j 9f }\n" \ + ".section __ex_table,\"a\"\n" \ + _ASM_PTR " 1b, 0b\n" \ + ".popsection\n" \ + "9:" \ + : "=r" (ret) \ + : "r" (ptr), "r" (x), "i" (-EFAULT)) + +#ifdef __tilegx__ +#define __put_user_1(x, ptr, ret) __put_user_asm(st1, x, ptr, ret) +#define __put_user_2(x, ptr, ret) __put_user_asm(st2, x, ptr, ret) +#define __put_user_4(x, ptr, ret) __put_user_asm(st4, x, ptr, ret) +#define __put_user_8(x, ptr, ret) __put_user_asm(st, x, ptr, ret) +#else +#define __put_user_1(x, ptr, ret) __put_user_asm(sb, x, ptr, ret) +#define __put_user_2(x, ptr, ret) __put_user_asm(sh, x, ptr, ret) +#define __put_user_4(x, ptr, ret) __put_user_asm(sw, x, ptr, ret) +#define __put_user_8(x, ptr, ret) \ + ({ \ + u64 __x = (__typeof((x)-(x)))(x); \ + int __lo = (int) __x, __hi = (int) (__x >> 32); \ + asm volatile("1: { sw %1, %2; addi %0, %1, 4 }\n" \ + "2: { sw %0, %3; movei %0, 0 }\n" \ + ".pushsection .fixup,\"ax\"\n" \ + "0: { movei %0, %4; j 9f }\n" \ + ".section __ex_table,\"a\"\n" \ + ".word 1b, 0b\n" \ + ".word 2b, 0b\n" \ + ".popsection\n" \ + "9:" \ + : "=&r" (ret) \ + : "r" (ptr), "r" (__lo32(__lo, __hi)), \ + "r" (__hi32(__lo, __hi)), "i" (-EFAULT)); \ + }) +#endif + +extern int __put_user_bad(void) + __attribute__((warning("sizeof __put_user argument not 1, 2, 4 or 8"))); /** * __put_user: - Write a simple value into user space, with less checking. @@ -217,39 +279,19 @@ extern int __put_user_bad(void); * function. * * Returns zero on success, or -EFAULT on error. - * - * Implementation note: The "case 8" logic of casting to the type of - * the result of subtracting the value from itself is basically a way - * of keeping all integer types the same, but casting any pointers to - * ptrdiff_t, i.e. also an integer type. This way there are no - * questionable casts seen by the compiler on an ILP32 platform. */ #define __put_user(x, ptr) \ ({ \ - int __pu_err = 0; \ - __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ - typeof(*__pu_addr) __pu_val = (x); \ - __chk_user_ptr(__pu_addr); \ - switch (sizeof(__pu_val)) { \ - case 1: \ - __pu_err = __put_user_1((long)__pu_val, __pu_addr); \ - break; \ - case 2: \ - __pu_err = __put_user_2((long)__pu_val, __pu_addr); \ - break; \ - case 4: \ - __pu_err = __put_user_4((long)__pu_val, __pu_addr); \ - break; \ - case 8: \ - __pu_err = \ - __put_user_8((__typeof__(__pu_val - __pu_val))__pu_val,\ - __pu_addr); \ - break; \ - default: \ - __pu_err = __put_user_bad(); \ - break; \ + int __ret; \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: __put_user_1(x, ptr, __ret); break; \ + case 2: __put_user_2(x, ptr, __ret); break; \ + case 4: __put_user_4(x, ptr, __ret); break; \ + case 8: __put_user_8(x, ptr, __ret); break; \ + default: __ret = __put_user_bad(); break; \ } \ - __pu_err; \ + __ret; \ }) /* @@ -378,7 +420,7 @@ static inline unsigned long __must_check copy_from_user(void *to, /** * __copy_in_user() - copy data within user space, with less checking. * @to: Destination address, in user space. - * @from: Source address, in kernel space. + * @from: Source address, in user space. * @n: Number of bytes to copy. * * Context: User context only. This function may sleep. diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h index f70bf1c541f1..a017246ca0ce 100644 --- a/arch/tile/include/asm/unistd.h +++ b/arch/tile/include/asm/unistd.h @@ -24,8 +24,8 @@ #include <asm-generic/unistd.h> /* Additional Tilera-specific syscalls. */ -#define __NR_flush_cache (__NR_arch_specific_syscall + 1) -__SYSCALL(__NR_flush_cache, sys_flush_cache) +#define __NR_cacheflush (__NR_arch_specific_syscall + 1) +__SYSCALL(__NR_cacheflush, sys_cacheflush) #ifndef __tilegx__ /* "Fast" syscalls provide atomic support for 32-bit chips. */ diff --git a/arch/tile/include/hv/drv_xgbe_intf.h b/arch/tile/include/hv/drv_xgbe_intf.h index f13188ac281a..2a20b266d944 100644 --- a/arch/tile/include/hv/drv_xgbe_intf.h +++ b/arch/tile/include/hv/drv_xgbe_intf.h @@ -460,7 +460,7 @@ typedef void* lepp_comp_t; * linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for * our page size of exactly 65536. We add one for a "body" fragment. */ -#define LEPP_MAX_FRAGS (65536 / HV_PAGE_SIZE_SMALL + 2 + 1) +#define LEPP_MAX_FRAGS (65536 / HV_DEFAULT_PAGE_SIZE_SMALL + 2 + 1) /** Total number of bytes needed for an lepp_tso_cmd_t. */ #define LEPP_TSO_CMD_SIZE(num_frags, header_size) \ diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h index 72ec1e972f15..ccd847e2347f 100644 --- a/arch/tile/include/hv/hypervisor.h +++ b/arch/tile/include/hv/hypervisor.h @@ -17,8 +17,8 @@ * The hypervisor's public API. */ -#ifndef _TILE_HV_H -#define _TILE_HV_H +#ifndef _HV_HV_H +#define _HV_HV_H #include <arch/chip.h> @@ -42,25 +42,45 @@ */ #define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN) -/** The log2 of the size of small pages, in bytes. This value should - * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL). +/** The log2 of the initial size of small pages, in bytes. + * See HV_DEFAULT_PAGE_SIZE_SMALL. */ -#define HV_LOG2_PAGE_SIZE_SMALL 16 +#define HV_LOG2_DEFAULT_PAGE_SIZE_SMALL 16 -/** The size of small pages, in bytes. This value should be verified +/** The initial size of small pages, in bytes. This value should be verified * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL). + * It may also be modified when installing a new context. */ -#define HV_PAGE_SIZE_SMALL (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_SMALL) +#define HV_DEFAULT_PAGE_SIZE_SMALL \ + (__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_SMALL) -/** The log2 of the size of large pages, in bytes. This value should be - * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE). +/** The log2 of the initial size of large pages, in bytes. + * See HV_DEFAULT_PAGE_SIZE_LARGE. */ -#define HV_LOG2_PAGE_SIZE_LARGE 24 +#define HV_LOG2_DEFAULT_PAGE_SIZE_LARGE 24 -/** The size of large pages, in bytes. This value should be verified +/** The initial size of large pages, in bytes. This value should be verified * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE). + * It may also be modified when installing a new context. */ -#define HV_PAGE_SIZE_LARGE (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_LARGE) +#define HV_DEFAULT_PAGE_SIZE_LARGE \ + (__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_LARGE) + +#if CHIP_VA_WIDTH() > 32 + +/** The log2 of the initial size of jumbo pages, in bytes. + * See HV_DEFAULT_PAGE_SIZE_JUMBO. + */ +#define HV_LOG2_DEFAULT_PAGE_SIZE_JUMBO 32 + +/** The initial size of jumbo pages, in bytes. This value should + * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_JUMBO). + * It may also be modified when installing a new context. + */ +#define HV_DEFAULT_PAGE_SIZE_JUMBO \ + (__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_JUMBO) + +#endif /** The log2 of the granularity at which page tables must be aligned; * in other words, the CPA for a page table must have this many zero @@ -280,8 +300,11 @@ #define HV_DISPATCH_GET_IPI_PTE 56 #endif +/** hv_set_pte_super_shift */ +#define HV_DISPATCH_SET_PTE_SUPER_SHIFT 57 + /** One more than the largest dispatch value */ -#define _HV_DISPATCH_END 57 +#define _HV_DISPATCH_END 58 #ifndef __ASSEMBLER__ @@ -401,7 +424,18 @@ typedef enum { * that the temperature has hit an upper limit and is no longer being * accurately tracked. */ - HV_SYSCONF_BOARD_TEMP = 6 + HV_SYSCONF_BOARD_TEMP = 6, + + /** Legal page size bitmask for hv_install_context(). + * For example, if 16KB and 64KB small pages are supported, + * it would return "HV_CTX_PG_SM_16K | HV_CTX_PG_SM_64K". + */ + HV_SYSCONF_VALID_PAGE_SIZES = 7, + + /** The size of jumbo pages, in bytes. + * If no jumbo pages are available, zero will be returned. + */ + HV_SYSCONF_PAGE_SIZE_JUMBO = 8, } HV_SysconfQuery; @@ -474,7 +508,19 @@ typedef enum { HV_CONFSTR_SWITCH_CONTROL = 14, /** Chip revision level. */ - HV_CONFSTR_CHIP_REV = 15 + HV_CONFSTR_CHIP_REV = 15, + + /** CPU module part number. */ + HV_CONFSTR_CPUMOD_PART_NUM = 16, + + /** CPU module serial number. */ + HV_CONFSTR_CPUMOD_SERIAL_NUM = 17, + + /** CPU module revision level. */ + HV_CONFSTR_CPUMOD_REV = 18, + + /** Human-readable CPU module description. */ + HV_CONFSTR_CPUMOD_DESC = 19 } HV_ConfstrQuery; @@ -494,11 +540,16 @@ int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len); /** Tile coordinate */ typedef struct { +#ifndef __BIG_ENDIAN__ /** X coordinate, relative to supervisor's top-left coordinate */ int x; /** Y coordinate, relative to supervisor's top-left coordinate */ int y; +#else + int y; + int x; +#endif } HV_Coord; @@ -649,6 +700,12 @@ void hv_set_rtc(HV_RTCTime time); * new page table does not need to contain any mapping for the * hv_install_context address itself. * + * At most one HV_CTX_PG_SM_* flag may be specified in "flags"; + * if multiple flags are specified, HV_EINVAL is returned. + * Specifying none of the flags results in using the default page size. + * All cores participating in a given client must request the same + * page size, or the results are undefined. + * * @param page_table Root of the page table. * @param access PTE providing info on how to read the page table. This * value must be consistent between multiple tiles sharing a page table, @@ -667,8 +724,36 @@ int hv_install_context(HV_PhysAddr page_table, HV_PTE access, HV_ASID asid, #define HV_CTX_DIRECTIO 0x1 /**< Direct I/O requests are accepted from PL0. */ +#define HV_CTX_PG_SM_4K 0x10 /**< Use 4K small pages, if available. */ +#define HV_CTX_PG_SM_16K 0x20 /**< Use 16K small pages, if available. */ +#define HV_CTX_PG_SM_64K 0x40 /**< Use 64K small pages, if available. */ +#define HV_CTX_PG_SM_MASK 0xf0 /**< Mask of all possible small pages. */ + #ifndef __ASSEMBLER__ + +/** Set the number of pages ganged together by HV_PTE_SUPER at a + * particular level of the page table. + * + * The current TILE-Gx hardware only supports powers of four + * (i.e. log2_count must be a multiple of two), and the requested + * "super" page size must be less than the span of the next level in + * the page table. The largest size that can be requested is 64GB. + * + * The shift value is initially "0" for all page table levels, + * indicating that the HV_PTE_SUPER bit is effectively ignored. + * + * If you change the count from one non-zero value to another, the + * hypervisor will flush the entire TLB and TSB to avoid confusion. + * + * @param level Page table level (0, 1, or 2) + * @param log2_count Base-2 log of the number of pages to gang together, + * i.e. how much to shift left the base page size for the super page size. + * @return Zero on success, or a hypervisor error code on failure. + */ +int hv_set_pte_super_shift(int level, int log2_count); + + /** Value returned from hv_inquire_context(). */ typedef struct { @@ -986,8 +1071,13 @@ HV_VirtAddrRange hv_inquire_virtual(int idx); /** A range of ASID values. */ typedef struct { +#ifndef __BIG_ENDIAN__ HV_ASID start; /**< First ASID in the range. */ unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ +#else + unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ + HV_ASID start; /**< First ASID in the range. */ +#endif } HV_ASIDRange; /** Returns information about a range of ASIDs. @@ -1238,11 +1328,14 @@ HV_Errno hv_set_command_line(HV_VirtAddr buf, int length); * with the existing priority pages) or "red/black" (if they don't). * The bitmask provides information on which parts of the cache * have been used for pinned pages so far on this tile; if (1 << N) - * appears in the bitmask, that indicates that a page has been marked - * "priority" whose PFN equals N, mod 8. + * appears in the bitmask, that indicates that a 4KB region of the + * cache starting at (N * 4KB) is in use by a "priority" page. + * The portion of cache used by a particular page can be computed + * by taking the page's PA, modulo CHIP_L2_CACHE_SIZE(), and setting + * all the "4KB" bits corresponding to the actual page size. * @param bitmask A bitmap of priority page set values */ -void hv_set_caching(unsigned int bitmask); +void hv_set_caching(unsigned long bitmask); /** Zero out a specified number of pages. @@ -1308,6 +1401,7 @@ typedef enum /** Message recipient. */ typedef struct { +#ifndef __BIG_ENDIAN__ /** X coordinate, relative to supervisor's top-left coordinate */ unsigned int x:11; @@ -1316,6 +1410,11 @@ typedef struct /** Status of this recipient */ HV_Recip_State state:10; +#else //__BIG_ENDIAN__ + HV_Recip_State state:10; + unsigned int y:11; + unsigned int x:11; +#endif } HV_Recipient; /** Send a message to a set of recipients. @@ -1851,12 +1950,12 @@ int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control, #define HV_PTE_INDEX_USER 10 /**< Page is user-accessible */ #define HV_PTE_INDEX_ACCESSED 11 /**< Page has been accessed */ #define HV_PTE_INDEX_DIRTY 12 /**< Page has been written */ - /* Bits 13-15 are reserved for + /* Bits 13-14 are reserved for future use. */ +#define HV_PTE_INDEX_SUPER 15 /**< Pages ganged together for TLB */ #define HV_PTE_INDEX_MODE 16 /**< Page mode; see HV_PTE_MODE_xxx */ #define HV_PTE_MODE_BITS 3 /**< Number of bits in mode */ - /* Bit 19 is reserved for - future use. */ +#define HV_PTE_INDEX_CLIENT2 19 /**< Page client state 2 */ #define HV_PTE_INDEX_LOTAR 20 /**< Page's LOTAR; must be high bits of word */ #define HV_PTE_LOTAR_BITS 12 /**< Number of bits in a LOTAR */ @@ -1869,15 +1968,6 @@ int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control, of word */ #define HV_PTE_PTFN_BITS 29 /**< Number of bits in a PTFN */ -/** Position of the PFN field within the PTE (subset of the PTFN). */ -#define HV_PTE_INDEX_PFN (HV_PTE_INDEX_PTFN + (HV_LOG2_PAGE_SIZE_SMALL - \ - HV_LOG2_PAGE_TABLE_ALIGN)) - -/** Length of the PFN field within the PTE (subset of the PTFN). */ -#define HV_PTE_INDEX_PFN_BITS (HV_PTE_INDEX_PTFN_BITS - \ - (HV_LOG2_PAGE_SIZE_SMALL - \ - HV_LOG2_PAGE_TABLE_ALIGN)) - /* * Legal values for the PTE's mode field */ @@ -1957,7 +2047,10 @@ int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control, /** Does this PTE map a page? * - * If this bit is set in the level-1 page table, the entry should be + * If this bit is set in a level-0 page table, the entry should be + * interpreted as a level-2 page table entry mapping a jumbo page. + * + * If this bit is set in a level-1 page table, the entry should be * interpreted as a level-2 page table entry mapping a large page. * * This bit should not be modified by the client while PRESENT is set, as @@ -1967,6 +2060,18 @@ int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control, */ #define HV_PTE_PAGE (__HV_PTE_ONE << HV_PTE_INDEX_PAGE) +/** Does this PTE implicitly reference multiple pages? + * + * If this bit is set in the page table (either in the level-2 page table, + * or in a higher level page table in conjunction with the PAGE bit) + * then the PTE specifies a range of contiguous pages, not a single page. + * The hv_set_pte_super_shift() allows you to specify the count for + * each level of the page table. + * + * Note: this bit is not supported on TILEPro systems. + */ +#define HV_PTE_SUPER (__HV_PTE_ONE << HV_PTE_INDEX_SUPER) + /** Is this a global (non-ASID) mapping? * * If this bit is set, the translations established by this PTE will @@ -2046,6 +2151,13 @@ int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control, */ #define HV_PTE_CLIENT1 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT1) +/** Client-private bit in PTE. + * + * This bit is guaranteed not to be inspected or modified by the + * hypervisor. + */ +#define HV_PTE_CLIENT2 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT2) + /** Non-coherent (NC) bit in PTE. * * If this bit is set, the mapping that is set up will be non-coherent @@ -2178,8 +2290,10 @@ hv_pte_clear_##name(HV_PTE pte) \ */ _HV_BIT(present, PRESENT) _HV_BIT(page, PAGE) +_HV_BIT(super, SUPER) _HV_BIT(client0, CLIENT0) _HV_BIT(client1, CLIENT1) +_HV_BIT(client2, CLIENT2) _HV_BIT(migrating, MIGRATING) _HV_BIT(nc, NC) _HV_BIT(readable, READABLE) @@ -2222,40 +2336,11 @@ hv_pte_set_mode(HV_PTE pte, unsigned int val) * * This field contains the upper bits of the CPA (client physical * address) of the target page; the complete CPA is this field with - * HV_LOG2_PAGE_SIZE_SMALL zero bits appended to it. - * - * For PTEs in a level-1 page table where the Page bit is set, the - * CPA must be aligned modulo the large page size. - */ -static __inline unsigned int -hv_pte_get_pfn(const HV_PTE pte) -{ - return pte.val >> HV_PTE_INDEX_PFN; -} - - -/** Set the page frame number into a PTE. See hv_pte_get_pfn. */ -static __inline HV_PTE -hv_pte_set_pfn(HV_PTE pte, unsigned int val) -{ - /* - * Note that the use of "PTFN" in the next line is intentional; we - * don't want any garbage lower bits left in that field. - */ - pte.val &= ~(((1ULL << HV_PTE_PTFN_BITS) - 1) << HV_PTE_INDEX_PTFN); - pte.val |= (__hv64) val << HV_PTE_INDEX_PFN; - return pte; -} - -/** Get the page table frame number from the PTE. - * - * This field contains the upper bits of the CPA (client physical - * address) of the target page table; the complete CPA is this field with - * with HV_PAGE_TABLE_ALIGN zero bits appended to it. + * HV_LOG2_PAGE_TABLE_ALIGN zero bits appended to it. * - * For PTEs in a level-1 page table when the Page bit is not set, the - * CPA must be aligned modulo the sticter of HV_PAGE_TABLE_ALIGN and - * the level-2 page table size. + * For all PTEs in the lowest-level page table, and for all PTEs with + * the Page bit set in all page tables, the CPA must be aligned modulo + * the relevant page size. */ static __inline unsigned long hv_pte_get_ptfn(const HV_PTE pte) @@ -2263,7 +2348,6 @@ hv_pte_get_ptfn(const HV_PTE pte) return pte.val >> HV_PTE_INDEX_PTFN; } - /** Set the page table frame number into a PTE. See hv_pte_get_ptfn. */ static __inline HV_PTE hv_pte_set_ptfn(HV_PTE pte, unsigned long val) @@ -2273,6 +2357,20 @@ hv_pte_set_ptfn(HV_PTE pte, unsigned long val) return pte; } +/** Get the client physical address from the PTE. See hv_pte_set_ptfn. */ +static __inline HV_PhysAddr +hv_pte_get_pa(const HV_PTE pte) +{ + return (__hv64) hv_pte_get_ptfn(pte) << HV_LOG2_PAGE_TABLE_ALIGN; +} + +/** Set the client physical address into a PTE. See hv_pte_get_ptfn. */ +static __inline HV_PTE +hv_pte_set_pa(HV_PTE pte, HV_PhysAddr pa) +{ + return hv_pte_set_ptfn(pte, pa >> HV_LOG2_PAGE_TABLE_ALIGN); +} + /** Get the remote tile caching this page. * @@ -2308,28 +2406,20 @@ hv_pte_set_lotar(HV_PTE pte, unsigned int val) #endif /* !__ASSEMBLER__ */ -/** Converts a client physical address to a pfn. */ -#define HV_CPA_TO_PFN(p) ((p) >> HV_LOG2_PAGE_SIZE_SMALL) - -/** Converts a pfn to a client physical address. */ -#define HV_PFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_SIZE_SMALL) - /** Converts a client physical address to a ptfn. */ #define HV_CPA_TO_PTFN(p) ((p) >> HV_LOG2_PAGE_TABLE_ALIGN) /** Converts a ptfn to a client physical address. */ #define HV_PTFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_TABLE_ALIGN) -/** Converts a ptfn to a pfn. */ -#define HV_PTFN_TO_PFN(p) \ - ((p) >> (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN)) - -/** Converts a pfn to a ptfn. */ -#define HV_PFN_TO_PTFN(p) \ - ((p) << (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN)) - #if CHIP_VA_WIDTH() > 32 +/* + * Note that we currently do not allow customizing the page size + * of the L0 pages, but fix them at 4GB, so we do not use the + * "_HV_xxx" nomenclature for the L0 macros. + */ + /** Log number of HV_PTE entries in L0 page table */ #define HV_LOG2_L0_ENTRIES (CHIP_VA_WIDTH() - HV_LOG2_L1_SPAN) @@ -2359,69 +2449,104 @@ hv_pte_set_lotar(HV_PTE pte, unsigned int val) #endif /* CHIP_VA_WIDTH() > 32 */ /** Log number of HV_PTE entries in L1 page table */ -#define HV_LOG2_L1_ENTRIES (HV_LOG2_L1_SPAN - HV_LOG2_PAGE_SIZE_LARGE) +#define _HV_LOG2_L1_ENTRIES(log2_page_size_large) \ + (HV_LOG2_L1_SPAN - log2_page_size_large) /** Number of HV_PTE entries in L1 page table */ -#define HV_L1_ENTRIES (1 << HV_LOG2_L1_ENTRIES) +#define _HV_L1_ENTRIES(log2_page_size_large) \ + (1 << _HV_LOG2_L1_ENTRIES(log2_page_size_large)) /** Log size of L1 page table in bytes */ -#define HV_LOG2_L1_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L1_ENTRIES) +#define _HV_LOG2_L1_SIZE(log2_page_size_large) \ + (HV_LOG2_PTE_SIZE + _HV_LOG2_L1_ENTRIES(log2_page_size_large)) /** Size of L1 page table in bytes */ -#define HV_L1_SIZE (1 << HV_LOG2_L1_SIZE) +#define _HV_L1_SIZE(log2_page_size_large) \ + (1 << _HV_LOG2_L1_SIZE(log2_page_size_large)) /** Log number of HV_PTE entries in level-2 page table */ -#define HV_LOG2_L2_ENTRIES (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL) +#define _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \ + (log2_page_size_large - log2_page_size_small) /** Number of HV_PTE entries in level-2 page table */ -#define HV_L2_ENTRIES (1 << HV_LOG2_L2_ENTRIES) +#define _HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \ + (1 << _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small)) /** Log size of level-2 page table in bytes */ -#define HV_LOG2_L2_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L2_ENTRIES) +#define _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small) \ + (HV_LOG2_PTE_SIZE + \ + _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small)) /** Size of level-2 page table in bytes */ -#define HV_L2_SIZE (1 << HV_LOG2_L2_SIZE) +#define _HV_L2_SIZE(log2_page_size_large, log2_page_size_small) \ + (1 << _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small)) #ifdef __ASSEMBLER__ #if CHIP_VA_WIDTH() > 32 /** Index in L1 for a specific VA */ -#define HV_L1_INDEX(va) \ - (((va) >> HV_LOG2_PAGE_SIZE_LARGE) & (HV_L1_ENTRIES - 1)) +#define _HV_L1_INDEX(va, log2_page_size_large) \ + (((va) >> log2_page_size_large) & (_HV_L1_ENTRIES(log2_page_size_large) - 1)) #else /* CHIP_VA_WIDTH() > 32 */ /** Index in L1 for a specific VA */ -#define HV_L1_INDEX(va) \ - (((va) >> HV_LOG2_PAGE_SIZE_LARGE)) +#define _HV_L1_INDEX(va, log2_page_size_large) \ + (((va) >> log2_page_size_large)) #endif /* CHIP_VA_WIDTH() > 32 */ /** Index in level-2 page table for a specific VA */ -#define HV_L2_INDEX(va) \ - (((va) >> HV_LOG2_PAGE_SIZE_SMALL) & (HV_L2_ENTRIES - 1)) +#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \ + (((va) >> log2_page_size_small) & \ + (_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1)) #else /* __ASSEMBLER __ */ #if CHIP_VA_WIDTH() > 32 /** Index in L1 for a specific VA */ -#define HV_L1_INDEX(va) \ - (((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_LARGE) & (HV_L1_ENTRIES - 1)) +#define _HV_L1_INDEX(va, log2_page_size_large) \ + (((HV_VirtAddr)(va) >> log2_page_size_large) & \ + (_HV_L1_ENTRIES(log2_page_size_large) - 1)) #else /* CHIP_VA_WIDTH() > 32 */ /** Index in L1 for a specific VA */ -#define HV_L1_INDEX(va) \ - (((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_LARGE)) +#define _HV_L1_INDEX(va, log2_page_size_large) \ + (((HV_VirtAddr)(va) >> log2_page_size_large)) #endif /* CHIP_VA_WIDTH() > 32 */ /** Index in level-2 page table for a specific VA */ -#define HV_L2_INDEX(va) \ - (((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_SMALL) & (HV_L2_ENTRIES - 1)) +#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \ + (((HV_VirtAddr)(va) >> log2_page_size_small) & \ + (_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1)) #endif /* __ASSEMBLER __ */ -#endif /* _TILE_HV_H */ +/** Position of the PFN field within the PTE (subset of the PTFN). */ +#define _HV_PTE_INDEX_PFN(log2_page_size) \ + (HV_PTE_INDEX_PTFN + (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) + +/** Length of the PFN field within the PTE (subset of the PTFN). */ +#define _HV_PTE_INDEX_PFN_BITS(log2_page_size) \ + (HV_PTE_INDEX_PTFN_BITS - (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) + +/** Converts a client physical address to a pfn. */ +#define _HV_CPA_TO_PFN(p, log2_page_size) ((p) >> log2_page_size) + +/** Converts a pfn to a client physical address. */ +#define _HV_PFN_TO_CPA(p, log2_page_size) \ + (((HV_PhysAddr)(p)) << log2_page_size) + +/** Converts a ptfn to a pfn. */ +#define _HV_PTFN_TO_PFN(p, log2_page_size) \ + ((p) >> (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) + +/** Converts a pfn to a ptfn. */ +#define _HV_PFN_TO_PTFN(p, log2_page_size) \ + ((p) << (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) + +#endif /* _HV_HV_H */ diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile index 0d826faf8f35..5de99248d8df 100644 --- a/arch/tile/kernel/Makefile +++ b/arch/tile/kernel/Makefile @@ -9,10 +9,9 @@ obj-y := backtrace.o entry.o irq.o messaging.o \ intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o obj-$(CONFIG_HARDWALL) += hardwall.o -obj-$(CONFIG_TILEGX) += futex_64.o obj-$(CONFIG_COMPAT) += compat.o compat_signal.o obj-$(CONFIG_SMP) += smpboot.o smp.o tlb.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o +obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_$(BITS).o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S index ec91568df880..133c4b56a99e 100644 --- a/arch/tile/kernel/entry.S +++ b/arch/tile/kernel/entry.S @@ -100,8 +100,9 @@ STD_ENTRY(smp_nap) */ STD_ENTRY(_cpu_idle) movei r1, 1 + IRQ_ENABLE_LOAD(r2, r3) mtspr INTERRUPT_CRITICAL_SECTION, r1 - IRQ_ENABLE(r2, r3) /* unmask, but still with ICS set */ + IRQ_ENABLE_APPLY(r2, r3) /* unmask, but still with ICS set */ mtspr INTERRUPT_CRITICAL_SECTION, zero .global _cpu_idle_nap _cpu_idle_nap: diff --git a/arch/tile/kernel/hardwall.c b/arch/tile/kernel/hardwall.c index 8c41891aab34..20273ee37deb 100644 --- a/arch/tile/kernel/hardwall.c +++ b/arch/tile/kernel/hardwall.c @@ -33,59 +33,157 @@ /* - * This data structure tracks the rectangle data, etc., associated - * one-to-one with a "struct file *" from opening HARDWALL_FILE. + * Implement a per-cpu "hardwall" resource class such as UDN or IPI. + * We use "hardwall" nomenclature throughout for historical reasons. + * The lock here controls access to the list data structure as well as + * to the items on the list. + */ +struct hardwall_type { + int index; + int is_xdn; + int is_idn; + int disabled; + const char *name; + struct list_head list; + spinlock_t lock; + struct proc_dir_entry *proc_dir; +}; + +enum hardwall_index { + HARDWALL_UDN = 0, +#ifndef __tilepro__ + HARDWALL_IDN = 1, + HARDWALL_IPI = 2, +#endif + _HARDWALL_TYPES +}; + +static struct hardwall_type hardwall_types[] = { + { /* user-space access to UDN */ + 0, + 1, + 0, + 0, + "udn", + LIST_HEAD_INIT(hardwall_types[HARDWALL_UDN].list), + __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_UDN].lock), + NULL + }, +#ifndef __tilepro__ + { /* user-space access to IDN */ + 1, + 1, + 1, + 1, /* disabled pending hypervisor support */ + "idn", + LIST_HEAD_INIT(hardwall_types[HARDWALL_IDN].list), + __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IDN].lock), + NULL + }, + { /* access to user-space IPI */ + 2, + 0, + 0, + 0, + "ipi", + LIST_HEAD_INIT(hardwall_types[HARDWALL_IPI].list), + __SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IPI].lock), + NULL + }, +#endif +}; + +/* + * This data structure tracks the cpu data, etc., associated + * one-to-one with a "struct file *" from opening a hardwall device file. * Note that the file's private data points back to this structure. */ struct hardwall_info { - struct list_head list; /* "rectangles" list */ + struct list_head list; /* for hardwall_types.list */ struct list_head task_head; /* head of tasks in this hardwall */ - struct cpumask cpumask; /* cpus in the rectangle */ + struct hardwall_type *type; /* type of this resource */ + struct cpumask cpumask; /* cpus reserved */ + int id; /* integer id for this hardwall */ + int teardown_in_progress; /* are we tearing this one down? */ + + /* Remaining fields only valid for user-network resources. */ int ulhc_x; /* upper left hand corner x coord */ int ulhc_y; /* upper left hand corner y coord */ int width; /* rectangle width */ int height; /* rectangle height */ - int id; /* integer id for this hardwall */ - int teardown_in_progress; /* are we tearing this one down? */ +#if CHIP_HAS_REV1_XDN() + atomic_t xdn_pending_count; /* cores in phase 1 of drain */ +#endif }; -/* Currently allocated hardwall rectangles */ -static LIST_HEAD(rectangles); /* /proc/tile/hardwall */ static struct proc_dir_entry *hardwall_proc_dir; /* Functions to manage files in /proc/tile/hardwall. */ -static void hardwall_add_proc(struct hardwall_info *rect); -static void hardwall_remove_proc(struct hardwall_info *rect); - -/* - * Guard changes to the hardwall data structures. - * This could be finer grained (e.g. one lock for the list of hardwall - * rectangles, then separate embedded locks for each one's list of tasks), - * but there are subtle correctness issues when trying to start with - * a task's "hardwall" pointer and lock the correct rectangle's embedded - * lock in the presence of a simultaneous deactivation, so it seems - * easier to have a single lock, given that none of these data - * structures are touched very frequently during normal operation. - */ -static DEFINE_SPINLOCK(hardwall_lock); +static void hardwall_add_proc(struct hardwall_info *); +static void hardwall_remove_proc(struct hardwall_info *); /* Allow disabling UDN access. */ -static int udn_disabled; static int __init noudn(char *str) { pr_info("User-space UDN access is disabled\n"); - udn_disabled = 1; + hardwall_types[HARDWALL_UDN].disabled = 1; return 0; } early_param("noudn", noudn); +#ifndef __tilepro__ +/* Allow disabling IDN access. */ +static int __init noidn(char *str) +{ + pr_info("User-space IDN access is disabled\n"); + hardwall_types[HARDWALL_IDN].disabled = 1; + return 0; +} +early_param("noidn", noidn); + +/* Allow disabling IPI access. */ +static int __init noipi(char *str) +{ + pr_info("User-space IPI access is disabled\n"); + hardwall_types[HARDWALL_IPI].disabled = 1; + return 0; +} +early_param("noipi", noipi); +#endif + /* - * Low-level primitives + * Low-level primitives for UDN/IDN */ +#ifdef __tilepro__ +#define mtspr_XDN(hwt, name, val) \ + do { (void)(hwt); __insn_mtspr(SPR_UDN_##name, (val)); } while (0) +#define mtspr_MPL_XDN(hwt, name, val) \ + do { (void)(hwt); __insn_mtspr(SPR_MPL_UDN_##name, (val)); } while (0) +#define mfspr_XDN(hwt, name) \ + ((void)(hwt), __insn_mfspr(SPR_UDN_##name)) +#else +#define mtspr_XDN(hwt, name, val) \ + do { \ + if ((hwt)->is_idn) \ + __insn_mtspr(SPR_IDN_##name, (val)); \ + else \ + __insn_mtspr(SPR_UDN_##name, (val)); \ + } while (0) +#define mtspr_MPL_XDN(hwt, name, val) \ + do { \ + if ((hwt)->is_idn) \ + __insn_mtspr(SPR_MPL_IDN_##name, (val)); \ + else \ + __insn_mtspr(SPR_MPL_UDN_##name, (val)); \ + } while (0) +#define mfspr_XDN(hwt, name) \ + ((hwt)->is_idn ? __insn_mfspr(SPR_IDN_##name) : __insn_mfspr(SPR_UDN_##name)) +#endif + /* Set a CPU bit if the CPU is online. */ #define cpu_online_set(cpu, dst) do { \ if (cpu_online(cpu)) \ @@ -101,7 +199,7 @@ static int contains(struct hardwall_info *r, int x, int y) } /* Compute the rectangle parameters and validate the cpumask. */ -static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask) +static int check_rectangle(struct hardwall_info *r, struct cpumask *mask) { int x, y, cpu, ulhc, lrhc; @@ -114,8 +212,6 @@ static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask) r->ulhc_y = cpu_y(ulhc); r->width = cpu_x(lrhc) - r->ulhc_x + 1; r->height = cpu_y(lrhc) - r->ulhc_y + 1; - cpumask_copy(&r->cpumask, mask); - r->id = ulhc; /* The ulhc cpu id can be the hardwall id. */ /* Width and height must be positive */ if (r->width <= 0 || r->height <= 0) @@ -128,7 +224,7 @@ static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask) return -EINVAL; /* - * Note that offline cpus can't be drained when this UDN + * Note that offline cpus can't be drained when this user network * rectangle eventually closes. We used to detect this * situation and print a warning, but it annoyed users and * they ignored it anyway, so now we just return without a @@ -137,16 +233,6 @@ static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask) return 0; } -/* Do the two given rectangles overlap on any cpu? */ -static int overlaps(struct hardwall_info *a, struct hardwall_info *b) -{ - return a->ulhc_x + a->width > b->ulhc_x && /* A not to the left */ - b->ulhc_x + b->width > a->ulhc_x && /* B not to the left */ - a->ulhc_y + a->height > b->ulhc_y && /* A not above */ - b->ulhc_y + b->height > a->ulhc_y; /* B not above */ -} - - /* * Hardware management of hardwall setup, teardown, trapping, * and enabling/disabling PL0 access to the networks. @@ -157,23 +243,35 @@ enum direction_protect { N_PROTECT = (1 << 0), E_PROTECT = (1 << 1), S_PROTECT = (1 << 2), - W_PROTECT = (1 << 3) + W_PROTECT = (1 << 3), + C_PROTECT = (1 << 4), }; -static void enable_firewall_interrupts(void) +static inline int xdn_which_interrupt(struct hardwall_type *hwt) +{ +#ifndef __tilepro__ + if (hwt->is_idn) + return INT_IDN_FIREWALL; +#endif + return INT_UDN_FIREWALL; +} + +static void enable_firewall_interrupts(struct hardwall_type *hwt) { - arch_local_irq_unmask_now(INT_UDN_FIREWALL); + arch_local_irq_unmask_now(xdn_which_interrupt(hwt)); } -static void disable_firewall_interrupts(void) +static void disable_firewall_interrupts(struct hardwall_type *hwt) { - arch_local_irq_mask_now(INT_UDN_FIREWALL); + arch_local_irq_mask_now(xdn_which_interrupt(hwt)); } /* Set up hardwall on this cpu based on the passed hardwall_info. */ -static void hardwall_setup_ipi_func(void *info) +static void hardwall_setup_func(void *info) { struct hardwall_info *r = info; + struct hardwall_type *hwt = r->type; + int cpu = smp_processor_id(); int x = cpu % smp_width; int y = cpu / smp_width; @@ -187,13 +285,12 @@ static void hardwall_setup_ipi_func(void *info) if (y == r->ulhc_y + r->height - 1) bits |= S_PROTECT; BUG_ON(bits == 0); - __insn_mtspr(SPR_UDN_DIRECTION_PROTECT, bits); - enable_firewall_interrupts(); - + mtspr_XDN(hwt, DIRECTION_PROTECT, bits); + enable_firewall_interrupts(hwt); } /* Set up all cpus on edge of rectangle to enable/disable hardwall SPRs. */ -static void hardwall_setup(struct hardwall_info *r) +static void hardwall_protect_rectangle(struct hardwall_info *r) { int x, y, cpu, delta; struct cpumask rect_cpus; @@ -217,37 +314,50 @@ static void hardwall_setup(struct hardwall_info *r) } /* Then tell all the cpus to set up their protection SPR */ - on_each_cpu_mask(&rect_cpus, hardwall_setup_ipi_func, r, 1); + on_each_cpu_mask(&rect_cpus, hardwall_setup_func, r, 1); } void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) { struct hardwall_info *rect; + struct hardwall_type *hwt; struct task_struct *p; struct siginfo info; - int x, y; int cpu = smp_processor_id(); int found_processes; unsigned long flags; - struct pt_regs *old_regs = set_irq_regs(regs); + irq_enter(); + /* Figure out which network trapped. */ + switch (fault_num) { +#ifndef __tilepro__ + case INT_IDN_FIREWALL: + hwt = &hardwall_types[HARDWALL_IDN]; + break; +#endif + case INT_UDN_FIREWALL: + hwt = &hardwall_types[HARDWALL_UDN]; + break; + default: + BUG(); + } + BUG_ON(hwt->disabled); + /* This tile trapped a network access; find the rectangle. */ - x = cpu % smp_width; - y = cpu / smp_width; - spin_lock_irqsave(&hardwall_lock, flags); - list_for_each_entry(rect, &rectangles, list) { - if (contains(rect, x, y)) + spin_lock_irqsave(&hwt->lock, flags); + list_for_each_entry(rect, &hwt->list, list) { + if (cpumask_test_cpu(cpu, &rect->cpumask)) break; } /* * It shouldn't be possible not to find this cpu on the * rectangle list, since only cpus in rectangles get hardwalled. - * The hardwall is only removed after the UDN is drained. + * The hardwall is only removed after the user network is drained. */ - BUG_ON(&rect->list == &rectangles); + BUG_ON(&rect->list == &hwt->list); /* * If we already started teardown on this hardwall, don't worry; @@ -255,30 +365,32 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) * to quiesce. */ if (rect->teardown_in_progress) { - pr_notice("cpu %d: detected hardwall violation %#lx" + pr_notice("cpu %d: detected %s hardwall violation %#lx" " while teardown already in progress\n", - cpu, (long) __insn_mfspr(SPR_UDN_DIRECTION_PROTECT)); + cpu, hwt->name, + (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); goto done; } /* * Kill off any process that is activated in this rectangle. * We bypass security to deliver the signal, since it must be - * one of the activated processes that generated the UDN + * one of the activated processes that generated the user network * message that caused this trap, and all the activated * processes shared a single open file so are pretty tightly * bound together from a security point of view to begin with. */ rect->teardown_in_progress = 1; wmb(); /* Ensure visibility of rectangle before notifying processes. */ - pr_notice("cpu %d: detected hardwall violation %#lx...\n", - cpu, (long) __insn_mfspr(SPR_UDN_DIRECTION_PROTECT)); + pr_notice("cpu %d: detected %s hardwall violation %#lx...\n", + cpu, hwt->name, (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_HARDWALL; found_processes = 0; - list_for_each_entry(p, &rect->task_head, thread.hardwall_list) { - BUG_ON(p->thread.hardwall != rect); + list_for_each_entry(p, &rect->task_head, + thread.hardwall[hwt->index].list) { + BUG_ON(p->thread.hardwall[hwt->index].info != rect); if (!(p->flags & PF_EXITING)) { found_processes = 1; pr_notice("hardwall: killing %d\n", p->pid); @@ -289,7 +401,7 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) pr_notice("hardwall: no associated processes!\n"); done: - spin_unlock_irqrestore(&hardwall_lock, flags); + spin_unlock_irqrestore(&hwt->lock, flags); /* * We have to disable firewall interrupts now, or else when we @@ -298,48 +410,87 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) * haven't yet drained the network, and that would allow packets * to cross out of the hardwall region. */ - disable_firewall_interrupts(); + disable_firewall_interrupts(hwt); irq_exit(); set_irq_regs(old_regs); } -/* Allow access from user space to the UDN. */ -void grant_network_mpls(void) +/* Allow access from user space to the user network. */ +void grant_hardwall_mpls(struct hardwall_type *hwt) { - __insn_mtspr(SPR_MPL_UDN_ACCESS_SET_0, 1); - __insn_mtspr(SPR_MPL_UDN_AVAIL_SET_0, 1); - __insn_mtspr(SPR_MPL_UDN_COMPLETE_SET_0, 1); - __insn_mtspr(SPR_MPL_UDN_TIMER_SET_0, 1); +#ifndef __tilepro__ + if (!hwt->is_xdn) { + __insn_mtspr(SPR_MPL_IPI_0_SET_0, 1); + return; + } +#endif + mtspr_MPL_XDN(hwt, ACCESS_SET_0, 1); + mtspr_MPL_XDN(hwt, AVAIL_SET_0, 1); + mtspr_MPL_XDN(hwt, COMPLETE_SET_0, 1); + mtspr_MPL_XDN(hwt, TIMER_SET_0, 1); #if !CHIP_HAS_REV1_XDN() - __insn_mtspr(SPR_MPL_UDN_REFILL_SET_0, 1); - __insn_mtspr(SPR_MPL_UDN_CA_SET_0, 1); + mtspr_MPL_XDN(hwt, REFILL_SET_0, 1); + mtspr_MPL_XDN(hwt, CA_SET_0, 1); #endif } -/* Deny access from user space to the UDN. */ -void restrict_network_mpls(void) +/* Deny access from user space to the user network. */ +void restrict_hardwall_mpls(struct hardwall_type *hwt) { - __insn_mtspr(SPR_MPL_UDN_ACCESS_SET_1, 1); - __insn_mtspr(SPR_MPL_UDN_AVAIL_SET_1, 1); - __insn_mtspr(SPR_MPL_UDN_COMPLETE_SET_1, 1); - __insn_mtspr(SPR_MPL_UDN_TIMER_SET_1, 1); +#ifndef __tilepro__ + if (!hwt->is_xdn) { + __insn_mtspr(SPR_MPL_IPI_0_SET_1, 1); + return; + } +#endif + mtspr_MPL_XDN(hwt, ACCESS_SET_1, 1); + mtspr_MPL_XDN(hwt, AVAIL_SET_1, 1); + mtspr_MPL_XDN(hwt, COMPLETE_SET_1, 1); + mtspr_MPL_XDN(hwt, TIMER_SET_1, 1); #if !CHIP_HAS_REV1_XDN() - __insn_mtspr(SPR_MPL_UDN_REFILL_SET_1, 1); - __insn_mtspr(SPR_MPL_UDN_CA_SET_1, 1); + mtspr_MPL_XDN(hwt, REFILL_SET_1, 1); + mtspr_MPL_XDN(hwt, CA_SET_1, 1); #endif } +/* Restrict or deny as necessary for the task we're switching to. */ +void hardwall_switch_tasks(struct task_struct *prev, + struct task_struct *next) +{ + int i; + for (i = 0; i < HARDWALL_TYPES; ++i) { + if (prev->thread.hardwall[i].info != NULL) { + if (next->thread.hardwall[i].info == NULL) + restrict_hardwall_mpls(&hardwall_types[i]); + } else if (next->thread.hardwall[i].info != NULL) { + grant_hardwall_mpls(&hardwall_types[i]); + } + } +} + +/* Does this task have the right to IPI the given cpu? */ +int hardwall_ipi_valid(int cpu) +{ +#ifdef __tilegx__ + struct hardwall_info *info = + current->thread.hardwall[HARDWALL_IPI].info; + return info && cpumask_test_cpu(cpu, &info->cpumask); +#else + return 0; +#endif +} /* - * Code to create, activate, deactivate, and destroy hardwall rectangles. + * Code to create, activate, deactivate, and destroy hardwall resources. */ -/* Create a hardwall for the given rectangle */ -static struct hardwall_info *hardwall_create( - size_t size, const unsigned char __user *bits) +/* Create a hardwall for the given resource */ +static struct hardwall_info *hardwall_create(struct hardwall_type *hwt, + size_t size, + const unsigned char __user *bits) { - struct hardwall_info *iter, *rect; + struct hardwall_info *iter, *info; struct cpumask mask; unsigned long flags; int rc; @@ -370,55 +521,62 @@ static struct hardwall_info *hardwall_create( } } - /* Allocate a new rectangle optimistically. */ - rect = kmalloc(sizeof(struct hardwall_info), + /* Allocate a new hardwall_info optimistically. */ + info = kmalloc(sizeof(struct hardwall_info), GFP_KERNEL | __GFP_ZERO); - if (rect == NULL) + if (info == NULL) return ERR_PTR(-ENOMEM); - INIT_LIST_HEAD(&rect->task_head); + INIT_LIST_HEAD(&info->task_head); + info->type = hwt; /* Compute the rectangle size and validate that it's plausible. */ - rc = setup_rectangle(rect, &mask); - if (rc != 0) { - kfree(rect); - return ERR_PTR(rc); + cpumask_copy(&info->cpumask, &mask); + info->id = find_first_bit(cpumask_bits(&mask), nr_cpumask_bits); + if (hwt->is_xdn) { + rc = check_rectangle(info, &mask); + if (rc != 0) { + kfree(info); + return ERR_PTR(rc); + } } /* Confirm it doesn't overlap and add it to the list. */ - spin_lock_irqsave(&hardwall_lock, flags); - list_for_each_entry(iter, &rectangles, list) { - if (overlaps(iter, rect)) { - spin_unlock_irqrestore(&hardwall_lock, flags); - kfree(rect); + spin_lock_irqsave(&hwt->lock, flags); + list_for_each_entry(iter, &hwt->list, list) { + if (cpumask_intersects(&iter->cpumask, &info->cpumask)) { + spin_unlock_irqrestore(&hwt->lock, flags); + kfree(info); return ERR_PTR(-EBUSY); } } - list_add_tail(&rect->list, &rectangles); - spin_unlock_irqrestore(&hardwall_lock, flags); + list_add_tail(&info->list, &hwt->list); + spin_unlock_irqrestore(&hwt->lock, flags); /* Set up appropriate hardwalling on all affected cpus. */ - hardwall_setup(rect); + if (hwt->is_xdn) + hardwall_protect_rectangle(info); /* Create a /proc/tile/hardwall entry. */ - hardwall_add_proc(rect); + hardwall_add_proc(info); - return rect; + return info; } /* Activate a given hardwall on this cpu for this process. */ -static int hardwall_activate(struct hardwall_info *rect) +static int hardwall_activate(struct hardwall_info *info) { - int cpu, x, y; + int cpu; unsigned long flags; struct task_struct *p = current; struct thread_struct *ts = &p->thread; + struct hardwall_type *hwt; - /* Require a rectangle. */ - if (rect == NULL) + /* Require a hardwall. */ + if (info == NULL) return -ENODATA; - /* Not allowed to activate a rectangle that is being torn down. */ - if (rect->teardown_in_progress) + /* Not allowed to activate a hardwall that is being torn down. */ + if (info->teardown_in_progress) return -EINVAL; /* @@ -428,78 +586,87 @@ static int hardwall_activate(struct hardwall_info *rect) if (cpumask_weight(&p->cpus_allowed) != 1) return -EPERM; - /* Make sure we are bound to a cpu in this rectangle. */ + /* Make sure we are bound to a cpu assigned to this resource. */ cpu = smp_processor_id(); BUG_ON(cpumask_first(&p->cpus_allowed) != cpu); - x = cpu_x(cpu); - y = cpu_y(cpu); - if (!contains(rect, x, y)) + if (!cpumask_test_cpu(cpu, &info->cpumask)) return -EINVAL; /* If we are already bound to this hardwall, it's a no-op. */ - if (ts->hardwall) { - BUG_ON(ts->hardwall != rect); + hwt = info->type; + if (ts->hardwall[hwt->index].info) { + BUG_ON(ts->hardwall[hwt->index].info != info); return 0; } - /* Success! This process gets to use the user networks on this cpu. */ - ts->hardwall = rect; - spin_lock_irqsave(&hardwall_lock, flags); - list_add(&ts->hardwall_list, &rect->task_head); - spin_unlock_irqrestore(&hardwall_lock, flags); - grant_network_mpls(); - printk(KERN_DEBUG "Pid %d (%s) activated for hardwall: cpu %d\n", - p->pid, p->comm, cpu); + /* Success! This process gets to use the resource on this cpu. */ + ts->hardwall[hwt->index].info = info; + spin_lock_irqsave(&hwt->lock, flags); + list_add(&ts->hardwall[hwt->index].list, &info->task_head); + spin_unlock_irqrestore(&hwt->lock, flags); + grant_hardwall_mpls(hwt); + printk(KERN_DEBUG "Pid %d (%s) activated for %s hardwall: cpu %d\n", + p->pid, p->comm, hwt->name, cpu); return 0; } /* - * Deactivate a task's hardwall. Must hold hardwall_lock. + * Deactivate a task's hardwall. Must hold lock for hardwall_type. * This method may be called from free_task(), so we don't want to * rely on too many fields of struct task_struct still being valid. * We assume the cpus_allowed, pid, and comm fields are still valid. */ -static void _hardwall_deactivate(struct task_struct *task) +static void _hardwall_deactivate(struct hardwall_type *hwt, + struct task_struct *task) { struct thread_struct *ts = &task->thread; if (cpumask_weight(&task->cpus_allowed) != 1) { - pr_err("pid %d (%s) releasing networks with" + pr_err("pid %d (%s) releasing %s hardwall with" " an affinity mask containing %d cpus!\n", - task->pid, task->comm, + task->pid, task->comm, hwt->name, cpumask_weight(&task->cpus_allowed)); BUG(); } - BUG_ON(ts->hardwall == NULL); - ts->hardwall = NULL; - list_del(&ts->hardwall_list); + BUG_ON(ts->hardwall[hwt->index].info == NULL); + ts->hardwall[hwt->index].info = NULL; + list_del(&ts->hardwall[hwt->index].list); if (task == current) - restrict_network_mpls(); + restrict_hardwall_mpls(hwt); } /* Deactivate a task's hardwall. */ -int hardwall_deactivate(struct task_struct *task) +static int hardwall_deactivate(struct hardwall_type *hwt, + struct task_struct *task) { unsigned long flags; int activated; - spin_lock_irqsave(&hardwall_lock, flags); - activated = (task->thread.hardwall != NULL); + spin_lock_irqsave(&hwt->lock, flags); + activated = (task->thread.hardwall[hwt->index].info != NULL); if (activated) - _hardwall_deactivate(task); - spin_unlock_irqrestore(&hardwall_lock, flags); + _hardwall_deactivate(hwt, task); + spin_unlock_irqrestore(&hwt->lock, flags); if (!activated) return -EINVAL; - printk(KERN_DEBUG "Pid %d (%s) deactivated for hardwall: cpu %d\n", - task->pid, task->comm, smp_processor_id()); + printk(KERN_DEBUG "Pid %d (%s) deactivated for %s hardwall: cpu %d\n", + task->pid, task->comm, hwt->name, smp_processor_id()); return 0; } -/* Stop a UDN switch before draining the network. */ -static void stop_udn_switch(void *ignored) +void hardwall_deactivate_all(struct task_struct *task) +{ + int i; + for (i = 0; i < HARDWALL_TYPES; ++i) + if (task->thread.hardwall[i].info) + hardwall_deactivate(&hardwall_types[i], task); +} + +/* Stop the switch before draining the network. */ +static void stop_xdn_switch(void *arg) { #if !CHIP_HAS_REV1_XDN() /* Freeze the switch and the demux. */ @@ -507,13 +674,71 @@ static void stop_udn_switch(void *ignored) SPR_UDN_SP_FREEZE__SP_FRZ_MASK | SPR_UDN_SP_FREEZE__DEMUX_FRZ_MASK | SPR_UDN_SP_FREEZE__NON_DEST_EXT_MASK); +#else + /* + * Drop all packets bound for the core or off the edge. + * We rely on the normal hardwall protection setup code + * to have set the low four bits to trigger firewall interrupts, + * and shift those bits up to trigger "drop on send" semantics, + * plus adding "drop on send to core" for all switches. + * In practice it seems the switches latch the DIRECTION_PROTECT + * SPR so they won't start dropping if they're already + * delivering the last message to the core, but it doesn't + * hurt to enable it here. + */ + struct hardwall_type *hwt = arg; + unsigned long protect = mfspr_XDN(hwt, DIRECTION_PROTECT); + mtspr_XDN(hwt, DIRECTION_PROTECT, (protect | C_PROTECT) << 5); #endif } +static void empty_xdn_demuxes(struct hardwall_type *hwt) +{ +#ifndef __tilepro__ + if (hwt->is_idn) { + while (__insn_mfspr(SPR_IDN_DATA_AVAIL) & (1 << 0)) + (void) __tile_idn0_receive(); + while (__insn_mfspr(SPR_IDN_DATA_AVAIL) & (1 << 1)) + (void) __tile_idn1_receive(); + return; + } +#endif + while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 0)) + (void) __tile_udn0_receive(); + while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 1)) + (void) __tile_udn1_receive(); + while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 2)) + (void) __tile_udn2_receive(); + while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 3)) + (void) __tile_udn3_receive(); +} + /* Drain all the state from a stopped switch. */ -static void drain_udn_switch(void *ignored) +static void drain_xdn_switch(void *arg) { -#if !CHIP_HAS_REV1_XDN() + struct hardwall_info *info = arg; + struct hardwall_type *hwt = info->type; + +#if CHIP_HAS_REV1_XDN() + /* + * The switches have been configured to drop any messages + * destined for cores (or off the edge of the rectangle). + * But the current message may continue to be delivered, + * so we wait until all the cores have finished any pending + * messages before we stop draining. + */ + int pending = mfspr_XDN(hwt, PENDING); + while (pending--) { + empty_xdn_demuxes(hwt); + if (hwt->is_idn) + __tile_idn_send(0); + else + __tile_udn_send(0); + } + atomic_dec(&info->xdn_pending_count); + while (atomic_read(&info->xdn_pending_count)) + empty_xdn_demuxes(hwt); +#else int i; int from_tile_words, ca_count; @@ -533,15 +758,7 @@ static void drain_udn_switch(void *ignored) (void) __insn_mfspr(SPR_UDN_DEMUX_WRITE_FIFO); /* Empty out demuxes. */ - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 0)) - (void) __tile_udn0_receive(); - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 1)) - (void) __tile_udn1_receive(); - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 2)) - (void) __tile_udn2_receive(); - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 3)) - (void) __tile_udn3_receive(); - BUG_ON((__insn_mfspr(SPR_UDN_DATA_AVAIL) & 0xF) != 0); + empty_xdn_demuxes(hwt); /* Empty out catch all. */ ca_count = __insn_mfspr(SPR_UDN_DEMUX_CA_COUNT); @@ -563,21 +780,25 @@ static void drain_udn_switch(void *ignored) #endif } -/* Reset random UDN state registers at boot up and during hardwall teardown. */ -void reset_network_state(void) +/* Reset random XDN state registers at boot up and during hardwall teardown. */ +static void reset_xdn_network_state(struct hardwall_type *hwt) { -#if !CHIP_HAS_REV1_XDN() - /* Reset UDN coordinates to their standard value */ - unsigned int cpu = smp_processor_id(); - unsigned int x = cpu % smp_width; - unsigned int y = cpu / smp_width; -#endif - - if (udn_disabled) + if (hwt->disabled) return; + /* Clear out other random registers so we have a clean slate. */ + mtspr_XDN(hwt, DIRECTION_PROTECT, 0); + mtspr_XDN(hwt, AVAIL_EN, 0); + mtspr_XDN(hwt, DEADLOCK_TIMEOUT, 0); + #if !CHIP_HAS_REV1_XDN() - __insn_mtspr(SPR_UDN_TILE_COORD, (x << 18) | (y << 7)); + /* Reset UDN coordinates to their standard value */ + { + unsigned int cpu = smp_processor_id(); + unsigned int x = cpu % smp_width; + unsigned int y = cpu / smp_width; + __insn_mtspr(SPR_UDN_TILE_COORD, (x << 18) | (y << 7)); + } /* Set demux tags to predefined values and enable them. */ __insn_mtspr(SPR_UDN_TAG_VALID, 0xf); @@ -585,56 +806,50 @@ void reset_network_state(void) __insn_mtspr(SPR_UDN_TAG_1, (1 << 1)); __insn_mtspr(SPR_UDN_TAG_2, (1 << 2)); __insn_mtspr(SPR_UDN_TAG_3, (1 << 3)); -#endif - /* Clear out other random registers so we have a clean slate. */ - __insn_mtspr(SPR_UDN_AVAIL_EN, 0); - __insn_mtspr(SPR_UDN_DEADLOCK_TIMEOUT, 0); -#if !CHIP_HAS_REV1_XDN() + /* Set other rev0 random registers to a clean state. */ __insn_mtspr(SPR_UDN_REFILL_EN, 0); __insn_mtspr(SPR_UDN_DEMUX_QUEUE_SEL, 0); __insn_mtspr(SPR_UDN_SP_FIFO_SEL, 0); -#endif /* Start the switch and demux. */ -#if !CHIP_HAS_REV1_XDN() __insn_mtspr(SPR_UDN_SP_FREEZE, 0); #endif } -/* Restart a UDN switch after draining. */ -static void restart_udn_switch(void *ignored) +void reset_network_state(void) { - reset_network_state(); - - /* Disable firewall interrupts. */ - __insn_mtspr(SPR_UDN_DIRECTION_PROTECT, 0); - disable_firewall_interrupts(); + reset_xdn_network_state(&hardwall_types[HARDWALL_UDN]); +#ifndef __tilepro__ + reset_xdn_network_state(&hardwall_types[HARDWALL_IDN]); +#endif } -/* Build a struct cpumask containing all valid tiles in bounding rectangle. */ -static void fill_mask(struct hardwall_info *r, struct cpumask *result) +/* Restart an XDN switch after draining. */ +static void restart_xdn_switch(void *arg) { - int x, y, cpu; + struct hardwall_type *hwt = arg; - cpumask_clear(result); +#if CHIP_HAS_REV1_XDN() + /* One last drain step to avoid races with injection and draining. */ + empty_xdn_demuxes(hwt); +#endif - cpu = r->ulhc_y * smp_width + r->ulhc_x; - for (y = 0; y < r->height; ++y, cpu += smp_width - r->width) { - for (x = 0; x < r->width; ++x, ++cpu) - cpu_online_set(cpu, result); - } + reset_xdn_network_state(hwt); + + /* Disable firewall interrupts. */ + disable_firewall_interrupts(hwt); } /* Last reference to a hardwall is gone, so clear the network. */ -static void hardwall_destroy(struct hardwall_info *rect) +static void hardwall_destroy(struct hardwall_info *info) { struct task_struct *task; + struct hardwall_type *hwt; unsigned long flags; - struct cpumask mask; - /* Make sure this file actually represents a rectangle. */ - if (rect == NULL) + /* Make sure this file actually represents a hardwall. */ + if (info == NULL) return; /* @@ -644,39 +859,53 @@ static void hardwall_destroy(struct hardwall_info *rect) * deactivate any remaining tasks before freeing the * hardwall_info object itself. */ - spin_lock_irqsave(&hardwall_lock, flags); - list_for_each_entry(task, &rect->task_head, thread.hardwall_list) - _hardwall_deactivate(task); - spin_unlock_irqrestore(&hardwall_lock, flags); - - /* Drain the UDN. */ - printk(KERN_DEBUG "Clearing hardwall rectangle %dx%d %d,%d\n", - rect->width, rect->height, rect->ulhc_x, rect->ulhc_y); - fill_mask(rect, &mask); - on_each_cpu_mask(&mask, stop_udn_switch, NULL, 1); - on_each_cpu_mask(&mask, drain_udn_switch, NULL, 1); + hwt = info->type; + info->teardown_in_progress = 1; + spin_lock_irqsave(&hwt->lock, flags); + list_for_each_entry(task, &info->task_head, + thread.hardwall[hwt->index].list) + _hardwall_deactivate(hwt, task); + spin_unlock_irqrestore(&hwt->lock, flags); + + if (hwt->is_xdn) { + /* Configure the switches for draining the user network. */ + printk(KERN_DEBUG + "Clearing %s hardwall rectangle %dx%d %d,%d\n", + hwt->name, info->width, info->height, + info->ulhc_x, info->ulhc_y); + on_each_cpu_mask(&info->cpumask, stop_xdn_switch, hwt, 1); + + /* Drain the network. */ +#if CHIP_HAS_REV1_XDN() + atomic_set(&info->xdn_pending_count, + cpumask_weight(&info->cpumask)); + on_each_cpu_mask(&info->cpumask, drain_xdn_switch, info, 0); +#else + on_each_cpu_mask(&info->cpumask, drain_xdn_switch, info, 1); +#endif - /* Restart switch and disable firewall. */ - on_each_cpu_mask(&mask, restart_udn_switch, NULL, 1); + /* Restart switch and disable firewall. */ + on_each_cpu_mask(&info->cpumask, restart_xdn_switch, hwt, 1); + } /* Remove the /proc/tile/hardwall entry. */ - hardwall_remove_proc(rect); - - /* Now free the rectangle from the list. */ - spin_lock_irqsave(&hardwall_lock, flags); - BUG_ON(!list_empty(&rect->task_head)); - list_del(&rect->list); - spin_unlock_irqrestore(&hardwall_lock, flags); - kfree(rect); + hardwall_remove_proc(info); + + /* Now free the hardwall from the list. */ + spin_lock_irqsave(&hwt->lock, flags); + BUG_ON(!list_empty(&info->task_head)); + list_del(&info->list); + spin_unlock_irqrestore(&hwt->lock, flags); + kfree(info); } static int hardwall_proc_show(struct seq_file *sf, void *v) { - struct hardwall_info *rect = sf->private; + struct hardwall_info *info = sf->private; char buf[256]; - int rc = cpulist_scnprintf(buf, sizeof(buf), &rect->cpumask); + int rc = cpulist_scnprintf(buf, sizeof(buf), &info->cpumask); buf[rc++] = '\n'; seq_write(sf, buf, rc); return 0; @@ -695,31 +924,45 @@ static const struct file_operations hardwall_proc_fops = { .release = single_release, }; -static void hardwall_add_proc(struct hardwall_info *rect) +static void hardwall_add_proc(struct hardwall_info *info) { char buf[64]; - snprintf(buf, sizeof(buf), "%d", rect->id); - proc_create_data(buf, 0444, hardwall_proc_dir, - &hardwall_proc_fops, rect); + snprintf(buf, sizeof(buf), "%d", info->id); + proc_create_data(buf, 0444, info->type->proc_dir, + &hardwall_proc_fops, info); } -static void hardwall_remove_proc(struct hardwall_info *rect) +static void hardwall_remove_proc(struct hardwall_info *info) { char buf[64]; - snprintf(buf, sizeof(buf), "%d", rect->id); - remove_proc_entry(buf, hardwall_proc_dir); + snprintf(buf, sizeof(buf), "%d", info->id); + remove_proc_entry(buf, info->type->proc_dir); } int proc_pid_hardwall(struct task_struct *task, char *buffer) { - struct hardwall_info *rect = task->thread.hardwall; - return rect ? sprintf(buffer, "%d\n", rect->id) : 0; + int i; + int n = 0; + for (i = 0; i < HARDWALL_TYPES; ++i) { + struct hardwall_info *info = task->thread.hardwall[i].info; + if (info) + n += sprintf(&buffer[n], "%s: %d\n", + info->type->name, info->id); + } + return n; } void proc_tile_hardwall_init(struct proc_dir_entry *root) { - if (!udn_disabled) - hardwall_proc_dir = proc_mkdir("hardwall", root); + int i; + for (i = 0; i < HARDWALL_TYPES; ++i) { + struct hardwall_type *hwt = &hardwall_types[i]; + if (hwt->disabled) + continue; + if (hardwall_proc_dir == NULL) + hardwall_proc_dir = proc_mkdir("hardwall", root); + hwt->proc_dir = proc_mkdir(hwt->name, hardwall_proc_dir); + } } @@ -729,34 +972,45 @@ void proc_tile_hardwall_init(struct proc_dir_entry *root) static long hardwall_ioctl(struct file *file, unsigned int a, unsigned long b) { - struct hardwall_info *rect = file->private_data; + struct hardwall_info *info = file->private_data; + int minor = iminor(file->f_mapping->host); + struct hardwall_type* hwt; if (_IOC_TYPE(a) != HARDWALL_IOCTL_BASE) return -EINVAL; + BUILD_BUG_ON(HARDWALL_TYPES != _HARDWALL_TYPES); + BUILD_BUG_ON(HARDWALL_TYPES != + sizeof(hardwall_types)/sizeof(hardwall_types[0])); + + if (minor < 0 || minor >= HARDWALL_TYPES) + return -EINVAL; + hwt = &hardwall_types[minor]; + WARN_ON(info && hwt != info->type); + switch (_IOC_NR(a)) { case _HARDWALL_CREATE: - if (udn_disabled) + if (hwt->disabled) return -ENOSYS; - if (rect != NULL) + if (info != NULL) return -EALREADY; - rect = hardwall_create(_IOC_SIZE(a), - (const unsigned char __user *)b); - if (IS_ERR(rect)) - return PTR_ERR(rect); - file->private_data = rect; + info = hardwall_create(hwt, _IOC_SIZE(a), + (const unsigned char __user *)b); + if (IS_ERR(info)) + return PTR_ERR(info); + file->private_data = info; return 0; case _HARDWALL_ACTIVATE: - return hardwall_activate(rect); + return hardwall_activate(info); case _HARDWALL_DEACTIVATE: - if (current->thread.hardwall != rect) + if (current->thread.hardwall[hwt->index].info != info) return -EINVAL; - return hardwall_deactivate(current); + return hardwall_deactivate(hwt, current); case _HARDWALL_GET_ID: - return rect ? rect->id : -EINVAL; + return info ? info->id : -EINVAL; default: return -EINVAL; @@ -775,26 +1029,28 @@ static long hardwall_compat_ioctl(struct file *file, /* The user process closed the file; revoke access to user networks. */ static int hardwall_flush(struct file *file, fl_owner_t owner) { - struct hardwall_info *rect = file->private_data; + struct hardwall_info *info = file->private_data; struct task_struct *task, *tmp; unsigned long flags; - if (rect) { + if (info) { /* * NOTE: if multiple threads are activated on this hardwall * file, the other threads will continue having access to the - * UDN until they are context-switched out and back in again. + * user network until they are context-switched out and back + * in again. * * NOTE: A NULL files pointer means the task is being torn * down, so in that case we also deactivate it. */ - spin_lock_irqsave(&hardwall_lock, flags); - list_for_each_entry_safe(task, tmp, &rect->task_head, - thread.hardwall_list) { + struct hardwall_type *hwt = info->type; + spin_lock_irqsave(&hwt->lock, flags); + list_for_each_entry_safe(task, tmp, &info->task_head, + thread.hardwall[hwt->index].list) { if (task->files == owner || task->files == NULL) - _hardwall_deactivate(task); + _hardwall_deactivate(hwt, task); } - spin_unlock_irqrestore(&hardwall_lock, flags); + spin_unlock_irqrestore(&hwt->lock, flags); } return 0; @@ -824,11 +1080,11 @@ static int __init dev_hardwall_init(void) int rc; dev_t dev; - rc = alloc_chrdev_region(&dev, 0, 1, "hardwall"); + rc = alloc_chrdev_region(&dev, 0, HARDWALL_TYPES, "hardwall"); if (rc < 0) return rc; cdev_init(&hardwall_dev, &dev_hardwall_fops); - rc = cdev_add(&hardwall_dev, dev, 1); + rc = cdev_add(&hardwall_dev, dev, HARDWALL_TYPES); if (rc < 0) return rc; diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S index 1a39b7c1c87e..f71bfeeaf1a9 100644 --- a/arch/tile/kernel/head_32.S +++ b/arch/tile/kernel/head_32.S @@ -69,7 +69,7 @@ ENTRY(_start) } { moveli lr, lo16(1f) - move r5, zero + moveli r5, CTX_PAGE_FLAG } { auli lr, lr, ha16(1f) @@ -141,11 +141,11 @@ ENTRY(empty_zero_page) .macro PTE va, cpa, bits1, no_org=0 .ifeq \no_org - .org swapper_pg_dir + HV_L1_INDEX(\va) * HV_PTE_SIZE + .org swapper_pg_dir + PGD_INDEX(\va) * HV_PTE_SIZE .endif .word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \ (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) - .word (\bits1) | (HV_CPA_TO_PFN(\cpa) << (HV_PTE_INDEX_PFN - 32)) + .word (\bits1) | (HV_CPA_TO_PTFN(\cpa) << (HV_PTE_INDEX_PTFN - 32)) .endm __PAGE_ALIGNED_DATA @@ -166,7 +166,7 @@ ENTRY(swapper_pg_dir) /* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */ PTE MEM_SV_INTRPT, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \ (1 << (HV_PTE_INDEX_EXECUTABLE - 32)) - .org swapper_pg_dir + HV_L1_SIZE + .org swapper_pg_dir + PGDIR_SIZE END(swapper_pg_dir) /* diff --git a/arch/tile/kernel/head_64.S b/arch/tile/kernel/head_64.S index 6bc3a932fe45..f9a2734f7b82 100644 --- a/arch/tile/kernel/head_64.S +++ b/arch/tile/kernel/head_64.S @@ -114,7 +114,7 @@ ENTRY(_start) shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET) } { - move r3, zero + moveli r3, CTX_PAGE_FLAG j hv_install_context } 1: @@ -210,19 +210,19 @@ ENTRY(empty_zero_page) .macro PTE cpa, bits1 .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\ HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\ - (\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN) + (\bits1) | (HV_CPA_TO_PTFN(\cpa) << HV_PTE_INDEX_PTFN) .endm __PAGE_ALIGNED_DATA .align PAGE_SIZE ENTRY(swapper_pg_dir) - .org swapper_pg_dir + HV_L0_INDEX(PAGE_OFFSET) * HV_PTE_SIZE + .org swapper_pg_dir + PGD_INDEX(PAGE_OFFSET) * HV_PTE_SIZE .Lsv_data_pmd: .quad 0 /* PTE temp_data_pmd - PAGE_OFFSET, 0 */ - .org swapper_pg_dir + HV_L0_INDEX(MEM_SV_START) * HV_PTE_SIZE + .org swapper_pg_dir + PGD_INDEX(MEM_SV_START) * HV_PTE_SIZE .Lsv_code_pmd: .quad 0 /* PTE temp_code_pmd - PAGE_OFFSET, 0 */ - .org swapper_pg_dir + HV_L0_SIZE + .org swapper_pg_dir + SIZEOF_PGD END(swapper_pg_dir) .align HV_PAGE_TABLE_ALIGN @@ -233,11 +233,11 @@ ENTRY(temp_data_pmd) * permissions later. */ .set addr, 0 - .rept HV_L1_ENTRIES + .rept PTRS_PER_PMD PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE - .set addr, addr + HV_PAGE_SIZE_LARGE + .set addr, addr + HPAGE_SIZE .endr - .org temp_data_pmd + HV_L1_SIZE + .org temp_data_pmd + SIZEOF_PMD END(temp_data_pmd) .align HV_PAGE_TABLE_ALIGN @@ -248,11 +248,11 @@ ENTRY(temp_code_pmd) * permissions later. */ .set addr, 0 - .rept HV_L1_ENTRIES + .rept PTRS_PER_PMD PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE - .set addr, addr + HV_PAGE_SIZE_LARGE + .set addr, addr + HPAGE_SIZE .endr - .org temp_code_pmd + HV_L1_SIZE + .org temp_code_pmd + SIZEOF_PMD END(temp_code_pmd) /* diff --git a/arch/tile/kernel/hvglue.lds b/arch/tile/kernel/hvglue.lds index 2b7cd0a659a9..d44c5a67a1ed 100644 --- a/arch/tile/kernel/hvglue.lds +++ b/arch/tile/kernel/hvglue.lds @@ -55,4 +55,5 @@ hv_store_mapping = TEXT_OFFSET + 0x106a0; hv_inquire_realpa = TEXT_OFFSET + 0x106c0; hv_flush_all = TEXT_OFFSET + 0x106e0; hv_get_ipi_pte = TEXT_OFFSET + 0x10700; -hv_glue_internals = TEXT_OFFSET + 0x10720; +hv_set_pte_super_shift = TEXT_OFFSET + 0x10720; +hv_glue_internals = TEXT_OFFSET + 0x10740; diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 30ae76e50c44..7c06d597ffd0 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S @@ -220,7 +220,9 @@ intvec_\vecname: * This routine saves just the first four registers, plus the * stack context so we can do proper backtracing right away, * and defers to handle_interrupt to save the rest. - * The backtracer needs pc, ex1, lr, sp, r52, and faultnum. + * The backtracer needs pc, ex1, lr, sp, r52, and faultnum, + * and needs sp set to its final location at the bottom of + * the stack frame. */ addli r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP) wh64 r0 /* cache line 7 */ @@ -450,23 +452,6 @@ intvec_\vecname: push_reg r5, r52 st r52, r4 - /* Load tp with our per-cpu offset. */ -#ifdef CONFIG_SMP - { - mfspr r20, SPR_SYSTEM_SAVE_K_0 - moveli r21, hw2_last(__per_cpu_offset) - } - { - shl16insli r21, r21, hw1(__per_cpu_offset) - bfextu r20, r20, 0, LOG2_THREAD_SIZE-1 - } - shl16insli r21, r21, hw0(__per_cpu_offset) - shl3add r20, r20, r21 - ld tp, r20 -#else - move tp, zero -#endif - /* * If we will be returning to the kernel, we will need to * reset the interrupt masks to the state they had before. @@ -489,6 +474,44 @@ intvec_\vecname: .endif st r21, r32 + /* + * we've captured enough state to the stack (including in + * particular our EX_CONTEXT state) that we can now release + * the interrupt critical section and replace it with our + * standard "interrupts disabled" mask value. This allows + * synchronous interrupts (and profile interrupts) to punch + * through from this point onwards. + * + * It's important that no code before this point touch memory + * other than our own stack (to keep the invariant that this + * is all that gets touched under ICS), and that no code after + * this point reference any interrupt-specific SPR, in particular + * the EX_CONTEXT_K_ values. + */ + .ifc \function,handle_nmi + IRQ_DISABLE_ALL(r20) + .else + IRQ_DISABLE(r20, r21) + .endif + mtspr INTERRUPT_CRITICAL_SECTION, zero + + /* Load tp with our per-cpu offset. */ +#ifdef CONFIG_SMP + { + mfspr r20, SPR_SYSTEM_SAVE_K_0 + moveli r21, hw2_last(__per_cpu_offset) + } + { + shl16insli r21, r21, hw1(__per_cpu_offset) + bfextu r20, r20, 0, LOG2_THREAD_SIZE-1 + } + shl16insli r21, r21, hw0(__per_cpu_offset) + shl3add r20, r20, r21 + ld tp, r20 +#else + move tp, zero +#endif + #ifdef __COLLECT_LINKER_FEEDBACK__ /* * Notify the feedback routines that we were in the @@ -513,21 +536,6 @@ intvec_\vecname: #endif /* - * we've captured enough state to the stack (including in - * particular our EX_CONTEXT state) that we can now release - * the interrupt critical section and replace it with our - * standard "interrupts disabled" mask value. This allows - * synchronous interrupts (and profile interrupts) to punch - * through from this point onwards. - */ - .ifc \function,handle_nmi - IRQ_DISABLE_ALL(r20) - .else - IRQ_DISABLE(r20, r21) - .endif - mtspr INTERRUPT_CRITICAL_SECTION, zero - - /* * Prepare the first 256 stack bytes to be rapidly accessible * without having to fetch the background data. */ @@ -736,9 +744,10 @@ STD_ENTRY(interrupt_return) beqzt r30, .Lrestore_regs j 3f 2: TRACE_IRQS_ON + IRQ_ENABLE_LOAD(r20, r21) movei r0, 1 mtspr INTERRUPT_CRITICAL_SECTION, r0 - IRQ_ENABLE(r20, r21) + IRQ_ENABLE_APPLY(r20, r21) beqzt r30, .Lrestore_regs 3: @@ -755,7 +764,6 @@ STD_ENTRY(interrupt_return) * that will save some cycles if this turns out to be a syscall. */ .Lrestore_regs: - FEEDBACK_REENTER(interrupt_return) /* called from elsewhere */ /* * Rotate so we have one high bit and one low bit to test. @@ -1249,7 +1257,7 @@ STD_ENTRY(fill_ra_stack) int_hand INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign int_hand INT_DTLB_MISS, DTLB_MISS, do_page_fault int_hand INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault - int_hand INT_IDN_FIREWALL, IDN_FIREWALL, bad_intr + int_hand INT_IDN_FIREWALL, IDN_FIREWALL, do_hardwall_trap int_hand INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap int_hand INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt int_hand INT_IDN_TIMER, IDN_TIMER, bad_intr diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c index 6255f2eab112..f0b54a934712 100644 --- a/arch/tile/kernel/machine_kexec.c +++ b/arch/tile/kernel/machine_kexec.c @@ -31,6 +31,8 @@ #include <asm/pgalloc.h> #include <asm/cacheflush.h> #include <asm/checksum.h> +#include <asm/tlbflush.h> +#include <asm/homecache.h> #include <hv/hypervisor.h> @@ -222,11 +224,22 @@ struct page *kimage_alloc_pages_arch(gfp_t gfp_mask, unsigned int order) return alloc_pages_node(0, gfp_mask, order); } +/* + * Address range in which pa=va mapping is set in setup_quasi_va_is_pa(). + * For tilepro, PAGE_OFFSET is used since this is the largest possbile value + * for tilepro, while for tilegx, we limit it to entire middle level page + * table which we assume has been allocated and is undoubtedly large enough. + */ +#ifndef __tilegx__ +#define QUASI_VA_IS_PA_ADDR_RANGE PAGE_OFFSET +#else +#define QUASI_VA_IS_PA_ADDR_RANGE PGDIR_SIZE +#endif + static void setup_quasi_va_is_pa(void) { - HV_PTE *pgtable; HV_PTE pte; - int i; + unsigned long i; /* * Flush our TLB to prevent conflicts between the previous contents @@ -234,16 +247,22 @@ static void setup_quasi_va_is_pa(void) */ local_flush_tlb_all(); - /* setup VA is PA, at least up to PAGE_OFFSET */ - - pgtable = (HV_PTE *)current->mm->pgd; + /* + * setup VA is PA, at least up to QUASI_VA_IS_PA_ADDR_RANGE. + * Note here we assume that level-1 page table is defined by + * HPAGE_SIZE. + */ pte = hv_pte(_PAGE_KERNEL | _PAGE_HUGE_PAGE); pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3); - - for (i = 0; i < pgd_index(PAGE_OFFSET); i++) { + for (i = 0; i < (QUASI_VA_IS_PA_ADDR_RANGE >> HPAGE_SHIFT); i++) { + unsigned long vaddr = i << HPAGE_SHIFT; + pgd_t *pgd = pgd_offset(current->mm, vaddr); + pud_t *pud = pud_offset(pgd, vaddr); + pte_t *ptep = (pte_t *) pmd_offset(pud, vaddr); unsigned long pfn = i << (HPAGE_SHIFT - PAGE_SHIFT); + if (pfn_valid(pfn)) - __set_pte(&pgtable[i], pfn_pte(pfn, pte)); + __set_pte(ptep, pfn_pte(pfn, pte)); } } @@ -251,6 +270,7 @@ static void setup_quasi_va_is_pa(void) void machine_kexec(struct kimage *image) { void *reboot_code_buffer; + pte_t *ptep; void (*rnk)(unsigned long, void *, unsigned long) __noreturn; @@ -266,8 +286,10 @@ void machine_kexec(struct kimage *image) */ homecache_change_page_home(image->control_code_page, 0, smp_processor_id()); - reboot_code_buffer = vmap(&image->control_code_page, 1, 0, - __pgprot(_PAGE_KERNEL | _PAGE_EXECUTABLE)); + reboot_code_buffer = page_address(image->control_code_page); + BUG_ON(reboot_code_buffer == NULL); + ptep = virt_to_pte(NULL, (unsigned long)reboot_code_buffer); + __set_pte(ptep, pte_mkexec(*ptep)); memcpy(reboot_code_buffer, relocate_new_kernel, relocate_new_kernel_size); __flush_icache_range( diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c index 98d476920106..001cbfa10ac6 100644 --- a/arch/tile/kernel/module.c +++ b/arch/tile/kernel/module.c @@ -159,7 +159,17 @@ int apply_relocate_add(Elf_Shdr *sechdrs, switch (ELF_R_TYPE(rel[i].r_info)) { -#define MUNGE(func) (*location = ((*location & ~func(-1)) | func(value))) +#ifdef __LITTLE_ENDIAN +# define MUNGE(func) \ + (*location = ((*location & ~func(-1)) | func(value))) +#else +/* + * Instructions are always little-endian, so when we read them as data, + * we have to swap them around before and after modifying them. + */ +# define MUNGE(func) \ + (*location = swab64((swab64(*location) & ~func(-1)) | func(value))) +#endif #ifndef __tilegx__ case R_TILE_32: diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c index 446a7f52cc11..dafc447b5125 100644 --- a/arch/tile/kernel/proc.c +++ b/arch/tile/kernel/proc.c @@ -22,6 +22,7 @@ #include <linux/proc_fs.h> #include <linux/sysctl.h> #include <linux/hardirq.h> +#include <linux/hugetlb.h> #include <linux/mman.h> #include <asm/unaligned.h> #include <asm/pgtable.h> diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index f572c19c4082..ba1023d8a021 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -128,10 +128,10 @@ void arch_release_thread_info(struct thread_info *info) * Calling deactivate here just frees up the data structures. * If the task we're freeing held the last reference to a * hardwall fd, it would have been released prior to this point - * anyway via exit_files(), and "hardwall" would be NULL by now. + * anyway via exit_files(), and the hardwall_task.info pointers + * would be NULL by now. */ - if (info->task->thread.hardwall) - hardwall_deactivate(info->task); + hardwall_deactivate_all(info->task); #endif if (step_state) { @@ -245,7 +245,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, #ifdef CONFIG_HARDWALL /* New thread does not own any networks. */ - p->thread.hardwall = NULL; + memset(&p->thread.hardwall[0], 0, + sizeof(struct hardwall_task) * HARDWALL_TYPES); #endif @@ -515,12 +516,7 @@ struct task_struct *__sched _switch_to(struct task_struct *prev, #ifdef CONFIG_HARDWALL /* Enable or disable access to the network registers appropriately. */ - if (prev->thread.hardwall != NULL) { - if (next->thread.hardwall == NULL) - restrict_network_mpls(); - } else if (next->thread.hardwall != NULL) { - grant_network_mpls(); - } + hardwall_switch_tasks(prev, next); #endif /* diff --git a/arch/tile/kernel/relocate_kernel.S b/arch/tile/kernel/relocate_kernel_32.S index 010b418515f8..010b418515f8 100644 --- a/arch/tile/kernel/relocate_kernel.S +++ b/arch/tile/kernel/relocate_kernel_32.S diff --git a/arch/tile/kernel/relocate_kernel_64.S b/arch/tile/kernel/relocate_kernel_64.S new file mode 100644 index 000000000000..1c09a4f5a4ea --- /dev/null +++ b/arch/tile/kernel/relocate_kernel_64.S @@ -0,0 +1,260 @@ +/* + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * copy new kernel into place and then call hv_reexec + * + */ + +#include <linux/linkage.h> +#include <arch/chip.h> +#include <asm/page.h> +#include <hv/hypervisor.h> + +#undef RELOCATE_NEW_KERNEL_VERBOSE + +STD_ENTRY(relocate_new_kernel) + + move r30, r0 /* page list */ + move r31, r1 /* address of page we are on */ + move r32, r2 /* start address of new kernel */ + + shrui r1, r1, PAGE_SHIFT + addi r1, r1, 1 + shli sp, r1, PAGE_SHIFT + addi sp, sp, -8 + /* we now have a stack (whether we need one or not) */ + + moveli r40, hw2_last(hv_console_putc) + shl16insli r40, r40, hw1(hv_console_putc) + shl16insli r40, r40, hw0(hv_console_putc) + +#ifdef RELOCATE_NEW_KERNEL_VERBOSE + moveli r0, 'r' + jalr r40 + + moveli r0, '_' + jalr r40 + + moveli r0, 'n' + jalr r40 + + moveli r0, '_' + jalr r40 + + moveli r0, 'k' + jalr r40 + + moveli r0, '\n' + jalr r40 +#endif + + /* + * Throughout this code r30 is pointer to the element of page + * list we are working on. + * + * Normally we get to the next element of the page list by + * incrementing r30 by eight. The exception is if the element + * on the page list is an IND_INDIRECTION in which case we use + * the element with the low bits masked off as the new value + * of r30. + * + * To get this started, we need the value passed to us (which + * will always be an IND_INDIRECTION) in memory somewhere with + * r30 pointing at it. To do that, we push the value passed + * to us on the stack and make r30 point to it. + */ + + st sp, r30 + move r30, sp + addi sp, sp, -16 + +#if CHIP_HAS_CBOX_HOME_MAP() + /* + * On TILE-GX, we need to flush all tiles' caches, since we may + * have been doing hash-for-home caching there. Note that we + * must do this _after_ we're completely done modifying any memory + * other than our output buffer (which we know is locally cached). + * We want the caches to be fully clean when we do the reexec, + * because the hypervisor is going to do this flush again at that + * point, and we don't want that second flush to overwrite any memory. + */ + { + move r0, zero /* cache_pa */ + moveli r1, hw2_last(HV_FLUSH_EVICT_L2) + } + { + shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2) + movei r2, -1 /* cache_cpumask; -1 means all client tiles */ + } + { + shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2) /* cache_control */ + move r3, zero /* tlb_va */ + } + { + move r4, zero /* tlb_length */ + move r5, zero /* tlb_pgsize */ + } + { + move r6, zero /* tlb_cpumask */ + move r7, zero /* asids */ + } + { + moveli r20, hw2_last(hv_flush_remote) + move r8, zero /* asidcount */ + } + shl16insli r20, r20, hw1(hv_flush_remote) + shl16insli r20, r20, hw0(hv_flush_remote) + + jalr r20 +#endif + + /* r33 is destination pointer, default to zero */ + + moveli r33, 0 + +.Lloop: ld r10, r30 + + andi r9, r10, 0xf /* low 4 bits tell us what type it is */ + xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */ + + cmpeqi r0, r9, 0x1 /* IND_DESTINATION */ + beqzt r0, .Ltry2 + + move r33, r10 + +#ifdef RELOCATE_NEW_KERNEL_VERBOSE + moveli r0, 'd' + jalr r40 +#endif + + addi r30, r30, 8 + j .Lloop + +.Ltry2: + cmpeqi r0, r9, 0x2 /* IND_INDIRECTION */ + beqzt r0, .Ltry4 + + move r30, r10 + +#ifdef RELOCATE_NEW_KERNEL_VERBOSE + moveli r0, 'i' + jalr r40 +#endif + + j .Lloop + +.Ltry4: + cmpeqi r0, r9, 0x4 /* IND_DONE */ + beqzt r0, .Ltry8 + + mf + +#ifdef RELOCATE_NEW_KERNEL_VERBOSE + moveli r0, 'D' + jalr r40 + moveli r0, '\n' + jalr r40 +#endif + + move r0, r32 + + moveli r41, hw2_last(hv_reexec) + shl16insli r41, r41, hw1(hv_reexec) + shl16insli r41, r41, hw0(hv_reexec) + + jalr r41 + + /* we should not get here */ + + moveli r0, '?' + jalr r40 + moveli r0, '\n' + jalr r40 + + j .Lhalt + +.Ltry8: cmpeqi r0, r9, 0x8 /* IND_SOURCE */ + beqz r0, .Lerr /* unknown type */ + + /* copy page at r10 to page at r33 */ + + move r11, r33 + + moveli r0, hw2_last(PAGE_SIZE) + shl16insli r0, r0, hw1(PAGE_SIZE) + shl16insli r0, r0, hw0(PAGE_SIZE) + add r33, r33, r0 + + /* copy word at r10 to word at r11 until r11 equals r33 */ + + /* We know page size must be multiple of 8, so we can unroll + * 8 times safely without any edge case checking. + * + * Issue a flush of the destination every 8 words to avoid + * incoherence when starting the new kernel. (Now this is + * just good paranoia because the hv_reexec call will also + * take care of this.) + */ + +1: + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0; addi r11, r11, 8 } + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0; addi r11, r11, 8 } + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0; addi r11, r11, 8 } + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0; addi r11, r11, 8 } + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0; addi r11, r11, 8 } + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0; addi r11, r11, 8 } + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0; addi r11, r11, 8 } + { ld r0, r10; addi r10, r10, 8 } + { st r11, r0 } + { flush r11 ; addi r11, r11, 8 } + + cmpeq r0, r33, r11 + beqzt r0, 1b + +#ifdef RELOCATE_NEW_KERNEL_VERBOSE + moveli r0, 's' + jalr r40 +#endif + + addi r30, r30, 8 + j .Lloop + + +.Lerr: moveli r0, 'e' + jalr r40 + moveli r0, 'r' + jalr r40 + moveli r0, 'r' + jalr r40 + moveli r0, '\n' + jalr r40 +.Lhalt: + moveli r41, hw2_last(hv_halt) + shl16insli r41, r41, hw1(hv_halt) + shl16insli r41, r41, hw0(hv_halt) + + jalr r41 + STD_ENDPROC(relocate_new_kernel) + + .section .rodata,"a" + + .globl relocate_new_kernel_size +relocate_new_kernel_size: + .long .Lend_relocate_new_kernel - relocate_new_kernel diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index 98d80eb49ddb..6098ccc59be2 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c @@ -28,6 +28,7 @@ #include <linux/highmem.h> #include <linux/smp.h> #include <linux/timex.h> +#include <linux/hugetlb.h> #include <asm/setup.h> #include <asm/sections.h> #include <asm/cacheflush.h> @@ -49,9 +50,6 @@ char chip_model[64] __write_once; struct pglist_data node_data[MAX_NUMNODES] __read_mostly; EXPORT_SYMBOL(node_data); -/* We only create bootmem data on node 0. */ -static bootmem_data_t __initdata node0_bdata; - /* Information on the NUMA nodes that we compute early */ unsigned long __cpuinitdata node_start_pfn[MAX_NUMNODES]; unsigned long __cpuinitdata node_end_pfn[MAX_NUMNODES]; @@ -534,37 +532,96 @@ static void __init setup_memory(void) #endif } -static void __init setup_bootmem_allocator(void) +/* + * On 32-bit machines, we only put bootmem on the low controller, + * since PAs > 4GB can't be used in bootmem. In principle one could + * imagine, e.g., multiple 1 GB controllers all of which could support + * bootmem, but in practice using controllers this small isn't a + * particularly interesting scenario, so we just keep it simple and + * use only the first controller for bootmem on 32-bit machines. + */ +static inline int node_has_bootmem(int nid) { - unsigned long bootmap_size, first_alloc_pfn, last_alloc_pfn; +#ifdef CONFIG_64BIT + return 1; +#else + return nid == 0; +#endif +} - /* Provide a node 0 bdata. */ - NODE_DATA(0)->bdata = &node0_bdata; +static inline unsigned long alloc_bootmem_pfn(int nid, + unsigned long size, + unsigned long goal) +{ + void *kva = __alloc_bootmem_node(NODE_DATA(nid), size, + PAGE_SIZE, goal); + unsigned long pfn = kaddr_to_pfn(kva); + BUG_ON(goal && PFN_PHYS(pfn) != goal); + return pfn; +} -#ifdef CONFIG_PCI - /* Don't let boot memory alias the PCI region. */ - last_alloc_pfn = min(max_low_pfn, pci_reserve_start_pfn); +static void __init setup_bootmem_allocator_node(int i) +{ + unsigned long start, end, mapsize, mapstart; + + if (node_has_bootmem(i)) { + NODE_DATA(i)->bdata = &bootmem_node_data[i]; + } else { + /* Share controller zero's bdata for now. */ + NODE_DATA(i)->bdata = &bootmem_node_data[0]; + return; + } + + /* Skip up to after the bss in node 0. */ + start = (i == 0) ? min_low_pfn : node_start_pfn[i]; + + /* Only lowmem, if we're a HIGHMEM build. */ +#ifdef CONFIG_HIGHMEM + end = node_lowmem_end_pfn[i]; #else - last_alloc_pfn = max_low_pfn; + end = node_end_pfn[i]; #endif - /* - * Initialize the boot-time allocator (with low memory only): - * The first argument says where to put the bitmap, and the - * second says where the end of allocatable memory is. - */ - bootmap_size = init_bootmem(min_low_pfn, last_alloc_pfn); + /* No memory here. */ + if (end == start) + return; + + /* Figure out where the bootmem bitmap is located. */ + mapsize = bootmem_bootmap_pages(end - start); + if (i == 0) { + /* Use some space right before the heap on node 0. */ + mapstart = start; + start += mapsize; + } else { + /* Allocate bitmap on node 0 to avoid page table issues. */ + mapstart = alloc_bootmem_pfn(0, PFN_PHYS(mapsize), 0); + } + /* Initialize a node. */ + init_bootmem_node(NODE_DATA(i), mapstart, start, end); + + /* Free all the space back into the allocator. */ + free_bootmem(PFN_PHYS(start), PFN_PHYS(end - start)); + +#if defined(CONFIG_PCI) /* - * Let the bootmem allocator use all the space we've given it - * except for its own bitmap. + * Throw away any memory aliased by the PCI region. FIXME: this + * is a temporary hack to work around bug 10502, and needs to be + * fixed properly. */ - first_alloc_pfn = min_low_pfn + PFN_UP(bootmap_size); - if (first_alloc_pfn >= last_alloc_pfn) - early_panic("Not enough memory on controller 0 for bootmem\n"); + if (pci_reserve_start_pfn < end && pci_reserve_end_pfn > start) + reserve_bootmem(PFN_PHYS(pci_reserve_start_pfn), + PFN_PHYS(pci_reserve_end_pfn - + pci_reserve_start_pfn), + BOOTMEM_EXCLUSIVE); +#endif +} - free_bootmem(PFN_PHYS(first_alloc_pfn), - PFN_PHYS(last_alloc_pfn - first_alloc_pfn)); +static void __init setup_bootmem_allocator(void) +{ + int i; + for (i = 0; i < MAX_NUMNODES; ++i) + setup_bootmem_allocator_node(i); #ifdef CONFIG_KEXEC if (crashk_res.start != crashk_res.end) @@ -595,14 +652,6 @@ static int __init percpu_size(void) return size; } -static inline unsigned long alloc_bootmem_pfn(int size, unsigned long goal) -{ - void *kva = __alloc_bootmem(size, PAGE_SIZE, goal); - unsigned long pfn = kaddr_to_pfn(kva); - BUG_ON(goal && PFN_PHYS(pfn) != goal); - return pfn; -} - static void __init zone_sizes_init(void) { unsigned long zones_size[MAX_NR_ZONES] = { 0 }; @@ -640,21 +689,22 @@ static void __init zone_sizes_init(void) * though, there'll be no lowmem, so we just alloc_bootmem * the memmap. There will be no percpu memory either. */ - if (__pfn_to_highbits(start) == 0) { - /* In low PAs, allocate via bootmem. */ + if (i != 0 && cpu_isset(i, isolnodes)) { + node_memmap_pfn[i] = + alloc_bootmem_pfn(0, memmap_size, 0); + BUG_ON(node_percpu[i] != 0); + } else if (node_has_bootmem(start)) { unsigned long goal = 0; node_memmap_pfn[i] = - alloc_bootmem_pfn(memmap_size, goal); + alloc_bootmem_pfn(i, memmap_size, 0); if (kdata_huge) goal = PFN_PHYS(lowmem_end) - node_percpu[i]; if (node_percpu[i]) node_percpu_pfn[i] = - alloc_bootmem_pfn(node_percpu[i], goal); - } else if (cpu_isset(i, isolnodes)) { - node_memmap_pfn[i] = alloc_bootmem_pfn(memmap_size, 0); - BUG_ON(node_percpu[i] != 0); + alloc_bootmem_pfn(i, node_percpu[i], + goal); } else { - /* In high PAs, just reserve some pages. */ + /* In non-bootmem zones, just reserve some pages. */ node_memmap_pfn[i] = node_free_pfn[i]; node_free_pfn[i] += PFN_UP(memmap_size); if (!kdata_huge) { @@ -678,16 +728,9 @@ static void __init zone_sizes_init(void) zones_size[ZONE_NORMAL] = end - start; #endif - /* - * Everyone shares node 0's bootmem allocator, but - * we use alloc_remap(), above, to put the actual - * struct page array on the individual controllers, - * which is most of the data that we actually care about. - * We can't place bootmem allocators on the other - * controllers since the bootmem allocator can only - * operate on 32-bit physical addresses. - */ - NODE_DATA(i)->bdata = NODE_DATA(0)->bdata; + /* Take zone metadata from controller 0 if we're isolnode. */ + if (node_isset(i, isolnodes)) + NODE_DATA(i)->bdata = &bootmem_node_data[0]; free_area_init_node(i, zones_size, start, NULL); printk(KERN_DEBUG " Normal zone: %ld per-cpu pages\n", @@ -870,6 +913,22 @@ subsys_initcall(topology_init); #endif /* CONFIG_NUMA */ +/* + * Initialize hugepage support on this cpu. We do this on all cores + * early in boot: before argument parsing for the boot cpu, and after + * argument parsing but before the init functions run on the secondaries. + * So the values we set up here in the hypervisor may be overridden on + * the boot cpu as arguments are parsed. + */ +static __cpuinit void init_super_pages(void) +{ +#ifdef CONFIG_HUGETLB_SUPER_PAGES + int i; + for (i = 0; i < HUGE_SHIFT_ENTRIES; ++i) + hv_set_pte_super_shift(i, huge_shift[i]); +#endif +} + /** * setup_cpu() - Do all necessary per-cpu, tile-specific initialization. * @boot: Is this the boot cpu? @@ -924,6 +983,8 @@ void __cpuinit setup_cpu(int boot) /* Reset the network state on this cpu. */ reset_network_state(); #endif + + init_super_pages(); } #ifdef CONFIG_BLK_DEV_INITRD @@ -1412,13 +1473,13 @@ void __init setup_per_cpu_areas(void) for (i = 0; i < size; i += PAGE_SIZE, ++pfn, ++pg) { /* Update the vmalloc mapping and page home. */ - pte_t *ptep = - virt_to_pte(NULL, (unsigned long)ptr + i); + unsigned long addr = (unsigned long)ptr + i; + pte_t *ptep = virt_to_pte(NULL, addr); pte_t pte = *ptep; BUG_ON(pfn != pte_pfn(pte)); pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3); pte = set_remote_cache_cpu(pte, cpu); - set_pte(ptep, pte); + set_pte_at(&init_mm, addr, ptep, pte); /* Update the lowmem mapping for consistency. */ lowmem_va = (unsigned long)pfn_to_kaddr(pfn); @@ -1431,7 +1492,7 @@ void __init setup_per_cpu_areas(void) BUG_ON(pte_huge(*ptep)); } BUG_ON(pfn != pte_pfn(*ptep)); - set_pte(ptep, pte); + set_pte_at(&init_mm, lowmem_va, ptep, pte); } } diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 89529c9f0605..27742e87e255 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c @@ -172,9 +172,6 @@ static tile_bundle_bits rewrite_load_store_unaligned( return (tilepro_bundle_bits) 0; } -#ifndef __LITTLE_ENDIAN -# error We assume little-endian representation with copy_xx_user size 2 here -#endif /* Handle unaligned load/store */ if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) { unsigned short val_16; @@ -195,8 +192,19 @@ static tile_bundle_bits rewrite_load_store_unaligned( state->update = 1; } } else { + unsigned short val_16; val = (val_reg == TREG_ZERO) ? 0 : regs->regs[val_reg]; - err = copy_to_user(addr, &val, size); + switch (size) { + case 2: + val_16 = val; + err = copy_to_user(addr, &val_16, sizeof(val_16)); + break; + case 4: + err = copy_to_user(addr, &val, sizeof(val)); + break; + default: + BUG(); + } } if (err) { diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index 91da0f721958..cbc73a8b8fe1 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c @@ -203,7 +203,7 @@ void __init ipi_init(void) if (hv_get_ipi_pte(tile, KERNEL_PL, &pte) != 0) panic("Failed to initialize IPI for cpu %d\n", cpu); - offset = hv_pte_get_pfn(pte) << PAGE_SHIFT; + offset = PFN_PHYS(pte_pfn(pte)); ipi_mappings[cpu] = ioremap_prot(offset, PAGE_SIZE, pte); } #endif diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c index cb44ba7ccd2d..b08095b402d6 100644 --- a/arch/tile/kernel/sys.c +++ b/arch/tile/kernel/sys.c @@ -32,11 +32,17 @@ #include <asm/syscalls.h> #include <asm/pgtable.h> #include <asm/homecache.h> +#include <asm/cachectl.h> #include <arch/chip.h> -SYSCALL_DEFINE0(flush_cache) +SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, + unsigned long, flags) { - homecache_evict(cpumask_of(smp_processor_id())); + if (flags & DCACHE) + homecache_evict(cpumask_of(smp_processor_id())); + if (flags & ICACHE) + flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(current->mm), + 0, 0, 0, NULL, NULL, 0); return 0; } diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c index 71ae728e9d0b..e25b0a89c18f 100644 --- a/arch/tile/kernel/sysfs.c +++ b/arch/tile/kernel/sysfs.c @@ -93,6 +93,10 @@ HV_CONF_ATTR(mezz_part, HV_CONFSTR_MEZZ_PART_NUM) HV_CONF_ATTR(mezz_serial, HV_CONFSTR_MEZZ_SERIAL_NUM) HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV) HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC) +HV_CONF_ATTR(cpumod_part, HV_CONFSTR_CPUMOD_PART_NUM) +HV_CONF_ATTR(cpumod_serial, HV_CONFSTR_CPUMOD_SERIAL_NUM) +HV_CONF_ATTR(cpumod_revision, HV_CONFSTR_CPUMOD_REV) +HV_CONF_ATTR(cpumod_description,HV_CONFSTR_CPUMOD_DESC) HV_CONF_ATTR(switch_control, HV_CONFSTR_SWITCH_CONTROL) static struct attribute *board_attrs[] = { @@ -104,6 +108,10 @@ static struct attribute *board_attrs[] = { &dev_attr_mezz_serial.attr, &dev_attr_mezz_revision.attr, &dev_attr_mezz_description.attr, + &dev_attr_cpumod_part.attr, + &dev_attr_cpumod_serial.attr, + &dev_attr_cpumod_revision.attr, + &dev_attr_cpumod_description.attr, &dev_attr_switch_control.attr, NULL }; diff --git a/arch/tile/kernel/tlb.c b/arch/tile/kernel/tlb.c index a5f241c24cac..3fd54d5bbd4c 100644 --- a/arch/tile/kernel/tlb.c +++ b/arch/tile/kernel/tlb.c @@ -15,6 +15,7 @@ #include <linux/cpumask.h> #include <linux/module.h> +#include <linux/hugetlb.h> #include <asm/tlbflush.h> #include <asm/homecache.h> #include <hv/hypervisor.h> @@ -49,25 +50,25 @@ void flush_tlb_current_task(void) flush_tlb_mm(current->mm); } -void flush_tlb_page_mm(const struct vm_area_struct *vma, struct mm_struct *mm, +void flush_tlb_page_mm(struct vm_area_struct *vma, struct mm_struct *mm, unsigned long va) { - unsigned long size = hv_page_size(vma); + unsigned long size = vma_kernel_pagesize(vma); int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0; flush_remote(0, cache, mm_cpumask(mm), va, size, size, mm_cpumask(mm), NULL, 0); } -void flush_tlb_page(const struct vm_area_struct *vma, unsigned long va) +void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) { flush_tlb_page_mm(vma, vma->vm_mm, va); } EXPORT_SYMBOL(flush_tlb_page); -void flush_tlb_range(const struct vm_area_struct *vma, +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - unsigned long size = hv_page_size(vma); + unsigned long size = vma_kernel_pagesize(vma); struct mm_struct *mm = vma->vm_mm; int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0; flush_remote(0, cache, mm_cpumask(mm), start, end - start, size, diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 73cff814ac57..5b19a23c8908 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c @@ -195,6 +195,25 @@ static int special_ill(bundle_bits bundle, int *sigp, int *codep) return 1; } +static const char *const int_name[] = { + [INT_MEM_ERROR] = "Memory error", + [INT_ILL] = "Illegal instruction", + [INT_GPV] = "General protection violation", + [INT_UDN_ACCESS] = "UDN access", + [INT_IDN_ACCESS] = "IDN access", +#if CHIP_HAS_SN() + [INT_SN_ACCESS] = "SN access", +#endif + [INT_SWINT_3] = "Software interrupt 3", + [INT_SWINT_2] = "Software interrupt 2", + [INT_SWINT_0] = "Software interrupt 0", + [INT_UNALIGN_DATA] = "Unaligned data", + [INT_DOUBLE_FAULT] = "Double fault", +#ifdef __tilegx__ + [INT_ILL_TRANS] = "Illegal virtual address", +#endif +}; + void __kprobes do_trap(struct pt_regs *regs, int fault_num, unsigned long reason) { @@ -211,10 +230,17 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, * current process and hope for the best. */ if (!user_mode(regs)) { + const char *name; if (fixup_exception(regs)) /* only UNALIGN_DATA in practice */ return; - pr_alert("Kernel took bad trap %d at PC %#lx\n", - fault_num, regs->pc); + if (fault_num >= 0 && + fault_num < sizeof(int_name)/sizeof(int_name[0]) && + int_name[fault_num] != NULL) + name = int_name[fault_num]; + else + name = "Unknown interrupt"; + pr_alert("Kernel took bad trap %d (%s) at PC %#lx\n", + fault_num, name, regs->pc); if (fault_num == INT_GPV) pr_alert("GPV_REASON is %#lx\n", reason); show_regs(regs); diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c index 771b251b409d..f5cada70c3c8 100644 --- a/arch/tile/lib/atomic_32.c +++ b/arch/tile/lib/atomic_32.c @@ -18,7 +18,6 @@ #include <linux/module.h> #include <linux/mm.h> #include <linux/atomic.h> -#include <asm/futex.h> #include <arch/chip.h> /* See <asm/atomic_32.h> */ @@ -50,7 +49,7 @@ int atomic_locks[PAGE_SIZE / sizeof(int)] __page_aligned_bss; #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ -static inline int *__atomic_hashed_lock(volatile void *v) +int *__atomic_hashed_lock(volatile void *v) { /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec_32.S */ #if ATOMIC_LOCKS_FOUND_VIA_TABLE() @@ -191,47 +190,6 @@ u64 _atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n) EXPORT_SYMBOL(_atomic64_cmpxchg); -static inline int *__futex_setup(int __user *v) -{ - /* - * Issue a prefetch to the counter to bring it into cache. - * As for __atomic_setup, but we can't do a read into the L1 - * since it might fault; instead we do a prefetch into the L2. - */ - __insn_prefetch(v); - return __atomic_hashed_lock((int __force *)v); -} - -struct __get_user futex_set(u32 __user *v, int i) -{ - return __atomic_xchg((int __force *)v, __futex_setup(v), i); -} - -struct __get_user futex_add(u32 __user *v, int n) -{ - return __atomic_xchg_add((int __force *)v, __futex_setup(v), n); -} - -struct __get_user futex_or(u32 __user *v, int n) -{ - return __atomic_or((int __force *)v, __futex_setup(v), n); -} - -struct __get_user futex_andn(u32 __user *v, int n) -{ - return __atomic_andn((int __force *)v, __futex_setup(v), n); -} - -struct __get_user futex_xor(u32 __user *v, int n) -{ - return __atomic_xor((int __force *)v, __futex_setup(v), n); -} - -struct __get_user futex_cmpxchg(u32 __user *v, int o, int n) -{ - return __atomic_cmpxchg((int __force *)v, __futex_setup(v), o, n); -} - /* * If any of the atomic or futex routines hit a bad address (not in * the page tables at kernel PL) this routine is called. The futex @@ -323,7 +281,4 @@ void __init __init_atomic_per_cpu(void) BUILD_BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE); #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ - - /* The futex code makes this assumption, so we validate it here. */ - BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int)); } diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c index 2a81d32de0da..dd5f0a33fdaf 100644 --- a/arch/tile/lib/exports.c +++ b/arch/tile/lib/exports.c @@ -18,14 +18,6 @@ /* arch/tile/lib/usercopy.S */ #include <linux/uaccess.h> -EXPORT_SYMBOL(__get_user_1); -EXPORT_SYMBOL(__get_user_2); -EXPORT_SYMBOL(__get_user_4); -EXPORT_SYMBOL(__get_user_8); -EXPORT_SYMBOL(__put_user_1); -EXPORT_SYMBOL(__put_user_2); -EXPORT_SYMBOL(__put_user_4); -EXPORT_SYMBOL(__put_user_8); EXPORT_SYMBOL(strnlen_user_asm); EXPORT_SYMBOL(strncpy_from_user_asm); EXPORT_SYMBOL(clear_user_asm); diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c index 84fdc8d8e735..6f867dbf7c56 100644 --- a/arch/tile/lib/memchr_64.c +++ b/arch/tile/lib/memchr_64.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/module.h> +#include "string-endian.h" void *memchr(const void *s, int c, size_t n) { @@ -39,11 +40,8 @@ void *memchr(const void *s, int c, size_t n) /* Read the first word, but munge it so that bytes before the array * will not match goal. - * - * Note that this shift count expression works because we know - * shift counts are taken mod 64. */ - before_mask = (1ULL << (s_int << 3)) - 1; + before_mask = MASK(s_int); v = (*p | before_mask) ^ (goal & before_mask); /* Compute the address of the last byte. */ @@ -65,7 +63,7 @@ void *memchr(const void *s, int c, size_t n) /* We found a match, but it might be in a byte past the end * of the array. */ - ret = ((char *)p) + (__insn_ctz(bits) >> 3); + ret = ((char *)p) + (CFZ(bits) >> 3); return (ret <= last_byte_ptr) ? ret : NULL; } EXPORT_SYMBOL(memchr); diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c index 3fab9a6a2bbe..c79b8e7c6828 100644 --- a/arch/tile/lib/memcpy_64.c +++ b/arch/tile/lib/memcpy_64.c @@ -15,7 +15,6 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/module.h> -#define __memcpy memcpy /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ /* Must be 8 bytes in size. */ @@ -188,6 +187,7 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) /* n != 0 if we get here. Write out any trailing bytes. */ dst1 = (char *)dst8; +#ifndef __BIG_ENDIAN__ if (n & 4) { ST4((uint32_t *)dst1, final); dst1 += 4; @@ -202,11 +202,30 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) } if (n) ST1((uint8_t *)dst1, final); +#else + if (n & 4) { + ST4((uint32_t *)dst1, final >> 32); + dst1 += 4; + } + else + { + final >>= 32; + } + if (n & 2) { + ST2((uint16_t *)dst1, final >> 16); + dst1 += 2; + } + else + { + final >>= 16; + } + if (n & 1) + ST1((uint8_t *)dst1, final >> 8); +#endif return RETVAL; } - #ifdef USERCOPY_FUNC #undef ST1 #undef ST2 diff --git a/arch/tile/lib/memcpy_tile64.c b/arch/tile/lib/memcpy_tile64.c index b2fe15e01075..3bc4b4e40d93 100644 --- a/arch/tile/lib/memcpy_tile64.c +++ b/arch/tile/lib/memcpy_tile64.c @@ -160,7 +160,7 @@ retry_source: break; if (get_remote_cache_cpu(src_pte) == smp_processor_id()) break; - src_page = pfn_to_page(hv_pte_get_pfn(src_pte)); + src_page = pfn_to_page(pte_pfn(src_pte)); get_page(src_page); if (pte_val(src_pte) != pte_val(*src_ptep)) { put_page(src_page); @@ -168,7 +168,7 @@ retry_source: } if (pte_huge(src_pte)) { /* Adjust the PTE to correspond to a small page */ - int pfn = hv_pte_get_pfn(src_pte); + int pfn = pte_pfn(src_pte); pfn += (((unsigned long)source & (HPAGE_SIZE-1)) >> PAGE_SHIFT); src_pte = pfn_pte(pfn, src_pte); @@ -188,7 +188,7 @@ retry_dest: put_page(src_page); break; } - dst_page = pfn_to_page(hv_pte_get_pfn(dst_pte)); + dst_page = pfn_to_page(pte_pfn(dst_pte)); if (dst_page == src_page) { /* * Source and dest are on the same page; this @@ -206,7 +206,7 @@ retry_dest: } if (pte_huge(dst_pte)) { /* Adjust the PTE to correspond to a small page */ - int pfn = hv_pte_get_pfn(dst_pte); + int pfn = pte_pfn(dst_pte); pfn += (((unsigned long)dest & (HPAGE_SIZE-1)) >> PAGE_SHIFT); dst_pte = pfn_pte(pfn, dst_pte); diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c index 617a9273aaa8..f39f9dc422b0 100644 --- a/arch/tile/lib/strchr_64.c +++ b/arch/tile/lib/strchr_64.c @@ -15,8 +15,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/module.h> - -#undef strchr +#include "string-endian.h" char *strchr(const char *s, int c) { @@ -33,13 +32,9 @@ char *strchr(const char *s, int c) * match neither zero nor goal (we make sure the high bit of each * byte is 1, and the low 7 bits are all the opposite of the goal * byte). - * - * Note that this shift count expression works because we know shift - * counts are taken mod 64. */ - const uint64_t before_mask = (1ULL << (s_int << 3)) - 1; - uint64_t v = (*p | before_mask) ^ - (goal & __insn_v1shrsi(before_mask, 1)); + const uint64_t before_mask = MASK(s_int); + uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui(before_mask, 1)); uint64_t zero_matches, goal_matches; while (1) { @@ -55,8 +50,8 @@ char *strchr(const char *s, int c) v = *++p; } - z = __insn_ctz(zero_matches); - g = __insn_ctz(goal_matches); + z = CFZ(zero_matches); + g = CFZ(goal_matches); /* If we found c before '\0' we got a match. Note that if c == '\0' * then g == z, and we correctly return the address of the '\0' diff --git a/arch/tile/lib/string-endian.h b/arch/tile/lib/string-endian.h new file mode 100644 index 000000000000..c0eed7ce69c3 --- /dev/null +++ b/arch/tile/lib/string-endian.h @@ -0,0 +1,33 @@ +/* + * Copyright 2011 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * Provide a mask based on the pointer alignment that + * sets up non-zero bytes before the beginning of the string. + * The MASK expression works because shift counts are taken mod 64. + * Also, specify how to count "first" and "last" bits + * when the bits have been read as a word. + */ + +#include <asm/byteorder.h> + +#ifdef __LITTLE_ENDIAN +#define MASK(x) (__insn_shl(1ULL, (x << 3)) - 1) +#define NULMASK(x) ((2ULL << x) - 1) +#define CFZ(x) __insn_ctz(x) +#define REVCZ(x) __insn_clz(x) +#else +#define MASK(x) (__insn_shl(-2LL, ((-x << 3) - 1))) +#define NULMASK(x) (-2LL << (63 - x)) +#define CFZ(x) __insn_clz(x) +#define REVCZ(x) __insn_ctz(x) +#endif diff --git a/arch/tile/lib/strlen_64.c b/arch/tile/lib/strlen_64.c index 1c92d46202a8..9583fc3361fa 100644 --- a/arch/tile/lib/strlen_64.c +++ b/arch/tile/lib/strlen_64.c @@ -15,8 +15,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/module.h> - -#undef strlen +#include "string-endian.h" size_t strlen(const char *s) { @@ -24,15 +23,13 @@ size_t strlen(const char *s) const uintptr_t s_int = (uintptr_t) s; const uint64_t *p = (const uint64_t *)(s_int & -8); - /* Read the first word, but force bytes before the string to be nonzero. - * This expression works because we know shift counts are taken mod 64. - */ - uint64_t v = *p | ((1ULL << (s_int << 3)) - 1); + /* Read and MASK the first word. */ + uint64_t v = *p | MASK(s_int); uint64_t bits; while ((bits = __insn_v1cmpeqi(v, 0)) == 0) v = *++p; - return ((const char *)p) + (__insn_ctz(bits) >> 3) - s; + return ((const char *)p) + (CFZ(bits) >> 3) - s; } EXPORT_SYMBOL(strlen); diff --git a/arch/tile/lib/usercopy_32.S b/arch/tile/lib/usercopy_32.S index 979f76d83746..b62d002af009 100644 --- a/arch/tile/lib/usercopy_32.S +++ b/arch/tile/lib/usercopy_32.S @@ -19,82 +19,6 @@ /* Access user memory, but use MMU to avoid propagating kernel exceptions. */ - .pushsection .fixup,"ax" - -get_user_fault: - { move r0, zero; move r1, zero } - { movei r2, -EFAULT; jrp lr } - ENDPROC(get_user_fault) - -put_user_fault: - { movei r0, -EFAULT; jrp lr } - ENDPROC(put_user_fault) - - .popsection - -/* - * __get_user_N functions take a pointer in r0, and return 0 in r2 - * on success, with the value in r0; or else -EFAULT in r2. - */ -#define __get_user_N(bytes, LOAD) \ - STD_ENTRY(__get_user_##bytes); \ -1: { LOAD r0, r0; move r1, zero; move r2, zero }; \ - jrp lr; \ - STD_ENDPROC(__get_user_##bytes); \ - .pushsection __ex_table,"a"; \ - .word 1b, get_user_fault; \ - .popsection - -__get_user_N(1, lb_u) -__get_user_N(2, lh_u) -__get_user_N(4, lw) - -/* - * __get_user_8 takes a pointer in r0, and returns 0 in r2 - * on success, with the value in r0/r1; or else -EFAULT in r2. - */ - STD_ENTRY(__get_user_8); -1: { lw r0, r0; addi r1, r0, 4 }; -2: { lw r1, r1; move r2, zero }; - jrp lr; - STD_ENDPROC(__get_user_8); - .pushsection __ex_table,"a"; - .word 1b, get_user_fault; - .word 2b, get_user_fault; - .popsection - -/* - * __put_user_N functions take a value in r0 and a pointer in r1, - * and return 0 in r0 on success or -EFAULT on failure. - */ -#define __put_user_N(bytes, STORE) \ - STD_ENTRY(__put_user_##bytes); \ -1: { STORE r1, r0; move r0, zero }; \ - jrp lr; \ - STD_ENDPROC(__put_user_##bytes); \ - .pushsection __ex_table,"a"; \ - .word 1b, put_user_fault; \ - .popsection - -__put_user_N(1, sb) -__put_user_N(2, sh) -__put_user_N(4, sw) - -/* - * __put_user_8 takes a value in r0/r1 and a pointer in r2, - * and returns 0 in r0 on success or -EFAULT on failure. - */ -STD_ENTRY(__put_user_8) -1: { sw r2, r0; addi r2, r2, 4 } -2: { sw r2, r1; move r0, zero } - jrp lr - STD_ENDPROC(__put_user_8) - .pushsection __ex_table,"a" - .word 1b, put_user_fault - .word 2b, put_user_fault - .popsection - - /* * strnlen_user_asm takes the pointer in r0, and the length bound in r1. * It returns the length, including the terminating NUL, or zero on exception. diff --git a/arch/tile/lib/usercopy_64.S b/arch/tile/lib/usercopy_64.S index 2ff44f87b78e..adb2dbbc70cd 100644 --- a/arch/tile/lib/usercopy_64.S +++ b/arch/tile/lib/usercopy_64.S @@ -19,55 +19,6 @@ /* Access user memory, but use MMU to avoid propagating kernel exceptions. */ - .pushsection .fixup,"ax" - -get_user_fault: - { movei r1, -EFAULT; move r0, zero } - jrp lr - ENDPROC(get_user_fault) - -put_user_fault: - { movei r0, -EFAULT; jrp lr } - ENDPROC(put_user_fault) - - .popsection - -/* - * __get_user_N functions take a pointer in r0, and return 0 in r1 - * on success, with the value in r0; or else -EFAULT in r1. - */ -#define __get_user_N(bytes, LOAD) \ - STD_ENTRY(__get_user_##bytes); \ -1: { LOAD r0, r0; move r1, zero }; \ - jrp lr; \ - STD_ENDPROC(__get_user_##bytes); \ - .pushsection __ex_table,"a"; \ - .quad 1b, get_user_fault; \ - .popsection - -__get_user_N(1, ld1u) -__get_user_N(2, ld2u) -__get_user_N(4, ld4u) -__get_user_N(8, ld) - -/* - * __put_user_N functions take a value in r0 and a pointer in r1, - * and return 0 in r0 on success or -EFAULT on failure. - */ -#define __put_user_N(bytes, STORE) \ - STD_ENTRY(__put_user_##bytes); \ -1: { STORE r1, r0; move r0, zero }; \ - jrp lr; \ - STD_ENDPROC(__put_user_##bytes); \ - .pushsection __ex_table,"a"; \ - .quad 1b, put_user_fault; \ - .popsection - -__put_user_N(1, st1) -__put_user_N(2, st2) -__put_user_N(4, st4) -__put_user_N(8, st) - /* * strnlen_user_asm takes the pointer in r0, and the length bound in r1. * It returns the length, including the terminating NUL, or zero on exception. diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index 22e58f51ed23..84ce7abbf5af 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c @@ -187,7 +187,7 @@ static pgd_t *get_current_pgd(void) HV_Context ctx = hv_inquire_context(); unsigned long pgd_pfn = ctx.page_table >> PAGE_SHIFT; struct page *pgd_page = pfn_to_page(pgd_pfn); - BUG_ON(PageHighMem(pgd_page)); /* oops, HIGHPTE? */ + BUG_ON(PageHighMem(pgd_page)); return (pgd_t *) __va(ctx.page_table); } @@ -273,11 +273,15 @@ static int handle_page_fault(struct pt_regs *regs, int si_code; int is_kernel_mode; pgd_t *pgd; + unsigned int flags; /* on TILE, protection faults are always writes */ if (!is_page_fault) write = 1; + flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | + (write ? FAULT_FLAG_WRITE : 0)); + is_kernel_mode = (EX1_PL(regs->ex1) != USER_PL); tsk = validate_current(); @@ -382,6 +386,8 @@ static int handle_page_fault(struct pt_regs *regs, vma = NULL; /* happy compiler */ goto bad_area_nosemaphore; } + +retry: down_read(&mm->mmap_sem); } @@ -429,7 +435,11 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(mm, vma, address, write); + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + return 0; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -437,10 +447,22 @@ good_area: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) + tsk->maj_flt++; + else + tsk->min_flt++; + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + + /* + * No need to up_read(&mm->mmap_sem) as we would + * have already released it in __lock_page_or_retry + * in mm/filemap.c. + */ + goto retry; + } + } #if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() /* diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c index 499f73770b05..dbcbdf7b8aa8 100644 --- a/arch/tile/mm/homecache.c +++ b/arch/tile/mm/homecache.c @@ -30,6 +30,7 @@ #include <linux/cache.h> #include <linux/smp.h> #include <linux/module.h> +#include <linux/hugetlb.h> #include <asm/page.h> #include <asm/sections.h> diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c index 42cfcba4e1ef..812e2d037972 100644 --- a/arch/tile/mm/hugetlbpage.c +++ b/arch/tile/mm/hugetlbpage.c @@ -27,85 +27,161 @@ #include <linux/mman.h> #include <asm/tlb.h> #include <asm/tlbflush.h> +#include <asm/setup.h> + +#ifdef CONFIG_HUGETLB_SUPER_PAGES + +/* + * Provide an additional huge page size (in addition to the regular default + * huge page size) if no "hugepagesz" arguments are specified. + * Note that it must be smaller than the default huge page size so + * that it's possible to allocate them on demand from the buddy allocator. + * You can change this to 64K (on a 16K build), 256K, 1M, or 4M, + * or not define it at all. + */ +#define ADDITIONAL_HUGE_SIZE (1024 * 1024UL) + +/* "Extra" page-size multipliers, one per level of the page table. */ +int huge_shift[HUGE_SHIFT_ENTRIES] = { +#ifdef ADDITIONAL_HUGE_SIZE +#define ADDITIONAL_HUGE_SHIFT __builtin_ctzl(ADDITIONAL_HUGE_SIZE / PAGE_SIZE) + [HUGE_SHIFT_PAGE] = ADDITIONAL_HUGE_SHIFT +#endif +}; + +/* + * This routine is a hybrid of pte_alloc_map() and pte_alloc_kernel(). + * It assumes that L2 PTEs are never in HIGHMEM (we don't support that). + * It locks the user pagetable, and bumps up the mm->nr_ptes field, + * but otherwise allocate the page table using the kernel versions. + */ +static pte_t *pte_alloc_hugetlb(struct mm_struct *mm, pmd_t *pmd, + unsigned long address) +{ + pte_t *new; + + if (pmd_none(*pmd)) { + new = pte_alloc_one_kernel(mm, address); + if (!new) + return NULL; + + smp_wmb(); /* See comment in __pte_alloc */ + + spin_lock(&mm->page_table_lock); + if (likely(pmd_none(*pmd))) { /* Has another populated it ? */ + mm->nr_ptes++; + pmd_populate_kernel(mm, pmd, new); + new = NULL; + } else + VM_BUG_ON(pmd_trans_splitting(*pmd)); + spin_unlock(&mm->page_table_lock); + if (new) + pte_free_kernel(mm, new); + } + + return pte_offset_kernel(pmd, address); +} +#endif pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz) { pgd_t *pgd; pud_t *pud; - pte_t *pte = NULL; - /* We do not yet support multiple huge page sizes. */ - BUG_ON(sz != PMD_SIZE); + addr &= -sz; /* Mask off any low bits in the address. */ pgd = pgd_offset(mm, addr); pud = pud_alloc(mm, pgd, addr); - if (pud) - pte = (pte_t *) pmd_alloc(mm, pud, addr); - BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte)); - return pte; +#ifdef CONFIG_HUGETLB_SUPER_PAGES + if (sz >= PGDIR_SIZE) { + BUG_ON(sz != PGDIR_SIZE && + sz != PGDIR_SIZE << huge_shift[HUGE_SHIFT_PGDIR]); + return (pte_t *)pud; + } else { + pmd_t *pmd = pmd_alloc(mm, pud, addr); + if (sz >= PMD_SIZE) { + BUG_ON(sz != PMD_SIZE && + sz != (PMD_SIZE << huge_shift[HUGE_SHIFT_PMD])); + return (pte_t *)pmd; + } + else { + if (sz != PAGE_SIZE << huge_shift[HUGE_SHIFT_PAGE]) + panic("Unexpected page size %#lx\n", sz); + return pte_alloc_hugetlb(mm, pmd, addr); + } + } +#else + BUG_ON(sz != PMD_SIZE); + return (pte_t *) pmd_alloc(mm, pud, addr); +#endif } -pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +static pte_t *get_pte(pte_t *base, int index, int level) { - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd = NULL; - - pgd = pgd_offset(mm, addr); - if (pgd_present(*pgd)) { - pud = pud_offset(pgd, addr); - if (pud_present(*pud)) - pmd = pmd_offset(pud, addr); + pte_t *ptep = base + index; +#ifdef CONFIG_HUGETLB_SUPER_PAGES + if (!pte_present(*ptep) && huge_shift[level] != 0) { + unsigned long mask = -1UL << huge_shift[level]; + pte_t *super_ptep = base + (index & mask); + pte_t pte = *super_ptep; + if (pte_present(pte) && pte_super(pte)) + ptep = super_ptep; } - return (pte_t *) pmd; +#endif + return ptep; } -#ifdef HUGETLB_TEST -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, - int write) +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) { - unsigned long start = address; - int length = 1; - int nr; - struct page *page; - struct vm_area_struct *vma; - - vma = find_vma(mm, addr); - if (!vma || !is_vm_hugetlb_page(vma)) - return ERR_PTR(-EINVAL); - - pte = huge_pte_offset(mm, address); + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; +#ifdef CONFIG_HUGETLB_SUPER_PAGES + pte_t *pte; +#endif - /* hugetlb should be locked, and hence, prefaulted */ - WARN_ON(!pte || pte_none(*pte)); + /* Get the top-level page table entry. */ + pgd = (pgd_t *)get_pte((pte_t *)mm->pgd, pgd_index(addr), 0); + if (!pgd_present(*pgd)) + return NULL; - page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; + /* We don't have four levels. */ + pud = pud_offset(pgd, addr); +#ifndef __PAGETABLE_PUD_FOLDED +# error support fourth page table level +#endif - WARN_ON(!PageHead(page)); + /* Check for an L0 huge PTE, if we have three levels. */ +#ifndef __PAGETABLE_PMD_FOLDED + if (pud_huge(*pud)) + return (pte_t *)pud; - return page; -} - -int pmd_huge(pmd_t pmd) -{ - return 0; -} + pmd = (pmd_t *)get_pte((pte_t *)pud_page_vaddr(*pud), + pmd_index(addr), 1); + if (!pmd_present(*pmd)) + return NULL; +#else + pmd = pmd_offset(pud, addr); +#endif -int pud_huge(pud_t pud) -{ - return 0; -} + /* Check for an L1 huge PTE. */ + if (pmd_huge(*pmd)) + return (pte_t *)pmd; + +#ifdef CONFIG_HUGETLB_SUPER_PAGES + /* Check for an L2 huge PTE. */ + pte = get_pte((pte_t *)pmd_page_vaddr(*pmd), pte_index(addr), 2); + if (!pte_present(*pte)) + return NULL; + if (pte_super(*pte)) + return pte; +#endif -struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int write) -{ return NULL; } -#else - struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) { @@ -149,8 +225,6 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) return 0; } -#endif - #ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, unsigned long addr, unsigned long len, @@ -322,21 +396,102 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, return hugetlb_get_unmapped_area_topdown(file, addr, len, pgoff, flags); } +#endif /* HAVE_ARCH_HUGETLB_UNMAPPED_AREA */ -static __init int setup_hugepagesz(char *opt) +#ifdef CONFIG_HUGETLB_SUPER_PAGES +static __init int __setup_hugepagesz(unsigned long ps) { - unsigned long ps = memparse(opt, &opt); - if (ps == PMD_SIZE) { - hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT); - } else if (ps == PUD_SIZE) { - hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT); + int log_ps = __builtin_ctzl(ps); + int level, base_shift; + + if ((1UL << log_ps) != ps || (log_ps & 1) != 0) { + pr_warn("Not enabling %ld byte huge pages;" + " must be a power of four.\n", ps); + return -EINVAL; + } + + if (ps > 64*1024*1024*1024UL) { + pr_warn("Not enabling %ld MB huge pages;" + " largest legal value is 64 GB .\n", ps >> 20); + return -EINVAL; + } else if (ps >= PUD_SIZE) { + static long hv_jpage_size; + if (hv_jpage_size == 0) + hv_jpage_size = hv_sysconf(HV_SYSCONF_PAGE_SIZE_JUMBO); + if (hv_jpage_size != PUD_SIZE) { + pr_warn("Not enabling >= %ld MB huge pages:" + " hypervisor reports size %ld\n", + PUD_SIZE >> 20, hv_jpage_size); + return -EINVAL; + } + level = 0; + base_shift = PUD_SHIFT; + } else if (ps >= PMD_SIZE) { + level = 1; + base_shift = PMD_SHIFT; + } else if (ps > PAGE_SIZE) { + level = 2; + base_shift = PAGE_SHIFT; } else { - pr_err("hugepagesz: Unsupported page size %lu M\n", - ps >> 20); - return 0; + pr_err("hugepagesz: huge page size %ld too small\n", ps); + return -EINVAL; } - return 1; + + if (log_ps != base_shift) { + int shift_val = log_ps - base_shift; + if (huge_shift[level] != 0) { + int old_shift = base_shift + huge_shift[level]; + pr_warn("Not enabling %ld MB huge pages;" + " already have size %ld MB.\n", + ps >> 20, (1UL << old_shift) >> 20); + return -EINVAL; + } + if (hv_set_pte_super_shift(level, shift_val) != 0) { + pr_warn("Not enabling %ld MB huge pages;" + " no hypervisor support.\n", ps >> 20); + return -EINVAL; + } + printk(KERN_DEBUG "Enabled %ld MB huge pages\n", ps >> 20); + huge_shift[level] = shift_val; + } + + hugetlb_add_hstate(log_ps - PAGE_SHIFT); + + return 0; +} + +static bool saw_hugepagesz; + +static __init int setup_hugepagesz(char *opt) +{ + if (!saw_hugepagesz) { + saw_hugepagesz = true; + memset(huge_shift, 0, sizeof(huge_shift)); + } + return __setup_hugepagesz(memparse(opt, NULL)); } __setup("hugepagesz=", setup_hugepagesz); -#endif /*HAVE_ARCH_HUGETLB_UNMAPPED_AREA*/ +#ifdef ADDITIONAL_HUGE_SIZE +/* + * Provide an additional huge page size if no "hugepagesz" args are given. + * In that case, all the cores have properly set up their hv super_shift + * already, but we need to notify the hugetlb code to enable the + * new huge page size from the Linux point of view. + */ +static __init int add_default_hugepagesz(void) +{ + if (!saw_hugepagesz) { + BUILD_BUG_ON(ADDITIONAL_HUGE_SIZE >= PMD_SIZE || + ADDITIONAL_HUGE_SIZE <= PAGE_SIZE); + BUILD_BUG_ON((PAGE_SIZE << ADDITIONAL_HUGE_SHIFT) != + ADDITIONAL_HUGE_SIZE); + BUILD_BUG_ON(ADDITIONAL_HUGE_SHIFT & 1); + hugetlb_add_hstate(ADDITIONAL_HUGE_SHIFT); + } + return 0; +} +arch_initcall(add_default_hugepagesz); +#endif + +#endif /* CONFIG_HUGETLB_SUPER_PAGES */ diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c index 6a9d20ddc34f..630dd2ce2afe 100644 --- a/arch/tile/mm/init.c +++ b/arch/tile/mm/init.c @@ -82,7 +82,7 @@ static int num_l2_ptes[MAX_NUMNODES]; static void init_prealloc_ptes(int node, int pages) { - BUG_ON(pages & (HV_L2_ENTRIES-1)); + BUG_ON(pages & (PTRS_PER_PTE - 1)); if (pages) { num_l2_ptes[node] = pages; l2_ptes[node] = __alloc_bootmem(pages * sizeof(pte_t), @@ -131,14 +131,9 @@ static void __init assign_pte(pmd_t *pmd, pte_t *page_table) #ifdef __tilegx__ -#if HV_L1_SIZE != HV_L2_SIZE -# error Rework assumption that L1 and L2 page tables are same size. -#endif - -/* Since pmd_t arrays and pte_t arrays are the same size, just use casts. */ static inline pmd_t *alloc_pmd(void) { - return (pmd_t *)alloc_pte(); + return __alloc_bootmem(L1_KERNEL_PGTABLE_SIZE, HV_PAGE_TABLE_ALIGN, 0); } static inline void assign_pmd(pud_t *pud, pmd_t *pmd) @@ -444,6 +439,7 @@ static pgd_t pgtables[PTRS_PER_PGD] */ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) { + unsigned long long irqmask; unsigned long address, pfn; pmd_t *pmd; pte_t *pte; @@ -633,10 +629,13 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) * - install pgtables[] as the real page table * - flush the TLB so the new page table takes effect */ + irqmask = interrupt_mask_save_mask(); + interrupt_mask_set_mask(-1ULL); rc = flush_and_install_context(__pa(pgtables), init_pgprot((unsigned long)pgtables), __get_cpu_var(current_asid), cpumask_bits(my_cpu_mask)); + interrupt_mask_restore_mask(irqmask); BUG_ON(rc != 0); /* Copy the page table back to the normal swapper_pg_dir. */ @@ -699,6 +698,7 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base) #endif /* CONFIG_HIGHMEM */ +#ifndef CONFIG_64BIT static void __init init_free_pfn_range(unsigned long start, unsigned long end) { unsigned long pfn; @@ -771,6 +771,7 @@ static void __init set_non_bootmem_pages_init(void) init_free_pfn_range(start, end); } } +#endif /* * paging_init() sets up the page tables - note that all of lowmem is @@ -807,7 +808,7 @@ void __init paging_init(void) * changing init_mm once we get up and running, and there's no * need for e.g. vmalloc_sync_all(). */ - BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END)); + BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END - 1)); pud = pud_offset(pgd_base + pgd_index(VMALLOC_START), VMALLOC_START); assign_pmd(pud, alloc_pmd()); #endif @@ -859,8 +860,10 @@ void __init mem_init(void) /* this will put all bootmem onto the freelists */ totalram_pages += free_all_bootmem(); +#ifndef CONFIG_64BIT /* count all remaining LOWMEM and give all HIGHMEM to page allocator */ set_non_bootmem_pages_init(); +#endif codesize = (unsigned long)&_etext - (unsigned long)&_text; datasize = (unsigned long)&_end - (unsigned long)&_sdata; diff --git a/arch/tile/mm/migrate.h b/arch/tile/mm/migrate.h index cd45a0837fa6..91683d97917e 100644 --- a/arch/tile/mm/migrate.h +++ b/arch/tile/mm/migrate.h @@ -24,6 +24,9 @@ /* * This function is used as a helper when setting up the initial * page table (swapper_pg_dir). + * + * You must mask ALL interrupts prior to invoking this code, since + * you can't legally touch the stack during the cache flush. */ extern int flush_and_install_context(HV_PhysAddr page_table, HV_PTE access, HV_ASID asid, @@ -39,6 +42,9 @@ extern int flush_and_install_context(HV_PhysAddr page_table, HV_PTE access, * * Note that any non-NULL pointers must not point to the page that * is handled by the stack_pte itself. + * + * You must mask ALL interrupts prior to invoking this code, since + * you can't legally touch the stack during the cache flush. */ extern int homecache_migrate_stack_and_flush(pte_t stack_pte, unsigned long va, size_t length, pte_t *stack_ptep, diff --git a/arch/tile/mm/migrate_32.S b/arch/tile/mm/migrate_32.S index ac01a7cdf77f..5305814bf187 100644 --- a/arch/tile/mm/migrate_32.S +++ b/arch/tile/mm/migrate_32.S @@ -40,8 +40,7 @@ #define FRAME_R32 16 #define FRAME_R33 20 #define FRAME_R34 24 -#define FRAME_R35 28 -#define FRAME_SIZE 32 +#define FRAME_SIZE 28 @@ -66,12 +65,11 @@ #define r_my_cpumask r5 /* Locals (callee-save); must not be more than FRAME_xxx above. */ -#define r_save_ics r30 -#define r_context_lo r31 -#define r_context_hi r32 -#define r_access_lo r33 -#define r_access_hi r34 -#define r_asid r35 +#define r_context_lo r30 +#define r_context_hi r31 +#define r_access_lo r32 +#define r_access_hi r33 +#define r_asid r34 STD_ENTRY(flush_and_install_context) /* @@ -104,11 +102,7 @@ STD_ENTRY(flush_and_install_context) sw r_tmp, r33 addi r_tmp, sp, FRAME_R34 } - { - sw r_tmp, r34 - addi r_tmp, sp, FRAME_R35 - } - sw r_tmp, r35 + sw r_tmp, r34 /* Move some arguments to callee-save registers. */ { @@ -121,13 +115,6 @@ STD_ENTRY(flush_and_install_context) } move r_asid, r_asid_in - /* Disable interrupts, since we can't use our stack. */ - { - mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION - movei r_tmp, 1 - } - mtspr INTERRUPT_CRITICAL_SECTION, r_tmp - /* First, flush our L2 cache. */ { move r0, zero /* cache_pa */ @@ -163,7 +150,7 @@ STD_ENTRY(flush_and_install_context) } { move r4, r_asid - movei r5, HV_CTX_DIRECTIO + moveli r5, HV_CTX_DIRECTIO | CTX_PAGE_FLAG } jal hv_install_context bnz r0, .Ldone @@ -175,9 +162,6 @@ STD_ENTRY(flush_and_install_context) } .Ldone: - /* Reset interrupts back how they were before. */ - mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics - /* Restore the callee-saved registers and return. */ addli lr, sp, FRAME_SIZE { @@ -202,10 +186,6 @@ STD_ENTRY(flush_and_install_context) } { lw r34, r_tmp - addli r_tmp, sp, FRAME_R35 - } - { - lw r35, r_tmp addi sp, sp, FRAME_SIZE } jrp lr diff --git a/arch/tile/mm/migrate_64.S b/arch/tile/mm/migrate_64.S index e76fea688beb..1d15b10833d1 100644 --- a/arch/tile/mm/migrate_64.S +++ b/arch/tile/mm/migrate_64.S @@ -38,8 +38,7 @@ #define FRAME_R30 16 #define FRAME_R31 24 #define FRAME_R32 32 -#define FRAME_R33 40 -#define FRAME_SIZE 48 +#define FRAME_SIZE 40 @@ -60,10 +59,9 @@ #define r_my_cpumask r3 /* Locals (callee-save); must not be more than FRAME_xxx above. */ -#define r_save_ics r30 -#define r_context r31 -#define r_access r32 -#define r_asid r33 +#define r_context r30 +#define r_access r31 +#define r_asid r32 /* * Caller-save locals and frame constants are the same as @@ -93,11 +91,7 @@ STD_ENTRY(flush_and_install_context) st r_tmp, r31 addi r_tmp, sp, FRAME_R32 } - { - st r_tmp, r32 - addi r_tmp, sp, FRAME_R33 - } - st r_tmp, r33 + st r_tmp, r32 /* Move some arguments to callee-save registers. */ { @@ -106,13 +100,6 @@ STD_ENTRY(flush_and_install_context) } move r_asid, r_asid_in - /* Disable interrupts, since we can't use our stack. */ - { - mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION - movei r_tmp, 1 - } - mtspr INTERRUPT_CRITICAL_SECTION, r_tmp - /* First, flush our L2 cache. */ { move r0, zero /* cache_pa */ @@ -147,7 +134,7 @@ STD_ENTRY(flush_and_install_context) } { move r2, r_asid - movei r3, HV_CTX_DIRECTIO + moveli r3, HV_CTX_DIRECTIO | CTX_PAGE_FLAG } jal hv_install_context bnez r0, 1f @@ -158,10 +145,7 @@ STD_ENTRY(flush_and_install_context) jal hv_flush_all } -1: /* Reset interrupts back how they were before. */ - mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics - - /* Restore the callee-saved registers and return. */ +1: /* Restore the callee-saved registers and return. */ addli lr, sp, FRAME_SIZE { ld lr, lr @@ -177,10 +161,6 @@ STD_ENTRY(flush_and_install_context) } { ld r32, r_tmp - addli r_tmp, sp, FRAME_R33 - } - { - ld r33, r_tmp addi sp, sp, FRAME_SIZE } jrp lr diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c index 2410aa899b3e..345edfed9fcd 100644 --- a/arch/tile/mm/pgtable.c +++ b/arch/tile/mm/pgtable.c @@ -132,15 +132,6 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags) set_pte_pfn(address, phys >> PAGE_SHIFT, flags); } -#if defined(CONFIG_HIGHPTE) -pte_t *_pte_offset_map(pmd_t *dir, unsigned long address) -{ - pte_t *pte = kmap_atomic(pmd_page(*dir)) + - (pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK; - return &pte[pte_index(address)]; -} -#endif - /** * shatter_huge_page() - ensure a given address is mapped by a small page. * @@ -289,33 +280,26 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd) #define L2_USER_PGTABLE_PAGES (1 << L2_USER_PGTABLE_ORDER) -struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) +struct page *pgtable_alloc_one(struct mm_struct *mm, unsigned long address, + int order) { gfp_t flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO; struct page *p; -#if L2_USER_PGTABLE_ORDER > 0 int i; -#endif - -#ifdef CONFIG_HIGHPTE - flags |= __GFP_HIGHMEM; -#endif p = alloc_pages(flags, L2_USER_PGTABLE_ORDER); if (p == NULL) return NULL; -#if L2_USER_PGTABLE_ORDER > 0 /* * Make every page have a page_count() of one, not just the first. * We don't use __GFP_COMP since it doesn't look like it works * correctly with tlb_remove_page(). */ - for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) { + for (i = 1; i < order; ++i) { init_page_count(p+i); inc_zone_page_state(p+i, NR_PAGETABLE); } -#endif pgtable_page_ctor(p); return p; @@ -326,28 +310,28 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) * process). We have to correct whatever pte_alloc_one() did before * returning the pages to the allocator. */ -void pte_free(struct mm_struct *mm, struct page *p) +void pgtable_free(struct mm_struct *mm, struct page *p, int order) { int i; pgtable_page_dtor(p); __free_page(p); - for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) { + for (i = 1; i < order; ++i) { __free_page(p+i); dec_zone_page_state(p+i, NR_PAGETABLE); } } -void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte, - unsigned long address) +void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte, + unsigned long address, int order) { int i; pgtable_page_dtor(pte); tlb_remove_page(tlb, pte); - for (i = 1; i < L2_USER_PGTABLE_PAGES; ++i) { + for (i = 1; i < order; ++i) { tlb_remove_page(tlb, pte + i); dec_zone_page_state(pte + i, NR_PAGETABLE); } @@ -490,7 +474,7 @@ void set_pte(pte_t *ptep, pte_t pte) /* Can this mm load a PTE with cached_priority set? */ static inline int mm_is_priority_cached(struct mm_struct *mm) { - return mm->context.priority_cached; + return mm->context.priority_cached != 0; } /* @@ -500,8 +484,8 @@ static inline int mm_is_priority_cached(struct mm_struct *mm) void start_mm_caching(struct mm_struct *mm) { if (!mm_is_priority_cached(mm)) { - mm->context.priority_cached = -1U; - hv_set_caching(-1U); + mm->context.priority_cached = -1UL; + hv_set_caching(-1UL); } } @@ -516,7 +500,7 @@ void start_mm_caching(struct mm_struct *mm) * Presumably we'll come back later and have more luck and clear * the value then; for now we'll just keep the cache marked for priority. */ -static unsigned int update_priority_cached(struct mm_struct *mm) +static unsigned long update_priority_cached(struct mm_struct *mm) { if (mm->context.priority_cached && down_write_trylock(&mm->mmap_sem)) { struct vm_area_struct *vm; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 66cc380bebf0..d700811785ea 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -32,6 +32,7 @@ config X86 select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_FRAME_POINTERS select HAVE_DMA_ATTRS + select HAVE_DMA_CONTIGUOUS if !SWIOTLB select HAVE_KRETPROBES select HAVE_OPTPROBES select HAVE_FTRACE_MCOUNT_RECORD @@ -92,6 +93,8 @@ config X86 select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC) select GENERIC_TIME_VSYSCALL if X86_64 select KTIME_SCALAR if X86_32 + select GENERIC_STRNCPY_FROM_USER + select GENERIC_STRNLEN_USER config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS || UPROBES) diff --git a/arch/x86/include/asm/dma-contiguous.h b/arch/x86/include/asm/dma-contiguous.h new file mode 100644 index 000000000000..c09241659971 --- /dev/null +++ b/arch/x86/include/asm/dma-contiguous.h @@ -0,0 +1,13 @@ +#ifndef ASMX86_DMA_CONTIGUOUS_H +#define ASMX86_DMA_CONTIGUOUS_H + +#ifdef __KERNEL__ + +#include <linux/types.h> +#include <asm-generic/dma-contiguous.h> + +static inline void +dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { } + +#endif +#endif diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 61c0bd25845a..f7b4c7903e7e 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -13,6 +13,7 @@ #include <asm/io.h> #include <asm/swiotlb.h> #include <asm-generic/dma-coherent.h> +#include <linux/dma-contiguous.h> #ifdef CONFIG_ISA # define ISA_DMA_BIT_MASK DMA_BIT_MASK(24) @@ -62,6 +63,10 @@ extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag, struct dma_attrs *attrs); +extern void dma_generic_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_addr, + struct dma_attrs *attrs); + #ifdef CONFIG_X86_DMA_REMAP /* Platform code defines bridge-specific code */ extern bool dma_capable(struct device *dev, dma_addr_t addr, size_t size); extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 851fe0dc13bc..04cd6882308e 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -32,6 +32,7 @@ #define segment_eq(a, b) ((a).seg == (b).seg) +#define user_addr_max() (current_thread_info()->addr_limit.seg) #define __addr_ok(addr) \ ((unsigned long __force)(addr) < \ (current_thread_info()->addr_limit.seg)) @@ -565,6 +566,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n); extern __must_check long strncpy_from_user(char *dst, const char __user *src, long count); +extern __must_check long strlen_user(const char __user *str); +extern __must_check long strnlen_user(const char __user *str, long n); + /* * movsl can be slow when source and dest are not both 8-byte aligned */ diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index 8084bc73b18c..576e39bca6ad 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h @@ -213,23 +213,6 @@ static inline unsigned long __must_check copy_from_user(void *to, return n; } -/** - * strlen_user: - Get the size of a string in user space. - * @str: The string to measure. - * - * Context: User context only. This function may sleep. - * - * Get the size of a NUL-terminated string in user space. - * - * Returns the size of the string INCLUDING the terminating NUL. - * On exception, returns 0. - * - * If there is a limit on the length of a valid string, you may wish to - * consider using strnlen_user() instead. - */ -#define strlen_user(str) strnlen_user(str, LONG_MAX) - -long strnlen_user(const char __user *str, long n); unsigned long __must_check clear_user(void __user *mem, unsigned long len); unsigned long __must_check __clear_user(void __user *mem, unsigned long len); diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index fcd4b6f3ef02..8e796fbbf9c6 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -208,9 +208,6 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) } } -__must_check long strnlen_user(const char __user *str, long n); -__must_check long __strnlen_user(const char __user *str, long n); -__must_check long strlen_user(const char __user *str); __must_check unsigned long clear_user(void __user *mem, unsigned long len); __must_check unsigned long __clear_user(void __user *mem, unsigned long len); diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h index ae03facfadd6..5b238981542a 100644 --- a/arch/x86/include/asm/word-at-a-time.h +++ b/arch/x86/include/asm/word-at-a-time.h @@ -10,6 +10,11 @@ * bit count instruction, that might be better than the multiply * and shift, for example. */ +struct word_at_a_time { + const unsigned long one_bits, high_bits; +}; + +#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } #ifdef CONFIG_64BIT @@ -37,10 +42,31 @@ static inline long count_masked_bytes(long mask) #endif -/* Return the high bit set in the first byte that is a zero */ -static inline unsigned long has_zero(unsigned long a) +/* Return nonzero if it has a zero */ +static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c) +{ + unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits; + *bits = mask; + return mask; +} + +static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c) +{ + return bits; +} + +static inline unsigned long create_zero_mask(unsigned long bits) +{ + bits = (bits - 1) & ~bits; + return bits >> 7; +} + +/* The mask we created is directly usable as a bytemask */ +#define zero_bytemask(mask) (mask) + +static inline unsigned long find_zero(unsigned long mask) { - return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80); + return count_masked_bytes(mask); } /* diff --git a/arch/x86/kernel/cpu/mcheck/mce-apei.c b/arch/x86/kernel/cpu/mcheck/mce-apei.c index 507ea58688e2..cd8b166a1735 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-apei.c +++ b/arch/x86/kernel/cpu/mcheck/mce-apei.c @@ -42,7 +42,8 @@ void apei_mce_report_mem_error(int corrected, struct cper_sec_mem_err *mem_err) struct mce m; /* Only corrected MC is reported */ - if (!corrected) + if (!corrected || !(mem_err->validation_bits & + CPER_MEM_VALID_PHYSICAL_ADDRESS)) return; mce_setup(&m); diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index 0c82091b1652..413c2ced887c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -126,6 +126,16 @@ static struct severity { SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA), USER ), + MCESEV( + KEEP, "HT thread notices Action required: instruction fetch error", + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR), + MCGMASK(MCG_STATUS_EIPV, 0) + ), + MCESEV( + AR, "Action required: instruction fetch error", + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR), + USER + ), #endif MCESEV( PANIC, "Action required: unknown MCACOD", @@ -165,15 +175,19 @@ static struct severity { }; /* - * If the EIPV bit is set, it means the saved IP is the - * instruction which caused the MCE. + * If mcgstatus indicated that ip/cs on the stack were + * no good, then "m->cs" will be zero and we will have + * to assume the worst case (IN_KERNEL) as we actually + * have no idea what we were executing when the machine + * check hit. + * If we do have a good "m->cs" (or a faked one in the + * case we were executing in VM86 mode) we can use it to + * distinguish an exception taken in user from from one + * taken in the kernel. */ static int error_context(struct mce *m) { - if (m->mcgstatus & MCG_STATUS_EIPV) - return (m->ip && (m->cs & 3) == 3) ? IN_USER : IN_KERNEL; - /* Unknown, assume kernel */ - return IN_KERNEL; + return ((m->cs & 3) == 3) ? IN_USER : IN_KERNEL; } int mce_severity(struct mce *m, int tolerant, char **msg) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 2afcbd253e1d..b772dd6ad450 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -437,6 +437,14 @@ static inline void mce_gather_info(struct mce *m, struct pt_regs *regs) if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) { m->ip = regs->ip; m->cs = regs->cs; + + /* + * When in VM86 mode make the cs look like ring 3 + * always. This is a lie, but it's better than passing + * the additional vm86 bit around everywhere. + */ + if (v8086_mode(regs)) + m->cs |= 3; } /* Use accurate RIP reporting if available. */ if (rip_msr) @@ -641,16 +649,18 @@ EXPORT_SYMBOL_GPL(machine_check_poll); * Do a quick check if any of the events requires a panic. * This decides if we keep the events around or clear them. */ -static int mce_no_way_out(struct mce *m, char **msg) +static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp) { - int i; + int i, ret = 0; for (i = 0; i < banks; i++) { m->status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i)); + if (m->status & MCI_STATUS_VAL) + __set_bit(i, validp); if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY) - return 1; + ret = 1; } - return 0; + return ret; } /* @@ -1013,6 +1023,7 @@ void do_machine_check(struct pt_regs *regs, long error_code) */ int kill_it = 0; DECLARE_BITMAP(toclear, MAX_NR_BANKS); + DECLARE_BITMAP(valid_banks, MAX_NR_BANKS); char *msg = "Unknown"; atomic_inc(&mce_entry); @@ -1027,7 +1038,8 @@ void do_machine_check(struct pt_regs *regs, long error_code) final = &__get_cpu_var(mces_seen); *final = m; - no_way_out = mce_no_way_out(&m, &msg); + memset(valid_banks, 0, sizeof(valid_banks)); + no_way_out = mce_no_way_out(&m, &msg, valid_banks); barrier(); @@ -1047,6 +1059,8 @@ void do_machine_check(struct pt_regs *regs, long error_code) order = mce_start(&no_way_out); for (i = 0; i < banks; i++) { __clear_bit(i, toclear); + if (!test_bit(i, valid_banks)) + continue; if (!mce_banks[i].ctl) continue; diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 3003250ac51d..62c9457ccd2f 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -100,14 +100,18 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size, struct dma_attrs *attrs) { unsigned long dma_mask; - struct page *page; + struct page *page = NULL; + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; dma_addr_t addr; dma_mask = dma_alloc_coherent_mask(dev, flag); flag |= __GFP_ZERO; again: - page = alloc_pages_node(dev_to_node(dev), flag, get_order(size)); + if (!(flag & GFP_ATOMIC)) + page = dma_alloc_from_contiguous(dev, count, get_order(size)); + if (!page) + page = alloc_pages_node(dev_to_node(dev), flag, get_order(size)); if (!page) return NULL; @@ -127,6 +131,16 @@ again: return page_address(page); } +void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_addr, struct dma_attrs *attrs) +{ + unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + struct page *page = virt_to_page(vaddr); + + if (!dma_release_from_contiguous(dev, page, count)) + free_pages((unsigned long)vaddr, get_order(size)); +} + /* * See <Documentation/x86/x86_64/boot-options.txt> for the iommu kernel * parameter documentation. diff --git a/arch/x86/kernel/pci-nommu.c b/arch/x86/kernel/pci-nommu.c index f96050685b46..871be4a84c7d 100644 --- a/arch/x86/kernel/pci-nommu.c +++ b/arch/x86/kernel/pci-nommu.c @@ -74,12 +74,6 @@ static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg, return nents; } -static void nommu_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_addr, struct dma_attrs *attrs) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} - static void nommu_sync_single_for_device(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir) @@ -97,7 +91,7 @@ static void nommu_sync_sg_for_device(struct device *dev, struct dma_map_ops nommu_dma_ops = { .alloc = dma_generic_alloc_coherent, - .free = nommu_free_coherent, + .free = dma_generic_free_coherent, .map_sg = nommu_map_sg, .map_page = nommu_map_page, .sync_single_for_device = nommu_sync_single_for_device, diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 366c688d619e..f2afee6a19c1 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -49,6 +49,7 @@ #include <asm/pci-direct.h> #include <linux/init_ohci1394_dma.h> #include <linux/kvm_para.h> +#include <linux/dma-contiguous.h> #include <linux/errno.h> #include <linux/kernel.h> @@ -925,6 +926,7 @@ void __init setup_arch(char **cmdline_p) } #endif memblock.current_limit = get_max_mapped(); + dma_contiguous_reserve(0); /* * NOTE: On x86-32, only from this point on, fixmaps are ready for use. diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c index 2e4e4b02c37a..f61ee67ec00f 100644 --- a/arch/x86/lib/usercopy.c +++ b/arch/x86/lib/usercopy.c @@ -43,100 +43,3 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n) return len; } EXPORT_SYMBOL_GPL(copy_from_user_nmi); - -/* - * Do a strncpy, return length of string without final '\0'. - * 'count' is the user-supplied count (return 'count' if we - * hit it), 'max' is the address space maximum (and we return - * -EFAULT if we hit it). - */ -static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max) -{ - long res = 0; - - /* - * Truncate 'max' to the user-specified limit, so that - * we only have one limit we need to check in the loop - */ - if (max > count) - max = count; - - while (max >= sizeof(unsigned long)) { - unsigned long c, mask; - - /* Fall back to byte-at-a-time if we get a page fault */ - if (unlikely(__get_user(c,(unsigned long __user *)(src+res)))) - break; - mask = has_zero(c); - if (mask) { - mask = (mask - 1) & ~mask; - mask >>= 7; - *(unsigned long *)(dst+res) = c & mask; - return res + count_masked_bytes(mask); - } - *(unsigned long *)(dst+res) = c; - res += sizeof(unsigned long); - max -= sizeof(unsigned long); - } - - while (max) { - char c; - - if (unlikely(__get_user(c,src+res))) - return -EFAULT; - dst[res] = c; - if (!c) - return res; - res++; - max--; - } - - /* - * Uhhuh. We hit 'max'. But was that the user-specified maximum - * too? If so, that's ok - we got as much as the user asked for. - */ - if (res >= count) - return res; - - /* - * Nope: we hit the address space limit, and we still had more - * characters the caller would have wanted. That's an EFAULT. - */ - return -EFAULT; -} - -/** - * strncpy_from_user: - Copy a NUL terminated string from userspace. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Source address, in user space. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from userspace to kernel space. - * - * On success, returns the length of the string (not including the trailing - * NUL). - * - * If access to userspace fails, returns -EFAULT (some data may have been - * copied). - * - * If @count is smaller than the length of the string, copies @count bytes - * and returns @count. - */ -long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - unsigned long max_addr, src_addr; - - if (unlikely(count <= 0)) - return 0; - - max_addr = current_thread_info()->addr_limit.seg; - src_addr = (unsigned long)src; - if (likely(src_addr < max_addr)) { - unsigned long max = max_addr - src_addr; - return do_strncpy_from_user(dst, src, count, max); - } - return -EFAULT; -} -EXPORT_SYMBOL(strncpy_from_user); diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 883b216c60b2..1781b2f950e2 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -95,47 +95,6 @@ __clear_user(void __user *to, unsigned long n) } EXPORT_SYMBOL(__clear_user); -/** - * strnlen_user: - Get the size of a string in user space. - * @s: The string to measure. - * @n: The maximum valid length - * - * Get the size of a NUL-terminated string in user space. - * - * Returns the size of the string INCLUDING the terminating NUL. - * On exception, returns 0. - * If the string is too long, returns a value greater than @n. - */ -long strnlen_user(const char __user *s, long n) -{ - unsigned long mask = -__addr_ok(s); - unsigned long res, tmp; - - might_fault(); - - __asm__ __volatile__( - " testl %0, %0\n" - " jz 3f\n" - " andl %0,%%ecx\n" - "0: repne; scasb\n" - " setne %%al\n" - " subl %%ecx,%0\n" - " addl %0,%%eax\n" - "1:\n" - ".section .fixup,\"ax\"\n" - "2: xorl %%eax,%%eax\n" - " jmp 1b\n" - "3: movb $1,%%al\n" - " jmp 1b\n" - ".previous\n" - _ASM_EXTABLE(0b,2b) - :"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp) - :"0" (n), "1" (s), "2" (0), "3" (mask) - :"cc"); - return res & mask; -} -EXPORT_SYMBOL(strnlen_user); - #ifdef CONFIG_X86_INTEL_USERCOPY static unsigned long __copy_user_intel(void __user *to, const void *from, unsigned long size) diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 0d0326f388c0..e5b130bc2d0e 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -52,54 +52,6 @@ unsigned long clear_user(void __user *to, unsigned long n) } EXPORT_SYMBOL(clear_user); -/* - * Return the size of a string (including the ending 0) - * - * Return 0 on exception, a value greater than N if too long - */ - -long __strnlen_user(const char __user *s, long n) -{ - long res = 0; - char c; - - while (1) { - if (res>n) - return n+1; - if (__get_user(c, s)) - return 0; - if (!c) - return res+1; - res++; - s++; - } -} -EXPORT_SYMBOL(__strnlen_user); - -long strnlen_user(const char __user *s, long n) -{ - if (!access_ok(VERIFY_READ, s, 1)) - return 0; - return __strnlen_user(s, n); -} -EXPORT_SYMBOL(strnlen_user); - -long strlen_user(const char __user *s) -{ - long res = 0; - char c; - - for (;;) { - if (get_user(c, s)) - return 0; - if (!c) - return res+1; - res++; - s++; - } -} -EXPORT_SYMBOL(strlen_user); - unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len) { if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { |