diff options
76 files changed, 1841 insertions, 460 deletions
diff --git a/Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml b/Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml new file mode 100644 index 000000000000..debfb54a8042 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/intel,ixp4xx-pci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intel IXP4xx PCI controller + +maintainers: + - Linus Walleij <linus.walleij@linaro.org> + +description: PCI host controller found in the Intel IXP4xx SoC series. + +allOf: + - $ref: /schemas/pci/pci-bus.yaml# + +properties: + compatible: + items: + - enum: + - intel,ixp42x-pci + - intel,ixp43x-pci + description: The two supported variants are ixp42x and ixp43x, + though more variants may exist. + + reg: + items: + - description: IXP4xx-specific registers + + interrupts: + items: + - description: Main PCI interrupt + - description: PCI DMA interrupt 1 + - description: PCI DMA interrupt 2 + + ranges: + maxItems: 2 + description: Typically one memory range of 64MB and one IO + space range of 64KB. + + dma-ranges: + maxItems: 1 + description: The DMA range tells the PCI host which addresses + the RAM is at. It can map only 64MB so if the RAM is bigger + than 64MB the DMA access has to be restricted to these + addresses. + + "#interrupt-cells": true + + interrupt-map: true + + interrupt-map-mask: + items: + - const: 0xf800 + - const: 0 + - const: 0 + - const: 7 + +required: + - compatible + - reg + - dma-ranges + - "#interrupt-cells" + - interrupt-map + - interrupt-map-mask + +unevaluatedProperties: false + +examples: + - | + pci@c0000000 { + compatible = "intel,ixp43x-pci"; + reg = <0xc0000000 0x1000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x00 0xff>; + + ranges = + <0x02000000 0 0x48000000 0x48000000 0 0x04000000>, + <0x01000000 0 0x00000000 0x4c000000 0 0x00010000>; + dma-ranges = + <0x02000000 0 0x00000000 0x00000000 0 0x04000000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + <0x0800 0 0 1 &gpio0 11 3>, /* INT A on slot 1 is irq 11 */ + <0x0800 0 0 2 &gpio0 10 3>, /* INT B on slot 1 is irq 10 */ + <0x0800 0 0 3 &gpio0 9 3>, /* INT C on slot 1 is irq 9 */ + <0x0800 0 0 4 &gpio0 8 3>, /* INT D on slot 1 is irq 8 */ + <0x1000 0 0 1 &gpio0 10 3>, /* INT A on slot 2 is irq 10 */ + <0x1000 0 0 2 &gpio0 9 3>, /* INT B on slot 2 is irq 9 */ + <0x1000 0 0 3 &gpio0 8 3>, /* INT C on slot 2 is irq 8 */ + <0x1000 0 0 4 &gpio0 11 3>, /* INT D on slot 2 is irq 11 */ + <0x1800 0 0 1 &gpio0 9 3>, /* INT A on slot 3 is irq 9 */ + <0x1800 0 0 2 &gpio0 8 3>, /* INT B on slot 3 is irq 8 */ + <0x1800 0 0 3 &gpio0 11 3>, /* INT C on slot 3 is irq 11 */ + <0x1800 0 0 4 &gpio0 10 3>; /* INT D on slot 3 is irq 10 */ + }; diff --git a/Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml b/Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml new file mode 100644 index 000000000000..61963fa9347e --- /dev/null +++ b/Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rng/intel,ixp46x-rng.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intel IXP46x RNG bindings + +description: | + The Intel IXP46x has a random number generator at a fixed physical + location in memory. Each read is guaranteed to provide a unique + 32 bit random number. + +maintainers: + - Linus Walleij <linus.walleij@linaro.org> + +properties: + compatible: + const: intel,ixp46x-rng + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + rng@70002100 { + compatible = "intel,ixp46x-rng"; + reg = <0x70002100 4>; + }; + diff --git a/MAINTAINERS b/MAINTAINERS index b80e6f70156b..b0a4a8bc8daa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2210,6 +2210,7 @@ M: Daniel Palmer <daniel@thingy.jp> L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained W: http://linux-chenxing.org/ +T: git git://github.com/linux-chenxing/linux.git F: Documentation/devicetree/bindings/arm/mstar/* F: Documentation/devicetree/bindings/clock/mstar,msc313-mpll.yaml F: Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml @@ -2479,9 +2480,12 @@ F: drivers/*/*/*s3c24* F: drivers/*/*s3c24* F: drivers/*/*s3c64xx* F: drivers/*/*s5pv210* +F: drivers/clocksource/samsung_pwm_timer.c F: drivers/memory/samsung/ +F: drivers/pwm/pwm-samsung.c F: drivers/soc/samsung/ F: drivers/tty/serial/samsung* +F: include/clocksource/samsung_pwm.h F: include/linux/platform_data/*s3c* F: include/linux/serial_s3c.h F: include/linux/soc/samsung/ @@ -9381,6 +9385,7 @@ F: include/linux/soc/ixp4xx/qmgr.h INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT M: Deepak Saxena <dsaxena@plexity.net> S: Maintained +F: Documentation/devicetree/bindings/display/intel,ixp46x-rng.yaml F: drivers/char/hw_random/ixp4xx-rng.c INTEL KEEM BAY DRM DRIVER @@ -13510,12 +13515,6 @@ L: linux-omap@vger.kernel.org S: Maintained F: arch/arm/mach-omap2/omap_hwmod*data* -OMAP HWMOD DATA FOR OMAP4-BASED DEVICES -M: Benoît Cousson <bcousson@baylibre.com> -L: linux-omap@vger.kernel.org -S: Maintained -F: arch/arm/mach-omap2/omap_hwmod_44xx_data.c - OMAP HWMOD SUPPORT M: Benoît Cousson <bcousson@baylibre.com> M: Paul Walmsley <paul@pwsan.com> @@ -14179,6 +14178,12 @@ S: Maintained F: Documentation/devicetree/bindings/pci/sifive,fu740-pcie.yaml F: drivers/pci/controller/dwc/pcie-fu740.c +PCI DRIVER FOR INTEL IXP4XX +M: Linus Walleij <linus.walleij@linaro.org> +S: Maintained +F: Documentation/devicetree/bindings/pci/intel,ixp4xx-pci.yaml +F: drivers/pci/controller/pci-ixp4xx.c + PCI DRIVER FOR INTEL VOLUME MANAGEMENT DEVICE (VMD) M: Jonathan Derrick <jonathan.derrick@intel.com> L: linux-pci@vger.kernel.org @@ -18126,6 +18131,7 @@ F: include/media/i2c/tw9910.h TEE SUBSYSTEM M: Jens Wiklander <jens.wiklander@linaro.org> +R: Sumit Garg <sumit.garg@linaro.org> L: op-tee@lists.trustedfirmware.org S: Maintained F: Documentation/staging/tee.rst diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 06b6187b67af..3ea1c417339f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -394,7 +394,8 @@ config ARCH_IXP4XX select HAVE_PCI select IXP4XX_IRQ select IXP4XX_TIMER - select NEED_MACH_IO_H + # With the new PCI driver this is not needed + select NEED_MACH_IO_H if PCI_IXP4XX_LEGACY select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO help diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 7902bc2096e0..1c4384db223d 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -609,6 +609,14 @@ choice when u-boot hands over to the kernel, the system silently crashes, with no serial output at all. + config DEBUG_MSTARV7_PMUART + bool "Kernel low-level debugging messages via MSTARV7 PM UART" + depends on ARCH_MSTARV7 + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for MSTAR ARMv7-based platforms on PM UART. + config DEBUG_MT6589_UART0 bool "Mediatek mt6589 UART0" depends on ARCH_MEDIATEK @@ -1607,6 +1615,7 @@ config DEBUG_UART_PHYS default 0x18000400 if DEBUG_BCM_HR2 default 0x18023000 if DEBUG_BCM_IPROC_UART3 default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1 + default 0x1f221000 if DEBUG_MSTARV7_PMUART default 0x20001000 if DEBUG_HIP01_UART default 0x20060000 if DEBUG_RK29_UART0 default 0x20064000 if DEBUG_RK29_UART1 || DEBUG_RK3X_UART2 @@ -1724,6 +1733,7 @@ config DEBUG_UART_VIRT default 0xf0100000 if DEBUG_DIGICOLOR_UA0 default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 || DEBUG_BCM2836 + default 0xf0221000 if DEBUG_MSTARV7_PMUART default 0xf1000300 if DEBUG_BCM_5301X default 0xf1000400 if DEBUG_BCM_HR2 default 0xf1002000 if DEBUG_MT8127_UART0 @@ -1805,8 +1815,8 @@ config DEBUG_UART_VIRT default 0xfedc0000 if DEBUG_EP93XX default 0xfee003f8 if DEBUG_FOOTBRIDGE_COM1 default 0xfee20000 if DEBUG_NSPIRE_CLASSIC_UART || DEBUG_NSPIRE_CX_UART - default 0xfef00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN - default 0xfef00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN + default 0xfec00000 if ARCH_IXP4XX && !CPU_BIG_ENDIAN + default 0xfec00003 if ARCH_IXP4XX && CPU_BIG_ENDIAN default 0xfef36000 if DEBUG_HIGHBANK_UART default 0xfefb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 default 0xfefb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 @@ -1829,6 +1839,7 @@ config DEBUG_UART_8250_SHIFT default 0 if DEBUG_FOOTBRIDGE_COM1 || ARCH_IOP32X || DEBUG_BCM_5301X || \ DEBUG_BCM_HR2 || DEBUG_OMAP7XXUART1 || DEBUG_OMAP7XXUART2 || \ DEBUG_OMAP7XXUART3 + default 3 if DEBUG_MSTARV7_PMUART default 2 config DEBUG_UART_8250_WORD diff --git a/arch/arm/boot/dts/am5718.dtsi b/arch/arm/boot/dts/am5718.dtsi index ebf4d3cc1cfb..6d7530a48c73 100644 --- a/arch/arm/boot/dts/am5718.dtsi +++ b/arch/arm/boot/dts/am5718.dtsi @@ -17,17 +17,13 @@ * VCP1, VCP2 * MLB * ISS - * USB3, USB4 + * USB3 */ &usb3_tm { status = "disabled"; }; -&usb4_tm { - status = "disabled"; -}; - &atl_tm { status = "disabled"; }; diff --git a/arch/arm/boot/dts/dra7-l4.dtsi b/arch/arm/boot/dts/dra7-l4.dtsi index 149144cdff35..648d23f7f748 100644 --- a/arch/arm/boot/dts/dra7-l4.dtsi +++ b/arch/arm/boot/dts/dra7-l4.dtsi @@ -4129,28 +4129,6 @@ }; }; - usb4_tm: target-module@140000 { /* 0x48940000, ap 75 3c.0 */ - compatible = "ti,sysc-omap4", "ti,sysc"; - reg = <0x140000 0x4>, - <0x140010 0x4>; - reg-names = "rev", "sysc"; - ti,sysc-mask = <SYSC_OMAP4_DMADISABLE>; - ti,sysc-midle = <SYSC_IDLE_FORCE>, - <SYSC_IDLE_NO>, - <SYSC_IDLE_SMART>, - <SYSC_IDLE_SMART_WKUP>; - ti,sysc-sidle = <SYSC_IDLE_FORCE>, - <SYSC_IDLE_NO>, - <SYSC_IDLE_SMART>, - <SYSC_IDLE_SMART_WKUP>; - /* Domains (P, C): l3init_pwrdm, l3init_clkdm */ - clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>; - clock-names = "fck"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x140000 0x20000>; - }; - target-module@170000 { /* 0x48970000, ap 21 0a.0 */ compatible = "ti,sysc-omap4", "ti,sysc"; reg = <0x170010 0x4>; diff --git a/arch/arm/boot/dts/dra71x.dtsi b/arch/arm/boot/dts/dra71x.dtsi index cad0e4a2bd8d..9c270d8f75d5 100644 --- a/arch/arm/boot/dts/dra71x.dtsi +++ b/arch/arm/boot/dts/dra71x.dtsi @@ -11,7 +11,3 @@ &rtctarget { status = "disabled"; }; - -&usb4_tm { - status = "disabled"; -}; diff --git a/arch/arm/boot/dts/dra72x.dtsi b/arch/arm/boot/dts/dra72x.dtsi index d403acc754b6..f3e934ef7d3e 100644 --- a/arch/arm/boot/dts/dra72x.dtsi +++ b/arch/arm/boot/dts/dra72x.dtsi @@ -108,7 +108,3 @@ &pcie2_rc { compatible = "ti,dra726-pcie-rc", "ti,dra7-pcie"; }; - -&usb4_tm { - status = "disabled"; -}; diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi index e1850d6c841a..b4e07d99ffde 100644 --- a/arch/arm/boot/dts/dra74x.dtsi +++ b/arch/arm/boot/dts/dra74x.dtsi @@ -49,49 +49,6 @@ reg = <0x41500000 0x100>; }; - target-module@48940000 { - compatible = "ti,sysc-omap4", "ti,sysc"; - reg = <0x48940000 0x4>, - <0x48940010 0x4>; - reg-names = "rev", "sysc"; - ti,sysc-mask = <SYSC_OMAP4_DMADISABLE>; - ti,sysc-midle = <SYSC_IDLE_FORCE>, - <SYSC_IDLE_NO>, - <SYSC_IDLE_SMART>, - <SYSC_IDLE_SMART_WKUP>; - ti,sysc-sidle = <SYSC_IDLE_FORCE>, - <SYSC_IDLE_NO>, - <SYSC_IDLE_SMART>, - <SYSC_IDLE_SMART_WKUP>; - clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>; - clock-names = "fck"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x48940000 0x20000>; - - omap_dwc3_4: omap_dwc3_4@0 { - compatible = "ti,dwc3"; - reg = <0 0x10000>; - interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>; - #address-cells = <1>; - #size-cells = <1>; - utmi-mode = <2>; - ranges; - status = "disabled"; - usb4: usb@10000 { - compatible = "snps,dwc3"; - reg = <0x10000 0x17000>; - interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "peripheral", - "host", - "otg"; - maximum-speed = "high-speed"; - dr_mode = "otg"; - }; - }; - }; target-module@41501000 { compatible = "ti,sysc-omap2", "ti,sysc"; @@ -224,3 +181,52 @@ &pcie2_rc { compatible = "ti,dra746-pcie-rc", "ti,dra7-pcie"; }; + +&l4_per3 { + segment@0 { + usb4_tm: target-module@140000 { /* 0x48940000, ap 75 3c.0 */ + compatible = "ti,sysc-omap4", "ti,sysc"; + reg = <0x140000 0x4>, + <0x140010 0x4>; + reg-names = "rev", "sysc"; + ti,sysc-mask = <SYSC_OMAP4_DMADISABLE>; + ti,sysc-midle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>, + <SYSC_IDLE_SMART_WKUP>; + ti,sysc-sidle = <SYSC_IDLE_FORCE>, + <SYSC_IDLE_NO>, + <SYSC_IDLE_SMART>, + <SYSC_IDLE_SMART_WKUP>; + /* Domains (P, C): l3init_pwrdm, l3init_clkdm */ + clocks = <&l3init_clkctrl DRA7_L3INIT_USB_OTG_SS4_CLKCTRL 0>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x140000 0x20000>; + + omap_dwc3_4: omap_dwc3_4@0 { + compatible = "ti,dwc3"; + reg = <0 0x10000>; + interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <1>; + utmi-mode = <2>; + ranges; + status = "disabled"; + usb4: usb@10000 { + compatible = "snps,dwc3"; + reg = <0x10000 0x17000>; + interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "peripheral", + "host", + "otg"; + maximum-speed = "high-speed"; + dr_mode = "otg"; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom-sdx55-t55.dts b/arch/arm/boot/dts/qcom-sdx55-t55.dts index ddcd53aa533d..2ffcd085904d 100644 --- a/arch/arm/boot/dts/qcom-sdx55-t55.dts +++ b/arch/arm/boot/dts/qcom-sdx55-t55.dts @@ -250,7 +250,7 @@ nand-ecc-step-size = <512>; nand-bus-width = <8>; /* efs2 partition is secured */ - secure-regions = <0x500000 0xb00000>; + secure-regions = /bits/ 64 <0x500000 0xb00000>; }; }; diff --git a/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts index 3065f84634b8..80c40da79604 100644 --- a/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts +++ b/arch/arm/boot/dts/qcom-sdx55-telit-fn980-tlb.dts @@ -250,8 +250,8 @@ nand-ecc-step-size = <512>; nand-bus-width = <8>; /* ico and efs2 partitions are secured */ - secure-regions = <0x500000 0x500000 - 0xa00000 0xb00000>; + secure-regions = /bits/ 64 <0x500000 0x500000 + 0xa00000 0xb00000>; }; }; diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi index 83b179692dff..13d216192904 100644 --- a/arch/arm/boot/dts/ste-href.dtsi +++ b/arch/arm/boot/dts/ste-href.dtsi @@ -4,6 +4,7 @@ */ #include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/leds/common.h> #include "ste-href-family-pinctrl.dtsi" / { @@ -64,17 +65,20 @@ reg = <0>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = <LED_COLOR_ID_BLUE>; linux,default-trigger = "heartbeat"; }; chan@1 { reg = <1>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = <LED_COLOR_ID_BLUE>; }; chan@2 { reg = <2>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = <LED_COLOR_ID_BLUE>; }; }; lp5521@34 { @@ -88,16 +92,19 @@ reg = <0>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = <LED_COLOR_ID_BLUE>; }; chan@1 { reg = <1>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = <LED_COLOR_ID_BLUE>; }; chan@2 { reg = <2>; led-cur = /bits/ 8 <0x2f>; max-cur = /bits/ 8 <0x5f>; + color = <LED_COLOR_ID_BLUE>; }; }; bh1780@29 { diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts index 97f497854e05..d05fa679dcd3 100644 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts @@ -85,7 +85,7 @@ pinctrl-0 = <&emac_rgmii_pins>; phy-supply = <®_gmac_3v3>; phy-handle = <&ext_rgmii_phy>; - phy-mode = "rgmii"; + phy-mode = "rgmii-id"; status = "okay"; }; diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 25b01da4771b..8b48326be9fd 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -55,6 +55,7 @@ void __init exynos_sysram_init(void) sysram_base_addr = of_iomap(node, 0); sysram_base_phys = of_translate_address(node, of_get_address(node, 0, NULL, NULL)); + of_node_put(node); break; } @@ -62,6 +63,7 @@ void __init exynos_sysram_init(void) if (!of_device_is_available(node)) continue; sysram_ns_base_addr = of_iomap(node, 0); + of_node_put(node); break; } } diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 9cebd360d58e..d1506ef7a537 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o -ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) +ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_IMX7D_CA7)$(CONFIG_SOC_LS1021A),) AFLAGS_headsmp.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 474dedb73bc7..f0a073a71401 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -68,11 +68,13 @@ void imx_set_cpu_arg(int cpu, u32 arg); void v7_secondary_startup(void); void imx_scu_map_io(void); void imx_smp_prepare(void); +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn); #else static inline void imx_scu_map_io(void) {} static inline void imx_smp_prepare(void) {} #endif void imx_src_init(void); +void imx7_src_init(void); void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); void imx_gpc_mask_all(void); @@ -131,6 +133,7 @@ static inline void imx_init_l2cache(void) {} #endif extern const struct smp_operations imx_smp_ops; +extern const struct smp_operations imx7_smp_ops; extern const struct smp_operations ls1021a_smp_ops; #endif diff --git a/arch/arm/mach-imx/headsmp.S b/arch/arm/mach-imx/headsmp.S index 766dbdb2ae27..fcba58be8e79 100644 --- a/arch/arm/mach-imx/headsmp.S +++ b/arch/arm/mach-imx/headsmp.S @@ -21,6 +21,15 @@ diag_reg_offset: ENTRY(v7_secondary_startup) ARM_BE8(setend be) @ go BE8 if entered LE + mrc p15, 0, r0, c0, c0, 0 + lsl r0, r0, #16 + lsr r0, r0, #20 + /* 0xc07 is cortex A7's ID */ + mov r1, #0xc00 + orr r1, #0x7 + cmp r0, r1 + beq secondary_startup + set_diag_reg b secondary_startup ENDPROC(v7_secondary_startup) diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index 82e22398d43d..e24a46dc5703 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -11,6 +11,7 @@ #include <asm/proc-fns.h> #include "common.h" +#include "hardware.h" /* * platform-specific code to shutdown a CPU @@ -40,5 +41,7 @@ int imx_cpu_kill(unsigned int cpu) return 0; imx_enable_cpu(cpu, false); imx_set_cpu_arg(cpu, 0); + if (cpu_is_imx7d()) + imx_gpcv2_set_core1_pdn_pup_by_software(true); return 1; } diff --git a/arch/arm/mach-imx/mach-imx50.c b/arch/arm/mach-imx/mach-imx50.c index f4da205f57db..a2d35f9ba474 100644 --- a/arch/arm/mach-imx/mach-imx50.c +++ b/arch/arm/mach-imx/mach-imx50.c @@ -9,6 +9,12 @@ #include <asm/mach/arch.h> #include "common.h" +#include "hardware.h" + +static void __init imx50_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX50); +} static const char * const imx50_dt_board_compat[] __initconst = { "fsl,imx50", @@ -16,5 +22,6 @@ static const char * const imx50_dt_board_compat[] __initconst = { }; DT_MACHINE_START(IMX50_DT, "Freescale i.MX50 (Device Tree Support)") + .init_early = imx50_init_early, .dt_compat = imx50_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 703998ebb52e..11dcc369ec14 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -40,27 +40,6 @@ static int ksz9021rn_phy_fixup(struct phy_device *phydev) return 0; } -static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val) -{ - phy_write(dev, 0x0d, device); - phy_write(dev, 0x0e, reg); - phy_write(dev, 0x0d, (1 << 14) | device); - phy_write(dev, 0x0e, val); -} - -static int ksz9031rn_phy_fixup(struct phy_device *dev) -{ - /* - * min rx data delay, max rx/tx clock delay, - * min rx/tx control delay - */ - mmd_write_reg(dev, 2, 4, 0); - mmd_write_reg(dev, 2, 5, 0); - mmd_write_reg(dev, 2, 8, 0x003ff); - - return 0; -} - /* * fixup for PLX PEX8909 bridge to configure GPIO1-7 as output High * as they are used for slots1-7 PERST# @@ -89,75 +68,11 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8609, ventana_pciesw_early_fixup); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8606, ventana_pciesw_early_fixup); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8604, ventana_pciesw_early_fixup); -static int ar8031_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* To enable AR8031 output a 125MHz clk from CLK_25M */ - phy_write(dev, 0xd, 0x7); - phy_write(dev, 0xe, 0x8016); - phy_write(dev, 0xd, 0x4007); - - val = phy_read(dev, 0xe); - val &= 0xffe3; - val |= 0x18; - phy_write(dev, 0xe, val); - - /* introduce tx clock delay */ - phy_write(dev, 0x1d, 0x5); - val = phy_read(dev, 0x1e); - val |= 0x0100; - phy_write(dev, 0x1e, val); - - return 0; -} - -#define PHY_ID_AR8031 0x004dd074 - -static int ar8035_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* Ar803x phy SmartEEE feature cause link status generates glitch, - * which cause ethernet link down/up issue, so disable SmartEEE - */ - phy_write(dev, 0xd, 0x3); - phy_write(dev, 0xe, 0x805d); - phy_write(dev, 0xd, 0x4003); - - val = phy_read(dev, 0xe); - phy_write(dev, 0xe, val & ~(1 << 8)); - - /* - * Enable 125MHz clock from CLK_25M on the AR8031. This - * is fed in to the IMX6 on the ENET_REF_CLK (V22) pad. - * Also, introduce a tx clock delay. - * - * This is the same as is the AR8031 fixup. - */ - ar8031_phy_fixup(dev); - - /*check phy power*/ - val = phy_read(dev, 0x0); - if (val & BMCR_PDOWN) - phy_write(dev, 0x0, val & ~BMCR_PDOWN); - - return 0; -} - -#define PHY_ID_AR8035 0x004dd072 - static void __init imx6q_enet_phy_init(void) { if (IS_BUILTIN(CONFIG_PHYLIB)) { phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, ksz9021rn_phy_fixup); - phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK, - ksz9031rn_phy_fixup); - phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffef, - ar8031_phy_fixup); - phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef, - ar8035_phy_fixup); } } @@ -257,9 +172,6 @@ static void __init imx6q_init_machine(void) imx_get_soc_revision()); imx6q_enet_phy_init(); - - of_platform_default_populate(NULL, NULL, NULL); - imx_anatop_init(); cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); imx6q_1588_init(); diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index 781e2a94fdd7..e65ed5218f53 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -15,31 +15,6 @@ #include "common.h" #include "cpuidle.h" -static int ar8031_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* Set RGMII IO voltage to 1.8V */ - phy_write(dev, 0x1d, 0x1f); - phy_write(dev, 0x1e, 0x8); - - /* introduce tx clock delay */ - phy_write(dev, 0x1d, 0x5); - val = phy_read(dev, 0x1e); - val |= 0x0100; - phy_write(dev, 0x1e, val); - - return 0; -} - -#define PHY_ID_AR8031 0x004dd074 -static void __init imx6sx_enet_phy_init(void) -{ - if (IS_BUILTIN(CONFIG_PHYLIB)) - phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, - ar8031_phy_fixup); -} - static void __init imx6sx_enet_clk_sel(void) { struct regmap *gpr; @@ -57,7 +32,6 @@ static void __init imx6sx_enet_clk_sel(void) static inline void imx6sx_enet_init(void) { - imx6sx_enet_phy_init(); imx6sx_enet_clk_sel(); } diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c index 879c35929a13..6fdd06bcf988 100644 --- a/arch/arm/mach-imx/mach-imx7d.c +++ b/arch/arm/mach-imx/mach-imx7d.c @@ -14,25 +14,6 @@ #include "common.h" -static int ar8031_phy_fixup(struct phy_device *dev) -{ - u16 val; - - /* Set RGMII IO voltage to 1.8V */ - phy_write(dev, 0x1d, 0x1f); - phy_write(dev, 0x1e, 0x8); - - /* disable phy AR8031 SmartEEE function. */ - phy_write(dev, 0xd, 0x3); - phy_write(dev, 0xe, 0x805d); - phy_write(dev, 0xd, 0x4003); - val = phy_read(dev, 0xe); - val &= ~(0x1 << 8); - phy_write(dev, 0xe, val); - - return 0; -} - static int bcm54220_phy_fixup(struct phy_device *dev) { /* enable RXC skew select RGMII copper mode */ @@ -44,14 +25,11 @@ static int bcm54220_phy_fixup(struct phy_device *dev) return 0; } -#define PHY_ID_AR8031 0x004dd074 #define PHY_ID_BCM54220 0x600d8589 static void __init imx7d_enet_phy_init(void) { if (IS_BUILTIN(CONFIG_PHYLIB)) { - phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, - ar8031_phy_fixup); phy_register_fixup_for_uid(PHY_ID_BCM54220, 0xffffffff, bcm54220_phy_fixup); } @@ -91,7 +69,7 @@ static void __init imx7d_init_late(void) static void __init imx7d_init_irq(void) { imx_init_revision_from_anatop(); - imx_src_init(); + imx7_src_init(); irqchip_init(); } @@ -102,6 +80,7 @@ static const char *const imx7d_dt_compat[] __initconst = { }; DT_MACHINE_START(IMX7D, "Freescale i.MX7 Dual (Device Tree)") + .smp = smp_ops(imx7_smp_ops), .init_irq = imx7d_init_irq, .init_machine = imx7d_init_machine, .init_late = imx7d_init_late, diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index cf4e9335831c..972639038be5 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -92,6 +92,32 @@ const struct smp_operations imx_smp_ops __initconst = { #endif }; +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +static void __init imx7_smp_init_cpus(void) +{ + struct device_node *np; + int i, ncores = 0; + + /* The iMX7D SCU does not report core count, get it from DT */ + for_each_of_cpu_node(np) + ncores++; + + for (i = ncores; i < NR_CPUS; i++) + set_cpu_possible(i, false); +} + +const struct smp_operations imx7_smp_ops __initconst = { + .smp_init_cpus = imx7_smp_init_cpus, + .smp_boot_secondary = imx_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = imx_cpu_die, + .cpu_kill = imx_cpu_kill, +#endif +}; + #define DCFG_CCSR_SCRATCHRW1 0x200 static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle) diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c index f52f371292ac..95fd1fbb0826 100644 --- a/arch/arm/mach-imx/src.c +++ b/arch/arm/mach-imx/src.c @@ -6,15 +6,19 @@ #include <linux/init.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/reset-controller.h> #include <linux/smp.h> #include <asm/smp_plat.h> #include "common.h" +#include "hardware.h" #define SRC_SCR 0x000 -#define SRC_GPR1 0x020 +#define SRC_GPR1_V1 0x020 +#define SRC_GPR1_V2 0x074 +#define SRC_GPR1(gpr_v2) ((gpr_v2) ? SRC_GPR1_V2 : SRC_GPR1_V1) #define BP_SRC_SCR_WARM_RESET_ENABLE 0 #define BP_SRC_SCR_SW_GPU_RST 1 #define BP_SRC_SCR_SW_VPU_RST 2 @@ -23,9 +27,18 @@ #define BP_SRC_SCR_SW_IPU2_RST 12 #define BP_SRC_SCR_CORE1_RST 14 #define BP_SRC_SCR_CORE1_ENABLE 22 +/* below is for i.MX7D */ +#define SRC_A7RCR1 0x008 +#define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1 +#define GPC_CPU_PGC_SW_PUP_REQ 0xf0 +#define GPC_CPU_PGC_SW_PDN_REQ 0xfc +#define GPC_PGC_C1 0x840 +#define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2 static void __iomem *src_base; static DEFINE_SPINLOCK(scr_lock); +static bool gpr_v2; +static void __iomem *gpc_base; static const int sw_reset_bits[5] = { BP_SRC_SCR_SW_GPU_RST, @@ -73,17 +86,64 @@ static struct reset_controller_dev imx_reset_controller = { .nr_resets = ARRAY_SIZE(sw_reset_bits), }; +static void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset) +{ + writel_relaxed(enable, gpc_base + offset); +} + +/* + * The motivation for bringing up the second i.MX7D core inside the kernel + * is that legacy vendor bootloaders usually do not implement PSCI support. + * This is a significant blocker for systems in the field that are running old + * bootloader versions to upgrade to a modern mainline kernel version, as only + * one CPU of the i.MX7D would be brought up. + * Bring up the second i.MX7D core inside the kernel to make the migration + * path to mainline kernel easier for the existing iMX7D users. + */ +void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) +{ + u32 reg = pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ; + u32 val, pup; + int ret; + + imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); + val = readl_relaxed(gpc_base + reg); + val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; + writel_relaxed(val, gpc_base + reg); + + ret = readl_relaxed_poll_timeout_atomic(gpc_base + reg, pup, + !(pup & BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7), + 5, 1000000); + if (ret < 0) { + pr_err("i.MX7D: CORE1_A7 power up timeout\n"); + val &= ~BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; + writel_relaxed(val, gpc_base + reg); + } + + imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); +} + void imx_enable_cpu(int cpu, bool enable) { u32 mask, val; cpu = cpu_logical_map(cpu); - mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); spin_lock(&scr_lock); - val = readl_relaxed(src_base + SRC_SCR); - val = enable ? val | mask : val & ~mask; - val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); - writel_relaxed(val, src_base + SRC_SCR); + if (gpr_v2) { + if (enable) + imx_gpcv2_set_core1_pdn_pup_by_software(false); + + mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_A7RCR1); + val = enable ? val | mask : val & ~mask; + writel_relaxed(val, src_base + SRC_A7RCR1); + } else { + mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; + val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); + writel_relaxed(val, src_base + SRC_SCR); + } spin_unlock(&scr_lock); } @@ -91,19 +151,19 @@ void imx_set_cpu_jump(int cpu, void *jump_addr) { cpu = cpu_logical_map(cpu); writel_relaxed(__pa_symbol(jump_addr), - src_base + SRC_GPR1 + cpu * 8); + src_base + SRC_GPR1(gpr_v2) + cpu * 8); } u32 imx_get_cpu_arg(int cpu) { cpu = cpu_logical_map(cpu); - return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4); + return readl_relaxed(src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4); } void imx_set_cpu_arg(int cpu, u32 arg) { cpu = cpu_logical_map(cpu); - writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); + writel_relaxed(arg, src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4); } void __init imx_src_init(void) @@ -131,3 +191,26 @@ void __init imx_src_init(void) writel_relaxed(val, src_base + SRC_SCR); spin_unlock(&scr_lock); } + +void __init imx7_src_init(void) +{ + struct device_node *np; + + gpr_v2 = true; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-src"); + if (!np) + return; + + src_base = of_iomap(np, 0); + if (!src_base) + return; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc"); + if (!np) + return; + + gpc_base = of_iomap(np, 0); + if (!gpc_base) + return; +} diff --git a/arch/arm/mach-imx/suspend-imx53.S b/arch/arm/mach-imx/suspend-imx53.S index 41b8aad65363..46570ec2fbcf 100644 --- a/arch/arm/mach-imx/suspend-imx53.S +++ b/arch/arm/mach-imx/suspend-imx53.S @@ -28,11 +28,11 @@ * ^ * ^ * imx53_suspend code - * PM_INFO structure(imx53_suspend_info) + * PM_INFO structure(imx5_cpu_suspend_info) * ======================== low address ======================= */ -/* Offsets of members of struct imx53_suspend_info */ +/* Offsets of members of struct imx5_cpu_suspend_info */ #define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0 #define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4 #define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8 diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 165c184801e1..bf14d65120b9 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -7,7 +7,7 @@ comment "IXP4xx Platforms" config MACH_IXP4XX_OF bool - prompt "Devce Tree IXP4xx boards" + prompt "Device Tree IXP4xx boards" default y select ARM_APPENDED_DTB # Old Redboot bootloaders deployed select I2C @@ -20,7 +20,7 @@ config MACH_IXP4XX_OF config MACH_NSLU2 bool prompt "Linksys NSLU2" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Linksys's NSLU2 NAS device. For more information on this platform, @@ -28,7 +28,7 @@ config MACH_NSLU2 config MACH_AVILA bool "Avila" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support the Gateworks Avila Network Platform. For more information on this platform, @@ -44,7 +44,7 @@ config MACH_LOFT config ARCH_ADI_COYOTE bool "Coyote" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support the ADI Engineering Coyote Gateway Reference Platform. For more @@ -52,7 +52,7 @@ config ARCH_ADI_COYOTE config MACH_GATEWAY7001 bool "Gateway 7001" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Gateway's 7001 Access Point. For more information on this platform, @@ -60,7 +60,7 @@ config MACH_GATEWAY7001 config MACH_WG302V2 bool "Netgear WG302 v2 / WAG302 v2" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Netgear's WG302 v2 or WAG302 v2 Access Points. For more information @@ -68,6 +68,7 @@ config MACH_WG302V2 config ARCH_IXDP425 bool "IXDP425" + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Intel's IXDP425 Development Platform (Also known as Richfield). @@ -75,6 +76,7 @@ config ARCH_IXDP425 config MACH_IXDPG425 bool "IXDPG425" + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Intel's IXDPG425 Development Platform (Also known as Montajade). @@ -120,7 +122,7 @@ config ARCH_PRPMC1100 config MACH_NAS100D bool prompt "NAS100D" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Iomega's NAS 100d device. For more information on this platform, @@ -129,7 +131,7 @@ config MACH_NAS100D config MACH_DSMG600 bool prompt "D-Link DSM-G600 RevA" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support D-Link's DSM-G600 RevA device. For more information on this platform, @@ -143,7 +145,7 @@ config ARCH_IXDP4XX config MACH_FSG bool prompt "Freecom FSG-3" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Freecom's FSG-3 device. For more information on this platform, @@ -152,7 +154,7 @@ config MACH_FSG config MACH_ARCOM_VULCAN bool prompt "Arcom/Eurotech Vulcan" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support Arcom's Vulcan board. @@ -173,7 +175,7 @@ config CPU_IXP43X config MACH_GTWX5715 bool "Gemtek WX5715 (Linksys WRV54G)" depends on ARCH_IXP4XX - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help This board is currently inside the Linksys WRV54G Gateways. @@ -196,7 +198,7 @@ config MACH_DEVIXP config MACH_MICCPT bool "Omicron MICCPT" - select FORCE_PCI + depends on IXP4XX_PCI_LEGACY help Say 'Y' here if you want your kernel to support the MICCPT board from OMICRON electronics GmbH. @@ -209,9 +211,16 @@ config MACH_MIC256 comment "IXP4xx Options" +config IXP4XX_PCI_LEGACY + bool "IXP4xx legacy PCI driver support" + depends on PCI + help + Selects legacy PCI driver. + Not recommended for new development. + config IXP4XX_INDIRECT_PCI bool "Use indirect PCI memory access" - depends on PCI + depends on IXP4XX_PCI_LEGACY help IXP4xx provides two methods of accessing PCI memory space: diff --git a/arch/arm/mach-ixp4xx/avila-setup.c b/arch/arm/mach-ixp4xx/avila-setup.c index 1981b33109cb..ec1d3029f80c 100644 --- a/arch/arm/mach-ixp4xx/avila-setup.c +++ b/arch/arm/mach-ixp4xx/avila-setup.c @@ -19,6 +19,7 @@ #include <linux/tty.h> #include <linux/serial_8250.h> #include <linux/gpio/machine.h> +#include <linux/platform_data/pata_ixp4xx_cf.h> #include <asm/types.h> #include <asm/setup.h> #include <asm/memory.h> diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 007a44412e24..b5eadd70d903 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -27,12 +27,12 @@ #include <linux/cpu.h> #include <linux/pci.h> #include <linux/sched_clock.h> +#include <linux/soc/ixp4xx/cpu.h> #include <linux/irqchip/irq-ixp4xx.h> #include <linux/platform_data/timer-ixp4xx.h> #include <linux/dma-map-ops.h> #include <mach/udc.h> #include <mach/hardware.h> -#include <mach/io.h> #include <linux/uaccess.h> #include <asm/page.h> #include <asm/exception.h> @@ -44,6 +44,27 @@ #include "irqs.h" +u32 ixp4xx_read_feature_bits(void) +{ + u32 val = ~__raw_readl(IXP4XX_EXP_CFG2); + + if (cpu_is_ixp42x_rev_a0()) + return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP | + IXP4XX_FEATURE_AES); + if (cpu_is_ixp42x()) + return val & IXP42X_FEATURE_MASK; + if (cpu_is_ixp43x()) + return val & IXP43X_FEATURE_MASK; + return val & IXP46X_FEATURE_MASK; +} +EXPORT_SYMBOL(ixp4xx_read_feature_bits); + +void ixp4xx_write_feature_bits(u32 value) +{ + __raw_writel(~value, IXP4XX_EXP_CFG2); +} +EXPORT_SYMBOL(ixp4xx_write_feature_bits); + #define IXP4XX_TIMER_FREQ 66666000 /************************************************************************* @@ -215,6 +236,27 @@ static struct resource ixp46x_i2c_resources[] = { } }; +/* A single 32-bit register on IXP46x */ +#define IXP4XX_HWRANDOM_BASE_PHYS 0x70002100 + +static struct resource ixp46x_hwrandom_resource[] = { + { + .start = IXP4XX_HWRANDOM_BASE_PHYS, + .end = IXP4XX_HWRANDOM_BASE_PHYS + 0x3, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device ixp46x_hwrandom_device = { + .name = "ixp4xx-hwrandom", + .id = -1, + .dev = { + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = ixp46x_hwrandom_resource, + .num_resources = ARRAY_SIZE(ixp46x_hwrandom_resource), +}; + /* * I2C controller. The IXP46x uses the same block as the IOP3xx, so * we just use the same device name. @@ -227,7 +269,8 @@ static struct platform_device ixp46x_i2c_controller = { }; static struct platform_device *ixp46x_devices[] __initdata = { - &ixp46x_i2c_controller + &ixp46x_hwrandom_device, + &ixp46x_i2c_controller, }; unsigned long ixp4xx_exp_bus_size; diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c index 507ee3878769..844329c5610d 100644 --- a/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/arch/arm/mach-ixp4xx/fsg-setup.c @@ -28,6 +28,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> +#include <mach/hardware.h> #include "irqs.h" diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h deleted file mode 100644 index b872a5354ddd..000000000000 --- a/arch/arm/mach-ixp4xx/include/mach/cpu.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * arch/arm/mach-ixp4xx/include/mach/cpu.h - * - * IXP4XX cpu type detection - * - * Copyright (C) 2007 MontaVista Software, Inc. - */ - -#ifndef __ASM_ARCH_CPU_H__ -#define __ASM_ARCH_CPU_H__ - -#include <linux/io.h> -#include <asm/cputype.h> - -/* Processor id value in CP15 Register 0 */ -#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */ -#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0 - -#define IXP43X_PROCESSOR_ID_VALUE 0x69054040 -#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0 - -#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */ -#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0 - -#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \ - IXP42X_PROCESSOR_ID_VALUE) -#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \ - IXP42X_PROCESSOR_ID_VALUE) -#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \ - IXP43X_PROCESSOR_ID_VALUE) -#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \ - IXP46X_PROCESSOR_ID_VALUE) - -static inline u32 ixp4xx_read_feature_bits(void) -{ - u32 val = ~__raw_readl(IXP4XX_EXP_CFG2); - - if (cpu_is_ixp42x_rev_a0()) - return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP | - IXP4XX_FEATURE_AES); - if (cpu_is_ixp42x()) - return val & IXP42X_FEATURE_MASK; - if (cpu_is_ixp43x()) - return val & IXP43X_FEATURE_MASK; - return val & IXP46X_FEATURE_MASK; -} - -static inline void ixp4xx_write_feature_bits(u32 value) -{ - __raw_writel(~value, IXP4XX_EXP_CFG2); -} - -#endif /* _ASM_ARCH_CPU_H */ diff --git a/arch/arm/mach-ixp4xx/include/mach/hardware.h b/arch/arm/mach-ixp4xx/include/mach/hardware.h index b884eedcd0fc..b2b7301ce503 100644 --- a/arch/arm/mach-ixp4xx/include/mach/hardware.h +++ b/arch/arm/mach-ixp4xx/include/mach/hardware.h @@ -23,7 +23,7 @@ #include "ixp4xx-regs.h" #ifndef __ASSEMBLER__ -#include <mach/cpu.h> +#include <linux/soc/ixp4xx/cpu.h> #endif /* Platform helper functions and definitions */ diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h index 708d085ce39f..abb07f105515 100644 --- a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h +++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h @@ -45,21 +45,21 @@ * it can be used with the low-level debug code. */ #define IXP4XX_PERIPHERAL_BASE_PHYS 0xC8000000 -#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEF00000) +#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEC00000) #define IXP4XX_PERIPHERAL_REGION_SIZE 0x00013000 /* * PCI Config registers */ #define IXP4XX_PCI_CFG_BASE_PHYS 0xC0000000 -#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEF13000) +#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEC13000) #define IXP4XX_PCI_CFG_REGION_SIZE 0x00001000 /* * Expansion BUS Configuration registers */ #define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000 -#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEF14000 +#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000 #define IXP4XX_EXP_CFG_REGION_SIZE 0x00001000 #define IXP4XX_EXP_CS0_OFFSET 0x00 @@ -120,6 +120,7 @@ #define IXP4XX_SSP_BASE_PHYS (IXP4XX_PERIPHERAL_BASE_PHYS + 0x12000) +/* The UART is explicitly put in the beginning of fixmap */ #define IXP4XX_UART1_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x0000) #define IXP4XX_UART2_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x1000) #define IXP4XX_PMU_BASE_VIRT (IXP4XX_PERIPHERAL_BASE_VIRT + 0x2000) @@ -299,58 +300,4 @@ #define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ -/* "fuse" bits of IXP_EXP_CFG2 */ -/* All IXP4xx CPUs */ -#define IXP4XX_FEATURE_RCOMP (1 << 0) -#define IXP4XX_FEATURE_USB_DEVICE (1 << 1) -#define IXP4XX_FEATURE_HASH (1 << 2) -#define IXP4XX_FEATURE_AES (1 << 3) -#define IXP4XX_FEATURE_DES (1 << 4) -#define IXP4XX_FEATURE_HDLC (1 << 5) -#define IXP4XX_FEATURE_AAL (1 << 6) -#define IXP4XX_FEATURE_HSS (1 << 7) -#define IXP4XX_FEATURE_UTOPIA (1 << 8) -#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9) -#define IXP4XX_FEATURE_NPEC_ETH (1 << 10) -#define IXP4XX_FEATURE_RESET_NPEA (1 << 11) -#define IXP4XX_FEATURE_RESET_NPEB (1 << 12) -#define IXP4XX_FEATURE_RESET_NPEC (1 << 13) -#define IXP4XX_FEATURE_PCI (1 << 14) -#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16) -#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22) -#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \ - IXP4XX_FEATURE_USB_DEVICE | \ - IXP4XX_FEATURE_HASH | \ - IXP4XX_FEATURE_AES | \ - IXP4XX_FEATURE_DES | \ - IXP4XX_FEATURE_HDLC | \ - IXP4XX_FEATURE_AAL | \ - IXP4XX_FEATURE_HSS | \ - IXP4XX_FEATURE_UTOPIA | \ - IXP4XX_FEATURE_NPEB_ETH0 | \ - IXP4XX_FEATURE_NPEC_ETH | \ - IXP4XX_FEATURE_RESET_NPEA | \ - IXP4XX_FEATURE_RESET_NPEB | \ - IXP4XX_FEATURE_RESET_NPEC | \ - IXP4XX_FEATURE_PCI | \ - IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \ - IXP4XX_FEATURE_XSCALE_MAX_FREQ) - - -/* IXP43x/46x CPUs */ -#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15) -#define IXP4XX_FEATURE_USB_HOST (1 << 18) -#define IXP4XX_FEATURE_NPEA_ETH (1 << 19) -#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \ - IXP4XX_FEATURE_ECC_TIMESYNC | \ - IXP4XX_FEATURE_USB_HOST | \ - IXP4XX_FEATURE_NPEA_ETH) - -/* IXP46x CPU (including IXP455) only */ -#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20) -#define IXP4XX_FEATURE_RSA (1 << 21) -#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \ - IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ - IXP4XX_FEATURE_RSA) - #endif diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h index 6d403fe0bf52..d8b4df96db08 100644 --- a/arch/arm/mach-ixp4xx/include/mach/platform.h +++ b/arch/arm/mach-ixp4xx/include/mach/platform.h @@ -80,20 +80,6 @@ extern unsigned long ixp4xx_exp_bus_size; #define IXP4XX_UART_XTAL 14745600 /* - * This structure provide a means for the board setup code - * to give information to th pata_ixp4xx driver. It is - * passed as platform_data. - */ -struct ixp4xx_pata_data { - volatile u32 *cs0_cfg; - volatile u32 *cs1_cfg; - unsigned long cs0_bits; - unsigned long cs1_bits; - void __iomem *cs0; - void __iomem *cs1; -}; - -/* * Frequency of clock used for primary clocksource */ extern unsigned long ixp4xx_timer_freq; diff --git a/arch/arm/mach-ixp4xx/ixp4xx-of.c b/arch/arm/mach-ixp4xx/ixp4xx-of.c index 7449b8319c8a..f9904716ec7f 100644 --- a/arch/arm/mach-ixp4xx/ixp4xx-of.c +++ b/arch/arm/mach-ixp4xx/ixp4xx-of.c @@ -9,8 +9,12 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <mach/hardware.h> -#include <mach/ixp4xx-regs.h> +/* + * These are the only fixed phys to virt mappings we ever need + * we put it right after the UART mapping at 0xffc80000-0xffc81fff + */ +#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000 +#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEC14000 static struct map_desc ixp4xx_of_io_desc[] __initdata = { /* diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 6959ad2e3aec..6133cf01cbe4 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -33,6 +33,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> +#include <mach/hardware.h> #include "irqs.h" diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index a428bb918703..8526a70e401b 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -31,6 +31,7 @@ #include <asm/mach/arch.h> #include <asm/mach/flash.h> #include <asm/mach/time.h> +#include <mach/hardware.h> #include "irqs.h" diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 9536b8f3c07d..208c700c2455 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -65,14 +65,14 @@ config MACH_OMAP_INNOVATOR config MACH_OMAP_H2 bool "TI H2 Support" depends on ARCH_OMAP16XX - help + help TI OMAP 1610/1611B H2 board support. Say Y here if you have such a board. config MACH_OMAP_H3 bool "TI H3 Support" depends on ARCH_OMAP16XX - help + help TI OMAP 1710 H3 board support. Say Y here if you have such a board. @@ -85,14 +85,14 @@ config MACH_HERALD config MACH_OMAP_OSK bool "TI OSK Support" depends on ARCH_OMAP16XX - help + help TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here if you have such a board. config OMAP_OSK_MISTRAL bool "Mistral QVGA board Support" depends on MACH_OMAP_OSK - help + help The OSK supports an optional add-on board with a Quarter-VGA touchscreen, PDA-ish buttons, a resume button, bicolor LED, and camera connector. Say Y here if you have this board. @@ -100,14 +100,14 @@ config OMAP_OSK_MISTRAL config MACH_OMAP_PERSEUS2 bool "TI Perseus2" depends on ARCH_OMAP730 - help + help Support for TI OMAP 730 Perseus2 board. Say Y here if you have such a board. config MACH_OMAP_FSAMPLE bool "TI F-Sample" depends on ARCH_OMAP730 - help + help Support for TI OMAP 850 F-Sample board. Say Y here if you have such a board. diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index d02fe63dab59..14beb59e5f7b 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -26,7 +26,6 @@ extern struct omap_domain_base cm_base; extern struct omap_domain_base cm2_base; -extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); # endif /* diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index b7ea609386d5..e2d069fe67f1 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -38,19 +38,6 @@ struct omap_domain_base cm2_base; #define CM_SINGLE_INSTANCE 0x2 /** - * omap2_set_globals_cm - set the CM/CM2 base addresses (for early use) - * @cm: CM base virtual address - * @cm2: CM2 base virtual address (if present on the booted SoC) - * - * XXX Will be replaced when the PRM/CM drivers are completed. - */ -void __init omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2) -{ - cm_base.va = cm; - cm2_base.va = cm2; -} - -/** * cm_split_idlest_reg - split CM_IDLEST reg addr into its components * @idlest_reg: CM_IDLEST* virtual address * @prcm_inst: pointer to an s16 to return the PRCM instance offset diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index db446f271f5d..32f58f58515e 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -130,7 +130,6 @@ void am33xx_init_early(void); void am35xx_init_early(void); void ti814x_init_early(void); void ti816x_init_early(void); -void am33xx_init_early(void); void am43xx_init_early(void); void am43xx_init_late(void); void omap4430_init_early(void); diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c index 73338cf80d76..062d431fc33a 100644 --- a/arch/arm/mach-omap2/control.c +++ b/arch/arm/mach-omap2/control.c @@ -136,11 +136,6 @@ struct omap3_control_regs { static struct omap3_control_regs control_context; #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */ -void __init omap2_set_globals_control(void __iomem *ctrl) -{ - omap2_ctrl_base = ctrl; -} - u8 omap_ctrl_readb(u16 offset) { u32 val; diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h index eceb4b09adb2..c4ca30ba1790 100644 --- a/arch/arm/mach-omap2/control.h +++ b/arch/arm/mach-omap2/control.h @@ -528,7 +528,6 @@ extern int omap3_ctrl_save_padconf(void); void omap3_ctrl_init(void); int omap2_control_base_init(void); int omap_control_init(void); -void omap2_set_globals_control(void __iomem *ctrl); void __init omap3_control_legacy_iomap_init(void); #else #define omap_ctrl_readb(x) 0 diff --git a/arch/arm/mach-omap2/pm33xx-core.c b/arch/arm/mach-omap2/pm33xx-core.c index 56f2c0bcae5a..bf0d25fd2cea 100644 --- a/arch/arm/mach-omap2/pm33xx-core.c +++ b/arch/arm/mach-omap2/pm33xx-core.c @@ -8,6 +8,7 @@ #include <linux/cpuidle.h> #include <linux/platform_data/pm33xx.h> +#include <linux/suspend.h> #include <asm/cpuidle.h> #include <asm/smp_scu.h> #include <asm/suspend.h> @@ -324,6 +325,44 @@ static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void) return NULL; } +#ifdef CONFIG_SUSPEND +/* + * Block system suspend initially. Later on pm33xx sets up it's own + * platform_suspend_ops after probe. That depends also on loaded + * wkup_m3_ipc and booted am335x-pm-firmware.elf. + */ +static int amx3_suspend_block(suspend_state_t state) +{ + pr_warn("PM not initialized for pm33xx, wkup_m3_ipc, or am335x-pm-firmware.elf\n"); + + return -EINVAL; +} + +static int amx3_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + return 1; + default: + return 0; + } +} + +static const struct platform_suspend_ops amx3_blocked_pm_ops = { + .begin = amx3_suspend_block, + .valid = amx3_pm_valid, +}; + +static void __init amx3_block_suspend(void) +{ + suspend_set_ops(&amx3_blocked_pm_ops); +} +#else +static inline void amx3_block_suspend(void) +{ +} +#endif /* CONFIG_SUSPEND */ + int __init amx3_common_pm_init(void) { struct am33xx_pm_platform_data *pdata; @@ -337,6 +376,7 @@ int __init amx3_common_pm_init(void) devinfo.size_data = sizeof(*pdata); devinfo.id = -1; platform_device_register_full(&devinfo); + amx3_block_suspend(); return 0; } diff --git a/arch/arm/mach-s3c/mach-rx1950.c b/arch/arm/mach-s3c/mach-rx1950.c index a3f46aa61c45..313e080e179e 100644 --- a/arch/arm/mach-s3c/mach-rx1950.c +++ b/arch/arm/mach-s3c/mach-rx1950.c @@ -271,7 +271,6 @@ static int rx1950_led_blink_set(struct gpio_desc *desc, int state, break; default: return -EINVAL; - break; } if (delay_on && delay_off && !*delay_on && !*delay_off) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 7336c1fd0dda..b0ce18d4cc98 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -16,6 +16,7 @@ config ARCH_SUNXI select IRQ_FASTEOI_HIERARCHY_HANDLERS select PINCTRL select RESET_CONTROLLER + select SUN4I_TIMER help This enables support for Allwinner sunxi based SoCs like the A64. diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts index e22b94c83647..5e66ce1a334f 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts @@ -79,7 +79,7 @@ &emac { pinctrl-names = "default"; pinctrl-0 = <&rgmii_pins>; - phy-mode = "rgmii-id"; + phy-mode = "rgmii-txid"; phy-handle = <&ext_rgmii_phy>; phy-supply = <®_dc1sw>; status = "okay"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 634a91af8e83..4b854eb21f72 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -227,7 +227,7 @@ <&pcie_phy 2>, <&pcie_phy 3>; phy-names = "pcie-phy-0", "pcie-phy-1", "pcie-phy-2", "pcie-phy-3"; - ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000>, + ranges = <0x82000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x1e00000>, <0x81000000 0x0 0xfbe00000 0x0 0xfbe00000 0x0 0x100000>; resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>, <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>, diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index b7a5abee2147..a7da8ea7b3ed 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -1058,7 +1058,7 @@ config PATA_ISAPNP config PATA_IXP4XX_CF tristate "IXP4XX Compact Flash support" - depends on ARCH_IXP4XX + depends on ARCH_IXP4XX || COMPILE_TEST help This option enables support for a Compact Flash connected on the ixp4xx expansion bus. This driver had been written for diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 43215a4c1e54..5881d64af943 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -17,6 +17,7 @@ #include <linux/libata.h> #include <linux/irq.h> #include <linux/platform_device.h> +#include <linux/platform_data/pata_ixp4xx_cf.h> #include <scsi/scsi_host.h> #define DRV_NAME "pata_ixp4xx_cf" diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index c11f12d4ab53..3f166c8a4099 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -152,7 +152,7 @@ config HW_RANDOM_VIA config HW_RANDOM_IXP4XX tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support" - depends on ARCH_IXP4XX + depends on ARCH_IXP4XX || COMPILE_TEST default HW_RANDOM help This driver provides kernel-side support for the Pseudo-Random diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c index beec1627db3c..188854dd16a9 100644 --- a/drivers/char/hw_random/ixp4xx-rng.c +++ b/drivers/char/hw_random/ixp4xx-rng.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * drivers/char/hw_random/ixp4xx-rng.c * @@ -8,23 +9,20 @@ * Copyright 2005 (c) MontaVista Software, Inc. * * Fixes by Michael Buesch - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> #include <linux/types.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/platform_device.h> #include <linux/init.h> #include <linux/bitops.h> #include <linux/hw_random.h> +#include <linux/of.h> +#include <linux/soc/ixp4xx/cpu.h> #include <asm/io.h> -#include <mach/hardware.h> - static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer) { @@ -40,35 +38,40 @@ static struct hwrng ixp4xx_rng_ops = { .data_read = ixp4xx_rng_data_read, }; -static int __init ixp4xx_rng_init(void) +static int ixp4xx_rng_probe(struct platform_device *pdev) { void __iomem * rng_base; - int err; + struct device *dev = &pdev->dev; + struct resource *res; if (!cpu_is_ixp46x()) /* includes IXP455 */ return -ENOSYS; - rng_base = ioremap(0x70002100, 4); - if (!rng_base) - return -ENOMEM; - ixp4xx_rng_ops.priv = (unsigned long)rng_base; - err = hwrng_register(&ixp4xx_rng_ops); - if (err) - iounmap(rng_base); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rng_base = devm_ioremap_resource(dev, res); + if (IS_ERR(rng_base)) + return PTR_ERR(rng_base); - return err; + ixp4xx_rng_ops.priv = (unsigned long)rng_base; + return devm_hwrng_register(dev, &ixp4xx_rng_ops); } -static void __exit ixp4xx_rng_exit(void) -{ - void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv; - - hwrng_unregister(&ixp4xx_rng_ops); - iounmap(rng_base); -} +static const struct of_device_id ixp4xx_rng_of_match[] = { + { + .compatible = "intel,ixp46x-rng", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ixp4xx_rng_of_match); -module_init(ixp4xx_rng_init); -module_exit(ixp4xx_rng_exit); +static struct platform_driver ixp4xx_rng_driver = { + .driver = { + .name = "ixp4xx-hwrandom", + .of_match_table = ixp4xx_rng_of_match, + }, + .probe = ixp4xx_rng_probe, +}; +module_platform_driver(ixp4xx_rng_driver); MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x"); diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 35fc5ee70491..98730aab287c 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -31,6 +31,10 @@ #include <linux/soc/ixp4xx/npe.h> #include <linux/soc/ixp4xx/qmgr.h> +/* Intermittent includes, delete this after v5.14-rc1 */ +#include <linux/soc/ixp4xx/cpu.h> +#include <mach/ixp4xx-regs.h> + #define MAX_KEYLEN 32 /* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */ diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index 85c66af9e56d..7ae754eadf22 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -37,6 +37,8 @@ #include <linux/module.h> #include <linux/soc/ixp4xx/npe.h> #include <linux/soc/ixp4xx/qmgr.h> +#include <mach/hardware.h> +#include <linux/soc/ixp4xx/cpu.h> #include "ixp46x_ts.h" diff --git a/drivers/net/ethernet/xscale/ptp_ixp46x.c b/drivers/net/ethernet/xscale/ptp_ixp46x.c index 9ecc395239e9..99d4d9439d05 100644 --- a/drivers/net/ethernet/xscale/ptp_ixp46x.c +++ b/drivers/net/ethernet/xscale/ptp_ixp46x.c @@ -12,9 +12,8 @@ #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> -#include <linux/module.h> - #include <linux/ptp_clock_kernel.h> +#include <linux/soc/ixp4xx/cpu.h> #include "ixp46x_ts.h" diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index e97521138f7e..3c51ab239fb2 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/soc/ixp4xx/npe.h> #include <linux/soc/ixp4xx/qmgr.h> +#include <linux/soc/ixp4xx/cpu.h> #define DEBUG_DESC 0 #define DEBUG_RX 0 diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 2f2c8a1729f9..5e1e3796efa4 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -37,6 +37,14 @@ config PCI_FTPCI100 depends on OF default ARCH_GEMINI +config PCI_IXP4XX + bool "Intel IXP4xx PCI controller" + depends on ARM && OF + default ARCH_IXP4XX + help + Say Y here if you want support for the PCI host controller found + in the Intel IXP4xx XScale-based network processor SoC. + config PCI_TEGRA bool "NVIDIA Tegra PCIe controller" depends on ARCH_TEGRA || COMPILE_TEST diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile index 63e3880a3e87..aaf30b3dcc14 100644 --- a/drivers/pci/controller/Makefile +++ b/drivers/pci/controller/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PCIE_CADENCE) += cadence/ obj-$(CONFIG_PCI_FTPCI100) += pci-ftpci100.o +obj-$(CONFIG_PCI_IXP4XX) += pci-ixp4xx.o obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o obj-$(CONFIG_PCI_HYPERV_INTERFACE) += pci-hyperv-intf.o obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o diff --git a/drivers/pci/controller/pci-ixp4xx.c b/drivers/pci/controller/pci-ixp4xx.c new file mode 100644 index 000000000000..896a45b24236 --- /dev/null +++ b/drivers/pci/controller/pci-ixp4xx.c @@ -0,0 +1,671 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for Intel IXP4xx PCI host controller + * + * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> + * + * Based on the IXP4xx arch/arm/mach-ixp4xx/common-pci.c driver + * Copyright (C) 2002 Intel Corporation + * Copyright (C) 2003 Greg Ungerer <gerg@linux-m68k.org> + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * Copyright (C) 2005 Deepak Saxena <dsaxena@plexity.net> + * Copyright (C) 2005 Alessandro Zummo <a.zummo@towertech.it> + * + * TODO: + * - Test IO-space access + * - DMA support + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_pci.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/bits.h> + +/* Register offsets */ +#define IXP4XX_PCI_NP_AD 0x00 +#define IXP4XX_PCI_NP_CBE 0x04 +#define IXP4XX_PCI_NP_WDATA 0x08 +#define IXP4XX_PCI_NP_RDATA 0x0c +#define IXP4XX_PCI_CRP_AD_CBE 0x10 +#define IXP4XX_PCI_CRP_WDATA 0x14 +#define IXP4XX_PCI_CRP_RDATA 0x18 +#define IXP4XX_PCI_CSR 0x1c +#define IXP4XX_PCI_ISR 0x20 +#define IXP4XX_PCI_INTEN 0x24 +#define IXP4XX_PCI_DMACTRL 0x28 +#define IXP4XX_PCI_AHBMEMBASE 0x2c +#define IXP4XX_PCI_AHBIOBASE 0x30 +#define IXP4XX_PCI_PCIMEMBASE 0x34 +#define IXP4XX_PCI_AHBDOORBELL 0x38 +#define IXP4XX_PCI_PCIDOORBELL 0x3c +#define IXP4XX_PCI_ATPDMA0_AHBADDR 0x40 +#define IXP4XX_PCI_ATPDMA0_PCIADDR 0x44 +#define IXP4XX_PCI_ATPDMA0_LENADDR 0x48 +#define IXP4XX_PCI_ATPDMA1_AHBADDR 0x4c +#define IXP4XX_PCI_ATPDMA1_PCIADDR 0x50 +#define IXP4XX_PCI_ATPDMA1_LENADDR 0x54 + +/* CSR bit definitions */ +#define IXP4XX_PCI_CSR_HOST BIT(0) +#define IXP4XX_PCI_CSR_ARBEN BIT(1) +#define IXP4XX_PCI_CSR_ADS BIT(2) +#define IXP4XX_PCI_CSR_PDS BIT(3) +#define IXP4XX_PCI_CSR_ABE BIT(4) +#define IXP4XX_PCI_CSR_DBT BIT(5) +#define IXP4XX_PCI_CSR_ASE BIT(8) +#define IXP4XX_PCI_CSR_IC BIT(15) +#define IXP4XX_PCI_CSR_PRST BIT(16) + +/* ISR (Interrupt status) Register bit definitions */ +#define IXP4XX_PCI_ISR_PSE BIT(0) +#define IXP4XX_PCI_ISR_PFE BIT(1) +#define IXP4XX_PCI_ISR_PPE BIT(2) +#define IXP4XX_PCI_ISR_AHBE BIT(3) +#define IXP4XX_PCI_ISR_APDC BIT(4) +#define IXP4XX_PCI_ISR_PADC BIT(5) +#define IXP4XX_PCI_ISR_ADB BIT(6) +#define IXP4XX_PCI_ISR_PDB BIT(7) + +/* INTEN (Interrupt Enable) Register bit definitions */ +#define IXP4XX_PCI_INTEN_PSE BIT(0) +#define IXP4XX_PCI_INTEN_PFE BIT(1) +#define IXP4XX_PCI_INTEN_PPE BIT(2) +#define IXP4XX_PCI_INTEN_AHBE BIT(3) +#define IXP4XX_PCI_INTEN_APDC BIT(4) +#define IXP4XX_PCI_INTEN_PADC BIT(5) +#define IXP4XX_PCI_INTEN_ADB BIT(6) +#define IXP4XX_PCI_INTEN_PDB BIT(7) + +/* Shift value for byte enable on NP cmd/byte enable register */ +#define IXP4XX_PCI_NP_CBE_BESL 4 + +/* PCI commands supported by NP access unit */ +#define NP_CMD_IOREAD 0x2 +#define NP_CMD_IOWRITE 0x3 +#define NP_CMD_CONFIGREAD 0xa +#define NP_CMD_CONFIGWRITE 0xb +#define NP_CMD_MEMREAD 0x6 +#define NP_CMD_MEMWRITE 0x7 + +/* Constants for CRP access into local config space */ +#define CRP_AD_CBE_BESL 20 +#define CRP_AD_CBE_WRITE 0x00010000 + +/* Special PCI configuration space registers for this controller */ +#define IXP4XX_PCI_RTOTTO 0x40 + +struct ixp4xx_pci { + struct device *dev; + void __iomem *base; + bool errata_hammer; + bool host_mode; +}; + +/* + * The IXP4xx has a peculiar address bus that will change the + * byte order on SoC peripherals depending on whether the device + * operates in big-endian or little-endian mode. That means that + * readl() and writel() that always use little-endian access + * will not work for SoC peripherals such as the PCI controller + * when used in big-endian mode. The accesses to the individual + * PCI devices on the other hand, are always little-endian and + * can use readl() and writel(). + * + * For local AHB bus access we need to use __raw_[readl|writel]() + * to make sure that we access the SoC devices in the CPU native + * endianness. + */ +static inline u32 ixp4xx_readl(struct ixp4xx_pci *p, u32 reg) +{ + return __raw_readl(p->base + reg); +} + +static inline void ixp4xx_writel(struct ixp4xx_pci *p, u32 reg, u32 val) +{ + __raw_writel(val, p->base + reg); +} + +static int ixp4xx_pci_check_master_abort(struct ixp4xx_pci *p) +{ + u32 isr = ixp4xx_readl(p, IXP4XX_PCI_ISR); + + if (isr & IXP4XX_PCI_ISR_PFE) { + /* Make sure the master abort bit is reset */ + ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE); + dev_dbg(p->dev, "master abort detected\n"); + return -EINVAL; + } + + return 0; +} + +static int ixp4xx_pci_read(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data) +{ + ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr); + + if (p->errata_hammer) { + int i; + + /* + * PCI workaround - only works if NP PCI space reads have + * no side effects. Hammer the register and read twice 8 + * times. last one will be good. + */ + for (i = 0; i < 8; i++) { + ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd); + *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA); + *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA); + } + } else { + ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd); + *data = ixp4xx_readl(p, IXP4XX_PCI_NP_RDATA); + } + + return ixp4xx_pci_check_master_abort(p); +} + +static int ixp4xx_pci_write(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 data) +{ + ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr); + + /* Set up the write */ + ixp4xx_writel(p, IXP4XX_PCI_NP_CBE, cmd); + + /* Execute the write by writing to NP_WDATA */ + ixp4xx_writel(p, IXP4XX_PCI_NP_WDATA, data); + + return ixp4xx_pci_check_master_abort(p); +} + +static u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where) +{ + /* Root bus is always 0 in this hardware */ + if (bus_num == 0) { + /* type 0 */ + return BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) | + (where & ~3); + } else { + /* type 1 */ + return (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) | + ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1; + } +} + +/* + * CRP functions are "Controller Configuration Port" accesses + * initiated from within this driver itself to read/write PCI + * control information in the config space. + */ +static u32 ixp4xx_crp_byte_lane_enable_bits(u32 n, int size) +{ + if (size == 1) + return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL; + if (size == 2) + return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL; + if (size == 4) + return 0; + return 0xffffffff; +} + +static int ixp4xx_crp_read_config(struct ixp4xx_pci *p, int where, int size, + u32 *value) +{ + u32 n, cmd, val; + + n = where % 4; + cmd = where & ~3; + + dev_dbg(p->dev, "%s from %d size %d cmd %08x\n", + __func__, where, size, cmd); + + ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd); + val = ixp4xx_readl(p, IXP4XX_PCI_CRP_RDATA); + + val >>= (8*n); + switch (size) { + case 1: + val &= U8_MAX; + dev_dbg(p->dev, "%s read byte %02x\n", __func__, val); + break; + case 2: + val &= U16_MAX; + dev_dbg(p->dev, "%s read word %04x\n", __func__, val); + break; + case 4: + val &= U32_MAX; + dev_dbg(p->dev, "%s read long %08x\n", __func__, val); + break; + default: + /* Should not happen */ + dev_err(p->dev, "%s illegal size\n", __func__); + return PCIBIOS_DEVICE_NOT_FOUND; + } + *value = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int ixp4xx_crp_write_config(struct ixp4xx_pci *p, int where, int size, + u32 value) +{ + u32 n, cmd, val; + + n = where % 4; + cmd = ixp4xx_crp_byte_lane_enable_bits(n, size); + if (cmd == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + cmd |= where & ~3; + cmd |= CRP_AD_CBE_WRITE; + + val = value << (8*n); + + dev_dbg(p->dev, "%s to %d size %d cmd %08x val %08x\n", + __func__, where, size, cmd, val); + + ixp4xx_writel(p, IXP4XX_PCI_CRP_AD_CBE, cmd); + ixp4xx_writel(p, IXP4XX_PCI_CRP_WDATA, val); + + return PCIBIOS_SUCCESSFUL; +} + +/* + * Then follows the functions that read and write from the common PCI + * configuration space. + */ +static u32 ixp4xx_byte_lane_enable_bits(u32 n, int size) +{ + if (size == 1) + return (0xf & ~BIT(n)) << 4; + if (size == 2) + return (0xf & ~(BIT(n) | BIT(n+1))) << 4; + if (size == 4) + return 0; + return 0xffffffff; +} + +static int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *value) +{ + struct ixp4xx_pci *p = bus->sysdata; + u32 n, addr, val, cmd; + u8 bus_num = bus->number; + int ret; + + *value = 0xffffffff; + n = where % 4; + cmd = ixp4xx_byte_lane_enable_bits(n, size); + if (cmd == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + + addr = ixp4xx_config_addr(bus_num, devfn, where); + cmd |= NP_CMD_CONFIGREAD; + dev_dbg(p->dev, "read_config from %d size %d dev %d:%d:%d address: %08x cmd: %08x\n", + where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd); + + ret = ixp4xx_pci_read(p, addr, cmd, &val); + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + val >>= (8*n); + switch (size) { + case 1: + val &= U8_MAX; + dev_dbg(p->dev, "%s read byte %02x\n", __func__, val); + break; + case 2: + val &= U16_MAX; + dev_dbg(p->dev, "%s read word %04x\n", __func__, val); + break; + case 4: + val &= U32_MAX; + dev_dbg(p->dev, "%s read long %08x\n", __func__, val); + break; + default: + /* Should not happen */ + dev_err(p->dev, "%s illegal size\n", __func__); + return PCIBIOS_DEVICE_NOT_FOUND; + } + *value = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int ixp4xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 value) +{ + struct ixp4xx_pci *p = bus->sysdata; + u32 n, addr, val, cmd; + u8 bus_num = bus->number; + int ret; + + n = where % 4; + cmd = ixp4xx_byte_lane_enable_bits(n, size); + if (cmd == 0xffffffff) + return PCIBIOS_BAD_REGISTER_NUMBER; + + addr = ixp4xx_config_addr(bus_num, devfn, where); + cmd |= NP_CMD_CONFIGWRITE; + val = value << (8*n); + + dev_dbg(p->dev, "write_config_byte %#x to %d size %d dev %d:%d:%d addr: %08x cmd %08x\n", + value, where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd); + + ret = ixp4xx_pci_write(p, addr, cmd, val); + if (ret) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ixp4xx_pci_ops = { + .read = ixp4xx_pci_read_config, + .write = ixp4xx_pci_write_config, +}; + +static u32 ixp4xx_pci_addr_to_64mconf(phys_addr_t addr) +{ + u8 base; + + base = ((addr & 0xff000000) >> 24); + return (base << 24) | ((base + 1) << 16) + | ((base + 2) << 8) | (base + 3); +} + +static int ixp4xx_pci_parse_map_ranges(struct ixp4xx_pci *p) +{ + struct device *dev = p->dev; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p); + struct resource_entry *win; + struct resource *res; + phys_addr_t addr; + + win = resource_list_first_type(&bridge->windows, IORESOURCE_MEM); + if (win) { + u32 pcimembase; + + res = win->res; + addr = res->start - win->offset; + + if (res->flags & IORESOURCE_PREFETCH) + res->name = "IXP4xx PCI PRE-MEM"; + else + res->name = "IXP4xx PCI NON-PRE-MEM"; + + dev_dbg(dev, "%s window %pR, bus addr %pa\n", + res->name, res, &addr); + if (resource_size(res) != SZ_64M) { + dev_err(dev, "memory range is not 64MB\n"); + return -EINVAL; + } + + pcimembase = ixp4xx_pci_addr_to_64mconf(addr); + /* Commit configuration */ + ixp4xx_writel(p, IXP4XX_PCI_PCIMEMBASE, pcimembase); + } else { + dev_err(dev, "no AHB memory mapping defined\n"); + } + + win = resource_list_first_type(&bridge->windows, IORESOURCE_IO); + if (win) { + res = win->res; + + addr = pci_pio_to_address(res->start); + if (addr & 0xff) { + dev_err(dev, "IO mem at uneven address: %pa\n", &addr); + return -EINVAL; + } + + res->name = "IXP4xx PCI IO MEM"; + /* + * Setup I/O space location for PCI->AHB access, the + * upper 24 bits of the address goes into the lower + * 24 bits of this register. + */ + ixp4xx_writel(p, IXP4XX_PCI_AHBIOBASE, (addr >> 8)); + } else { + dev_info(dev, "no IO space AHB memory mapping defined\n"); + } + + return 0; +} + +static int ixp4xx_pci_parse_map_dma_ranges(struct ixp4xx_pci *p) +{ + struct device *dev = p->dev; + struct pci_host_bridge *bridge = pci_host_bridge_from_priv(p); + struct resource_entry *win; + struct resource *res; + phys_addr_t addr; + u32 ahbmembase; + + win = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM); + if (win) { + res = win->res; + addr = res->start - win->offset; + + if (resource_size(res) != SZ_64M) { + dev_err(dev, "DMA memory range is not 64MB\n"); + return -EINVAL; + } + + dev_dbg(dev, "DMA MEM BASE: %pa\n", &addr); + /* + * 4 PCI-to-AHB windows of 16 MB each, write the 8 high bits + * into each byte of the PCI_AHBMEMBASE register. + */ + ahbmembase = ixp4xx_pci_addr_to_64mconf(addr); + /* Commit AHB membase */ + ixp4xx_writel(p, IXP4XX_PCI_AHBMEMBASE, ahbmembase); + } else { + dev_err(dev, "no DMA memory range defined\n"); + } + + return 0; +} + +/* Only used to get context for abort handling */ +static struct ixp4xx_pci *ixp4xx_pci_abort_singleton; + +static int ixp4xx_pci_abort_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) +{ + struct ixp4xx_pci *p = ixp4xx_pci_abort_singleton; + u32 isr, status; + int ret; + + isr = ixp4xx_readl(p, IXP4XX_PCI_ISR); + ret = ixp4xx_crp_read_config(p, PCI_STATUS, 2, &status); + if (ret) { + dev_err(p->dev, "unable to read abort status\n"); + return -EINVAL; + } + + dev_err(p->dev, + "PCI: abort_handler addr = %#lx, isr = %#x, status = %#x\n", + addr, isr, status); + + /* Make sure the Master Abort bit is reset */ + ixp4xx_writel(p, IXP4XX_PCI_ISR, IXP4XX_PCI_ISR_PFE); + status |= PCI_STATUS_REC_MASTER_ABORT; + ret = ixp4xx_crp_write_config(p, PCI_STATUS, 2, status); + if (ret) + dev_err(p->dev, "unable to clear abort status bit\n"); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) { + dev_err(p->dev, "imprecise abort\n"); + regs->ARM_pc += 4; + } + + return 0; +} + +static int __init ixp4xx_pci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct ixp4xx_pci *p; + struct pci_host_bridge *host; + int ret; + u32 val; + phys_addr_t addr; + u32 basereg[4] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + }; + int i; + + host = devm_pci_alloc_host_bridge(dev, sizeof(*p)); + if (!host) + return -ENOMEM; + + host->ops = &ixp4xx_pci_ops; + p = pci_host_bridge_priv(host); + host->sysdata = p; + p->dev = dev; + dev_set_drvdata(dev, p); + + /* + * Set up quirk for erratic behaviour in the 42x variant + * when accessing config space. + */ + if (of_device_is_compatible(np, "intel,ixp42x-pci")) { + p->errata_hammer = true; + dev_info(dev, "activate hammering errata\n"); + } + + p->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(p->base)) + return PTR_ERR(p->base); + + val = ixp4xx_readl(p, IXP4XX_PCI_CSR); + p->host_mode = !!(val & IXP4XX_PCI_CSR_HOST); + dev_info(dev, "controller is in %s mode\n", + p->host_mode ? "host" : "option"); + + /* Hook in our fault handler for PCI errors */ + ixp4xx_pci_abort_singleton = p; + hook_fault_code(16+6, ixp4xx_pci_abort_handler, SIGBUS, 0, + "imprecise external abort"); + + ret = ixp4xx_pci_parse_map_ranges(p); + if (ret) + return ret; + + ret = ixp4xx_pci_parse_map_dma_ranges(p); + if (ret) + return ret; + + /* This is only configured in host mode */ + if (p->host_mode) { + addr = __pa(PAGE_OFFSET); + /* This is a noop (0x00) but explains what is going on */ + addr |= PCI_BASE_ADDRESS_SPACE_MEMORY; + + for (i = 0; i < 4; i++) { + /* Write this directly into the config space */ + ret = ixp4xx_crp_write_config(p, basereg[i], 4, addr); + if (ret) + dev_err(dev, "failed to set up PCI_BASE_ADDRESS_%d\n", i); + else + dev_info(dev, "set PCI_BASE_ADDR_%d to %pa\n", i, &addr); + addr += SZ_16M; + } + + /* + * Enable CSR window at 64 MiB to allow PCI masters to continue + * prefetching past the 64 MiB boundary, if all AHB to PCI + * windows are consecutive. + */ + ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_4, 4, addr); + if (ret) + dev_err(dev, "failed to set up PCI_BASE_ADDRESS_4\n"); + else + dev_info(dev, "set PCI_BASE_ADDR_4 to %pa\n", &addr); + + /* + * Put the IO memory window at the very end of physical memory + * at 0xfffffc00. This is when the system is trying to access IO + * memory over AHB. + */ + addr = 0xfffffc00; + addr |= PCI_BASE_ADDRESS_SPACE_IO; + ret = ixp4xx_crp_write_config(p, PCI_BASE_ADDRESS_5, 4, addr); + if (ret) + dev_err(dev, "failed to set up PCI_BASE_ADDRESS_5\n"); + else + dev_info(dev, "set PCI_BASE_ADDR_5 to %pa\n", &addr); + + /* + * Retry timeout to 0x80 + * Transfer ready timeout to 0xff + */ + ret = ixp4xx_crp_write_config(p, IXP4XX_PCI_RTOTTO, 4, + 0x000080ff); + if (ret) + dev_err(dev, "failed to set up TRDY limit\n"); + else + dev_info(dev, "set TRDY limit to 0x80ff\n"); + } + + /* Clear interrupts */ + val = IXP4XX_PCI_ISR_PSE | IXP4XX_PCI_ISR_PFE | IXP4XX_PCI_ISR_PPE | IXP4XX_PCI_ISR_AHBE; + ixp4xx_writel(p, IXP4XX_PCI_ISR, val); + + /* + * Set Initialize Complete in PCI Control Register: allow IXP4XX to + * generate PCI configuration cycles. Specify that the AHB bus is + * operating in big-endian mode. Set up byte lane swapping between + * little-endian PCI and the big-endian AHB bus. + */ + val = IXP4XX_PCI_CSR_IC | IXP4XX_PCI_CSR_ABE; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + val |= (IXP4XX_PCI_CSR_PDS | IXP4XX_PCI_CSR_ADS); + ixp4xx_writel(p, IXP4XX_PCI_CSR, val); + + ret = ixp4xx_crp_write_config(p, PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); + if (ret) + dev_err(dev, "unable to initialize master and command memory\n"); + else + dev_info(dev, "initialized as master\n"); + + pci_host_probe(host); + + return 0; +} + +static const struct of_device_id ixp4xx_pci_of_match[] = { + { + .compatible = "intel,ixp42x-pci", + }, + { + .compatible = "intel,ixp43x-pci", + }, + {}, +}; + +/* + * This driver needs to be a builtin module with suppressed bind + * attributes since the probe() is initializing a hard exception + * handler and this can only be done from __init-tagged code + * sections. This module cannot be removed and inserted at all. + */ +static struct platform_driver ixp4xx_pci_driver = { + .driver = { + .name = "ixp4xx-pci", + .suppress_bind_attrs = true, + .of_match_table = ixp4xx_pci_of_match, + }, +}; +builtin_platform_driver_probe(ixp4xx_pci_driver, ixp4xx_pci_probe); diff --git a/drivers/soc/imx/soc-imx.c b/drivers/soc/imx/soc-imx.c index 0738c0f36792..ac6d856ba228 100644 --- a/drivers/soc/imx/soc-imx.c +++ b/drivers/soc/imx/soc-imx.c @@ -70,6 +70,9 @@ static int __init imx_soc_device_init(void) case MXC_CPU_MX35: soc_id = "i.MX35"; break; + case MXC_CPU_MX50: + soc_id = "i.MX50"; + break; case MXC_CPU_MX51: ocotp_compat = "fsl,imx51-iim"; soc_id = "i.MX51"; diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c index 3c158251a58b..7bd19354982a 100644 --- a/drivers/soc/ixp4xx/ixp4xx-npe.c +++ b/drivers/soc/ixp4xx/ixp4xx-npe.c @@ -21,6 +21,8 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/soc/ixp4xx/npe.h> +#include <mach/hardware.h> +#include <linux/soc/ixp4xx/cpu.h> #define DEBUG_MSG 0 #define DEBUG_FW 0 diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c index 8c968382cea7..7149510b307e 100644 --- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c +++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c @@ -12,6 +12,8 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/soc/ixp4xx/qmgr.h> +#include <mach/hardware.h> +#include <linux/soc/ixp4xx/cpu.h> static struct qmgr_regs __iomem *qmgr_regs; static int qmgr_irq_1; diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 976dee036470..20ace654553a 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -144,6 +144,8 @@ config SOC_TEGRA_FLOWCTRL config SOC_TEGRA_PMC bool select GENERIC_PINCONF + select PM_OPP + select PM_GENERIC_DOMAINS config SOC_TEGRA_POWERGATE_BPMP def_bool y diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index 3dc54f59cafe..cd33e99249c3 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -3,9 +3,16 @@ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. */ +#define dev_fmt(fmt) "tegra-soc: " fmt + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/export.h> #include <linux/of.h> +#include <linux/pm_opp.h> #include <soc/tegra/common.h> +#include <soc/tegra/fuse.h> static const struct of_device_id tegra_machine_match[] = { { .compatible = "nvidia,tegra20", }, @@ -31,3 +38,93 @@ bool soc_is_tegra(void) return match != NULL; } + +static int tegra_core_dev_init_opp_state(struct device *dev) +{ + unsigned long rate; + struct clk *clk; + int err; + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get clk: %pe\n", clk); + return PTR_ERR(clk); + } + + rate = clk_get_rate(clk); + if (!rate) { + dev_err(dev, "failed to get clk rate\n"); + return -EINVAL; + } + + /* first dummy rate-setting initializes voltage vote */ + err = dev_pm_opp_set_rate(dev, rate); + if (err) { + dev_err(dev, "failed to initialize OPP clock: %d\n", err); + return err; + } + + return 0; +} + +/** + * devm_tegra_core_dev_init_opp_table() - initialize OPP table + * @dev: device for which OPP table is initialized + * @params: pointer to the OPP table configuration + * + * This function will initialize OPP table and sync OPP state of a Tegra SoC + * core device. + * + * Return: 0 on success or errorno. + */ +int devm_tegra_core_dev_init_opp_table(struct device *dev, + struct tegra_core_opp_params *params) +{ + u32 hw_version; + int err; + + err = devm_pm_opp_set_clkname(dev, NULL); + if (err) { + dev_err(dev, "failed to set OPP clk: %d\n", err); + return err; + } + + /* Tegra114+ doesn't support OPP yet */ + if (!of_machine_is_compatible("nvidia,tegra20") && + !of_machine_is_compatible("nvidia,tegra30")) + return -ENODEV; + + if (of_machine_is_compatible("nvidia,tegra20")) + hw_version = BIT(tegra_sku_info.soc_process_id); + else + hw_version = BIT(tegra_sku_info.soc_speedo_id); + + err = devm_pm_opp_set_supported_hw(dev, &hw_version, 1); + if (err) { + dev_err(dev, "failed to set OPP supported HW: %d\n", err); + return err; + } + + /* + * Older device-trees have an empty OPP table, we will get + * -ENODEV from devm_pm_opp_of_add_table() in this case. + */ + err = devm_pm_opp_of_add_table(dev); + if (err) { + if (err == -ENODEV) + dev_err_once(dev, "OPP table not found, please update device-tree\n"); + else + dev_err(dev, "failed to add OPP table: %d\n", err); + + return err; + } + + if (params->init_state) { + err = tegra_core_dev_init_opp_state(dev); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(devm_tegra_core_dev_init_opp_table); diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 94b60a692b51..3d9da3d359da 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -489,10 +489,8 @@ static int __init tegra_init_fuse(void) size_t size = sizeof(*fuse->lookups) * fuse->soc->num_lookups; fuse->lookups = kmemdup(fuse->soc->lookups, size, GFP_KERNEL); - if (!fuse->lookups) - return -ENOMEM; - - nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups); + if (fuse->lookups) + nvmem_add_cell_lookups(fuse->lookups, fuse->soc->num_lookups); } return 0; diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 9ea7f0168457..c1aa7815bd6e 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -37,7 +37,8 @@ defined(CONFIG_ARCH_TEGRA_132_SOC) || \ defined(CONFIG_ARCH_TEGRA_210_SOC) || \ defined(CONFIG_ARCH_TEGRA_186_SOC) || \ - defined(CONFIG_ARCH_TEGRA_194_SOC) + defined(CONFIG_ARCH_TEGRA_194_SOC) || \ + defined(CONFIG_ARCH_TEGRA_234_SOC) static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) { if (WARN_ON(!fuse->base)) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 4a582eae82ef..ea62f84d1c8b 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -38,6 +38,7 @@ #include <linux/pinctrl/pinctrl.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> +#include <linux/pm_opp.h> #include <linux/reboot.h> #include <linux/regmap.h> #include <linux/reset.h> @@ -428,6 +429,9 @@ struct tegra_pmc { struct irq_chip irq; struct notifier_block clk_nb; + + bool core_domain_state_synced; + bool core_domain_registered; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { @@ -1297,12 +1301,107 @@ free_mem: return err; } +bool tegra_pmc_core_domain_state_synced(void) +{ + return pmc->core_domain_state_synced; +} + +static int +tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd, + unsigned int level) +{ + struct dev_pm_opp *opp; + int err; + + opp = dev_pm_opp_find_level_ceil(&genpd->dev, &level); + if (IS_ERR(opp)) { + dev_err(&genpd->dev, "failed to find OPP for level %u: %pe\n", + level, opp); + return PTR_ERR(opp); + } + + mutex_lock(&pmc->powergates_lock); + err = dev_pm_opp_set_opp(pmc->dev, opp); + mutex_unlock(&pmc->powergates_lock); + + dev_pm_opp_put(opp); + + if (err) { + dev_err(&genpd->dev, "failed to set voltage to %duV: %d\n", + level, err); + return err; + } + + return 0; +} + +static unsigned int +tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd, + struct dev_pm_opp *opp) +{ + return dev_pm_opp_get_level(opp); +} + +static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) +{ + struct generic_pm_domain *genpd; + const char *rname = "core"; + int err; + + genpd = devm_kzalloc(pmc->dev, sizeof(*genpd), GFP_KERNEL); + if (!genpd) + return -ENOMEM; + + genpd->name = np->name; + genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; + genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; + + err = devm_pm_opp_set_regulators(pmc->dev, &rname, 1); + if (err) + return dev_err_probe(pmc->dev, err, + "failed to set core OPP regulator\n"); + + err = pm_genpd_init(genpd, NULL, false); + if (err) { + dev_err(pmc->dev, "failed to init core genpd: %d\n", err); + return err; + } + + err = of_genpd_add_provider_simple(np, genpd); + if (err) { + dev_err(pmc->dev, "failed to add core genpd: %d\n", err); + goto remove_genpd; + } + + pmc->core_domain_registered = true; + + return 0; + +remove_genpd: + pm_genpd_remove(genpd); + + return err; +} + static int tegra_powergate_init(struct tegra_pmc *pmc, struct device_node *parent) { + struct of_phandle_args child_args, parent_args; struct device_node *np, *child; int err = 0; + /* + * Core power domain is the parent of powergate domains, hence it + * should be registered first. + */ + np = of_get_child_by_name(parent, "core-domain"); + if (np) { + err = tegra_pmc_core_pd_add(pmc, np); + of_node_put(np); + if (err) + return err; + } + np = of_get_child_by_name(parent, "powergates"); if (!np) return 0; @@ -1313,6 +1412,21 @@ static int tegra_powergate_init(struct tegra_pmc *pmc, of_node_put(child); break; } + + if (of_parse_phandle_with_args(child, "power-domains", + "#power-domain-cells", + 0, &parent_args)) + continue; + + child_args.np = child; + child_args.args_count = 0; + + err = of_genpd_add_subdomain(&parent_args, &child_args); + of_node_put(parent_args.np); + if (err) { + of_node_put(child); + break; + } } of_node_put(np); @@ -1356,6 +1470,12 @@ static void tegra_powergate_remove_all(struct device_node *parent) } of_node_put(np); + + np = of_get_child_by_name(parent, "core-domain"); + if (np) { + of_genpd_del_provider(np); + of_genpd_remove_last(np); + } } static const struct tegra_io_pad_soc * @@ -3667,6 +3787,29 @@ static const struct of_device_id tegra_pmc_match[] = { { } }; +static void tegra_pmc_sync_state(struct device *dev) +{ + int err; + + /* + * Older device-trees don't have core PD, and thus, there are + * no dependencies that will block the state syncing. We shouldn't + * mark the domain as synced in this case. + */ + if (!pmc->core_domain_registered) + return; + + pmc->core_domain_state_synced = true; + + /* this is a no-op if core regulator isn't used */ + mutex_lock(&pmc->powergates_lock); + err = dev_pm_opp_sync_regulators(dev); + mutex_unlock(&pmc->powergates_lock); + + if (err) + dev_err(dev, "failed to sync regulators: %d\n", err); +} + static struct platform_driver tegra_pmc_driver = { .driver = { .name = "tegra-pmc", @@ -3675,6 +3818,7 @@ static struct platform_driver tegra_pmc_driver = { #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) .pm = &tegra_pmc_pm_ops, #endif + .sync_state = tegra_pmc_sync_state, }, .probe = tegra_pmc_probe, }; diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index 367a71a3cd10..b8ce9fd0650d 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -12,16 +12,22 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/of.h> +#include <linux/reboot.h> #include <linux/regulator/coupler.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <soc/tegra/pmc.h> + struct tegra_regulator_coupler { struct regulator_coupler coupler; struct regulator_dev *core_rdev; struct regulator_dev *cpu_rdev; struct regulator_dev *rtc_rdev; - int core_min_uV; + struct notifier_block reboot_notifier; + int core_min_uV, cpu_min_uV; + bool sys_reboot_mode_req; + bool sys_reboot_mode; }; static inline struct tegra_regulator_coupler * @@ -38,6 +44,21 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra, int core_cur_uV; int err; + /* + * Tegra20 SoC has critical DVFS-capable devices that are + * permanently-active or active at a boot time, like EMC + * (DRAM controller) or Display controller for example. + * + * The voltage of a CORE SoC power domain shall not be dropped below + * a minimum level, which is determined by device's clock rate. + * This means that we can't fully allow CORE voltage scaling until + * the state of all DVFS-critical CORE devices is synced. + */ + if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) { + pr_info_once("voltage state synced\n"); + return 0; + } + if (tegra->core_min_uV > 0) return tegra->core_min_uV; @@ -58,7 +79,7 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra, */ tegra->core_min_uV = core_max_uV; - pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV); + pr_info("core voltage initialized to %duV\n", tegra->core_min_uV); return tegra->core_min_uV; } @@ -242,6 +263,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (cpu_uV < 0) return cpu_uV; + /* store boot voltage level */ + if (!tegra->cpu_min_uV) + tegra->cpu_min_uV = cpu_uV; + /* * CPU's regulator may not have any consumers, hence the voltage * must not be changed in that case because CPU simply won't @@ -250,6 +275,10 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (!cpu_min_uV_consumers) cpu_min_uV = cpu_uV; + /* restore boot voltage level */ + if (tegra->sys_reboot_mode) + cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + if (cpu_min_uV > cpu_uV) { err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, cpu_uV, cpu_min_uV); @@ -290,6 +319,8 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EINVAL; } + tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + if (rdev == cpu_rdev) return tegra20_cpu_voltage_update(tegra, cpu_rdev, core_rdev, rtc_rdev); @@ -303,6 +334,51 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EPERM; } +static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, + bool sys_reboot_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev) + return 0; + + WRITE_ONCE(tegra->sys_reboot_mode_req, true); + + /* + * Some devices use CPU soft-reboot method and in this case we + * should ensure that voltages are sane for the reboot by restoring + * the minimum boot levels. + */ + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode); + + return 0; +} + +static int tegra20_regulator_reboot(struct notifier_block *notifier, + unsigned long event, void *cmd) +{ + struct tegra_regulator_coupler *tegra; + int ret; + + if (event != SYS_RESTART) + return NOTIFY_DONE; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + reboot_notifier); + + ret = tegra20_regulator_prepare_reboot(tegra, true); + + return notifier_from_errno(ret); +} + static int tegra20_regulator_attach(struct regulator_coupler *coupler, struct regulator_dev *rdev) { @@ -335,6 +411,14 @@ static int tegra20_regulator_detach(struct regulator_coupler *coupler, { struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler); + /* + * We don't expect regulators to be decoupled during reboot, + * this may race with the reboot handler and shouldn't ever + * happen in practice. + */ + if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING)) + return -EPERM; + if (tegra->core_rdev == rdev) { tegra->core_rdev = NULL; return 0; @@ -359,13 +443,19 @@ static struct tegra_regulator_coupler tegra20_coupler = { .detach_regulator = tegra20_regulator_detach, .balance_voltage = tegra20_regulator_balance_voltage, }, + .reboot_notifier.notifier_call = tegra20_regulator_reboot, }; static int __init tegra_regulator_coupler_init(void) { + int err; + if (!of_machine_is_compatible("nvidia,tegra20")) return 0; + err = register_reboot_notifier(&tegra20_coupler.reboot_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra20_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index 0e776b20f625..e74bbc9c7859 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -12,17 +12,22 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/of.h> +#include <linux/reboot.h> #include <linux/regulator/coupler.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <soc/tegra/fuse.h> +#include <soc/tegra/pmc.h> struct tegra_regulator_coupler { struct regulator_coupler coupler; struct regulator_dev *core_rdev; struct regulator_dev *cpu_rdev; - int core_min_uV; + struct notifier_block reboot_notifier; + int core_min_uV, cpu_min_uV; + bool sys_reboot_mode_req; + bool sys_reboot_mode; }; static inline struct tegra_regulator_coupler * @@ -39,6 +44,21 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra, int core_cur_uV; int err; + /* + * Tegra30 SoC has critical DVFS-capable devices that are + * permanently-active or active at a boot time, like EMC + * (DRAM controller) or Display controller for example. + * + * The voltage of a CORE SoC power domain shall not be dropped below + * a minimum level, which is determined by device's clock rate. + * This means that we can't fully allow CORE voltage scaling until + * the state of all DVFS-critical CORE devices is synced. + */ + if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) { + pr_info_once("voltage state synced\n"); + return 0; + } + if (tegra->core_min_uV > 0) return tegra->core_min_uV; @@ -59,7 +79,7 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra, */ tegra->core_min_uV = core_max_uV; - pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV); + pr_info("core voltage initialized to %duV\n", tegra->core_min_uV); return tegra->core_min_uV; } @@ -172,6 +192,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (cpu_uV < 0) return cpu_uV; + /* store boot voltage level */ + if (!tegra->cpu_min_uV) + tegra->cpu_min_uV = cpu_uV; + /* * CPU's regulator may not have any consumers, hence the voltage * must not be changed in that case because CPU simply won't @@ -195,6 +219,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* restore boot voltage level */ + if (tegra->sys_reboot_mode) + cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + if (core_min_limited_uV > core_uV) { pr_err("core voltage constraint violated: %d %d %d\n", core_uV, core_min_limited_uV, cpu_uV); @@ -263,9 +291,56 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler, return -EINVAL; } + tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + return tegra30_voltage_update(tegra, cpu_rdev, core_rdev); } +static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, + bool sys_reboot_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->cpu_rdev) + return 0; + + WRITE_ONCE(tegra->sys_reboot_mode_req, true); + + /* + * Some devices use CPU soft-reboot method and in this case we + * should ensure that voltages are sane for the reboot by restoring + * the minimum boot levels. + */ + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode); + + return 0; +} + +static int tegra30_regulator_reboot(struct notifier_block *notifier, + unsigned long event, void *cmd) +{ + struct tegra_regulator_coupler *tegra; + int ret; + + if (event != SYS_RESTART) + return NOTIFY_DONE; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + reboot_notifier); + + ret = tegra30_regulator_prepare_reboot(tegra, true); + + return notifier_from_errno(ret); +} + static int tegra30_regulator_attach(struct regulator_coupler *coupler, struct regulator_dev *rdev) { @@ -292,6 +367,14 @@ static int tegra30_regulator_detach(struct regulator_coupler *coupler, { struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler); + /* + * We don't expect regulators to be decoupled during reboot, + * this may race with the reboot handler and shouldn't ever + * happen in practice. + */ + if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING)) + return -EPERM; + if (tegra->core_rdev == rdev) { tegra->core_rdev = NULL; return 0; @@ -311,13 +394,19 @@ static struct tegra_regulator_coupler tegra30_coupler = { .detach_regulator = tegra30_regulator_detach, .balance_voltage = tegra30_regulator_balance_voltage, }, + .reboot_notifier.notifier_call = tegra30_regulator_reboot, }; static int __init tegra_regulator_coupler_init(void) { + int err; + if (!of_machine_is_compatible("nvidia,tegra30")) return 0; + err = register_reboot_notifier(&tegra30_coupler.reboot_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra30_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); diff --git a/include/linux/platform_data/pata_ixp4xx_cf.h b/include/linux/platform_data/pata_ixp4xx_cf.h new file mode 100644 index 000000000000..601ba97fef57 --- /dev/null +++ b/include/linux/platform_data/pata_ixp4xx_cf.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PLATFORM_DATA_PATA_IXP4XX_H +#define __PLATFORM_DATA_PATA_IXP4XX_H + +#include <linux/types.h> + +/* + * This structure provide a means for the board setup code + * to give information to th pata_ixp4xx driver. It is + * passed as platform_data. + */ +struct ixp4xx_pata_data { + volatile u32 *cs0_cfg; + volatile u32 *cs1_cfg; + unsigned long cs0_bits; + unsigned long cs1_bits; + void __iomem *cs0; + void __iomem *cs1; +}; + +#endif diff --git a/include/linux/soc/ixp4xx/cpu.h b/include/linux/soc/ixp4xx/cpu.h new file mode 100644 index 000000000000..88bd8de0e803 --- /dev/null +++ b/include/linux/soc/ixp4xx/cpu.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * IXP4XX cpu type detection + * + * Copyright (C) 2007 MontaVista Software, Inc. + */ + +#ifndef __SOC_IXP4XX_CPU_H__ +#define __SOC_IXP4XX_CPU_H__ + +#include <linux/io.h> +#ifdef CONFIG_ARM +#include <asm/cputype.h> +#endif + +/* Processor id value in CP15 Register 0 */ +#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */ +#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0 + +#define IXP43X_PROCESSOR_ID_VALUE 0x69054040 +#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0 + +#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */ +#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0 + +/* "fuse" bits of IXP_EXP_CFG2 */ +/* All IXP4xx CPUs */ +#define IXP4XX_FEATURE_RCOMP (1 << 0) +#define IXP4XX_FEATURE_USB_DEVICE (1 << 1) +#define IXP4XX_FEATURE_HASH (1 << 2) +#define IXP4XX_FEATURE_AES (1 << 3) +#define IXP4XX_FEATURE_DES (1 << 4) +#define IXP4XX_FEATURE_HDLC (1 << 5) +#define IXP4XX_FEATURE_AAL (1 << 6) +#define IXP4XX_FEATURE_HSS (1 << 7) +#define IXP4XX_FEATURE_UTOPIA (1 << 8) +#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9) +#define IXP4XX_FEATURE_NPEC_ETH (1 << 10) +#define IXP4XX_FEATURE_RESET_NPEA (1 << 11) +#define IXP4XX_FEATURE_RESET_NPEB (1 << 12) +#define IXP4XX_FEATURE_RESET_NPEC (1 << 13) +#define IXP4XX_FEATURE_PCI (1 << 14) +#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16) +#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22) +#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \ + IXP4XX_FEATURE_USB_DEVICE | \ + IXP4XX_FEATURE_HASH | \ + IXP4XX_FEATURE_AES | \ + IXP4XX_FEATURE_DES | \ + IXP4XX_FEATURE_HDLC | \ + IXP4XX_FEATURE_AAL | \ + IXP4XX_FEATURE_HSS | \ + IXP4XX_FEATURE_UTOPIA | \ + IXP4XX_FEATURE_NPEB_ETH0 | \ + IXP4XX_FEATURE_NPEC_ETH | \ + IXP4XX_FEATURE_RESET_NPEA | \ + IXP4XX_FEATURE_RESET_NPEB | \ + IXP4XX_FEATURE_RESET_NPEC | \ + IXP4XX_FEATURE_PCI | \ + IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \ + IXP4XX_FEATURE_XSCALE_MAX_FREQ) + + +/* IXP43x/46x CPUs */ +#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15) +#define IXP4XX_FEATURE_USB_HOST (1 << 18) +#define IXP4XX_FEATURE_NPEA_ETH (1 << 19) +#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \ + IXP4XX_FEATURE_ECC_TIMESYNC | \ + IXP4XX_FEATURE_USB_HOST | \ + IXP4XX_FEATURE_NPEA_ETH) + +/* IXP46x CPU (including IXP455) only */ +#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20) +#define IXP4XX_FEATURE_RSA (1 << 21) +#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \ + IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ + IXP4XX_FEATURE_RSA) + +#ifdef CONFIG_ARCH_IXP4XX +#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \ + IXP42X_PROCESSOR_ID_VALUE) +#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \ + IXP42X_PROCESSOR_ID_VALUE) +#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \ + IXP43X_PROCESSOR_ID_VALUE) +#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \ + IXP46X_PROCESSOR_ID_VALUE) + +u32 ixp4xx_read_feature_bits(void); +void ixp4xx_write_feature_bits(u32 value); +#else +#define cpu_is_ixp42x_rev_a0() 0 +#define cpu_is_ixp42x() 0 +#define cpu_is_ixp43x() 0 +#define cpu_is_ixp46x() 0 +static inline u32 ixp4xx_read_feature_bits(void) +{ + return 0; +} +static inline void ixp4xx_write_feature_bits(u32 value) +{ +} +#endif + +#endif /* _ASM_ARCH_CPU_H */ diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h index fc9250fb3133..aa840ed043e1 100644 --- a/include/linux/soc/samsung/exynos-regs-pmu.h +++ b/include/linux/soc/samsung/exynos-regs-pmu.h @@ -611,12 +611,6 @@ #define EXYNOS5420_FSYS2_OPTION 0x4168 #define EXYNOS5420_PSGEN_OPTION 0x4188 -/* For EXYNOS_CENTRAL_SEQ_OPTION */ -#define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 BIT(16) -#define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 BUT(17) -#define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 BIT(24) -#define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 BIT(25) - #define EXYNOS5420_ARM_USE_STANDBY_WFI0 BIT(4) #define EXYNOS5420_ARM_USE_STANDBY_WFI1 BIT(5) #define EXYNOS5420_ARM_USE_STANDBY_WFI2 BIT(6) diff --git a/include/soc/imx/cpu.h b/include/soc/imx/cpu.h index 42d6aeb951fa..0bf610acafd0 100644 --- a/include/soc/imx/cpu.h +++ b/include/soc/imx/cpu.h @@ -9,6 +9,7 @@ #define MXC_CPU_MX27 27 #define MXC_CPU_MX31 31 #define MXC_CPU_MX35 35 +#define MXC_CPU_MX50 50 #define MXC_CPU_MX51 51 #define MXC_CPU_MX53 53 #define MXC_CPU_IMX6SL 0x60 diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h index 98027a76ce3d..af41ad80ec21 100644 --- a/include/soc/tegra/common.h +++ b/include/soc/tegra/common.h @@ -6,6 +6,37 @@ #ifndef __SOC_TEGRA_COMMON_H__ #define __SOC_TEGRA_COMMON_H__ +#include <linux/errno.h> +#include <linux/types.h> + +struct device; + +/** + * Tegra SoC core device OPP table configuration + * + * @init_state: pre-initialize OPP state of a device + */ +struct tegra_core_opp_params { + bool init_state; +}; + +#ifdef CONFIG_ARCH_TEGRA bool soc_is_tegra(void); +int devm_tegra_core_dev_init_opp_table(struct device *dev, + struct tegra_core_opp_params *params); +#else +static inline bool soc_is_tegra(void) +{ + return false; +} + +static inline int +devm_tegra_core_dev_init_opp_table(struct device *dev, + struct tegra_core_opp_params *params) +{ + return -ENODEV; +} +#endif + #endif /* __SOC_TEGRA_COMMON_H__ */ diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 78cbc787a4dc..990701f788bc 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -52,14 +52,28 @@ struct tegra_sku_info { enum tegra_revision revision; }; +#ifdef CONFIG_ARCH_TEGRA +extern struct tegra_sku_info tegra_sku_info; u32 tegra_read_straps(void); u32 tegra_read_ram_code(void); int tegra_fuse_readl(unsigned long offset, u32 *value); - -#ifdef CONFIG_ARCH_TEGRA -extern struct tegra_sku_info tegra_sku_info; #else static struct tegra_sku_info tegra_sku_info __maybe_unused; + +static inline u32 tegra_read_straps(void) +{ + return 0; +} + +static inline u32 tegra_read_ram_code(void) +{ + return 0; +} + +static inline int tegra_fuse_readl(unsigned long offset, u32 *value) +{ + return -ENODEV; +} #endif struct device *tegra_soc_device_register(void); diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index 361cb64246f7..d186bccd125d 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -171,6 +171,8 @@ int tegra_io_rail_power_off(unsigned int id); void tegra_pmc_set_suspend_mode(enum tegra_suspend_mode mode); void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode); +bool tegra_pmc_core_domain_state_synced(void); + #else static inline int tegra_powergate_power_on(unsigned int id) { @@ -227,6 +229,11 @@ static inline void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode) { } +static inline bool tegra_pmc_core_domain_state_synced(void) +{ + return false; +} + #endif /* CONFIG_SOC_TEGRA_PMC */ #if defined(CONFIG_SOC_TEGRA_PMC) && defined(CONFIG_PM_SLEEP) |