diff options
191 files changed, 7007 insertions, 1707 deletions
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index bae0d87a38b2..5573c08d3180 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -50,6 +50,11 @@ Optional regions, used when the GIC doesn't have banked registers. The offset is cpu-offset * cpu-nr. +- arm,routable-irqs : Total number of gic irq inputs which are not directly + connected from the peripherals, but are routed dynamically + by a crossbar/multiplexer preceding the GIC. The GIC irq + input line is assigned dynamically when the corresponding + peripheral's crossbar line is mapped. Example: intc: interrupt-controller@fff11000 { @@ -57,6 +62,7 @@ Example: #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; + arm,routable-irqs = <160>; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; }; diff --git a/Documentation/devicetree/bindings/arm/omap/crossbar.txt b/Documentation/devicetree/bindings/arm/omap/crossbar.txt new file mode 100644 index 000000000000..fb88585cfb93 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/omap/crossbar.txt @@ -0,0 +1,27 @@ +Some socs have a large number of interrupts requests to service +the needs of its many peripherals and subsystems. All of the +interrupt lines from the subsystems are not needed at the same +time, so they have to be muxed to the irq-controller appropriately. +In such places a interrupt controllers are preceded by an CROSSBAR +that provides flexibility in muxing the device requests to the controller +inputs. + +Required properties: +- compatible : Should be "ti,irq-crossbar" +- reg: Base address and the size of the crossbar registers. +- ti,max-irqs: Total number of irqs available at the interrupt controller. +- ti,reg-size: Size of a individual register in bytes. Every individual + register is assumed to be of same size. Valid sizes are 1, 2, 4. +- ti,irqs-reserved: List of the reserved irq lines that are not muxed using + crossbar. These interrupt lines are reserved in the soc, + so crossbar bar driver should not consider them as free + lines. + +Examples: + crossbar_mpu: @4a020000 { + compatible = "ti,irq-crossbar"; + reg = <0x4a002a48 0x130>; + ti,max-irqs = <160>; + ti,reg-size = <2>; + ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>; + }; diff --git a/Documentation/devicetree/bindings/clock/arm-integrator.txt b/Documentation/devicetree/bindings/clock/arm-integrator.txt new file mode 100644 index 000000000000..652914b17b95 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/arm-integrator.txt @@ -0,0 +1,34 @@ +Clock bindings for ARM Integrator Core Module clocks + +Auxilary Oscillator Clock + +This is a configurable clock fed from a 24 MHz chrystal, +used for generating e.g. video clocks. It is located on the +core module and there is only one of these. + +This clock node *must* be a subnode of the core module, since +it obtains the base address for it's address range from its +parent node. + + +Required properties: +- compatible: must be "arm,integrator-cm-auxosc" +- #clock-cells: must be <0> + +Optional properties: +- clocks: parent clock(s) + +Example: + +core-module@10000000 { + xtal24mhz: xtal24mhz@24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + auxosc: cm_aux_osc@25M { + #clock-cells = <0>; + compatible = "arm,integrator-cm-auxosc"; + clocks = <&xtal24mhz>; + }; +}; diff --git a/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt new file mode 100644 index 000000000000..4897bea7e3f8 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt @@ -0,0 +1,23 @@ +* Altera SOCFPGA specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Altera SOCFPGA specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "altr,socfpga-dw-mshc": for Altera's SOCFPGA platform + +Example: + + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 129 4>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt new file mode 100644 index 000000000000..d53d3765b2c6 --- /dev/null +++ b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt @@ -0,0 +1,35 @@ +Altera SOCFPGA SoC DWMAC controller + +The device node has following properties. + +Required properties: + - compatible : Should contain "altr,socfpga-stmmac" + - altr,sysmgr-syscon : Should be the phandle to the system manager node that + encompasses the glue register, and the register offset. + +Sub-nodes: +The dwmac core should be added as subnode to SOCFPGA dwmac glue. +- dwmac : The binding details of dwmac can be found in + Documentation/devicetree/bindings/net/stmmac.txt + +Example: + +ethernet0: ethernet0 { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "altr,socfpga-stmmac"; + altr,sysmgr-syscon = <&sysmgr 0x60>; + status = "disabled"; + ranges; + + gmac0: gmac0@ff700000 { + compatible = "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff700000 0x2000>; + interrupts = <0 115 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac0_clk>; + clock-names = "stmmaceth"; + }; +}; diff --git a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt index 0347d8350d94..af25e77c0e0c 100644 --- a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt +++ b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt @@ -6,8 +6,11 @@ Orion5x SoCs. Sending the character 'A', at 19200 baud, tells the microcontroller to turn the power off. This driver adds a handler to pm_power_off which is called to turn the power off. +Synology NAS devices use a similar scheme, but a different baud rate, +9600, and a different character, '1'. + Required Properties: -- compatible: Should be "qnap,power-off" +- compatible: Should be "qnap,power-off" or "synology,power-off" - reg: Address and length of the register set for UART1 - clocks: tclk clock diff --git a/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt new file mode 100644 index 000000000000..5ab26b7e9d35 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt @@ -0,0 +1,47 @@ +STMicroelectronics STi family Sysconfig Peripheral Powerdown Reset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip peripheral controllers such as USB and SATA, using +"powerdown" control bits found in the STi family SoC system configuration +registers. These have been grouped together into a single reset controller +device for convenience. + +The actual action taken when powerdown is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "st,<chip>-powerdown" + ex: "st,stih415-powerdown", "st,stih416-powerdown" +- #reset-cells: 1, see below + +example: + + powerdown: powerdown-controller { + #reset-cells = <1>; + compatible = "st,stih415-powerdown"; + }; + + +Specifying powerdown control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the powerdown device node and an +index specifying which channel to use, as described in reset.txt + +example: + + usb1: usb@fe200000 { + resets = <&powerdown STIH41X_USB1_POWERDOWN>; + }; + +Macro definitions for the supported reset channels can be found in: + +include/dt-bindings/reset-controller/stih415-resets.h +include/dt-bindings/reset-controller/stih416-resets.h diff --git a/Documentation/devicetree/bindings/reset/st,sti-softreset.txt b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt new file mode 100644 index 000000000000..a8d3d3c25ca2 --- /dev/null +++ b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt @@ -0,0 +1,46 @@ +STMicroelectronics STi family Sysconfig Peripheral SoftReset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip peripheral controllers such as USB and SATA, using +"softreset" control bits found in the STi family SoC system configuration +registers. + +The actual action taken when softreset is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "st,<chip>-softreset" example: + "st,stih415-softreset" or "st,stih416-softreset"; +- #reset-cells: 1, see below + +example: + + softreset: softreset-controller { + #reset-cells = <1>; + compatible = "st,stih415-softreset"; + }; + + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the softreset device node and an +index specifying which channel to use, as described in reset.txt + +example: + + ethernet0{ + resets = <&softreset STIH415_ETH0_SOFTRESET>; + }; + +Macro definitions for the supported reset channels can be found in: + +include/dt-bindings/reset-controller/stih415-resets.h +include/dt-bindings/reset-controller/stih416-resets.h diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt index 5dc8d30061ce..de11eb4c121f 100644 --- a/Documentation/devicetree/bindings/watchdog/marvel.txt +++ b/Documentation/devicetree/bindings/watchdog/marvel.txt @@ -3,17 +3,24 @@ Required Properties: - Compatibility : "marvell,orion-wdt" -- reg : Address of the timer registers + "marvell,armada-370-wdt" + "marvell,armada-xp-wdt" + +- reg : Should contain two entries: first one with the + timer control address, second one with the + rstout enable address. Optional properties: +- interrupts : Contains the IRQ for watchdog expiration - timeout-sec : Contains the watchdog timeout in seconds Example: wdt@20300 { compatible = "marvell,orion-wdt"; - reg = <0x20300 0x28>; + reg = <0x20300 0x28>, <0x20108 0x4>; + interrupts = <3>; timeout-sec = <10>; status = "okay"; }; diff --git a/MAINTAINERS b/MAINTAINERS index fb08dcececf1..9dbf7f1898c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1167,6 +1167,14 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) W: http://www.arm.linux.org.uk/ S: Maintained +ARM/QUALCOMM SUPPORT +M: Kumar Gala <galak@codeaurora.org> +M: David Brown <davidb@codeaurora.org> +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: arch/arm/mach-qcom/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/galak/linux-qcom.git + ARM/RADISYS ENP2611 MACHINE SUPPORT M: Lennert Buytenhek <kernel@wantstofly.org> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 25a6b53436fc..ffb884c4a269 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -659,9 +659,8 @@ config ARCH_PXA help Support for Intel/Marvell's PXA2xx/PXA3xx processor line. -config ARCH_MSM_NODT - bool "Qualcomm MSM" - select ARCH_MSM +config ARCH_MSM + bool "Qualcomm MSM (non-multiplatform)" select ARCH_REQUIRE_GPIOLIB select COMMON_CLK select GENERIC_CLOCKEVENTS @@ -1016,6 +1015,8 @@ source "arch/arm/plat-pxa/Kconfig" source "arch/arm/mach-mmp/Kconfig" +source "arch/arm/mach-qcom/Kconfig" + source "arch/arm/mach-realview/Kconfig" source "arch/arm/mach-rockchip/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 0531da8e5216..4491c7b05275 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -956,7 +956,7 @@ config DEBUG_STI_UART config DEBUG_MSM_UART bool - depends on ARCH_MSM + depends on ARCH_MSM || ARCH_QCOM config DEBUG_LL_INCLUDE string diff --git a/arch/arm/Makefile b/arch/arm/Makefile index a3c06ddbe3e4..dd1bd7ed77be 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -180,6 +180,7 @@ machine-$(CONFIG_ARCH_OMAP2PLUS) += omap2 machine-$(CONFIG_ARCH_ORION5X) += orion5x machine-$(CONFIG_ARCH_PICOXCELL) += picoxcell machine-$(CONFIG_ARCH_PXA) += pxa +machine-$(CONFIG_ARCH_QCOM) += qcom machine-$(CONFIG_ARCH_REALVIEW) += realview machine-$(CONFIG_ARCH_ROCKCHIP) += rockchip machine-$(CONFIG_ARCH_RPC) += rpc diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 6d1e43d46187..3269029a1ce6 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -119,9 +119,6 @@ dtb-$(CONFIG_ARCH_KIRKWOOD) += kirkwood-cloudbox.dtb \ kirkwood-ts219-6282.dtb dtb-$(CONFIG_ARCH_MARCO) += marco-evb.dtb dtb-$(CONFIG_ARCH_MOXART) += moxart-uc7112lx.dtb -dtb-$(CONFIG_ARCH_MSM) += qcom-msm8660-surf.dtb \ - qcom-msm8960-cdp.dtb \ - qcom-apq8074-dragonboard.dtb dtb-$(CONFIG_ARCH_MVEBU) += armada-370-db.dtb \ armada-370-mirabox.dtb \ armada-370-netgear-rn102.dtb \ @@ -233,6 +230,9 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ dra7-evm.dtb dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-ethernet-disk-mini-v2.dtb dtb-$(CONFIG_ARCH_PRIMA2) += prima2-evb.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcom-msm8660-surf.dtb \ + qcom-msm8960-cdp.dtb \ + qcom-apq8074-dragonboard.dtb dtb-$(CONFIG_ARCH_U8500) += ste-snowball.dtb \ ste-hrefprev60-stuib.dtb \ ste-hrefprev60-tvk.dtb \ diff --git a/arch/arm/boot/dts/integratorap.dts b/arch/arm/boot/dts/integratorap.dts index e6be9315ff0a..b10e6351da53 100644 --- a/arch/arm/boot/dts/integratorap.dts +++ b/arch/arm/boot/dts/integratorap.dts @@ -18,6 +18,28 @@ bootargs = "root=/dev/ram0 console=ttyAM0,38400n8 earlyprintk"; }; + /* 24 MHz chrystal on the core module */ + xtal24mhz: xtal24mhz@24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + pclk: pclk@0 { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clock-div = <1>; + clock-mult = <1>; + clocks = <&xtal24mhz>; + }; + + /* The UART clock is 14.74 MHz divided by an ICS525 */ + uartclk: uartclk@14.74M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <14745600>; + }; + syscon { compatible = "arm,integrator-ap-syscon"; reg = <0x11000000 0x100>; @@ -28,14 +50,17 @@ timer0: timer@13000000 { compatible = "arm,integrator-timer"; + clocks = <&xtal24mhz>; }; timer1: timer@13000100 { compatible = "arm,integrator-timer"; + clocks = <&xtal24mhz>; }; timer2: timer@13000200 { compatible = "arm,integrator-timer"; + clocks = <&xtal24mhz>; }; pic: pic@14000000 { @@ -92,26 +117,36 @@ rtc: rtc@15000000 { compatible = "arm,pl030", "arm,primecell"; arm,primecell-periphid = <0x00041030>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; uart0: uart@16000000 { compatible = "arm,pl010", "arm,primecell"; arm,primecell-periphid = <0x00041010>; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; }; uart1: uart@17000000 { compatible = "arm,pl010", "arm,primecell"; arm,primecell-periphid = <0x00041010>; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; }; kmi0: kmi@18000000 { compatible = "arm,pl050", "arm,primecell"; arm,primecell-periphid = <0x00041050>; + clocks = <&xtal24mhz>, <&pclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; kmi1: kmi@19000000 { compatible = "arm,pl050", "arm,primecell"; arm,primecell-periphid = <0x00041050>; + clocks = <&xtal24mhz>, <&pclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; }; }; diff --git a/arch/arm/boot/dts/integratorcp.dts b/arch/arm/boot/dts/integratorcp.dts index a21c17de9a5e..d43f15b4f79a 100644 --- a/arch/arm/boot/dts/integratorcp.dts +++ b/arch/arm/boot/dts/integratorcp.dts @@ -13,25 +13,107 @@ bootargs = "root=/dev/ram0 console=ttyAMA0,38400n8 earlyprintk"; }; + /* + * The Integrator/CP overall clocking architecture can be found in + * ARM DUI 0184B page 7-28 "Integrator/CP922T system clocks" which + * appear to illustrate the layout used in most configurations. + */ + + /* The codec chrystal operates at 24.576 MHz */ + xtal_codec: xtal24.576@24.576M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24576000>; + }; + + /* The chrystal is divided by 2 by the codec for the AACI bit clock */ + aaci_bitclk: aaci_bitclk@12.288M { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clock-div = <2>; + clock-mult = <1>; + clocks = <&xtal_codec>; + }; + + /* This is a 25MHz chrystal on the base board */ + xtal25mhz: xtal25mhz@25M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + /* The UART clock is 14.74 MHz divided from 25MHz by an ICS525 */ + uartclk: uartclk@14.74M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <14745600>; + }; + + /* Actually sysclk I think */ + pclk: pclk@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <0>; + }; + + core-module@10000000 { + /* 24 MHz chrystal on the core module */ + xtal24mhz: xtal24mhz@24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + + /* + * External oscillator on the core module, usually used + * to drive video circuitry. Driven from the 24MHz clock. + */ + auxosc: cm_aux_osc@25M { + #clock-cells = <0>; + compatible = "arm,integrator-cm-auxosc"; + clocks = <&xtal24mhz>; + }; + + /* The KMI clock is the 24 MHz oscillator divided to 8MHz */ + kmiclk: kmiclk@1M { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clock-div = <3>; + clock-mult = <1>; + clocks = <&xtal24mhz>; + }; + + /* The timer clock is the 24 MHz oscillator divided to 1MHz */ + timclk: timclk@1M { + #clock-cells = <0>; + compatible = "fixed-factor-clock"; + clock-div = <24>; + clock-mult = <1>; + clocks = <&xtal24mhz>; + }; + }; + syscon { compatible = "arm,integrator-cp-syscon"; reg = <0xcb000000 0x100>; }; timer0: timer@13000000 { - /* TIMER0 runs @ 25MHz */ + /* TIMER0 runs directly on the 25MHz chrystal */ compatible = "arm,integrator-cp-timer"; - status = "disabled"; + clocks = <&xtal25mhz>; }; timer1: timer@13000100 { /* TIMER1 runs @ 1MHz */ compatible = "arm,integrator-cp-timer"; + clocks = <&timclk>; }; timer2: timer@13000200 { /* TIMER2 runs @ 1MHz */ compatible = "arm,integrator-cp-timer"; + clocks = <&timclk>; }; pic: pic@14000000 { @@ -74,22 +156,32 @@ */ rtc@15000000 { compatible = "arm,pl031", "arm,primecell"; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; uart@16000000 { compatible = "arm,pl011", "arm,primecell"; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; }; uart@17000000 { compatible = "arm,pl011", "arm,primecell"; + clocks = <&uartclk>, <&pclk>; + clock-names = "uartclk", "apb_pclk"; }; kmi@18000000 { compatible = "arm,pl050", "arm,primecell"; + clocks = <&kmiclk>, <&pclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; kmi@19000000 { compatible = "arm,pl050", "arm,primecell"; + clocks = <&kmiclk>, <&pclk>; + clock-names = "KMIREFCLK", "apb_pclk"; }; /* @@ -100,18 +192,24 @@ reg = <0x1c000000 0x1000>; interrupts = <23 24>; max-frequency = <515633>; + clocks = <&uartclk>, <&pclk>; + clock-names = "mclk", "apb_pclk"; }; aaci@1d000000 { compatible = "arm,pl041", "arm,primecell"; reg = <0x1d000000 0x1000>; interrupts = <25>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; clcd@c0000000 { compatible = "arm,pl110", "arm,primecell"; reg = <0xC0000000 0x1000>; interrupts = <22>; + clocks = <&auxosc>, <&pclk>; + clock-names = "clcd", "apb_pclk"; }; }; }; diff --git a/arch/arm/boot/dts/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom-msm8660-surf.dts index 68a72f5507b9..169bad90dac9 100644 --- a/arch/arm/boot/dts/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom-msm8660-surf.dts @@ -1,63 +1,6 @@ -/dts-v1/; - -/include/ "skeleton.dtsi" - -#include <dt-bindings/clock/qcom,gcc-msm8660.h> +#include "qcom-msm8660.dtsi" / { model = "Qualcomm MSM8660 SURF"; compatible = "qcom,msm8660-surf", "qcom,msm8660"; - interrupt-parent = <&intc>; - - intc: interrupt-controller@2080000 { - compatible = "qcom,msm-8660-qgic"; - interrupt-controller; - #interrupt-cells = <3>; - reg = < 0x02080000 0x1000 >, - < 0x02081000 0x1000 >; - }; - - timer@2000000 { - compatible = "qcom,scss-timer", "qcom,msm-timer"; - interrupts = <1 0 0x301>, - <1 1 0x301>, - <1 2 0x301>; - reg = <0x02000000 0x100>; - clock-frequency = <27000000>, - <32768>; - cpu-offset = <0x40000>; - }; - - msmgpio: gpio@800000 { - compatible = "qcom,msm-gpio"; - reg = <0x00800000 0x4000>; - gpio-controller; - #gpio-cells = <2>; - ngpio = <173>; - interrupts = <0 16 0x4>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gcc: clock-controller@900000 { - compatible = "qcom,gcc-msm8660"; - #clock-cells = <1>; - #reset-cells = <1>; - reg = <0x900000 0x4000>; - }; - - serial@19c40000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x19c40000 0x1000>, - <0x19c00000 0x1000>; - interrupts = <0 195 0x0>; - clocks = <&gcc GSBI12_UART_CLK>, <&gcc GSBI12_H_CLK>; - clock-names = "core", "iface"; - }; - - qcom,ssbi@500000 { - compatible = "qcom,ssbi"; - reg = <0x500000 0x1000>; - qcom,controller-type = "pmic-arbiter"; - }; }; diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi new file mode 100644 index 000000000000..69d6c4edea30 --- /dev/null +++ b/arch/arm/boot/dts/qcom-msm8660.dtsi @@ -0,0 +1,63 @@ +/dts-v1/; + +/include/ "skeleton.dtsi" + +#include <dt-bindings/clock/qcom,gcc-msm8660.h> + +/ { + model = "Qualcomm MSM8660"; + compatible = "qcom,msm8660"; + interrupt-parent = <&intc>; + + intc: interrupt-controller@2080000 { + compatible = "qcom,msm-8660-qgic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = < 0x02080000 0x1000 >, + < 0x02081000 0x1000 >; + }; + + timer@2000000 { + compatible = "qcom,scss-timer", "qcom,msm-timer"; + interrupts = <1 0 0x301>, + <1 1 0x301>, + <1 2 0x301>; + reg = <0x02000000 0x100>; + clock-frequency = <27000000>, + <32768>; + cpu-offset = <0x40000>; + }; + + msmgpio: gpio@800000 { + compatible = "qcom,msm-gpio"; + reg = <0x00800000 0x4000>; + gpio-controller; + #gpio-cells = <2>; + ngpio = <173>; + interrupts = <0 16 0x4>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gcc: clock-controller@900000 { + compatible = "qcom,gcc-msm8660"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0x900000 0x4000>; + }; + + serial@19c40000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x19c40000 0x1000>, + <0x19c00000 0x1000>; + interrupts = <0 195 0x0>; + clocks = <&gcc GSBI12_UART_CLK>, <&gcc GSBI12_H_CLK>; + clock-names = "core", "iface"; + }; + + qcom,ssbi@500000 { + compatible = "qcom,ssbi"; + reg = <0x500000 0x1000>; + qcom,controller-type = "pmic-arbiter"; + }; +}; diff --git a/arch/arm/boot/dts/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom-msm8960-cdp.dts index 7c30de4fa302..a58fb88315f6 100644 --- a/arch/arm/boot/dts/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom-msm8960-cdp.dts @@ -1,70 +1,6 @@ -/dts-v1/; - -/include/ "skeleton.dtsi" - -#include <dt-bindings/clock/qcom,gcc-msm8960.h> +#include "qcom-msm8960.dtsi" / { model = "Qualcomm MSM8960 CDP"; compatible = "qcom,msm8960-cdp", "qcom,msm8960"; - interrupt-parent = <&intc>; - - intc: interrupt-controller@2000000 { - compatible = "qcom,msm-qgic2"; - interrupt-controller; - #interrupt-cells = <3>; - reg = < 0x02000000 0x1000 >, - < 0x02002000 0x1000 >; - }; - - timer@200a000 { - compatible = "qcom,kpss-timer", "qcom,msm-timer"; - interrupts = <1 1 0x301>, - <1 2 0x301>, - <1 3 0x301>; - reg = <0x0200a000 0x100>; - clock-frequency = <27000000>, - <32768>; - cpu-offset = <0x80000>; - }; - - msmgpio: gpio@800000 { - compatible = "qcom,msm-gpio"; - gpio-controller; - #gpio-cells = <2>; - ngpio = <150>; - interrupts = <0 16 0x4>; - interrupt-controller; - #interrupt-cells = <2>; - reg = <0x800000 0x4000>; - }; - - gcc: clock-controller@900000 { - compatible = "qcom,gcc-msm8960"; - #clock-cells = <1>; - #reset-cells = <1>; - reg = <0x900000 0x4000>; - }; - - clock-controller@4000000 { - compatible = "qcom,mmcc-msm8960"; - reg = <0x4000000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - serial@16440000 { - compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; - reg = <0x16440000 0x1000>, - <0x16400000 0x1000>; - interrupts = <0 154 0x0>; - clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; - clock-names = "core", "iface"; - }; - - qcom,ssbi@500000 { - compatible = "qcom,ssbi"; - reg = <0x500000 0x1000>; - qcom,controller-type = "pmic-arbiter"; - }; }; diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-msm8960.dtsi new file mode 100644 index 000000000000..ff002826552a --- /dev/null +++ b/arch/arm/boot/dts/qcom-msm8960.dtsi @@ -0,0 +1,70 @@ +/dts-v1/; + +/include/ "skeleton.dtsi" + +#include <dt-bindings/clock/qcom,gcc-msm8960.h> + +/ { + model = "Qualcomm MSM8960"; + compatible = "qcom,msm8960"; + interrupt-parent = <&intc>; + + intc: interrupt-controller@2000000 { + compatible = "qcom,msm-qgic2"; + interrupt-controller; + #interrupt-cells = <3>; + reg = < 0x02000000 0x1000 >, + < 0x02002000 0x1000 >; + }; + + timer@200a000 { + compatible = "qcom,kpss-timer", "qcom,msm-timer"; + interrupts = <1 1 0x301>, + <1 2 0x301>, + <1 3 0x301>; + reg = <0x0200a000 0x100>; + clock-frequency = <27000000>, + <32768>; + cpu-offset = <0x80000>; + }; + + msmgpio: gpio@800000 { + compatible = "qcom,msm-gpio"; + gpio-controller; + #gpio-cells = <2>; + ngpio = <150>; + interrupts = <0 16 0x4>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x800000 0x4000>; + }; + + gcc: clock-controller@900000 { + compatible = "qcom,gcc-msm8960"; + #clock-cells = <1>; + #reset-cells = <1>; + reg = <0x900000 0x4000>; + }; + + clock-controller@4000000 { + compatible = "qcom,mmcc-msm8960"; + reg = <0x4000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + serial@16440000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x16440000 0x1000>, + <0x16400000 0x1000>; + interrupts = <0 154 0x0>; + clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>; + clock-names = "core", "iface"; + }; + + qcom,ssbi@500000 { + compatible = "qcom,ssbi"; + reg = <0x500000 0x1000>; + qcom,controller-type = "pmic-arbiter"; + }; +}; diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index 71b1251f79c7..67a6d968cebb 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -313,6 +313,29 @@ clock-output-names = "extal"; }; + /* + * The external audio clocks are configured as 0 Hz fixed frequency clocks by + * default. Boards that provide audio clocks should override them. + */ + audio_clk_a: audio_clk_a { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "audio_clk_a"; + }; + audio_clk_b: audio_clk_b { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "audio_clk_b"; + }; + audio_clk_c: audio_clk_c { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "audio_clk_c"; + }; + /* Special CPG clocks */ cpg_clocks: cpg_clocks@e6150000 { compatible = "renesas,r8a7790-cpg-clocks", diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 537f1a5c07f5..404553c97f31 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -92,7 +92,12 @@ #address-cells = <1>; #size-cells = <0>; - osc: osc1 { + osc1: osc1 { + #clock-cells = <0>; + compatible = "fixed-clock"; + }; + + osc2: osc2 { #clock-cells = <0>; compatible = "fixed-clock"; }; @@ -100,7 +105,11 @@ f2s_periph_ref_clk: f2s_periph_ref_clk { #clock-cells = <0>; compatible = "fixed-clock"; - clock-frequency = <10000000>; + }; + + f2s_sdram_ref_clk: f2s_sdram_ref_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; }; main_pll: main_pll { @@ -108,7 +117,7 @@ #size-cells = <0>; #clock-cells = <0>; compatible = "altr,socfpga-pll-clock"; - clocks = <&osc>; + clocks = <&osc1>; reg = <0x40>; mpuclk: mpuclk { @@ -162,7 +171,7 @@ #size-cells = <0>; #clock-cells = <0>; compatible = "altr,socfpga-pll-clock"; - clocks = <&osc>; + clocks = <&osc1>, <&osc2>, <&f2s_periph_ref_clk>; reg = <0x80>; emac0_clk: emac0_clk { @@ -213,7 +222,7 @@ #size-cells = <0>; #clock-cells = <0>; compatible = "altr,socfpga-pll-clock"; - clocks = <&osc>; + clocks = <&osc1>, <&osc2>, <&f2s_sdram_ref_clk>; reg = <0xC0>; ddr_dqs_clk: ddr_dqs_clk { @@ -441,26 +450,43 @@ }; }; - gmac0: ethernet@ff700000 { - compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0xff700000 0x2000>; - interrupts = <0 115 4>; - interrupt-names = "macirq"; - mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - clocks = <&emac0_clk>; - clock-names = "stmmaceth"; + ethernet0: ethernet0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,socfpga-stmmac"; + altr,sysmgr-syscon = <&sysmgr 0x60>; status = "disabled"; + ranges; + + gmac0: gmac0@ff700000 { + compatible = "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff700000 0x2000>; + interrupts = <0 115 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac0_clk>; + clock-names = "stmmaceth"; + }; }; - gmac1: ethernet@ff702000 { - compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0xff702000 0x2000>; - interrupts = <0 120 4>; - interrupt-names = "macirq"; - mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - clocks = <&emac1_clk>; - clock-names = "stmmaceth"; + ethernet1: ethernet1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,socfpga-stmmac"; + altr,sysmgr-syscon = <&sysmgr 0x60>; status = "disabled"; + ranges; + + gmac1: gmac1@ff702000 { + device_type = "network"; + compatible = "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff702000 0x2000>; + interrupts = <0 120 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac1_clk>; + clock-names = "stmmaceth"; + }; }; L2: l2-cache@fffef000 { @@ -473,6 +499,17 @@ arm,data-latency = <2 1 1>; }; + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 139 4>; + fifo-depth = <0x400>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&l4_mp_clk>, <&sdmmc_clk>; + clock-names = "biu", "ciu"; + }; + /* Local timer */ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; @@ -526,9 +563,9 @@ reg = <0xffd05000 0x1000>; }; - sysmgr@ffd08000 { - compatible = "altr,sys-mgr"; - reg = <0xffd08000 0x4000>; - }; + sysmgr: sysmgr@ffd08000 { + compatible = "altr,sys-mgr", "syscon"; + reg = <0xffd08000 0x4000>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi index a85b4043f888..6c87b7070ca7 100644 --- a/arch/arm/boot/dts/socfpga_arria5.dtsi +++ b/arch/arm/boot/dts/socfpga_arria5.dtsi @@ -27,6 +27,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + serial0@ffc02000 { clock-frequency = <100000000>; }; diff --git a/arch/arm/boot/dts/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/socfpga_arria5_socdk.dts index 5beffb2265f4..2d6b38ba9370 100644 --- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts @@ -37,4 +37,28 @@ */ ethernet0 = &gmac1; }; + + aliases { + /* this allow the ethaddr uboot environmnet variable contents + * to be added to the gmac1 device tree blob. + */ + ethernet0 = &gmac1; + }; +}; + +ðernet1 { + status = "okay"; +}; + +&gmac1 { + phy-mode = "rgmii"; + + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txen-skew-ps = <0>; + txc-skew-ps = <2600>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <2000>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi index a8716f6dbe2e..ca41b0ebf461 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi @@ -28,6 +28,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + ethernet@ff702000 { phy-mode = "rgmii"; phy-addr = <0xffffffff>; /* probe for phy addr */ diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts index 2ee52ab8cabb..26c63a07f8b9 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts @@ -38,3 +38,20 @@ ethernet0 = &gmac1; }; }; + +ðernet1 { + status = "okay"; +}; + +&gmac1 { + phy-mode = "rgmii"; + + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txen-skew-ps = <0>; + txc-skew-ps = <2600>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <2000>; +}; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts index 50b99a2c12ae..469bb5cac886 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts @@ -30,8 +30,28 @@ device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ }; + + aliases { + /* this allow the ethaddr uboot environmnet variable contents + * to be added to the gmac1 device tree blob. + */ + ethernet0 = &gmac1; + }; }; -&gmac1 { +ðernet1 { status = "okay"; }; + +&gmac1 { + phy-mode = "rgmii"; + + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txen-skew-ps = <0>; + txc-skew-ps = <2600>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <2000>; +}; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index d1ec0cab2dee..91f6ccf714ee 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -41,6 +41,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + ethernet@ff700000 { phy-mode = "gmii"; status = "okay"; @@ -75,3 +86,11 @@ }; }; }; + +ðernet0 { + status = "okay"; +}; + +&gmac0 { + phy-mode = "gmii"; +}; diff --git a/arch/arm/boot/dts/stih415-clock.dtsi b/arch/arm/boot/dts/stih415-clock.dtsi index 174c799df741..d047dbc28d61 100644 --- a/arch/arm/boot/dts/stih415-clock.dtsi +++ b/arch/arm/boot/dts/stih415-clock.dtsi @@ -34,5 +34,19 @@ compatible = "fixed-clock"; clock-frequency = <100000000>; }; + + CLKS_GMAC0_PHY: clockgenA1@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLKS_GMAC0_PHY"; + }; + + CLKS_ETH1_PHY: clockgenA0@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLKS_ETH1_PHY"; + }; }; }; diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi index e56449d41481..f09fb10a3791 100644 --- a/arch/arm/boot/dts/stih415-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi @@ -7,6 +7,7 @@ * publishhed by the Free Software Foundation. */ #include "st-pincfg.h" +#include <dt-bindings/interrupt-controller/arm-gic.h> / { aliases { @@ -45,35 +46,49 @@ #size-cells = <1>; compatible = "st,stih415-sbc-pinctrl"; st,syscfg = <&syscfg_sbc>; + reg = <0xfe61f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 180 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfe610000 0x5000>; PIO0: gpio@fe610000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO0"; }; PIO1: gpio@fe611000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO1"; }; PIO2: gpio@fe612000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO2"; }; PIO3: gpio@fe613000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO3"; }; PIO4: gpio@fe614000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO4"; }; @@ -104,6 +119,64 @@ }; }; }; + + rc{ + pinctrl_ir: ir0 { + st,pins { + ir = <&PIO4 0 ALT2 IN>; + }; + }; + }; + + gmac1 { + pinctrl_mii1: mii1 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txer = <&PIO0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txen = <&PIO0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + col = <&PIO0 7 ALT1 IN BYPASS 1000>; + mdio = <&PIO1 0 ALT1 OUT BYPASS 0>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + crs = <&PIO1 2 ALT1 IN BYPASS 1000>; + mdint = <&PIO1 3 ALT1 IN BYPASS 0>; + rxd0 = <&PIO1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxdv = <&PIO2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT1 IN NICLK 1000 CLK_A>; + }; + }; + + pinctrl_rgmii1: rgmii1-0 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT DE_IO 1000 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT DE_IO 1000 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT DE_IO 1000 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT DE_IO 1000 CLK_A>; + txen = <&PIO0 5 ALT1 OUT DE_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + mdio = <&PIO1 0 ALT1 OUT BYPASS 0>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + rxd0 = <&PIO1 4 ALT1 IN DE_IO 0 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN DE_IO 0 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN DE_IO 0 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN DE_IO 0 CLK_A>; + + rxdv = <&PIO2 0 ALT1 IN DE_IO 500 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT4 OUT NICLK 0 CLK_B>; + + clk125= <&PIO3 7 ALT4 IN NICLK 0 CLK_A>; + }; + }; + }; }; pin-controller-front { @@ -111,53 +184,73 @@ #size-cells = <1>; compatible = "st,stih415-front-pinctrl"; st,syscfg = <&syscfg_front>; + reg = <0xfee0f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 181 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfee00000 0x8000>; PIO5: gpio@fee00000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO5"; }; PIO6: gpio@fee01000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO6"; }; PIO7: gpio@fee02000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO7"; }; PIO8: gpio@fee03000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO8"; }; PIO9: gpio@fee04000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO9"; }; PIO10: gpio@fee05000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO10"; }; PIO11: gpio@fee06000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x6000 0x100>; st,bank-name = "PIO11"; }; PIO12: gpio@fee07000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x7000 0x100>; st,bank-name = "PIO12"; }; @@ -186,41 +279,57 @@ #size-cells = <1>; compatible = "st,stih415-rear-pinctrl"; st,syscfg = <&syscfg_rear>; + reg = <0xfe82f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfe820000 0x8000>; PIO13: gpio@fe820000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO13"; }; PIO14: gpio@fe821000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO14"; }; PIO15: gpio@fe822000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO15"; }; PIO16: gpio@fe823000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO16"; }; PIO17: gpio@fe824000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO17"; }; PIO18: gpio@fe825000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO18"; }; @@ -233,6 +342,77 @@ }; }; }; + + gmac0{ + pinctrl_mii0: mii0 { + st,pins { + mdint = <&PIO13 6 ALT2 IN BYPASS 0>; + txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + + txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + crs = <&PIO15 2 ALT2 IN BYPASS 1000>; + col = <&PIO15 3 ALT2 IN BYPASS 1000>; + mdio = <&PIO15 4 ALT2 OUT BYPASS 3000>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + + rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + phyclk = <&PIO13 5 ALT2 OUT NICLK 1000 CLK_A>; + + }; + }; + + pinctrl_gmii0: gmii0 { + st,pins { + mdint = <&PIO13 6 ALT2 IN BYPASS 0>; + mdio = <&PIO15 4 ALT2 OUT BYPASS 3000>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + + txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd4 = <&PIO14 4 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd5 = <&PIO14 5 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd6 = <&PIO14 6 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + txd7 = <&PIO14 7 ALT2 OUT SE_NICLK_IO 3000 CLK_B>; + + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>; + crs = <&PIO15 2 ALT2 IN BYPASS 1000>; + col = <&PIO15 3 ALT2 IN BYPASS 1000>; + rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + + rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd4 = <&PIO16 4 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd5 = <&PIO16 5 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd6 = <&PIO16 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + rxd7 = <&PIO16 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>; + + rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + clk125 = <&PIO17 6 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO13 5 ALT4 OUT NICLK 0 CLK_B>; + + + }; + }; + }; }; pin-controller-left { @@ -240,23 +420,33 @@ #size-cells = <1>; compatible = "st,stih415-left-pinctrl"; st,syscfg = <&syscfg_left>; + reg = <0xfd6bf080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfd6b0000 0x3000>; PIO100: gpio@fd6b0000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO100"; }; PIO101: gpio@fd6b1000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO101"; }; PIO102: gpio@fd6b2000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO102"; }; @@ -267,35 +457,49 @@ #size-cells = <1>; compatible = "st,stih415-right-pinctrl"; st,syscfg = <&syscfg_right>; + reg = <0xfd33f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfd330000 0x5000>; PIO103: gpio@fd330000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO103"; }; PIO104: gpio@fd331000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO104"; }; PIO105: gpio@fd332000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO105"; }; PIO106: gpio@fd333000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO106"; }; PIO107: gpio@fd334000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO107"; }; diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index d9c7dd1d95a4..d89064c20c8a 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -10,6 +10,7 @@ #include "stih415-clock.dtsi" #include "stih415-pinctrl.dtsi" #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/reset-controller/stih415-resets.h> / { L2: cache-controller { @@ -28,6 +29,16 @@ ranges; compatible = "simple-bus"; + powerdown: powerdown-controller { + #reset-cells = <1>; + compatible = "st,stih415-powerdown"; + }; + + softreset: softreset-controller { + #reset-cells = <1>; + compatible = "st,stih415-softreset"; + }; + syscfg_sbc: sbc-syscfg@fe600000{ compatible = "st,stih415-sbc-syscfg", "syscon"; reg = <0xfe600000 0xb4>; @@ -136,5 +147,64 @@ status = "disabled"; }; + + ethernet0: dwmac@fe810000 { + device_type = "network"; + compatible = "st,stih415-dwmac", "snps,dwmac", "snps,dwmac-3.610"; + status = "disabled"; + + reg = <0xfe810000 0x8000>, <0x148 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + + interrupts = <0 147 0>, <0 148 0>, <0 149 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + resets = <&softreset STIH415_ETH0_SOFTRESET>; + reset-names = "stmmaceth"; + + snps,pbl = <32>; + snps,mixed-burst; + snps,force_sf_dma_mode; + + st,syscon = <&syscfg_rear>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii0>; + clock-names = "stmmaceth"; + clocks = <&CLKS_GMAC0_PHY>; + }; + + ethernet1: dwmac@fef08000 { + device_type = "network"; + compatible = "st,stih415-dwmac", "snps,dwmac", "snps,dwmac-3.610"; + status = "disabled"; + reg = <0xfef08000 0x8000>, <0x74 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + interrupts = <0 150 0>, <0 151 0>, <0 152 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + + snps,pbl = <32>; + snps,mixed-burst; + snps,force_sf_dma_mode; + + st,syscon = <&syscfg_sbc>; + + resets = <&softreset STIH415_ETH1_SOFTRESET>; + reset-names = "stmmaceth"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii1>; + clock-names = "stmmaceth"; + clocks = <&CLKS_ETH1_PHY>; + }; + + rc: rc@fe518000 { + compatible = "st,comms-irb"; + reg = <0xfe518000 0x234>; + interrupts = <0 203 0>; + clocks = <&CLK_SYSIN>; + rx-mode = "infrared"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ir>; + resets = <&softreset STIH415_IRB_SOFTRESET>; + }; }; }; diff --git a/arch/arm/boot/dts/stih416-clock.dtsi b/arch/arm/boot/dts/stih416-clock.dtsi index 7026bf1158d8..a6942c75cbbb 100644 --- a/arch/arm/boot/dts/stih416-clock.dtsi +++ b/arch/arm/boot/dts/stih416-clock.dtsi @@ -37,5 +37,19 @@ clock-frequency = <100000000>; clock-output-names = "CLK_S_ICN_REG_0"; }; + + CLK_S_GMAC0_PHY: clockgenA1@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLK_S_GMAC0_PHY"; + }; + + CLK_S_ETH1_PHY: clockgenA0@7 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "CLK_S_ETH1_PHY"; + }; }; }; diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi index b29ff4ba542c..e7f8b5f4460a 100644 --- a/arch/arm/boot/dts/stih416-pinctrl.dtsi +++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi @@ -8,6 +8,7 @@ * publishhed by the Free Software Foundation. */ #include "st-pincfg.h" +#include <dt-bindings/interrupt-controller/arm-gic.h> / { aliases { @@ -49,46 +50,69 @@ #size-cells = <1>; compatible = "st,stih416-sbc-pinctrl"; st,syscfg = <&syscfg_sbc>; + reg = <0xfe61f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 182 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfe610000 0x6000>; PIO0: gpio@fe610000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO0"; }; PIO1: gpio@fe611000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO1"; }; PIO2: gpio@fe612000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO2"; }; PIO3: gpio@fe613000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO3"; }; PIO4: gpio@fe614000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO4"; }; PIO40: gpio@fe615000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO40"; st,retime-pin-mask = <0x7f>; }; + rc{ + pinctrl_ir: ir0 { + st,pins { + ir = <&PIO4 0 ALT2 IN>; + }; + }; + }; sbc_serial1 { pinctrl_sbc_serial1: sbc_serial1 { st,pins { @@ -115,6 +139,58 @@ }; }; }; + + gmac1 { + pinctrl_mii1: mii1 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txer = <&PIO0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txen = <&PIO0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + col = <&PIO0 7 ALT1 IN BYPASS 1000>; + + mdio = <&PIO1 0 ALT1 OUT BYPASS 1500>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + crs = <&PIO1 2 ALT1 IN BYPASS 1000>; + mdint = <&PIO1 3 ALT1 IN BYPASS 0>; + rxd0 = <&PIO1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>; + + rxdv = <&PIO2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT1 OUT NICLK 0 CLK_A>; + }; + }; + pinctrl_rgmii1: rgmii1-0 { + st,pins { + txd0 = <&PIO0 0 ALT1 OUT DE_IO 500 CLK_A>; + txd1 = <&PIO0 1 ALT1 OUT DE_IO 500 CLK_A>; + txd2 = <&PIO0 2 ALT1 OUT DE_IO 500 CLK_A>; + txd3 = <&PIO0 3 ALT1 OUT DE_IO 500 CLK_A>; + txen = <&PIO0 5 ALT1 OUT DE_IO 0 CLK_A>; + txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>; + + mdio = <&PIO1 0 ALT1 OUT BYPASS 0>; + mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>; + rxd0 = <&PIO1 4 ALT1 IN DE_IO 500 CLK_A>; + rxd1 = <&PIO1 5 ALT1 IN DE_IO 500 CLK_A>; + rxd2 = <&PIO1 6 ALT1 IN DE_IO 500 CLK_A>; + rxd3 = <&PIO1 7 ALT1 IN DE_IO 500 CLK_A>; + + rxdv = <&PIO2 0 ALT1 IN DE_IO 500 CLK_A>; + rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>; + phyclk = <&PIO2 3 ALT4 OUT NICLK 0 CLK_B>; + + clk125= <&PIO3 7 ALT4 IN NICLK 0 CLK_A>; + }; + }; + }; }; pin-controller-front { @@ -122,65 +198,89 @@ #size-cells = <1>; compatible = "st,stih416-front-pinctrl"; st,syscfg = <&syscfg_front>; + reg = <0xfee0f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfee00000 0x10000>; PIO5: gpio@fee00000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO5"; }; PIO6: gpio@fee01000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO6"; }; PIO7: gpio@fee02000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO7"; }; PIO8: gpio@fee03000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO8"; }; PIO9: gpio@fee04000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO9"; }; PIO10: gpio@fee05000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO10"; }; PIO11: gpio@fee06000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x6000 0x100>; st,bank-name = "PIO11"; }; PIO12: gpio@fee07000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x7000 0x100>; st,bank-name = "PIO12"; }; PIO30: gpio@fee08000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x8000 0x100>; st,bank-name = "PIO30"; }; PIO31: gpio@fee09000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x9000 0x100>; st,bank-name = "PIO31"; }; @@ -217,41 +317,57 @@ #size-cells = <1>; compatible = "st,stih416-rear-pinctrl"; st,syscfg = <&syscfg_rear>; + reg = <0xfe82f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfe820000 0x6000>; PIO13: gpio@fe820000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO13"; }; PIO14: gpio@fe821000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO14"; }; PIO15: gpio@fe822000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO15"; }; PIO16: gpio@fe823000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO16"; }; PIO17: gpio@fe824000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO17"; }; PIO18: gpio@fe825000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x5000 0x100>; st,bank-name = "PIO18"; st,retime-pin-mask = <0xf>; @@ -265,6 +381,63 @@ }; }; }; + + gmac0 { + pinctrl_mii0: mii0 { + st,pins { + mdint = <&PIO13 6 ALT2 IN BYPASS 0>; + txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>; + + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>; + crs = <&PIO15 2 ALT2 IN BYPASS 1000>; + col = <&PIO15 3 ALT2 IN BYPASS 1000>; + mdio= <&PIO15 4 ALT2 OUT BYPASS 1500>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + + rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>; + rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + phyclk = <&PIO13 5 ALT2 OUT NICLK 0 CLK_B>; + }; + }; + + pinctrl_gmii0: gmii0 { + st,pins { + }; + }; + pinctrl_rgmii0: rgmii0 { + st,pins { + phyclk = <&PIO13 5 ALT4 OUT NICLK 0 CLK_B>; + txen = <&PIO13 7 ALT2 OUT DE_IO 0 CLK_A>; + txd0 = <&PIO14 0 ALT2 OUT DE_IO 500 CLK_A>; + txd1 = <&PIO14 1 ALT2 OUT DE_IO 500 CLK_A>; + txd2 = <&PIO14 2 ALT2 OUT DE_IO 500 CLK_B>; + txd3 = <&PIO14 3 ALT2 OUT DE_IO 500 CLK_B>; + txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>; + + mdio = <&PIO15 4 ALT2 OUT BYPASS 0>; + mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>; + + rxdv = <&PIO15 6 ALT2 IN DE_IO 500 CLK_A>; + rxd0 =<&PIO16 0 ALT2 IN DE_IO 500 CLK_A>; + rxd1 =<&PIO16 1 ALT2 IN DE_IO 500 CLK_A>; + rxd2 =<&PIO16 2 ALT2 IN DE_IO 500 CLK_A>; + rxd3 =<&PIO16 3 ALT2 IN DE_IO 500 CLK_A>; + rxclk =<&PIO17 0 ALT2 IN NICLK 0 CLK_A>; + + clk125=<&PIO17 6 ALT1 IN NICLK 0 CLK_A>; + }; + }; + }; }; pin-controller-fvdp-fe { @@ -272,23 +445,33 @@ #size-cells = <1>; compatible = "st,stih416-fvdp-fe-pinctrl"; st,syscfg = <&syscfg_fvdp_fe>; + reg = <0xfd6bf080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfd6b0000 0x3000>; PIO100: gpio@fd6b0000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO100"; }; PIO101: gpio@fd6b1000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO101"; }; PIO102: gpio@fd6b2000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO102"; }; @@ -299,29 +482,41 @@ #size-cells = <1>; compatible = "st,stih416-fvdp-lite-pinctrl"; st,syscfg = <&syscfg_fvdp_lite>; + reg = <0xfd33f080 0x4>; + reg-names = "irqmux"; + interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>; + interrupts-names = "irqmux"; ranges = <0 0xfd330000 0x5000>; PIO103: gpio@fd330000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0 0x100>; st,bank-name = "PIO103"; }; PIO104: gpio@fd331000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x1000 0x100>; st,bank-name = "PIO104"; }; PIO105: gpio@fd332000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x2000 0x100>; st,bank-name = "PIO105"; }; PIO106: gpio@fd333000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x3000 0x100>; st,bank-name = "PIO106"; }; @@ -329,6 +524,8 @@ PIO107: gpio@fd334000 { gpio-controller; #gpio-cells = <1>; + interrupt-controller; + #interrupt-cells = <2>; reg = <0x4000 0x100>; st,bank-name = "PIO107"; st,retime-pin-mask = <0xf>; diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index b7ab47b95816..8299a7b8fee8 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -10,6 +10,7 @@ #include "stih416-clock.dtsi" #include "stih416-pinctrl.dtsi" #include <dt-bindings/interrupt-controller/arm-gic.h> +#include <dt-bindings/reset-controller/stih416-resets.h> / { L2: cache-controller { compatible = "arm,pl310-cache"; @@ -27,6 +28,16 @@ ranges; compatible = "simple-bus"; + powerdown: powerdown-controller { + #reset-cells = <1>; + compatible = "st,stih416-powerdown"; + }; + + softreset: softreset-controller { + #reset-cells = <1>; + compatible = "st,stih416-softreset"; + }; + syscfg_sbc:sbc-syscfg@fe600000{ compatible = "st,stih416-sbc-syscfg", "syscon"; reg = <0xfe600000 0x1000>; @@ -145,5 +156,61 @@ status = "disabled"; }; + + ethernet0: dwmac@fe810000 { + device_type = "network"; + compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710"; + status = "disabled"; + reg = <0xfe810000 0x8000>, <0x8bc 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + + interrupts = <0 133 0>, <0 134 0>, <0 135 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + + snps,pbl = <32>; + snps,mixed-burst; + + st,syscon = <&syscfg_rear>; + resets = <&softreset STIH416_ETH0_SOFTRESET>; + reset-names = "stmmaceth"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii0>; + clock-names = "stmmaceth"; + clocks = <&CLK_S_GMAC0_PHY>; + }; + + ethernet1: dwmac@fef08000 { + device_type = "network"; + compatible = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710"; + status = "disabled"; + reg = <0xfef08000 0x8000>, <0x7f0 0x4>; + reg-names = "stmmaceth", "sti-ethconf"; + interrupts = <0 136 0>, <0 137 0>, <0 138 0>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + + snps,pbl = <32>; + snps,mixed-burst; + + st,syscon = <&syscfg_sbc>; + + resets = <&softreset STIH416_ETH1_SOFTRESET>; + reset-names = "stmmaceth"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mii1>; + clock-names = "stmmaceth"; + clocks = <&CLK_S_ETH1_PHY>; + }; + + rc: rc@fe518000 { + compatible = "st,comms-irb"; + reg = <0xfe518000 0x234>; + interrupts = <0 203 0>; + rx-mode = "infrared"; + clocks = <&CLK_SYSIN>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ir>; + resets = <&softreset STIH416_IRB_SOFTRESET>; + }; + }; }; diff --git a/arch/arm/boot/dts/stih41x-b2000.dtsi b/arch/arm/boot/dts/stih41x-b2000.dtsi index 1e6aa92772f5..bf65c49095af 100644 --- a/arch/arm/boot/dts/stih41x-b2000.dtsi +++ b/arch/arm/boot/dts/stih41x-b2000.dtsi @@ -20,6 +20,8 @@ aliases { ttyAS0 = &serial2; + ethernet0 = ðernet0; + ethernet1 = ðernet1; }; soc { @@ -46,5 +48,25 @@ status = "okay"; }; + + ethernet0: dwmac@fe810000 { + status = "okay"; + phy-mode = "mii"; + pinctrl-0 = <&pinctrl_mii0>; + + snps,reset-gpio = <&PIO106 2>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 10000>; + }; + + ethernet1: dwmac@fef08000 { + status = "disabled"; + phy-mode = "mii"; + st,tx-retime-src = "txclk"; + + snps,reset-gpio = <&PIO4 7>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 10000>; + }; }; }; diff --git a/arch/arm/boot/dts/stih41x-b2020.dtsi b/arch/arm/boot/dts/stih41x-b2020.dtsi index 0ef0a69df8ea..3dc74c25a57b 100644 --- a/arch/arm/boot/dts/stih41x-b2020.dtsi +++ b/arch/arm/boot/dts/stih41x-b2020.dtsi @@ -19,6 +19,7 @@ aliases { ttyAS0 = &sbc_serial1; + ethernet1 = ðernet1; }; soc { sbc_serial1: serial@fe531000 { @@ -60,5 +61,17 @@ i2c@fe541000 { status = "okay"; }; + + ethernet1: dwmac@fef08000 { + status = "okay"; + phy-mode = "rgmii-id"; + max-speed = <1000>; + st,tx-retime-src = "clk_125"; + snps,reset-gpio = <&PIO3 0>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 10000>; + + pinctrl-0 = <&pinctrl_rgmii1>; + }; }; }; diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 53c6a26b633d..fd6bff0c5b96 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c @@ -271,10 +271,14 @@ static void __init integrator_cp_of_init(struct device_node *np) void __iomem *base; int irq; const char *name = of_get_property(np, "compatible", NULL); + struct clk *clk; base = of_iomap(np, 0); if (WARN_ON(!base)) return; + clk = of_clk_get(np, 0); + if (WARN_ON(IS_ERR(clk))) + return; /* Ensure timer is disabled */ writel(0, base + TIMER_CTRL); @@ -283,13 +287,13 @@ static void __init integrator_cp_of_init(struct device_node *np) goto err; if (!init_count) - sp804_clocksource_init(base, name); + __sp804_clocksource_and_sched_clock_init(base, name, clk, 0); else { irq = irq_of_parse_and_map(np, 0); if (irq <= 0) goto err; - sp804_clockevents_init(base, irq, name); + __sp804_clockevents_init(base, irq, clk, name); } init_count++; diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 4e1ce211d43f..e3a05e8801d8 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -52,6 +52,7 @@ CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y CONFIG_STMMAC_ETH=y +CONFIG_MICREL_PHY=y # CONFIG_STMMAC_PHY_ID_ZERO_WORKAROUND is not set CONFIG_INPUT_EVDEV=y # CONFIG_SERIO_SERPORT is not set @@ -66,6 +67,9 @@ CONFIG_SERIAL_8250_DW=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT3_FS=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y # CONFIG_DNOTIFY is not set # CONFIG_INOTIFY_USER is not set CONFIG_VFAT_FS=y @@ -82,3 +86,5 @@ CONFIG_DEBUG_INFO=y CONFIG_ENABLE_DEFAULT_TRACERS=y CONFIG_DEBUG_USER=y CONFIG_XZ_DEC=y +CONFIG_MMC=y +CONFIG_MMC_DW=y diff --git a/arch/arm/mach-davinci/aemif.c b/arch/arm/mach-davinci/aemif.c index f091a9010c2f..ff8b7e76b6e9 100644 --- a/arch/arm/mach-davinci/aemif.c +++ b/arch/arm/mach-davinci/aemif.c @@ -16,6 +16,7 @@ #include <linux/time.h> #include <linux/platform_data/mtd-davinci-aemif.h> +#include <linux/platform_data/mtd-davinci.h> /* Timing value configuration */ @@ -43,6 +44,17 @@ WSTROBE(WSTROBE_MAX) | \ WSETUP(WSETUP_MAX)) +static inline unsigned int davinci_aemif_readl(void __iomem *base, int offset) +{ + return readl_relaxed(base + offset); +} + +static inline void davinci_aemif_writel(void __iomem *base, + int offset, unsigned long value) +{ + writel_relaxed(value, base + offset); +} + /* * aemif_calc_rate - calculate timing data. * @wanted: The cycle time needed in nanoseconds. @@ -76,6 +88,7 @@ static int aemif_calc_rate(int wanted, unsigned long clk, int max) * @t: timing values to be progammed * @base: The virtual base address of the AEMIF interface * @cs: chip-select to program the timing values for + * @clkrate: the AEMIF clkrate * * This function programs the given timing values (in real clock) into the * AEMIF registers taking the AEMIF clock into account. @@ -86,24 +99,17 @@ static int aemif_calc_rate(int wanted, unsigned long clk, int max) * * Returns 0 on success, else negative errno. */ -int davinci_aemif_setup_timing(struct davinci_aemif_timing *t, - void __iomem *base, unsigned cs) +static int davinci_aemif_setup_timing(struct davinci_aemif_timing *t, + void __iomem *base, unsigned cs, + unsigned long clkrate) { unsigned set, val; int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup; unsigned offset = A1CR_OFFSET + cs * 4; - struct clk *aemif_clk; - unsigned long clkrate; if (!t) return 0; /* Nothing to do */ - aemif_clk = clk_get(NULL, "aemif"); - if (IS_ERR(aemif_clk)) - return PTR_ERR(aemif_clk); - - clkrate = clk_get_rate(aemif_clk); - clkrate /= 1000; /* turn clock into kHz for ease of use */ ta = aemif_calc_rate(t->ta, clkrate, TA_MAX); @@ -130,4 +136,83 @@ int davinci_aemif_setup_timing(struct davinci_aemif_timing *t, return 0; } -EXPORT_SYMBOL(davinci_aemif_setup_timing); + +/** + * davinci_aemif_setup - setup AEMIF interface by davinci_nand_pdata + * @pdev - link to platform device to setup settings for + * + * This function does not use any locking while programming the AEMIF + * because it is expected that there is only one user of a given + * chip-select. + * + * Returns 0 on success, else negative errno. + */ +int davinci_aemif_setup(struct platform_device *pdev) +{ + struct davinci_nand_pdata *pdata = dev_get_platdata(&pdev->dev); + uint32_t val; + unsigned long clkrate; + struct resource *res; + void __iomem *base; + struct clk *clk; + int ret = 0; + + clk = clk_get(&pdev->dev, "aemif"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(clk); + if (ret < 0) { + dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n", + ret); + goto err_put; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(&pdev->dev, "cannot get IORESOURCE_MEM\n"); + ret = -ENOMEM; + goto err; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res); + ret = -ENOMEM; + goto err; + } + + /* + * Setup Async configuration register in case we did not boot + * from NAND and so bootloader did not bother to set it up. + */ + val = davinci_aemif_readl(base, A1CR_OFFSET + pdev->id * 4); + /* + * Extended Wait is not valid and Select Strobe mode is not + * used + */ + val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK); + if (pdata->options & NAND_BUSWIDTH_16) + val |= 0x1; + + davinci_aemif_writel(base, A1CR_OFFSET + pdev->id * 4, val); + + clkrate = clk_get_rate(clk); + + if (pdata->timing) + ret = davinci_aemif_setup_timing(pdata->timing, base, pdev->id, + clkrate); + + if (ret < 0) + dev_dbg(&pdev->dev, "NAND timing values setup fail\n"); + + iounmap(base); +err: + clk_disable_unprepare(clk); +err_put: + clk_put(clk); + return ret; +} diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index d1f45af7a530..5623131c4f0b 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -419,6 +419,9 @@ static inline void da830_evm_init_nand(int mux_mode) if (ret) pr_warning("da830_evm_init: NAND device not registered.\n"); + if (davinci_aemif_setup(&da830_evm_nand_device)) + pr_warn("%s: Cannot configure AEMIF.\n", __func__); + gpio_direction_output(mux_mode, 1); } #else diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index e0af0eccde8f..234c5bb091f5 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -358,6 +358,9 @@ static inline void da850_evm_setup_nor_nand(void) platform_add_devices(da850_evm_devices, ARRAY_SIZE(da850_evm_devices)); + + if (davinci_aemif_setup(&da850_evm_nandflash_device)) + pr_warn("%s: Cannot configure AEMIF.\n", __func__); } } diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 987605b78556..5602957b67d7 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -778,6 +778,11 @@ static __init void davinci_evm_init(void) /* only one device will be jumpered and detected */ if (HAS_NAND) { platform_device_register(&davinci_evm_nandflash_device); + + if (davinci_aemif_setup(&davinci_evm_nandflash_device)) + pr_warn("%s: Cannot configure AEMIF.\n", + __func__); + evm_leds[7].default_trigger = "nand-disk"; if (HAS_NOR) pr_warning("WARNING: both NAND and NOR flash " diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 13d0801fd6b1..ae129bc49273 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -805,6 +805,9 @@ static __init void evm_init(void) platform_device_register(&davinci_nand_device); + if (davinci_aemif_setup(&davinci_nand_device)) + pr_warn("%s: Cannot configure AEMIF.\n", __func__); + dm646x_init_edma(dm646x_edma_rsv); if (HAS_ATA) diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 7aa105b1fd0f..96fc00a167f5 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -27,6 +27,7 @@ #include <mach/cp_intc.h> #include <mach/da8xx.h> #include <linux/platform_data/mtd-davinci.h> +#include <linux/platform_data/mtd-davinci-aemif.h> #include <mach/mux.h> #include <linux/platform_data/spi-davinci.h> @@ -432,6 +433,9 @@ static void __init mityomapl138_setup_nand(void) { platform_add_devices(mityomapl138_devices, ARRAY_SIZE(mityomapl138_devices)); + + if (davinci_aemif_setup(&mityomapl138_nandflash_device)) + pr_warn("%s: Cannot configure AEMIF.\n", __func__); } static const short mityomap_mii_pins[] = { diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h index 5362df3df89f..f4a5b34489b7 100644 --- a/arch/arm/mach-dove/include/mach/bridge-regs.h +++ b/arch/arm/mach-dove/include/mach/bridge-regs.h @@ -21,6 +21,7 @@ #define CPU_CTRL_PCIE1_LINK 0x00000008 #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108) #define SOFT_RESET_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index abeff25532ab..6e8b0e10b420 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -30,6 +30,9 @@ config ARCH_CINTEGRATOR config INTEGRATOR_IMPD1 tristate "Include support for Integrator/IM-PD1" depends on ARCH_INTEGRATOR_AP + select ARCH_REQUIRE_GPIOLIB + select ARM_VIC + select GPIO_PL061 if GPIOLIB help The IM-PD1 is an add-on logic module for the Integrator which allows ARM(R) Ltd PrimeCells to be developed and evaluated. diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index 9f82f9dcbb98..d9b784824808 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -23,6 +23,7 @@ #include <linux/io.h> #include <linux/platform_data/clk-integrator.h> #include <linux/slab.h> +#include <linux/irqchip/arm-vic.h> #include <mach/lm.h> #include <mach/impd1.h> @@ -35,6 +36,7 @@ MODULE_PARM_DESC(lmid, "logic module stack position"); struct impd1_module { void __iomem *base; + void __iomem *vic_base; }; void impd1_tweak_control(struct device *dev, u32 mask, u32 val) @@ -262,9 +264,6 @@ struct impd1_device { static struct impd1_device impd1_devs[] = { { - .offset = 0x03000000, - .id = 0x00041190, - }, { .offset = 0x00100000, .irq = { 1 }, .id = 0x00141011, @@ -304,46 +303,72 @@ static struct impd1_device impd1_devs[] = { } }; -static int impd1_probe(struct lm_device *dev) +/* + * Valid IRQs: 0 thru 9 and 11, 10 unused. + */ +#define IMPD1_VALID_IRQS 0x00000bffU + +static int __init impd1_probe(struct lm_device *dev) { struct impd1_module *impd1; - int i, ret; + int irq_base; + int i; if (dev->id != module_id) return -EINVAL; - if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers")) + if (!devm_request_mem_region(&dev->dev, dev->resource.start, + SZ_4K, "LM registers")) return -EBUSY; - impd1 = kzalloc(sizeof(struct impd1_module), GFP_KERNEL); - if (!impd1) { - ret = -ENOMEM; - goto release_lm; - } + impd1 = devm_kzalloc(&dev->dev, sizeof(struct impd1_module), + GFP_KERNEL); + if (!impd1) + return -ENOMEM; - impd1->base = ioremap(dev->resource.start, SZ_4K); - if (!impd1->base) { - ret = -ENOMEM; - goto free_impd1; - } + impd1->base = devm_ioremap(&dev->dev, dev->resource.start, SZ_4K); + if (!impd1->base) + return -ENOMEM; - lm_set_drvdata(dev, impd1); + integrator_impd1_clk_init(impd1->base, dev->id); - printk("IM-PD1 found at 0x%08lx\n", - (unsigned long)dev->resource.start); + if (!devm_request_mem_region(&dev->dev, + dev->resource.start + 0x03000000, + SZ_4K, "VIC")) + return -EBUSY; - integrator_impd1_clk_init(impd1->base, dev->id); + impd1->vic_base = devm_ioremap(&dev->dev, + dev->resource.start + 0x03000000, + SZ_4K); + if (!impd1->vic_base) + return -ENOMEM; + + irq_base = vic_init_cascaded(impd1->vic_base, dev->irq, + IMPD1_VALID_IRQS, 0); + + lm_set_drvdata(dev, impd1); + + dev_info(&dev->dev, "IM-PD1 found at 0x%08lx\n", + (unsigned long)dev->resource.start); for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { struct impd1_device *idev = impd1_devs + i; struct amba_device *d; unsigned long pc_base; char devname[32]; + int irq1 = idev->irq[0]; + int irq2 = idev->irq[1]; + + /* Translate IRQs to IM-PD1 local numberspace */ + if (irq1) + irq1 += irq_base; + if (irq2) + irq2 += irq_base; pc_base = dev->resource.start + idev->offset; snprintf(devname, 32, "lm%x:%5.5lx", dev->id, idev->offset >> 12); d = amba_ahb_device_add_res(&dev->dev, devname, pc_base, SZ_4K, - dev->irq, dev->irq, + irq1, irq2, idev->platform_data, idev->id, &dev->resource); if (IS_ERR(d)) { @@ -353,14 +378,6 @@ static int impd1_probe(struct lm_device *dev) } return 0; - - free_impd1: - if (impd1 && impd1->base) - iounmap(impd1->base); - kfree(impd1); - release_lm: - release_mem_region(dev->resource.start, SZ_4K); - return ret; } static int impd1_remove_one(struct device *dev, void *data) @@ -371,16 +388,10 @@ static int impd1_remove_one(struct device *dev, void *data) static void impd1_remove(struct lm_device *dev) { - struct impd1_module *impd1 = lm_get_drvdata(dev); - device_for_each_child(&dev->dev, NULL, impd1_remove_one); integrator_impd1_clk_exit(dev->id); lm_set_drvdata(dev, NULL); - - iounmap(impd1->base); - kfree(impd1); - release_mem_region(dev->resource.start, SZ_4K); } static struct lm_driver impd1_driver = { diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 17c0fe627435..fedcd2fab094 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -42,6 +42,7 @@ #include <linux/sys_soc.h> #include <linux/termios.h> #include <linux/sched_clock.h> +#include <linux/clk-provider.h> #include <mach/hardware.h> #include <mach/platform.h> @@ -402,10 +403,7 @@ static void __init ap_of_timer_init(void) struct clk *clk; unsigned long rate; - clk = clk_get_sys("ap_timer", NULL); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); + of_clk_init(NULL); err = of_property_read_string(of_aliases, "arm,timer-primary", &path); @@ -415,6 +413,12 @@ static void __init ap_of_timer_init(void) base = of_iomap(node, 0); if (WARN_ON(!base)) return; + + clk = of_clk_get(node, 0); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + writel(0, base + TIMER_CTRL); integrator_clocksource_init(rate, base); @@ -427,6 +431,12 @@ static void __init ap_of_timer_init(void) if (WARN_ON(!base)) return; irq = irq_of_parse_and_map(node, 0); + + clk = of_clk_get(node, 0); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + writel(0, base + TIMER_CTRL); integrator_clockevent_init(rate, base, irq); } @@ -440,7 +450,6 @@ static void __init ap_init_irq_of(void) { cm_init(); of_irq_init(fpga_irq_of_match); - integrator_clk_init(false); } /* For the Device Tree, add in the UART callbacks as AUXDATA */ diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index a3ef961e4a93..0ad5f60598c8 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -23,7 +23,6 @@ #include <linux/irqchip/versatile-fpga.h> #include <linux/gfp.h> #include <linux/mtd/physmap.h> -#include <linux/platform_data/clk-integrator.h> #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/of_platform.h> @@ -33,8 +32,6 @@ #include <mach/platform.h> #include <asm/setup.h> #include <asm/mach-types.h> -#include <asm/hardware/arm_timer.h> -#include <asm/hardware/icst.h> #include <mach/lm.h> @@ -43,8 +40,6 @@ #include <asm/mach/map.h> #include <asm/mach/time.h> -#include <asm/hardware/timer-sp.h> - #include <plat/clcd.h> #include <plat/sched_clock.h> @@ -250,7 +245,6 @@ static void __init intcp_init_irq_of(void) { cm_init(); of_irq_init(fpga_irq_of_match); - integrator_clk_init(true); } /* diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h index 8b9d1c9ff199..60f64218d6a6 100644 --- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h +++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h @@ -21,6 +21,7 @@ #define CPU_RESET 0x00000002 #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108) #define SOFT_RESET_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 9625cf378931..a7f959e58c3d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -1,50 +1,9 @@ -config ARCH_MSM - bool - -config ARCH_MSM_DT - bool "Qualcomm MSM DT Support" if ARCH_MULTI_V7 - select ARCH_MSM - select ARCH_REQUIRE_GPIOLIB - select CLKSRC_OF - select GENERIC_CLOCKEVENTS - help - Support for Qualcomm's devicetree based MSM systems. - if ARCH_MSM -menu "Qualcomm MSM SoC Selection" - depends on ARCH_MSM_DT - -config ARCH_MSM8X60 - bool "Enable support for MSM8X60" - select ARM_GIC - select CPU_V7 - select HAVE_SMP - select MSM_SCM if SMP - select MSM_TIMER - -config ARCH_MSM8960 - bool "Enable support for MSM8960" - select ARM_GIC - select CPU_V7 - select HAVE_SMP - select MSM_SCM if SMP - select MSM_TIMER - -config ARCH_MSM8974 - bool "Enable support for MSM8974" - select ARM_GIC - select CPU_V7 - select HAVE_ARM_ARCH_TIMER - select HAVE_SMP - select MSM_SCM if SMP - -endmenu - choice prompt "Qualcomm MSM SoC Type" default ARCH_MSM7X00A - depends on ARCH_MSM_NODT + depends on ARCH_MSM config ARCH_MSM7X00A bool "MSM7x00A / MSM7x01A" @@ -54,7 +13,7 @@ config ARCH_MSM7X00A select MACH_TROUT if !MACH_HALIBUT select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_SMD_PKG3 config ARCH_MSM7X30 @@ -66,7 +25,7 @@ config ARCH_MSM7X30 select MSM_GPIOMUX select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_VIC config ARCH_QSD8X50 @@ -78,7 +37,7 @@ config ARCH_QSD8X50 select MSM_GPIOMUX select MSM_PROC_COMM select MSM_SMD - select MSM_TIMER + select CLKSRC_QCOM select MSM_VIC endchoice @@ -99,7 +58,7 @@ config MSM_VIC bool menu "Qualcomm MSM Board Type" - depends on ARCH_MSM_NODT + depends on ARCH_MSM config MACH_HALIBUT depends on ARCH_MSM @@ -153,7 +112,4 @@ config MSM_GPIOMUX config MSM_SCM bool -config MSM_TIMER - bool - endif diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 8e307a10d3c3..27c078a568df 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_MSM_TIMER) += timer.o obj-$(CONFIG_MSM_PROC_COMM) += clock.o obj-$(CONFIG_MSM_VIC) += irq-vic.o @@ -14,18 +13,11 @@ obj-$(CONFIG_ARCH_QSD8X50) += dma.o io.o obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o obj-$(CONFIG_MSM_SMD) += last_radio_log.o -obj-$(CONFIG_MSM_SCM) += scm.o scm-boot.o - -CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) - -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o board-trout-panel.o devices-msm7x00.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o -obj-$(CONFIG_ARCH_MSM_DT) += board-dt.o obj-$(CONFIG_MSM_GPIOMUX) += gpiomux.o obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o diff --git a/arch/arm/mach-msm/common.h b/arch/arm/mach-msm/common.h index 33c7725adae2..0a4899b7d85c 100644 --- a/arch/arm/mach-msm/common.h +++ b/arch/arm/mach-msm/common.h @@ -24,7 +24,6 @@ extern void __iomem *__msm_ioremap_caller(phys_addr_t phys_addr, size_t size, unsigned int mtype, void *caller); extern struct smp_operations msm_smp_ops; -extern void msm_cpu_die(unsigned int cpu); struct msm_mmc_platform_data; diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S deleted file mode 100644 index 6c62c3f82fe6..000000000000 --- a/arch/arm/mach-msm/headsmp.S +++ /dev/null @@ -1,39 +0,0 @@ -/* - * linux/arch/arm/mach-realview/headsmp.S - * - * Copyright (c) 2003 ARM Limited - * 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. - */ -#include <linux/linkage.h> -#include <linux/init.h> - -/* - * MSM 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(msm_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 - - /* - * we've been released from the holding pen: secondary_stack - * should now contain the SVC stack for this core - */ - b secondary_startup -ENDPROC(msm_secondary_startup) - - .align -1: .long . - .long pen_release diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c deleted file mode 100644 index 326a87261f9a..000000000000 --- a/arch/arm/mach-msm/hotplug.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2002 ARM Ltd. - * 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. - */ -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/smp.h> - -#include <asm/smp_plat.h> - -#include "common.h" - -static inline void cpu_enter_lowpower(void) -{ -} - -static inline void cpu_leave_lowpower(void) -{ -} - -static inline void platform_do_lowpower(unsigned int cpu) -{ - /* Just enter wfi for now. TODO: Properly shut off the cpu. */ - for (;;) { - /* - * here's the WFI - */ - asm("wfi" - : - : - : "memory", "cc"); - - if (pen_release == cpu_logical_map(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 - * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else - */ - pr_debug("CPU%u: spurious wakeup call\n", cpu); - } -} - -/* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled - */ -void __ref msm_cpu_die(unsigned int cpu) -{ - /* - * we're ready for shutdown now, so do it - */ - cpu_enter_lowpower(); - platform_do_lowpower(cpu); - - /* - * bring this CPU back into the world of cache - * coherency, and then restore interrupts - */ - cpu_leave_lowpower(); -} diff --git a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h index 5f03484584d4..e20d6da234a6 100644 --- a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h +++ b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h @@ -15,6 +15,7 @@ #define L2_WRITETHROUGH 0x00020000 #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108) #define SOFT_RESET_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 922cbd8e3519..c1fdf926de3b 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -72,6 +72,7 @@ config SOC_DRA7XX select ARM_CPU_SUSPEND if PM select ARM_GIC select HAVE_ARM_ARCH_TIMER + select IRQ_CROSSBAR config ARCH_OMAP2PLUS bool diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index 3664562f9148..693fe486e917 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -138,7 +138,7 @@ static void wakeupgen_mask(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&wakeupgen_lock, flags); - _wakeupgen_clear(d->irq, irq_target_cpu[d->irq]); + _wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]); raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); } @@ -150,7 +150,7 @@ static void wakeupgen_unmask(struct irq_data *d) unsigned long flags; raw_spin_lock_irqsave(&wakeupgen_lock, flags); - _wakeupgen_set(d->irq, irq_target_cpu[d->irq]); + _wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]); raw_spin_unlock_irqrestore(&wakeupgen_lock, flags); } diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 6cd3f3772ecf..95e171a055f3 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -22,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/export.h> #include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/irq-crossbar.h> #include <linux/of_address.h> #include <linux/reboot.h> @@ -288,5 +289,8 @@ void __init omap_gic_of_init(void) skip_errata_init: omap_wakeupgen_init(); +#ifdef CONFIG_IRQ_CROSSBAR + irqcrossbar_init(); +#endif irqchip_init(); } diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h index f727d03f1688..5766e3fbff69 100644 --- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h +++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h @@ -18,6 +18,7 @@ #define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104) #define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108) +#define RSTOUTn_MASK_PHYS (ORION5X_BRIDGE_PHYS_BASE + 0x108) #define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c) diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig new file mode 100644 index 000000000000..a028be234334 --- /dev/null +++ b/arch/arm/mach-qcom/Kconfig @@ -0,0 +1,33 @@ +config ARCH_QCOM + bool "Qualcomm Support" if ARCH_MULTI_V7 + select ARCH_REQUIRE_GPIOLIB + select ARM_GIC + select CLKSRC_OF + select GENERIC_CLOCKEVENTS + select HAVE_SMP + select QCOM_SCM if SMP + help + Support for Qualcomm's devicetree based systems. + +if ARCH_QCOM + +menu "Qualcomm SoC Selection" + +config ARCH_MSM8X60 + bool "Enable support for MSM8X60" + select CLKSRC_QCOM + +config ARCH_MSM8960 + bool "Enable support for MSM8960" + select CLKSRC_QCOM + +config ARCH_MSM8974 + bool "Enable support for MSM8974" + select HAVE_ARM_ARCH_TIMER + +endmenu + +config QCOM_SCM + bool + +endif diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile new file mode 100644 index 000000000000..8f756ae1ae31 --- /dev/null +++ b/arch/arm/mach-qcom/Makefile @@ -0,0 +1,5 @@ +obj-y := board.o +obj-$(CONFIG_SMP) += platsmp.o +obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o + +CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-qcom/board.c index 1f11d93e700e..830f69c3a3ce 100644 --- a/arch/arm/mach-msm/board-dt.c +++ b/arch/arm/mach-qcom/board.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2012,2013 The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2014 The Linux Foundation. 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 and @@ -17,10 +17,9 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include "common.h" +extern struct smp_operations qcom_smp_ops; -static const char * const msm_dt_match[] __initconst = { - "qcom,msm8660-fluid", +static const char * const qcom_dt_match[] __initconst = { "qcom,msm8660-surf", "qcom,msm8960-cdp", NULL @@ -31,11 +30,11 @@ static const char * const apq8074_dt_match[] __initconst = { NULL }; -DT_MACHINE_START(MSM_DT, "Qualcomm MSM (Flattened Device Tree)") - .smp = smp_ops(msm_smp_ops), - .dt_compat = msm_dt_match, +DT_MACHINE_START(QCOM_DT, "Qualcomm (Flattened Device Tree)") + .smp = smp_ops(qcom_smp_ops), + .dt_compat = qcom_dt_match, MACHINE_END -DT_MACHINE_START(APQ_DT, "Qualcomm MSM (Flattened Device Tree)") +DT_MACHINE_START(APQ_DT, "Qualcomm (Flattened Device Tree)") .dt_compat = apq8074_dt_match, MACHINE_END diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-qcom/platsmp.c index f10a1f58fde9..9c53ea70550d 100644 --- a/arch/arm/mach-msm/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -2,6 +2,7 @@ * Copyright (C) 2002 ARM Ltd. * All Rights Reserved * Copyright (c) 2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2014 The Linux Foundation. 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 @@ -12,42 +13,38 @@ #include <linux/errno.h> #include <linux/delay.h> #include <linux/device.h> -#include <linux/jiffies.h> #include <linux/smp.h> #include <linux/io.h> -#include <asm/cacheflush.h> #include <asm/cputype.h> -#include <asm/mach-types.h> #include <asm/smp_plat.h> #include "scm-boot.h" -#include "common.h" #define VDD_SC1_ARRAY_CLAMP_GFS_CTL 0x15A0 #define SCSS_CPU1CORE_RESET 0xD80 #define SCSS_DBG_STATUS_CORE_PWRDUP 0xE64 -extern void msm_secondary_startup(void); +extern void secondary_startup(void); static DEFINE_SPINLOCK(boot_lock); +#ifdef CONFIG_HOTPLUG_CPU +static void __ref qcom_cpu_die(unsigned int cpu) +{ + wfi(); +} +#endif + static inline int get_core_count(void) { /* 1 + the PART[1:0] field of MIDR */ return ((read_cpuid_id() >> 4) & 3) + 1; } -static void msm_secondary_init(unsigned int cpu) +static void qcom_secondary_init(unsigned int cpu) { /* - * 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); @@ -57,7 +54,7 @@ static void msm_secondary_init(unsigned int cpu) static void prepare_cold_cpu(unsigned int cpu) { int ret; - ret = scm_set_boot_addr(virt_to_phys(msm_secondary_startup), + ret = scm_set_boot_addr(virt_to_phys(secondary_startup), SCM_FLAG_COLDBOOT_CPU1); if (ret == 0) { void __iomem *sc1_base_ptr; @@ -73,9 +70,8 @@ static void prepare_cold_cpu(unsigned int cpu) "address\n"); } -static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) +static int qcom_boot_secondary(unsigned int cpu, struct task_struct *idle) { - unsigned long timeout; static int cold_boot_done; /* Only need to bring cpu out of reset this way once */ @@ -91,39 +87,19 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) 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_logical_map(cpu); - sync_cache_w(&pen_release); - - /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ arch_send_wakeup_ipi_mask(cpumask_of(cpu)); - 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; + return 0; } /* @@ -132,7 +108,7 @@ static int msm_boot_secondary(unsigned int cpu, struct task_struct *idle) * does not support the ARM SCU, so just set the possible cpu mask to * NR_CPUS. */ -static void __init msm_smp_init_cpus(void) +static void __init qcom_smp_init_cpus(void) { unsigned int i, ncores = get_core_count(); @@ -146,16 +122,16 @@ static void __init msm_smp_init_cpus(void) set_cpu_possible(i, true); } -static void __init msm_smp_prepare_cpus(unsigned int max_cpus) +static void __init qcom_smp_prepare_cpus(unsigned int max_cpus) { } -struct smp_operations msm_smp_ops __initdata = { - .smp_init_cpus = msm_smp_init_cpus, - .smp_prepare_cpus = msm_smp_prepare_cpus, - .smp_secondary_init = msm_secondary_init, - .smp_boot_secondary = msm_boot_secondary, +struct smp_operations qcom_smp_ops __initdata = { + .smp_init_cpus = qcom_smp_init_cpus, + .smp_prepare_cpus = qcom_smp_prepare_cpus, + .smp_secondary_init = qcom_secondary_init, + .smp_boot_secondary = qcom_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU - .cpu_die = msm_cpu_die, + .cpu_die = qcom_cpu_die, #endif }; diff --git a/arch/arm/mach-msm/scm-boot.c b/arch/arm/mach-qcom/scm-boot.c index 45cee3e469a5..45cee3e469a5 100644 --- a/arch/arm/mach-msm/scm-boot.c +++ b/arch/arm/mach-qcom/scm-boot.c diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-qcom/scm-boot.h index 7be32ff5d687..7be32ff5d687 100644 --- a/arch/arm/mach-msm/scm-boot.h +++ b/arch/arm/mach-qcom/scm-boot.h diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-qcom/scm.c index c536fd6bf827..c536fd6bf827 100644 --- a/arch/arm/mach-msm/scm.c +++ b/arch/arm/mach-qcom/scm.c diff --git a/arch/arm/mach-msm/scm.h b/arch/arm/mach-qcom/scm.h index 00b31ea58f29..00b31ea58f29 100644 --- a/arch/arm/mach-msm/scm.h +++ b/arch/arm/mach-qcom/scm.h diff --git a/arch/arm/mach-shmobile/clock-r7s72100.c b/arch/arm/mach-shmobile/clock-r7s72100.c index e6ab0cd5b286..bee0073c9b64 100644 --- a/arch/arm/mach-shmobile/clock-r7s72100.c +++ b/arch/arm/mach-shmobile/clock-r7s72100.c @@ -22,12 +22,15 @@ #include <mach/common.h> #include <mach/r7s72100.h> -/* registers */ +/* Frequency Control Registers */ #define FRQCR 0xfcfe0010 #define FRQCR2 0xfcfe0014 +/* Standby Control Registers */ #define STBCR3 0xfcfe0420 #define STBCR4 0xfcfe0424 +#define STBCR7 0xfcfe0430 #define STBCR9 0xfcfe0438 +#define STBCR10 0xfcfe043c #define PLL_RATE 30 @@ -67,7 +70,7 @@ static struct clk pll_clk = { static unsigned long bus_recalc(struct clk *clk) { - return clk->parent->rate * 2 / 3; + return clk->parent->rate / 3; } static struct sh_clk_ops bus_clk_ops = { @@ -145,15 +148,25 @@ struct clk div4_clks[DIV4_NR] = { | CLK_ENABLE_ON_INIT), }; -enum { MSTP97, MSTP96, MSTP95, MSTP94, +enum { + MSTP107, MSTP106, MSTP105, MSTP104, MSTP103, + MSTP97, MSTP96, MSTP95, MSTP94, + MSTP74, MSTP47, MSTP46, MSTP45, MSTP44, MSTP43, MSTP42, MSTP41, MSTP40, - MSTP33, MSTP_NR }; + MSTP33, MSTP_NR +}; static struct clk mstp_clks[MSTP_NR] = { + [MSTP107] = SH_CLK_MSTP8(&peripheral1_clk, STBCR10, 7, 0), /* RSPI0 */ + [MSTP106] = SH_CLK_MSTP8(&peripheral1_clk, STBCR10, 6, 0), /* RSPI1 */ + [MSTP105] = SH_CLK_MSTP8(&peripheral1_clk, STBCR10, 5, 0), /* RSPI2 */ + [MSTP104] = SH_CLK_MSTP8(&peripheral1_clk, STBCR10, 4, 0), /* RSPI3 */ + [MSTP103] = SH_CLK_MSTP8(&peripheral1_clk, STBCR10, 3, 0), /* RSPI4 */ [MSTP97] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 7, 0), /* RIIC0 */ [MSTP96] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 6, 0), /* RIIC1 */ [MSTP95] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 5, 0), /* RIIC2 */ [MSTP94] = SH_CLK_MSTP8(&peripheral0_clk, STBCR9, 4, 0), /* RIIC3 */ + [MSTP74] = SH_CLK_MSTP8(&peripheral1_clk, STBCR7, 4, 0), /* Ether */ [MSTP47] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 7, 0), /* SCIF0 */ [MSTP46] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 6, 0), /* SCIF1 */ [MSTP45] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 5, 0), /* SCIF2 */ @@ -176,6 +189,21 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), /* MSTP clocks */ + CLKDEV_DEV_ID("rspi-rz.0", &mstp_clks[MSTP107]), + CLKDEV_DEV_ID("rspi-rz.1", &mstp_clks[MSTP106]), + CLKDEV_DEV_ID("rspi-rz.2", &mstp_clks[MSTP105]), + CLKDEV_DEV_ID("rspi-rz.3", &mstp_clks[MSTP104]), + CLKDEV_DEV_ID("rspi-rz.4", &mstp_clks[MSTP103]), + CLKDEV_DEV_ID("e800c800.spi", &mstp_clks[MSTP107]), + CLKDEV_DEV_ID("e800d000.spi", &mstp_clks[MSTP106]), + CLKDEV_DEV_ID("e800d800.spi", &mstp_clks[MSTP105]), + CLKDEV_DEV_ID("e800e000.spi", &mstp_clks[MSTP104]), + CLKDEV_DEV_ID("e800e800.spi", &mstp_clks[MSTP103]), + CLKDEV_DEV_ID("fcfee000.i2c", &mstp_clks[MSTP97]), + CLKDEV_DEV_ID("fcfee400.i2c", &mstp_clks[MSTP96]), + CLKDEV_DEV_ID("fcfee800.i2c", &mstp_clks[MSTP95]), + CLKDEV_DEV_ID("fcfeec00.i2c", &mstp_clks[MSTP94]), + CLKDEV_DEV_ID("r7s72100-ether", &mstp_clks[MSTP74]), CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP33]), /* ICK */ diff --git a/arch/arm/mach-shmobile/clock-r8a7778.c b/arch/arm/mach-shmobile/clock-r8a7778.c index 9783945f8bc7..2009a9bc6356 100644 --- a/arch/arm/mach-shmobile/clock-r8a7778.c +++ b/arch/arm/mach-shmobile/clock-r8a7778.c @@ -221,6 +221,10 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("fffc6000.spi", &mstp_clks[MSTP007]), /* HSPI2 */ CLKDEV_DEV_ID("rcar_sound", &mstp_clks[MSTP008]), /* SRU */ + CLKDEV_ICK_ID("clk_a", "rcar_sound", &audio_clk_a), + CLKDEV_ICK_ID("clk_b", "rcar_sound", &audio_clk_b), + CLKDEV_ICK_ID("clk_c", "rcar_sound", &audio_clk_c), + CLKDEV_ICK_ID("clk_i", "rcar_sound", &s1_clk), CLKDEV_ICK_ID("ssi.0", "rcar_sound", &mstp_clks[MSTP012]), CLKDEV_ICK_ID("ssi.1", "rcar_sound", &mstp_clks[MSTP011]), CLKDEV_ICK_ID("ssi.2", "rcar_sound", &mstp_clks[MSTP010]), diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index f1fb89b76786..93a562531d53 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -127,16 +127,16 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP322] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 22, 0), /* SDHI1 */ [MSTP321] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 21, 0), /* SDHI2 */ [MSTP320] = SH_CLK_MSTP32(&clkp_clk, MSTPCR3, 20, 0), /* SDHI3 */ - [MSTP120] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 20, 0), /* VIN3 */ - [MSTP116] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 16, 0), /* PCIe */ - [MSTP115] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 15, 0), /* SATA */ - [MSTP114] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 14, 0), /* Ether */ - [MSTP110] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 10, 0), /* VIN0 */ - [MSTP109] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 9, 0), /* VIN1 */ - [MSTP108] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 8, 0), /* VIN2 */ - [MSTP103] = SH_CLK_MSTP32(&clks_clk, MSTPCR1, 3, 0), /* DU */ - [MSTP101] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 1, 0), /* USB2 */ - [MSTP100] = SH_CLK_MSTP32(&clkp_clk, MSTPCR1, 0, 0), /* USB0/1 */ + [MSTP120] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 20, MSTPSR1, 0), /* VIN3 */ + [MSTP116] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 16, MSTPSR1, 0), /* PCIe */ + [MSTP115] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 15, MSTPSR1, 0), /* SATA */ + [MSTP114] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 14, MSTPSR1, 0), /* Ether */ + [MSTP110] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 10, MSTPSR1, 0), /* VIN0 */ + [MSTP109] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 9, MSTPSR1, 0), /* VIN1 */ + [MSTP108] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 8, MSTPSR1, 0), /* VIN2 */ + [MSTP103] = SH_CLK_MSTP32_STS(&clks_clk, MSTPCR1, 3, MSTPSR1, 0), /* DU */ + [MSTP101] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 1, MSTPSR1, 0), /* USB2 */ + [MSTP100] = SH_CLK_MSTP32_STS(&clkp_clk, MSTPCR1, 0, MSTPSR1, 0), /* USB0/1 */ [MSTP030] = SH_CLK_MSTP32(&clkp_clk, MSTPCR0, 30, 0), /* I2C0 */ [MSTP029] = SH_CLK_MSTP32(&clkp_clk, MSTPCR0, 29, 0), /* I2C1 */ [MSTP028] = SH_CLK_MSTP32(&clkp_clk, MSTPCR0, 28, 0), /* I2C2 */ diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index f44987a92ad4..3f93503f5b96 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -43,17 +43,26 @@ * see "p1 / 2" on R8A7790_CLOCK_ROOT() below */ -#define CPG_BASE 0xe6150000 -#define CPG_LEN 0x1000 - -#define SMSTPCR1 0xe6150134 -#define SMSTPCR2 0xe6150138 -#define SMSTPCR3 0xe615013c -#define SMSTPCR5 0xe6150144 -#define SMSTPCR7 0xe615014c -#define SMSTPCR8 0xe6150990 -#define SMSTPCR9 0xe6150994 -#define SMSTPCR10 0xe6150998 +#define CPG_BASE 0xe6150000 +#define CPG_LEN 0x1000 + +#define SMSTPCR1 0xe6150134 +#define SMSTPCR2 0xe6150138 +#define SMSTPCR3 0xe615013c +#define SMSTPCR5 0xe6150144 +#define SMSTPCR7 0xe615014c +#define SMSTPCR8 0xe6150990 +#define SMSTPCR9 0xe6150994 +#define SMSTPCR10 0xe6150998 + +#define MSTPSR1 IOMEM(0xe6150038) +#define MSTPSR2 IOMEM(0xe6150040) +#define MSTPSR3 IOMEM(0xe6150048) +#define MSTPSR5 IOMEM(0xe615003c) +#define MSTPSR7 IOMEM(0xe61501c4) +#define MSTPSR8 IOMEM(0xe61509a0) +#define MSTPSR9 IOMEM(0xe61509a4) +#define MSTPSR10 IOMEM(0xe61509a8) #define SDCKCR 0xE6150074 #define SD2CKCR 0xE6150078 @@ -82,6 +91,15 @@ static struct clk main_clk = { .ops = &followparent_clk_ops, }; +static struct clk audio_clk_a = { +}; + +static struct clk audio_clk_b = { +}; + +static struct clk audio_clk_c = { +}; + /* * clock ratio of these clock will be updated * on r8a7790_clock_init() @@ -115,6 +133,9 @@ SH_FIXED_RATIO_CLK_SET(ddr_clk, pll3_clk, 1, 8); SH_FIXED_RATIO_CLK_SET(mp_clk, pll1_div2_clk, 1, 15); static struct clk *main_clks[] = { + &audio_clk_a, + &audio_clk_b, + &audio_clk_c, &extal_clk, &extal_div2_clk, &main_clk, @@ -183,15 +204,22 @@ static struct clk div6_clks[DIV6_NR] = { /* MSTP */ enum { + MSTP1017, /* parent of SCU */ + + MSTP1031, MSTP1030, + MSTP1029, MSTP1028, MSTP1027, MSTP1026, MSTP1025, MSTP1024, MSTP1023, MSTP1022, MSTP1015, MSTP1014, MSTP1013, MSTP1012, MSTP1011, MSTP1010, MSTP1009, MSTP1008, MSTP1007, MSTP1006, MSTP1005, MSTP931, MSTP930, MSTP929, MSTP928, MSTP917, + MSTP815, MSTP814, MSTP813, + MSTP811, MSTP810, MSTP809, MSTP808, MSTP726, MSTP725, MSTP724, MSTP723, MSTP722, MSTP721, MSTP720, MSTP717, MSTP716, - MSTP704, + MSTP704, MSTP703, MSTP522, + MSTP502, MSTP501, MSTP315, MSTP314, MSTP313, MSTP312, MSTP311, MSTP305, MSTP304, MSTP216, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP124, @@ -199,53 +227,77 @@ enum { }; static struct clk mstp_clks[MSTP_NR] = { - [MSTP1015] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 15, 0), /* SSI0 */ - [MSTP1014] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 14, 0), /* SSI1 */ - [MSTP1013] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 13, 0), /* SSI2 */ - [MSTP1012] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 12, 0), /* SSI3 */ - [MSTP1011] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 11, 0), /* SSI4 */ - [MSTP1010] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 10, 0), /* SSI5 */ - [MSTP1009] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 9, 0), /* SSI6 */ - [MSTP1008] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 8, 0), /* SSI7 */ - [MSTP1007] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 7, 0), /* SSI8 */ - [MSTP1006] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 6, 0), /* SSI9 */ - [MSTP1005] = SH_CLK_MSTP32(&p_clk, SMSTPCR10, 5, 0), /* SSI ALL */ - [MSTP931] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 31, 0), /* I2C0 */ - [MSTP930] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 30, 0), /* I2C1 */ - [MSTP929] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 29, 0), /* I2C2 */ - [MSTP928] = SH_CLK_MSTP32(&p_clk, SMSTPCR9, 28, 0), /* I2C3 */ - [MSTP917] = SH_CLK_MSTP32(&qspi_clk, SMSTPCR9, 17, 0), /* QSPI */ - [MSTP813] = SH_CLK_MSTP32(&p_clk, SMSTPCR8, 13, 0), /* Ether */ - [MSTP726] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 26, 0), /* LVDS0 */ - [MSTP725] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 25, 0), /* LVDS1 */ - [MSTP724] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 24, 0), /* DU0 */ - [MSTP723] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 23, 0), /* DU1 */ - [MSTP722] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 22, 0), /* DU2 */ - [MSTP721] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 21, 0), /* SCIF0 */ - [MSTP720] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 20, 0), /* SCIF1 */ - [MSTP717] = SH_CLK_MSTP32(&zs_clk, SMSTPCR7, 17, 0), /* HSCIF0 */ - [MSTP716] = SH_CLK_MSTP32(&zs_clk, SMSTPCR7, 16, 0), /* HSCIF1 */ - [MSTP704] = SH_CLK_MSTP32(&mp_clk, SMSTPCR7, 4, 0), /* HSUSB */ - [MSTP522] = SH_CLK_MSTP32(&extal_clk, SMSTPCR5, 22, 0), /* Thermal */ - [MSTP315] = SH_CLK_MSTP32(&div6_clks[DIV6_MMC0], SMSTPCR3, 15, 0), /* MMC0 */ - [MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_SD0], SMSTPCR3, 14, 0), /* SDHI0 */ - [MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_SD1], SMSTPCR3, 13, 0), /* SDHI1 */ - [MSTP312] = SH_CLK_MSTP32(&div6_clks[DIV6_SD2], SMSTPCR3, 12, 0), /* SDHI2 */ - [MSTP311] = SH_CLK_MSTP32(&div6_clks[DIV6_SD3], SMSTPCR3, 11, 0), /* SDHI3 */ - [MSTP305] = SH_CLK_MSTP32(&div6_clks[DIV6_MMC1], SMSTPCR3, 5, 0), /* MMC1 */ - [MSTP304] = SH_CLK_MSTP32(&cp_clk, SMSTPCR3, 4, 0), /* TPU0 */ - [MSTP216] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 16, 0), /* SCIFB2 */ - [MSTP207] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 7, 0), /* SCIFB1 */ - [MSTP206] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 6, 0), /* SCIFB0 */ - [MSTP204] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 4, 0), /* SCIFA0 */ - [MSTP203] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 3, 0), /* SCIFA1 */ - [MSTP202] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 2, 0), /* SCIFA2 */ - [MSTP124] = SH_CLK_MSTP32(&rclk_clk, SMSTPCR1, 24, 0), /* CMT0 */ + [MSTP1031] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 31, MSTPSR10, 0), /* SCU0 */ + [MSTP1030] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 30, MSTPSR10, 0), /* SCU1 */ + [MSTP1029] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 29, MSTPSR10, 0), /* SCU2 */ + [MSTP1028] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 28, MSTPSR10, 0), /* SCU3 */ + [MSTP1027] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 27, MSTPSR10, 0), /* SCU4 */ + [MSTP1026] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 26, MSTPSR10, 0), /* SCU5 */ + [MSTP1025] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 25, MSTPSR10, 0), /* SCU6 */ + [MSTP1024] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 24, MSTPSR10, 0), /* SCU7 */ + [MSTP1023] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 23, MSTPSR10, 0), /* SCU8 */ + [MSTP1022] = SH_CLK_MSTP32_STS(&mstp_clks[MSTP1017], SMSTPCR10, 22, MSTPSR10, 0), /* SCU9 */ + [MSTP1017] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 17, MSTPSR10, 0), /* SCU */ + [MSTP1015] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 15, MSTPSR10, 0), /* SSI0 */ + [MSTP1014] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 14, MSTPSR10, 0), /* SSI1 */ + [MSTP1013] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 13, MSTPSR10, 0), /* SSI2 */ + [MSTP1012] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 12, MSTPSR10, 0), /* SSI3 */ + [MSTP1011] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 11, MSTPSR10, 0), /* SSI4 */ + [MSTP1010] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 10, MSTPSR10, 0), /* SSI5 */ + [MSTP1009] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 9, MSTPSR10, 0), /* SSI6 */ + [MSTP1008] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 8, MSTPSR10, 0), /* SSI7 */ + [MSTP1007] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 7, MSTPSR10, 0), /* SSI8 */ + [MSTP1006] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 6, MSTPSR10, 0), /* SSI9 */ + [MSTP1005] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR10, 5, MSTPSR10, 0), /* SSI ALL */ + [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ + [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ + [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ + [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ + [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ + [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */ + [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */ + [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ + [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */ + [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */ + [MSTP809] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 9, MSTPSR8, 0), /* VIN2 */ + [MSTP808] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 8, MSTPSR8, 0), /* VIN3 */ + [MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */ + [MSTP725] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 25, MSTPSR7, 0), /* LVDS1 */ + [MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */ + [MSTP723] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 23, MSTPSR7, 0), /* DU1 */ + [MSTP722] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 22, MSTPSR7, 0), /* DU2 */ + [MSTP721] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 21, MSTPSR7, 0), /* SCIF0 */ + [MSTP720] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 20, MSTPSR7, 0), /* SCIF1 */ + [MSTP717] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 17, MSTPSR7, 0), /* HSCIF0 */ + [MSTP716] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR7, 16, MSTPSR7, 0), /* HSCIF1 */ + [MSTP704] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 4, MSTPSR7, 0), /* HSUSB */ + [MSTP703] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR7, 3, MSTPSR7, 0), /* EHCI */ + [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */ + [MSTP502] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 2, MSTPSR5, 0), /* Audio-DMAC low */ + [MSTP501] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR5, 1, MSTPSR5, 0), /* Audio-DMAC hi */ + [MSTP315] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_MMC0], SMSTPCR3, 15, MSTPSR3, 0), /* MMC0 */ + [MSTP314] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD0], SMSTPCR3, 14, MSTPSR3, 0), /* SDHI0 */ + [MSTP313] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD1], SMSTPCR3, 13, MSTPSR3, 0), /* SDHI1 */ + [MSTP312] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD2], SMSTPCR3, 12, MSTPSR3, 0), /* SDHI2 */ + [MSTP311] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD3], SMSTPCR3, 11, MSTPSR3, 0), /* SDHI3 */ + [MSTP305] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_MMC1], SMSTPCR3, 5, MSTPSR3, 0), /* MMC1 */ + [MSTP304] = SH_CLK_MSTP32_STS(&cp_clk, SMSTPCR3, 4, MSTPSR3, 0), /* TPU0 */ + [MSTP216] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 16, MSTPSR2, 0), /* SCIFB2 */ + [MSTP207] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 7, MSTPSR2, 0), /* SCIFB1 */ + [MSTP206] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 6, MSTPSR2, 0), /* SCIFB0 */ + [MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */ + [MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */ + [MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */ + [MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */ }; static struct clk_lookup lookups[] = { /* main clocks */ + CLKDEV_CON_ID("audio_clk_a", &audio_clk_a), + CLKDEV_CON_ID("audio_clk_b", &audio_clk_b), + CLKDEV_CON_ID("audio_clk_c", &audio_clk_c), + CLKDEV_CON_ID("audio_clk_internal", &m2_clk), CLKDEV_CON_ID("extal", &extal_clk), CLKDEV_CON_ID("extal_div2", &extal_div2_clk), CLKDEV_CON_ID("main", &main_clk), @@ -291,32 +343,32 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP720]), CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP717]), CLKDEV_DEV_ID("sh-sci.9", &mstp_clks[MSTP716]), - CLKDEV_DEV_ID("e6508000.i2c", &mstp_clks[MSTP931]), CLKDEV_DEV_ID("i2c-rcar_gen2.0", &mstp_clks[MSTP931]), - CLKDEV_DEV_ID("e6518000.i2c", &mstp_clks[MSTP930]), CLKDEV_DEV_ID("i2c-rcar_gen2.1", &mstp_clks[MSTP930]), - CLKDEV_DEV_ID("e6530000.i2c", &mstp_clks[MSTP929]), CLKDEV_DEV_ID("i2c-rcar_gen2.2", &mstp_clks[MSTP929]), - CLKDEV_DEV_ID("e6540000.i2c", &mstp_clks[MSTP928]), CLKDEV_DEV_ID("i2c-rcar_gen2.3", &mstp_clks[MSTP928]), CLKDEV_DEV_ID("r8a7790-ether", &mstp_clks[MSTP813]), - CLKDEV_DEV_ID("e61f0000.thermal", &mstp_clks[MSTP522]), + CLKDEV_DEV_ID("r8a7790-vin.0", &mstp_clks[MSTP811]), + CLKDEV_DEV_ID("r8a7790-vin.1", &mstp_clks[MSTP810]), + CLKDEV_DEV_ID("r8a7790-vin.2", &mstp_clks[MSTP809]), + CLKDEV_DEV_ID("r8a7790-vin.3", &mstp_clks[MSTP808]), CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]), - CLKDEV_DEV_ID("ee200000.mmc", &mstp_clks[MSTP315]), + CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP502]), + CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP501]), CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP315]), - CLKDEV_DEV_ID("ee100000.sd", &mstp_clks[MSTP314]), CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), - CLKDEV_DEV_ID("ee120000.sd", &mstp_clks[MSTP313]), CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), - CLKDEV_DEV_ID("ee140000.sd", &mstp_clks[MSTP312]), CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP312]), - CLKDEV_DEV_ID("ee160000.sd", &mstp_clks[MSTP311]), CLKDEV_DEV_ID("sh_mobile_sdhi.3", &mstp_clks[MSTP311]), - CLKDEV_DEV_ID("ee220000.mmc", &mstp_clks[MSTP305]), CLKDEV_DEV_ID("sh_mmcif.1", &mstp_clks[MSTP305]), CLKDEV_DEV_ID("sh_cmt.0", &mstp_clks[MSTP124]), CLKDEV_DEV_ID("qspi.0", &mstp_clks[MSTP917]), CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP704]), + CLKDEV_DEV_ID("pci-rcar-gen2.0", &mstp_clks[MSTP703]), + CLKDEV_DEV_ID("pci-rcar-gen2.1", &mstp_clks[MSTP703]), + CLKDEV_DEV_ID("pci-rcar-gen2.2", &mstp_clks[MSTP703]), + CLKDEV_DEV_ID("sata-r8a7790.0", &mstp_clks[MSTP815]), + CLKDEV_DEV_ID("sata-r8a7790.1", &mstp_clks[MSTP814]), /* ICK */ CLKDEV_ICK_ID("usbhs", "usb_phy_rcar_gen2", &mstp_clks[MSTP704]), @@ -325,6 +377,20 @@ static struct clk_lookup lookups[] = { CLKDEV_ICK_ID("du.0", "rcar-du-r8a7790", &mstp_clks[MSTP724]), CLKDEV_ICK_ID("du.1", "rcar-du-r8a7790", &mstp_clks[MSTP723]), CLKDEV_ICK_ID("du.2", "rcar-du-r8a7790", &mstp_clks[MSTP722]), + CLKDEV_ICK_ID("clk_a", "rcar_sound", &audio_clk_a), + CLKDEV_ICK_ID("clk_b", "rcar_sound", &audio_clk_b), + CLKDEV_ICK_ID("clk_c", "rcar_sound", &audio_clk_c), + CLKDEV_ICK_ID("clk_i", "rcar_sound", &m2_clk), + CLKDEV_ICK_ID("scu.0", "rcar_sound", &mstp_clks[MSTP1031]), + CLKDEV_ICK_ID("scu.1", "rcar_sound", &mstp_clks[MSTP1030]), + CLKDEV_ICK_ID("scu.2", "rcar_sound", &mstp_clks[MSTP1029]), + CLKDEV_ICK_ID("scu.3", "rcar_sound", &mstp_clks[MSTP1028]), + CLKDEV_ICK_ID("scu.4", "rcar_sound", &mstp_clks[MSTP1027]), + CLKDEV_ICK_ID("scu.5", "rcar_sound", &mstp_clks[MSTP1026]), + CLKDEV_ICK_ID("scu.6", "rcar_sound", &mstp_clks[MSTP1025]), + CLKDEV_ICK_ID("scu.7", "rcar_sound", &mstp_clks[MSTP1024]), + CLKDEV_ICK_ID("scu.8", "rcar_sound", &mstp_clks[MSTP1023]), + CLKDEV_ICK_ID("scu.9", "rcar_sound", &mstp_clks[MSTP1022]), CLKDEV_ICK_ID("ssi.0", "rcar_sound", &mstp_clks[MSTP1015]), CLKDEV_ICK_ID("ssi.1", "rcar_sound", &mstp_clks[MSTP1014]), CLKDEV_ICK_ID("ssi.2", "rcar_sound", &mstp_clks[MSTP1013]), diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index f5461262ee25..701383fe3267 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -59,10 +59,19 @@ #define SMSTPCR10 0xE6150998 #define SMSTPCR11 0xE615099C +#define MSTPSR1 IOMEM(0xe6150038) +#define MSTPSR2 IOMEM(0xe6150040) +#define MSTPSR3 IOMEM(0xe6150048) +#define MSTPSR5 IOMEM(0xe615003c) +#define MSTPSR7 IOMEM(0xe61501c4) +#define MSTPSR8 IOMEM(0xe61509a0) +#define MSTPSR9 IOMEM(0xe61509a4) +#define MSTPSR11 IOMEM(0xe61509ac) + #define MODEMR 0xE6160060 #define SDCKCR 0xE6150074 -#define SD2CKCR 0xE6150078 -#define SD3CKCR 0xE615007C +#define SD1CKCR 0xE6150078 +#define SD2CKCR 0xE615026c #define MMC0CKCR 0xE6150240 #define MMC1CKCR 0xE6150244 #define SSPCKCR 0xE6150248 @@ -93,6 +102,7 @@ static struct clk main_clk = { */ SH_FIXED_RATIO_CLK_SET(pll1_clk, main_clk, 1, 1); SH_FIXED_RATIO_CLK_SET(pll3_clk, main_clk, 1, 1); +SH_FIXED_RATIO_CLK_SET(qspi_clk, pll1_clk, 1, 1); /* fixed ratio clock */ SH_FIXED_RATIO_CLK_SET(extal_div2_clk, extal_clk, 1, 2); @@ -103,7 +113,9 @@ SH_FIXED_RATIO_CLK_SET(hp_clk, pll1_clk, 1, 12); SH_FIXED_RATIO_CLK_SET(p_clk, pll1_clk, 1, 24); SH_FIXED_RATIO_CLK_SET(rclk_clk, pll1_clk, 1, (48 * 1024)); SH_FIXED_RATIO_CLK_SET(mp_clk, pll1_div2_clk, 1, 15); +SH_FIXED_RATIO_CLK_SET(zg_clk, pll1_clk, 1, 3); SH_FIXED_RATIO_CLK_SET(zx_clk, pll1_clk, 1, 3); +SH_FIXED_RATIO_CLK_SET(zs_clk, pll1_clk, 1, 6); static struct clk *main_clks[] = { &extal_clk, @@ -114,46 +126,103 @@ static struct clk *main_clks[] = { &pll3_clk, &hp_clk, &p_clk, + &qspi_clk, &rclk_clk, &mp_clk, &cp_clk, + &zg_clk, &zx_clk, + &zs_clk, +}; + +/* SDHI (DIV4) clock */ +static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, 24, 0, 36, 48, 10 }; + +static struct clk_div_mult_table div4_div_mult_table = { + .divisors = divisors, + .nr_divisors = ARRAY_SIZE(divisors), +}; + +static struct clk_div4_table div4_table = { + .div_mult_table = &div4_div_mult_table, +}; + +enum { + DIV4_SDH, DIV4_SD0, + DIV4_NR +}; + +static struct clk div4_clks[DIV4_NR] = { + [DIV4_SDH] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 8, 0x0dff, CLK_ENABLE_ON_INIT), + [DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1de0, CLK_ENABLE_ON_INIT), +}; + +/* DIV6 clocks */ +enum { + DIV6_SD1, DIV6_SD2, + DIV6_NR +}; + +static struct clk div6_clks[DIV6_NR] = { + [DIV6_SD1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0), + [DIV6_SD2] = SH_CLK_DIV6(&pll1_div2_clk, SD2CKCR, 0), }; /* MSTP */ enum { + MSTP1108, MSTP1107, MSTP1106, + MSTP931, MSTP930, MSTP929, MSTP928, MSTP927, MSTP925, + MSTP917, + MSTP815, MSTP814, MSTP813, + MSTP811, MSTP810, MSTP809, MSTP726, MSTP724, MSTP723, MSTP721, MSTP720, MSTP719, MSTP718, MSTP715, MSTP714, MSTP522, + MSTP314, MSTP312, MSTP311, MSTP216, MSTP207, MSTP206, - MSTP204, MSTP203, MSTP202, MSTP1105, MSTP1106, MSTP1107, + MSTP204, MSTP203, MSTP202, MSTP124, MSTP_NR }; static struct clk mstp_clks[MSTP_NR] = { - [MSTP813] = SH_CLK_MSTP32(&p_clk, SMSTPCR8, 13, 0), /* Ether */ - [MSTP726] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 26, 0), /* LVDS0 */ - [MSTP724] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 24, 0), /* DU0 */ - [MSTP723] = SH_CLK_MSTP32(&zx_clk, SMSTPCR7, 23, 0), /* DU1 */ - [MSTP721] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 21, 0), /* SCIF0 */ - [MSTP720] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 20, 0), /* SCIF1 */ - [MSTP719] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 19, 0), /* SCIF2 */ - [MSTP718] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 18, 0), /* SCIF3 */ - [MSTP715] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 15, 0), /* SCIF4 */ - [MSTP714] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 14, 0), /* SCIF5 */ - [MSTP522] = SH_CLK_MSTP32(&extal_clk, SMSTPCR5, 22, 0), /* Thermal */ - [MSTP216] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 16, 0), /* SCIFB2 */ - [MSTP207] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 7, 0), /* SCIFB1 */ - [MSTP206] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 6, 0), /* SCIFB0 */ - [MSTP204] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 4, 0), /* SCIFA0 */ - [MSTP203] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 3, 0), /* SCIFA1 */ - [MSTP202] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 2, 0), /* SCIFA2 */ - [MSTP1105] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 5, 0), /* SCIFA3 */ - [MSTP1106] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 6, 0), /* SCIFA4 */ - [MSTP1107] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 7, 0), /* SCIFA5 */ - [MSTP124] = SH_CLK_MSTP32(&rclk_clk, SMSTPCR1, 24, 0), /* CMT0 */ + [MSTP1108] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 8, MSTPSR11, 0), /* SCIFA5 */ + [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA4 */ + [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA3 */ + [MSTP931] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ + [MSTP930] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ + [MSTP929] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ + [MSTP928] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ + [MSTP927] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */ + [MSTP925] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */ + [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ + [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */ + [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */ + [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ + [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */ + [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */ + [MSTP809] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 9, MSTPSR8, 0), /* VIN2 */ + [MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */ + [MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */ + [MSTP723] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 23, MSTPSR7, 0), /* DU1 */ + [MSTP721] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 21, MSTPSR7, 0), /* SCIF0 */ + [MSTP720] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 20, MSTPSR7, 0), /* SCIF1 */ + [MSTP719] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 19, MSTPSR7, 0), /* SCIF2 */ + [MSTP718] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 18, MSTPSR7, 0), /* SCIF3 */ + [MSTP715] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 15, MSTPSR7, 0), /* SCIF4 */ + [MSTP714] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 14, MSTPSR7, 0), /* SCIF5 */ + [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */ + [MSTP314] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD0], SMSTPCR3, 14, MSTPSR3, 0), /* SDHI0 */ + [MSTP312] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD1], SMSTPCR3, 12, MSTPSR3, 0), /* SDHI1 */ + [MSTP311] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD2], SMSTPCR3, 11, MSTPSR3, 0), /* SDHI2 */ + [MSTP216] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 16, MSTPSR2, 0), /* SCIFB2 */ + [MSTP207] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 7, MSTPSR2, 0), /* SCIFB1 */ + [MSTP206] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 6, MSTPSR2, 0), /* SCIFB0 */ + [MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */ + [MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */ + [MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */ + [MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */ }; static struct clk_lookup lookups[] = { @@ -165,8 +234,11 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("pll1", &pll1_clk), CLKDEV_CON_ID("pll1_div2", &pll1_div2_clk), CLKDEV_CON_ID("pll3", &pll3_clk), + CLKDEV_CON_ID("zg", &zg_clk), + CLKDEV_CON_ID("zs", &zs_clk), CLKDEV_CON_ID("hp", &hp_clk), CLKDEV_CON_ID("p", &p_clk), + CLKDEV_CON_ID("qspi", &qspi_clk), CLKDEV_CON_ID("rclk", &rclk_clk), CLKDEV_CON_ID("mp", &mp_clk), CLKDEV_CON_ID("cp", &cp_clk), @@ -188,13 +260,27 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-sci.9", &mstp_clks[MSTP718]), /* SCIF3 */ CLKDEV_DEV_ID("sh-sci.10", &mstp_clks[MSTP715]), /* SCIF4 */ CLKDEV_DEV_ID("sh-sci.11", &mstp_clks[MSTP714]), /* SCIF5 */ - CLKDEV_DEV_ID("sh-sci.12", &mstp_clks[MSTP1105]), /* SCIFA3 */ - CLKDEV_DEV_ID("sh-sci.13", &mstp_clks[MSTP1106]), /* SCIFA4 */ - CLKDEV_DEV_ID("sh-sci.14", &mstp_clks[MSTP1107]), /* SCIFA5 */ + CLKDEV_DEV_ID("sh-sci.12", &mstp_clks[MSTP1106]), /* SCIFA3 */ + CLKDEV_DEV_ID("sh-sci.13", &mstp_clks[MSTP1107]), /* SCIFA4 */ + CLKDEV_DEV_ID("sh-sci.14", &mstp_clks[MSTP1108]), /* SCIFA5 */ + CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), + CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP312]), + CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), CLKDEV_DEV_ID("sh_cmt.0", &mstp_clks[MSTP124]), - CLKDEV_DEV_ID("e61f0000.thermal", &mstp_clks[MSTP522]), + CLKDEV_DEV_ID("qspi.0", &mstp_clks[MSTP917]), CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]), + CLKDEV_DEV_ID("i2c-rcar_gen2.0", &mstp_clks[MSTP931]), + CLKDEV_DEV_ID("i2c-rcar_gen2.1", &mstp_clks[MSTP930]), + CLKDEV_DEV_ID("i2c-rcar_gen2.2", &mstp_clks[MSTP929]), + CLKDEV_DEV_ID("i2c-rcar_gen2.3", &mstp_clks[MSTP928]), + CLKDEV_DEV_ID("i2c-rcar_gen2.4", &mstp_clks[MSTP927]), + CLKDEV_DEV_ID("i2c-rcar_gen2.5", &mstp_clks[MSTP925]), CLKDEV_DEV_ID("r8a7791-ether", &mstp_clks[MSTP813]), /* Ether */ + CLKDEV_DEV_ID("r8a7791-vin.0", &mstp_clks[MSTP811]), + CLKDEV_DEV_ID("r8a7791-vin.1", &mstp_clks[MSTP810]), + CLKDEV_DEV_ID("r8a7791-vin.2", &mstp_clks[MSTP809]), + CLKDEV_DEV_ID("sata-r8a7791.0", &mstp_clks[MSTP815]), + CLKDEV_DEV_ID("sata-r8a7791.1", &mstp_clks[MSTP814]), }; #define R8A7791_CLOCK_ROOT(e, m, p0, p1, p30, p31) \ @@ -232,10 +318,21 @@ void __init r8a7791_clock_init(void) break; } + if ((mode & (MD(3) | MD(2) | MD(1))) == MD(2)) + SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 16); + else + SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 20); + for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) ret = clk_register(main_clks[k]); if (!ret) + ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + + if (!ret) + ret = sh_clk_div6_register(div6_clks, DIV6_NR); + + if (!ret) ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); clkdev_add_table(lookups, ARRAY_SIZE(lookups)); diff --git a/arch/arm/mach-shmobile/include/mach/r8a7790.h b/arch/arm/mach-shmobile/include/mach/r8a7790.h index 5fbfa28b40b6..2177325af22f 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7790.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7790.h @@ -3,6 +3,31 @@ #include <mach/rcar-gen2.h> +/* DMA slave IDs */ +enum { + RCAR_DMA_SLAVE_INVALID, + AUDIO_DMAC_SLAVE_SSI0_TX, + AUDIO_DMAC_SLAVE_SSI0_RX, + AUDIO_DMAC_SLAVE_SSI1_TX, + AUDIO_DMAC_SLAVE_SSI1_RX, + AUDIO_DMAC_SLAVE_SSI2_TX, + AUDIO_DMAC_SLAVE_SSI2_RX, + AUDIO_DMAC_SLAVE_SSI3_TX, + AUDIO_DMAC_SLAVE_SSI3_RX, + AUDIO_DMAC_SLAVE_SSI4_TX, + AUDIO_DMAC_SLAVE_SSI4_RX, + AUDIO_DMAC_SLAVE_SSI5_TX, + AUDIO_DMAC_SLAVE_SSI5_RX, + AUDIO_DMAC_SLAVE_SSI6_TX, + AUDIO_DMAC_SLAVE_SSI6_RX, + AUDIO_DMAC_SLAVE_SSI7_TX, + AUDIO_DMAC_SLAVE_SSI7_RX, + AUDIO_DMAC_SLAVE_SSI8_TX, + AUDIO_DMAC_SLAVE_SSI8_RX, + AUDIO_DMAC_SLAVE_SSI9_TX, + AUDIO_DMAC_SLAVE_SSI9_RX, +}; + void r8a7790_add_standard_devices(void); void r8a7790_add_dt_devices(void); void r8a7790_clock_init(void); diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index 6ab37aa1e919..c4616f0698c6 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -24,12 +24,100 @@ #include <linux/platform_data/gpio-rcar.h> #include <linux/platform_data/irq-renesas-irqc.h> #include <linux/serial_sci.h> +#include <linux/sh_dma.h> #include <linux/sh_timer.h> #include <mach/common.h> +#include <mach/dma-register.h> #include <mach/irqs.h> #include <mach/r8a7790.h> #include <asm/mach/arch.h> +/* Audio-DMAC */ +#define AUDIO_DMAC_SLAVE(_id, _addr, t, r) \ +{ \ + .slave_id = AUDIO_DMAC_SLAVE_## _id ##_TX, \ + .addr = _addr + 0x8, \ + .chcr = CHCR_TX(XMIT_SZ_32BIT), \ + .mid_rid = t, \ +}, { \ + .slave_id = AUDIO_DMAC_SLAVE_## _id ##_RX, \ + .addr = _addr + 0xc, \ + .chcr = CHCR_RX(XMIT_SZ_32BIT), \ + .mid_rid = r, \ +} + +static const struct sh_dmae_slave_config r8a7790_audio_dmac_slaves[] = { + AUDIO_DMAC_SLAVE(SSI0, 0xec241000, 0x01, 0x02), + AUDIO_DMAC_SLAVE(SSI1, 0xec241040, 0x03, 0x04), + AUDIO_DMAC_SLAVE(SSI2, 0xec241080, 0x05, 0x06), + AUDIO_DMAC_SLAVE(SSI3, 0xec2410c0, 0x07, 0x08), + AUDIO_DMAC_SLAVE(SSI4, 0xec241100, 0x09, 0x0a), + AUDIO_DMAC_SLAVE(SSI5, 0xec241140, 0x0b, 0x0c), + AUDIO_DMAC_SLAVE(SSI6, 0xec241180, 0x0d, 0x0e), + AUDIO_DMAC_SLAVE(SSI7, 0xec2411c0, 0x0f, 0x10), + AUDIO_DMAC_SLAVE(SSI8, 0xec241200, 0x11, 0x12), + AUDIO_DMAC_SLAVE(SSI9, 0xec241240, 0x13, 0x14), +}; + +#define DMAE_CHANNEL(a, b) \ +{ \ + .offset = (a) - 0x20, \ + .dmars = (a) - 0x20 + 0x40, \ + .chclr_bit = (b), \ + .chclr_offset = 0x80 - 0x20, \ +} + +static const struct sh_dmae_channel r8a7790_audio_dmac_channels[] = { + DMAE_CHANNEL(0x8000, 0), + DMAE_CHANNEL(0x8080, 1), + DMAE_CHANNEL(0x8100, 2), + DMAE_CHANNEL(0x8180, 3), + DMAE_CHANNEL(0x8200, 4), + DMAE_CHANNEL(0x8280, 5), + DMAE_CHANNEL(0x8300, 6), + DMAE_CHANNEL(0x8380, 7), + DMAE_CHANNEL(0x8400, 8), + DMAE_CHANNEL(0x8480, 9), + DMAE_CHANNEL(0x8500, 10), + DMAE_CHANNEL(0x8580, 11), + DMAE_CHANNEL(0x8600, 12), +}; + +static struct sh_dmae_pdata r8a7790_audio_dmac_platform_data = { + .slave = r8a7790_audio_dmac_slaves, + .slave_num = ARRAY_SIZE(r8a7790_audio_dmac_slaves), + .channel = r8a7790_audio_dmac_channels, + .channel_num = ARRAY_SIZE(r8a7790_audio_dmac_channels), + .ts_low_shift = TS_LOW_SHIFT, + .ts_low_mask = TS_LOW_BIT << TS_LOW_SHIFT, + .ts_high_shift = TS_HI_SHIFT, + .ts_high_mask = TS_HI_BIT << TS_HI_SHIFT, + .ts_shift = dma_ts_shift, + .ts_shift_num = ARRAY_SIZE(dma_ts_shift), + .dmaor_init = DMAOR_DME, + .chclr_present = 1, + .chclr_bitwise = 1, +}; + +static struct resource r8a7790_audio_dmac_resources[] = { + /* Channel registers and DMAOR for low */ + DEFINE_RES_MEM(0xec700020, 0x8663 - 0x20), + DEFINE_RES_IRQ(gic_spi(346)), + DEFINE_RES_NAMED(gic_spi(320), 13, NULL, IORESOURCE_IRQ), + + /* Channel registers and DMAOR for hi */ + DEFINE_RES_MEM(0xec720020, 0x8663 - 0x20), /* hi */ + DEFINE_RES_IRQ(gic_spi(347)), + DEFINE_RES_NAMED(gic_spi(333), 13, NULL, IORESOURCE_IRQ), +}; + +#define r8a7790_register_audio_dmac(id) \ + platform_device_register_resndata( \ + &platform_bus, "sh-dma-engine", id, \ + &r8a7790_audio_dmac_resources[id * 3], 3, \ + &r8a7790_audio_dmac_platform_data, \ + sizeof(r8a7790_audio_dmac_platform_data)) + static const struct resource pfc_resources[] __initconst = { DEFINE_RES_MEM(0xe6060000, 0x250), }; @@ -101,6 +189,8 @@ void __init r8a7790_pinmux_init(void) r8a7790_register_i2c(1); r8a7790_register_i2c(2); r8a7790_register_i2c(3); + r8a7790_register_audio_dmac(0); + r8a7790_register_audio_dmac(1); } #define __R8A7790_SCIF(scif_type, _scscr, index, baseaddr, irq) \ diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig index d2c13ba1190b..abf9ee9bbc3f 100644 --- a/arch/arm/mach-sti/Kconfig +++ b/arch/arm/mach-sti/Kconfig @@ -5,6 +5,7 @@ menuconfig ARCH_STI select PINCTRL select PINCTRL_ST select MFD_SYSCON + select ARCH_HAS_RESET_CONTROLLER select HAVE_ARM_SCU if SMP select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_754322 @@ -24,6 +25,7 @@ if ARCH_STI config SOC_STIH415 bool "STiH415 STMicroelectronics Consumer Electronics family" default y + select STIH415_RESET help This enables support for STMicroelectronics Digital Consumer Electronics family StiH415 parts, primarily targeted at set-top-box @@ -33,6 +35,7 @@ config SOC_STIH415 config SOC_STIH416 bool "STiH416 STMicroelectronics Consumer Electronics family" default y + select STIH416_RESET help This enables support for STMicroelectronics Digital Consumer Electronics family StiH416 parts, primarily targeted at set-top-box diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index a335126ae18f..f2c89fb8fca9 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c @@ -108,7 +108,7 @@ void __init versatile_init_irq(void) np = of_find_matching_node_by_address(NULL, vic_of_match, VERSATILE_VIC_BASE); - __vic_init(VA_VIC_BASE, IRQ_VIC_START, ~0, 0, np); + __vic_init(VA_VIC_BASE, 0, IRQ_VIC_START, ~0, 0, np); writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 830ff07f3385..3ec6e8e8d368 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -595,14 +595,16 @@ void __init orion_spi_1_init(unsigned long mapbase) /***************************************************************************** * Watchdog ****************************************************************************/ -static struct resource orion_wdt_resource = - DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28); +static struct resource orion_wdt_resource[] = { + DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04), + DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04), +}; static struct platform_device orion_wdt_device = { .name = "orion_wdt", .id = -1, - .num_resources = 1, - .resource = &orion_wdt_resource, + .num_resources = ARRAY_SIZE(orion_wdt_resource), + .resource = orion_wdt_resource, }; void __init orion_wdt_init(void) diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile index 22fb66590dcd..dba48a5d5bb9 100644 --- a/arch/avr32/Makefile +++ b/arch/avr32/Makefile @@ -11,7 +11,7 @@ all: uImage vmlinux.elf KBUILD_DEFCONFIG := atstk1002_defconfig -KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic +KBUILD_CFLAGS += -pipe -fno-builtin -mno-pic -D__linux__ KBUILD_AFLAGS += -mrelax -mno-pic KBUILD_CFLAGS_MODULE += -mno-relax LDFLAGS_vmlinux += --relax diff --git a/arch/avr32/boards/mimc200/fram.c b/arch/avr32/boards/mimc200/fram.c index 9764a1a1073e..c1466a872b9c 100644 --- a/arch/avr32/boards/mimc200/fram.c +++ b/arch/avr32/boards/mimc200/fram.c @@ -11,6 +11,7 @@ #define FRAM_VERSION "1.0" #include <linux/miscdevice.h> +#include <linux/module.h> #include <linux/proc_fs.h> #include <linux/mm.h> #include <linux/io.h> diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild index cfb9fe1b8df9..c7c64a63c29f 100644 --- a/arch/avr32/include/asm/Kbuild +++ b/arch/avr32/include/asm/Kbuild @@ -17,5 +17,6 @@ generic-y += scatterlist.h generic-y += sections.h generic-y += topology.h generic-y += trace_clock.h +generic-y += vga.h generic-y += xor.h generic-y += hash.h diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h index fc6483f83ccc..4f5ec2bb7172 100644 --- a/arch/avr32/include/asm/io.h +++ b/arch/avr32/include/asm/io.h @@ -295,6 +295,8 @@ extern void __iounmap(void __iomem *addr); #define iounmap(addr) \ __iounmap(addr) +#define ioremap_wc ioremap_nocache + #define cached(addr) P1SEGADDR(addr) #define uncached(addr) P2SEGADDR(addr) diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 9e39ceb1d19f..d4dd41fb951b 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h @@ -172,10 +172,20 @@ struct eeh_ops { }; extern struct eeh_ops *eeh_ops; -extern int eeh_subsystem_enabled; +extern bool eeh_subsystem_enabled; extern raw_spinlock_t confirm_error_lock; extern int eeh_probe_mode; +static inline bool eeh_enabled(void) +{ + return eeh_subsystem_enabled; +} + +static inline void eeh_set_enable(bool mode) +{ + eeh_subsystem_enabled = mode; +} + #define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */ #define EEH_PROBE_MODE_DEVTREE (1<<1) /* From device tree */ @@ -246,7 +256,7 @@ void eeh_remove_device(struct pci_dev *); * If this macro yields TRUE, the caller relays to eeh_check_failure() * which does further tests out of line. */ -#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_subsystem_enabled) +#define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_enabled()) /* * Reads from a device which has been isolated by EEH will return @@ -257,6 +267,13 @@ void eeh_remove_device(struct pci_dev *); #else /* !CONFIG_EEH */ +static inline bool eeh_enabled(void) +{ + return false; +} + +static inline void eeh_set_enable(bool mode) { } + static inline int eeh_init(void) { return 0; diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h index d750336b171d..623f2971ce0e 100644 --- a/arch/powerpc/include/asm/hugetlb.h +++ b/arch/powerpc/include/asm/hugetlb.h @@ -127,7 +127,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { #ifdef CONFIG_PPC64 - return __pte(pte_update(mm, addr, ptep, ~0UL, 1)); + return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 1)); #else return __pte(pte_update(ptep, ~0UL, 0)); #endif diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index bc141c950b1e..eb9261024f51 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h @@ -195,6 +195,7 @@ extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr, static inline unsigned long pte_update(struct mm_struct *mm, unsigned long addr, pte_t *ptep, unsigned long clr, + unsigned long set, int huge) { #ifdef PTE_ATOMIC_UPDATES @@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm, andi. %1,%0,%6\n\ bne- 1b \n\ andc %1,%0,%4 \n\ + or %1,%1,%7\n\ stdcx. %1,0,%3 \n\ bne- 1b" : "=&r" (old), "=&r" (tmp), "=m" (*ptep) - : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY) + : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY), "r" (set) : "cc" ); #else unsigned long old = pte_val(*ptep); - *ptep = __pte(old & ~clr); + *ptep = __pte((old & ~clr) | set); #endif /* huge pages use the old page table lock */ if (!huge) @@ -231,9 +233,9 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm, { unsigned long old; - if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) + if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) return 0; - old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0); + old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0); return (old & _PAGE_ACCESSED) != 0; } #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG @@ -252,7 +254,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, if ((pte_val(*ptep) & _PAGE_RW) == 0) return; - pte_update(mm, addr, ptep, _PAGE_RW, 0); + pte_update(mm, addr, ptep, _PAGE_RW, 0, 0); } static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, @@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, if ((pte_val(*ptep) & _PAGE_RW) == 0) return; - pte_update(mm, addr, ptep, _PAGE_RW, 1); + pte_update(mm, addr, ptep, _PAGE_RW, 0, 1); } /* @@ -284,14 +286,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0); + unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0); return __pte(old); } static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t * ptep) { - pte_update(mm, addr, ptep, ~0UL, 0); + pte_update(mm, addr, ptep, ~0UL, 0, 0); } @@ -506,7 +508,9 @@ extern int pmdp_set_access_flags(struct vm_area_struct *vma, extern unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, - pmd_t *pmdp, unsigned long clr); + pmd_t *pmdp, + unsigned long clr, + unsigned long set); static inline int __pmdp_test_and_clear_young(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp) @@ -515,7 +519,7 @@ static inline int __pmdp_test_and_clear_young(struct mm_struct *mm, if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0) return 0; - old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED); + old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0); return ((old & _PAGE_ACCESSED) != 0); } @@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr, if ((pmd_val(*pmdp) & _PAGE_RW) == 0) return; - pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW); + pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0); } #define __HAVE_ARCH_PMDP_SPLITTING_FLUSH diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index f83b6f3e1b39..3ebb188c3ff5 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h @@ -75,12 +75,34 @@ static inline pte_t pte_mknuma(pte_t pte) return pte; } +#define ptep_set_numa ptep_set_numa +static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + if ((pte_val(*ptep) & _PAGE_PRESENT) == 0) + VM_BUG_ON(1); + + pte_update(mm, addr, ptep, _PAGE_PRESENT, _PAGE_NUMA, 0); + return; +} + #define pmd_numa pmd_numa static inline int pmd_numa(pmd_t pmd) { return pte_numa(pmd_pte(pmd)); } +#define pmdp_set_numa pmdp_set_numa +static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp) +{ + if ((pmd_val(*pmdp) & _PAGE_PRESENT) == 0) + VM_BUG_ON(1); + + pmd_hugepage_update(mm, addr, pmdp, _PAGE_PRESENT, _PAGE_NUMA); + return; +} + #define pmd_mknonnuma pmd_mknonnuma static inline pmd_t pmd_mknonnuma(pmd_t pmd) { diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h index 0d9cecddf8a4..c53f5f6d1761 100644 --- a/arch/powerpc/include/asm/vdso.h +++ b/arch/powerpc/include/asm/vdso.h @@ -4,11 +4,11 @@ #ifdef __KERNEL__ /* Default link addresses for the vDSOs */ -#define VDSO32_LBASE 0x100000 -#define VDSO64_LBASE 0x100000 +#define VDSO32_LBASE 0x0 +#define VDSO64_LBASE 0x0 /* Default map addresses for 32bit vDSO */ -#define VDSO32_MBASE VDSO32_LBASE +#define VDSO32_MBASE 0x100000 #define VDSO_VERSION_STRING LINUX_2.6.15 diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 148db72a8c43..e7b76a6bf150 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -28,6 +28,7 @@ #include <linux/pci.h> #include <linux/proc_fs.h> #include <linux/rbtree.h> +#include <linux/reboot.h> #include <linux/seq_file.h> #include <linux/spinlock.h> #include <linux/export.h> @@ -89,7 +90,7 @@ /* Platform dependent EEH operations */ struct eeh_ops *eeh_ops = NULL; -int eeh_subsystem_enabled; +bool eeh_subsystem_enabled = false; EXPORT_SYMBOL(eeh_subsystem_enabled); /* @@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev) eeh_stats.total_mmio_ffs++; - if (!eeh_subsystem_enabled) + if (!eeh_enabled()) return 0; if (!edev) { @@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name) return -EEXIST; } +static int eeh_reboot_notifier(struct notifier_block *nb, + unsigned long action, void *unused) +{ + eeh_set_enable(false); + return NOTIFY_DONE; +} + +static struct notifier_block eeh_reboot_nb = { + .notifier_call = eeh_reboot_notifier, +}; + /** * eeh_init - EEH initialization * @@ -778,6 +790,14 @@ int eeh_init(void) if (machine_is(powernv) && cnt++ <= 0) return ret; + /* Register reboot notifier */ + ret = register_reboot_notifier(&eeh_reboot_nb); + if (ret) { + pr_warn("%s: Failed to register notifier (%d)\n", + __func__, ret); + return ret; + } + /* call platform initialization function */ if (!eeh_ops) { pr_warning("%s: Platform EEH operation not found\n", @@ -822,7 +842,7 @@ int eeh_init(void) return ret; } - if (eeh_subsystem_enabled) + if (eeh_enabled()) pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); else pr_warning("EEH: No capable adapters found\n"); @@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev) struct device_node *dn; struct eeh_dev *edev; - if (!dev || !eeh_subsystem_enabled) + if (!dev || !eeh_enabled()) return; pr_debug("EEH: Adding device %s\n", pci_name(dev)); @@ -1005,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev) { struct eeh_dev *edev; - if (!dev || !eeh_subsystem_enabled) + if (!dev || !eeh_enabled()) return; edev = pci_dev_to_eeh_dev(dev); @@ -1045,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev) static int proc_eeh_show(struct seq_file *m, void *v) { - if (0 == eeh_subsystem_enabled) { + if (!eeh_enabled()) { seq_printf(m, "EEH Subsystem is globally disabled\n"); seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); } else { diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 879f09620f83..7c6bb4b17b49 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq) mtlr r0 blr +/* + * void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp); + */ _GLOBAL(call_do_irq) mflr r0 stw r0,4(r1) lwz r10,THREAD+KSP_LIMIT(r2) - addi r11,r3,THREAD_INFO_GAP + addi r11,r4,THREAD_INFO_GAP stwu r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4) mr r1,r4 stw r10,8(r1) diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S index 79683d0393f5..6ac107ac402a 100644 --- a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S +++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S @@ -6,7 +6,7 @@ .globl vdso32_start, vdso32_end .balign PAGE_SIZE vdso32_start: - .incbin "arch/powerpc/kernel/vdso32/vdso32.so" + .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg" .balign PAGE_SIZE vdso32_end: diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S index 8df9e2463007..df60fca6a13d 100644 --- a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S +++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S @@ -6,7 +6,7 @@ .globl vdso64_start, vdso64_end .balign PAGE_SIZE vdso64_start: - .incbin "arch/powerpc/kernel/vdso64/vdso64.so" + .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg" .balign PAGE_SIZE vdso64_end: diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 65b7b65e8708..62bf5e8e78da 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -510,7 +510,8 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address, } unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, - pmd_t *pmdp, unsigned long clr) + pmd_t *pmdp, unsigned long clr, + unsigned long set) { unsigned long old, tmp; @@ -526,14 +527,15 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr, andi. %1,%0,%6\n\ bne- 1b \n\ andc %1,%0,%4 \n\ + or %1,%1,%7\n\ stdcx. %1,0,%3 \n\ bne- 1b" : "=&r" (old), "=&r" (tmp), "=m" (*pmdp) - : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY) + : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY), "r" (set) : "cc" ); #else old = pmd_val(*pmdp); - *pmdp = __pmd(old & ~clr); + *pmdp = __pmd((old & ~clr) | set); #endif if (old & _PAGE_HASHPTE) hpte_do_hugepage_flush(mm, addr, pmdp); @@ -708,7 +710,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) { - pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT); + pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0); } /* @@ -835,7 +837,7 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm, unsigned long old; pgtable_t *pgtable_slot; - old = pmd_hugepage_update(mm, addr, pmdp, ~0UL); + old = pmd_hugepage_update(mm, addr, pmdp, ~0UL, 0); old_pmd = __pmd(old); /* * We have pmd == none and we are holding page_table_lock. diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c index a770df2dae70..6c0b1f5f8d2c 100644 --- a/arch/powerpc/mm/subpage-prot.c +++ b/arch/powerpc/mm/subpage-prot.c @@ -78,7 +78,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr, pte = pte_offset_map_lock(mm, pmd, addr, &ptl); arch_enter_lazy_mmu_mode(); for (; npages > 0; --npages) { - pte_update(mm, addr, pte, 0, 0); + pte_update(mm, addr, pte, 0, 0, 0); addr += PAGE_SIZE; ++pte; } diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index e1e71618b70c..f51474336460 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb, /* We simply send special EEH event */ if ((changed_evts & OPAL_EVENT_PCI_ERROR) && - (events & OPAL_EVENT_PCI_ERROR)) + (events & OPAL_EVENT_PCI_ERROR) && + eeh_enabled()) eeh_send_failure_event(NULL); return 0; @@ -489,8 +490,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose, static int ioda_eeh_reset(struct eeh_pe *pe, int option) { struct pci_controller *hose = pe->phb; - struct eeh_dev *edev; - struct pci_dev *dev; + struct pci_bus *bus; int ret; /* @@ -519,31 +519,11 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) if (pe->type & EEH_PE_PHB) { ret = ioda_eeh_phb_reset(hose, option); } else { - if (pe->type & EEH_PE_DEVICE) { - /* - * If it's device PE, we didn't refer to the parent - * PCI bus yet. So we have to figure it out indirectly. - */ - edev = list_first_entry(&pe->edevs, - struct eeh_dev, list); - dev = eeh_dev_to_pci_dev(edev); - dev = dev->bus->self; - } else { - /* - * If it's bus PE, the parent PCI bus is already there - * and just pick it up. - */ - dev = pe->bus->self; - } - - /* - * Do reset based on the fact that the direct upstream bridge - * is root bridge (port) or not. - */ - if (dev->bus->number == 0) + bus = eeh_pe_bus_get(pe); + if (pci_is_root_bus(bus)) ret = ioda_eeh_root_reset(hose, option); else - ret = ioda_eeh_bridge_reset(hose, dev, option); + ret = ioda_eeh_bridge_reset(hose, bus->self, option); } return ret; diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index a79fddc5e74e..a59788e83b8b 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -145,7 +145,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) * Enable EEH explicitly so that we will do EEH check * while accessing I/O stuff */ - eeh_subsystem_enabled = 1; + eeh_set_enable(true); /* Save memory bars */ eeh_save_bars(edev); diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 9ef3cc8ebc11..8a8f0472d98f 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) enable = 1; if (enable) { - eeh_subsystem_enabled = 1; + eeh_set_enable(true); eeh_add_to_parent_pe(edev); pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n", diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 70670a2d9cf2..c413ec158ff5 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -113,7 +113,8 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge) { struct device_node *dn, *pdn; struct pci_bus *bus; - const __be32 *pcie_link_speed_stats; + u32 pcie_link_speed_stats[2]; + int rc; bus = bridge->bus; @@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge) return 0; for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) { - pcie_link_speed_stats = of_get_property(pdn, - "ibm,pcie-link-speed-stats", NULL); - if (pcie_link_speed_stats) + rc = of_property_read_u32_array(pdn, + "ibm,pcie-link-speed-stats", + &pcie_link_speed_stats[0], 2); + if (!rc) break; } of_node_put(pdn); - if (!pcie_link_speed_stats) { + if (rc) { pr_err("no ibm,pcie-link-speed-stats property\n"); return 0; } - switch (be32_to_cpup(pcie_link_speed_stats)) { + switch (pcie_link_speed_stats[0]) { case 0x01: bus->max_bus_speed = PCIE_SPEED_2_5GT; break; case 0x02: bus->max_bus_speed = PCIE_SPEED_5_0GT; break; + case 0x04: + bus->max_bus_speed = PCIE_SPEED_8_0GT; + break; default: bus->max_bus_speed = PCI_SPEED_UNKNOWN; break; } - switch (be32_to_cpup(pcie_link_speed_stats)) { + switch (pcie_link_speed_stats[1]) { case 0x01: bus->cur_bus_speed = PCIE_SPEED_2_5GT; break; case 0x02: bus->cur_bus_speed = PCIE_SPEED_5_0GT; break; + case 0x04: + bus->cur_bus_speed = PCIE_SPEED_8_0GT; + break; default: bus->cur_bus_speed = PCI_SPEED_UNKNOWN; break; diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 1e16cbd61da2..61d6d62cc0d3 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -616,36 +616,35 @@ static int dma_buf_describe(struct seq_file *s) if (ret) return ret; - seq_printf(s, "\nDma-buf Objects:\n"); - seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n"); + seq_puts(s, "\nDma-buf Objects:\n"); + seq_puts(s, "size\tflags\tmode\tcount\texp_name\n"); list_for_each_entry(buf_obj, &db_list.head, list_node) { ret = mutex_lock_interruptible(&buf_obj->lock); if (ret) { - seq_printf(s, - "\tERROR locking buffer object: skipping\n"); + seq_puts(s, + "\tERROR locking buffer object: skipping\n"); continue; } - seq_printf(s, "\t"); - - seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n", - buf_obj->exp_name, buf_obj->size, + seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n", + buf_obj->size, buf_obj->file->f_flags, buf_obj->file->f_mode, - (long)(buf_obj->file->f_count.counter)); + (long)(buf_obj->file->f_count.counter), + buf_obj->exp_name); - seq_printf(s, "\t\tAttached Devices:\n"); + seq_puts(s, "\tAttached Devices:\n"); attach_count = 0; list_for_each_entry(attach_obj, &buf_obj->attachments, node) { - seq_printf(s, "\t\t"); + seq_puts(s, "\t"); - seq_printf(s, "%s\n", attach_obj->dev->init_name); + seq_printf(s, "%s\n", dev_name(attach_obj->dev)); attach_count++; } - seq_printf(s, "\n\t\tTotal %d devices attached\n", + seq_printf(s, "Total %d devices attached\n\n", attach_count); count++; diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 962fd35cbd8d..5a86da97a70b 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -31,7 +31,6 @@ #define DRIVER_NAME "CCI-400" #define DRIVER_NAME_PMU DRIVER_NAME " PMU" -#define PMU_NAME "CCI_400" #define CCI_PORT_CTRL 0x0 #define CCI_CTRL_STATUS 0xc @@ -88,8 +87,7 @@ static unsigned long cci_ctrl_phys; #define CCI_REV_R0 0 #define CCI_REV_R1 1 -#define CCI_REV_R0_P4 4 -#define CCI_REV_R1_P2 6 +#define CCI_REV_R1_PX 5 #define CCI_PMU_EVT_SEL 0x000 #define CCI_PMU_CNTR 0x004 @@ -163,6 +161,15 @@ static struct pmu_port_event_ranges port_event_range[] = { }, }; +/* + * Export different PMU names for the different revisions so userspace knows + * because the event ids are different + */ +static char *const pmu_names[] = { + [CCI_REV_R0] = "CCI_400", + [CCI_REV_R1] = "CCI_400_r1", +}; + struct cci_pmu_drv_data { void __iomem *base; struct arm_pmu *cci_pmu; @@ -193,21 +200,16 @@ static int probe_cci_revision(void) rev = readl_relaxed(cci_ctrl_base + CCI_PID2) & CCI_PID2_REV_MASK; rev >>= CCI_PID2_REV_SHIFT; - if (rev <= CCI_REV_R0_P4) + if (rev < CCI_REV_R1_PX) return CCI_REV_R0; - else if (rev <= CCI_REV_R1_P2) + else return CCI_REV_R1; - - return -ENOENT; } static struct pmu_port_event_ranges *port_range_by_rev(void) { int rev = probe_cci_revision(); - if (rev < 0) - return NULL; - return &port_event_range[rev]; } @@ -526,7 +528,7 @@ static void pmu_write_counter(struct perf_event *event, u32 value) static int cci_pmu_init(struct arm_pmu *cci_pmu, struct platform_device *pdev) { *cci_pmu = (struct arm_pmu){ - .name = PMU_NAME, + .name = pmu_names[probe_cci_revision()], .max_period = (1LLU << 32) - 1, .get_hw_events = pmu_get_hw_events, .get_event_idx = pmu_get_event_idx, diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index 725c46162bbd..31f2c805d3e5 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -890,13 +890,12 @@ int __init mvebu_mbus_dt_init(void) const __be32 *prop; int ret; - np = of_find_matching_node(NULL, of_mvebu_mbus_ids); + np = of_find_matching_node_and_match(NULL, of_mvebu_mbus_ids, &of_id); if (!np) { pr_err("could not find a matching SoC family\n"); return -ENODEV; } - of_id = of_match_node(of_mvebu_mbus_ids, np); mbus_state.soc = of_id->data; prop = of_get_property(np, "controller", NULL); diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 2f2b08457c67..244759bbd7b7 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -342,11 +342,11 @@ config HW_RANDOM_TPM If unsure, say Y. config HW_RANDOM_MSM - tristate "Qualcomm MSM Random Number Generator support" - depends on HW_RANDOM && ARCH_MSM + tristate "Qualcomm SoCs Random Number Generator support" + depends on HW_RANDOM && ARCH_QCOM ---help--- This driver provides kernel-side support for the Random Number - Generator hardware found on Qualcomm MSM SoCs. + Generator hardware found on Qualcomm SoCs. To compile this driver as a module, choose M here. the module will be called msm-rng. diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 7641965d208d..f9f605695e40 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -111,4 +111,5 @@ source "drivers/clk/qcom/Kconfig" endmenu +source "drivers/clk/bcm/Kconfig" source "drivers/clk/mvebu/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index a367a9831717..88af4a399d6c 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ +obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ ifeq ($(CONFIG_COMMON_CLK), y) diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig new file mode 100644 index 000000000000..a7262fb8ce55 --- /dev/null +++ b/drivers/clk/bcm/Kconfig @@ -0,0 +1,9 @@ +config CLK_BCM_KONA + bool "Broadcom Kona CCU clock support" + depends on ARCH_BCM_MOBILE + depends on COMMON_CLK + default y + help + Enable common clock framework support for Broadcom SoCs + using "Kona" style clock control units, including those + in the BCM281xx family. diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile new file mode 100644 index 000000000000..cf93359aa862 --- /dev/null +++ b/drivers/clk/bcm/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o +obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o +obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c new file mode 100644 index 000000000000..3c66de696aeb --- /dev/null +++ b/drivers/clk/bcm/clk-bcm281xx.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * Copyright 2013 Linaro 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "clk-kona.h" +#include "dt-bindings/clock/bcm281xx.h" + +/* bcm11351 CCU device tree "compatible" strings */ +#define BCM11351_DT_ROOT_CCU_COMPAT "brcm,bcm11351-root-ccu" +#define BCM11351_DT_AON_CCU_COMPAT "brcm,bcm11351-aon-ccu" +#define BCM11351_DT_HUB_CCU_COMPAT "brcm,bcm11351-hub-ccu" +#define BCM11351_DT_MASTER_CCU_COMPAT "brcm,bcm11351-master-ccu" +#define BCM11351_DT_SLAVE_CCU_COMPAT "brcm,bcm11351-slave-ccu" + +/* Root CCU clocks */ + +static struct peri_clk_data frac_1m_data = { + .gate = HW_SW_GATE(0x214, 16, 0, 1), + .trig = TRIGGER(0x0e04, 0), + .div = FRAC_DIVIDER(0x0e00, 0, 22, 16), + .clocks = CLOCKS("ref_crystal"), +}; + +/* AON CCU clocks */ + +static struct peri_clk_data hub_timer_data = { + .gate = HW_SW_GATE(0x0414, 16, 0, 1), + .clocks = CLOCKS("bbl_32k", + "frac_1m", + "dft_19_5m"), + .sel = SELECTOR(0x0a10, 0, 2), + .trig = TRIGGER(0x0a40, 4), +}; + +static struct peri_clk_data pmu_bsc_data = { + .gate = HW_SW_GATE(0x0418, 16, 0, 1), + .clocks = CLOCKS("ref_crystal", + "pmu_bsc_var", + "bbl_32k"), + .sel = SELECTOR(0x0a04, 0, 2), + .div = DIVIDER(0x0a04, 3, 4), + .trig = TRIGGER(0x0a40, 0), +}; + +static struct peri_clk_data pmu_bsc_var_data = { + .clocks = CLOCKS("var_312m", + "ref_312m"), + .sel = SELECTOR(0x0a00, 0, 2), + .div = DIVIDER(0x0a00, 4, 5), + .trig = TRIGGER(0x0a40, 2), +}; + +/* Hub CCU clocks */ + +static struct peri_clk_data tmon_1m_data = { + .gate = HW_SW_GATE(0x04a4, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "frac_1m"), + .sel = SELECTOR(0x0e74, 0, 2), + .trig = TRIGGER(0x0e84, 1), +}; + +/* Master CCU clocks */ + +static struct peri_clk_data sdio1_data = { + .gate = HW_SW_GATE(0x0358, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a28, 0, 3), + .div = DIVIDER(0x0a28, 4, 14), + .trig = TRIGGER(0x0afc, 9), +}; + +static struct peri_clk_data sdio2_data = { + .gate = HW_SW_GATE(0x035c, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a2c, 0, 3), + .div = DIVIDER(0x0a2c, 4, 14), + .trig = TRIGGER(0x0afc, 10), +}; + +static struct peri_clk_data sdio3_data = { + .gate = HW_SW_GATE(0x0364, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a34, 0, 3), + .div = DIVIDER(0x0a34, 4, 14), + .trig = TRIGGER(0x0afc, 12), +}; + +static struct peri_clk_data sdio4_data = { + .gate = HW_SW_GATE(0x0360, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_52m", + "ref_52m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a30, 0, 3), + .div = DIVIDER(0x0a30, 4, 14), + .trig = TRIGGER(0x0afc, 11), +}; + +static struct peri_clk_data usb_ic_data = { + .gate = HW_SW_GATE(0x0354, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_96m", + "ref_96m"), + .div = FIXED_DIVIDER(2), + .sel = SELECTOR(0x0a24, 0, 2), + .trig = TRIGGER(0x0afc, 7), +}; + +/* also called usbh_48m */ +static struct peri_clk_data hsic2_48m_data = { + .gate = HW_SW_GATE(0x0370, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a38, 0, 2), + .div = FIXED_DIVIDER(2), + .trig = TRIGGER(0x0afc, 5), +}; + +/* also called usbh_12m */ +static struct peri_clk_data hsic2_12m_data = { + .gate = HW_SW_GATE(0x0370, 20, 4, 5), + .div = DIVIDER(0x0a38, 12, 2), + .clocks = CLOCKS("ref_crystal", + "var_96m", + "ref_96m"), + .pre_div = FIXED_DIVIDER(2), + .sel = SELECTOR(0x0a38, 0, 2), + .trig = TRIGGER(0x0afc, 5), +}; + +/* Slave CCU clocks */ + +static struct peri_clk_data uartb_data = { + .gate = HW_SW_GATE(0x0400, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_156m", + "ref_156m"), + .sel = SELECTOR(0x0a10, 0, 2), + .div = FRAC_DIVIDER(0x0a10, 4, 12, 8), + .trig = TRIGGER(0x0afc, 2), +}; + +static struct peri_clk_data uartb2_data = { + .gate = HW_SW_GATE(0x0404, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_156m", + "ref_156m"), + .sel = SELECTOR(0x0a14, 0, 2), + .div = FRAC_DIVIDER(0x0a14, 4, 12, 8), + .trig = TRIGGER(0x0afc, 3), +}; + +static struct peri_clk_data uartb3_data = { + .gate = HW_SW_GATE(0x0408, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_156m", + "ref_156m"), + .sel = SELECTOR(0x0a18, 0, 2), + .div = FRAC_DIVIDER(0x0a18, 4, 12, 8), + .trig = TRIGGER(0x0afc, 4), +}; + +static struct peri_clk_data uartb4_data = { + .gate = HW_SW_GATE(0x0408, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_156m", + "ref_156m"), + .sel = SELECTOR(0x0a1c, 0, 2), + .div = FRAC_DIVIDER(0x0a1c, 4, 12, 8), + .trig = TRIGGER(0x0afc, 5), +}; + +static struct peri_clk_data ssp0_data = { + .gate = HW_SW_GATE(0x0410, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a20, 0, 3), + .div = DIVIDER(0x0a20, 4, 14), + .trig = TRIGGER(0x0afc, 6), +}; + +static struct peri_clk_data ssp2_data = { + .gate = HW_SW_GATE(0x0418, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_96m", + "ref_96m"), + .sel = SELECTOR(0x0a28, 0, 3), + .div = DIVIDER(0x0a28, 4, 14), + .trig = TRIGGER(0x0afc, 8), +}; + +static struct peri_clk_data bsc1_data = { + .gate = HW_SW_GATE(0x0458, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_13m", + "ref_13m"), + .sel = SELECTOR(0x0a64, 0, 3), + .trig = TRIGGER(0x0afc, 23), +}; + +static struct peri_clk_data bsc2_data = { + .gate = HW_SW_GATE(0x045c, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_13m", + "ref_13m"), + .sel = SELECTOR(0x0a68, 0, 3), + .trig = TRIGGER(0x0afc, 24), +}; + +static struct peri_clk_data bsc3_data = { + .gate = HW_SW_GATE(0x0484, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m", + "ref_104m", + "var_13m", + "ref_13m"), + .sel = SELECTOR(0x0a84, 0, 3), + .trig = TRIGGER(0x0b00, 2), +}; + +static struct peri_clk_data pwm_data = { + .gate = HW_SW_GATE(0x0468, 18, 2, 3), + .clocks = CLOCKS("ref_crystal", + "var_104m"), + .sel = SELECTOR(0x0a70, 0, 2), + .div = DIVIDER(0x0a70, 4, 3), + .trig = TRIGGER(0x0afc, 15), +}; + +/* + * CCU setup routines + * + * These are called from kona_dt_ccu_setup() to initialize the array + * of clocks provided by the CCU. Once allocated, the entries in + * the array are initialized by calling kona_clk_setup() with the + * initialization data for each clock. They return 0 if successful + * or an error code otherwise. + */ +static int __init bcm281xx_root_ccu_clks_setup(struct ccu_data *ccu) +{ + struct clk **clks; + size_t count = BCM281XX_ROOT_CCU_CLOCK_COUNT; + + clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); + if (!clks) { + pr_err("%s: failed to allocate root clocks\n", __func__); + return -ENOMEM; + } + ccu->data.clks = clks; + ccu->data.clk_num = count; + + PERI_CLK_SETUP(clks, ccu, BCM281XX_ROOT_CCU_FRAC_1M, frac_1m); + + return 0; +} + +static int __init bcm281xx_aon_ccu_clks_setup(struct ccu_data *ccu) +{ + struct clk **clks; + size_t count = BCM281XX_AON_CCU_CLOCK_COUNT; + + clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); + if (!clks) { + pr_err("%s: failed to allocate aon clocks\n", __func__); + return -ENOMEM; + } + ccu->data.clks = clks; + ccu->data.clk_num = count; + + PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_HUB_TIMER, hub_timer); + PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC, pmu_bsc); + PERI_CLK_SETUP(clks, ccu, BCM281XX_AON_CCU_PMU_BSC_VAR, pmu_bsc_var); + + return 0; +} + +static int __init bcm281xx_hub_ccu_clks_setup(struct ccu_data *ccu) +{ + struct clk **clks; + size_t count = BCM281XX_HUB_CCU_CLOCK_COUNT; + + clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); + if (!clks) { + pr_err("%s: failed to allocate hub clocks\n", __func__); + return -ENOMEM; + } + ccu->data.clks = clks; + ccu->data.clk_num = count; + + PERI_CLK_SETUP(clks, ccu, BCM281XX_HUB_CCU_TMON_1M, tmon_1m); + + return 0; +} + +static int __init bcm281xx_master_ccu_clks_setup(struct ccu_data *ccu) +{ + struct clk **clks; + size_t count = BCM281XX_MASTER_CCU_CLOCK_COUNT; + + clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); + if (!clks) { + pr_err("%s: failed to allocate master clocks\n", __func__); + return -ENOMEM; + } + ccu->data.clks = clks; + ccu->data.clk_num = count; + + PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO1, sdio1); + PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO2, sdio2); + PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO3, sdio3); + PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_SDIO4, sdio4); + PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_USB_IC, usb_ic); + PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_48M, hsic2_48m); + PERI_CLK_SETUP(clks, ccu, BCM281XX_MASTER_CCU_HSIC2_12M, hsic2_12m); + + return 0; +} + +static int __init bcm281xx_slave_ccu_clks_setup(struct ccu_data *ccu) +{ + struct clk **clks; + size_t count = BCM281XX_SLAVE_CCU_CLOCK_COUNT; + + clks = kzalloc(count * sizeof(*clks), GFP_KERNEL); + if (!clks) { + pr_err("%s: failed to allocate slave clocks\n", __func__); + return -ENOMEM; + } + ccu->data.clks = clks; + ccu->data.clk_num = count; + + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB, uartb); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB2, uartb2); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB3, uartb3); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_UARTB4, uartb4); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP0, ssp0); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_SSP2, ssp2); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC1, bsc1); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC2, bsc2); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_BSC3, bsc3); + PERI_CLK_SETUP(clks, ccu, BCM281XX_SLAVE_CCU_PWM, pwm); + + return 0; +} + +/* Device tree match table callback functions */ + +static void __init kona_dt_root_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(node, bcm281xx_root_ccu_clks_setup); +} + +static void __init kona_dt_aon_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(node, bcm281xx_aon_ccu_clks_setup); +} + +static void __init kona_dt_hub_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(node, bcm281xx_hub_ccu_clks_setup); +} + +static void __init kona_dt_master_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(node, bcm281xx_master_ccu_clks_setup); +} + +static void __init kona_dt_slave_ccu_setup(struct device_node *node) +{ + kona_dt_ccu_setup(node, bcm281xx_slave_ccu_clks_setup); +} + +CLK_OF_DECLARE(bcm11351_root_ccu, BCM11351_DT_ROOT_CCU_COMPAT, + kona_dt_root_ccu_setup); +CLK_OF_DECLARE(bcm11351_aon_ccu, BCM11351_DT_AON_CCU_COMPAT, + kona_dt_aon_ccu_setup); +CLK_OF_DECLARE(bcm11351_hub_ccu, BCM11351_DT_HUB_CCU_COMPAT, + kona_dt_hub_ccu_setup); +CLK_OF_DECLARE(bcm11351_master_ccu, BCM11351_DT_MASTER_CCU_COMPAT, + kona_dt_master_ccu_setup); +CLK_OF_DECLARE(bcm11351_slave_ccu, BCM11351_DT_SLAVE_CCU_COMPAT, + kona_dt_slave_ccu_setup); diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c new file mode 100644 index 000000000000..c7607feb18dd --- /dev/null +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -0,0 +1,769 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * Copyright 2013 Linaro 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/io.h> +#include <linux/of_address.h> + +#include "clk-kona.h" + +/* These are used when a selector or trigger is found to be unneeded */ +#define selector_clear_exists(sel) ((sel)->width = 0) +#define trigger_clear_exists(trig) FLAG_CLEAR(trig, TRIG, EXISTS) + +LIST_HEAD(ccu_list); /* The list of set up CCUs */ + +/* Validity checking */ + +static bool clk_requires_trigger(struct kona_clk *bcm_clk) +{ + struct peri_clk_data *peri = bcm_clk->peri; + struct bcm_clk_sel *sel; + struct bcm_clk_div *div; + + if (bcm_clk->type != bcm_clk_peri) + return false; + + sel = &peri->sel; + if (sel->parent_count && selector_exists(sel)) + return true; + + div = &peri->div; + if (!divider_exists(div)) + return false; + + /* Fixed dividers don't need triggers */ + if (!divider_is_fixed(div)) + return true; + + div = &peri->pre_div; + + return divider_exists(div) && !divider_is_fixed(div); +} + +static bool peri_clk_data_offsets_valid(struct kona_clk *bcm_clk) +{ + struct peri_clk_data *peri; + struct bcm_clk_gate *gate; + struct bcm_clk_div *div; + struct bcm_clk_sel *sel; + struct bcm_clk_trig *trig; + const char *name; + u32 range; + u32 limit; + + BUG_ON(bcm_clk->type != bcm_clk_peri); + peri = bcm_clk->peri; + name = bcm_clk->name; + range = bcm_clk->ccu->range; + + limit = range - sizeof(u32); + limit = round_down(limit, sizeof(u32)); + + gate = &peri->gate; + if (gate_exists(gate)) { + if (gate->offset > limit) { + pr_err("%s: bad gate offset for %s (%u > %u)\n", + __func__, name, gate->offset, limit); + return false; + } + } + + div = &peri->div; + if (divider_exists(div)) { + if (div->offset > limit) { + pr_err("%s: bad divider offset for %s (%u > %u)\n", + __func__, name, div->offset, limit); + return false; + } + } + + div = &peri->pre_div; + if (divider_exists(div)) { + if (div->offset > limit) { + pr_err("%s: bad pre-divider offset for %s " + "(%u > %u)\n", + __func__, name, div->offset, limit); + return false; + } + } + + sel = &peri->sel; + if (selector_exists(sel)) { + if (sel->offset > limit) { + pr_err("%s: bad selector offset for %s (%u > %u)\n", + __func__, name, sel->offset, limit); + return false; + } + } + + trig = &peri->trig; + if (trigger_exists(trig)) { + if (trig->offset > limit) { + pr_err("%s: bad trigger offset for %s (%u > %u)\n", + __func__, name, trig->offset, limit); + return false; + } + } + + trig = &peri->pre_trig; + if (trigger_exists(trig)) { + if (trig->offset > limit) { + pr_err("%s: bad pre-trigger offset for %s (%u > %u)\n", + __func__, name, trig->offset, limit); + return false; + } + } + + return true; +} + +/* A bit position must be less than the number of bits in a 32-bit register. */ +static bool bit_posn_valid(u32 bit_posn, const char *field_name, + const char *clock_name) +{ + u32 limit = BITS_PER_BYTE * sizeof(u32) - 1; + + if (bit_posn > limit) { + pr_err("%s: bad %s bit for %s (%u > %u)\n", __func__, + field_name, clock_name, bit_posn, limit); + return false; + } + return true; +} + +/* + * A bitfield must be at least 1 bit wide. Both the low-order and + * high-order bits must lie within a 32-bit register. We require + * fields to be less than 32 bits wide, mainly because we use + * shifting to produce field masks, and shifting a full word width + * is not well-defined by the C standard. + */ +static bool bitfield_valid(u32 shift, u32 width, const char *field_name, + const char *clock_name) +{ + u32 limit = BITS_PER_BYTE * sizeof(u32); + + if (!width) { + pr_err("%s: bad %s field width 0 for %s\n", __func__, + field_name, clock_name); + return false; + } + if (shift + width > limit) { + pr_err("%s: bad %s for %s (%u + %u > %u)\n", __func__, + field_name, clock_name, shift, width, limit); + return false; + } + return true; +} + +/* + * All gates, if defined, have a status bit, and for hardware-only + * gates, that's it. Gates that can be software controlled also + * have an enable bit. And a gate that can be hardware or software + * controlled will have a hardware/software select bit. + */ +static bool gate_valid(struct bcm_clk_gate *gate, const char *field_name, + const char *clock_name) +{ + if (!bit_posn_valid(gate->status_bit, "gate status", clock_name)) + return false; + + if (gate_is_sw_controllable(gate)) { + if (!bit_posn_valid(gate->en_bit, "gate enable", clock_name)) + return false; + + if (gate_is_hw_controllable(gate)) { + if (!bit_posn_valid(gate->hw_sw_sel_bit, + "gate hw/sw select", + clock_name)) + return false; + } + } else { + BUG_ON(!gate_is_hw_controllable(gate)); + } + + return true; +} + +/* + * A selector bitfield must be valid. Its parent_sel array must + * also be reasonable for the field. + */ +static bool sel_valid(struct bcm_clk_sel *sel, const char *field_name, + const char *clock_name) +{ + if (!bitfield_valid(sel->shift, sel->width, field_name, clock_name)) + return false; + + if (sel->parent_count) { + u32 max_sel; + u32 limit; + + /* + * Make sure the selector field can hold all the + * selector values we expect to be able to use. A + * clock only needs to have a selector defined if it + * has more than one parent. And in that case the + * highest selector value will be in the last entry + * in the array. + */ + max_sel = sel->parent_sel[sel->parent_count - 1]; + limit = (1 << sel->width) - 1; + if (max_sel > limit) { + pr_err("%s: bad selector for %s " + "(%u needs > %u bits)\n", + __func__, clock_name, max_sel, + sel->width); + return false; + } + } else { + pr_warn("%s: ignoring selector for %s (no parents)\n", + __func__, clock_name); + selector_clear_exists(sel); + kfree(sel->parent_sel); + sel->parent_sel = NULL; + } + + return true; +} + +/* + * A fixed divider just needs to be non-zero. A variable divider + * has to have a valid divider bitfield, and if it has a fraction, + * the width of the fraction must not be no more than the width of + * the divider as a whole. + */ +static bool div_valid(struct bcm_clk_div *div, const char *field_name, + const char *clock_name) +{ + if (divider_is_fixed(div)) { + /* Any fixed divider value but 0 is OK */ + if (div->fixed == 0) { + pr_err("%s: bad %s fixed value 0 for %s\n", __func__, + field_name, clock_name); + return false; + } + return true; + } + if (!bitfield_valid(div->shift, div->width, field_name, clock_name)) + return false; + + if (divider_has_fraction(div)) + if (div->frac_width > div->width) { + pr_warn("%s: bad %s fraction width for %s (%u > %u)\n", + __func__, field_name, clock_name, + div->frac_width, div->width); + return false; + } + + return true; +} + +/* + * If a clock has two dividers, the combined number of fractional + * bits must be representable in a 32-bit unsigned value. This + * is because we scale up a dividend using both dividers before + * dividing to improve accuracy, and we need to avoid overflow. + */ +static bool kona_dividers_valid(struct kona_clk *bcm_clk) +{ + struct peri_clk_data *peri = bcm_clk->peri; + struct bcm_clk_div *div; + struct bcm_clk_div *pre_div; + u32 limit; + + BUG_ON(bcm_clk->type != bcm_clk_peri); + + if (!divider_exists(&peri->div) || !divider_exists(&peri->pre_div)) + return true; + + div = &peri->div; + pre_div = &peri->pre_div; + if (divider_is_fixed(div) || divider_is_fixed(pre_div)) + return true; + + limit = BITS_PER_BYTE * sizeof(u32); + + return div->frac_width + pre_div->frac_width <= limit; +} + + +/* A trigger just needs to represent a valid bit position */ +static bool trig_valid(struct bcm_clk_trig *trig, const char *field_name, + const char *clock_name) +{ + return bit_posn_valid(trig->bit, field_name, clock_name); +} + +/* Determine whether the set of peripheral clock registers are valid. */ +static bool +peri_clk_data_valid(struct kona_clk *bcm_clk) +{ + struct peri_clk_data *peri; + struct bcm_clk_gate *gate; + struct bcm_clk_sel *sel; + struct bcm_clk_div *div; + struct bcm_clk_div *pre_div; + struct bcm_clk_trig *trig; + const char *name; + + BUG_ON(bcm_clk->type != bcm_clk_peri); + + /* + * First validate register offsets. This is the only place + * where we need something from the ccu, so we do these + * together. + */ + if (!peri_clk_data_offsets_valid(bcm_clk)) + return false; + + peri = bcm_clk->peri; + name = bcm_clk->name; + gate = &peri->gate; + if (gate_exists(gate) && !gate_valid(gate, "gate", name)) + return false; + + sel = &peri->sel; + if (selector_exists(sel)) { + if (!sel_valid(sel, "selector", name)) + return false; + + } else if (sel->parent_count > 1) { + pr_err("%s: multiple parents but no selector for %s\n", + __func__, name); + + return false; + } + + div = &peri->div; + pre_div = &peri->pre_div; + if (divider_exists(div)) { + if (!div_valid(div, "divider", name)) + return false; + + if (divider_exists(pre_div)) + if (!div_valid(pre_div, "pre-divider", name)) + return false; + } else if (divider_exists(pre_div)) { + pr_err("%s: pre-divider but no divider for %s\n", __func__, + name); + return false; + } + + trig = &peri->trig; + if (trigger_exists(trig)) { + if (!trig_valid(trig, "trigger", name)) + return false; + + if (trigger_exists(&peri->pre_trig)) { + if (!trig_valid(trig, "pre-trigger", name)) { + return false; + } + } + if (!clk_requires_trigger(bcm_clk)) { + pr_warn("%s: ignoring trigger for %s (not needed)\n", + __func__, name); + trigger_clear_exists(trig); + } + } else if (trigger_exists(&peri->pre_trig)) { + pr_err("%s: pre-trigger but no trigger for %s\n", __func__, + name); + return false; + } else if (clk_requires_trigger(bcm_clk)) { + pr_err("%s: required trigger missing for %s\n", __func__, + name); + return false; + } + + return kona_dividers_valid(bcm_clk); +} + +static bool kona_clk_valid(struct kona_clk *bcm_clk) +{ + switch (bcm_clk->type) { + case bcm_clk_peri: + if (!peri_clk_data_valid(bcm_clk)) + return false; + break; + default: + pr_err("%s: unrecognized clock type (%d)\n", __func__, + (int)bcm_clk->type); + return false; + } + return true; +} + +/* + * Scan an array of parent clock names to determine whether there + * are any entries containing BAD_CLK_NAME. Such entries are + * placeholders for non-supported clocks. Keep track of the + * position of each clock name in the original array. + * + * Allocates an array of pointers to to hold the names of all + * non-null entries in the original array, and returns a pointer to + * that array in *names. This will be used for registering the + * clock with the common clock code. On successful return, + * *count indicates how many entries are in that names array. + * + * If there is more than one entry in the resulting names array, + * another array is allocated to record the parent selector value + * for each (defined) parent clock. This is the value that + * represents this parent clock in the clock's source selector + * register. The position of the clock in the original parent array + * defines that selector value. The number of entries in this array + * is the same as the number of entries in the parent names array. + * + * The array of selector values is returned. If the clock has no + * parents, no selector is required and a null pointer is returned. + * + * Returns a null pointer if the clock names array supplied was + * null. (This is not an error.) + * + * Returns a pointer-coded error if an error occurs. + */ +static u32 *parent_process(const char *clocks[], + u32 *count, const char ***names) +{ + static const char **parent_names; + static u32 *parent_sel; + const char **clock; + u32 parent_count; + u32 bad_count = 0; + u32 orig_count; + u32 i; + u32 j; + + *count = 0; /* In case of early return */ + *names = NULL; + if (!clocks) + return NULL; + + /* + * Count the number of names in the null-terminated array, + * and find out how many of those are actually clock names. + */ + for (clock = clocks; *clock; clock++) + if (*clock == BAD_CLK_NAME) + bad_count++; + orig_count = (u32)(clock - clocks); + parent_count = orig_count - bad_count; + + /* If all clocks are unsupported, we treat it as no clock */ + if (!parent_count) + return NULL; + + /* Avoid exceeding our parent clock limit */ + if (parent_count > PARENT_COUNT_MAX) { + pr_err("%s: too many parents (%u > %u)\n", __func__, + parent_count, PARENT_COUNT_MAX); + return ERR_PTR(-EINVAL); + } + + /* + * There is one parent name for each defined parent clock. + * We also maintain an array containing the selector value + * for each defined clock. If there's only one clock, the + * selector is not required, but we allocate space for the + * array anyway to keep things simple. + */ + parent_names = kmalloc(parent_count * sizeof(parent_names), GFP_KERNEL); + if (!parent_names) { + pr_err("%s: error allocating %u parent names\n", __func__, + parent_count); + return ERR_PTR(-ENOMEM); + } + + /* There is at least one parent, so allocate a selector array */ + + parent_sel = kmalloc(parent_count * sizeof(*parent_sel), GFP_KERNEL); + if (!parent_sel) { + pr_err("%s: error allocating %u parent selectors\n", __func__, + parent_count); + kfree(parent_names); + + return ERR_PTR(-ENOMEM); + } + + /* Now fill in the parent names and selector arrays */ + for (i = 0, j = 0; i < orig_count; i++) { + if (clocks[i] != BAD_CLK_NAME) { + parent_names[j] = clocks[i]; + parent_sel[j] = i; + j++; + } + } + *names = parent_names; + *count = parent_count; + + return parent_sel; +} + +static int +clk_sel_setup(const char **clocks, struct bcm_clk_sel *sel, + struct clk_init_data *init_data) +{ + const char **parent_names = NULL; + u32 parent_count = 0; + u32 *parent_sel; + + /* + * If a peripheral clock has multiple parents, the value + * used by the hardware to select that parent is represented + * by the parent clock's position in the "clocks" list. Some + * values don't have defined or supported clocks; these will + * have BAD_CLK_NAME entries in the parents[] array. The + * list is terminated by a NULL entry. + * + * We need to supply (only) the names of defined parent + * clocks when registering a clock though, so we use an + * array of parent selector values to map between the + * indexes the common clock code uses and the selector + * values we need. + */ + parent_sel = parent_process(clocks, &parent_count, &parent_names); + if (IS_ERR(parent_sel)) { + int ret = PTR_ERR(parent_sel); + + pr_err("%s: error processing parent clocks for %s (%d)\n", + __func__, init_data->name, ret); + + return ret; + } + + init_data->parent_names = parent_names; + init_data->num_parents = parent_count; + + sel->parent_count = parent_count; + sel->parent_sel = parent_sel; + + return 0; +} + +static void clk_sel_teardown(struct bcm_clk_sel *sel, + struct clk_init_data *init_data) +{ + kfree(sel->parent_sel); + sel->parent_sel = NULL; + sel->parent_count = 0; + + init_data->num_parents = 0; + kfree(init_data->parent_names); + init_data->parent_names = NULL; +} + +static void peri_clk_teardown(struct peri_clk_data *data, + struct clk_init_data *init_data) +{ + clk_sel_teardown(&data->sel, init_data); + init_data->ops = NULL; +} + +/* + * Caller is responsible for freeing the parent_names[] and + * parent_sel[] arrays in the peripheral clock's "data" structure + * that can be assigned if the clock has one or more parent clocks + * associated with it. + */ +static int peri_clk_setup(struct ccu_data *ccu, struct peri_clk_data *data, + struct clk_init_data *init_data) +{ + init_data->ops = &kona_peri_clk_ops; + init_data->flags = CLK_IGNORE_UNUSED; + + return clk_sel_setup(data->clocks, &data->sel, init_data); +} + +static void bcm_clk_teardown(struct kona_clk *bcm_clk) +{ + switch (bcm_clk->type) { + case bcm_clk_peri: + peri_clk_teardown(bcm_clk->data, &bcm_clk->init_data); + break; + default: + break; + } + bcm_clk->data = NULL; + bcm_clk->type = bcm_clk_none; +} + +static void kona_clk_teardown(struct clk *clk) +{ + struct clk_hw *hw; + struct kona_clk *bcm_clk; + + if (!clk) + return; + + hw = __clk_get_hw(clk); + if (!hw) { + pr_err("%s: clk %p has null hw pointer\n", __func__, clk); + return; + } + clk_unregister(clk); + + bcm_clk = to_kona_clk(hw); + bcm_clk_teardown(bcm_clk); +} + +struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, + enum bcm_clk_type type, void *data) +{ + struct kona_clk *bcm_clk; + struct clk_init_data *init_data; + struct clk *clk = NULL; + + bcm_clk = kzalloc(sizeof(*bcm_clk), GFP_KERNEL); + if (!bcm_clk) { + pr_err("%s: failed to allocate bcm_clk for %s\n", __func__, + name); + return NULL; + } + bcm_clk->ccu = ccu; + bcm_clk->name = name; + + init_data = &bcm_clk->init_data; + init_data->name = name; + switch (type) { + case bcm_clk_peri: + if (peri_clk_setup(ccu, data, init_data)) + goto out_free; + break; + default: + data = NULL; + break; + } + bcm_clk->type = type; + bcm_clk->data = data; + + /* Make sure everything makes sense before we set it up */ + if (!kona_clk_valid(bcm_clk)) { + pr_err("%s: clock data invalid for %s\n", __func__, name); + goto out_teardown; + } + + bcm_clk->hw.init = init_data; + clk = clk_register(NULL, &bcm_clk->hw); + if (IS_ERR(clk)) { + pr_err("%s: error registering clock %s (%ld)\n", __func__, + name, PTR_ERR(clk)); + goto out_teardown; + } + BUG_ON(!clk); + + return clk; +out_teardown: + bcm_clk_teardown(bcm_clk); +out_free: + kfree(bcm_clk); + + return NULL; +} + +static void ccu_clks_teardown(struct ccu_data *ccu) +{ + u32 i; + + for (i = 0; i < ccu->data.clk_num; i++) + kona_clk_teardown(ccu->data.clks[i]); + kfree(ccu->data.clks); +} + +static void kona_ccu_teardown(struct ccu_data *ccu) +{ + if (!ccu) + return; + + if (!ccu->base) + goto done; + + of_clk_del_provider(ccu->node); /* safe if never added */ + ccu_clks_teardown(ccu); + list_del(&ccu->links); + of_node_put(ccu->node); + iounmap(ccu->base); +done: + kfree(ccu->name); + kfree(ccu); +} + +/* + * Set up a CCU. Call the provided ccu_clks_setup callback to + * initialize the array of clocks provided by the CCU. + */ +void __init kona_dt_ccu_setup(struct device_node *node, + int (*ccu_clks_setup)(struct ccu_data *)) +{ + struct ccu_data *ccu; + struct resource res = { 0 }; + resource_size_t range; + int ret; + + ccu = kzalloc(sizeof(*ccu), GFP_KERNEL); + if (ccu) + ccu->name = kstrdup(node->name, GFP_KERNEL); + if (!ccu || !ccu->name) { + pr_err("%s: unable to allocate CCU struct for %s\n", + __func__, node->name); + kfree(ccu); + + return; + } + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + pr_err("%s: no valid CCU registers found for %s\n", __func__, + node->name); + goto out_err; + } + + range = resource_size(&res); + if (range > (resource_size_t)U32_MAX) { + pr_err("%s: address range too large for %s\n", __func__, + node->name); + goto out_err; + } + + ccu->range = (u32)range; + ccu->base = ioremap(res.start, ccu->range); + if (!ccu->base) { + pr_err("%s: unable to map CCU registers for %s\n", __func__, + node->name); + goto out_err; + } + + spin_lock_init(&ccu->lock); + INIT_LIST_HEAD(&ccu->links); + ccu->node = of_node_get(node); + + list_add_tail(&ccu->links, &ccu_list); + + /* Set up clocks array (in ccu->data) */ + if (ccu_clks_setup(ccu)) + goto out_err; + + ret = of_clk_add_provider(node, of_clk_src_onecell_get, &ccu->data); + if (ret) { + pr_err("%s: error adding ccu %s as provider (%d)\n", __func__, + node->name, ret); + goto out_err; + } + + if (!kona_ccu_init(ccu)) + pr_err("Broadcom %s initialization had errors\n", node->name); + + return; +out_err: + kona_ccu_teardown(ccu); + pr_err("Broadcom %s setup aborted\n", node->name); +} diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c new file mode 100644 index 000000000000..e3d339e08309 --- /dev/null +++ b/drivers/clk/bcm/clk-kona.c @@ -0,0 +1,1033 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * Copyright 2013 Linaro 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "clk-kona.h" + +#include <linux/delay.h> + +#define CCU_ACCESS_PASSWORD 0xA5A500 +#define CLK_GATE_DELAY_LOOP 2000 + +/* Bitfield operations */ + +/* Produces a mask of set bits covering a range of a 32-bit value */ +static inline u32 bitfield_mask(u32 shift, u32 width) +{ + return ((1 << width) - 1) << shift; +} + +/* Extract the value of a bitfield found within a given register value */ +static inline u32 bitfield_extract(u32 reg_val, u32 shift, u32 width) +{ + return (reg_val & bitfield_mask(shift, width)) >> shift; +} + +/* Replace the value of a bitfield found within a given register value */ +static inline u32 bitfield_replace(u32 reg_val, u32 shift, u32 width, u32 val) +{ + u32 mask = bitfield_mask(shift, width); + + return (reg_val & ~mask) | (val << shift); +} + +/* Divider and scaling helpers */ + +/* + * Implement DIV_ROUND_CLOSEST() for 64-bit dividend and both values + * unsigned. Note that unlike do_div(), the remainder is discarded + * and the return value is the quotient (not the remainder). + */ +u64 do_div_round_closest(u64 dividend, unsigned long divisor) +{ + u64 result; + + result = dividend + ((u64)divisor >> 1); + (void)do_div(result, divisor); + + return result; +} + +/* Convert a divider into the scaled divisor value it represents. */ +static inline u64 scaled_div_value(struct bcm_clk_div *div, u32 reg_div) +{ + return (u64)reg_div + ((u64)1 << div->frac_width); +} + +/* + * Build a scaled divider value as close as possible to the + * given whole part (div_value) and fractional part (expressed + * in billionths). + */ +u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, u32 billionths) +{ + u64 combined; + + BUG_ON(!div_value); + BUG_ON(billionths >= BILLION); + + combined = (u64)div_value * BILLION + billionths; + combined <<= div->frac_width; + + return do_div_round_closest(combined, BILLION); +} + +/* The scaled minimum divisor representable by a divider */ +static inline u64 +scaled_div_min(struct bcm_clk_div *div) +{ + if (divider_is_fixed(div)) + return (u64)div->fixed; + + return scaled_div_value(div, 0); +} + +/* The scaled maximum divisor representable by a divider */ +u64 scaled_div_max(struct bcm_clk_div *div) +{ + u32 reg_div; + + if (divider_is_fixed(div)) + return (u64)div->fixed; + + reg_div = ((u32)1 << div->width) - 1; + + return scaled_div_value(div, reg_div); +} + +/* + * Convert a scaled divisor into its divider representation as + * stored in a divider register field. + */ +static inline u32 +divider(struct bcm_clk_div *div, u64 scaled_div) +{ + BUG_ON(scaled_div < scaled_div_min(div)); + BUG_ON(scaled_div > scaled_div_max(div)); + + return (u32)(scaled_div - ((u64)1 << div->frac_width)); +} + +/* Return a rate scaled for use when dividing by a scaled divisor. */ +static inline u64 +scale_rate(struct bcm_clk_div *div, u32 rate) +{ + if (divider_is_fixed(div)) + return (u64)rate; + + return (u64)rate << div->frac_width; +} + +/* CCU access */ + +/* Read a 32-bit register value from a CCU's address space. */ +static inline u32 __ccu_read(struct ccu_data *ccu, u32 reg_offset) +{ + return readl(ccu->base + reg_offset); +} + +/* Write a 32-bit register value into a CCU's address space. */ +static inline void +__ccu_write(struct ccu_data *ccu, u32 reg_offset, u32 reg_val) +{ + writel(reg_val, ccu->base + reg_offset); +} + +static inline unsigned long ccu_lock(struct ccu_data *ccu) +{ + unsigned long flags; + + spin_lock_irqsave(&ccu->lock, flags); + + return flags; +} +static inline void ccu_unlock(struct ccu_data *ccu, unsigned long flags) +{ + spin_unlock_irqrestore(&ccu->lock, flags); +} + +/* + * Enable/disable write access to CCU protected registers. The + * WR_ACCESS register for all CCUs is at offset 0. + */ +static inline void __ccu_write_enable(struct ccu_data *ccu) +{ + if (ccu->write_enabled) { + pr_err("%s: access already enabled for %s\n", __func__, + ccu->name); + return; + } + ccu->write_enabled = true; + __ccu_write(ccu, 0, CCU_ACCESS_PASSWORD | 1); +} + +static inline void __ccu_write_disable(struct ccu_data *ccu) +{ + if (!ccu->write_enabled) { + pr_err("%s: access wasn't enabled for %s\n", __func__, + ccu->name); + return; + } + + __ccu_write(ccu, 0, CCU_ACCESS_PASSWORD); + ccu->write_enabled = false; +} + +/* + * Poll a register in a CCU's address space, returning when the + * specified bit in that register's value is set (or clear). Delay + * a microsecond after each read of the register. Returns true if + * successful, or false if we gave up trying. + * + * Caller must ensure the CCU lock is held. + */ +static inline bool +__ccu_wait_bit(struct ccu_data *ccu, u32 reg_offset, u32 bit, bool want) +{ + unsigned int tries; + u32 bit_mask = 1 << bit; + + for (tries = 0; tries < CLK_GATE_DELAY_LOOP; tries++) { + u32 val; + bool bit_val; + + val = __ccu_read(ccu, reg_offset); + bit_val = (val & bit_mask) != 0; + if (bit_val == want) + return true; + udelay(1); + } + return false; +} + +/* Gate operations */ + +/* Determine whether a clock is gated. CCU lock must be held. */ +static bool +__is_clk_gate_enabled(struct ccu_data *ccu, struct bcm_clk_gate *gate) +{ + u32 bit_mask; + u32 reg_val; + + /* If there is no gate we can assume it's enabled. */ + if (!gate_exists(gate)) + return true; + + bit_mask = 1 << gate->status_bit; + reg_val = __ccu_read(ccu, gate->offset); + + return (reg_val & bit_mask) != 0; +} + +/* Determine whether a clock is gated. */ +static bool +is_clk_gate_enabled(struct ccu_data *ccu, struct bcm_clk_gate *gate) +{ + long flags; + bool ret; + + /* Avoid taking the lock if we can */ + if (!gate_exists(gate)) + return true; + + flags = ccu_lock(ccu); + ret = __is_clk_gate_enabled(ccu, gate); + ccu_unlock(ccu, flags); + + return ret; +} + +/* + * Commit our desired gate state to the hardware. + * Returns true if successful, false otherwise. + */ +static bool +__gate_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate) +{ + u32 reg_val; + u32 mask; + bool enabled = false; + + BUG_ON(!gate_exists(gate)); + if (!gate_is_sw_controllable(gate)) + return true; /* Nothing we can change */ + + reg_val = __ccu_read(ccu, gate->offset); + + /* For a hardware/software gate, set which is in control */ + if (gate_is_hw_controllable(gate)) { + mask = (u32)1 << gate->hw_sw_sel_bit; + if (gate_is_sw_managed(gate)) + reg_val |= mask; + else + reg_val &= ~mask; + } + + /* + * If software is in control, enable or disable the gate. + * If hardware is, clear the enabled bit for good measure. + * If a software controlled gate can't be disabled, we're + * required to write a 0 into the enable bit (but the gate + * will be enabled). + */ + mask = (u32)1 << gate->en_bit; + if (gate_is_sw_managed(gate) && (enabled = gate_is_enabled(gate)) && + !gate_is_no_disable(gate)) + reg_val |= mask; + else + reg_val &= ~mask; + + __ccu_write(ccu, gate->offset, reg_val); + + /* For a hardware controlled gate, we're done */ + if (!gate_is_sw_managed(gate)) + return true; + + /* Otherwise wait for the gate to be in desired state */ + return __ccu_wait_bit(ccu, gate->offset, gate->status_bit, enabled); +} + +/* + * Initialize a gate. Our desired state (hardware/software select, + * and if software, its enable state) is committed to hardware + * without the usual checks to see if it's already set up that way. + * Returns true if successful, false otherwise. + */ +static bool gate_init(struct ccu_data *ccu, struct bcm_clk_gate *gate) +{ + if (!gate_exists(gate)) + return true; + return __gate_commit(ccu, gate); +} + +/* + * Set a gate to enabled or disabled state. Does nothing if the + * gate is not currently under software control, or if it is already + * in the requested state. Returns true if successful, false + * otherwise. CCU lock must be held. + */ +static bool +__clk_gate(struct ccu_data *ccu, struct bcm_clk_gate *gate, bool enable) +{ + bool ret; + + if (!gate_exists(gate) || !gate_is_sw_managed(gate)) + return true; /* Nothing to do */ + + if (!enable && gate_is_no_disable(gate)) { + pr_warn("%s: invalid gate disable request (ignoring)\n", + __func__); + return true; + } + + if (enable == gate_is_enabled(gate)) + return true; /* No change */ + + gate_flip_enabled(gate); + ret = __gate_commit(ccu, gate); + if (!ret) + gate_flip_enabled(gate); /* Revert the change */ + + return ret; +} + +/* Enable or disable a gate. Returns 0 if successful, -EIO otherwise */ +static int clk_gate(struct ccu_data *ccu, const char *name, + struct bcm_clk_gate *gate, bool enable) +{ + unsigned long flags; + bool success; + + /* + * Avoid taking the lock if we can. We quietly ignore + * requests to change state that don't make sense. + */ + if (!gate_exists(gate) || !gate_is_sw_managed(gate)) + return 0; + if (!enable && gate_is_no_disable(gate)) + return 0; + + flags = ccu_lock(ccu); + __ccu_write_enable(ccu); + + success = __clk_gate(ccu, gate, enable); + + __ccu_write_disable(ccu); + ccu_unlock(ccu, flags); + + if (success) + return 0; + + pr_err("%s: failed to %s gate for %s\n", __func__, + enable ? "enable" : "disable", name); + + return -EIO; +} + +/* Trigger operations */ + +/* + * Caller must ensure CCU lock is held and access is enabled. + * Returns true if successful, false otherwise. + */ +static bool __clk_trigger(struct ccu_data *ccu, struct bcm_clk_trig *trig) +{ + /* Trigger the clock and wait for it to finish */ + __ccu_write(ccu, trig->offset, 1 << trig->bit); + + return __ccu_wait_bit(ccu, trig->offset, trig->bit, false); +} + +/* Divider operations */ + +/* Read a divider value and return the scaled divisor it represents. */ +static u64 divider_read_scaled(struct ccu_data *ccu, struct bcm_clk_div *div) +{ + unsigned long flags; + u32 reg_val; + u32 reg_div; + + if (divider_is_fixed(div)) + return (u64)div->fixed; + + flags = ccu_lock(ccu); + reg_val = __ccu_read(ccu, div->offset); + ccu_unlock(ccu, flags); + + /* Extract the full divider field from the register value */ + reg_div = bitfield_extract(reg_val, div->shift, div->width); + + /* Return the scaled divisor value it represents */ + return scaled_div_value(div, reg_div); +} + +/* + * Convert a divider's scaled divisor value into its recorded form + * and commit it into the hardware divider register. + * + * Returns 0 on success. Returns -EINVAL for invalid arguments. + * Returns -ENXIO if gating failed, and -EIO if a trigger failed. + */ +static int __div_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, + struct bcm_clk_div *div, struct bcm_clk_trig *trig) +{ + bool enabled; + u32 reg_div; + u32 reg_val; + int ret = 0; + + BUG_ON(divider_is_fixed(div)); + + /* + * If we're just initializing the divider, and no initial + * state was defined in the device tree, we just find out + * what its current value is rather than updating it. + */ + if (div->scaled_div == BAD_SCALED_DIV_VALUE) { + reg_val = __ccu_read(ccu, div->offset); + reg_div = bitfield_extract(reg_val, div->shift, div->width); + div->scaled_div = scaled_div_value(div, reg_div); + + return 0; + } + + /* Convert the scaled divisor to the value we need to record */ + reg_div = divider(div, div->scaled_div); + + /* Clock needs to be enabled before changing the rate */ + enabled = __is_clk_gate_enabled(ccu, gate); + if (!enabled && !__clk_gate(ccu, gate, true)) { + ret = -ENXIO; + goto out; + } + + /* Replace the divider value and record the result */ + reg_val = __ccu_read(ccu, div->offset); + reg_val = bitfield_replace(reg_val, div->shift, div->width, reg_div); + __ccu_write(ccu, div->offset, reg_val); + + /* If the trigger fails we still want to disable the gate */ + if (!__clk_trigger(ccu, trig)) + ret = -EIO; + + /* Disable the clock again if it was disabled to begin with */ + if (!enabled && !__clk_gate(ccu, gate, false)) + ret = ret ? ret : -ENXIO; /* return first error */ +out: + return ret; +} + +/* + * Initialize a divider by committing our desired state to hardware + * without the usual checks to see if it's already set up that way. + * Returns true if successful, false otherwise. + */ +static bool div_init(struct ccu_data *ccu, struct bcm_clk_gate *gate, + struct bcm_clk_div *div, struct bcm_clk_trig *trig) +{ + if (!divider_exists(div) || divider_is_fixed(div)) + return true; + return !__div_commit(ccu, gate, div, trig); +} + +static int divider_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, + struct bcm_clk_div *div, struct bcm_clk_trig *trig, + u64 scaled_div) +{ + unsigned long flags; + u64 previous; + int ret; + + BUG_ON(divider_is_fixed(div)); + + previous = div->scaled_div; + if (previous == scaled_div) + return 0; /* No change */ + + div->scaled_div = scaled_div; + + flags = ccu_lock(ccu); + __ccu_write_enable(ccu); + + ret = __div_commit(ccu, gate, div, trig); + + __ccu_write_disable(ccu); + ccu_unlock(ccu, flags); + + if (ret) + div->scaled_div = previous; /* Revert the change */ + + return ret; + +} + +/* Common clock rate helpers */ + +/* + * Implement the common clock framework recalc_rate method, taking + * into account a divider and an optional pre-divider. The + * pre-divider register pointer may be NULL. + */ +static unsigned long clk_recalc_rate(struct ccu_data *ccu, + struct bcm_clk_div *div, struct bcm_clk_div *pre_div, + unsigned long parent_rate) +{ + u64 scaled_parent_rate; + u64 scaled_div; + u64 result; + + if (!divider_exists(div)) + return parent_rate; + + if (parent_rate > (unsigned long)LONG_MAX) + return 0; /* actually this would be a caller bug */ + + /* + * If there is a pre-divider, divide the scaled parent rate + * by the pre-divider value first. In this case--to improve + * accuracy--scale the parent rate by *both* the pre-divider + * value and the divider before actually computing the + * result of the pre-divider. + * + * If there's only one divider, just scale the parent rate. + */ + if (pre_div && divider_exists(pre_div)) { + u64 scaled_rate; + + scaled_rate = scale_rate(pre_div, parent_rate); + scaled_rate = scale_rate(div, scaled_rate); + scaled_div = divider_read_scaled(ccu, pre_div); + scaled_parent_rate = do_div_round_closest(scaled_rate, + scaled_div); + } else { + scaled_parent_rate = scale_rate(div, parent_rate); + } + + /* + * Get the scaled divisor value, and divide the scaled + * parent rate by that to determine this clock's resulting + * rate. + */ + scaled_div = divider_read_scaled(ccu, div); + result = do_div_round_closest(scaled_parent_rate, scaled_div); + + return (unsigned long)result; +} + +/* + * Compute the output rate produced when a given parent rate is fed + * into two dividers. The pre-divider can be NULL, and even if it's + * non-null it may be nonexistent. It's also OK for the divider to + * be nonexistent, and in that case the pre-divider is also ignored. + * + * If scaled_div is non-null, it is used to return the scaled divisor + * value used by the (downstream) divider to produce that rate. + */ +static long round_rate(struct ccu_data *ccu, struct bcm_clk_div *div, + struct bcm_clk_div *pre_div, + unsigned long rate, unsigned long parent_rate, + u64 *scaled_div) +{ + u64 scaled_parent_rate; + u64 min_scaled_div; + u64 max_scaled_div; + u64 best_scaled_div; + u64 result; + + BUG_ON(!divider_exists(div)); + BUG_ON(!rate); + BUG_ON(parent_rate > (u64)LONG_MAX); + + /* + * If there is a pre-divider, divide the scaled parent rate + * by the pre-divider value first. In this case--to improve + * accuracy--scale the parent rate by *both* the pre-divider + * value and the divider before actually computing the + * result of the pre-divider. + * + * If there's only one divider, just scale the parent rate. + * + * For simplicity we treat the pre-divider as fixed (for now). + */ + if (divider_exists(pre_div)) { + u64 scaled_rate; + u64 scaled_pre_div; + + scaled_rate = scale_rate(pre_div, parent_rate); + scaled_rate = scale_rate(div, scaled_rate); + scaled_pre_div = divider_read_scaled(ccu, pre_div); + scaled_parent_rate = do_div_round_closest(scaled_rate, + scaled_pre_div); + } else { + scaled_parent_rate = scale_rate(div, parent_rate); + } + + /* + * Compute the best possible divider and ensure it is in + * range. A fixed divider can't be changed, so just report + * the best we can do. + */ + if (!divider_is_fixed(div)) { + best_scaled_div = do_div_round_closest(scaled_parent_rate, + rate); + min_scaled_div = scaled_div_min(div); + max_scaled_div = scaled_div_max(div); + if (best_scaled_div > max_scaled_div) + best_scaled_div = max_scaled_div; + else if (best_scaled_div < min_scaled_div) + best_scaled_div = min_scaled_div; + } else { + best_scaled_div = divider_read_scaled(ccu, div); + } + + /* OK, figure out the resulting rate */ + result = do_div_round_closest(scaled_parent_rate, best_scaled_div); + + if (scaled_div) + *scaled_div = best_scaled_div; + + return (long)result; +} + +/* Common clock parent helpers */ + +/* + * For a given parent selector (register field) value, find the + * index into a selector's parent_sel array that contains it. + * Returns the index, or BAD_CLK_INDEX if it's not found. + */ +static u8 parent_index(struct bcm_clk_sel *sel, u8 parent_sel) +{ + u8 i; + + BUG_ON(sel->parent_count > (u32)U8_MAX); + for (i = 0; i < sel->parent_count; i++) + if (sel->parent_sel[i] == parent_sel) + return i; + return BAD_CLK_INDEX; +} + +/* + * Fetch the current value of the selector, and translate that into + * its corresponding index in the parent array we registered with + * the clock framework. + * + * Returns parent array index that corresponds with the value found, + * or BAD_CLK_INDEX if the found value is out of range. + */ +static u8 selector_read_index(struct ccu_data *ccu, struct bcm_clk_sel *sel) +{ + unsigned long flags; + u32 reg_val; + u32 parent_sel; + u8 index; + + /* If there's no selector, there's only one parent */ + if (!selector_exists(sel)) + return 0; + + /* Get the value in the selector register */ + flags = ccu_lock(ccu); + reg_val = __ccu_read(ccu, sel->offset); + ccu_unlock(ccu, flags); + + parent_sel = bitfield_extract(reg_val, sel->shift, sel->width); + + /* Look up that selector's parent array index and return it */ + index = parent_index(sel, parent_sel); + if (index == BAD_CLK_INDEX) + pr_err("%s: out-of-range parent selector %u (%s 0x%04x)\n", + __func__, parent_sel, ccu->name, sel->offset); + + return index; +} + +/* + * Commit our desired selector value to the hardware. + * + * Returns 0 on success. Returns -EINVAL for invalid arguments. + * Returns -ENXIO if gating failed, and -EIO if a trigger failed. + */ +static int +__sel_commit(struct ccu_data *ccu, struct bcm_clk_gate *gate, + struct bcm_clk_sel *sel, struct bcm_clk_trig *trig) +{ + u32 parent_sel; + u32 reg_val; + bool enabled; + int ret = 0; + + BUG_ON(!selector_exists(sel)); + + /* + * If we're just initializing the selector, and no initial + * state was defined in the device tree, we just find out + * what its current value is rather than updating it. + */ + if (sel->clk_index == BAD_CLK_INDEX) { + u8 index; + + reg_val = __ccu_read(ccu, sel->offset); + parent_sel = bitfield_extract(reg_val, sel->shift, sel->width); + index = parent_index(sel, parent_sel); + if (index == BAD_CLK_INDEX) + return -EINVAL; + sel->clk_index = index; + + return 0; + } + + BUG_ON((u32)sel->clk_index >= sel->parent_count); + parent_sel = sel->parent_sel[sel->clk_index]; + + /* Clock needs to be enabled before changing the parent */ + enabled = __is_clk_gate_enabled(ccu, gate); + if (!enabled && !__clk_gate(ccu, gate, true)) + return -ENXIO; + + /* Replace the selector value and record the result */ + reg_val = __ccu_read(ccu, sel->offset); + reg_val = bitfield_replace(reg_val, sel->shift, sel->width, parent_sel); + __ccu_write(ccu, sel->offset, reg_val); + + /* If the trigger fails we still want to disable the gate */ + if (!__clk_trigger(ccu, trig)) + ret = -EIO; + + /* Disable the clock again if it was disabled to begin with */ + if (!enabled && !__clk_gate(ccu, gate, false)) + ret = ret ? ret : -ENXIO; /* return first error */ + + return ret; +} + +/* + * Initialize a selector by committing our desired state to hardware + * without the usual checks to see if it's already set up that way. + * Returns true if successful, false otherwise. + */ +static bool sel_init(struct ccu_data *ccu, struct bcm_clk_gate *gate, + struct bcm_clk_sel *sel, struct bcm_clk_trig *trig) +{ + if (!selector_exists(sel)) + return true; + return !__sel_commit(ccu, gate, sel, trig); +} + +/* + * Write a new value into a selector register to switch to a + * different parent clock. Returns 0 on success, or an error code + * (from __sel_commit()) otherwise. + */ +static int selector_write(struct ccu_data *ccu, struct bcm_clk_gate *gate, + struct bcm_clk_sel *sel, struct bcm_clk_trig *trig, + u8 index) +{ + unsigned long flags; + u8 previous; + int ret; + + previous = sel->clk_index; + if (previous == index) + return 0; /* No change */ + + sel->clk_index = index; + + flags = ccu_lock(ccu); + __ccu_write_enable(ccu); + + ret = __sel_commit(ccu, gate, sel, trig); + + __ccu_write_disable(ccu); + ccu_unlock(ccu, flags); + + if (ret) + sel->clk_index = previous; /* Revert the change */ + + return ret; +} + +/* Clock operations */ + +static int kona_peri_clk_enable(struct clk_hw *hw) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct bcm_clk_gate *gate = &bcm_clk->peri->gate; + + return clk_gate(bcm_clk->ccu, bcm_clk->name, gate, true); +} + +static void kona_peri_clk_disable(struct clk_hw *hw) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct bcm_clk_gate *gate = &bcm_clk->peri->gate; + + (void)clk_gate(bcm_clk->ccu, bcm_clk->name, gate, false); +} + +static int kona_peri_clk_is_enabled(struct clk_hw *hw) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct bcm_clk_gate *gate = &bcm_clk->peri->gate; + + return is_clk_gate_enabled(bcm_clk->ccu, gate) ? 1 : 0; +} + +static unsigned long kona_peri_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct peri_clk_data *data = bcm_clk->peri; + + return clk_recalc_rate(bcm_clk->ccu, &data->div, &data->pre_div, + parent_rate); +} + +static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct bcm_clk_div *div = &bcm_clk->peri->div; + + if (!divider_exists(div)) + return __clk_get_rate(hw->clk); + + /* Quietly avoid a zero rate */ + return round_rate(bcm_clk->ccu, div, &bcm_clk->peri->pre_div, + rate ? rate : 1, *parent_rate, NULL); +} + +static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct peri_clk_data *data = bcm_clk->peri; + struct bcm_clk_sel *sel = &data->sel; + struct bcm_clk_trig *trig; + int ret; + + BUG_ON(index >= sel->parent_count); + + /* If there's only one parent we don't require a selector */ + if (!selector_exists(sel)) + return 0; + + /* + * The regular trigger is used by default, but if there's a + * pre-trigger we want to use that instead. + */ + trig = trigger_exists(&data->pre_trig) ? &data->pre_trig + : &data->trig; + + ret = selector_write(bcm_clk->ccu, &data->gate, sel, trig, index); + if (ret == -ENXIO) { + pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); + ret = -EIO; /* Don't proliferate weird errors */ + } else if (ret == -EIO) { + pr_err("%s: %strigger failed for %s\n", __func__, + trig == &data->pre_trig ? "pre-" : "", + bcm_clk->name); + } + + return ret; +} + +static u8 kona_peri_clk_get_parent(struct clk_hw *hw) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct peri_clk_data *data = bcm_clk->peri; + u8 index; + + index = selector_read_index(bcm_clk->ccu, &data->sel); + + /* Not all callers would handle an out-of-range value gracefully */ + return index == BAD_CLK_INDEX ? 0 : index; +} + +static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct kona_clk *bcm_clk = to_kona_clk(hw); + struct peri_clk_data *data = bcm_clk->peri; + struct bcm_clk_div *div = &data->div; + u64 scaled_div = 0; + int ret; + + if (parent_rate > (unsigned long)LONG_MAX) + return -EINVAL; + + if (rate == __clk_get_rate(hw->clk)) + return 0; + + if (!divider_exists(div)) + return rate == parent_rate ? 0 : -EINVAL; + + /* + * A fixed divider can't be changed. (Nor can a fixed + * pre-divider be, but for now we never actually try to + * change that.) Tolerate a request for a no-op change. + */ + if (divider_is_fixed(&data->div)) + return rate == parent_rate ? 0 : -EINVAL; + + /* + * Get the scaled divisor value needed to achieve a clock + * rate as close as possible to what was requested, given + * the parent clock rate supplied. + */ + (void)round_rate(bcm_clk->ccu, div, &data->pre_div, + rate ? rate : 1, parent_rate, &scaled_div); + + /* + * We aren't updating any pre-divider at this point, so + * we'll use the regular trigger. + */ + ret = divider_write(bcm_clk->ccu, &data->gate, &data->div, + &data->trig, scaled_div); + if (ret == -ENXIO) { + pr_err("%s: gating failure for %s\n", __func__, bcm_clk->name); + ret = -EIO; /* Don't proliferate weird errors */ + } else if (ret == -EIO) { + pr_err("%s: trigger failed for %s\n", __func__, bcm_clk->name); + } + + return ret; +} + +struct clk_ops kona_peri_clk_ops = { + .enable = kona_peri_clk_enable, + .disable = kona_peri_clk_disable, + .is_enabled = kona_peri_clk_is_enabled, + .recalc_rate = kona_peri_clk_recalc_rate, + .round_rate = kona_peri_clk_round_rate, + .set_parent = kona_peri_clk_set_parent, + .get_parent = kona_peri_clk_get_parent, + .set_rate = kona_peri_clk_set_rate, +}; + +/* Put a peripheral clock into its initial state */ +static bool __peri_clk_init(struct kona_clk *bcm_clk) +{ + struct ccu_data *ccu = bcm_clk->ccu; + struct peri_clk_data *peri = bcm_clk->peri; + const char *name = bcm_clk->name; + struct bcm_clk_trig *trig; + + BUG_ON(bcm_clk->type != bcm_clk_peri); + + if (!gate_init(ccu, &peri->gate)) { + pr_err("%s: error initializing gate for %s\n", __func__, name); + return false; + } + if (!div_init(ccu, &peri->gate, &peri->div, &peri->trig)) { + pr_err("%s: error initializing divider for %s\n", __func__, + name); + return false; + } + + /* + * For the pre-divider and selector, the pre-trigger is used + * if it's present, otherwise we just use the regular trigger. + */ + trig = trigger_exists(&peri->pre_trig) ? &peri->pre_trig + : &peri->trig; + + if (!div_init(ccu, &peri->gate, &peri->pre_div, trig)) { + pr_err("%s: error initializing pre-divider for %s\n", __func__, + name); + return false; + } + + if (!sel_init(ccu, &peri->gate, &peri->sel, trig)) { + pr_err("%s: error initializing selector for %s\n", __func__, + name); + return false; + } + + return true; +} + +static bool __kona_clk_init(struct kona_clk *bcm_clk) +{ + switch (bcm_clk->type) { + case bcm_clk_peri: + return __peri_clk_init(bcm_clk); + default: + BUG(); + } + return -EINVAL; +} + +/* Set a CCU and all its clocks into their desired initial state */ +bool __init kona_ccu_init(struct ccu_data *ccu) +{ + unsigned long flags; + unsigned int which; + struct clk **clks = ccu->data.clks; + bool success = true; + + flags = ccu_lock(ccu); + __ccu_write_enable(ccu); + + for (which = 0; which < ccu->data.clk_num; which++) { + struct kona_clk *bcm_clk; + + if (!clks[which]) + continue; + bcm_clk = to_kona_clk(__clk_get_hw(clks[which])); + success &= __kona_clk_init(bcm_clk); + } + + __ccu_write_disable(ccu); + ccu_unlock(ccu, flags); + return success; +} diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h new file mode 100644 index 000000000000..5e139adc3dc5 --- /dev/null +++ b/drivers/clk/bcm/clk-kona.h @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * Copyright 2013 Linaro 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CLK_KONA_H +#define _CLK_KONA_H + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/of.h> +#include <linux/clk-provider.h> + +#define BILLION 1000000000 + +/* The common clock framework uses u8 to represent a parent index */ +#define PARENT_COUNT_MAX ((u32)U8_MAX) + +#define BAD_CLK_INDEX U8_MAX /* Can't ever be valid */ +#define BAD_CLK_NAME ((const char *)-1) + +#define BAD_SCALED_DIV_VALUE U64_MAX + +/* + * Utility macros for object flag management. If possible, flags + * should be defined such that 0 is the desired default value. + */ +#define FLAG(type, flag) BCM_CLK_ ## type ## _FLAGS_ ## flag +#define FLAG_SET(obj, type, flag) ((obj)->flags |= FLAG(type, flag)) +#define FLAG_CLEAR(obj, type, flag) ((obj)->flags &= ~(FLAG(type, flag))) +#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag)) +#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag))) + +/* Clock field state tests */ + +#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS) +#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED) +#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW) +#define gate_is_sw_controllable(gate) FLAG_TEST(gate, GATE, SW) +#define gate_is_sw_managed(gate) FLAG_TEST(gate, GATE, SW_MANAGED) +#define gate_is_no_disable(gate) FLAG_TEST(gate, GATE, NO_DISABLE) + +#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) + +#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) +#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) +#define divider_has_fraction(div) (!divider_is_fixed(div) && \ + (div)->frac_width > 0) + +#define selector_exists(sel) ((sel)->width != 0) +#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS) + +/* Clock type, used to tell common block what it's part of */ +enum bcm_clk_type { + bcm_clk_none, /* undefined clock type */ + bcm_clk_bus, + bcm_clk_core, + bcm_clk_peri +}; + +/* + * Each CCU defines a mapped area of memory containing registers + * used to manage clocks implemented by the CCU. Access to memory + * within the CCU's space is serialized by a spinlock. Before any + * (other) address can be written, a special access "password" value + * must be written to its WR_ACCESS register (located at the base + * address of the range). We keep track of the name of each CCU as + * it is set up, and maintain them in a list. + */ +struct ccu_data { + void __iomem *base; /* base of mapped address space */ + spinlock_t lock; /* serialization lock */ + bool write_enabled; /* write access is currently enabled */ + struct list_head links; /* for ccu_list */ + struct device_node *node; + struct clk_onecell_data data; + const char *name; + u32 range; /* byte range of address space */ +}; + +/* + * Gating control and status is managed by a 32-bit gate register. + * + * There are several types of gating available: + * - (no gate) + * A clock with no gate is assumed to be always enabled. + * - hardware-only gating (auto-gating) + * Enabling or disabling clocks with this type of gate is + * managed automatically by the hardware. Such clocks can be + * considered by the software to be enabled. The current status + * of auto-gated clocks can be read from the gate status bit. + * - software-only gating + * Auto-gating is not available for this type of clock. + * Instead, software manages whether it's enabled by setting or + * clearing the enable bit. The current gate status of a gate + * under software control can be read from the gate status bit. + * To ensure a change to the gating status is complete, the + * status bit can be polled to verify that the gate has entered + * the desired state. + * - selectable hardware or software gating + * Gating for this type of clock can be configured to be either + * under software or hardware control. Which type is in use is + * determined by the hw_sw_sel bit of the gate register. + */ +struct bcm_clk_gate { + u32 offset; /* gate register offset */ + u32 status_bit; /* 0: gate is disabled; 0: gatge is enabled */ + u32 en_bit; /* 0: disable; 1: enable */ + u32 hw_sw_sel_bit; /* 0: hardware gating; 1: software gating */ + u32 flags; /* BCM_CLK_GATE_FLAGS_* below */ +}; + +/* + * Gate flags: + * HW means this gate can be auto-gated + * SW means the state of this gate can be software controlled + * NO_DISABLE means this gate is (only) enabled if under software control + * SW_MANAGED means the status of this gate is under software control + * ENABLED means this software-managed gate is *supposed* to be enabled + */ +#define BCM_CLK_GATE_FLAGS_EXISTS ((u32)1 << 0) /* Gate is valid */ +#define BCM_CLK_GATE_FLAGS_HW ((u32)1 << 1) /* Can auto-gate */ +#define BCM_CLK_GATE_FLAGS_SW ((u32)1 << 2) /* Software control */ +#define BCM_CLK_GATE_FLAGS_NO_DISABLE ((u32)1 << 3) /* HW or enabled */ +#define BCM_CLK_GATE_FLAGS_SW_MANAGED ((u32)1 << 4) /* SW now in control */ +#define BCM_CLK_GATE_FLAGS_ENABLED ((u32)1 << 5) /* If SW_MANAGED */ + +/* + * Gate initialization macros. + * + * Any gate initially under software control will be enabled. + */ + +/* A hardware/software gate initially under software control */ +#define HW_SW_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ + { \ + .offset = (_offset), \ + .status_bit = (_status_bit), \ + .en_bit = (_en_bit), \ + .hw_sw_sel_bit = (_hw_sw_sel_bit), \ + .flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \ + FLAG(GATE, SW_MANAGED)|FLAG(GATE, ENABLED)| \ + FLAG(GATE, EXISTS), \ + } + +/* A hardware/software gate initially under hardware control */ +#define HW_SW_GATE_AUTO(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ + { \ + .offset = (_offset), \ + .status_bit = (_status_bit), \ + .en_bit = (_en_bit), \ + .hw_sw_sel_bit = (_hw_sw_sel_bit), \ + .flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \ + FLAG(GATE, EXISTS), \ + } + +/* A hardware-or-enabled gate (enabled if not under hardware control) */ +#define HW_ENABLE_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ + { \ + .offset = (_offset), \ + .status_bit = (_status_bit), \ + .en_bit = (_en_bit), \ + .hw_sw_sel_bit = (_hw_sw_sel_bit), \ + .flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \ + FLAG(GATE, NO_DISABLE)|FLAG(GATE, EXISTS), \ + } + +/* A software-only gate */ +#define SW_ONLY_GATE(_offset, _status_bit, _en_bit) \ + { \ + .offset = (_offset), \ + .status_bit = (_status_bit), \ + .en_bit = (_en_bit), \ + .flags = FLAG(GATE, SW)|FLAG(GATE, SW_MANAGED)| \ + FLAG(GATE, ENABLED)|FLAG(GATE, EXISTS), \ + } + +/* A hardware-only gate */ +#define HW_ONLY_GATE(_offset, _status_bit) \ + { \ + .offset = (_offset), \ + .status_bit = (_status_bit), \ + .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ + } + +/* + * Each clock can have zero, one, or two dividers which change the + * output rate of the clock. Each divider can be either fixed or + * variable. If there are two dividers, they are the "pre-divider" + * and the "regular" or "downstream" divider. If there is only one, + * there is no pre-divider. + * + * A fixed divider is any non-zero (positive) value, and it + * indicates how the input rate is affected by the divider. + * + * The value of a variable divider is maintained in a sub-field of a + * 32-bit divider register. The position of the field in the + * register is defined by its offset and width. The value recorded + * in this field is always 1 less than the value it represents. + * + * In addition, a variable divider can indicate that some subset + * of its bits represent a "fractional" part of the divider. Such + * bits comprise the low-order portion of the divider field, and can + * be viewed as representing the portion of the divider that lies to + * the right of the decimal point. Most variable dividers have zero + * fractional bits. Variable dividers with non-zero fraction width + * still record a value 1 less than the value they represent; the + * added 1 does *not* affect the low-order bit in this case, it + * affects the bits above the fractional part only. (Often in this + * code a divider field value is distinguished from the value it + * represents by referring to the latter as a "divisor".) + * + * In order to avoid dealing with fractions, divider arithmetic is + * performed using "scaled" values. A scaled value is one that's + * been left-shifted by the fractional width of a divider. Dividing + * a scaled value by a scaled divisor produces the desired quotient + * without loss of precision and without any other special handling + * for fractions. + * + * The recorded value of a variable divider can be modified. To + * modify either divider (or both), a clock must be enabled (i.e., + * using its gate). In addition, a trigger register (described + * below) must be used to commit the change, and polled to verify + * the change is complete. + */ +struct bcm_clk_div { + union { + struct { /* variable divider */ + u32 offset; /* divider register offset */ + u32 shift; /* field shift */ + u32 width; /* field width */ + u32 frac_width; /* field fraction width */ + + u64 scaled_div; /* scaled divider value */ + }; + u32 fixed; /* non-zero fixed divider value */ + }; + u32 flags; /* BCM_CLK_DIV_FLAGS_* below */ +}; + +/* + * Divider flags: + * EXISTS means this divider exists + * FIXED means it is a fixed-rate divider + */ +#define BCM_CLK_DIV_FLAGS_EXISTS ((u32)1 << 0) /* Divider is valid */ +#define BCM_CLK_DIV_FLAGS_FIXED ((u32)1 << 1) /* Fixed-value */ + +/* Divider initialization macros */ + +/* A fixed (non-zero) divider */ +#define FIXED_DIVIDER(_value) \ + { \ + .fixed = (_value), \ + .flags = FLAG(DIV, EXISTS)|FLAG(DIV, FIXED), \ + } + +/* A divider with an integral divisor */ +#define DIVIDER(_offset, _shift, _width) \ + { \ + .offset = (_offset), \ + .shift = (_shift), \ + .width = (_width), \ + .scaled_div = BAD_SCALED_DIV_VALUE, \ + .flags = FLAG(DIV, EXISTS), \ + } + +/* A divider whose divisor has an integer and fractional part */ +#define FRAC_DIVIDER(_offset, _shift, _width, _frac_width) \ + { \ + .offset = (_offset), \ + .shift = (_shift), \ + .width = (_width), \ + .frac_width = (_frac_width), \ + .scaled_div = BAD_SCALED_DIV_VALUE, \ + .flags = FLAG(DIV, EXISTS), \ + } + +/* + * Clocks may have multiple "parent" clocks. If there is more than + * one, a selector must be specified to define which of the parent + * clocks is currently in use. The selected clock is indicated in a + * sub-field of a 32-bit selector register. The range of + * representable selector values typically exceeds the number of + * available parent clocks. Occasionally the reset value of a + * selector field is explicitly set to a (specific) value that does + * not correspond to a defined input clock. + * + * We register all known parent clocks with the common clock code + * using a packed array (i.e., no empty slots) of (parent) clock + * names, and refer to them later using indexes into that array. + * We maintain an array of selector values indexed by common clock + * index values in order to map between these common clock indexes + * and the selector values used by the hardware. + * + * Like dividers, a selector can be modified, but to do so a clock + * must be enabled, and a trigger must be used to commit the change. + */ +struct bcm_clk_sel { + u32 offset; /* selector register offset */ + u32 shift; /* field shift */ + u32 width; /* field width */ + + u32 parent_count; /* number of entries in parent_sel[] */ + u32 *parent_sel; /* array of parent selector values */ + u8 clk_index; /* current selected index in parent_sel[] */ +}; + +/* Selector initialization macro */ +#define SELECTOR(_offset, _shift, _width) \ + { \ + .offset = (_offset), \ + .shift = (_shift), \ + .width = (_width), \ + .clk_index = BAD_CLK_INDEX, \ + } + +/* + * Making changes to a variable divider or a selector for a clock + * requires the use of a trigger. A trigger is defined by a single + * bit within a register. To signal a change, a 1 is written into + * that bit. To determine when the change has been completed, that + * trigger bit is polled; the read value will be 1 while the change + * is in progress, and 0 when it is complete. + * + * Occasionally a clock will have more than one trigger. In this + * case, the "pre-trigger" will be used when changing a clock's + * selector and/or its pre-divider. + */ +struct bcm_clk_trig { + u32 offset; /* trigger register offset */ + u32 bit; /* trigger bit */ + u32 flags; /* BCM_CLK_TRIG_FLAGS_* below */ +}; + +/* + * Trigger flags: + * EXISTS means this trigger exists + */ +#define BCM_CLK_TRIG_FLAGS_EXISTS ((u32)1 << 0) /* Trigger is valid */ + +/* Trigger initialization macro */ +#define TRIGGER(_offset, _bit) \ + { \ + .offset = (_offset), \ + .bit = (_bit), \ + .flags = FLAG(TRIG, EXISTS), \ + } + +struct peri_clk_data { + struct bcm_clk_gate gate; + struct bcm_clk_trig pre_trig; + struct bcm_clk_div pre_div; + struct bcm_clk_trig trig; + struct bcm_clk_div div; + struct bcm_clk_sel sel; + const char *clocks[]; /* must be last; use CLOCKS() to declare */ +}; +#define CLOCKS(...) { __VA_ARGS__, NULL, } +#define NO_CLOCKS { NULL, } /* Must use of no parent clocks */ + +struct kona_clk { + struct clk_hw hw; + struct clk_init_data init_data; + const char *name; /* name of this clock */ + struct ccu_data *ccu; /* ccu this clock is associated with */ + enum bcm_clk_type type; + union { + void *data; + struct peri_clk_data *peri; + }; +}; +#define to_kona_clk(_hw) \ + container_of(_hw, struct kona_clk, hw) + +/* Exported globals */ + +extern struct clk_ops kona_peri_clk_ops; + +/* Help functions */ + +#define PERI_CLK_SETUP(clks, ccu, id, name) \ + clks[id] = kona_clk_setup(ccu, #name, bcm_clk_peri, &name ## _data) + +/* Externally visible functions */ + +extern u64 do_div_round_closest(u64 dividend, unsigned long divisor); +extern u64 scaled_div_max(struct bcm_clk_div *div); +extern u64 scaled_div_build(struct bcm_clk_div *div, u32 div_value, + u32 billionths); + +extern struct clk *kona_clk_setup(struct ccu_data *ccu, const char *name, + enum bcm_clk_type type, void *data); +extern void __init kona_dt_ccu_setup(struct device_node *node, + int (*ccu_clks_setup)(struct ccu_data *)); +extern bool __init kona_ccu_init(struct ccu_data *ccu); + +#endif /* _CLK_KONA_H */ diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 8cbfcf88fae3..a820b0cfcf57 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -33,7 +33,7 @@ struct clk_icst { struct clk_hw hw; void __iomem *vcoreg; void __iomem *lockreg; - const struct icst_params *params; + struct icst_params *params; unsigned long rate; }; @@ -84,6 +84,8 @@ static unsigned long icst_recalc_rate(struct clk_hw *hw, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (parent_rate) + icst->params->ref = parent_rate; vco = vco_get(icst->vcoreg); icst->rate = icst_hz(icst->params, vco); return icst->rate; @@ -105,6 +107,8 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_icst *icst = to_icst(hw); struct icst_vco vco; + if (parent_rate) + icst->params->ref = parent_rate; vco = icst_hz_to_vco(icst->params, rate); icst->rate = icst_hz(icst->params, vco); vco_set(icst->lockreg, icst->vcoreg, vco); @@ -120,24 +124,33 @@ static const struct clk_ops icst_ops = { struct clk *icst_clk_register(struct device *dev, const struct clk_icst_desc *desc, const char *name, + const char *parent_name, void __iomem *base) { struct clk *clk; struct clk_icst *icst; struct clk_init_data init; + struct icst_params *pclone; icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL); if (!icst) { pr_err("could not allocate ICST clock!\n"); return ERR_PTR(-ENOMEM); } + + pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL); + if (!pclone) { + pr_err("could not clone ICST params\n"); + return ERR_PTR(-ENOMEM); + } + init.name = name; init.ops = &icst_ops; init.flags = CLK_IS_ROOT; - init.parent_names = NULL; - init.num_parents = 0; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); icst->hw.init = &init; - icst->params = desc->params; + icst->params = pclone; icst->vcoreg = base + desc->vco_offset; icst->lockreg = base + desc->lock_offset; diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h index be99dd0da785..04e6f0aef588 100644 --- a/drivers/clk/versatile/clk-icst.h +++ b/drivers/clk/versatile/clk-icst.h @@ -16,4 +16,5 @@ struct clk_icst_desc { struct clk *icst_clk_register(struct device *dev, const struct clk_icst_desc *desc, const char *name, + const char *parent_name, void __iomem *base); diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index 844f8d711a12..6d8b8e1a080a 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c @@ -93,13 +93,15 @@ void integrator_impd1_clk_init(void __iomem *base, unsigned int id) imc = &impd1_clks[id]; imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id); - clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, base); + clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL, + base); imc->vco1clk = clk; imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id); /* VCO2 is also called "CLK2" */ imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id); - clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, base); + clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, NULL, + base); imc->vco2clk = clk; /* MMCI uses CLK2 right off */ diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-integrator.c index bda8967e09c2..734c4b8fe6ab 100644 --- a/drivers/clk/versatile/clk-integrator.c +++ b/drivers/clk/versatile/clk-integrator.c @@ -10,21 +10,17 @@ #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/err.h> -#include <linux/platform_data/clk-integrator.h> - -#include <mach/hardware.h> -#include <mach/platform.h> +#include <linux/of.h> +#include <linux/of_address.h> #include "clk-icst.h" -/* - * Implementation of the ARM Integrator/AP and Integrator/CP clock tree. - * Inspired by portions of: - * plat-versatile/clock.c and plat-versatile/include/plat/clock.h - */ +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 -static const struct icst_params cp_auxvco_params = { - .ref = 24000000, +/* Base offset for the core module */ +static void __iomem *cm_base; + +static const struct icst_params cp_auxosc_params = { .vco_max = ICST525_VCO_MAX_5V, .vco_min = ICST525_VCO_MIN, .vd_min = 8, @@ -35,50 +31,39 @@ static const struct icst_params cp_auxvco_params = { .idx2s = icst525_idx2s, }; -static const struct clk_icst_desc __initdata cp_icst_desc = { - .params = &cp_auxvco_params, +static const struct clk_icst_desc __initdata cm_auxosc_desc = { + .params = &cp_auxosc_params, .vco_offset = 0x1c, .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, }; -/* - * integrator_clk_init() - set up the integrator clock tree - * @is_cp: pass true if it's the Integrator/CP else AP is assumed - */ -void __init integrator_clk_init(bool is_cp) +static void __init of_integrator_cm_osc_setup(struct device_node *np) { - struct clk *clk; - - /* APB clock dummy */ - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); - clk_register_clkdev(clk, "apb_pclk", NULL); - - /* UART reference clock */ - clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT, - 14745600); - clk_register_clkdev(clk, NULL, "uart0"); - clk_register_clkdev(clk, NULL, "uart1"); - if (is_cp) - clk_register_clkdev(clk, NULL, "mmci"); - - /* 24 MHz clock */ - clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT, - 24000000); - clk_register_clkdev(clk, NULL, "kmi0"); - clk_register_clkdev(clk, NULL, "kmi1"); - if (!is_cp) - clk_register_clkdev(clk, NULL, "ap_timer"); + struct clk *clk = ERR_PTR(-EINVAL); + const char *clk_name = np->name; + const struct clk_icst_desc *desc = &cm_auxosc_desc; + const char *parent_name; - if (!is_cp) - return; + if (!cm_base) { + /* Remap the core module base if not done yet */ + struct device_node *parent; - /* 1 MHz clock */ - clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT, - 1000000); - clk_register_clkdev(clk, NULL, "sp804"); + parent = of_get_parent(np); + if (!np) { + pr_err("no parent on core module clock\n"); + return; + } + cm_base = of_iomap(parent, 0); + if (!cm_base) { + pr_err("could not remap core module base\n"); + return; + } + } - /* ICST VCO clock used on the Integrator/CP CLCD */ - clk = icst_clk_register(NULL, &cp_icst_desc, "icst", - __io_address(INTEGRATOR_HDR_BASE)); - clk_register_clkdev(clk, NULL, "clcd"); + parent_name = of_clk_get_parent_name(np, 0); + clk = icst_clk_register(NULL, desc, clk_name, parent_name, cm_base); + if (!IS_ERR(clk)) + of_clk_add_provider(np, of_clk_src_simple_get, clk); } +CLK_OF_DECLARE(integrator_cm_auxosc_clk, + "arm,integrator-cm-auxosc", of_integrator_cm_osc_setup); diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c index 747e7b31117c..c8b523117fb7 100644 --- a/drivers/clk/versatile/clk-realview.c +++ b/drivers/clk/versatile/clk-realview.c @@ -85,10 +85,10 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) /* ICST VCO clock */ if (is_pb1176) clk = icst_clk_register(NULL, &realview_osc0_desc, - "osc0", sysbase); + "osc0", NULL, sysbase); else clk = icst_clk_register(NULL, &realview_osc4_desc, - "osc4", sysbase); + "osc4", NULL, sysbase); clk_register_clkdev(clk, NULL, "dev:clcd"); clk_register_clkdev(clk, NULL, "issp:clcd"); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index cd6950fd8caf..6510ec4f45ff 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -140,3 +140,6 @@ config VF_PIT_TIMER bool help Support for Period Interrupt Timer on Freescale Vybrid Family SoCs. + +config CLKSRC_QCOM + bool diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index c7ca50a9c232..2e0c0cc0a014 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o +obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/arch/arm/mach-msm/timer.c b/drivers/clocksource/qcom-timer.c index fd1644987534..e807acf4c665 100644 --- a/arch/arm/mach-msm/timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -1,7 +1,7 @@ /* * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2012,2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -26,10 +26,6 @@ #include <linux/of_irq.h> #include <linux/sched_clock.h> -#include <asm/mach/time.h> - -#include "common.h" - #define TIMER_MATCH_VAL 0x0000 #define TIMER_COUNT_VAL 0x0004 #define TIMER_ENABLE 0x0008 @@ -110,15 +106,6 @@ static notrace cycle_t msm_read_timer_count(struct clocksource *cs) return readl_relaxed(source_base + TIMER_COUNT_VAL); } -static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) -{ - /* - * Shift timer count down by a constant due to unreliable lower bits - * on some targets. - */ - return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; -} - static struct clocksource msm_clocksource = { .name = "dg_timer", .rating = 300, @@ -232,7 +219,7 @@ err: sched_clock_register(msm_sched_clock_read, sched_bits, dgt_hz); } -#ifdef CONFIG_OF +#ifdef CONFIG_ARCH_QCOM static void __init msm_dt_timer_init(struct device_node *np) { u32 freq; @@ -285,7 +272,7 @@ static void __init msm_dt_timer_init(struct device_node *np) } CLOCKSOURCE_OF_DECLARE(kpss_timer, "qcom,kpss-timer", msm_dt_timer_init); CLOCKSOURCE_OF_DECLARE(scss_timer, "qcom,scss-timer", msm_dt_timer_init); -#endif +#else static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, u32 sts) @@ -305,6 +292,15 @@ static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, return 0; } +static notrace cycle_t msm_read_timer_count_shift(struct clocksource *cs) +{ + /* + * Shift timer count down by a constant due to unreliable lower bits + * on some targets. + */ + return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; +} + void __init msm7x01_timer_init(void) { struct clocksource *cs = &msm_clocksource; @@ -331,3 +327,4 @@ void __init qsd8x50_timer_init(void) return; msm_timer_init(19200000 / 4, 32, 7, false); } +#endif diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 31297499a60a..077db3aa985b 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -113,7 +113,7 @@ config ARM_INTEGRATOR If in doubt, say Y. config ARM_KIRKWOOD_CPUFREQ - def_bool ARCH_KIRKWOOD && OF + def_bool MACH_KIRKWOOD help This adds the CPUFreq driver for Marvell Kirkwood SoCs. diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index d988948a89a0..97ccc31dbdd8 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -22,7 +22,7 @@ config ARM_HIGHBANK_CPUIDLE config ARM_KIRKWOOD_CPUIDLE bool "CPU Idle Driver for Marvell Kirkwood SoCs" - depends on ARCH_KIRKWOOD + depends on ARCH_KIRKWOOD || MACH_KIRKWOOD help This adds the CPU Idle driver for Marvell Kirkwood SoCs. diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 903f24d28ba0..2c38d950a1e5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -192,7 +192,7 @@ config GPIO_MSM_V1 config GPIO_MSM_V2 tristate "Qualcomm MSM GPIO v2" - depends on GPIOLIB && OF && ARCH_MSM + depends on GPIOLIB && OF && ARCH_QCOM help Say yes here to support the GPIO interface on ARM v7 based Qualcomm MSM chips. Most of the pins on the MSM can be diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index c69d1e07a3a6..b6984971ce0c 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -3,7 +3,7 @@ config DRM_MSM tristate "MSM DRM" depends on DRM depends on MSM_IOMMU - depends on (ARCH_MSM && ARCH_MSM8960) || (ARM && COMPILE_TEST) + depends on ARCH_MSM8960 || (ARM && COMPILE_TEST) select DRM_KMS_HELPER select SHMEM select TMPFS diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 61ffdca96e25..111068782da4 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -69,3 +69,11 @@ config VERSATILE_FPGA_IRQ_NR config XTENSA_MX bool select IRQ_DOMAIN + +config IRQ_CROSSBAR + bool + help + Support for a CROSSBAR ip that preceeds the main interrupt controller. + The primary irqchip invokes the crossbar's callback which inturn allocates + a free irq and configures the IP. Thus the peripheral interrupts are + routed to one of the free irqchip interrupt lines. diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 5194afb39e78..cb37e5777f18 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o +obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c new file mode 100644 index 000000000000..fc817d28d1fe --- /dev/null +++ b/drivers/irqchip/irq-crossbar.c @@ -0,0 +1,208 @@ +/* + * drivers/irqchip/irq-crossbar.c + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Author: Sricharan R <r.sricharan@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> +#include <linux/irqchip/arm-gic.h> + +#define IRQ_FREE -1 +#define GIC_IRQ_START 32 + +/* + * @int_max: maximum number of supported interrupts + * @irq_map: array of interrupts to crossbar number mapping + * @crossbar_base: crossbar base address + * @register_offsets: offsets for each irq number + */ +struct crossbar_device { + uint int_max; + uint *irq_map; + void __iomem *crossbar_base; + int *register_offsets; + void (*write) (int, int); +}; + +static struct crossbar_device *cb; + +static inline void crossbar_writel(int irq_no, int cb_no) +{ + writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writew(int irq_no, int cb_no) +{ + writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writeb(int irq_no, int cb_no) +{ + writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline int allocate_free_irq(int cb_no) +{ + int i; + + for (i = 0; i < cb->int_max; i++) { + if (cb->irq_map[i] == IRQ_FREE) { + cb->irq_map[i] = cb_no; + return i; + } + } + + return -ENODEV; +} + +static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); + return 0; +} + +static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; + + if (hw > GIC_IRQ_START) + cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; +} + +static int crossbar_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + unsigned long ret; + + ret = allocate_free_irq(intspec[1]); + + if (IS_ERR_VALUE(ret)) + return ret; + + *out_hwirq = ret + GIC_IRQ_START; + return 0; +} + +const struct irq_domain_ops routable_irq_domain_ops = { + .map = crossbar_domain_map, + .unmap = crossbar_domain_unmap, + .xlate = crossbar_domain_xlate +}; + +static int __init crossbar_of_init(struct device_node *node) +{ + int i, size, max, reserved = 0, entry; + const __be32 *irqsr; + + cb = kzalloc(sizeof(struct cb_device *), GFP_KERNEL); + + if (!cb) + return -ENOMEM; + + cb->crossbar_base = of_iomap(node, 0); + if (!cb->crossbar_base) + goto err1; + + of_property_read_u32(node, "ti,max-irqs", &max); + cb->irq_map = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->irq_map) + goto err2; + + cb->int_max = max; + + for (i = 0; i < max; i++) + cb->irq_map[i] = IRQ_FREE; + + /* Get and mark reserved irqs */ + irqsr = of_get_property(node, "ti,irqs-reserved", &size); + if (irqsr) { + size /= sizeof(__be32); + + for (i = 0; i < size; i++) { + of_property_read_u32_index(node, + "ti,irqs-reserved", + i, &entry); + if (entry > max) { + pr_err("Invalid reserved entry\n"); + goto err3; + } + cb->irq_map[entry] = 0; + } + } + + cb->register_offsets = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->register_offsets) + goto err3; + + of_property_read_u32(node, "ti,reg-size", &size); + + switch (size) { + case 1: + cb->write = crossbar_writeb; + break; + case 2: + cb->write = crossbar_writew; + break; + case 4: + cb->write = crossbar_writel; + break; + default: + pr_err("Invalid reg-size property\n"); + goto err4; + break; + } + + /* + * Register offsets are not linear because of the + * reserved irqs. so find and store the offsets once. + */ + for (i = 0; i < max; i++) { + if (!cb->irq_map[i]) + continue; + + cb->register_offsets[i] = reserved; + reserved += size; + } + + register_routable_domain_ops(&routable_irq_domain_ops); + return 0; + +err4: + kfree(cb->register_offsets); +err3: + kfree(cb->irq_map); +err2: + iounmap(cb->crossbar_base); +err1: + kfree(cb); + return -ENOMEM; +} + +static const struct of_device_id crossbar_match[] __initconst = { + { .compatible = "ti,irq-crossbar" }, + {} +}; + +int __init irqcrossbar_init(void) +{ + struct device_node *np; + np = of_find_matching_node(NULL, crossbar_match); + if (!np) + return -ENODEV; + + crossbar_of_init(np); + return 0; +} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 341c6016812d..07a7050841ec 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -824,16 +824,25 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_and_handler(irq, &gic_chip, handle_fasteoi_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + + gic_routable_irq_domain_ops->map(d, irq, hw); } irq_set_chip_data(irq, d->host_data); return 0; } +static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + gic_routable_irq_domain_ops->unmap(d, irq); +} + static int gic_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) { + unsigned long ret = 0; + if (d->of_node != controller) return -EINVAL; if (intsize < 3) @@ -843,11 +852,20 @@ static int gic_irq_domain_xlate(struct irq_domain *d, *out_hwirq = intspec[1] + 16; /* For SPIs, we need to add 16 more to get the GIC irq ID number */ - if (!intspec[0]) - *out_hwirq += 16; + if (!intspec[0]) { + ret = gic_routable_irq_domain_ops->xlate(d, controller, + intspec, + intsize, + out_hwirq, + out_type); + + if (IS_ERR_VALUE(ret)) + return ret; + } *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; - return 0; + + return ret; } #ifdef CONFIG_SMP @@ -871,9 +889,41 @@ static struct notifier_block gic_cpu_notifier = { const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, + .unmap = gic_irq_domain_unmap, .xlate = gic_irq_domain_xlate, }; +/* Default functions for routable irq domain */ +static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + return 0; +} + +static void gic_routable_irq_domain_unmap(struct irq_domain *d, + unsigned int irq) +{ +} + +static int gic_routable_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) +{ + *out_hwirq += 16; + return 0; +} + +const struct irq_domain_ops gic_default_routable_irq_domain_ops = { + .map = gic_routable_irq_domain_map, + .unmap = gic_routable_irq_domain_unmap, + .xlate = gic_routable_irq_domain_xlate, +}; + +const struct irq_domain_ops *gic_routable_irq_domain_ops = + &gic_default_routable_irq_domain_ops; + void __init gic_init_bases(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base, u32 percpu_offset, struct device_node *node) @@ -881,6 +931,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, irq_hw_number_t hwirq_base; struct gic_chip_data *gic; int gic_irqs, irq_base, i; + int nr_routable_irqs; BUG_ON(gic_nr >= MAX_GIC_NR); @@ -946,14 +997,25 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic->gic_irqs = gic_irqs; gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ - irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); - if (IS_ERR_VALUE(irq_base)) { - WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", - irq_start); - irq_base = irq_start; + + if (of_property_read_u32(node, "arm,routable-irqs", + &nr_routable_irqs)) { + irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, + numa_node_id()); + if (IS_ERR_VALUE(irq_base)) { + WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", + irq_start); + irq_base = irq_start; + } + + gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, + hwirq_base, &gic_irq_domain_ops, gic); + } else { + gic->domain = irq_domain_add_linear(node, nr_routable_irqs, + &gic_irq_domain_ops, + gic); } - gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, - hwirq_base, &gic_irq_domain_ops, gic); + if (WARN_ON(!gic->domain)) return; diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index e51d40031884..8e41be62812e 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -111,7 +111,8 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init); static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) { struct irq_domain *d = irq_get_handler_data(irq); - struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq); + + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) & gc->mask_cache; @@ -123,6 +124,19 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) } } +/* + * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register. + * To avoid interrupt events on stale irqs, we clear them before unmask. + */ +static unsigned int orion_bridge_irq_startup(struct irq_data *d) +{ + struct irq_chip_type *ct = irq_data_get_chip_type(d); + + ct->chip.irq_ack(d); + ct->chip.irq_unmask(d); + return 0; +} + static int __init orion_bridge_irq_init(struct device_node *np, struct device_node *parent) { @@ -143,7 +157,7 @@ static int __init orion_bridge_irq_init(struct device_node *np, } ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, - handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); + handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); if (ret) { pr_err("%s: unable to alloc irq domain gc\n", np->name); return ret; @@ -176,12 +190,14 @@ static int __init orion_bridge_irq_init(struct device_node *np, gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE; gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK; + gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup; gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; - /* mask all interrupts */ + /* mask and clear all interrupts */ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK); + writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE); irq_set_handler_data(irq, domain); irq_set_chained_handler(irq, orion_bridge_irq_handler); diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 8e21ae0bab46..fd2c980e4cea 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -57,6 +57,7 @@ /** * struct vic_device - VIC PM device + * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0. * @irq: The IRQ number for the base of the VIC. * @base: The register base for the VIC. * @valid_sources: A bitmask of valid interrupts @@ -224,6 +225,17 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) return handled; } +static void vic_handle_irq_cascaded(unsigned int irq, struct irq_desc *desc) +{ + u32 stat, hwirq; + struct vic_device *vic = irq_desc_get_handler_data(desc); + + while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { + hwirq = ffs(stat) - 1; + generic_handle_irq(irq_find_mapping(vic->domain, hwirq)); + } +} + /* * Keep iterating over all registered VIC's until there are no pending * interrupts. @@ -246,6 +258,7 @@ static struct irq_domain_ops vic_irqdomain_ops = { /** * vic_register() - Register a VIC. * @base: The base address of the VIC. + * @parent_irq: The parent IRQ if cascaded, else 0. * @irq: The base IRQ for the VIC. * @valid_sources: bitmask of valid interrupts * @resume_sources: bitmask of interrupts allowed for resume sources. @@ -257,7 +270,8 @@ static struct irq_domain_ops vic_irqdomain_ops = { * * This also configures the IRQ domain for the VIC. */ -static void __init vic_register(void __iomem *base, unsigned int irq, +static void __init vic_register(void __iomem *base, unsigned int parent_irq, + unsigned int irq, u32 valid_sources, u32 resume_sources, struct device_node *node) { @@ -273,15 +287,25 @@ static void __init vic_register(void __iomem *base, unsigned int irq, v->base = base; v->valid_sources = valid_sources; v->resume_sources = resume_sources; - v->irq = irq; set_handle_irq(vic_handle_irq); vic_id++; + + if (parent_irq) { + irq_set_handler_data(parent_irq, v); + irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded); + } + v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, &vic_irqdomain_ops, v); /* create an IRQ mapping for each valid IRQ */ for (i = 0; i < fls(valid_sources); i++) if (valid_sources & (1 << i)) irq_create_mapping(v->domain, i); + /* If no base IRQ was passed, figure out our allocated base */ + if (irq) + v->irq = irq; + else + v->irq = irq_find_mapping(v->domain, 0); } static void vic_ack_irq(struct irq_data *d) @@ -409,10 +433,10 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, writel(32, base + VIC_PL190_DEF_VECT_ADDR); } - vic_register(base, irq_start, vic_sources, 0, node); + vic_register(base, 0, irq_start, vic_sources, 0, node); } -void __init __vic_init(void __iomem *base, int irq_start, +void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, u32 vic_sources, u32 resume_sources, struct device_node *node) { @@ -449,7 +473,7 @@ void __init __vic_init(void __iomem *base, int irq_start, vic_init2(base); - vic_register(base, irq_start, vic_sources, resume_sources, node); + vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node); } /** @@ -462,8 +486,30 @@ void __init __vic_init(void __iomem *base, int irq_start, void __init vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources) { - __vic_init(base, irq_start, vic_sources, resume_sources, NULL); + __vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL); +} + +/** + * vic_init_cascaded() - initialise a cascaded vectored interrupt controller + * @base: iomem base address + * @parent_irq: the parent IRQ we're cascaded off + * @irq_start: starting interrupt number, must be muliple of 32 + * @vic_sources: bitmask of interrupt sources to allow + * @resume_sources: bitmask of interrupt sources to allow for resume + * + * This returns the base for the new interrupts or negative on error. + */ +int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq, + u32 vic_sources, u32 resume_sources) +{ + struct vic_device *v; + + v = &vic_devices[vic_id]; + __vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL); + /* Return out acquired base */ + return v->irq; } +EXPORT_SYMBOL_GPL(vic_init_cascaded); #ifdef CONFIG_OF int __init vic_of_init(struct device_node *node, struct device_node *parent) @@ -485,7 +531,7 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent) /* * Passing 0 as first IRQ makes the simple domain allocate descriptors */ - __vic_init(regs, 0, interrupt_mask, wakeup_mask, node); + __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node); return 0; } diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 72156c123033..44c358ecf5a1 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -421,7 +421,7 @@ config LEDS_MC13783 config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" depends on LEDS_CLASS - depends on ARCH_KIRKWOOD + depends on ARCH_KIRKWOOD || MACH_KIRKWOOD default y help This option enable support for the dual-GPIO LED found on the @@ -431,7 +431,7 @@ config LEDS_NS2 config LEDS_NETXBIG tristate "LED support for Big Network series LEDs" depends on LEDS_CLASS - depends on ARCH_KIRKWOOD + depends on ARCH_KIRKWOOD || MACH_KIRKWOOD default y help This option enable support for LEDs found on the LaCie 2Big diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index a4989ec6292e..8eb6a36f125a 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -746,28 +746,6 @@ static int nand_davinci_probe(struct platform_device *pdev) goto err_clk_enable; } - /* - * Setup Async configuration register in case we did not boot from - * NAND and so bootloader did not bother to set it up. - */ - val = davinci_nand_readl(info, A1CR_OFFSET + info->core_chipsel * 4); - - /* Extended Wait is not valid and Select Strobe mode is not used */ - val &= ~(ACR_ASIZE_MASK | ACR_EW_MASK | ACR_SS_MASK); - if (info->chip.options & NAND_BUSWIDTH_16) - val |= 0x1; - - davinci_nand_writel(info, A1CR_OFFSET + info->core_chipsel * 4, val); - - ret = 0; - if (info->timing) - ret = davinci_aemif_setup_timing(info->timing, info->base, - info->core_chipsel); - if (ret < 0) { - dev_dbg(&pdev->dev, "NAND timing values setup fail\n"); - goto err; - } - spin_lock_irq(&davinci_nand_lock); /* put CSxNAND into NAND mode */ diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index ecadecea79b2..73df8b6c6fb4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o +stmmac-$(CONFIG_ARCH_SOCFPGA) += dwmac-socfpga.o stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c new file mode 100644 index 000000000000..c7f034b9583c --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -0,0 +1,183 @@ +/* Copyright (C) 2014 Altera Corporation + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Adopted from dwmac-sti.c + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_net.h> +#include <linux/of_platform.h> +#include <linux/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/stmmac.h> + +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 +#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 + +struct socfpga_dwmac { + int interface; + u32 reg_offset; + struct device *dev; + struct regmap *sys_mgr_base_addr; + struct device_node *dwmac_np; +}; + +static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) +{ + struct device_node *np = dev->of_node; + struct device_node *stmmac_np; + struct regmap *sys_mgr_base_addr; + u32 reg_offset; + int ret; + + stmmac_np = of_get_next_available_child(np, NULL); + if (!stmmac_np) { + dev_info(dev, "No dwmac node found\n"); + return -EINVAL; + } + + if (!of_device_is_compatible(stmmac_np, "snps,dwmac")) { + dev_info(dev, "dwmac node isn't compatible with snps,dwmac\n"); + return -EINVAL; + } + + dwmac->interface = of_get_phy_mode(stmmac_np); + of_node_put(stmmac_np); + + sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); + if (IS_ERR(sys_mgr_base_addr)) { + dev_info(dev, "No sysmgr-syscon node found\n"); + return PTR_ERR(sys_mgr_base_addr); + } + + ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, ®_offset); + if (ret) { + dev_info(dev, "Could not reg_offset into sysmgr-syscon!\n"); + return -EINVAL; + } + + dwmac->reg_offset = reg_offset; + dwmac->sys_mgr_base_addr = sys_mgr_base_addr; + dwmac->dwmac_np = stmmac_np; + dwmac->dev = dev; + + return 0; +} + +static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) +{ + struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; + int phymode = dwmac->interface; + u32 reg_offset = dwmac->reg_offset; + u32 ctrl, val, shift = 0; + + if (of_machine_is_compatible("altr,socfpga-vt")) + return 0; + + switch (phymode) { + case PHY_INTERFACE_MODE_RGMII: + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; + break; + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; + break; + default: + dev_err(dwmac->dev, "bad phy mode %d\n", phymode); + return -EINVAL; + } + + regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); + ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << shift); + ctrl |= val << shift; + + regmap_write(sys_mgr_base_addr, reg_offset, ctrl); + return 0; +} + +static int socfpga_dwmac_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + int ret = -ENOMEM; + struct socfpga_dwmac *dwmac; + + dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) + return -ENOMEM; + + ret = socfpga_dwmac_parse_data(dwmac, dev); + if (ret) { + dev_err(dev, "Unable to parse OF data\n"); + return ret; + } + + ret = socfpga_dwmac_setup(dwmac); + if (ret) { + dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); + return ret; + } + + if (node) { + ret = of_platform_populate(node, NULL, NULL, dev); + if (ret) { + dev_err(dev, "failed to add dwmac core\n"); + return ret; + } + } else { + dev_err(dev, "no device node, failed to add dwmac core\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, dwmac); + + return 0; +} + +static int socfpga_dwmac_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id socfpga_dwmac_match[] = { + { .compatible = "altr,socfpga-stmmac" }, + {}, +}; +MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); + +static struct platform_driver socfpga_dwmac_driver = { + .probe = socfpga_dwmac_probe, + .remove = socfpga_dwmac_remove, + .driver = { + .name = "socfpga-dwmac", + .of_match_table = of_match_ptr(socfpga_dwmac_match), + }, +}; + +module_platform_driver(socfpga_dwmac_driver); + +MODULE_ALIAS("platform:socfpga-dwmac"); +MODULE_AUTHOR("Dinh Nguyen <dinguyen@altera.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Altera SOCFPGA DWMAC Glue Layer"); diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index afa2354f6600..5e6b33f9c294 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -24,7 +24,7 @@ config PHY_EXYNOS_MIPI_VIDEO config PHY_MVEBU_SATA def_bool y - depends on ARCH_KIRKWOOD || ARCH_DOVE + depends on ARCH_KIRKWOOD || ARCH_DOVE || MACH_KIRKWOOD depends on OF select GENERIC_PHY diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 6d452a78b19c..fa0e4e057b99 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -22,7 +22,7 @@ config POWER_RESET_GPIO config POWER_RESET_MSM bool "Qualcomm MSM power-off driver" - depends on POWER_RESET && ARCH_MSM + depends on POWER_RESET && ARCH_QCOM help Power off and restart support for Qualcomm boards. diff --git a/drivers/power/reset/qnap-poweroff.c b/drivers/power/reset/qnap-poweroff.c index 37f56f7ee926..a75db7f8a92f 100644 --- a/drivers/power/reset/qnap-poweroff.c +++ b/drivers/power/reset/qnap-poweroff.c @@ -1,5 +1,5 @@ /* - * QNAP Turbo NAS Board power off + * QNAP Turbo NAS Board power off. Can also be used on Synology devices. * * Copyright (C) 2012 Andrew Lunn <andrew@lunn.ch> * @@ -25,17 +25,43 @@ #define UART1_REG(x) (base + ((UART_##x) << 2)) +struct power_off_cfg { + u32 baud; + char cmd; +}; + +static const struct power_off_cfg qnap_power_off_cfg = { + .baud = 19200, + .cmd = 'A', +}; + +static const struct power_off_cfg synology_power_off_cfg = { + .baud = 9600, + .cmd = '1', +}; + +static const struct of_device_id qnap_power_off_of_match_table[] = { + { .compatible = "qnap,power-off", + .data = &qnap_power_off_cfg, + }, + { .compatible = "synology,power-off", + .data = &synology_power_off_cfg, + }, + {} +}; +MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table); + static void __iomem *base; static unsigned long tclk; +static const struct power_off_cfg *cfg; static void qnap_power_off(void) { - /* 19200 baud divisor */ - const unsigned divisor = ((tclk + (8 * 19200)) / (16 * 19200)); + const unsigned divisor = ((tclk + (8 * cfg->baud)) / (16 * cfg->baud)); pr_err("%s: triggering power-off...\n", __func__); - /* hijack UART1 and reset into sane state (19200,8n1) */ + /* hijack UART1 and reset into sane state */ writel(0x83, UART1_REG(LCR)); writel(divisor & 0xff, UART1_REG(DLL)); writel((divisor >> 8) & 0xff, UART1_REG(DLM)); @@ -44,16 +70,21 @@ static void qnap_power_off(void) writel(0x00, UART1_REG(FCR)); writel(0x00, UART1_REG(MCR)); - /* send the power-off command 'A' to PIC */ - writel('A', UART1_REG(TX)); + /* send the power-off command to PIC */ + writel(cfg->cmd, UART1_REG(TX)); } static int qnap_power_off_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct resource *res; struct clk *clk; char symname[KSYM_NAME_LEN]; + const struct of_device_id *match = + of_match_node(qnap_power_off_of_match_table, np); + cfg = match->data; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Missing resource"); @@ -94,12 +125,6 @@ static int qnap_power_off_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id qnap_power_off_of_match_table[] = { - { .compatible = "qnap,power-off", }, - {} -}; -MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table); - static struct platform_driver qnap_power_off_driver = { .probe = qnap_power_off_probe, .remove = qnap_power_off_remove, diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c9d04f797862..0615f50a14cd 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -11,3 +11,5 @@ menuconfig RESET_CONTROLLER via GPIOs or SoC-internal reset controller modules. If unsure, say no. + +source "drivers/reset/sti/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index cc29832c9638..4f60caf750ce 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_RESET_CONTROLLER) += core.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o +obj-$(CONFIG_ARCH_STI) += sti/ diff --git a/drivers/reset/sti/Kconfig b/drivers/reset/sti/Kconfig new file mode 100644 index 000000000000..88d2d0316613 --- /dev/null +++ b/drivers/reset/sti/Kconfig @@ -0,0 +1,15 @@ +if ARCH_STI + +config STI_RESET_SYSCFG + bool + select RESET_CONTROLLER + +config STIH415_RESET + bool + select STI_RESET_SYSCFG + +config STIH416_RESET + bool + select STI_RESET_SYSCFG + +endif diff --git a/drivers/reset/sti/Makefile b/drivers/reset/sti/Makefile new file mode 100644 index 000000000000..be1c97647871 --- /dev/null +++ b/drivers/reset/sti/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_STI_RESET_SYSCFG) += reset-syscfg.o + +obj-$(CONFIG_STIH415_RESET) += reset-stih415.o +obj-$(CONFIG_STIH416_RESET) += reset-stih416.o diff --git a/drivers/reset/sti/reset-stih415.c b/drivers/reset/sti/reset-stih415.c new file mode 100644 index 000000000000..e6f6c41abe12 --- /dev/null +++ b/drivers/reset/sti/reset-stih415.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2013 STMicroelectronics (R&D) Limited + * Author: Stephen Gallimore <stephen.gallimore@st.com> + * Author: Srinivas Kandagatla <srinivas.kandagatla@st.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. + */ +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +#include <dt-bindings/reset-controller/stih415-resets.h> + +#include "reset-syscfg.h" + +/* + * STiH415 Peripheral powerdown definitions. + */ +static const char stih415_front[] = "st,stih415-front-syscfg"; +static const char stih415_rear[] = "st,stih415-rear-syscfg"; +static const char stih415_sbc[] = "st,stih415-sbc-syscfg"; +static const char stih415_lpm[] = "st,stih415-lpm-syscfg"; + +#define STIH415_PDN_FRONT(_bit) \ + _SYSCFG_RST_CH(stih415_front, SYSCFG_114, _bit, SYSSTAT_187, _bit) + +#define STIH415_PDN_REAR(_cntl, _stat) \ + _SYSCFG_RST_CH(stih415_rear, SYSCFG_336, _cntl, SYSSTAT_384, _stat) + +#define STIH415_SRST_REAR(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_rear, _reg, _bit) + +#define STIH415_SRST_SBC(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_sbc, _reg, _bit) + +#define STIH415_SRST_FRONT(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_front, _reg, _bit) + +#define STIH415_SRST_LPM(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih415_lpm, _reg, _bit) + +#define SYSCFG_114 0x38 /* Powerdown request EMI/NAND/Keyscan */ +#define SYSSTAT_187 0x15c /* Powerdown status EMI/NAND/Keyscan */ + +#define SYSCFG_336 0x90 /* Powerdown request USB/SATA/PCIe */ +#define SYSSTAT_384 0x150 /* Powerdown status USB/SATA/PCIe */ + +#define SYSCFG_376 0x130 /* Reset generator 0 control 0 */ +#define SYSCFG_166 0x108 /* Softreset Ethernet 0 */ +#define SYSCFG_31 0x7c /* Softreset Ethernet 1 */ +#define LPM_SYSCFG_1 0x4 /* Softreset IRB */ + +static const struct syscfg_reset_channel_data stih415_powerdowns[] = { + [STIH415_EMISS_POWERDOWN] = STIH415_PDN_FRONT(0), + [STIH415_NAND_POWERDOWN] = STIH415_PDN_FRONT(1), + [STIH415_KEYSCAN_POWERDOWN] = STIH415_PDN_FRONT(2), + [STIH415_USB0_POWERDOWN] = STIH415_PDN_REAR(0, 0), + [STIH415_USB1_POWERDOWN] = STIH415_PDN_REAR(1, 1), + [STIH415_USB2_POWERDOWN] = STIH415_PDN_REAR(2, 2), + [STIH415_SATA0_POWERDOWN] = STIH415_PDN_REAR(3, 3), + [STIH415_SATA1_POWERDOWN] = STIH415_PDN_REAR(4, 4), + [STIH415_PCIE_POWERDOWN] = STIH415_PDN_REAR(5, 8), +}; + +static const struct syscfg_reset_channel_data stih415_softresets[] = { + [STIH415_ETH0_SOFTRESET] = STIH415_SRST_FRONT(SYSCFG_166, 0), + [STIH415_ETH1_SOFTRESET] = STIH415_SRST_SBC(SYSCFG_31, 0), + [STIH415_IRB_SOFTRESET] = STIH415_SRST_LPM(LPM_SYSCFG_1, 6), + [STIH415_USB0_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 9), + [STIH415_USB1_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 10), + [STIH415_USB2_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 11), +}; + +static struct syscfg_reset_controller_data stih415_powerdown_controller = { + .wait_for_ack = true, + .nr_channels = ARRAY_SIZE(stih415_powerdowns), + .channels = stih415_powerdowns, +}; + +static struct syscfg_reset_controller_data stih415_softreset_controller = { + .wait_for_ack = false, + .active_low = true, + .nr_channels = ARRAY_SIZE(stih415_softresets), + .channels = stih415_softresets, +}; + +static struct of_device_id stih415_reset_match[] = { + { .compatible = "st,stih415-powerdown", + .data = &stih415_powerdown_controller, }, + { .compatible = "st,stih415-softreset", + .data = &stih415_softreset_controller, }, + {}, +}; + +static struct platform_driver stih415_reset_driver = { + .probe = syscfg_reset_probe, + .driver = { + .name = "reset-stih415", + .owner = THIS_MODULE, + .of_match_table = stih415_reset_match, + }, +}; + +static int __init stih415_reset_init(void) +{ + return platform_driver_register(&stih415_reset_driver); +} +arch_initcall(stih415_reset_init); diff --git a/drivers/reset/sti/reset-stih416.c b/drivers/reset/sti/reset-stih416.c new file mode 100644 index 000000000000..fe3bf02bdc8c --- /dev/null +++ b/drivers/reset/sti/reset-stih416.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2013 STMicroelectronics (R&D) Limited + * Author: Stephen Gallimore <stephen.gallimore@st.com> + * Author: Srinivas Kandagatla <srinivas.kandagatla@st.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. + */ +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +#include <dt-bindings/reset-controller/stih416-resets.h> + +#include "reset-syscfg.h" + +/* + * STiH416 Peripheral powerdown definitions. + */ +static const char stih416_front[] = "st,stih416-front-syscfg"; +static const char stih416_rear[] = "st,stih416-rear-syscfg"; +static const char stih416_sbc[] = "st,stih416-sbc-syscfg"; +static const char stih416_lpm[] = "st,stih416-lpm-syscfg"; +static const char stih416_cpu[] = "st,stih416-cpu-syscfg"; + +#define STIH416_PDN_FRONT(_bit) \ + _SYSCFG_RST_CH(stih416_front, SYSCFG_1500, _bit, SYSSTAT_1578, _bit) + +#define STIH416_PDN_REAR(_cntl, _stat) \ + _SYSCFG_RST_CH(stih416_rear, SYSCFG_2525, _cntl, SYSSTAT_2583, _stat) + +#define SYSCFG_1500 0x7d0 /* Powerdown request EMI/NAND/Keyscan */ +#define SYSSTAT_1578 0x908 /* Powerdown status EMI/NAND/Keyscan */ + +#define SYSCFG_2525 0x834 /* Powerdown request USB/SATA/PCIe */ +#define SYSSTAT_2583 0x91c /* Powerdown status USB/SATA/PCIe */ + +#define SYSCFG_2552 0x8A0 /* Reset Generator control 0 */ +#define SYSCFG_1539 0x86c /* Softreset Ethernet 0 */ +#define SYSCFG_510 0x7f8 /* Softreset Ethernet 1 */ +#define LPM_SYSCFG_1 0x4 /* Softreset IRB */ +#define SYSCFG_2553 0x8a4 /* Softreset SATA0/1, PCIE0/1 */ +#define SYSCFG_7563 0x8cc /* MPE softresets 0 */ +#define SYSCFG_7564 0x8d0 /* MPE softresets 1 */ + +#define STIH416_SRST_CPU(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_cpu, _reg, _bit) + +#define STIH416_SRST_FRONT(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_front, _reg, _bit) + +#define STIH416_SRST_REAR(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_rear, _reg, _bit) + +#define STIH416_SRST_LPM(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_lpm, _reg, _bit) + +#define STIH416_SRST_SBC(_reg, _bit) \ + _SYSCFG_RST_CH_NO_ACK(stih416_sbc, _reg, _bit) + +static const struct syscfg_reset_channel_data stih416_powerdowns[] = { + [STIH416_EMISS_POWERDOWN] = STIH416_PDN_FRONT(0), + [STIH416_NAND_POWERDOWN] = STIH416_PDN_FRONT(1), + [STIH416_KEYSCAN_POWERDOWN] = STIH416_PDN_FRONT(2), + [STIH416_USB0_POWERDOWN] = STIH416_PDN_REAR(0, 0), + [STIH416_USB1_POWERDOWN] = STIH416_PDN_REAR(1, 1), + [STIH416_USB2_POWERDOWN] = STIH416_PDN_REAR(2, 2), + [STIH416_USB3_POWERDOWN] = STIH416_PDN_REAR(6, 5), + [STIH416_SATA0_POWERDOWN] = STIH416_PDN_REAR(3, 3), + [STIH416_SATA1_POWERDOWN] = STIH416_PDN_REAR(4, 4), + [STIH416_PCIE0_POWERDOWN] = STIH416_PDN_REAR(7, 9), + [STIH416_PCIE1_POWERDOWN] = STIH416_PDN_REAR(5, 8), +}; + +static const struct syscfg_reset_channel_data stih416_softresets[] = { + [STIH416_ETH0_SOFTRESET] = STIH416_SRST_FRONT(SYSCFG_1539, 0), + [STIH416_ETH1_SOFTRESET] = STIH416_SRST_SBC(SYSCFG_510, 0), + [STIH416_IRB_SOFTRESET] = STIH416_SRST_LPM(LPM_SYSCFG_1, 6), + [STIH416_USB0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 9), + [STIH416_USB1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 10), + [STIH416_USB2_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 11), + [STIH416_USB3_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 28), + [STIH416_SATA0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 7), + [STIH416_SATA1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 3), + [STIH416_PCIE0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 15), + [STIH416_PCIE1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 2), + [STIH416_AUD_DAC_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 14), + [STIH416_HDTVOUT_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 5), + [STIH416_VTAC_M_RX_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 25), + [STIH416_VTAC_A_RX_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 26), + [STIH416_SYNC_HD_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 5), + [STIH416_SYNC_SD_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 6), + [STIH416_BLITTER_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 10), + [STIH416_GPU_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 11), + [STIH416_VTAC_M_TX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 18), + [STIH416_VTAC_A_TX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 19), + [STIH416_VTG_AUX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 21), + [STIH416_JPEG_DEC_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 23), + [STIH416_HVA_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 2), + [STIH416_COMPO_M_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 3), + [STIH416_COMPO_A_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 4), + [STIH416_VP8_DEC_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 10), + [STIH416_VTG_MAIN_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 16), +}; + +static struct syscfg_reset_controller_data stih416_powerdown_controller = { + .wait_for_ack = true, + .nr_channels = ARRAY_SIZE(stih416_powerdowns), + .channels = stih416_powerdowns, +}; + +static struct syscfg_reset_controller_data stih416_softreset_controller = { + .wait_for_ack = false, + .active_low = true, + .nr_channels = ARRAY_SIZE(stih416_softresets), + .channels = stih416_softresets, +}; + +static struct of_device_id stih416_reset_match[] = { + { .compatible = "st,stih416-powerdown", + .data = &stih416_powerdown_controller, }, + { .compatible = "st,stih416-softreset", + .data = &stih416_softreset_controller, }, + {}, +}; + +static struct platform_driver stih416_reset_driver = { + .probe = syscfg_reset_probe, + .driver = { + .name = "reset-stih416", + .owner = THIS_MODULE, + .of_match_table = stih416_reset_match, + }, +}; + +static int __init stih416_reset_init(void) +{ + return platform_driver_register(&stih416_reset_driver); +} +arch_initcall(stih416_reset_init); diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c new file mode 100644 index 000000000000..a145cc066d4a --- /dev/null +++ b/drivers/reset/sti/reset-syscfg.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2013 STMicroelectronics Limited + * Author: Stephen Gallimore <stephen.gallimore@st.com> + * + * Inspired by mach-imx/src.c + * + * 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/platform_device.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/types.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> + +#include "reset-syscfg.h" + +/** + * Reset channel regmap configuration + * + * @reset: regmap field for the channel's reset bit. + * @ack: regmap field for the channel's ack bit (optional). + */ +struct syscfg_reset_channel { + struct regmap_field *reset; + struct regmap_field *ack; +}; + +/** + * A reset controller which groups together a set of related reset bits, which + * may be located in different system configuration registers. + * + * @rst: base reset controller structure. + * @active_low: are the resets in this controller active low, i.e. clearing + * the reset bit puts the hardware into reset. + * @channels: An array of reset channels for this controller. + */ +struct syscfg_reset_controller { + struct reset_controller_dev rst; + bool active_low; + struct syscfg_reset_channel *channels; +}; + +#define to_syscfg_reset_controller(_rst) \ + container_of(_rst, struct syscfg_reset_controller, rst) + +static int syscfg_reset_program_hw(struct reset_controller_dev *rcdev, + unsigned long idx, int assert) +{ + struct syscfg_reset_controller *rst = to_syscfg_reset_controller(rcdev); + const struct syscfg_reset_channel *ch; + u32 ctrl_val = rst->active_low ? !assert : !!assert; + int err; + + if (idx >= rcdev->nr_resets) + return -EINVAL; + + ch = &rst->channels[idx]; + + err = regmap_field_write(ch->reset, ctrl_val); + if (err) + return err; + + if (ch->ack) { + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + u32 ack_val; + + while (true) { + err = regmap_field_read(ch->ack, &ack_val); + if (err) + return err; + + if (ack_val == ctrl_val) + break; + + if (time_after(jiffies, timeout)) + return -ETIME; + + cpu_relax(); + } + } + + return 0; +} + +static int syscfg_reset_assert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + return syscfg_reset_program_hw(rcdev, idx, true); +} + +static int syscfg_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + return syscfg_reset_program_hw(rcdev, idx, false); +} + +static int syscfg_reset_dev(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + int err = syscfg_reset_assert(rcdev, idx); + if (err) + return err; + + return syscfg_reset_deassert(rcdev, idx); +} + +static struct reset_control_ops syscfg_reset_ops = { + .reset = syscfg_reset_dev, + .assert = syscfg_reset_assert, + .deassert = syscfg_reset_deassert, +}; + +static int syscfg_reset_controller_register(struct device *dev, + const struct syscfg_reset_controller_data *data) +{ + struct syscfg_reset_controller *rc; + size_t size; + int i, err; + + rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL); + if (!rc) + return -ENOMEM; + + size = sizeof(struct syscfg_reset_channel) * data->nr_channels; + + rc->channels = devm_kzalloc(dev, size, GFP_KERNEL); + if (!rc->channels) + return -ENOMEM; + + rc->rst.ops = &syscfg_reset_ops, + rc->rst.of_node = dev->of_node; + rc->rst.nr_resets = data->nr_channels; + rc->active_low = data->active_low; + + for (i = 0; i < data->nr_channels; i++) { + struct regmap *map; + struct regmap_field *f; + const char *compatible = data->channels[i].compatible; + + map = syscon_regmap_lookup_by_compatible(compatible); + if (IS_ERR(map)) + return PTR_ERR(map); + + f = devm_regmap_field_alloc(dev, map, data->channels[i].reset); + if (IS_ERR(f)) + return PTR_ERR(f); + + rc->channels[i].reset = f; + + if (!data->wait_for_ack) + continue; + + f = devm_regmap_field_alloc(dev, map, data->channels[i].ack); + if (IS_ERR(f)) + return PTR_ERR(f); + + rc->channels[i].ack = f; + } + + err = reset_controller_register(&rc->rst); + if (!err) + dev_info(dev, "registered\n"); + + return err; +} + +int syscfg_reset_probe(struct platform_device *pdev) +{ + struct device *dev = pdev ? &pdev->dev : NULL; + const struct of_device_id *match; + + if (!dev || !dev->driver) + return -ENODEV; + + match = of_match_device(dev->driver->of_match_table, dev); + if (!match || !match->data) + return -EINVAL; + + return syscfg_reset_controller_register(dev, match->data); +} diff --git a/drivers/reset/sti/reset-syscfg.h b/drivers/reset/sti/reset-syscfg.h new file mode 100644 index 000000000000..2cc2283bac40 --- /dev/null +++ b/drivers/reset/sti/reset-syscfg.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2013 STMicroelectronics (R&D) Limited + * Author: Stephen Gallimore <stephen.gallimore@st.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. + */ +#ifndef __STI_RESET_SYSCFG_H +#define __STI_RESET_SYSCFG_H + +#include <linux/device.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> + +/** + * Reset channel description for a system configuration register based + * reset controller. + * + * @compatible: Compatible string of the syscon regmap containing this + * channel's control and ack (status) bits. + * @reset: Regmap field description of the channel's reset bit. + * @ack: Regmap field description of the channel's acknowledge bit. + */ +struct syscfg_reset_channel_data { + const char *compatible; + struct reg_field reset; + struct reg_field ack; +}; + +#define _SYSCFG_RST_CH(_c, _rr, _rb, _ar, _ab) \ + { .compatible = _c, \ + .reset = REG_FIELD(_rr, _rb, _rb), \ + .ack = REG_FIELD(_ar, _ab, _ab), } + +#define _SYSCFG_RST_CH_NO_ACK(_c, _rr, _rb) \ + { .compatible = _c, \ + .reset = REG_FIELD(_rr, _rb, _rb), } + +/** + * Description of a system configuration register based reset controller. + * + * @wait_for_ack: The controller will wait for reset assert and de-assert to + * be "ack'd" in a channel's ack field. + * @active_low: Are the resets in this controller active low, i.e. clearing + * the reset bit puts the hardware into reset. + * @nr_channels: The number of reset channels in this controller. + * @channels: An array of reset channel descriptions. + */ +struct syscfg_reset_controller_data { + bool wait_for_ack; + bool active_low; + int nr_channels; + const struct syscfg_reset_channel_data *channels; +}; + +/** + * syscfg_reset_probe(): platform device probe function used by syscfg + * reset controller drivers. This registers a reset + * controller configured by the OF match data for + * the compatible device which should be of type + * "struct syscfg_reset_controller_data". + * + * @pdev: platform device + */ +int syscfg_reset_probe(struct platform_device *pdev); + +#endif /* __STI_RESET_SYSCFG_H */ diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index 7854a656628f..835b425549bd 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -275,10 +275,7 @@ static int isl12057_probe(struct i2c_client *client, dev_set_drvdata(dev, data); rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - return 0; + return PTR_ERR_OR_ZERO(rtc); } #ifdef CONFIG_OF diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index d536c5962c99..d15a999363fc 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -222,6 +222,7 @@ static int __init mv_rtc_probe(struct platform_device *pdev) struct resource *res; struct rtc_plat_data *pdata; u32 rtc_time; + u32 rtc_date; int ret = 0; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); @@ -257,6 +258,17 @@ static int __init mv_rtc_probe(struct platform_device *pdev) } } + /* + * A date after January 19th, 2038 does not fit on 32 bits and + * will confuse the kernel and userspace. Reset to a sane date + * (January 1st, 2013) if we're after 2038. + */ + rtc_date = readl(pdata->ioaddr + RTC_DATE_REG_OFFS); + if (bcd2bin((rtc_date >> RTC_YEAR_OFFS) & 0xff) >= 38) { + dev_info(&pdev->dev, "invalid RTC date, resetting to January 1st, 2013\n"); + writel(0x130101, pdata->ioaddr + RTC_DATE_REG_OFFS); + } + pdata->irq = platform_get_irq(pdev, 0); platform_set_drvdata(pdev, pdata); diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c index 1ebe67cd1833..7442bc130055 100644 --- a/drivers/sh/clk/cpg.c +++ b/drivers/sh/clk/cpg.c @@ -36,9 +36,47 @@ static void sh_clk_write(int value, struct clk *clk) iowrite32(value, clk->mapped_reg); } +static unsigned int r8(const void __iomem *addr) +{ + return ioread8(addr); +} + +static unsigned int r16(const void __iomem *addr) +{ + return ioread16(addr); +} + +static unsigned int r32(const void __iomem *addr) +{ + return ioread32(addr); +} + static int sh_clk_mstp_enable(struct clk *clk) { sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk); + if (clk->status_reg) { + unsigned int (*read)(const void __iomem *addr); + int i; + void __iomem *mapped_status = (phys_addr_t)clk->status_reg - + (phys_addr_t)clk->enable_reg + clk->mapped_reg; + + if (clk->flags & CLK_ENABLE_REG_8BIT) + read = r8; + else if (clk->flags & CLK_ENABLE_REG_16BIT) + read = r16; + else + read = r32; + + for (i = 1000; + (read(mapped_status) & (1 << clk->enable_bit)) && i; + i--) + cpu_relax(); + if (!i) { + pr_err("cpg: failed to enable %p[%d]\n", + clk->enable_reg, clk->enable_bit); + return -ETIMEDOUT; + } + } return 0; } diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 35c066489a19..1bc9cbc4f1b8 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -142,7 +142,7 @@ config RCAR_THERMAL config KIRKWOOD_THERMAL tristate "Temperature sensor on Marvell Kirkwood SoCs" - depends on ARCH_KIRKWOOD + depends on ARCH_KIRKWOOD || MACH_KIRKWOOD depends on OF help Support for the Kirkwood thermal sensor driver into the Linux thermal diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a3815eaed421..ce9b12d38786 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1024,7 +1024,7 @@ config SERIAL_SGI_IOC3 config SERIAL_MSM bool "MSM on-chip serial port support" - depends on ARCH_MSM + depends on ARCH_MSM || ARCH_QCOM select SERIAL_CORE config SERIAL_MSM_CONSOLE diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 79d25894343a..f1ff408c4b17 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -292,7 +292,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE + depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU select WATCHDOG_CORE help Say Y here if to include support for the watchdog timer diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index f7722a424676..6f9b4c6e9bca 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -19,101 +19,204 @@ #include <linux/platform_device.h> #include <linux/watchdog.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> -#include <linux/spinlock.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/of.h> -#include <mach/bridge-regs.h> +#include <linux/of_device.h> + +/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */ +#define ORION_RSTOUT_MASK_OFFSET 0x20108 + +/* Internal registers can be configured at any 1 MiB aligned address */ +#define INTERNAL_REGS_MASK ~(SZ_1M - 1) /* * Watchdog timer block registers. */ #define TIMER_CTRL 0x0000 -#define WDT_EN 0x0010 -#define WDT_VAL 0x0024 +#define TIMER_A370_STATUS 0x04 #define WDT_MAX_CYCLE_COUNT 0xffffffff -#define WDT_IN_USE 0 -#define WDT_OK_TO_CLOSE 1 -#define WDT_RESET_OUT_EN BIT(1) -#define WDT_INT_REQ BIT(3) +#define WDT_A370_RATIO_MASK(v) ((v) << 16) +#define WDT_A370_RATIO_SHIFT 5 +#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT) + +#define WDT_AXP_FIXED_ENABLE_BIT BIT(10) +#define WDT_A370_EXPIRED BIT(31) static bool nowayout = WATCHDOG_NOWAYOUT; static int heartbeat = -1; /* module parameter (seconds) */ -static unsigned int wdt_max_duration; /* (seconds) */ -static struct clk *clk; -static unsigned int wdt_tclk; -static void __iomem *wdt_reg; -static DEFINE_SPINLOCK(wdt_lock); -static int orion_wdt_ping(struct watchdog_device *wdt_dev) +struct orion_watchdog; + +struct orion_watchdog_data { + int wdt_counter_offset; + int wdt_enable_bit; + int rstout_enable_bit; + int (*clock_init)(struct platform_device *, + struct orion_watchdog *); + int (*start)(struct watchdog_device *); +}; + +struct orion_watchdog { + struct watchdog_device wdt; + void __iomem *reg; + void __iomem *rstout; + unsigned long clk_rate; + struct clk *clk; + const struct orion_watchdog_data *data; +}; + +static int orion_wdt_clock_init(struct platform_device *pdev, + struct orion_watchdog *dev) { - spin_lock(&wdt_lock); + int ret; - /* Reload watchdog duration */ - writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL); + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + ret = clk_prepare_enable(dev->clk); + if (ret) { + clk_put(dev->clk); + return ret; + } - spin_unlock(&wdt_lock); + dev->clk_rate = clk_get_rate(dev->clk); return 0; } -static int orion_wdt_start(struct watchdog_device *wdt_dev) +static int armada370_wdt_clock_init(struct platform_device *pdev, + struct orion_watchdog *dev) { - u32 reg; + int ret; - spin_lock(&wdt_lock); + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + ret = clk_prepare_enable(dev->clk); + if (ret) { + clk_put(dev->clk); + return ret; + } + + /* Setup watchdog input clock */ + atomic_io_modify(dev->reg + TIMER_CTRL, + WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT), + WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT)); + + dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO; + return 0; +} + +static int armadaxp_wdt_clock_init(struct platform_device *pdev, + struct orion_watchdog *dev) +{ + int ret; + + dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed"); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + ret = clk_prepare_enable(dev->clk); + if (ret) { + clk_put(dev->clk); + return ret; + } + + /* Enable the fixed watchdog clock input */ + atomic_io_modify(dev->reg + TIMER_CTRL, + WDT_AXP_FIXED_ENABLE_BIT, + WDT_AXP_FIXED_ENABLE_BIT); + + dev->clk_rate = clk_get_rate(dev->clk); + return 0; +} + +static int orion_wdt_ping(struct watchdog_device *wdt_dev) +{ + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); + /* Reload watchdog duration */ + writel(dev->clk_rate * wdt_dev->timeout, + dev->reg + dev->data->wdt_counter_offset); + return 0; +} + +static int armada370_start(struct watchdog_device *wdt_dev) +{ + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); /* Set watchdog duration */ - writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL); + writel(dev->clk_rate * wdt_dev->timeout, + dev->reg + dev->data->wdt_counter_offset); - /* Clear watchdog timer interrupt */ - writel(~WDT_INT_REQ, BRIDGE_CAUSE); + /* Clear the watchdog expiration bit */ + atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0); /* Enable watchdog timer */ - reg = readl(wdt_reg + TIMER_CTRL); - reg |= WDT_EN; - writel(reg, wdt_reg + TIMER_CTRL); + atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, + dev->data->wdt_enable_bit); + + atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, + dev->data->rstout_enable_bit); + return 0; +} + +static int orion_start(struct watchdog_device *wdt_dev) +{ + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); + + /* Set watchdog duration */ + writel(dev->clk_rate * wdt_dev->timeout, + dev->reg + dev->data->wdt_counter_offset); + + /* Enable watchdog timer */ + atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, + dev->data->wdt_enable_bit); /* Enable reset on watchdog */ - reg = readl(RSTOUTn_MASK); - reg |= WDT_RESET_OUT_EN; - writel(reg, RSTOUTn_MASK); + atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, + dev->data->rstout_enable_bit); - spin_unlock(&wdt_lock); return 0; } -static int orion_wdt_stop(struct watchdog_device *wdt_dev) +static int orion_wdt_start(struct watchdog_device *wdt_dev) { - u32 reg; + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); - spin_lock(&wdt_lock); + /* There are some per-SoC quirks to handle */ + return dev->data->start(wdt_dev); +} + +static int orion_wdt_stop(struct watchdog_device *wdt_dev) +{ + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); /* Disable reset on watchdog */ - reg = readl(RSTOUTn_MASK); - reg &= ~WDT_RESET_OUT_EN; - writel(reg, RSTOUTn_MASK); + atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, 0); /* Disable watchdog timer */ - reg = readl(wdt_reg + TIMER_CTRL); - reg &= ~WDT_EN; - writel(reg, wdt_reg + TIMER_CTRL); + atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0); - spin_unlock(&wdt_lock); return 0; } -static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev) +static int orion_wdt_enabled(struct orion_watchdog *dev) { - unsigned int time_left; + bool enabled, running; + + enabled = readl(dev->rstout) & dev->data->rstout_enable_bit; + running = readl(dev->reg + TIMER_CTRL) & dev->data->wdt_enable_bit; - spin_lock(&wdt_lock); - time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk; - spin_unlock(&wdt_lock); + return enabled && running; +} - return time_left; +static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev) +{ + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); + return readl(dev->reg + dev->data->wdt_counter_offset) / dev->clk_rate; } static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev, @@ -137,68 +240,188 @@ static const struct watchdog_ops orion_wdt_ops = { .get_timeleft = orion_wdt_get_timeleft, }; -static struct watchdog_device orion_wdt = { - .info = &orion_wdt_info, - .ops = &orion_wdt_ops, - .min_timeout = 1, +static irqreturn_t orion_wdt_irq(int irq, void *devid) +{ + panic("Watchdog Timeout"); + return IRQ_HANDLED; +} + +/* + * The original devicetree binding for this driver specified only + * one memory resource, so in order to keep DT backwards compatibility + * we try to fallback to a hardcoded register address, if the resource + * is missing from the devicetree. + */ +static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev, + phys_addr_t internal_regs) +{ + struct resource *res; + phys_addr_t rstout; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) + return devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + + /* This workaround works only for "orion-wdt", DT-enabled */ + if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt")) + return NULL; + + rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET; + + WARN(1, FW_BUG "falling back to harcoded RSTOUT reg %pa\n", &rstout); + return devm_ioremap(&pdev->dev, rstout, 0x4); +} + +static const struct orion_watchdog_data orion_data = { + .rstout_enable_bit = BIT(1), + .wdt_enable_bit = BIT(4), + .wdt_counter_offset = 0x24, + .clock_init = orion_wdt_clock_init, + .start = orion_start, +}; + +static const struct orion_watchdog_data armada370_data = { + .rstout_enable_bit = BIT(8), + .wdt_enable_bit = BIT(8), + .wdt_counter_offset = 0x34, + .clock_init = armada370_wdt_clock_init, + .start = armada370_start, }; +static const struct orion_watchdog_data armadaxp_data = { + .rstout_enable_bit = BIT(8), + .wdt_enable_bit = BIT(8), + .wdt_counter_offset = 0x34, + .clock_init = armadaxp_wdt_clock_init, + .start = armada370_start, +}; + +static const struct of_device_id orion_wdt_of_match_table[] = { + { + .compatible = "marvell,orion-wdt", + .data = &orion_data, + }, + { + .compatible = "marvell,armada-370-wdt", + .data = &armada370_data, + }, + { + .compatible = "marvell,armada-xp-wdt", + .data = &armadaxp_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); + static int orion_wdt_probe(struct platform_device *pdev) { + struct orion_watchdog *dev; + const struct of_device_id *match; + unsigned int wdt_max_duration; /* (seconds) */ struct resource *res; - int ret; + int ret, irq; - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "Orion Watchdog missing clock\n"); - return -ENODEV; - } - clk_prepare_enable(clk); - wdt_tclk = clk_get_rate(clk); + dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog), + GFP_KERNEL); + if (!dev) + return -ENOMEM; + + match = of_match_device(orion_wdt_of_match_table, &pdev->dev); + if (!match) + /* Default legacy match */ + match = &orion_wdt_of_match_table[0]; + + dev->wdt.info = &orion_wdt_info; + dev->wdt.ops = &orion_wdt_ops; + dev->wdt.min_timeout = 1; + dev->data = match->data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; - wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!wdt_reg) - return -ENOMEM; - wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; + dev->reg = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!dev->reg) + return -ENOMEM; - orion_wdt.timeout = wdt_max_duration; - orion_wdt.max_timeout = wdt_max_duration; - watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev); + dev->rstout = orion_wdt_ioremap_rstout(pdev, res->start & + INTERNAL_REGS_MASK); + if (!dev->rstout) + return -ENODEV; - watchdog_set_nowayout(&orion_wdt, nowayout); - ret = watchdog_register_device(&orion_wdt); + ret = dev->data->clock_init(pdev, dev); if (ret) { - clk_disable_unprepare(clk); + dev_err(&pdev->dev, "cannot initialize clock\n"); return ret; } + wdt_max_duration = WDT_MAX_CYCLE_COUNT / dev->clk_rate; + + dev->wdt.timeout = wdt_max_duration; + dev->wdt.max_timeout = wdt_max_duration; + watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev); + + platform_set_drvdata(pdev, &dev->wdt); + watchdog_set_drvdata(&dev->wdt, dev); + + /* + * Let's make sure the watchdog is fully stopped, unless it's + * explicitly enabled. This may be the case if the module was + * removed and re-insterted, or if the bootloader explicitly + * set a running watchdog before booting the kernel. + */ + if (!orion_wdt_enabled(dev)) + orion_wdt_stop(&dev->wdt); + + /* Request the IRQ only after the watchdog is disabled */ + irq = platform_get_irq(pdev, 0); + if (irq > 0) { + /* + * Not all supported platforms specify an interrupt for the + * watchdog, so let's make it optional. + */ + ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0, + pdev->name, dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto disable_clk; + } + } + + watchdog_set_nowayout(&dev->wdt, nowayout); + ret = watchdog_register_device(&dev->wdt); + if (ret) + goto disable_clk; + pr_info("Initial timeout %d sec%s\n", - orion_wdt.timeout, nowayout ? ", nowayout" : ""); + dev->wdt.timeout, nowayout ? ", nowayout" : ""); return 0; + +disable_clk: + clk_disable_unprepare(dev->clk); + clk_put(dev->clk); + return ret; } static int orion_wdt_remove(struct platform_device *pdev) { - watchdog_unregister_device(&orion_wdt); - clk_disable_unprepare(clk); + struct watchdog_device *wdt_dev = platform_get_drvdata(pdev); + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); + + watchdog_unregister_device(wdt_dev); + clk_disable_unprepare(dev->clk); + clk_put(dev->clk); return 0; } static void orion_wdt_shutdown(struct platform_device *pdev) { - orion_wdt_stop(&orion_wdt); + struct watchdog_device *wdt_dev = platform_get_drvdata(pdev); + orion_wdt_stop(wdt_dev); } -static const struct of_device_id orion_wdt_of_match_table[] = { - { .compatible = "marvell,orion-wdt", }, - {}, -}; -MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); - static struct platform_driver orion_wdt_driver = { .probe = orion_wdt_probe, .remove = orion_wdt_remove, diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c index 4c2d452c4bfc..21887d63dad5 100644 --- a/fs/ceph/acl.c +++ b/fs/ceph/acl.c @@ -54,11 +54,6 @@ static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode, return acl; } -void ceph_forget_all_cached_acls(struct inode *inode) -{ - forget_all_cached_acls(inode); -} - struct posix_acl *ceph_get_acl(struct inode *inode, int type) { int size; @@ -160,11 +155,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) goto out_dput; } - if (value) - ret = __ceph_setxattr(dentry, name, value, size, 0); - else - ret = __ceph_removexattr(dentry, name); - + ret = __ceph_setxattr(dentry, name, value, size, 0); if (ret) { if (new_mode != old_mode) { newattrs.ia_mode = old_mode; diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 6da4df84ba30..45eda6d7a40c 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -100,6 +100,14 @@ static unsigned fpos_off(loff_t p) return p & 0xffffffff; } +static int fpos_cmp(loff_t l, loff_t r) +{ + int v = ceph_frag_compare(fpos_frag(l), fpos_frag(r)); + if (v) + return v; + return (int)(fpos_off(l) - fpos_off(r)); +} + /* * When possible, we try to satisfy a readdir by peeking at the * dcache. We make this work by carefully ordering dentries on @@ -156,7 +164,7 @@ more: if (!d_unhashed(dentry) && dentry->d_inode && ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && - ctx->pos <= di->offset) + fpos_cmp(ctx->pos, di->offset) <= 0) break; dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry, dentry->d_name.len, dentry->d_name.name, di->offset, @@ -695,9 +703,8 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, ceph_mdsc_put_request(req); if (!err) - err = ceph_init_acl(dentry, dentry->d_inode, dir); - - if (err) + ceph_init_acl(dentry, dentry->d_inode, dir); + else d_drop(dentry); return err; } @@ -735,7 +742,9 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry, if (!err && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); ceph_mdsc_put_request(req); - if (err) + if (!err) + ceph_init_acl(dentry, dentry->d_inode, dir); + else d_drop(dentry); return err; } @@ -776,7 +785,9 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) err = ceph_handle_notrace_create(dir, dentry); ceph_mdsc_put_request(req); out: - if (err < 0) + if (!err) + ceph_init_acl(dentry, dentry->d_inode, dir); + else d_drop(dentry); return err; } diff --git a/fs/ceph/file.c b/fs/ceph/file.c index dfd2ce3419f8..09c7afe32e49 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -286,6 +286,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, } else { dout("atomic_open finish_open on dn %p\n", dn); if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) { + ceph_init_acl(dentry, dentry->d_inode, dir); *opened |= FILE_CREATED; } err = finish_open(file, dentry, ceph_open, opened); diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 2df963f1cf5a..10a4ccbf38da 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -144,7 +144,11 @@ enum { Opt_ino32, Opt_noino32, Opt_fscache, - Opt_nofscache + Opt_nofscache, +#ifdef CONFIG_CEPH_FS_POSIX_ACL + Opt_acl, +#endif + Opt_noacl }; static match_table_t fsopt_tokens = { @@ -172,6 +176,10 @@ static match_table_t fsopt_tokens = { {Opt_noino32, "noino32"}, {Opt_fscache, "fsc"}, {Opt_nofscache, "nofsc"}, +#ifdef CONFIG_CEPH_FS_POSIX_ACL + {Opt_acl, "acl"}, +#endif + {Opt_noacl, "noacl"}, {-1, NULL} }; @@ -271,6 +279,14 @@ static int parse_fsopt_token(char *c, void *private) case Opt_nofscache: fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE; break; +#ifdef CONFIG_CEPH_FS_POSIX_ACL + case Opt_acl: + fsopt->sb_flags |= MS_POSIXACL; + break; +#endif + case Opt_noacl: + fsopt->sb_flags &= ~MS_POSIXACL; + break; default: BUG_ON(token); } @@ -438,6 +454,13 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) else seq_puts(m, ",nofsc"); +#ifdef CONFIG_CEPH_FS_POSIX_ACL + if (fsopt->sb_flags & MS_POSIXACL) + seq_puts(m, ",acl"); + else + seq_puts(m, ",noacl"); +#endif + if (fsopt->wsize) seq_printf(m, ",wsize=%d", fsopt->wsize); if (fsopt->rsize != CEPH_RSIZE_DEFAULT) @@ -819,9 +842,6 @@ static int ceph_set_super(struct super_block *s, void *data) s->s_flags = fsc->mount_options->sb_flags; s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */ -#ifdef CONFIG_CEPH_FS_POSIX_ACL - s->s_flags |= MS_POSIXACL; -#endif s->s_xattr = ceph_xattr_handlers; s->s_fs_info = fsc; @@ -911,6 +931,10 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type, struct ceph_options *opt = NULL; dout("ceph_mount\n"); + +#ifdef CONFIG_CEPH_FS_POSIX_ACL + flags |= MS_POSIXACL; +#endif err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path); if (err < 0) { res = ERR_PTR(err); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 19793b56d0a7..d8801a95b685 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -13,6 +13,7 @@ #include <linux/wait.h> #include <linux/writeback.h> #include <linux/slab.h> +#include <linux/posix_acl.h> #include <linux/ceph/libceph.h> @@ -743,7 +744,11 @@ extern const struct xattr_handler *ceph_xattr_handlers[]; struct posix_acl *ceph_get_acl(struct inode *, int); int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type); int ceph_init_acl(struct dentry *, struct inode *, struct inode *); -void ceph_forget_all_cached_acls(struct inode *inode); + +static inline void ceph_forget_all_cached_acls(struct inode *inode) +{ + forget_all_cached_acls(inode); +} #else diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 898b6565ad3e..a55ec37378c6 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -12,6 +12,9 @@ #define XATTR_CEPH_PREFIX "ceph." #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) +static int __remove_xattr(struct ceph_inode_info *ci, + struct ceph_inode_xattr *xattr); + /* * List of handlers for synthetic system.* attributes. Other * attributes are handled directly. @@ -319,8 +322,7 @@ static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, static int __set_xattr(struct ceph_inode_info *ci, const char *name, int name_len, const char *val, int val_len, - int dirty, - int should_free_name, int should_free_val, + int flags, int update_xattr, struct ceph_inode_xattr **newxattr) { struct rb_node **p; @@ -349,12 +351,31 @@ static int __set_xattr(struct ceph_inode_info *ci, xattr = NULL; } + if (update_xattr) { + int err = 0; + if (xattr && (flags & XATTR_CREATE)) + err = -EEXIST; + else if (!xattr && (flags & XATTR_REPLACE)) + err = -ENODATA; + if (err) { + kfree(name); + kfree(val); + return err; + } + if (update_xattr < 0) { + if (xattr) + __remove_xattr(ci, xattr); + kfree(name); + return 0; + } + } + if (!xattr) { new = 1; xattr = *newxattr; xattr->name = name; xattr->name_len = name_len; - xattr->should_free_name = should_free_name; + xattr->should_free_name = update_xattr; ci->i_xattrs.count++; dout("__set_xattr count=%d\n", ci->i_xattrs.count); @@ -364,7 +385,7 @@ static int __set_xattr(struct ceph_inode_info *ci, if (xattr->should_free_val) kfree((void *)xattr->val); - if (should_free_name) { + if (update_xattr) { kfree((void *)name); name = xattr->name; } @@ -379,8 +400,8 @@ static int __set_xattr(struct ceph_inode_info *ci, xattr->val = ""; xattr->val_len = val_len; - xattr->dirty = dirty; - xattr->should_free_val = (val && should_free_val); + xattr->dirty = update_xattr; + xattr->should_free_val = (val && update_xattr); if (new) { rb_link_node(&xattr->node, parent, p); @@ -442,7 +463,7 @@ static int __remove_xattr(struct ceph_inode_info *ci, struct ceph_inode_xattr *xattr) { if (!xattr) - return -EOPNOTSUPP; + return -ENODATA; rb_erase(&xattr->node, &ci->i_xattrs.index); @@ -588,7 +609,7 @@ start: p += len; err = __set_xattr(ci, name, namelen, val, len, - 0, 0, 0, &xattrs[numattr]); + 0, 0, &xattrs[numattr]); if (err < 0) goto bad; @@ -850,6 +871,9 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, dout("setxattr value=%.*s\n", (int)size, value); + if (!value) + flags |= CEPH_XATTR_REMOVE; + /* do request */ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR, USE_AUTH_MDS); @@ -892,7 +916,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, struct ceph_inode_info *ci = ceph_inode(inode); int issued; int err; - int dirty; + int dirty = 0; int name_len = strlen(name); int val_len = size; char *newname = NULL; @@ -953,12 +977,14 @@ retry: goto retry; } - err = __set_xattr(ci, newname, name_len, newval, - val_len, 1, 1, 1, &xattr); + err = __set_xattr(ci, newname, name_len, newval, val_len, + flags, value ? 1 : -1, &xattr); - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); - ci->i_xattrs.dirty = true; - inode->i_ctime = CURRENT_TIME; + if (!err) { + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); + ci->i_xattrs.dirty = true; + inode->i_ctime = CURRENT_TIME; + } spin_unlock(&ci->i_ceph_lock); if (dirty) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c819b0bd491a..7ff866dbb89e 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -865,8 +865,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, return rc; } -static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, - __u16 fid, u32 *pacllen) +struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, + const struct cifs_fid *cifsfid, u32 *pacllen) { struct cifs_ntsd *pntsd = NULL; unsigned int xid; @@ -877,7 +877,8 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, return ERR_CAST(tlink); xid = get_xid(); - rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); + rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd, + pacllen); free_xid(xid); cifs_put_tlink(tlink); @@ -946,7 +947,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); - pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen); + pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen); cifsFileInfo_put(open_file); return pntsd; } @@ -1006,19 +1007,31 @@ out: /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, - struct inode *inode, const char *path, const __u16 *pfid) + struct inode *inode, const char *path, + const struct cifs_fid *pfid) { struct cifs_ntsd *pntsd = NULL; u32 acllen = 0; int rc = 0; + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + struct cifs_tcon *tcon; cifs_dbg(NOISY, "converting ACL to mode for %s\n", path); - if (pfid) - pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen); - else - pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + if (pfid && (tcon->ses->server->ops->get_acl_by_fid)) + pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid, + &acllen); + else if (tcon->ses->server->ops->get_acl) + pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path, + &acllen); + else { + cifs_put_tlink(tlink); + return -EOPNOTSUPP; + } /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ if (IS_ERR(pntsd)) { rc = PTR_ERR(pntsd); @@ -1030,6 +1043,8 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc); } + cifs_put_tlink(tlink); + return rc; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 86dc28c7aa5c..cf32f0393369 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -398,6 +398,8 @@ struct smb_version_operations { const struct nls_table *, int); struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *, const char *, u32 *); + struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *, + const struct cifs_fid *, u32 *); int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, int); }; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d00e09dfc452..acc4ee8ed075 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -151,7 +151,7 @@ extern struct inode *cifs_iget(struct super_block *sb, extern int cifs_get_inode_info(struct inode **inode, const char *full_path, FILE_ALL_INFO *data, struct super_block *sb, - int xid, const __u16 *fid); + int xid, const struct cifs_fid *fid); extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, struct super_block *sb, unsigned int xid); @@ -162,11 +162,13 @@ extern int cifs_rename_pending_delete(const char *full_path, const unsigned int xid); extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct inode *inode, - const char *path, const __u16 *pfid); + const char *path, const struct cifs_fid *pfid); extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64, kuid_t, kgid_t); extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, const char *, u32 *); +extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *, + const struct cifs_fid *, u32 *); extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, const char *, int); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d3a6796caa5a..3db0c5fd9a11 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -378,7 +378,7 @@ cifs_create_get_file_info: xid); else { rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, - xid, &fid->netfid); + xid, fid); if (newinode) { if (server->ops->set_lease_key) server->ops->set_lease_key(newinode, fid); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 755584684f6c..53c15074bb36 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -244,7 +244,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, xid); else rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, - xid, &fid->netfid); + xid, fid); out: kfree(buf); @@ -2389,7 +2389,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *poffset) { unsigned long nr_pages, i; - size_t copied, len, cur_len; + size_t bytes, copied, len, cur_len; ssize_t total_written = 0; loff_t offset; struct iov_iter it; @@ -2444,14 +2444,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, save_len = cur_len; for (i = 0; i < nr_pages; i++) { - copied = min_t(const size_t, cur_len, PAGE_SIZE); + bytes = min_t(const size_t, cur_len, PAGE_SIZE); copied = iov_iter_copy_from_user(wdata->pages[i], &it, - 0, copied); + 0, bytes); cur_len -= copied; iov_iter_advance(&it, copied); + /* + * If we didn't copy as much as we expected, then that + * may mean we trod into an unmapped area. Stop copying + * at that point. On the next pass through the big + * loop, we'll likely end up getting a zero-length + * write and bailing out of it. + */ + if (copied < bytes) + break; } cur_len = save_len - cur_len; + /* + * If we have no data to send, then that probably means that + * the copy above failed altogether. That's most likely because + * the address in the iovec was bogus. Set the rc to -EFAULT, + * free anything we allocated and bail out. + */ + if (!cur_len) { + for (i = 0; i < nr_pages; i++) + put_page(wdata->pages[i]); + kfree(wdata); + rc = -EFAULT; + break; + } + + /* + * i + 1 now represents the number of pages we actually used in + * the copy phase above. Bring nr_pages down to that, and free + * any pages that we didn't use. + */ + for ( ; nr_pages > i + 1; nr_pages--) + put_page(wdata->pages[nr_pages - 1]); + wdata->sync_mode = WB_SYNC_ALL; wdata->nr_pages = nr_pages; wdata->offset = (__u64)offset; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index be58b8fcdb3c..aadc2b68678b 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -677,7 +677,7 @@ cgfi_exit: int cifs_get_inode_info(struct inode **inode, const char *full_path, FILE_ALL_INFO *data, struct super_block *sb, int xid, - const __u16 *fid) + const struct cifs_fid *fid) { bool validinum = false; __u16 srchflgs; diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index bfd66d84831e..526fb89f9230 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -1073,6 +1073,7 @@ struct smb_version_operations smb1_operations = { #endif /* CIFS_XATTR */ #ifdef CONFIG_CIFS_ACL .get_acl = get_cifs_acl, + .get_acl_by_fid = get_cifs_acl_by_fid, .set_acl = set_cifs_acl, #endif /* CIFS_ACL */ }; diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index c38350851b08..bc0bb9c34f72 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -57,4 +57,7 @@ #define SMB2_CMACAES_SIZE (16) #define SMB3_SIGNKEY_SIZE (16) +/* Maximum buffer size value we can send with 1 credit */ +#define SMB2_MAX_BUFFER_SIZE 65536 + #endif /* _SMB2_GLOB_H */ diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 757da3e54d3d..192f51a12cf1 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -182,11 +182,8 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) /* start with specified wsize, or default */ wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; wsize = min_t(unsigned int, wsize, server->max_write); - /* - * limit write size to 2 ** 16, because we don't support multicredit - * requests now. - */ - wsize = min_t(unsigned int, wsize, 2 << 15); + /* set it to the maximum buffer size value we can send with 1 credit */ + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); return wsize; } @@ -200,11 +197,8 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) /* start with specified rsize, or default */ rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; rsize = min_t(unsigned int, rsize, server->max_read); - /* - * limit write size to 2 ** 16, because we don't support multicredit - * requests now. - */ - rsize = min_t(unsigned int, rsize, 2 << 15); + /* set it to the maximum buffer size value we can send with 1 credit */ + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); return rsize; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index a3f7a9c3cc69..860344701067 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -413,7 +413,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) /* SMB2 only has an extended negflavor */ server->negflavor = CIFS_NEGFLAVOR_EXTENDED; - server->maxBuf = le32_to_cpu(rsp->MaxTransactSize); + /* set it to the maximum buffer size value we can send with 1 credit */ + server->maxBuf = min_t(unsigned int, le32_to_cpu(rsp->MaxTransactSize), + SMB2_MAX_BUFFER_SIZE); server->max_read = le32_to_cpu(rsp->MaxReadSize); server->max_write = le32_to_cpu(rsp->MaxWriteSize); /* BB Do we need to validate the SecurityMode? */ diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ece55565b9cd..d3a534fdc5ff 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -771,6 +771,8 @@ do { \ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \ (einode)->xtime.tv_sec = \ (signed)le32_to_cpu((raw_inode)->xtime); \ + else \ + (einode)->xtime.tv_sec = 0; \ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \ ext4_decode_extra_time(&(einode)->xtime, \ raw_inode->xtime ## _extra); \ diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 10cff4736b11..74bc2d549c58 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3906,6 +3906,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, } else err = ret; map->m_flags |= EXT4_MAP_MAPPED; + map->m_pblk = newblock; if (allocated > map->m_len) allocated = map->m_len; map->m_len = allocated; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 6bea80614d77..a2a837f00407 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -140,7 +140,7 @@ static long swap_inode_boot_loader(struct super_block *sb, handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); if (IS_ERR(handle)) { err = -EINVAL; - goto swap_boot_out; + goto journal_err_out; } /* Protect extent tree against block allocations via delalloc */ @@ -198,6 +198,7 @@ static long swap_inode_boot_loader(struct super_block *sb, ext4_double_up_write_data_sem(inode, inode_bl); +journal_err_out: ext4_inode_resume_unlocked_dio(inode); ext4_inode_resume_unlocked_dio(inode_bl); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index c5adbb318a90..f3b84cd9de56 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -243,6 +243,7 @@ static int ext4_alloc_group_tables(struct super_block *sb, ext4_group_t group; ext4_group_t last_group; unsigned overhead; + __u16 uninit_mask = (flexbg_size > 1) ? ~EXT4_BG_BLOCK_UNINIT : ~0; BUG_ON(flex_gd->count == 0 || group_data == NULL); @@ -266,7 +267,7 @@ next_group: src_group++; for (; src_group <= last_group; src_group++) { overhead = ext4_group_overhead_blocks(sb, src_group); - if (overhead != 0) + if (overhead == 0) last_blk += group_data[src_group - group].blocks_count; else break; @@ -280,8 +281,7 @@ next_group: group = ext4_get_group_number(sb, start_blk - 1); group -= group_data[0].group; group_data[group].free_blocks_count--; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + flex_gd->bg_flags[group] &= uninit_mask; } /* Allocate inode bitmaps */ @@ -292,22 +292,30 @@ next_group: group = ext4_get_group_number(sb, start_blk - 1); group -= group_data[0].group; group_data[group].free_blocks_count--; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + flex_gd->bg_flags[group] &= uninit_mask; } /* Allocate inode tables */ for (; it_index < flex_gd->count; it_index++) { - if (start_blk + EXT4_SB(sb)->s_itb_per_group > last_blk) + unsigned int itb = EXT4_SB(sb)->s_itb_per_group; + ext4_fsblk_t next_group_start; + + if (start_blk + itb > last_blk) goto next_group; group_data[it_index].inode_table = start_blk; - group = ext4_get_group_number(sb, start_blk - 1); + group = ext4_get_group_number(sb, start_blk); + next_group_start = ext4_group_first_block_no(sb, group + 1); group -= group_data[0].group; - group_data[group].free_blocks_count -= - EXT4_SB(sb)->s_itb_per_group; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + if (start_blk + itb > next_group_start) { + flex_gd->bg_flags[group + 1] &= uninit_mask; + overhead = start_blk + itb - next_group_start; + group_data[group + 1].free_blocks_count -= overhead; + itb -= overhead; + } + + group_data[group].free_blocks_count -= itb; + flex_gd->bg_flags[group] &= uninit_mask; start_blk += EXT4_SB(sb)->s_itb_per_group; } @@ -401,7 +409,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle, start = ext4_group_first_block_no(sb, group); group -= flex_gd->groups[0].group; - count2 = sb->s_blocksize * 8 - (block - start); + count2 = EXT4_BLOCKS_PER_GROUP(sb) - (block - start); if (count2 > count) count2 = count; @@ -620,7 +628,7 @@ handle_ib: if (err) goto out; count = group_table_count[j]; - start = group_data[i].block_bitmap; + start = (&group_data[i].block_bitmap)[j]; block = start; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1f7784de05b6..710fed2377d4 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3695,16 +3695,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) for (i = 0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; - i = le32_to_cpu(es->s_flags); - if (i & EXT2_FLAGS_UNSIGNED_HASH) - sbi->s_hash_unsigned = 3; - else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { + if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) { + i = le32_to_cpu(es->s_flags); + if (i & EXT2_FLAGS_UNSIGNED_HASH) + sbi->s_hash_unsigned = 3; + else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { #ifdef __CHAR_UNSIGNED__ - es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); - sbi->s_hash_unsigned = 3; + if (!(sb->s_flags & MS_RDONLY)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); + sbi->s_hash_unsigned = 3; #else - es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); + if (!(sb->s_flags & MS_RDONLY)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); #endif + } } /* Handle clustersize */ diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index e1959efad64f..b5ebc2d7d80d 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c @@ -50,6 +50,8 @@ void fscache_objlist_add(struct fscache_object *obj) struct fscache_object *xobj; struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL; + ASSERT(RB_EMPTY_NODE(&obj->objlist_link)); + write_lock(&fscache_object_list_lock); while (*p) { @@ -75,6 +77,9 @@ void fscache_objlist_add(struct fscache_object *obj) */ void fscache_objlist_remove(struct fscache_object *obj) { + if (RB_EMPTY_NODE(&obj->objlist_link)) + return; + write_lock(&fscache_object_list_lock); BUG_ON(RB_EMPTY_ROOT(&fscache_object_list)); diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 53d35c504240..d3b4539f1651 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -314,6 +314,9 @@ void fscache_object_init(struct fscache_object *object, object->cache = cache; object->cookie = cookie; object->parent = NULL; +#ifdef CONFIG_FSCACHE_OBJECT_LIST + RB_CLEAR_NODE(&object->objlist_link); +#endif object->oob_event_mask = 0; for (t = object->oob_table; t->events; t++) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 8360674c85bc..60bb365f54a5 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -514,11 +514,13 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type, * similarly constrained call sites */ ret = start_this_handle(journal, handle, GFP_NOFS); - if (ret < 0) + if (ret < 0) { jbd2_journal_free_reserved(handle); + return ret; + } handle->h_type = type; handle->h_line_no = line_no; - return ret; + return 0; } EXPORT_SYMBOL(jbd2_journal_start_reserved); diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index 2b7882b508db..9a3c68cf6026 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -324,23 +324,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h switch (flag) { case M_INSERT: /* insert item into L[0] */ - if (item_pos == tb->lnum[0] - 1 - && tb->lbytes != -1) { + if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) { /* part of new item falls into L[0] */ int new_item_len; int version; - ret_val = - leaf_shift_left(tb, tb->lnum[0] - 1, - -1); + ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, -1); /* Calculate item length to insert to S[0] */ - new_item_len = - ih_item_len(ih) - tb->lbytes; + new_item_len = ih_item_len(ih) - tb->lbytes; /* Calculate and check item length to insert to L[0] */ - put_ih_item_len(ih, - ih_item_len(ih) - - new_item_len); + put_ih_item_len(ih, ih_item_len(ih) - new_item_len); RFALSE(ih_item_len(ih) <= 0, "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d", @@ -349,30 +343,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* Insert new item into L[0] */ buffer_info_init_left(tb, &bi); leaf_insert_into_buf(&bi, - n + item_pos - - ret_val, ih, body, - zeros_num > - ih_item_len(ih) ? - ih_item_len(ih) : - zeros_num); + n + item_pos - ret_val, ih, body, + zeros_num > ih_item_len(ih) ? ih_item_len(ih) : zeros_num); version = ih_version(ih); /* Calculate key component, item length and body to insert into S[0] */ - set_le_ih_k_offset(ih, - le_ih_k_offset(ih) + - (tb-> - lbytes << - (is_indirect_le_ih - (ih) ? tb->tb_sb-> - s_blocksize_bits - - UNFM_P_SHIFT : - 0))); + set_le_ih_k_offset(ih, le_ih_k_offset(ih) + + (tb-> lbytes << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0))); put_ih_item_len(ih, new_item_len); if (tb->lbytes > zeros_num) { - body += - (tb->lbytes - zeros_num); + body += (tb->lbytes - zeros_num); zeros_num = 0; } else zeros_num -= tb->lbytes; @@ -383,15 +365,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h } else { /* new item in whole falls into L[0] */ /* Shift lnum[0]-1 items to L[0] */ - ret_val = - leaf_shift_left(tb, tb->lnum[0] - 1, - tb->lbytes); + ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, tb->lbytes); /* Insert new item into L[0] */ buffer_info_init_left(tb, &bi); - leaf_insert_into_buf(&bi, - n + item_pos - - ret_val, ih, body, - zeros_num); + leaf_insert_into_buf(&bi, n + item_pos - ret_val, ih, body, zeros_num); tb->insert_size[0] = 0; zeros_num = 0; } @@ -399,264 +376,117 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h case M_PASTE: /* append item in L[0] */ - if (item_pos == tb->lnum[0] - 1 - && tb->lbytes != -1) { + if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) { /* we must shift the part of the appended item */ - if (is_direntry_le_ih - (B_N_PITEM_HEAD(tbS0, item_pos))) { + if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) { RFALSE(zeros_num, "PAP-12090: invalid parameter in case of a directory"); /* directory item */ if (tb->lbytes > pos_in_item) { /* new directory entry falls into L[0] */ - struct item_head - *pasted; - int l_pos_in_item = - pos_in_item; + struct item_head *pasted; + int l_pos_in_item = pos_in_item; /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */ - ret_val = - leaf_shift_left(tb, - tb-> - lnum - [0], - tb-> - lbytes - - - 1); - if (ret_val - && !item_pos) { - pasted = - B_N_PITEM_HEAD - (tb->L[0], - B_NR_ITEMS - (tb-> - L[0]) - - 1); - l_pos_in_item += - I_ENTRY_COUNT - (pasted) - - (tb-> - lbytes - - 1); + ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes-1); + if (ret_val && !item_pos) { + pasted = B_N_PITEM_HEAD(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1); + l_pos_in_item += I_ENTRY_COUNT(pasted) - (tb->lbytes -1); } /* Append given directory entry to directory item */ buffer_info_init_left(tb, &bi); - leaf_paste_in_buffer - (&bi, - n + item_pos - - ret_val, - l_pos_in_item, - tb->insert_size[0], - body, zeros_num); + leaf_paste_in_buffer(&bi, n + item_pos - ret_val, l_pos_in_item, tb->insert_size[0], body, zeros_num); /* previous string prepared space for pasting new entry, following string pastes this entry */ /* when we have merge directory item, pos_in_item has been changed too */ /* paste new directory entry. 1 is entry number */ - leaf_paste_entries(&bi, - n + - item_pos - - - ret_val, - l_pos_in_item, - 1, - (struct - reiserfs_de_head - *) - body, - body - + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, n + item_pos - ret_val, l_pos_in_item, + 1, (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); tb->insert_size[0] = 0; } else { /* new directory item doesn't fall into L[0] */ /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */ - leaf_shift_left(tb, - tb-> - lnum[0], - tb-> - lbytes); + leaf_shift_left(tb, tb->lnum[0], tb->lbytes); } /* Calculate new position to append in item body */ pos_in_item -= tb->lbytes; } else { /* regular object */ - RFALSE(tb->lbytes <= 0, - "PAP-12095: there is nothing to shift to L[0]. lbytes=%d", - tb->lbytes); - RFALSE(pos_in_item != - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)), + RFALSE(tb->lbytes <= 0, "PAP-12095: there is nothing to shift to L[0]. lbytes=%d", tb->lbytes); + RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)), "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d", - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)), - pos_in_item); + ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),pos_in_item); if (tb->lbytes >= pos_in_item) { /* appended item will be in L[0] in whole */ int l_n; /* this bytes number must be appended to the last item of L[h] */ - l_n = - tb->lbytes - - pos_in_item; + l_n = tb->lbytes - pos_in_item; /* Calculate new insert_size[0] */ - tb->insert_size[0] -= - l_n; + tb->insert_size[0] -= l_n; - RFALSE(tb-> - insert_size[0] <= - 0, + RFALSE(tb->insert_size[0] <= 0, "PAP-12105: there is nothing to paste into L[0]. insert_size=%d", - tb-> - insert_size[0]); - ret_val = - leaf_shift_left(tb, - tb-> - lnum - [0], - ih_item_len - (B_N_PITEM_HEAD - (tbS0, - item_pos))); + tb->insert_size[0]); + ret_val = leaf_shift_left(tb, tb->lnum[0], ih_item_len + (B_N_PITEM_HEAD(tbS0, item_pos))); /* Append to body of item in L[0] */ buffer_info_init_left(tb, &bi); leaf_paste_in_buffer - (&bi, - n + item_pos - - ret_val, - ih_item_len - (B_N_PITEM_HEAD - (tb->L[0], - n + item_pos - - ret_val)), l_n, - body, - zeros_num > - l_n ? l_n : - zeros_num); + (&bi, n + item_pos - ret_val, ih_item_len + (B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val)), + l_n, body, + zeros_num > l_n ? l_n : zeros_num); /* 0-th item in S0 can be only of DIRECT type when l_n != 0 */ { int version; - int temp_l = - l_n; - - RFALSE - (ih_item_len - (B_N_PITEM_HEAD - (tbS0, - 0)), + int temp_l = l_n; + + RFALSE(ih_item_len(B_N_PITEM_HEAD(tbS0, 0)), "PAP-12106: item length must be 0"); - RFALSE - (comp_short_le_keys - (B_N_PKEY - (tbS0, 0), - B_N_PKEY - (tb->L[0], - n + - item_pos - - - ret_val)), + RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY + (tb->L[0], n + item_pos - ret_val)), "PAP-12107: items must be of the same file"); if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val))) { - temp_l = - l_n - << - (tb-> - tb_sb-> - s_blocksize_bits - - - UNFM_P_SHIFT); + temp_l = l_n << (tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT); } /* update key of first item in S0 */ - version = - ih_version - (B_N_PITEM_HEAD - (tbS0, 0)); - set_le_key_k_offset - (version, - B_N_PKEY - (tbS0, 0), - le_key_k_offset - (version, - B_N_PKEY - (tbS0, - 0)) + - temp_l); + version = ih_version(B_N_PITEM_HEAD(tbS0, 0)); + set_le_key_k_offset(version, B_N_PKEY(tbS0, 0), + le_key_k_offset(version,B_N_PKEY(tbS0, 0)) + temp_l); /* update left delimiting key */ - set_le_key_k_offset - (version, - B_N_PDELIM_KEY - (tb-> - CFL[0], - tb-> - lkey[0]), - le_key_k_offset - (version, - B_N_PDELIM_KEY - (tb-> - CFL[0], - tb-> - lkey[0])) - + temp_l); + set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), + le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0])) + temp_l); } /* Calculate new body, position in item and insert_size[0] */ if (l_n > zeros_num) { - body += - (l_n - - zeros_num); + body += (l_n - zeros_num); zeros_num = 0; } else - zeros_num -= - l_n; + zeros_num -= l_n; pos_in_item = 0; - RFALSE - (comp_short_le_keys - (B_N_PKEY(tbS0, 0), - B_N_PKEY(tb->L[0], - B_NR_ITEMS - (tb-> - L[0]) - - 1)) - || - !op_is_left_mergeable - (B_N_PKEY(tbS0, 0), - tbS0->b_size) - || - !op_is_left_mergeable - (B_N_PDELIM_KEY - (tb->CFL[0], - tb->lkey[0]), - tbS0->b_size), + RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1)) + || !op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size) + || !op_is_left_mergeable(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), tbS0->b_size), "PAP-12120: item must be merge-able with left neighboring item"); } else { /* only part of the appended item will be in L[0] */ /* Calculate position in item for append in S[0] */ - pos_in_item -= - tb->lbytes; + pos_in_item -= tb->lbytes; - RFALSE(pos_in_item <= 0, - "PAP-12125: no place for paste. pos_in_item=%d", - pos_in_item); + RFALSE(pos_in_item <= 0, "PAP-12125: no place for paste. pos_in_item=%d", pos_in_item); /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ - leaf_shift_left(tb, - tb-> - lnum[0], - tb-> - lbytes); + leaf_shift_left(tb, tb->lnum[0], tb->lbytes); } } } else { /* appended item will be in L[0] in whole */ @@ -665,52 +495,30 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if (!item_pos && op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)) { /* if we paste into first item of S[0] and it is left mergable */ /* then increment pos_in_item by the size of the last item in L[0] */ - pasted = - B_N_PITEM_HEAD(tb->L[0], - n - 1); + pasted = B_N_PITEM_HEAD(tb->L[0], n - 1); if (is_direntry_le_ih(pasted)) - pos_in_item += - ih_entry_count - (pasted); + pos_in_item += ih_entry_count(pasted); else - pos_in_item += - ih_item_len(pasted); + pos_in_item += ih_item_len(pasted); } /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ - ret_val = - leaf_shift_left(tb, tb->lnum[0], - tb->lbytes); + ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes); /* Append to body of item in L[0] */ buffer_info_init_left(tb, &bi); - leaf_paste_in_buffer(&bi, - n + item_pos - - ret_val, + leaf_paste_in_buffer(&bi, n + item_pos - ret_val, pos_in_item, tb->insert_size[0], body, zeros_num); /* if appended item is directory, paste entry */ - pasted = - B_N_PITEM_HEAD(tb->L[0], - n + item_pos - - ret_val); + pasted = B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val); if (is_direntry_le_ih(pasted)) - leaf_paste_entries(&bi, - n + - item_pos - - ret_val, - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, n + item_pos - ret_val, + pos_in_item, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, + tb->insert_size[0]); /* if appended item is indirect item, put unformatted node into un list */ if (is_indirect_le_ih(pasted)) set_ih_free_space(pasted, 0); @@ -722,13 +530,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h reiserfs_panic(tb->tb_sb, "PAP-12130", "lnum > 0: unexpected mode: " " %s(%d)", - (flag == - M_DELETE) ? "DELETE" : ((flag == - M_CUT) - ? "CUT" - : - "UNKNOWN"), - flag); + (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } } else { /* new item doesn't fall into L[0] */ @@ -748,14 +550,12 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h case M_INSERT: /* insert item */ if (n - tb->rnum[0] < item_pos) { /* new item or its part falls to R[0] */ if (item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1) { /* part of new item falls into R[0] */ - loff_t old_key_comp, old_len, - r_zeros_number; + loff_t old_key_comp, old_len, r_zeros_number; const char *r_body; int version; loff_t offset; - leaf_shift_right(tb, tb->rnum[0] - 1, - -1); + leaf_shift_right(tb, tb->rnum[0] - 1, -1); version = ih_version(ih); /* Remember key component and item length */ @@ -763,29 +563,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h old_len = ih_item_len(ih); /* Calculate key component and item length to insert into R[0] */ - offset = - le_ih_k_offset(ih) + - ((old_len - - tb-> - rbytes) << (is_indirect_le_ih(ih) - ? tb->tb_sb-> - s_blocksize_bits - - UNFM_P_SHIFT : 0)); + offset = le_ih_k_offset(ih) + ((old_len - tb->rbytes) << (is_indirect_le_ih(ih) ? tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT : 0)); set_le_ih_k_offset(ih, offset); put_ih_item_len(ih, tb->rbytes); /* Insert part of the item into R[0] */ buffer_info_init_right(tb, &bi); if ((old_len - tb->rbytes) > zeros_num) { r_zeros_number = 0; - r_body = - body + (old_len - - tb->rbytes) - - zeros_num; + r_body = body + (old_len - tb->rbytes) - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - (old_len - - tb->rbytes); + r_zeros_number = zeros_num - (old_len - tb->rbytes); zeros_num -= r_zeros_number; } @@ -798,25 +586,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* Calculate key component and item length to insert into S[0] */ set_le_ih_k_offset(ih, old_key_comp); - put_ih_item_len(ih, - old_len - tb->rbytes); + put_ih_item_len(ih, old_len - tb->rbytes); tb->insert_size[0] -= tb->rbytes; } else { /* whole new item falls into R[0] */ /* Shift rnum[0]-1 items to R[0] */ - ret_val = - leaf_shift_right(tb, - tb->rnum[0] - 1, - tb->rbytes); + ret_val = leaf_shift_right(tb, tb->rnum[0] - 1, tb->rbytes); /* Insert new item into R[0] */ buffer_info_init_right(tb, &bi); - leaf_insert_into_buf(&bi, - item_pos - n + - tb->rnum[0] - 1, - ih, body, - zeros_num); + leaf_insert_into_buf(&bi, item_pos - n + tb->rnum[0] - 1, + ih, body, zeros_num); if (item_pos - n + tb->rnum[0] - 1 == 0) { replace_key(tb, tb->CFR[0], @@ -841,200 +622,97 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h RFALSE(zeros_num, "PAP-12145: invalid parameter in case of a directory"); - entry_count = - I_ENTRY_COUNT(B_N_PITEM_HEAD - (tbS0, - item_pos)); + entry_count = I_ENTRY_COUNT(B_N_PITEM_HEAD + (tbS0, item_pos)); if (entry_count - tb->rbytes < pos_in_item) /* new directory entry falls into R[0] */ { int paste_entry_position; - RFALSE(tb->rbytes - 1 >= - entry_count - || !tb-> - insert_size[0], + RFALSE(tb->rbytes - 1 >= entry_count || !tb-> insert_size[0], "PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d", - tb->rbytes, - entry_count); + tb->rbytes, entry_count); /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */ - leaf_shift_right(tb, - tb-> - rnum - [0], - tb-> - rbytes - - 1); + leaf_shift_right(tb, tb->rnum[0], tb->rbytes - 1); /* Paste given directory entry to directory item */ - paste_entry_position = - pos_in_item - - entry_count + - tb->rbytes - 1; + paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1; buffer_info_init_right(tb, &bi); - leaf_paste_in_buffer - (&bi, 0, - paste_entry_position, - tb->insert_size[0], - body, zeros_num); + leaf_paste_in_buffer(&bi, 0, paste_entry_position, tb->insert_size[0], body, zeros_num); /* paste entry */ - leaf_paste_entries(&bi, - 0, - paste_entry_position, - 1, - (struct - reiserfs_de_head - *) - body, - body - + - DEH_SIZE, - tb-> - insert_size - [0] - ); - - if (paste_entry_position - == 0) { + leaf_paste_entries(&bi, 0, paste_entry_position, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); + + if (paste_entry_position == 0) { /* change delimiting keys */ - replace_key(tb, - tb-> - CFR - [0], - tb-> - rkey - [0], - tb-> - R - [0], - 0); + replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0],0); } tb->insert_size[0] = 0; pos_in_item++; } else { /* new directory entry doesn't fall into R[0] */ - leaf_shift_right(tb, - tb-> - rnum - [0], - tb-> - rbytes); + leaf_shift_right(tb, tb->rnum[0], tb->rbytes); } } else { /* regular object */ - int n_shift, n_rem, - r_zeros_number; + int n_shift, n_rem, r_zeros_number; const char *r_body; /* Calculate number of bytes which must be shifted from appended item */ - if ((n_shift = - tb->rbytes - - tb->insert_size[0]) < 0) + if ((n_shift = tb->rbytes - tb->insert_size[0]) < 0) n_shift = 0; - RFALSE(pos_in_item != - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)), + RFALSE(pos_in_item != ih_item_len + (B_N_PITEM_HEAD(tbS0, item_pos)), "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d", - pos_in_item, - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos))); - - leaf_shift_right(tb, - tb->rnum[0], - n_shift); + pos_in_item, ih_item_len + (B_N_PITEM_HEAD(tbS0, item_pos))); + + leaf_shift_right(tb, tb->rnum[0], n_shift); /* Calculate number of bytes which must remain in body after appending to R[0] */ - if ((n_rem = - tb->insert_size[0] - - tb->rbytes) < 0) + if ((n_rem = tb->insert_size[0] - tb->rbytes) < 0) n_rem = 0; { int version; - unsigned long temp_rem = - n_rem; - - version = - ih_version - (B_N_PITEM_HEAD - (tb->R[0], 0)); - if (is_indirect_le_key - (version, - B_N_PKEY(tb->R[0], - 0))) { - temp_rem = - n_rem << - (tb->tb_sb-> - s_blocksize_bits - - - UNFM_P_SHIFT); + unsigned long temp_rem = n_rem; + + version = ih_version(B_N_PITEM_HEAD(tb->R[0], 0)); + if (is_indirect_le_key(version, B_N_PKEY(tb->R[0], 0))) { + temp_rem = n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT); } - set_le_key_k_offset - (version, - B_N_PKEY(tb->R[0], - 0), - le_key_k_offset - (version, - B_N_PKEY(tb->R[0], - 0)) + - temp_rem); - set_le_key_k_offset - (version, - B_N_PDELIM_KEY(tb-> - CFR - [0], - tb-> - rkey - [0]), - le_key_k_offset - (version, - B_N_PDELIM_KEY - (tb->CFR[0], - tb->rkey[0])) + - temp_rem); + set_le_key_k_offset(version, B_N_PKEY(tb->R[0], 0), + le_key_k_offset(version, B_N_PKEY(tb->R[0], 0)) + temp_rem); + set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]), + le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0])) + temp_rem); } /* k_offset (B_N_PKEY(tb->R[0],0)) += n_rem; k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/ - do_balance_mark_internal_dirty - (tb, tb->CFR[0], 0); + do_balance_mark_internal_dirty(tb, tb->CFR[0], 0); /* Append part of body into R[0] */ buffer_info_init_right(tb, &bi); if (n_rem > zeros_num) { r_zeros_number = 0; - r_body = - body + n_rem - - zeros_num; + r_body = body + n_rem - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - n_rem; - zeros_num -= - r_zeros_number; + r_zeros_number = zeros_num - n_rem; + zeros_num -= r_zeros_number; } - leaf_paste_in_buffer(&bi, 0, - n_shift, - tb-> - insert_size - [0] - - n_rem, - r_body, - r_zeros_number); - - if (is_indirect_le_ih - (B_N_PITEM_HEAD - (tb->R[0], 0))) { + leaf_paste_in_buffer(&bi, 0, n_shift, + tb->insert_size[0] - n_rem, + r_body, r_zeros_number); + + if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->R[0], 0))) { #if 0 RFALSE(n_rem, "PAP-12160: paste more than one unformatted node pointer"); #endif - set_ih_free_space - (B_N_PITEM_HEAD - (tb->R[0], 0), 0); + set_ih_free_space(B_N_PITEM_HEAD(tb->R[0], 0), 0); } tb->insert_size[0] = n_rem; if (!n_rem) @@ -1044,58 +722,28 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h struct item_head *pasted; - ret_val = - leaf_shift_right(tb, tb->rnum[0], - tb->rbytes); + ret_val = leaf_shift_right(tb, tb->rnum[0], tb->rbytes); /* append item in R[0] */ if (pos_in_item >= 0) { buffer_info_init_right(tb, &bi); - leaf_paste_in_buffer(&bi, - item_pos - - n + - tb-> - rnum[0], - pos_in_item, - tb-> - insert_size - [0], body, - zeros_num); + leaf_paste_in_buffer(&bi, item_pos - n + tb->rnum[0], pos_in_item, + tb->insert_size[0], body, zeros_num); } /* paste new entry, if item is directory item */ - pasted = - B_N_PITEM_HEAD(tb->R[0], - item_pos - n + - tb->rnum[0]); - if (is_direntry_le_ih(pasted) - && pos_in_item >= 0) { - leaf_paste_entries(&bi, - item_pos - - n + - tb->rnum[0], - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] - ); + pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]); + if (is_direntry_le_ih(pasted) && pos_in_item >= 0) { + leaf_paste_entries(&bi, item_pos - n + tb->rnum[0], + pos_in_item, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); if (!pos_in_item) { - RFALSE(item_pos - n + - tb->rnum[0], + RFALSE(item_pos - n + tb->rnum[0], "PAP-12165: directory item must be first item of node when pasting is in 0th position"); /* update delimiting keys */ - replace_key(tb, - tb->CFR[0], - tb->rkey[0], - tb->R[0], - 0); + replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0); } } @@ -1111,22 +759,16 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h default: /* cases d and t */ reiserfs_panic(tb->tb_sb, "PAP-12175", "rnum > 0: unexpected mode: %s(%d)", - (flag == - M_DELETE) ? "DELETE" : ((flag == - M_CUT) ? "CUT" - : "UNKNOWN"), - flag); + (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } } /* tb->rnum[0] > 0 */ RFALSE(tb->blknum[0] > 3, - "PAP-12180: blknum can not be %d. It must be <= 3", - tb->blknum[0]); + "PAP-12180: blknum can not be %d. It must be <= 3", tb->blknum[0]); RFALSE(tb->blknum[0] < 0, - "PAP-12185: blknum can not be %d. It must be >= 0", - tb->blknum[0]); + "PAP-12185: blknum can not be %d. It must be >= 0", tb->blknum[0]); /* if while adding to a node we discover that it is possible to split it in two, and merge the left part into the left neighbor and the @@ -1177,8 +819,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if (n - snum[i] < item_pos) { /* new item or it's part falls to first new node S_new[i] */ if (item_pos == n - snum[i] + 1 && sbytes[i] != -1) { /* part of new item falls into S_new[i] */ - int old_key_comp, old_len, - r_zeros_number; + int old_key_comp, old_len, r_zeros_number; const char *r_body; int version; @@ -1192,15 +833,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h old_len = ih_item_len(ih); /* Calculate key component and item length to insert into S_new[i] */ - set_le_ih_k_offset(ih, - le_ih_k_offset(ih) + - ((old_len - - sbytes[i]) << - (is_indirect_le_ih - (ih) ? tb->tb_sb-> - s_blocksize_bits - - UNFM_P_SHIFT : - 0))); + set_le_ih_k_offset(ih, le_ih_k_offset(ih) + + ((old_len - sbytes[i]) << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0))); put_ih_item_len(ih, sbytes[i]); @@ -1209,39 +843,29 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if ((old_len - sbytes[i]) > zeros_num) { r_zeros_number = 0; - r_body = - body + (old_len - - sbytes[i]) - - zeros_num; + r_body = body + (old_len - sbytes[i]) - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - (old_len - - sbytes[i]); + r_zeros_number = zeros_num - (old_len - sbytes[i]); zeros_num -= r_zeros_number; } - leaf_insert_into_buf(&bi, 0, ih, r_body, - r_zeros_number); + leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeros_number); /* Calculate key component and item length to insert into S[i] */ set_le_ih_k_offset(ih, old_key_comp); - put_ih_item_len(ih, - old_len - sbytes[i]); + put_ih_item_len(ih, old_len - sbytes[i]); tb->insert_size[0] -= sbytes[i]; } else { /* whole new item falls into S_new[i] */ /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, - snum[i] - 1, sbytes[i], - S_new[i]); + snum[i] - 1, sbytes[i], S_new[i]); /* Insert new item into S_new[i] */ buffer_info_init_bh(tb, &bi, S_new[i]); - leaf_insert_into_buf(&bi, - item_pos - n + - snum[i] - 1, ih, - body, zeros_num); + leaf_insert_into_buf(&bi, item_pos - n + snum[i] - 1, + ih, body, zeros_num); zeros_num = tb->insert_size[0] = 0; } @@ -1268,150 +892,73 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h int entry_count; - entry_count = - ih_entry_count(aux_ih); + entry_count = ih_entry_count(aux_ih); - if (entry_count - sbytes[i] < - pos_in_item - && pos_in_item <= - entry_count) { + if (entry_count - sbytes[i] < pos_in_item && pos_in_item <= entry_count) { /* new directory entry falls into S_new[i] */ - RFALSE(!tb-> - insert_size[0], - "PAP-12215: insert_size is already 0"); - RFALSE(sbytes[i] - 1 >= - entry_count, + RFALSE(!tb->insert_size[0], "PAP-12215: insert_size is already 0"); + RFALSE(sbytes[i] - 1 >= entry_count, "PAP-12220: there are no so much entries (%d), only %d", - sbytes[i] - 1, - entry_count); + sbytes[i] - 1, entry_count); /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */ - leaf_move_items - (LEAF_FROM_S_TO_SNEW, - tb, snum[i], - sbytes[i] - 1, - S_new[i]); + leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i] - 1, S_new[i]); /* Paste given directory entry to directory item */ buffer_info_init_bh(tb, &bi, S_new[i]); - leaf_paste_in_buffer - (&bi, 0, - pos_in_item - - entry_count + - sbytes[i] - 1, - tb->insert_size[0], - body, zeros_num); + leaf_paste_in_buffer(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1, + tb->insert_size[0], body, zeros_num); /* paste new directory entry */ - leaf_paste_entries(&bi, - 0, - pos_in_item - - - entry_count - + - sbytes - [i] - - 1, 1, - (struct - reiserfs_de_head - *) - body, - body - + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); tb->insert_size[0] = 0; pos_in_item++; } else { /* new directory entry doesn't fall into S_new[i] */ - leaf_move_items - (LEAF_FROM_S_TO_SNEW, - tb, snum[i], - sbytes[i], - S_new[i]); + leaf_move_items(LEAF_FROM_S_TO_SNEW,tb, snum[i], sbytes[i], S_new[i]); } } else { /* regular object */ - int n_shift, n_rem, - r_zeros_number; + int n_shift, n_rem, r_zeros_number; const char *r_body; - RFALSE(pos_in_item != - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)) - || tb->insert_size[0] <= - 0, + RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)) || tb->insert_size[0] <= 0, "PAP-12225: item too short or insert_size <= 0"); /* Calculate number of bytes which must be shifted from appended item */ - n_shift = - sbytes[i] - - tb->insert_size[0]; + n_shift = sbytes[i] - tb->insert_size[0]; if (n_shift < 0) n_shift = 0; - leaf_move_items - (LEAF_FROM_S_TO_SNEW, tb, - snum[i], n_shift, - S_new[i]); + leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], n_shift, S_new[i]); /* Calculate number of bytes which must remain in body after append to S_new[i] */ - n_rem = - tb->insert_size[0] - - sbytes[i]; + n_rem = tb->insert_size[0] - sbytes[i]; if (n_rem < 0) n_rem = 0; /* Append part of body into S_new[0] */ buffer_info_init_bh(tb, &bi, S_new[i]); if (n_rem > zeros_num) { r_zeros_number = 0; - r_body = - body + n_rem - - zeros_num; + r_body = body + n_rem - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - n_rem; - zeros_num -= - r_zeros_number; + r_zeros_number = zeros_num - n_rem; + zeros_num -= r_zeros_number; } - leaf_paste_in_buffer(&bi, 0, - n_shift, - tb-> - insert_size - [0] - - n_rem, - r_body, - r_zeros_number); + leaf_paste_in_buffer(&bi, 0, n_shift, + tb->insert_size[0] - n_rem, + r_body, r_zeros_number); { struct item_head *tmp; - tmp = - B_N_PITEM_HEAD(S_new - [i], - 0); + tmp = B_N_PITEM_HEAD(S_new[i], 0); if (is_indirect_le_ih (tmp)) { - set_ih_free_space - (tmp, 0); - set_le_ih_k_offset - (tmp, - le_ih_k_offset - (tmp) + - (n_rem << - (tb-> - tb_sb-> - s_blocksize_bits - - - UNFM_P_SHIFT))); + set_ih_free_space(tmp, 0); + set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + (n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT))); } else { - set_le_ih_k_offset - (tmp, - le_ih_k_offset - (tmp) + - n_rem); + set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + n_rem); } } @@ -1426,8 +973,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h struct item_head *pasted; #ifdef CONFIG_REISERFS_CHECK - struct item_head *ih_check = - B_N_PITEM_HEAD(tbS0, item_pos); + struct item_head *ih_check = B_N_PITEM_HEAD(tbS0, item_pos); if (!is_direntry_le_ih(ih_check) && (pos_in_item != ih_item_len(ih_check) @@ -1439,8 +985,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h "to ih_item_len"); #endif /* CONFIG_REISERFS_CHECK */ - leaf_mi = - leaf_move_items(LEAF_FROM_S_TO_SNEW, + leaf_mi = leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]); @@ -1452,30 +997,19 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* paste into item */ buffer_info_init_bh(tb, &bi, S_new[i]); leaf_paste_in_buffer(&bi, - item_pos - n + - snum[i], + item_pos - n + snum[i], pos_in_item, tb->insert_size[0], body, zeros_num); - pasted = - B_N_PITEM_HEAD(S_new[i], - item_pos - n + - snum[i]); + pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]); if (is_direntry_le_ih(pasted)) { leaf_paste_entries(&bi, - item_pos - - n + snum[i], - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] + item_pos - n + snum[i], + pos_in_item, 1, + (struct reiserfs_de_head *)body, + body + DEH_SIZE, + tb->insert_size[0] ); } @@ -1495,11 +1029,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h default: /* cases d and t */ reiserfs_panic(tb->tb_sb, "PAP-12245", "blknum > 2: unexpected mode: %s(%d)", - (flag == - M_DELETE) ? "DELETE" : ((flag == - M_CUT) ? "CUT" - : "UNKNOWN"), - flag); + (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } memcpy(insert_key + i, B_N_PKEY(S_new[i], 0), KEY_SIZE); @@ -1524,9 +1054,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* If we insert the first key change the delimiting key */ if (item_pos == 0) { if (tb->CFL[0]) /* can be 0 in reiserfsck */ - replace_key(tb, tb->CFL[0], tb->lkey[0], - tbS0, 0); - + replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0); } break; @@ -1536,53 +1064,27 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h pasted = B_N_PITEM_HEAD(tbS0, item_pos); /* when directory, may be new entry already pasted */ if (is_direntry_le_ih(pasted)) { - if (pos_in_item >= 0 && - pos_in_item <= - ih_entry_count(pasted)) { + if (pos_in_item >= 0 && pos_in_item <= ih_entry_count(pasted)) { RFALSE(!tb->insert_size[0], "PAP-12260: insert_size is 0 already"); /* prepare space */ buffer_info_init_tbS0(tb, &bi); - leaf_paste_in_buffer(&bi, - item_pos, - pos_in_item, - tb-> - insert_size - [0], body, + leaf_paste_in_buffer(&bi, item_pos, pos_in_item, + tb->insert_size[0], body, zeros_num); /* paste entry */ - leaf_paste_entries(&bi, - item_pos, - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, item_pos, pos_in_item, 1, + (struct reiserfs_de_head *)body, + body + DEH_SIZE, + tb->insert_size[0]); if (!item_pos && !pos_in_item) { - RFALSE(!tb->CFL[0] - || !tb->L[0], + RFALSE(!tb->CFL[0] || !tb->L[0], "PAP-12270: CFL[0]/L[0] must be specified"); - if (tb->CFL[0]) { - replace_key(tb, - tb-> - CFL - [0], - tb-> - lkey - [0], - tbS0, - 0); - - } + if (tb->CFL[0]) + replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0); } tb->insert_size[0] = 0; } @@ -1593,13 +1095,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h "PAP-12275: insert size must not be %d", tb->insert_size[0]); buffer_info_init_tbS0(tb, &bi); - leaf_paste_in_buffer(&bi, - item_pos, - pos_in_item, - tb-> - insert_size - [0], body, - zeros_num); + leaf_paste_in_buffer(&bi, item_pos, pos_in_item, + tb->insert_size[0], body, zeros_num); if (is_indirect_le_ih(pasted)) { #if 0 @@ -1611,8 +1108,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h tb-> insert_size[0]); #endif - set_ih_free_space - (pasted, 0); + set_ih_free_space(pasted, 0); } tb->insert_size[0] = 0; } @@ -1620,8 +1116,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h else { if (tb->insert_size[0]) { print_cur_tb("12285"); - reiserfs_panic(tb-> - tb_sb, + reiserfs_panic(tb->tb_sb, "PAP-12285", "insert_size " "must be 0 " diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 8e4f41d9af4d..34c7bdc06014 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -701,6 +701,18 @@ static inline pte_t pte_mknuma(pte_t pte) } #endif +#ifndef ptep_set_numa +static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + pte_t ptent = *ptep; + + ptent = pte_mknuma(ptent); + set_pte_at(mm, addr, ptep, ptent); + return; +} +#endif + #ifndef pmd_mknuma static inline pmd_t pmd_mknuma(pmd_t pmd) { @@ -708,6 +720,18 @@ static inline pmd_t pmd_mknuma(pmd_t pmd) return pmd_clear_flags(pmd, _PAGE_PRESENT); } #endif + +#ifndef pmdp_set_numa +static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp) +{ + pmd_t pmd = *pmdp; + + pmd = pmd_mknuma(pmd); + set_pmd_at(mm, addr, pmdp, pmd); + return; +} +#endif #else extern int pte_numa(pte_t pte); extern int pmd_numa(pmd_t pmd); @@ -715,6 +739,8 @@ extern pte_t pte_mknonnuma(pte_t pte); extern pmd_t pmd_mknonnuma(pmd_t pmd); extern pte_t pte_mknuma(pte_t pte); extern pmd_t pmd_mknuma(pmd_t pmd); +extern void ptep_set_numa(struct mm_struct *mm, unsigned long addr, pte_t *ptep); +extern void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp); #endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */ #else static inline int pmd_numa(pmd_t pmd) @@ -742,10 +768,23 @@ static inline pte_t pte_mknuma(pte_t pte) return pte; } +static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + return; +} + + static inline pmd_t pmd_mknuma(pmd_t pmd) { return pmd; } + +static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp) +{ + return ; +} #endif /* CONFIG_NUMA_BALANCING */ #endif /* CONFIG_MMU */ diff --git a/include/dt-bindings/clock/bcm281xx.h b/include/dt-bindings/clock/bcm281xx.h new file mode 100644 index 000000000000..e0096940886d --- /dev/null +++ b/include/dt-bindings/clock/bcm281xx.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * Copyright 2013 Linaro 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CLOCK_BCM281XX_H +#define _CLOCK_BCM281XX_H + +/* + * This file defines the values used to specify clocks provided by + * the clock control units (CCUs) on Broadcom BCM281XX family SoCs. + */ + +/* root CCU clock ids */ + +#define BCM281XX_ROOT_CCU_FRAC_1M 0 +#define BCM281XX_ROOT_CCU_CLOCK_COUNT 1 + +/* aon CCU clock ids */ + +#define BCM281XX_AON_CCU_HUB_TIMER 0 +#define BCM281XX_AON_CCU_PMU_BSC 1 +#define BCM281XX_AON_CCU_PMU_BSC_VAR 2 +#define BCM281XX_AON_CCU_CLOCK_COUNT 3 + +/* hub CCU clock ids */ + +#define BCM281XX_HUB_CCU_TMON_1M 0 +#define BCM281XX_HUB_CCU_CLOCK_COUNT 1 + +/* master CCU clock ids */ + +#define BCM281XX_MASTER_CCU_SDIO1 0 +#define BCM281XX_MASTER_CCU_SDIO2 1 +#define BCM281XX_MASTER_CCU_SDIO3 2 +#define BCM281XX_MASTER_CCU_SDIO4 3 +#define BCM281XX_MASTER_CCU_USB_IC 4 +#define BCM281XX_MASTER_CCU_HSIC2_48M 5 +#define BCM281XX_MASTER_CCU_HSIC2_12M 6 +#define BCM281XX_MASTER_CCU_CLOCK_COUNT 7 + +/* slave CCU clock ids */ + +#define BCM281XX_SLAVE_CCU_UARTB 0 +#define BCM281XX_SLAVE_CCU_UARTB2 1 +#define BCM281XX_SLAVE_CCU_UARTB3 2 +#define BCM281XX_SLAVE_CCU_UARTB4 3 +#define BCM281XX_SLAVE_CCU_SSP0 4 +#define BCM281XX_SLAVE_CCU_SSP2 5 +#define BCM281XX_SLAVE_CCU_BSC1 6 +#define BCM281XX_SLAVE_CCU_BSC2 7 +#define BCM281XX_SLAVE_CCU_BSC3 8 +#define BCM281XX_SLAVE_CCU_PWM 9 +#define BCM281XX_SLAVE_CCU_CLOCK_COUNT 10 + +#endif /* _CLOCK_BCM281XX_H */ diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h index 859e9be511d9..6548a5fbcf4a 100644 --- a/include/dt-bindings/clock/r8a7790-clock.h +++ b/include/dt-bindings/clock/r8a7790-clock.h @@ -46,8 +46,8 @@ #define R8A7790_CLK_MSIOF1 8 #define R8A7790_CLK_MSIOF3 15 #define R8A7790_CLK_SCIFB2 16 -#define R8A7790_CLK_SYS_DMAC0 18 -#define R8A7790_CLK_SYS_DMAC1 19 +#define R8A7790_CLK_SYS_DMAC1 18 +#define R8A7790_CLK_SYS_DMAC0 19 /* MSTP3 */ #define R8A7790_CLK_TPU0 4 diff --git a/include/dt-bindings/reset-controller/stih415-resets.h b/include/dt-bindings/reset-controller/stih415-resets.h new file mode 100644 index 000000000000..c2f8a66913c5 --- /dev/null +++ b/include/dt-bindings/reset-controller/stih415-resets.h @@ -0,0 +1,26 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH415 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH415 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH415 + +#define STIH415_EMISS_POWERDOWN 0 +#define STIH415_NAND_POWERDOWN 1 +#define STIH415_KEYSCAN_POWERDOWN 2 +#define STIH415_USB0_POWERDOWN 3 +#define STIH415_USB1_POWERDOWN 4 +#define STIH415_USB2_POWERDOWN 5 +#define STIH415_SATA0_POWERDOWN 6 +#define STIH415_SATA1_POWERDOWN 7 +#define STIH415_PCIE_POWERDOWN 8 + +#define STIH415_ETH0_SOFTRESET 0 +#define STIH415_ETH1_SOFTRESET 1 +#define STIH415_IRB_SOFTRESET 2 +#define STIH415_USB0_SOFTRESET 3 +#define STIH415_USB1_SOFTRESET 4 +#define STIH415_USB2_SOFTRESET 5 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH415 */ diff --git a/include/dt-bindings/reset-controller/stih416-resets.h b/include/dt-bindings/reset-controller/stih416-resets.h new file mode 100644 index 000000000000..2127743f23e3 --- /dev/null +++ b/include/dt-bindings/reset-controller/stih416-resets.h @@ -0,0 +1,50 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH416 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH416 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH416 + +#define STIH416_EMISS_POWERDOWN 0 +#define STIH416_NAND_POWERDOWN 1 +#define STIH416_KEYSCAN_POWERDOWN 2 +#define STIH416_USB0_POWERDOWN 3 +#define STIH416_USB1_POWERDOWN 4 +#define STIH416_USB2_POWERDOWN 5 +#define STIH416_USB3_POWERDOWN 6 +#define STIH416_SATA0_POWERDOWN 7 +#define STIH416_SATA1_POWERDOWN 8 +#define STIH416_PCIE0_POWERDOWN 9 +#define STIH416_PCIE1_POWERDOWN 10 + +#define STIH416_ETH0_SOFTRESET 0 +#define STIH416_ETH1_SOFTRESET 1 +#define STIH416_IRB_SOFTRESET 2 +#define STIH416_USB0_SOFTRESET 3 +#define STIH416_USB1_SOFTRESET 4 +#define STIH416_USB2_SOFTRESET 5 +#define STIH416_USB3_SOFTRESET 6 +#define STIH416_SATA0_SOFTRESET 7 +#define STIH416_SATA1_SOFTRESET 8 +#define STIH416_PCIE0_SOFTRESET 9 +#define STIH416_PCIE1_SOFTRESET 10 +#define STIH416_AUD_DAC_SOFTRESET 11 +#define STIH416_HDTVOUT_SOFTRESET 12 +#define STIH416_VTAC_M_RX_SOFTRESET 13 +#define STIH416_VTAC_A_RX_SOFTRESET 14 +#define STIH416_SYNC_HD_SOFTRESET 15 +#define STIH416_SYNC_SD_SOFTRESET 16 +#define STIH416_BLITTER_SOFTRESET 17 +#define STIH416_GPU_SOFTRESET 18 +#define STIH416_VTAC_M_TX_SOFTRESET 19 +#define STIH416_VTAC_A_TX_SOFTRESET 20 +#define STIH416_VTG_AUX_SOFTRESET 21 +#define STIH416_JPEG_DEC_SOFTRESET 22 +#define STIH416_HVA_SOFTRESET 23 +#define STIH416_COMPO_M_SOFTRESET 24 +#define STIH416_COMPO_A_SOFTRESET 25 +#define STIH416_VP8_DEC_SOFTRESET 26 +#define STIH416_VTG_MAIN_SOFTRESET 27 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH416 */ diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 2623cffc73a1..25bfb0eff772 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -373,8 +373,9 @@ extern const char *ceph_mds_op_name(int op); /* * Ceph setxattr request flags. */ -#define CEPH_XATTR_CREATE 1 -#define CEPH_XATTR_REPLACE 2 +#define CEPH_XATTR_CREATE (1 << 0) +#define CEPH_XATTR_REPLACE (1 << 1) +#define CEPH_XATTR_REMOVE (1 << 31) union ceph_mds_request_args { struct { diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index dfac5ed31120..f886985a28b2 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -171,7 +171,7 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, size_t size, int flags, const char *); #define dma_buf_export(priv, ops, size, flags) \ - dma_buf_export_named(priv, ops, size, flags, __FILE__) + dma_buf_export_named(priv, ops, size, flags, KBUILD_MODNAME) int dma_buf_fd(struct dma_buf *dmabuf, int flags); struct dma_buf *dma_buf_get(int fd); diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 0ceb389dba6c..7ed92d0560d5 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -93,6 +93,11 @@ int gic_get_cpu_id(unsigned int cpu); void gic_migrate_target(unsigned int new_cpu_id); unsigned long gic_get_sgir_physaddr(void); +extern const struct irq_domain_ops *gic_routable_irq_domain_ops; +static inline void __init register_routable_domain_ops + (const struct irq_domain_ops *ops) +{ + gic_routable_irq_domain_ops = ops; +} #endif /* __ASSEMBLY */ - #endif diff --git a/include/linux/irqchip/arm-vic.h b/include/linux/irqchip/arm-vic.h index e3c82dc95756..ba46c794b4e5 100644 --- a/include/linux/irqchip/arm-vic.h +++ b/include/linux/irqchip/arm-vic.h @@ -29,8 +29,10 @@ struct device_node; struct pt_regs; -void __vic_init(void __iomem *base, int irq_start, u32 vic_sources, - u32 resume_sources, struct device_node *node); +void __vic_init(void __iomem *base, int parent_irq, int irq_start, + u32 vic_sources, u32 resume_sources, struct device_node *node); void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); +int vic_init_cascaded(void __iomem *base, unsigned int parent_irq, + u32 vic_sources, u32 resume_sources); #endif diff --git a/include/linux/irqchip/irq-crossbar.h b/include/linux/irqchip/irq-crossbar.h new file mode 100644 index 000000000000..e5537b81df8d --- /dev/null +++ b/include/linux/irqchip/irq-crossbar.h @@ -0,0 +1,11 @@ +/* + * drivers/irqchip/irq-crossbar.h + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +int irqcrossbar_init(void); diff --git a/include/linux/platform_data/clk-integrator.h b/include/linux/platform_data/clk-integrator.h index 280edac9d0a5..addd48cac625 100644 --- a/include/linux/platform_data/clk-integrator.h +++ b/include/linux/platform_data/clk-integrator.h @@ -1,3 +1,2 @@ -void integrator_clk_init(bool is_cp); void integrator_impd1_clk_init(void __iomem *base, unsigned int id); void integrator_impd1_clk_exit(unsigned int id); diff --git a/include/linux/platform_data/mtd-davinci-aemif.h b/include/linux/platform_data/mtd-davinci-aemif.h index 05b293443097..97948ac2bb9b 100644 --- a/include/linux/platform_data/mtd-davinci-aemif.h +++ b/include/linux/platform_data/mtd-davinci-aemif.h @@ -10,6 +10,8 @@ #ifndef _MACH_DAVINCI_AEMIF_H #define _MACH_DAVINCI_AEMIF_H +#include <linux/platform_device.h> + #define NRCSR_OFFSET 0x00 #define AWCCR_OFFSET 0x04 #define A1CR_OFFSET 0x10 @@ -31,6 +33,5 @@ struct davinci_aemif_timing { u8 ta; }; -int davinci_aemif_setup_timing(struct davinci_aemif_timing *t, - void __iomem *base, unsigned cs); +int davinci_aemif_setup(struct platform_device *pdev); #endif diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h index 60c72395ec6b..1f208b2a1ed6 100644 --- a/include/linux/sh_clk.h +++ b/include/linux/sh_clk.h @@ -52,6 +52,7 @@ struct clk { unsigned long flags; void __iomem *enable_reg; + void __iomem *status_reg; unsigned int enable_bit; void __iomem *mapped_reg; @@ -116,22 +117,26 @@ long clk_round_parent(struct clk *clk, unsigned long target, unsigned long *best_freq, unsigned long *parent_freq, unsigned int div_min, unsigned int div_max); -#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _flags) \ +#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _status_reg, _flags) \ { \ .parent = _parent, \ .enable_reg = (void __iomem *)_enable_reg, \ .enable_bit = _enable_bit, \ + .status_reg = _status_reg, \ .flags = _flags, \ } -#define SH_CLK_MSTP32(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_32BIT) +#define SH_CLK_MSTP32(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_32BIT) -#define SH_CLK_MSTP16(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_16BIT) +#define SH_CLK_MSTP32_STS(_p, _r, _b, _s, _f) \ + SH_CLK_MSTP(_p, _r, _b, _s, _f | CLK_ENABLE_REG_32BIT) -#define SH_CLK_MSTP8(_p, _r, _b, _f) \ - SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_8BIT) +#define SH_CLK_MSTP16(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_16BIT) + +#define SH_CLK_MSTP8(_p, _r, _b, _f) \ + SH_CLK_MSTP(_p, _r, _b, 0, _f | CLK_ENABLE_REG_8BIT) int sh_clk_mstp_register(struct clk *clks, int nr); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index b1d255f04135..4dae9cbe9259 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1076,7 +1076,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear) next_seq = log_next_seq; len = 0; - prev = 0; while (len >= 0 && seq < next_seq) { struct printk_log *msg = log_from_idx(idx); int textlen; @@ -2788,7 +2787,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, next_idx = idx; l = 0; - prev = 0; while (seq < dumper->next_seq) { struct printk_log *msg = log_from_idx(idx); diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 82166bf974e1..da23eb96779f 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1545,6 +1545,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, entry = pmd_mknonnuma(entry); entry = pmd_modify(entry, newprot); ret = HPAGE_PMD_NR; + set_pmd_at(mm, addr, pmd, entry); BUG_ON(pmd_write(entry)); } else { struct page *page = pmd_page(*pmd); @@ -1557,16 +1558,10 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, */ if (!is_huge_zero_page(page) && !pmd_numa(*pmd)) { - entry = *pmd; - entry = pmd_mknuma(entry); + pmdp_set_numa(mm, addr, pmd); ret = HPAGE_PMD_NR; } } - - /* Set PMD if cleared earlier */ - if (ret == HPAGE_PMD_NR) - set_pmd_at(mm, addr, pmd, entry); - spin_unlock(ptl); } diff --git a/mm/mprotect.c b/mm/mprotect.c index 7332c1785744..769a67a15803 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -58,36 +58,27 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (pte_numa(ptent)) ptent = pte_mknonnuma(ptent); ptent = pte_modify(ptent, newprot); + /* + * Avoid taking write faults for pages we + * know to be dirty. + */ + if (dirty_accountable && pte_dirty(ptent)) + ptent = pte_mkwrite(ptent); + ptep_modify_prot_commit(mm, addr, pte, ptent); updated = true; } else { struct page *page; - ptent = *pte; page = vm_normal_page(vma, addr, oldpte); if (page && !PageKsm(page)) { if (!pte_numa(oldpte)) { - ptent = pte_mknuma(ptent); - set_pte_at(mm, addr, pte, ptent); + ptep_set_numa(mm, addr, pte); updated = true; } } } - - /* - * Avoid taking write faults for pages we know to be - * dirty. - */ - if (dirty_accountable && pte_dirty(ptent)) { - ptent = pte_mkwrite(ptent); - updated = true; - } - if (updated) pages++; - - /* Only !prot_numa always clears the pte */ - if (!prot_numa) - ptep_modify_prot_commit(mm, addr, pte, ptent); } else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) { swp_entry_t entry = pte_to_swp_entry(oldpte); diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index 78ed4a42ad21..106e2e22fed2 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig @@ -1,6 +1,6 @@ config SND_KIRKWOOD_SOC tristate "SoC Audio for the Marvell Kirkwood and Dove chips" - depends on ARCH_KIRKWOOD || ARCH_DOVE || COMPILE_TEST + depends on ARCH_KIRKWOOD || ARCH_DOVE || MACH_KIRKWOOD || COMPILE_TEST help Say Y or M if you want to add support for codecs attached to the Kirkwood I2S interface. You will also need to select the |