diff options
Diffstat (limited to 'arch')
687 files changed, 20758 insertions, 7048 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 643567258f92..c8424a85bc04 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -320,24 +320,6 @@ config ARCH_MULTIPLATFORM select SPARSE_IRQ select USE_OF -config ARCH_INTEGRATOR - bool "ARM Ltd. Integrator family" - select ARM_AMBA - select ARM_PATCH_PHYS_VIRT if MMU - select AUTO_ZRELADDR - select COMMON_CLK - select COMMON_CLK_VERSATILE - select GENERIC_CLOCKEVENTS - select HAVE_TCM - select ICST - select MULTI_IRQ_HANDLER - select PLAT_VERSATILE - select SPARSE_IRQ - select USE_OF - select VERSATILE_FPGA_IRQ - help - Support for ARM's Integrator platform. - config ARCH_REALVIEW bool "ARM Ltd. RealView family" select ARCH_WANT_OPTIONAL_GPIOLIB @@ -350,6 +332,7 @@ config ARCH_REALVIEW select ICST select NEED_MACH_MEMORY_H select PLAT_VERSATILE + select PLAT_VERSATILE_SCHED_CLOCK help This enables support for ARM Ltd RealView boards. @@ -365,6 +348,7 @@ config ARCH_VERSATILE select ICST select PLAT_VERSATILE select PLAT_VERSATILE_CLOCK + select PLAT_VERSATILE_SCHED_CLOCK select VERSATILE_FPGA_IRQ help This enables support for ARM Ltd Versatile board. @@ -855,6 +839,8 @@ config ARCH_VIRT # source "arch/arm/mach-mvebu/Kconfig" +source "arch/arm/mach-asm9260/Kconfig" + source "arch/arm/mach-at91/Kconfig" source "arch/arm/mach-axxia/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 6a4ee008b092..f9295a4e1036 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -93,6 +93,27 @@ choice prompt "Kernel low-level debugging port" depends on DEBUG_LL + config DEBUG_ASM9260_UART + bool "Kernel low-level debugging via asm9260 UART" + depends on MACH_ASM9260 + help + Say Y here if you want the debug print routines to direct + their output to an UART or USART port on asm9260 based + machines. + + DEBUG_UART_PHYS | DEBUG_UART_VIRT + + 0x80000000 | 0xf0000000 | UART0 + 0x80004000 | 0xf0004000 | UART1 + 0x80008000 | 0xf0008000 | UART2 + 0x8000c000 | 0xf000c000 | UART3 + 0x80010000 | 0xf0010000 | UART4 + 0x80014000 | 0xf0014000 | UART5 + 0x80018000 | 0xf0018000 | UART6 + 0x8001c000 | 0xf001c000 | UART7 + 0x80020000 | 0xf0020000 | UART8 + 0x80024000 | 0xf0024000 | UART9 + config AT91_DEBUG_LL_DBGU0 bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl" depends on HAVE_AT91_DBGU0 @@ -113,7 +134,7 @@ choice config DEBUG_BCM_5301X bool "Kernel low-level debugging on BCM5301X UART1" depends on ARCH_BCM_5301X - select DEBUG_UART_PL01X + select DEBUG_UART_8250 config DEBUG_BCM_KONA_UART bool "Kernel low-level debugging messages via BCM KONA UART" @@ -664,6 +685,64 @@ choice Say Y here if you want kernel low-level debugging support on Rockchip RK32xx based platforms. + config DEBUG_R7S72100_SCIF2 + bool "Kernel low-level debugging messages via SCIF2 on R7S72100" + depends on ARCH_R7S72100 + help + Say Y here if you want kernel low-level debugging support + via SCIF2 on Renesas RZ/A1H (R7S72100). + + config DEBUG_RCAR_GEN1_SCIF0 + bool "Kernel low-level debugging messages via SCIF0 on R8A7778" + depends on ARCH_R8A7778 + help + Say Y here if you want kernel low-level debugging support + via SCIF0 on Renesas R-Car M1A (R8A7778). + + config DEBUG_RCAR_GEN1_SCIF2 + bool "Kernel low-level debugging messages via SCIF2 on R8A7779" + depends on ARCH_R8A7779 + help + Say Y here if you want kernel low-level debugging support + via SCIF2 on Renesas R-Car H1 (R8A7779). + + config DEBUG_RCAR_GEN2_SCIF0 + bool "Kernel low-level debugging messages via SCIF0 on R8A7790/R8A7791/R8A7793)" + depends on ARCH_R8A7790 || ARCH_R8A7791 || ARCH_R8A7793 + help + Say Y here if you want kernel low-level debugging support + via SCIF0 on Renesas R-Car H2 (R8A7790), M2-W (R8A7791), or + M2-N (R8A7793). + + config DEBUG_RCAR_GEN2_SCIF2 + bool "Kernel low-level debugging messages via SCIF2 on R8A7794" + depends on ARCH_R8A7794 + help + Say Y here if you want kernel low-level debugging support + via SCIF2 on Renesas R-Car E2 (R8A7794). + + config DEBUG_RMOBILE_SCIFA0 + bool "Kernel low-level debugging messages via SCIFA0 on R8A73A4/SH7372" + depends on ARCH_R8A73A4 || ARCH_SH7372 + help + Say Y here if you want kernel low-level debugging support + via SCIFA0 on Renesas R-Mobile APE6 (R8A73A4) or SH-Mobile + AP4 (SH7372). + + config DEBUG_RMOBILE_SCIFA1 + bool "Kernel low-level debugging messages via SCIFA1 on R8A7740" + depends on ARCH_R8A7740 + help + Say Y here if you want kernel low-level debugging support + via SCIFA1 on Renesas R-Mobile A1 (R8A7740). + + config DEBUG_RMOBILE_SCIFA4 + bool "Kernel low-level debugging messages via SCIFA4 on SH73A0" + depends on ARCH_SH73A0 + help + Say Y here if you want kernel low-level debugging support + via SCIFA4 on Renesas SH-Mobile AG5 (SH73A0). + config DEBUG_S3C_UART0 depends on PLAT_SAMSUNG select DEBUG_EXYNOS_UART if ARCH_EXYNOS @@ -734,6 +813,14 @@ choice their output to UART 2. The port must have been initialised by the boot-loader before use. + config DEBUG_SA1100 + depends on ARCH_SA1100 + bool "Use SA1100 UARTs for low-level debug" + help + Say Y here if you want kernel low-level debugging support + on SA-11x0 UART ports. The kernel will check for the first + enabled UART in a sequence 3-1-2. + config DEBUG_SOCFPGA_UART depends on ARCH_SOCFPGA bool "Use SOCFPGA UART for low-level debug" @@ -742,6 +829,14 @@ choice Say Y here if you want kernel low-level debugging support on SOCFPGA based platforms. + config DEBUG_SUN9I_UART0 + bool "Kernel low-level debugging messages via sun9i UART0" + depends on MACH_SUN9I + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + on Allwinner A80 based platforms on the UART0. + config DEBUG_SUNXI_UART0 bool "Kernel low-level debugging messages via sunXi UART0" depends on ARCH_SUNXI @@ -877,6 +972,22 @@ choice Say Y here if you want kernel low-level debugging support for Mediatek mt6589 based platforms on UART0. + config DEBUG_MT8127_UART0 + bool "Mediatek mt8127 UART0" + depends on ARCH_MEDIATEK + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for Mediatek mt8127 based platforms on UART0. + + config DEBUG_MT8135_UART3 + bool "Mediatek mt8135 UART3" + depends on ARCH_MEDIATEK + select DEBUG_UART_8250 + help + Say Y here if you want kernel low-level debugging support + for Mediatek mt8135 based platforms on UART3. + config DEBUG_VEXPRESS_UART0_DETECT bool "Autodetect UART0 on Versatile Express Cortex-A core tiles" depends on ARCH_VEXPRESS && CPU_CP15_MMU @@ -1052,7 +1163,9 @@ config DEBUG_STI_UART config DEBUG_LL_INCLUDE string + default "debug/sa1100.S" if DEBUG_SA1100 default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250 + default "debug/asm9260.S" if DEBUG_ASM9260_UART default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2 default "debug/meson.S" if DEBUG_MESON_UARTAO default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X @@ -1072,6 +1185,14 @@ config DEBUG_LL_INCLUDE DEBUG_IMX6SX_UART default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART + default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF2 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF0 + default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF2 + default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA0 + default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA1 + default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA4 default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART default "debug/s5pv210.S" if DEBUG_S5PV210_UART default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1 @@ -1117,6 +1238,7 @@ config DEBUG_UART_PHYS default 0x02530c00 if DEBUG_KEYSTONE_UART0 default 0x02531000 if DEBUG_KEYSTONE_UART1 default 0x03010fe0 if ARCH_RPC + default 0x07000000 if DEBUG_SUN9I_UART0 default 0x10009000 if DEBUG_REALVIEW_STD_PORT || \ DEBUG_VEXPRESS_UART0_CA9 default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT @@ -1124,7 +1246,9 @@ config DEBUG_UART_PHYS default 0x10126000 if DEBUG_RK3X_UART1 default 0x101f1000 if ARCH_VERSATILE default 0x101fb000 if DEBUG_NOMADIK_UART + default 0x11002000 if DEBUG_MT8127_UART0 default 0x11006000 if DEBUG_MT6589_UART0 + default 0x11009000 if DEBUG_MT8135_UART3 default 0x16000000 if ARCH_INTEGRATOR default 0x18000300 if DEBUG_BCM_5301X default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1 @@ -1146,6 +1270,7 @@ config DEBUG_UART_PHYS default 0x78000000 if DEBUG_CNS3XXX default 0x7c0003f8 if FOOTBRIDGE default 0x78000000 if DEBUG_CNS3XXX + default 0x80010000 if DEBUG_ASM9260_UART default 0x80070000 if DEBUG_IMX23_UART default 0x80074000 if DEBUG_IMX28_UART default 0x80230000 if DEBUG_PICOXCELL_UART @@ -1163,6 +1288,12 @@ config DEBUG_UART_PHYS default 0xd4018000 if DEBUG_MMP_UART3 default 0xe0000000 if ARCH_SPEAR13XX default 0xe4007000 if DEBUG_HIP04_UART + default 0xe6c40000 if DEBUG_RMOBILE_SCIFA0 + default 0xe6c50000 if DEBUG_RMOBILE_SCIFA1 + default 0xe6c80000 if DEBUG_RMOBILE_SCIFA4 + default 0xe6e58000 if DEBUG_RCAR_GEN2_SCIF2 + default 0xe6e60000 if DEBUG_RCAR_GEN2_SCIF0 + default 0xe8008000 if DEBUG_R7S72100_SCIF2 default 0xf0000be0 if ARCH_EBSA110 default 0xf040ab00 if DEBUG_BRCMSTB_UART default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE @@ -1176,32 +1307,42 @@ config DEBUG_UART_PHYS default 0xff690000 if DEBUG_RK32_UART2 default 0xffc02000 if DEBUG_SOCFPGA_UART default 0xffd82340 if ARCH_IOP13XX + default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0 + default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2 default 0xfff36000 if DEBUG_HIGHBANK_UART default 0xfffe8600 if DEBUG_UART_BCM63XX default 0xfffff700 if ARCH_IOP33X depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_LL_UART_EFM32 || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ - DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ - DEBUG_UART_BCM63XX + DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \ + DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \ + DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ + DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ + DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \ + DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART config DEBUG_UART_VIRT hex "Virtual base address of debug UART" default 0xe0010fe0 if ARCH_RPC default 0xe1000000 if DEBUG_MSM_UART default 0xf0000be0 if ARCH_EBSA110 + default 0xf0010000 if DEBUG_ASM9260_UART default 0xf01fb000 if DEBUG_NOMADIK_UART default 0xf0201000 if DEBUG_BCM2835 default 0xf1000300 if DEBUG_BCM_5301X + default 0xf1002000 if DEBUG_MT8127_UART0 default 0xf1006000 if DEBUG_MT6589_UART0 + default 0xf1009000 if DEBUG_MT8135_UART3 default 0xf11f1000 if ARCH_VERSATILE default 0xf1600000 if ARCH_INTEGRATOR default 0xf1c28000 if DEBUG_SUNXI_UART0 default 0xf1c28400 if DEBUG_SUNXI_UART1 default 0xf1f02800 if DEBUG_SUNXI_R_UART - default 0xf2100000 if DEBUG_PXA_UART1 + default 0xf6200000 if DEBUG_PXA_UART1 default 0xf4090000 if ARCH_LPC32XX default 0xf4200000 if ARCH_GEMINI + default 0xf7000000 if DEBUG_SUN9I_UART0 default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \ DEBUG_S3C2410_UART0) default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \ @@ -1257,12 +1398,12 @@ config DEBUG_UART_VIRT depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ - DEBUG_UART_BCM63XX + DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART config DEBUG_UART_8250_SHIFT int "Register offset shift for the 8250 debug UART" depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250 - default 0 if FOOTBRIDGE || ARCH_IOP32X + default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X default 2 config DEBUG_UART_8250_WORD diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 034a94904d69..c1785eec2cf7 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -312,8 +312,12 @@ $(INSTALL_TARGETS): $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@ PHONY += dtbs dtbs_install -dtbs dtbs_install: prepare scripts - $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@ + +dtbs: prepare scripts + $(Q)$(MAKE) $(build)=$(boot)/dts + +dtbs_install: + $(Q)$(MAKE) $(dtbinst)=$(boot)/dts # We use MRPROPER_FILES and CLEAN_FILES now archclean: diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 413fd94b5301..68be9017593d 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -397,8 +397,7 @@ dtb_check_done: add sp, sp, r6 #endif - tst r4, #1 - bleq cache_clean_flush + bl cache_clean_flush adr r0, BSYM(restart) add r0, r0, r6 @@ -1047,6 +1046,8 @@ cache_clean_flush: b call_cache_fn __armv4_mpu_cache_flush: + tst r4, #1 + movne pc, lr mov r2, #1 mov r3, #0 mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache @@ -1064,6 +1065,8 @@ __armv4_mpu_cache_flush: mov pc, lr __fa526_cache_flush: + tst r4, #1 + movne pc, lr mov r1, #0 mcr p15, 0, r1, c7, c14, 0 @ clean and invalidate D cache mcr p15, 0, r1, c7, c5, 0 @ flush I cache @@ -1072,13 +1075,16 @@ __fa526_cache_flush: __armv6_mmu_cache_flush: mov r1, #0 - mcr p15, 0, r1, c7, c14, 0 @ clean+invalidate D + tst r4, #1 + mcreq p15, 0, r1, c7, c14, 0 @ clean+invalidate D mcr p15, 0, r1, c7, c5, 0 @ invalidate I+BTB - mcr p15, 0, r1, c7, c15, 0 @ clean+invalidate unified + mcreq p15, 0, r1, c7, c15, 0 @ clean+invalidate unified mcr p15, 0, r1, c7, c10, 4 @ drain WB mov pc, lr __armv7_mmu_cache_flush: + tst r4, #1 + bne iflush mrc p15, 0, r10, c0, c1, 5 @ read ID_MMFR1 tst r10, #0xf << 16 @ hierarchical cache (ARMv7) mov r10, #0 @@ -1139,6 +1145,8 @@ iflush: mov pc, lr __armv5tej_mmu_cache_flush: + tst r4, #1 + movne pc, lr 1: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate D cache bne 1b mcr p15, 0, r0, c7, c5, 0 @ flush I cache @@ -1146,6 +1154,8 @@ __armv5tej_mmu_cache_flush: mov pc, lr __armv4_mmu_cache_flush: + tst r4, #1 + movne pc, lr mov r2, #64*1024 @ default: 32K dcache size (*2) mov r11, #32 @ default: 32 byte line size mrc p15, 0, r3, c0, c0, 1 @ read cache type @@ -1179,6 +1189,8 @@ no_cache_id: __armv3_mmu_cache_flush: __armv3_mpu_cache_flush: + tst r4, #1 + movne pc, lr mov r1, #0 mcr p15, 0, r1, c7, c0, 0 @ invalidate whole cache v3 mov pc, lr diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 38c89cafa1ab..fe92f5df9d3c 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -376,25 +376,24 @@ dtb-$(CONFIG_ARCH_S5PV210) += s5pv210-aquila.dtb \ s5pv210-smdkc110.dtb \ s5pv210-smdkv210.dtb \ s5pv210-torbreck.dtb -dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += r7s72100-genmai.dtb \ +dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += \ + r8a73a4-ape6evm.dtb \ + r8a73a4-ape6evm-reference.dtb \ r8a7740-armadillo800eva.dtb \ r8a7778-bockw.dtb \ r8a7778-bockw-reference.dtb \ r8a7779-marzen.dtb \ - r8a7791-koelsch.dtb \ r8a7790-lager.dtb \ + sh7372-mackerel.dtb \ sh73a0-kzm9g.dtb \ - sh73a0-kzm9g-reference.dtb \ - r8a73a4-ape6evm.dtb \ - r8a73a4-ape6evm-reference.dtb \ - sh7372-mackerel.dtb + sh73a0-kzm9g-reference.dtb dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d.dtb \ r7s72100-genmai.dtb \ r8a7740-armadillo800eva.dtb \ + r8a7779-marzen.dtb \ + r8a7790-lager.dtb \ r8a7791-henninger.dtb \ r8a7791-koelsch.dtb \ - r8a7790-lager.dtb \ - r8a7779-marzen.dtb \ r8a7794-alt.dtb dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_arria5_socdk.dtb \ socfpga_cyclone5_socdk.dtb \ @@ -517,15 +516,7 @@ dtb-$(CONFIG_MACH_DOVE) += dove-cm-a510.dtb \ dove-dove-db.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt6589-aquaris5.dtb -targets += dtbs dtbs_install -targets += $(dtb-y) endif -# *.dtb used to be generated in the directory above. Clean out the -# old build results so people don't accidentally use them. -dtbs: $(addprefix $(obj)/, $(dtb-y)) - $(Q)rm -f $(obj)/../*.dtb - -clean-files := *.dtb - -dtbs_install: $(addsuffix _dtbinst_, $(dtb-y)) +always := $(dtb-y) +clean-files := *.dtb diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts index e2156a583de7..c4b968f0feb5 100644 --- a/arch/arm/boot/dts/am335x-evm.dts +++ b/arch/arm/boot/dts/am335x-evm.dts @@ -489,7 +489,7 @@ reg = <0x00060000 0x00020000>; }; partition@4 { - label = "NAND.u-boot-spl"; + label = "NAND.u-boot-spl-os"; reg = <0x00080000 0x00040000>; }; partition@5 { diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index e7ac47fa6615..a521ac0a7d5a 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -291,8 +291,8 @@ dcdc3: regulator-dcdc3 { compatible = "ti,tps65218-dcdc3"; regulator-name = "vdcdc3"; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-boot-on; regulator-always-on; }; diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 859ff3d620ee..87aa4f3b8b3d 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -363,8 +363,8 @@ dcdc3: regulator-dcdc3 { compatible = "ti,tps65218-dcdc3"; regulator-name = "vdds_ddr"; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-boot-on; regulator-always-on; }; diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index ac3e4859935f..f7e9bba10bd6 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -358,8 +358,8 @@ dcdc3: regulator-dcdc3 { compatible = "ti,tps65218-dcdc3"; regulator-name = "vdcdc3"; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; regulator-boot-on; regulator-always-on; }; diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 83286ec9702c..90dba78554c8 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -180,7 +180,8 @@ mbusc: mbus-controller@20000 { compatible = "marvell,mbus-controller"; - reg = <0x20000 0x100>, <0x20180 0x20>; + reg = <0x20000 0x100>, <0x20180 0x20>, + <0x20250 0x8>; }; mpic: interrupt-controller@20000 { diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts index 0478c55ca656..ea8673647494 100644 --- a/arch/arm/boot/dts/armada-xp-gp.dts +++ b/arch/arm/boot/dts/armada-xp-gp.dts @@ -23,6 +23,7 @@ */ /dts-v1/; +#include <dt-bindings/gpio/gpio.h> #include "armada-xp-mv78460.dtsi" / { @@ -48,6 +49,14 @@ <0x00000001 0x00000000 0x00000001 0x00000000>; }; + cpus { + pm_pic { + ctrl-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>, + <&gpio0 17 GPIO_ACTIVE_LOW>, + <&gpio0 18 GPIO_ACTIVE_LOW>; + }; + }; + soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 @@ -115,7 +124,15 @@ serial@12300 { status = "okay"; }; - + pinctrl { + pinctrl-0 = <&pic_pins>; + pinctrl-names = "default"; + pic_pins: pic-pins-0 { + marvell,pins = "mpp16", "mpp17", + "mpp18"; + marvell,function = "gpio"; + }; + }; sata@a0000 { nr-ports = <2>; status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi index bff9f6c18db1..2be244a96edf 100644 --- a/arch/arm/boot/dts/armada-xp.dtsi +++ b/arch/arm/boot/dts/armada-xp.dtsi @@ -35,6 +35,11 @@ }; internal-regs { + sdramc@1400 { + compatible = "marvell,armada-xp-sdram-controller"; + reg = <0x1400 0x500>; + }; + L2: l2-cache { compatible = "marvell,aurora-system-cache"; reg = <0x08000 0x1000>; diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts index 50ccd151091e..667d323e80a3 100644 --- a/arch/arm/boot/dts/emev2-kzm9d.dts +++ b/arch/arm/boot/dts/emev2-kzm9d.dts @@ -25,37 +25,7 @@ chosen { bootargs = "console=ttyS1,115200n81 ignore_loglevel root=/dev/nfs ip=dhcp"; - }; - - reg_1p8v: regulator@0 { - compatible = "regulator-fixed"; - regulator-name = "fixed-1.8V"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - regulator-boot-on; - }; - - reg_3p3v: regulator@1 { - compatible = "regulator-fixed"; - regulator-name = "fixed-3.3V"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; - }; - - lan9220@20000000 { - compatible = "smsc,lan9220", "smsc,lan9115"; - reg = <0x20000000 0x10000>; - phy-mode = "mii"; - interrupt-parent = <&gpio0>; - interrupts = <1 IRQ_TYPE_EDGE_RISING>; - reg-io-width = <4>; - smsc,irq-active-high; - smsc,irq-push-pull; - vddvario-supply = <®_1p8v>; - vdd33a-supply = <®_3p3v>; + stdout-path = &uart1; }; gpio_keys { @@ -92,4 +62,35 @@ gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>; }; }; + + reg_1p8v: regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + reg_3p3v: regulator@1 { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + lan9220@20000000 { + compatible = "smsc,lan9220", "smsc,lan9115"; + reg = <0x20000000 0x10000>; + phy-mode = "mii"; + interrupt-parent = <&gpio0>; + interrupts = <1 IRQ_TYPE_EDGE_RISING>; + reg-io-width = <4>; + smsc,irq-active-high; + smsc,irq-push-pull; + vddvario-supply = <®_1p8v>; + vdd33a-supply = <®_3p3v>; + }; }; diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi index 00eeed3721b6..cc7bfe0ba40a 100644 --- a/arch/arm/boot/dts/emev2.dtsi +++ b/arch/arm/boot/dts/emev2.dtsi @@ -55,7 +55,7 @@ <0 121 IRQ_TYPE_LEVEL_HIGH>; }; - smu@e0110000 { + clocks@e0110000 { compatible = "renesas,emev2-smu"; reg = <0xe0110000 0x10000>; #address-cells = <2>; @@ -129,7 +129,7 @@ }; }; - sti@e0180000 { + timer@e0180000 { compatible = "renesas,em-sti"; reg = <0xe0180000 0x54>; interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>; @@ -137,7 +137,7 @@ clock-names = "sclk"; }; - uart@e1020000 { + uart0: serial@e1020000 { compatible = "renesas,em-uart"; reg = <0xe1020000 0x38>; interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>; @@ -145,7 +145,7 @@ clock-names = "sclk"; }; - uart@e1030000 { + uart1: serial@e1030000 { compatible = "renesas,em-uart"; reg = <0xe1030000 0x38>; interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>; @@ -153,7 +153,7 @@ clock-names = "sclk"; }; - uart@e1040000 { + uart2: serial@e1040000 { compatible = "renesas,em-uart"; reg = <0xe1040000 0x38>; interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>; @@ -161,7 +161,7 @@ clock-names = "sclk"; }; - uart@e1050000 { + uart3: serial@e1050000 { compatible = "renesas,em-uart"; reg = <0xe1050000 0x38>; interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index e51fcef884a4..60429ad1c5d8 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts @@ -624,4 +624,8 @@ num-cs = <1>; }; +&usbdrd_dwc3 { + dr_mode = "host"; +}; + #include "cros-ec-keyboard.dtsi" diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index f21b9aa00fbb..d55c1a2eb798 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -555,7 +555,7 @@ #size-cells = <1>; ranges; - dwc3 { + usbdrd_dwc3: dwc3 { compatible = "synopsys,dwc3"; reg = <0x12000000 0x10000>; interrupts = <0 72 0>; diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi index d3c0bf5c84e3..b5756c21ea1d 100644 --- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi @@ -282,7 +282,6 @@ }; &ssi1 { - fsl,mode = "i2s-slave"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi index cade1bdc97e9..86f03c1b147c 100644 --- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi @@ -287,7 +287,6 @@ }; &ssi1 { - fsl,mode = "i2s-slave"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi index cf13239a1619..4a8d97f47759 100644 --- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi +++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi @@ -376,12 +376,10 @@ }; &ssi1 { - fsl,mode = "i2s-slave"; status = "okay"; }; &ssi2 { - fsl,mode = "i2s-slave"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl-rex.dtsi b/arch/arm/boot/dts/imx6qdl-rex.dtsi index df7bcf86c156..488a640796ac 100644 --- a/arch/arm/boot/dts/imx6qdl-rex.dtsi +++ b/arch/arm/boot/dts/imx6qdl-rex.dtsi @@ -308,7 +308,6 @@ }; &ssi1 { - fsl,mode = "i2s-slave"; status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index baf2f00d519a..5db4a2417d94 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -107,10 +107,8 @@ "Headphone Jack", "HPOUTR", "Ext Spk", "SPKOUTL", "Ext Spk", "SPKOUTR", - "MICBIAS", "AMIC", - "IN3R", "MICBIAS", - "DMIC", "MICBIAS", - "DMICDAT", "DMIC"; + "AMIC", "MICBIAS", + "IN3R", "AMIC"; mux-int-port = <2>; mux-ext-port = <3>; }; @@ -179,7 +177,7 @@ codec: wm8962@1a { compatible = "wlf,wm8962"; reg = <0x1a>; - clocks = <&clks 201>; + clocks = <&clks IMX6QDL_CLK_CKO>; DCVDD-supply = <®_audio>; DBVDD-supply = <®_audio>; AVDD-supply = <®_audio>; diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index 88e3d477bf16..28e38f8c6b0f 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi @@ -6,8 +6,18 @@ / { core-module@10000000 { - compatible = "arm,core-module-integrator"; + compatible = "arm,core-module-integrator", "syscon"; reg = <0x10000000 0x200>; + + /* Use core module LED to indicate CPU load */ + led@0c.0 { + compatible = "register-bit-led"; + offset = <0x0c>; + mask = <0x01>; + label = "integrator:core_module"; + linux,default-trigger = "cpu0"; + default-state = "on"; + }; }; ebi@12000000 { @@ -82,5 +92,41 @@ reg = <0x19000000 0x1000>; interrupts = <4>; }; + + syscon { + /* Debug registers mapped as syscon */ + compatible = "syscon"; + reg = <0x1a000000 0x10>; + + led@04.0 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x01>; + label = "integrator:green0"; + linux,default-trigger = "heartbeat"; + default-state = "on"; + }; + led@04.1 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x02>; + label = "integrator:yellow"; + default-state = "off"; + }; + led@04.2 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x04>; + label = "integrator:red"; + default-state = "off"; + }; + led@04.3 { + compatible = "register-bit-led"; + offset = <0x04>; + mask = <0x08>; + label = "integrator:green1"; + default-state = "off"; + }; + }; }; }; diff --git a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi index 25ba08331d88..3cbaf98c1372 100644 --- a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi +++ b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi @@ -64,6 +64,7 @@ #include "twl4030.dtsi" #include "twl4030_omap3.dtsi" +#include <dt-bindings/input/input.h> &mmc1 { vmmc-supply = <&vmmc1>; @@ -75,6 +76,22 @@ ti,pullups = <0x000001>; }; +&twl_keypad { + linux,keymap = < + MATRIX_KEY(0x00, 0x01, KEY_A) + MATRIX_KEY(0x00, 0x02, KEY_B) + MATRIX_KEY(0x00, 0x03, KEY_LEFT) + + MATRIX_KEY(0x01, 0x01, KEY_UP) + MATRIX_KEY(0x01, 0x02, KEY_ENTER) + MATRIX_KEY(0x01, 0x03, KEY_DOWN) + + MATRIX_KEY(0x02, 0x01, KEY_RIGHT) + MATRIX_KEY(0x02, 0x02, KEY_C) + MATRIX_KEY(0x02, 0x03, KEY_D) + >; +}; + &hsusb1_phy { reset-gpios = <&twl_gpio 6 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/omap3-evm-common.dtsi b/arch/arm/boot/dts/omap3-evm-common.dtsi index c8747c7f1cc8..127f3e7c10c4 100644 --- a/arch/arm/boot/dts/omap3-evm-common.dtsi +++ b/arch/arm/boot/dts/omap3-evm-common.dtsi @@ -2,6 +2,7 @@ * Common support for omap3 EVM boards */ +#include <dt-bindings/input/input.h> #include "omap-gpmc-smsc911x.dtsi" / { @@ -111,6 +112,26 @@ ti,use-leds; }; +&twl_keypad { + linux,keymap = < + MATRIX_KEY(2, 2, KEY_1) + MATRIX_KEY(1, 1, KEY_2) + MATRIX_KEY(0, 0, KEY_3) + MATRIX_KEY(3, 2, KEY_4) + MATRIX_KEY(2, 1, KEY_5) + MATRIX_KEY(1, 0, KEY_6) + MATRIX_KEY(1, 3, KEY_7) + MATRIX_KEY(3, 1, KEY_8) + MATRIX_KEY(2, 0, KEY_9) + MATRIX_KEY(2, 3, KEY_KPASTERISK) + MATRIX_KEY(0, 2, KEY_0) + MATRIX_KEY(3, 0, KEY_KPDOT) + /* s4 not wired */ + MATRIX_KEY(1, 2, KEY_BACKSPACE) + MATRIX_KEY(0, 1, KEY_ENTER) + >; +}; + &usb_otg_hs { interface-type = <0>; usb-phy = <&usb2_phy>; diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts index 72dca0b7904d..77fee3fb7515 100644 --- a/arch/arm/boot/dts/omap3-ldp.dts +++ b/arch/arm/boot/dts/omap3-ldp.dts @@ -7,6 +7,7 @@ */ /dts-v1/; +#include <dt-bindings/input/input.h> #include "omap34xx.dtsi" #include "omap-gpmc-smsc911x.dtsi" @@ -141,7 +142,7 @@ }; partition@2000000 { label = "Filesystem"; - reg = <0x2000000 0xe000000>; + reg = <0x2000000 0x6000000>; }; }; @@ -263,6 +264,26 @@ }; }; +&twl_keypad { + linux,keymap = <MATRIX_KEY(0, 0, KEY_1) + MATRIX_KEY(0, 1, KEY_2) + MATRIX_KEY(0, 2, KEY_3) + MATRIX_KEY(1, 0, KEY_4) + MATRIX_KEY(1, 1, KEY_5) + MATRIX_KEY(1, 2, KEY_6) + MATRIX_KEY(1, 3, KEY_F5) + MATRIX_KEY(2, 0, KEY_7) + MATRIX_KEY(2, 1, KEY_8) + MATRIX_KEY(2, 2, KEY_9) + MATRIX_KEY(2, 3, KEY_F6) + MATRIX_KEY(3, 0, KEY_F7) + MATRIX_KEY(3, 1, KEY_0) + MATRIX_KEY(3, 2, KEY_F8) + MATRIX_KEY(5, 4, KEY_RESERVED) + MATRIX_KEY(4, 4, KEY_VOLUMEUP) + MATRIX_KEY(5, 5, KEY_VOLUMEDOWN)>; +}; + &uart3 { interrupts-extended = <&intc 74 &omap3_pmx_core OMAP3_UART3_RX>; }; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index d0e884d3a737..e602e75ce5b7 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -79,7 +79,7 @@ * hierarchy. */ ocp { - compatible = "simple-bus"; + compatible = "ti,omap3-l3-smx", "simple-bus"; reg = <0x68000000 0x10000>; interrupts = <9 10>; #address-cells = <1>; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 878c979203d0..84045a5c3ce8 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -895,7 +895,7 @@ reg = <0x58002000 0x1000>; status = "disabled"; ti,hwmods = "dss_rfbi"; - clocks = <&dss_dss_clk>, <&dss_fck>; + clocks = <&dss_dss_clk>, <&l3_div_ck>; clock-names = "fck", "ick"; }; diff --git a/arch/arm/boot/dts/omap44xx-clocks.dtsi b/arch/arm/boot/dts/omap44xx-clocks.dtsi index c821ff5e9b8d..f2c48f09824e 100644 --- a/arch/arm/boot/dts/omap44xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap44xx-clocks.dtsi @@ -1018,14 +1018,6 @@ reg = <0x1120>; }; - dss_fck: dss_fck { - #clock-cells = <0>; - compatible = "ti,gate-clock"; - clocks = <&l3_div_ck>; - ti,bit-shift = <1>; - reg = <0x1120>; - }; - fdif_fck: fdif_fck { #clock-cells = <0>; compatible = "ti,divider-clock"; diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts index a3ed23c0a8f5..1518c5bcca33 100644 --- a/arch/arm/boot/dts/r7s72100-genmai.dts +++ b/arch/arm/boot/dts/r7s72100-genmai.dts @@ -21,7 +21,8 @@ }; chosen { - bootargs = "console=ttySC2,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp"; + bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp"; + stdout-path = &scif2; }; memory { diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi index 801a556e264b..277e73c110e5 100644 --- a/arch/arm/boot/dts/r7s72100.dtsi +++ b/arch/arm/boot/dts/r7s72100.dtsi @@ -52,16 +52,6 @@ clock-output-names = "usb_x1"; }; - /* Special CPG clocks */ - cpg_clocks: cpg_clocks@fcfe0000 { - #clock-cells = <1>; - compatible = "renesas,r7s72100-cpg-clocks", - "renesas,rz-cpg-clocks"; - reg = <0xfcfe0000 0x18>; - clocks = <&extal_clk>, <&usb_x1_clk>; - clock-output-names = "pll", "i", "g"; - }; - /* Fixed factor clocks */ b_clk: b_clk { #clock-cells = <0>; @@ -88,6 +78,16 @@ clock-output-names = "p0"; }; + /* Special CPG clocks */ + cpg_clocks: cpg_clocks@fcfe0000 { + #clock-cells = <1>; + compatible = "renesas,r7s72100-cpg-clocks", + "renesas,rz-cpg-clocks"; + reg = <0xfcfe0000 0x18>; + clocks = <&extal_clk>, <&usb_x1_clk>; + clock-output-names = "pll", "i", "g"; + }; + /* MSTP clocks */ mstp3_clks: mstp3_clks@fcfe0420 { #clock-cells = <1>; @@ -148,97 +148,6 @@ }; }; - gic: interrupt-controller@e8201000 { - compatible = "arm,cortex-a9-gic"; - #interrupt-cells = <3>; - #address-cells = <0>; - interrupt-controller; - reg = <0xe8201000 0x1000>, - <0xe8202000 0x1000>; - }; - - i2c0: i2c@fcfee000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; - reg = <0xfcfee000 0x44>; - interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>, - <0 158 IRQ_TYPE_EDGE_RISING>, - <0 159 IRQ_TYPE_EDGE_RISING>, - <0 160 IRQ_TYPE_LEVEL_HIGH>, - <0 161 IRQ_TYPE_LEVEL_HIGH>, - <0 162 IRQ_TYPE_LEVEL_HIGH>, - <0 163 IRQ_TYPE_LEVEL_HIGH>, - <0 164 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp9_clks R7S72100_CLK_I2C0>; - clock-frequency = <100000>; - status = "disabled"; - }; - - i2c1: i2c@fcfee400 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; - reg = <0xfcfee400 0x44>; - interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>, - <0 166 IRQ_TYPE_EDGE_RISING>, - <0 167 IRQ_TYPE_EDGE_RISING>, - <0 168 IRQ_TYPE_LEVEL_HIGH>, - <0 169 IRQ_TYPE_LEVEL_HIGH>, - <0 170 IRQ_TYPE_LEVEL_HIGH>, - <0 171 IRQ_TYPE_LEVEL_HIGH>, - <0 172 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp9_clks R7S72100_CLK_I2C1>; - clock-frequency = <100000>; - status = "disabled"; - }; - - i2c2: i2c@fcfee800 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; - reg = <0xfcfee800 0x44>; - interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>, - <0 174 IRQ_TYPE_EDGE_RISING>, - <0 175 IRQ_TYPE_EDGE_RISING>, - <0 176 IRQ_TYPE_LEVEL_HIGH>, - <0 177 IRQ_TYPE_LEVEL_HIGH>, - <0 178 IRQ_TYPE_LEVEL_HIGH>, - <0 179 IRQ_TYPE_LEVEL_HIGH>, - <0 180 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp9_clks R7S72100_CLK_I2C2>; - clock-frequency = <100000>; - status = "disabled"; - }; - - i2c3: i2c@fcfeec00 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; - reg = <0xfcfeec00 0x44>; - interrupts = <0 181 IRQ_TYPE_LEVEL_HIGH>, - <0 182 IRQ_TYPE_EDGE_RISING>, - <0 183 IRQ_TYPE_EDGE_RISING>, - <0 184 IRQ_TYPE_LEVEL_HIGH>, - <0 185 IRQ_TYPE_LEVEL_HIGH>, - <0 186 IRQ_TYPE_LEVEL_HIGH>, - <0 187 IRQ_TYPE_LEVEL_HIGH>, - <0 188 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&mstp9_clks R7S72100_CLK_I2C3>; - clock-frequency = <100000>; - status = "disabled"; - }; - - mtu2: timer@fcff0000 { - compatible = "renesas,mtu2-r7s72100", "renesas,mtu2"; - reg = <0xfcff0000 0x400>; - interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "tgi0a"; - clocks = <&mstp3_clks R7S72100_CLK_MTU2>; - clock-names = "fck"; - status = "disabled"; - }; - scif0: serial@e8007000 { compatible = "renesas,scif-r7s72100", "renesas,scif"; reg = <0xe8007000 64>; @@ -404,4 +313,95 @@ #size-cells = <0>; status = "disabled"; }; + + gic: interrupt-controller@e8201000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0xe8201000 0x1000>, + <0xe8202000 0x1000>; + }; + + i2c0: i2c@fcfee000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; + reg = <0xfcfee000 0x44>; + interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>, + <0 158 IRQ_TYPE_EDGE_RISING>, + <0 159 IRQ_TYPE_EDGE_RISING>, + <0 160 IRQ_TYPE_LEVEL_HIGH>, + <0 161 IRQ_TYPE_LEVEL_HIGH>, + <0 162 IRQ_TYPE_LEVEL_HIGH>, + <0 163 IRQ_TYPE_LEVEL_HIGH>, + <0 164 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R7S72100_CLK_I2C0>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c1: i2c@fcfee400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; + reg = <0xfcfee400 0x44>; + interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>, + <0 166 IRQ_TYPE_EDGE_RISING>, + <0 167 IRQ_TYPE_EDGE_RISING>, + <0 168 IRQ_TYPE_LEVEL_HIGH>, + <0 169 IRQ_TYPE_LEVEL_HIGH>, + <0 170 IRQ_TYPE_LEVEL_HIGH>, + <0 171 IRQ_TYPE_LEVEL_HIGH>, + <0 172 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R7S72100_CLK_I2C1>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c2: i2c@fcfee800 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; + reg = <0xfcfee800 0x44>; + interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>, + <0 174 IRQ_TYPE_EDGE_RISING>, + <0 175 IRQ_TYPE_EDGE_RISING>, + <0 176 IRQ_TYPE_LEVEL_HIGH>, + <0 177 IRQ_TYPE_LEVEL_HIGH>, + <0 178 IRQ_TYPE_LEVEL_HIGH>, + <0 179 IRQ_TYPE_LEVEL_HIGH>, + <0 180 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R7S72100_CLK_I2C2>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c3: i2c@fcfeec00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; + reg = <0xfcfeec00 0x44>; + interrupts = <0 181 IRQ_TYPE_LEVEL_HIGH>, + <0 182 IRQ_TYPE_EDGE_RISING>, + <0 183 IRQ_TYPE_EDGE_RISING>, + <0 184 IRQ_TYPE_LEVEL_HIGH>, + <0 185 IRQ_TYPE_LEVEL_HIGH>, + <0 186 IRQ_TYPE_LEVEL_HIGH>, + <0 187 IRQ_TYPE_LEVEL_HIGH>, + <0 188 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R7S72100_CLK_I2C3>; + clock-frequency = <100000>; + status = "disabled"; + }; + + mtu2: timer@fcff0000 { + compatible = "renesas,mtu2-r7s72100", "renesas,mtu2"; + reg = <0xfcff0000 0x400>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tgi0a"; + clocks = <&mstp3_clks R7S72100_CLK_MTU2>; + clock-names = "fck"; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts b/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts index a860f32bca27..2bcf69124a6a 100644 --- a/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts +++ b/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts @@ -21,7 +21,8 @@ }; chosen { - bootargs = "console=ttySC0,115200 ignore_loglevel rw"; + bootargs = "ignore_loglevel rw"; + stdout-path = &scifa0; }; memory@40000000 { diff --git a/arch/arm/boot/dts/r8a73a4.dtsi b/arch/arm/boot/dts/r8a73a4.dtsi index ef152e384822..c17afef92e8d 100644 --- a/arch/arm/boot/dts/r8a73a4.dtsi +++ b/arch/arm/boot/dts/r8a73a4.dtsi @@ -30,18 +30,6 @@ }; }; - gic: interrupt-controller@f1001000 { - compatible = "arm,cortex-a15-gic"; - #interrupt-cells = <3>; - #address-cells = <0>; - interrupt-controller; - reg = <0 0xf1001000 0 0x1000>, - <0 0xf1002000 0 0x1000>, - <0 0xf1004000 0 0x2000>, - <0 0xf1006000 0 0x2000>; - interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; - }; - timer { compatible = "arm,armv7-timer"; interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>, @@ -50,6 +38,80 @@ <1 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>; }; + dmac: dma-multiplexer { + compatible = "renesas,shdma-mux"; + #dma-cells = <1>; + dma-channels = <20>; + dma-requests = <256>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dma0: dma-controller@e6700020 { + compatible = "renesas,shdma-r8a73a4"; + reg = <0 0xe6700020 0 0x89e0>; + interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH + 0 200 IRQ_TYPE_LEVEL_HIGH + 0 201 IRQ_TYPE_LEVEL_HIGH + 0 202 IRQ_TYPE_LEVEL_HIGH + 0 203 IRQ_TYPE_LEVEL_HIGH + 0 204 IRQ_TYPE_LEVEL_HIGH + 0 205 IRQ_TYPE_LEVEL_HIGH + 0 206 IRQ_TYPE_LEVEL_HIGH + 0 207 IRQ_TYPE_LEVEL_HIGH + 0 208 IRQ_TYPE_LEVEL_HIGH + 0 209 IRQ_TYPE_LEVEL_HIGH + 0 210 IRQ_TYPE_LEVEL_HIGH + 0 211 IRQ_TYPE_LEVEL_HIGH + 0 212 IRQ_TYPE_LEVEL_HIGH + 0 213 IRQ_TYPE_LEVEL_HIGH + 0 214 IRQ_TYPE_LEVEL_HIGH + 0 215 IRQ_TYPE_LEVEL_HIGH + 0 216 IRQ_TYPE_LEVEL_HIGH + 0 217 IRQ_TYPE_LEVEL_HIGH + 0 218 IRQ_TYPE_LEVEL_HIGH + 0 219 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15", + "ch16", "ch17", "ch18", "ch19"; + }; + }; + + pfc: pfc@e6050000 { + compatible = "renesas,pfc-r8a73a4"; + reg = <0 0xe6050000 0 0x9000>; + gpio-controller; + #gpio-cells = <2>; + interrupts-extended = + <&irqc0 0 0>, <&irqc0 1 0>, <&irqc0 2 0>, <&irqc0 3 0>, + <&irqc0 4 0>, <&irqc0 5 0>, <&irqc0 6 0>, <&irqc0 7 0>, + <&irqc0 8 0>, <&irqc0 9 0>, <&irqc0 10 0>, <&irqc0 11 0>, + <&irqc0 12 0>, <&irqc0 13 0>, <&irqc0 14 0>, <&irqc0 15 0>, + <&irqc0 16 0>, <&irqc0 17 0>, <&irqc0 18 0>, <&irqc0 19 0>, + <&irqc0 20 0>, <&irqc0 21 0>, <&irqc0 22 0>, <&irqc0 23 0>, + <&irqc0 24 0>, <&irqc0 25 0>, <&irqc0 26 0>, <&irqc0 27 0>, + <&irqc0 28 0>, <&irqc0 29 0>, <&irqc0 30 0>, <&irqc0 31 0>, + <&irqc1 0 0>, <&irqc1 1 0>, <&irqc1 2 0>, <&irqc1 3 0>, + <&irqc1 4 0>, <&irqc1 5 0>, <&irqc1 6 0>, <&irqc1 7 0>, + <&irqc1 8 0>, <&irqc1 9 0>, <&irqc1 10 0>, <&irqc1 11 0>, + <&irqc1 12 0>, <&irqc1 13 0>, <&irqc1 14 0>, <&irqc1 15 0>, + <&irqc1 16 0>, <&irqc1 17 0>, <&irqc1 18 0>, <&irqc1 19 0>, + <&irqc1 20 0>, <&irqc1 21 0>, <&irqc1 22 0>, <&irqc1 23 0>, + <&irqc1 24 0>, <&irqc1 25 0>; + }; + + i2c5: i2c@e60b0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,rmobile-iic"; + reg = <0 0xe60b0000 0 0x428>; + interrupts = <0 179 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + irqc0: interrupt-controller@e61c0000 { compatible = "renesas,irqc-r8a73a4", "renesas,irqc"; #interrupt-cells = <2>; @@ -122,48 +184,6 @@ <0 57 IRQ_TYPE_LEVEL_HIGH>; }; - dmac: dma-multiplexer@0 { - compatible = "renesas,shdma-mux"; - #dma-cells = <1>; - dma-channels = <20>; - dma-requests = <256>; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - dma0: dma-controller@e6700020 { - compatible = "renesas,shdma-r8a73a4"; - reg = <0 0xe6700020 0 0x89e0>; - interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH - 0 200 IRQ_TYPE_LEVEL_HIGH - 0 201 IRQ_TYPE_LEVEL_HIGH - 0 202 IRQ_TYPE_LEVEL_HIGH - 0 203 IRQ_TYPE_LEVEL_HIGH - 0 204 IRQ_TYPE_LEVEL_HIGH - 0 205 IRQ_TYPE_LEVEL_HIGH - 0 206 IRQ_TYPE_LEVEL_HIGH - 0 207 IRQ_TYPE_LEVEL_HIGH - 0 208 IRQ_TYPE_LEVEL_HIGH - 0 209 IRQ_TYPE_LEVEL_HIGH - 0 210 IRQ_TYPE_LEVEL_HIGH - 0 211 IRQ_TYPE_LEVEL_HIGH - 0 212 IRQ_TYPE_LEVEL_HIGH - 0 213 IRQ_TYPE_LEVEL_HIGH - 0 214 IRQ_TYPE_LEVEL_HIGH - 0 215 IRQ_TYPE_LEVEL_HIGH - 0 216 IRQ_TYPE_LEVEL_HIGH - 0 217 IRQ_TYPE_LEVEL_HIGH - 0 218 IRQ_TYPE_LEVEL_HIGH - 0 219 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "error", - "ch0", "ch1", "ch2", "ch3", - "ch4", "ch5", "ch6", "ch7", - "ch8", "ch9", "ch10", "ch11", - "ch12", "ch13", "ch14", "ch15", - "ch16", "ch17", "ch18", "ch19"; - }; - }; - thermal@e61f0000 { compatible = "renesas,thermal-r8a73a4", "renesas,rcar-thermal"; reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>, @@ -216,15 +236,6 @@ status = "disabled"; }; - i2c5: i2c@e60b0000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "renesas,rmobile-iic"; - reg = <0 0xe60b0000 0 0x428>; - interrupts = <0 179 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; - i2c6: i2c@e6550000 { #address-cells = <1>; #size-cells = <0>; @@ -252,20 +263,6 @@ status = "disabled"; }; - scifa0: serial@e6c40000 { - compatible = "renesas,scifa-r8a73a4", "renesas,scifa"; - reg = <0 0xe6c40000 0 0x100>; - interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; - - scifa1: serial@e6c50000 { - compatible = "renesas,scifa-r8a73a4", "renesas,scifa"; - reg = <0 0xe6c50000 0 0x100>; - interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>; - status = "disabled"; - }; - scifb2: serial@e6c20000 { compatible = "renesas,scifb-r8a73a4", "renesas,scifb"; reg = <0 0xe6c20000 0 0x100>; @@ -280,6 +277,20 @@ status = "disabled"; }; + scifa0: serial@e6c40000 { + compatible = "renesas,scifa-r8a73a4", "renesas,scifa"; + reg = <0 0xe6c40000 0 0x100>; + interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + scifa1: serial@e6c50000 { + compatible = "renesas,scifa-r8a73a4", "renesas,scifa"; + reg = <0 0xe6c50000 0 0x100>; + interrupts = <0 145 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + scifb4: serial@e6ce0000 { compatible = "renesas,scifb-r8a73a4", "renesas,scifb"; reg = <0 0xe6ce0000 0 0x100>; @@ -294,45 +305,6 @@ status = "disabled"; }; - mmcif0: mmc@ee200000 { - compatible = "renesas,sh-mmcif"; - reg = <0 0xee200000 0 0x80>; - interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>; - reg-io-width = <4>; - status = "disabled"; - }; - - mmcif1: mmc@ee220000 { - compatible = "renesas,sh-mmcif"; - reg = <0 0xee220000 0 0x80>; - interrupts = <0 170 IRQ_TYPE_LEVEL_HIGH>; - reg-io-width = <4>; - status = "disabled"; - }; - - pfc: pfc@e6050000 { - compatible = "renesas,pfc-r8a73a4"; - reg = <0 0xe6050000 0 0x9000>; - gpio-controller; - #gpio-cells = <2>; - interrupts-extended = - <&irqc0 0 0>, <&irqc0 1 0>, <&irqc0 2 0>, <&irqc0 3 0>, - <&irqc0 4 0>, <&irqc0 5 0>, <&irqc0 6 0>, <&irqc0 7 0>, - <&irqc0 8 0>, <&irqc0 9 0>, <&irqc0 10 0>, <&irqc0 11 0>, - <&irqc0 12 0>, <&irqc0 13 0>, <&irqc0 14 0>, <&irqc0 15 0>, - <&irqc0 16 0>, <&irqc0 17 0>, <&irqc0 18 0>, <&irqc0 19 0>, - <&irqc0 20 0>, <&irqc0 21 0>, <&irqc0 22 0>, <&irqc0 23 0>, - <&irqc0 24 0>, <&irqc0 25 0>, <&irqc0 26 0>, <&irqc0 27 0>, - <&irqc0 28 0>, <&irqc0 29 0>, <&irqc0 30 0>, <&irqc0 31 0>, - <&irqc1 0 0>, <&irqc1 1 0>, <&irqc1 2 0>, <&irqc1 3 0>, - <&irqc1 4 0>, <&irqc1 5 0>, <&irqc1 6 0>, <&irqc1 7 0>, - <&irqc1 8 0>, <&irqc1 9 0>, <&irqc1 10 0>, <&irqc1 11 0>, - <&irqc1 12 0>, <&irqc1 13 0>, <&irqc1 14 0>, <&irqc1 15 0>, - <&irqc1 16 0>, <&irqc1 17 0>, <&irqc1 18 0>, <&irqc1 19 0>, - <&irqc1 20 0>, <&irqc1 21 0>, <&irqc1 22 0>, <&irqc1 23 0>, - <&irqc1 24 0>, <&irqc1 25 0>; - }; - sdhi0: sd@ee100000 { compatible = "renesas,sdhi-r8a73a4"; reg = <0 0xee100000 0 0x100>; @@ -356,4 +328,32 @@ cap-sd-highspeed; status = "disabled"; }; + + mmcif0: mmc@ee200000 { + compatible = "renesas,sh-mmcif"; + reg = <0 0xee200000 0 0x80>; + interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>; + reg-io-width = <4>; + status = "disabled"; + }; + + mmcif1: mmc@ee220000 { + compatible = "renesas,sh-mmcif"; + reg = <0 0xee220000 0 0x80>; + interrupts = <0 170 IRQ_TYPE_LEVEL_HIGH>; + reg-io-width = <4>; + status = "disabled"; + }; + + gic: interrupt-controller@f1001000 { + compatible = "arm,cortex-a15-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0 0xf1001000 0 0x1000>, + <0 0xf1002000 0 0x1000>, + <0 0xf1004000 0 0x2000>, + <0 0xf1006000 0 0x2000>; + interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; }; diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts index effb7b46f131..2703428557fc 100644 --- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts +++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw"; + stdout-path = &scifa1; }; memory { diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi index d46c213a17ad..eed697a6bd6b 100644 --- a/arch/arm/boot/dts/r8a7740.dtsi +++ b/arch/arm/boot/dts/r8a7740.dtsi @@ -433,7 +433,7 @@ clocks = <&cpg_clocks R8A7740_CLK_S>, <&cpg_clocks R8A7740_CLK_S>, <&sub_clk>, <&cpg_clocks R8A7740_CLK_B>, - <&sub_clk>, <&sub_clk>, + <&cpg_clocks R8A7740_CLK_HPP>, <&sub_clk>, <&cpg_clocks R8A7740_CLK_B>; #clock-cells = <1>; renesas,clock-indices = < diff --git a/arch/arm/boot/dts/r8a7778-bockw-reference.dts b/arch/arm/boot/dts/r8a7778-bockw-reference.dts index 3342c74c5de8..fba294905ff4 100644 --- a/arch/arm/boot/dts/r8a7778-bockw-reference.dts +++ b/arch/arm/boot/dts/r8a7778-bockw-reference.dts @@ -28,7 +28,8 @@ }; chosen { - bootargs = "console=ttySC0,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw"; + bootargs = "ignore_loglevel root=/dev/nfs ip=dhcp rw"; + stdout-path = &scif0; }; memory { diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts index c160404e4d40..e83d40e24bcd 100644 --- a/arch/arm/boot/dts/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/r8a7779-marzen.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=ttySC2,115200 ignore_loglevel root=/dev/nfs ip=on"; + stdout-path = &scif2; }; memory { @@ -68,6 +69,78 @@ gpios = <&gpio4 31 GPIO_ACTIVE_HIGH>; }; }; + + vga-encoder { + compatible = "adi,adv7123"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + vga_enc_in: endpoint { + remote-endpoint = <&du_out_rgb0>; + }; + }; + port@1 { + reg = <1>; + vga_enc_out: endpoint { + remote-endpoint = <&vga_in>; + }; + }; + }; + }; + + vga { + compatible = "vga-connector"; + + port { + vga_in: endpoint { + remote-endpoint = <&vga_enc_out>; + }; + }; + }; + + lvds-encoder { + compatible = "thine,thc63lvdm83d"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds_enc_in: endpoint { + remote-endpoint = <&du_out_rgb1>; + }; + }; + port@1 { + reg = <1>; + lvds_connector: endpoint { + }; + }; + }; + }; +}; + +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&vga_enc_in>; + }; + }; + port@1 { + endpoint { + remote-endpoint = <&lvds_enc_in>; + }; + }; + }; }; &irqpin0 { @@ -83,6 +156,17 @@ }; &pfc { + du_pins: du { + du0 { + renesas,groups = "du0_rgb888", "du0_sync_1", "du0_clk_out_0"; + renesas,function = "du0"; + }; + du1 { + renesas,groups = "du1_rgb666", "du1_sync_1", "du1_clk_out"; + renesas,function = "du1"; + }; + }; + lan0_pins: lan0 { intc { renesas,groups = "intc_irq1_b"; diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi index 7cfba9aa1b41..fda814ed191d 100644 --- a/arch/arm/boot/dts/r8a7779.dtsi +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -379,6 +379,30 @@ status = "disabled"; }; + du: display@fff80000 { + compatible = "renesas,du-r8a7779"; + reg = <0 0xfff80000 0 0x40000>; + interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7779_CLK_DU>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb0: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_rgb1: endpoint { + }; + }; + }; + }; + clocks { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index 69098b906b39..acab2e153382 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -25,6 +25,7 @@ chosen { bootargs = "console=ttySC6,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp"; + stdout-path = &scifa0; }; memory@40000000 { @@ -144,6 +145,56 @@ states = <3300000 1 1800000 0>; }; + + vga-encoder { + compatible = "adi,adv7123"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7123_in: endpoint { + remote-endpoint = <&du_out_rgb>; + }; + }; + port@1 { + reg = <1>; + adv7123_out: endpoint { + remote-endpoint = <&vga_in>; + }; + }; + }; + }; + + vga { + compatible = "vga-connector"; + + port { + vga_in: endpoint { + remote-endpoint = <&adv7123_out>; + }; + }; + }; +}; + +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&adv7123_in>; + }; + }; + port@2 { + lvds_connector: endpoint { + }; + }; + }; }; &extal_clk { @@ -151,9 +202,6 @@ }; &pfc { - pinctrl-0 = <&du_pins>; - pinctrl-names = "default"; - du_pins: du { renesas,groups = "du_rgb666", "du_sync_1", "du_clk_out_0"; renesas,function = "du"; diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index d0e17733dc1a..0c20c90d8c06 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -600,6 +600,96 @@ status = "disabled"; }; + vsp1@fe920000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe920000 0 0x8000>; + interrupts = <0 266 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_R>; + + renesas,has-sru; + renesas,#rpf = <5>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + vsp1@fe928000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe928000 0 0x8000>; + interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>; + + renesas,has-lut; + renesas,has-sru; + renesas,#rpf = <5>; + renesas,#uds = <3>; + renesas,#wpf = <4>; + }; + + vsp1@fe930000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe930000 0 0x8000>; + interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU0>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + vsp1@fe938000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe938000 0 0x8000>; + interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU1>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + du: display@feb00000 { + compatible = "renesas,du-r8a7790"; + reg = <0 0xfeb00000 0 0x70000>, + <0 0xfeb90000 0 0x1c>, + <0 0xfeb94000 0 0x1c>; + reg-names = "du", "lvds.0", "lvds.1"; + interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>, + <0 268 IRQ_TYPE_LEVEL_HIGH>, + <0 269 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7790_CLK_DU0>, + <&mstp7_clks R8A7790_CLK_DU1>, + <&mstp7_clks R8A7790_CLK_DU2>, + <&mstp7_clks R8A7790_CLK_LVDS0>, + <&mstp7_clks R8A7790_CLK_LVDS1>; + clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_lvds0: endpoint { + }; + }; + port@2 { + reg = <2>; + du_out_lvds1: endpoint { + }; + }; + }; + }; + clocks { #address-cells = <2>; #size-cells = <2>; @@ -666,9 +756,9 @@ #clock-cells = <0>; clock-output-names = "sd2"; }; - sd3_clk: sd3_clk@e615007c { + sd3_clk: sd3_clk@e615026c { compatible = "renesas,r8a7790-div6-clock", "renesas,cpg-div6-clock"; - reg = <0 0xe615007c 0 4>; + reg = <0 0xe615026c 0 4>; clocks = <&pll1_div2_clk>; #clock-cells = <0>; clock-output-names = "sd3"; diff --git a/arch/arm/boot/dts/r8a7791-henninger.dts b/arch/arm/boot/dts/r8a7791-henninger.dts index f1b56de10205..0868899882e3 100644 --- a/arch/arm/boot/dts/r8a7791-henninger.dts +++ b/arch/arm/boot/dts/r8a7791-henninger.dts @@ -23,6 +23,7 @@ chosen { bootargs = "console=ttySC0,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp"; + stdout-path = &scif0; }; memory@40000000 { diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index 07550e775e80..924183817b02 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -25,7 +25,8 @@ }; chosen { - bootargs = "console=ttySC6,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp"; + bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp"; + stdout-path = &scif0; }; memory@40000000 { @@ -211,14 +212,24 @@ }; }; +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + ports { + port@1 { + lvds_connector: endpoint { + }; + }; + }; +}; + &extal_clk { clock-frequency = <20000000>; }; &pfc { - pinctrl-0 = <&du_pins>; - pinctrl-names = "default"; - i2c2_pins: i2c2 { renesas,groups = "i2c2"; renesas,function = "i2c2"; diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index e06c11fa8698..e4a7170f368b 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -637,6 +637,75 @@ status = "disabled"; }; + vsp1@fe928000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe928000 0 0x8000>; + interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7791_CLK_VSP1_S>; + + renesas,has-lut; + renesas,has-sru; + renesas,#rpf = <5>; + renesas,#uds = <3>; + renesas,#wpf = <4>; + }; + + vsp1@fe930000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe930000 0 0x8000>; + interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU0>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + vsp1@fe938000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe938000 0 0x8000>; + interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU1>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + du: display@feb00000 { + compatible = "renesas,du-r8a7791"; + reg = <0 0xfeb00000 0 0x40000>, + <0 0xfeb90000 0 0x1c>; + reg-names = "du", "lvds.0"; + interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>, + <0 268 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_DU0>, + <&mstp7_clks R8A7791_CLK_DU1>, + <&mstp7_clks R8A7791_CLK_LVDS0>; + clock-names = "du.0", "du.1", "lvds.0"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_lvds0: endpoint { + }; + }; + }; + }; + clocks { #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts index 79d06ef017a0..8aec51268b7d 100644 --- a/arch/arm/boot/dts/r8a7794-alt.dts +++ b/arch/arm/boot/dts/r8a7794-alt.dts @@ -21,6 +21,7 @@ chosen { bootargs = "console=ttySC0,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp"; + stdout-path = &scif2; }; memory@40000000 { diff --git a/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi new file mode 100644 index 000000000000..65cb50f0c29f --- /dev/null +++ b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi @@ -0,0 +1,41 @@ +/* + * Common file for the AA104XD12 panel connected to Renesas R-Car boards + * + * Copyright (C) 2014 Renesas Electronics Corp. + * + * 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. + */ + +/ { + panel { + compatible = "mitsubishi,aa104xd12", "panel-dpi"; + + width-mm = <210>; + height-mm = <158>; + + panel-timing { + /* 1024x768 @65Hz */ + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hsync-len = <136>; + hfront-porch = <20>; + hback-porch = <160>; + vfront-porch = <3>; + vback-porch = <29>; + vsync-len = <6>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds_connector>; + }; + }; + }; +}; + +&lvds_connector { + remote-endpoint = <&panel_in>; +}; diff --git a/arch/arm/boot/dts/sama5d31.dtsi b/arch/arm/boot/dts/sama5d31.dtsi index 7997dc9863ed..883878b32971 100644 --- a/arch/arm/boot/dts/sama5d31.dtsi +++ b/arch/arm/boot/dts/sama5d31.dtsi @@ -12,5 +12,5 @@ #include "sama5d3_uart.dtsi" / { - compatible = "atmel,samad31", "atmel,sama5d3", "atmel,sama5"; + compatible = "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; }; diff --git a/arch/arm/boot/dts/sama5d33.dtsi b/arch/arm/boot/dts/sama5d33.dtsi index 39f832253caf..4b4434aca351 100644 --- a/arch/arm/boot/dts/sama5d33.dtsi +++ b/arch/arm/boot/dts/sama5d33.dtsi @@ -10,5 +10,5 @@ #include "sama5d3_gmac.dtsi" / { - compatible = "atmel,samad33", "atmel,sama5d3", "atmel,sama5"; + compatible = "atmel,sama5d33", "atmel,sama5d3", "atmel,sama5"; }; diff --git a/arch/arm/boot/dts/sama5d34.dtsi b/arch/arm/boot/dts/sama5d34.dtsi index 89cda2c0da39..aa01573fdee9 100644 --- a/arch/arm/boot/dts/sama5d34.dtsi +++ b/arch/arm/boot/dts/sama5d34.dtsi @@ -12,5 +12,5 @@ #include "sama5d3_mci2.dtsi" / { - compatible = "atmel,samad34", "atmel,sama5d3", "atmel,sama5"; + compatible = "atmel,sama5d34", "atmel,sama5d3", "atmel,sama5"; }; diff --git a/arch/arm/boot/dts/sama5d35.dtsi b/arch/arm/boot/dts/sama5d35.dtsi index d20cd71b5f0e..16c39f4c96a4 100644 --- a/arch/arm/boot/dts/sama5d35.dtsi +++ b/arch/arm/boot/dts/sama5d35.dtsi @@ -14,5 +14,5 @@ #include "sama5d3_tcb1.dtsi" / { - compatible = "atmel,samad35", "atmel,sama5d3", "atmel,sama5"; + compatible = "atmel,sama5d35", "atmel,sama5d3", "atmel,sama5"; }; diff --git a/arch/arm/boot/dts/sama5d36.dtsi b/arch/arm/boot/dts/sama5d36.dtsi index db58cad6acd3..e85139ef40af 100644 --- a/arch/arm/boot/dts/sama5d36.dtsi +++ b/arch/arm/boot/dts/sama5d36.dtsi @@ -16,5 +16,5 @@ #include "sama5d3_uart.dtsi" / { - compatible = "atmel,samad36", "atmel,sama5d3", "atmel,sama5"; + compatible = "atmel,sama5d36", "atmel,sama5d3", "atmel,sama5"; }; diff --git a/arch/arm/boot/dts/sama5d3xcm.dtsi b/arch/arm/boot/dts/sama5d3xcm.dtsi index 962dc28dc37b..cfcd200b0c17 100644 --- a/arch/arm/boot/dts/sama5d3xcm.dtsi +++ b/arch/arm/boot/dts/sama5d3xcm.dtsi @@ -8,7 +8,7 @@ */ / { - compatible = "atmel,samad3xcm", "atmel,sama5d3", "atmel,sama5"; + compatible = "atmel,sama5d3xcm", "atmel,sama5d3", "atmel,sama5"; chosen { bootargs = "console=ttyS0,115200 rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs"; diff --git a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts index 30ef97e99dc5..0dac0e66ccad 100644 --- a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts +++ b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts @@ -40,6 +40,7 @@ chosen { bootargs = "console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel rw"; + stdout-path = &scifa4; }; memory { diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index 9d2323020d34..bfd3f1c734b8 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -11,6 +11,7 @@ #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/mfd/dbx500-prcmu.h> +#include <dt-bindings/arm/ux500_pm_domains.h> #include "skeleton.dtsi" / { @@ -43,6 +44,10 @@ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; }; + pm_domains: pm_domains0 { + compatible = "stericsson,ux500-pm-domains"; + #power-domain-cells = <1>; + }; clocks { compatible = "stericsson,u8500-clks"; @@ -636,6 +641,7 @@ clock-frequency = <400000>; clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80122000 { @@ -651,6 +657,7 @@ clocks = <&prcc_kclk 1 2>, <&prcc_pclk 1 2>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80128000 { @@ -666,6 +673,7 @@ clocks = <&prcc_kclk 1 6>, <&prcc_pclk 1 6>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@80110000 { @@ -681,6 +689,7 @@ clocks = <&prcc_kclk 2 0>, <&prcc_pclk 2 0>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; i2c@8012a000 { @@ -696,6 +705,7 @@ clocks = <&prcc_kclk 1 9>, <&prcc_pclk 1 10>; clock-names = "i2cclk", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; ssp@80002000 { @@ -709,6 +719,7 @@ dmas = <&dma 8 0 0x2>, /* Logical - DevToMem */ <&dma 8 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; ssp@80003000 { @@ -722,6 +733,7 @@ dmas = <&dma 9 0 0x2>, /* Logical - DevToMem */ <&dma 9 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@8011a000 { @@ -736,6 +748,7 @@ dmas = <&dma 0 0 0x2>, /* Logical - DevToMem */ <&dma 0 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80112000 { @@ -750,6 +763,7 @@ dmas = <&dma 35 0 0x2>, /* Logical - DevToMem */ <&dma 35 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80111000 { @@ -764,6 +778,7 @@ dmas = <&dma 33 0 0x2>, /* Logical - DevToMem */ <&dma 33 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; spi@80129000 { @@ -778,6 +793,7 @@ dmas = <&dma 40 0 0x2>, /* Logical - DevToMem */ <&dma 40 0 0x0>; /* Logical - MemToDev */ dma-names = "rx", "tx"; + power-domains = <&pm_domains DOMAIN_VAPE>; }; uart@80120000 { @@ -836,6 +852,7 @@ clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -851,6 +868,7 @@ clocks = <&prcc_kclk 2 4>, <&prcc_pclk 2 6>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -866,6 +884,7 @@ clocks = <&prcc_kclk 3 4>, <&prcc_pclk 3 4>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -881,6 +900,7 @@ clocks = <&prcc_kclk 2 5>, <&prcc_pclk 2 7>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -896,6 +916,7 @@ clocks = <&prcc_kclk 2 2>, <&prcc_pclk 2 4>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; @@ -911,6 +932,7 @@ clocks = <&prcc_kclk 3 7>, <&prcc_pclk 3 7>; clock-names = "sdi", "apb_pclk"; + power-domains = <&pm_domains DOMAIN_VAPE>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi index 543f895d18d3..2e652e2339e9 100644 --- a/arch/arm/boot/dts/sun6i-a31.dtsi +++ b/arch/arm/boot/dts/sun6i-a31.dtsi @@ -361,6 +361,10 @@ clocks = <&ahb1_gates 6>; resets = <&ahb1_rst 6>; #dma-cells = <1>; + + /* DMA controller requires AHB1 clocked from PLL6 */ + assigned-clocks = <&ahb1_mux>; + assigned-clock-parents = <&pll6>; }; mmc0: mmc@01c0f000 { diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts index 5c21d216515a..8b7aa0dcdc6e 100644 --- a/arch/arm/boot/dts/tegra114-dalmore.dts +++ b/arch/arm/boot/dts/tegra114-dalmore.dts @@ -15,6 +15,7 @@ aliases { rtc0 = "/i2c@7000d000/tps65913@58"; rtc1 = "/rtc@7000e000"; + serial0 = &uartd; }; memory { diff --git a/arch/arm/boot/dts/tegra114-roth.dts b/arch/arm/boot/dts/tegra114-roth.dts index c7c6825f11fb..38acf78d7815 100644 --- a/arch/arm/boot/dts/tegra114-roth.dts +++ b/arch/arm/boot/dts/tegra114-roth.dts @@ -15,6 +15,10 @@ linux,initrd-end = <0x82800000>; }; + aliases { + serial0 = &uartd; + }; + firmware { trusted-foundations { compatible = "tlm,trusted-foundations"; @@ -916,8 +920,6 @@ regulator-name = "vddio-sdmmc3"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; }; ldousb { @@ -962,7 +964,7 @@ sdhci@78000400 { status = "okay"; bus-width = <4>; - vmmc-supply = <&vddio_sdmmc3>; + vqmmc-supply = <&vddio_sdmmc3>; cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; power-gpios = <&gpio TEGRA_GPIO(H, 0) GPIO_ACTIVE_HIGH>; }; @@ -971,7 +973,6 @@ sdhci@78000600 { status = "okay"; bus-width = <8>; - vmmc-supply = <&vdd_1v8>; non-removable; }; diff --git a/arch/arm/boot/dts/tegra114-tn7.dts b/arch/arm/boot/dts/tegra114-tn7.dts index 963662145635..f91c2c9b2f94 100644 --- a/arch/arm/boot/dts/tegra114-tn7.dts +++ b/arch/arm/boot/dts/tegra114-tn7.dts @@ -15,6 +15,10 @@ linux,initrd-end = <0x82800000>; }; + aliases { + serial0 = &uartd; + }; + firmware { trusted-foundations { compatible = "tlm,trusted-foundations"; @@ -240,7 +244,6 @@ sdhci@78000600 { status = "okay"; bus-width = <8>; - vmmc-supply = <&vdd_1v8>; non-removable; }; diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 2ca9c1807f72..222f3b3f4dd5 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -9,13 +9,6 @@ compatible = "nvidia,tegra114"; interrupt-parent = <&gic>; - aliases { - serial0 = &uarta; - serial1 = &uartb; - serial2 = &uartc; - serial3 = &uartd; - }; - host1x@50000000 { compatible = "nvidia,tegra114-host1x", "simple-bus"; reg = <0x50000000 0x00028000>; diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts index 029c9a021541..51b373ff1065 100644 --- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts +++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@0,7000d000/pmic@40"; rtc1 = "/rtc@0,7000e000"; + serial0 = &uartd; }; memory { diff --git a/arch/arm/boot/dts/tegra124-nyan-big.dts b/arch/arm/boot/dts/tegra124-nyan-big.dts index 7d0784ce4c74..53181d310247 100644 --- a/arch/arm/boot/dts/tegra124-nyan-big.dts +++ b/arch/arm/boot/dts/tegra124-nyan-big.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@0,7000d000/pmic@40"; rtc1 = "/rtc@0,7000e000"; + serial0 = &uarta; }; memory { diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts index 13008858e967..5c3f7813360d 100644 --- a/arch/arm/boot/dts/tegra124-venice2.dts +++ b/arch/arm/boot/dts/tegra124-venice2.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@0,7000d000/pmic@40"; rtc1 = "/rtc@0,7000e000"; + serial0 = &uarta; }; memory { diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi index 478c555ebd96..df2b06b29985 100644 --- a/arch/arm/boot/dts/tegra124.dtsi +++ b/arch/arm/boot/dts/tegra124.dtsi @@ -286,7 +286,7 @@ * the APB DMA based serial driver, the comptible is * "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart". */ - serial@0,70006000 { + uarta: serial@0,70006000 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; reg = <0x0 0x70006000 0x0 0x40>; reg-shift = <2>; @@ -299,7 +299,7 @@ status = "disabled"; }; - serial@0,70006040 { + uartb: serial@0,70006040 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; reg = <0x0 0x70006040 0x0 0x40>; reg-shift = <2>; @@ -312,7 +312,7 @@ status = "disabled"; }; - serial@0,70006200 { + uartc: serial@0,70006200 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; reg = <0x0 0x70006200 0x0 0x40>; reg-shift = <2>; @@ -325,7 +325,7 @@ status = "disabled"; }; - serial@0,70006300 { + uartd: serial@0,70006300 { compatible = "nvidia,tegra124-uart", "nvidia,tegra20-uart"; reg = <0x0 0x70006300 0x0 0x40>; reg-shift = <2>; diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts index a37279af687c..b926a07b9443 100644 --- a/arch/arm/boot/dts/tegra20-harmony.dts +++ b/arch/arm/boot/dts/tegra20-harmony.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@7000d000/tps6586x@34"; rtc1 = "/rtc@7000e000"; + serial0 = &uartd; }; memory { diff --git a/arch/arm/boot/dts/tegra20-iris-512.dts b/arch/arm/boot/dts/tegra20-iris-512.dts index 8cfb83f42e1f..1dd7d7bfdfcc 100644 --- a/arch/arm/boot/dts/tegra20-iris-512.dts +++ b/arch/arm/boot/dts/tegra20-iris-512.dts @@ -6,6 +6,11 @@ model = "Toradex Colibri T20 512MB on Iris"; compatible = "toradex,iris", "toradex,colibri_t20-512", "nvidia,tegra20"; + aliases { + serial0 = &uarta; + serial1 = &uartd; + }; + host1x@50000000 { hdmi@54280000 { status = "okay"; diff --git a/arch/arm/boot/dts/tegra20-medcom-wide.dts b/arch/arm/boot/dts/tegra20-medcom-wide.dts index 1b7c56b33aca..9b87526ab0b7 100644 --- a/arch/arm/boot/dts/tegra20-medcom-wide.dts +++ b/arch/arm/boot/dts/tegra20-medcom-wide.dts @@ -6,6 +6,10 @@ model = "Avionic Design Medcom-Wide board"; compatible = "ad,medcom-wide", "ad,tamonten", "nvidia,tegra20"; + aliases { + serial0 = &uartd; + }; + pwm@7000a000 { status = "okay"; }; diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index d4438e30de45..ed7e1009326c 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -10,6 +10,8 @@ aliases { rtc0 = "/i2c@7000d000/tps6586x@34"; rtc1 = "/rtc@7000e000"; + serial0 = &uarta; + serial1 = &uartc; }; memory { diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts index a1d4bf9895d7..ea282c7c0ca5 100644 --- a/arch/arm/boot/dts/tegra20-seaboard.dts +++ b/arch/arm/boot/dts/tegra20-seaboard.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@7000d000/tps6586x@34"; rtc1 = "/rtc@7000e000"; + serial0 = &uartd; }; memory { diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi index 80e7d386ce34..13d4e6185275 100644 --- a/arch/arm/boot/dts/tegra20-tamonten.dtsi +++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi @@ -7,6 +7,7 @@ aliases { rtc0 = "/i2c@7000d000/tps6586x@34"; rtc1 = "/rtc@7000e000"; + serial0 = &uartd; }; memory { diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts index 5ad87979ab13..d99af4ef9c64 100644 --- a/arch/arm/boot/dts/tegra20-trimslice.dts +++ b/arch/arm/boot/dts/tegra20-trimslice.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@7000c500/rtc@56"; rtc1 = "/rtc@7000e000"; + serial0 = &uarta; }; memory { diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts index ca8484cccddc..04c58e9ca490 100644 --- a/arch/arm/boot/dts/tegra20-ventana.dts +++ b/arch/arm/boot/dts/tegra20-ventana.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@7000d000/tps6586x@34"; rtc1 = "/rtc@7000e000"; + serial0 = &uartd; }; memory { diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts index 1843725785c9..340d81108df1 100644 --- a/arch/arm/boot/dts/tegra20-whistler.dts +++ b/arch/arm/boot/dts/tegra20-whistler.dts @@ -10,6 +10,7 @@ aliases { rtc0 = "/i2c@7000d000/max8907@3c"; rtc1 = "/rtc@7000e000"; + serial0 = &uarta; }; memory { diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 3b374c49d04d..8acf5d85c99d 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -9,14 +9,6 @@ compatible = "nvidia,tegra20"; interrupt-parent = <&intc>; - aliases { - serial0 = &uarta; - serial1 = &uartb; - serial2 = &uartc; - serial3 = &uartd; - serial4 = &uarte; - }; - host1x@50000000 { compatible = "nvidia,tegra20-host1x", "simple-bus"; reg = <0x50000000 0x00024000>; diff --git a/arch/arm/boot/dts/tegra30-apalis-eval.dts b/arch/arm/boot/dts/tegra30-apalis-eval.dts index 45d40f024585..6236bdecb48b 100644 --- a/arch/arm/boot/dts/tegra30-apalis-eval.dts +++ b/arch/arm/boot/dts/tegra30-apalis-eval.dts @@ -11,6 +11,10 @@ rtc0 = "/i2c@7000c000/rtc@68"; rtc1 = "/i2c@7000d000/tps65911@2d"; rtc2 = "/rtc@7000e000"; + serial0 = &uarta; + serial1 = &uartb; + serial2 = &uartc; + serial3 = &uartd; }; pcie-controller@00003000 { diff --git a/arch/arm/boot/dts/tegra30-beaver.dts b/arch/arm/boot/dts/tegra30-beaver.dts index cee8f2246fdb..6b157eeabcc5 100644 --- a/arch/arm/boot/dts/tegra30-beaver.dts +++ b/arch/arm/boot/dts/tegra30-beaver.dts @@ -9,6 +9,7 @@ aliases { rtc0 = "/i2c@7000d000/tps65911@2d"; rtc1 = "/rtc@7000e000"; + serial0 = &uarta; }; memory { diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index 206379546244..a1b682ea01bd 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -30,6 +30,8 @@ aliases { rtc0 = "/i2c@7000d000/tps65911@2d"; rtc1 = "/rtc@7000e000"; + serial0 = &uarta; + serial1 = &uartc; }; memory { diff --git a/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts b/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts index 7793abd5bef1..4d3ddc585641 100644 --- a/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts +++ b/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts @@ -10,6 +10,9 @@ rtc0 = "/i2c@7000c000/rtc@68"; rtc1 = "/i2c@7000d000/tps65911@2d"; rtc2 = "/rtc@7000e000"; + serial0 = &uarta; + serial1 = &uartb; + serial2 = &uartd; }; host1x@50000000 { diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index aa6ccea13d30..b270b9e3d455 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -9,14 +9,6 @@ compatible = "nvidia,tegra30"; interrupt-parent = <&intc>; - aliases { - serial0 = &uarta; - serial1 = &uartb; - serial2 = &uartc; - serial3 = &uartd; - serial4 = &uarte; - }; - pcie-controller@00003000 { compatible = "nvidia,tegra30-pcie"; device_type = "pci"; diff --git a/arch/arm/boot/dts/vf610-cosmic.dts b/arch/arm/boot/dts/vf610-cosmic.dts index 3fd1b74e1216..de1b453c2932 100644 --- a/arch/arm/boot/dts/vf610-cosmic.dts +++ b/arch/arm/boot/dts/vf610-cosmic.dts @@ -33,6 +33,13 @@ }; +&esdhc1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_esdhc1>; + bus-width = <4>; + status = "okay"; +}; + &fec1 { phy-mode = "rmii"; pinctrl-names = "default"; @@ -42,6 +49,18 @@ &iomuxc { vf610-cosmic { + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + VF610_PAD_PTA24__ESDHC1_CLK 0x31ef + VF610_PAD_PTA25__ESDHC1_CMD 0x31ef + VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef + VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef + VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef + VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef + VF610_PAD_PTB28__GPIO_98 0x219d + >; + }; + pinctrl_fec1: fec1grp { fsl,pins = < VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2 diff --git a/arch/arm/boot/dts/zynq-parallella.dts b/arch/arm/boot/dts/zynq-parallella.dts index e1f51ca127fe..0429bbd89fba 100644 --- a/arch/arm/boot/dts/zynq-parallella.dts +++ b/arch/arm/boot/dts/zynq-parallella.dts @@ -34,6 +34,10 @@ }; }; +&clkc { + fclk-enable = <0xf>; +}; + &gem0 { status = "okay"; phy-mode = "rgmii-id"; diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index e093f2fcee7a..5662a872689b 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c @@ -26,6 +26,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/edma.h> +#include <linux/dma-mapping.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_dma.h> @@ -1625,6 +1626,11 @@ static int edma_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct device *dev = &pdev->dev; int ret; + struct platform_device_info edma_dev_info = { + .name = "edma-dma-engine", + .dma_mask = DMA_BIT_MASK(32), + .parent = &pdev->dev, + }; if (node) { /* Check if this is a second instance registered */ @@ -1796,6 +1802,9 @@ static int edma_probe(struct platform_device *pdev) } edma_cc[j]->info = info[j]; arch_num_cc++; + + edma_dev_info.id = j; + platform_device_register_full(&edma_dev_info); } return 0; diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig index bc614f44b33d..83a87e48901c 100644 --- a/arch/arm/configs/bcm_defconfig +++ b/arch/arm/configs/bcm_defconfig @@ -25,7 +25,8 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_BCM=y -CONFIG_ARCH_BCM_MOBILE=y +CONFIG_ARCH_BCM_21664=y +CONFIG_ARCH_BCM_281XX=y CONFIG_ARM_THUMBEE=y CONFIG_SMP=y CONFIG_PREEMPT=y diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 72058b8a6f4d..e21ef830a483 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig @@ -142,11 +142,13 @@ CONFIG_MMC_DW_IDMAC=y CONFIG_MMC_DW_EXYNOS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_MAX77686=y +CONFIG_RTC_DRV_MAX77802=y CONFIG_RTC_DRV_S5M=y CONFIG_RTC_DRV_S3C=y CONFIG_DMADEVICES=y CONFIG_PL330_DMA=y CONFIG_COMMON_CLK_MAX77686=y +CONFIG_COMMON_CLK_MAX77802=y CONFIG_COMMON_CLK_S2MPS11=y CONFIG_EXYNOS_IOMMU=y CONFIG_IIO=y diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index e688741c89aa..e6b0007355f8 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -97,6 +97,7 @@ CONFIG_SERIAL_IMX_CONSOLE=y # CONFIG_HW_RANDOM is not set CONFIG_I2C_CHARDEV=y CONFIG_I2C_IMX=y +CONFIG_SPI=y CONFIG_SPI_IMX=y CONFIG_SPI_SPIDEV=y CONFIG_GPIO_SYSFS=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 8fca6e276b69..6790f1b3f3a1 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -158,6 +158,7 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_ALGOPCF=m CONFIG_I2C_ALGOPCA=m CONFIG_I2C_IMX=y +CONFIG_SPI=y CONFIG_SPI_IMX=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_MC9S08DZ60=y diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig index c1f5adc5493e..71f14675d009 100644 --- a/arch/arm/configs/integrator_defconfig +++ b/arch/arm/configs/integrator_defconfig @@ -8,6 +8,9 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_MULTI_V4T=y +CONFIG_ARCH_MULTI_V5=y +# CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_INTEGRATOR=y CONFIG_ARCH_INTEGRATOR_AP=y CONFIG_ARCH_INTEGRATOR_CP=y diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig deleted file mode 100644 index b33d19b7f134..000000000000 --- a/arch/arm/configs/koelsch_defconfig +++ /dev/null @@ -1,113 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_NO_HZ=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_LOG_BUF_SHIFT=16 -CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_SYSCTL_SYSCALL=y -CONFIG_EMBEDDED=y -CONFIG_PERF_EVENTS=y -CONFIG_SLAB=y -CONFIG_ARCH_SHMOBILE_LEGACY=y -CONFIG_ARCH_R8A7791=y -CONFIG_MACH_KOELSCH=y -# CONFIG_SWP_EMULATE is not set -CONFIG_CPU_BPREDICT_DISABLE=y -CONFIG_PL310_ERRATA_588369=y -CONFIG_ARM_ERRATA_754322=y -CONFIG_PCI=y -CONFIG_PCI_RCAR_GEN2=y -CONFIG_PCI_RCAR_GEN2_PCIE=y -CONFIG_SMP=y -CONFIG_SCHED_MC=y -CONFIG_NR_CPUS=8 -CONFIG_AEABI=y -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_ARM_APPENDED_DTB=y -CONFIG_KEXEC=y -CONFIG_AUTO_ZRELADDR=y -CONFIG_VFP=y -CONFIG_NEON=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_PM_RUNTIME=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_BLK_DEV_SD=y -CONFIG_ATA=y -CONFIG_SATA_RCAR=y -CONFIG_MTD=y -CONFIG_MTD_M25P80=y -CONFIG_MTD_SPI_NOR=y -CONFIG_EEPROM_AT24=y -CONFIG_NETDEVICES=y -# CONFIG_NET_VENDOR_ARC is not set -# CONFIG_NET_CADENCE is not set -# CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_NET_VENDOR_CIRRUS is not set -# CONFIG_NET_VENDOR_FARADAY is not set -# CONFIG_NET_VENDOR_INTEL is not set -# CONFIG_NET_VENDOR_MARVELL is not set -# CONFIG_NET_VENDOR_MICREL is not set -# CONFIG_NET_VENDOR_NATSEMI is not set -CONFIG_SH_ETH=y -# CONFIG_NET_VENDOR_SEEQ is not set -# CONFIG_NET_VENDOR_SMSC is not set -# CONFIG_NET_VENDOR_STMICRO is not set -# CONFIG_NET_VENDOR_VIA is not set -# CONFIG_NET_VENDOR_WIZNET is not set -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -# CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_SH_SCI=y -CONFIG_SERIAL_SH_SCI_NR_UARTS=20 -CONFIG_SERIAL_SH_SCI_CONSOLE=y -CONFIG_I2C=y -CONFIG_I2C_MUX=y -CONFIG_I2C_SH_MOBILE=y -CONFIG_I2C_RCAR=y -CONFIG_SPI=y -CONFIG_SPI_RSPI=y -CONFIG_SPI_SH_MSIOF=y -CONFIG_GPIOLIB=y -CONFIG_GPIO_RCAR=y -# CONFIG_HWMON is not set -CONFIG_THERMAL=y -CONFIG_RCAR_THERMAL=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_DA9210=y -CONFIG_REGULATOR_GPIO=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_SOC_CAMERA=y -CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_VIDEO_RCAR_VIN=y -# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set -CONFIG_VIDEO_ADV7180=y -# CONFIG_HID is not set -# CONFIG_USB_SUPPORT is not set -CONFIG_MMC=y -CONFIG_MMC_SDHI=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y -# CONFIG_IOMMU_SUPPORT is not set -# CONFIG_DNOTIFY is not set -CONFIG_TMPFS=y -CONFIG_CONFIGFS_FS=y -# CONFIG_MISC_FILESYSTEMS is not set -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -# CONFIG_ENABLE_MUST_CHECK is not set -# CONFIG_ARM_UNWIND is not set diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index f1dc7fc668f3..9d7a32f93fcf 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -217,6 +217,7 @@ CONFIG_I2C_CADENCE=y CONFIG_I2C_DESIGNWARE_PLATFORM=y CONFIG_I2C_EXYNOS5=y CONFIG_I2C_MV64XXX=y +CONFIG_I2C_S3C2410=y CONFIG_I2C_SIRF=y CONFIG_I2C_TEGRA=y CONFIG_I2C_ST=y @@ -235,6 +236,7 @@ CONFIG_SPI_TEGRA20_SLINK=y CONFIG_SPI_XILINX=y CONFIG_PINCTRL_AS3722=y CONFIG_PINCTRL_PALMAS=y +CONFIG_PINCTRL_APQ8084=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_GENERIC_PLATFORM=y CONFIG_GPIO_DWAPB=y @@ -411,6 +413,7 @@ CONFIG_NVEC_POWER=y CONFIG_NVEC_PAZ00=y CONFIG_QCOM_GSBI=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_APQ_MMCC_8084=y CONFIG_MSM_GCC_8660=y CONFIG_MSM_MMCC_8960=y CONFIG_MSM_MMCC_8974=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 16e719c268dd..b3f86670d2eb 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -86,7 +86,6 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y # CONFIG_INET_LRO is not set -CONFIG_IPV6=y CONFIG_NETFILTER=y CONFIG_CAN=m CONFIG_CAN_C_CAN=m @@ -112,6 +111,7 @@ CONFIG_MTD_OOPS=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ECC_BCH=y CONFIG_MTD_NAND_OMAP2=y CONFIG_MTD_ONENAND=y CONFIG_MTD_ONENAND_VERIFY_WRITE=y @@ -317,7 +317,7 @@ CONFIG_EXT4_FS=y CONFIG_FANOTIFY=y CONFIG_QUOTA=y CONFIG_QFMT_V2=y -CONFIG_AUTOFS4_FS=y +CONFIG_AUTOFS4_FS=m CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index d7346ad51043..c8201a93b54d 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -17,7 +17,6 @@ CONFIG_ARCH_R8A7779=y CONFIG_ARCH_R8A7790=y CONFIG_ARCH_R8A7791=y CONFIG_ARCH_R8A7794=y -CONFIG_MACH_KOELSCH=y CONFIG_MACH_LAGER=y CONFIG_MACH_MARZEN=y # CONFIG_SWP_EMULATE is not set diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index d7a5855a5db8..a2956c3112f1 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -1,5 +1,6 @@ -CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y +CONFIG_FHANDLE=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -11,23 +12,17 @@ CONFIG_PROFILING=y CONFIG_OPROFILE=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -CONFIG_HOTPLUG=y # CONFIG_LBDAF is not set # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set CONFIG_ARCH_SOCFPGA=y -CONFIG_MACH_SOCFPGA_CYCLONE5=y CONFIG_ARM_THUMBEE=y -# CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set -# CONFIG_CACHE_L2X0 is not set -CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y CONFIG_NR_CPUS=2 CONFIG_AEABI=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="" CONFIG_VFP=y CONFIG_NEON=y CONFIG_NET=y @@ -41,38 +36,30 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y +CONFIG_IPV6=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_VLAN_8021Q=y +CONFIG_VLAN_8021Q_GVRP=y CONFIG_CAN=y -CONFIG_CAN_RAW=y -CONFIG_CAN_BCM=y -CONFIG_CAN_GW=y -CONFIG_CAN_DEV=y -CONFIG_CAN_CALC_BITTIMING=y CONFIG_CAN_C_CAN=y CONFIG_CAN_C_CAN_PLATFORM=y CONFIG_CAN_DEBUG_DEVICES=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y -CONFIG_PROC_DEVICETREE=y +CONFIG_DEVTMPFS_MOUNT=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=2 CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_SRAM=y CONFIG_SCSI=y # CONFIG_SCSI_PROC_FS is not set CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y CONFIG_STMMAC_ETH=y +CONFIG_DWMAC_SOCFPGA=y CONFIG_MICREL_PHY=y -# CONFIG_STMMAC_PHY_ID_ZERO_WORKAROUND is not set CONFIG_INPUT_EVDEV=y -CONFIG_DWMAC_SOCFPGA=y -CONFIG_PPS=y -CONFIG_NETWORK_PHY_TIMESTAMPING=y -CONFIG_PTP_1588_CLOCK=y -CONFIG_VLAN_8021Q=y -CONFIG_VLAN_8021Q_GVRP=y -CONFIG_GARP=y -CONFIG_IPV6=y # CONFIG_SERIO_SERPORT is not set CONFIG_SERIO_AMBAKMI=y CONFIG_LEGACY_PTY_COUNT=16 @@ -81,45 +68,43 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 CONFIG_SERIAL_8250_DW=y +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_DWAPB=y -# CONFIG_RTC_HCTOSYS is not set +CONFIG_PMBUS=y +CONFIG_SENSORS_LTC2978=y +CONFIG_SENSORS_LTC2978_REGULATOR=y CONFIG_WATCHDOG=y CONFIG_DW_WATCHDOG=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_USB=y +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_HOST=y +CONFIG_MMC=y +CONFIG_MMC_DW=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y CONFIG_EXT3_FS=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -# CONFIG_DNOTIFY is not set -# CONFIG_INOTIFY_USER is not set -CONFIG_FHANDLE=y +CONFIG_EXT4_FS=y CONFIG_VFAT_FS=y CONFIG_NTFS_FS=y CONFIG_NTFS_RW=y CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y +CONFIG_CONFIGFS_FS=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_SCHED_DEBUG is not set -CONFIG_DEBUG_INFO=y CONFIG_ENABLE_DEFAULT_TRACERS=y CONFIG_DEBUG_USER=y CONFIG_XZ_DEC=y -CONFIG_I2C=y -CONFIG_I2C_DESIGNWARE_CORE=y -CONFIG_I2C_DESIGNWARE_PLATFORM=y -CONFIG_I2C_CHARDEV=y -CONFIG_MMC=y -CONFIG_MMC_DW=y -CONFIG_PM=y -CONFIG_SUSPEND=y -CONFIG_MMC_UNSAFE_RESUME=y -CONFIG_USB=y -CONFIG_USB_DWC2=y -CONFIG_USB_DWC2_HOST=y -CONFIG_USB_DWC2_PLATFORM=y diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 2c9f10df7568..89aefe10d66b 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -28,7 +28,7 @@ struct firmware_ops { /* * Enters CPU idle mode */ - int (*do_idle)(void); + int (*do_idle)(unsigned long mode); /* * Sets boot address of specified physical CPU */ @@ -41,6 +41,14 @@ struct firmware_ops { * Initializes L2 cache */ int (*l2x0_init)(void); + /* + * Enter system-wide suspend. + */ + int (*suspend)(void); + /* + * Restore state of privileged hardware after system-wide suspend. + */ + int (*resume)(void); }; /* Global pointer for current firmware_ops structure, can't be NULL. */ diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index fc44d3761f9e..ce73ab635414 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -44,16 +44,6 @@ struct cpu_context_save { __u32 extra[2]; /* Xscale 'acc' register, etc */ }; -struct arm_restart_block { - union { - /* For user cache flushing */ - struct { - unsigned long start; - unsigned long end; - } cache; - }; -}; - /* * low level task data that entry.S needs immediate access to. * __switch_to() assumes cpu_context follows immediately after cpu_domain. @@ -79,7 +69,6 @@ struct thread_info { unsigned long thumbee_state; /* ThumbEE Handler Base register */ #endif struct restart_block restart_block; - struct arm_restart_block arm_restart_block; }; #define INIT_THREAD_INFO(tsk) \ diff --git a/arch/arm/include/debug/asm9260.S b/arch/arm/include/debug/asm9260.S new file mode 100644 index 000000000000..292f85b49fca --- /dev/null +++ b/arch/arm/include/debug/asm9260.S @@ -0,0 +1,29 @@ +/* Debugging macro include header + * + * Copyright (C) 1994-1999 Russell King + * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks + * Modified for ASM9260 by Oleksij Remepl <linux@rempel-privat.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + + .macro addruart, rp, rv, tmp + ldr \rp, = CONFIG_DEBUG_UART_PHYS + ldr \rv, = CONFIG_DEBUG_UART_VIRT + .endm + + .macro waituart,rd,rx + .endm + + .macro senduart,rd,rx + str \rd, [\rx, #0x50] @ TXDATA + .endm + + .macro busyuart,rd,rx +1002: ldr \rd, [\rx, #0x60] @ STAT + tst \rd, #1 << 27 @ TXEMPTY + beq 1002b @ wait until transmit done + .endm diff --git a/arch/arm/include/debug/renesas-scif.S b/arch/arm/include/debug/renesas-scif.S new file mode 100644 index 000000000000..97820a8df51a --- /dev/null +++ b/arch/arm/include/debug/renesas-scif.S @@ -0,0 +1,52 @@ +/* + * Renesas SCIF(A) debugging macro include header + * + * Based on r8a7790.S + * + * Copyright (C) 2012-2013 Renesas Electronics Corporation + * Copyright (C) 1994-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define SCIF_PHYS CONFIG_DEBUG_UART_PHYS +#define SCIF_VIRT ((SCIF_PHYS & 0x00ffffff) | 0xfd000000) + +#if CONFIG_DEBUG_UART_PHYS < 0xe6e00000 +/* SCIFA */ +#define FTDR 0x20 +#define FSR 0x14 +#else +/* SCIF */ +#define FTDR 0x0c +#define FSR 0x10 +#endif + +#define TDFE (1 << 5) +#define TEND (1 << 6) + + .macro addruart, rp, rv, tmp + ldr \rp, =SCIF_PHYS + ldr \rv, =SCIF_VIRT + .endm + + .macro waituart, rd, rx +1001: ldrh \rd, [\rx, #FSR] + tst \rd, #TDFE + beq 1001b + .endm + + .macro senduart, rd, rx + strb \rd, [\rx, #FTDR] + ldrh \rd, [\rx, #FSR] + bic \rd, \rd, #TEND + strh \rd, [\rx, #FSR] + .endm + + .macro busyuart, rd, rx +1001: ldrh \rd, [\rx, #FSR] + tst \rd, #TEND + beq 1001b + .endm diff --git a/arch/arm/mach-sa1100/include/mach/debug-macro.S b/arch/arm/include/debug/sa1100.S index 530772d937ad..a0ae4f4cd924 100644 --- a/arch/arm/mach-sa1100/include/mach/debug-macro.S +++ b/arch/arm/include/debug/sa1100.S @@ -1,4 +1,4 @@ -/* arch/arm/mach-sa1100/include/mach/debug-macro.S +/* arch/arm/include/debug/sa1100.S * * Debugging macro include header * @@ -10,7 +10,13 @@ * published by the Free Software Foundation. * */ -#include <mach/hardware.h> + +#define UTCR3 0x0c +#define UTDR 0x14 +#define UTSR1 0x20 +#define UTCR3_TXE 0x00000002 /* Transmit Enable */ +#define UTSR1_TBY 0x00000001 /* Transmitter BusY (read) */ +#define UTSR1_TNF 0x00000004 /* Transmit FIFO Not Full (read) */ .macro addruart, rp, rv, tmp mrc p15, 0, \rp, c1, c0 diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 0c8b10801d36..9f5d81881eb6 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -533,8 +533,6 @@ static int bad_syscall(int n, struct pt_regs *regs) return regs->ARM_r0; } -static long do_cache_op_restart(struct restart_block *); - static inline int __do_cache_op(unsigned long start, unsigned long end) { @@ -543,24 +541,8 @@ __do_cache_op(unsigned long start, unsigned long end) do { unsigned long chunk = min(PAGE_SIZE, end - start); - if (signal_pending(current)) { - struct thread_info *ti = current_thread_info(); - - ti->restart_block = (struct restart_block) { - .fn = do_cache_op_restart, - }; - - ti->arm_restart_block = (struct arm_restart_block) { - { - .cache = { - .start = start, - .end = end, - }, - }, - }; - - return -ERESTART_RESTARTBLOCK; - } + if (fatal_signal_pending(current)) + return 0; ret = flush_cache_user_range(start, start + chunk); if (ret) @@ -573,15 +555,6 @@ __do_cache_op(unsigned long start, unsigned long end) return 0; } -static long do_cache_op_restart(struct restart_block *unused) -{ - struct arm_restart_block *restart_block; - - restart_block = ¤t_thread_info()->arm_restart_block; - return __do_cache_op(restart_block->cache.start, - restart_block->cache.end); -} - static inline int do_cache_op(unsigned long start, unsigned long end, int flags) { diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 57a403a5c22b..8664ff17cbbe 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -197,7 +197,8 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp, pgd = pgdp + pgd_index(addr); do { next = kvm_pgd_addr_end(addr, end); - unmap_puds(kvm, pgd, addr, next); + if (!pgd_none(*pgd)) + unmap_puds(kvm, pgd, addr, next); } while (pgd++, addr = next, addr != end); } @@ -834,6 +835,11 @@ static bool kvm_is_write_fault(struct kvm_vcpu *vcpu) return kvm_vcpu_dabt_iswrite(vcpu); } +static bool kvm_is_device_pfn(unsigned long pfn) +{ + return !pfn_valid(pfn); +} + static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm_memory_slot *memslot, unsigned long hva, unsigned long fault_status) @@ -904,7 +910,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (is_error_pfn(pfn)) return -EFAULT; - if (kvm_is_mmio_pfn(pfn)) + if (kvm_is_device_pfn(pfn)) mem_type = PAGE_S2_DEVICE; spin_lock(&kvm->mmu_lock); diff --git a/arch/arm/mach-asm9260/Kconfig b/arch/arm/mach-asm9260/Kconfig new file mode 100644 index 000000000000..8423be76080e --- /dev/null +++ b/arch/arm/mach-asm9260/Kconfig @@ -0,0 +1,6 @@ +config MACH_ASM9260 + bool "Alphascale ASM9260" + depends on ARCH_MULTI_V5 + select CPU_ARM926T + help + Support for Alphascale ASM9260 based platform. diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 3d225105e0d1..b6117bea9a6f 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -11,6 +11,7 @@ */ #include <asm/system_misc.h> +#include <asm/irq.h> #include <mach/hardware.h> #include "soc.h" diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index bd7e56889b43..f25b9aec9c50 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -10,6 +10,7 @@ */ #include <asm/system_misc.h> +#include <asm/irq.h> #include <mach/cpu.h> #include <mach/at91_dbgu.h> #include <mach/hardware.h> diff --git a/arch/arm/mach-at91/include/mach/atmel-mci.h b/arch/arm/mach-at91/include/mach/atmel-mci.h deleted file mode 100644 index 3069e4135573..000000000000 --- a/arch/arm/mach-at91/include/mach/atmel-mci.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __MACH_ATMEL_MCI_H -#define __MACH_ATMEL_MCI_H - -#include <linux/platform_data/dma-atmel.h> - -/** - * struct mci_dma_data - DMA data for MCI interface - */ -struct mci_dma_data { - struct at_dma_slave sdata; -}; - -/* accessor macros */ -#define slave_data_ptr(s) (&(s)->sdata) -#define find_slave_dev(s) ((s)->sdata.dma_dev) - -#endif /* __MACH_ATMEL_MCI_H */ diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index 9625dddb5cd3..1bd39b45d08b 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -5,8 +5,56 @@ menuconfig ARCH_BCM if ARCH_BCM +comment "IPROC architected SoCs" + +config ARCH_BCM_IPROC + bool + select ARM_GIC + select CACHE_L2X0 + select HAVE_ARM_SCU if SMP + select HAVE_ARM_TWD if SMP + select ARM_GLOBAL_TIMER + + select CLKSRC_MMIO + select ARCH_REQUIRE_GPIOLIB + select ARM_AMBA + select PINCTRL + help + This enables support for systems based on Broadcom IPROC architected SoCs. + The IPROC complex contains one or more ARM CPUs along with common + core periperals. Application specific SoCs are created by adding a + uArchitecture containing peripherals outside of the IPROC complex. + Currently supported SoCs are Cygnus. + +config ARCH_BCM_CYGNUS + bool "Broadcom Cygnus Support" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC + help + Enable support for the Cygnus family, + which includes the following variants: + BCM11300, BCM11320, BCM11350, BCM11360, + BCM58300, BCM58302, BCM58303, BCM58305. + +config ARCH_BCM_5301X + bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 + select ARCH_BCM_IPROC + help + Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. + + This is a network SoC line mostly used in home routers and + wifi access points, it's internal name is Northstar. + This inclused the following SoC: BCM53010, BCM53011, BCM53012, + BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, + BCM4708 and BCM4709. + + Do not confuse this with the BCM4760 which is a totally + different SoC or with the older BCM47XX and BCM53XX based + network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx + +comment "KONA architected SoCs" + config ARCH_BCM_MOBILE - bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7 + bool select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_754322 select ARM_ERRATA_775420 @@ -15,16 +63,13 @@ config ARCH_BCM_MOBILE select TICK_ONESHOT select HAVE_ARM_ARCH_TIMER select PINCTRL + select ARCH_BCM_MOBILE_SMP if SMP help This enables support for systems based on Broadcom mobile SoCs. -if ARCH_BCM_MOBILE - -menu "Broadcom Mobile SoC Selection" - config ARCH_BCM_281XX bool "Broadcom BCM281XX SoC family" - default y + select ARCH_BCM_MOBILE select HAVE_SMP help Enable support for the BCM281XX family, which includes @@ -33,7 +78,7 @@ config ARCH_BCM_281XX config ARCH_BCM_21664 bool "Broadcom BCM21664 SoC family" - default y + select ARCH_BCM_MOBILE select HAVE_SMP help Enable support for the BCM21664 family, which includes @@ -41,19 +86,18 @@ config ARCH_BCM_21664 config ARCH_BCM_MOBILE_L2_CACHE bool "Broadcom mobile SoC level 2 cache support" - depends on (ARCH_BCM_281XX || ARCH_BCM_21664) + depends on ARCH_BCM_MOBILE default y select CACHE_L2X0 select ARCH_BCM_MOBILE_SMC config ARCH_BCM_MOBILE_SMC bool - depends on ARCH_BCM_281XX || ARCH_BCM_21664 + depends on ARCH_BCM_MOBILE config ARCH_BCM_MOBILE_SMP - bool "Broadcom mobile SoC SMP support" - depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP - default y + bool + depends on ARCH_BCM_MOBILE select HAVE_ARM_SCU select ARM_ERRATA_764369 help @@ -61,9 +105,7 @@ config ARCH_BCM_MOBILE_SMP Provided as an option so SMP support for SoCs of this type can be disabled for an SMP-enabled kernel. -endmenu - -endif +comment "Other Architectures" config ARCH_BCM2835 bool "Broadcom BCM2835 family" if ARCH_MULTI_V6 @@ -78,27 +120,6 @@ config ARCH_BCM2835 This enables support for the Broadcom BCM2835 SoC. This SoC is used in the Raspberry Pi and Roku 2 devices. -config ARCH_BCM_5301X - bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7 - select ARM_GIC - select CACHE_L2X0 - select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if SMP - select ARM_GLOBAL_TIMER - select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK - help - Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores. - - This is a network SoC line mostly used in home routers and - wifi access points, it's internal name is Northstar. - This inclused the following SoC: BCM53010, BCM53011, BCM53012, - BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707, - BCM4708 and BCM4709. - - Do not confuse this with the BCM4760 which is a totally - different SoC or with the older BCM47XX and BCM53XX based - network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx - config ARCH_BCM_63XX bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7 depends on MMU diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 6710ea321220..4c38674c73ec 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -10,6 +10,9 @@ # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. +# Cygnus +obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o + # BCM281XX obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c new file mode 100644 index 000000000000..30dc58be51b8 --- /dev/null +++ b/arch/arm/mach-bcm/bcm_cygnus.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <asm/mach/arch.h> + +static const char const *bcm_cygnus_dt_compat[] = { + "brcm,cygnus", + NULL, +}; + +DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC") + .l2c_aux_val = 0, + .l2c_aux_mask = ~0, + .dt_compat = bcm_cygnus_dt_compat, +MACHINE_END diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig index 24f85be71671..3e40a947f3ea 100644 --- a/arch/arm/mach-berlin/Kconfig +++ b/arch/arm/mach-berlin/Kconfig @@ -1,10 +1,11 @@ menuconfig ARCH_BERLIN bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 + select ARCH_HAS_RESET_CONTROLLER select ARCH_REQUIRE_GPIOLIB select ARM_GIC - select GENERIC_IRQ_CHIP select DW_APB_ICTL select DW_APB_TIMER_OF + select GENERIC_IRQ_CHIP select PINCTRL if ARCH_BERLIN diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index 5623131c4f0b..f8f62fbaa915 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -80,8 +80,8 @@ static int da830_evm_usb_ocic_notify(da8xx_ocic_handler_t handler) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "OHCI over-current indicator", NULL); if (error) - printk(KERN_ERR "%s: could not request IRQ to watch " - "over-current indicator changes\n", __func__); + pr_err("%s: could not request IRQ to watch over-current indicator changes\n", + __func__); } else free_irq(irq, NULL); @@ -145,8 +145,7 @@ static __init void da830_evm_usb_init(void) /* USB_REFCLKIN is not used. */ ret = davinci_cfg_reg(DA830_USB0_DRVVBUS); if (ret) - pr_warning("%s: USB 2.0 PinMux setup failed: %d\n", - __func__, ret); + pr_warn("%s: USB 2.0 PinMux setup failed: %d\n", __func__, ret); else { /* * TPS2065 switch @ 5V supplies 1 A (sustains 1.5 A), @@ -154,37 +153,35 @@ static __init void da830_evm_usb_init(void) */ ret = da8xx_register_usb20(1000, 3); if (ret) - pr_warning("%s: USB 2.0 registration failed: %d\n", - __func__, ret); + pr_warn("%s: USB 2.0 registration failed: %d\n", + __func__, ret); } ret = davinci_cfg_reg_list(da830_evm_usb11_pins); if (ret) { - pr_warning("%s: USB 1.1 PinMux setup failed: %d\n", - __func__, ret); + pr_warn("%s: USB 1.1 PinMux setup failed: %d\n", __func__, ret); return; } ret = gpio_request(ON_BD_USB_DRV, "ON_BD_USB_DRV"); if (ret) { - printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port " - "power control: %d\n", __func__, ret); + pr_err("%s: failed to request GPIO for USB 1.1 port power control: %d\n", + __func__, ret); return; } gpio_direction_output(ON_BD_USB_DRV, 0); ret = gpio_request(ON_BD_USB_OVC, "ON_BD_USB_OVC"); if (ret) { - printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port " - "over-current indicator: %d\n", __func__, ret); + pr_err("%s: failed to request GPIO for USB 1.1 port over-current indicator: %d\n", + __func__, ret); return; } gpio_direction_input(ON_BD_USB_OVC); ret = da8xx_register_usb11(&da830_evm_usb11_pdata); if (ret) - pr_warning("%s: USB 1.1 registration failed: %d\n", - __func__, ret); + pr_warn("%s: USB 1.1 registration failed: %d\n", __func__, ret); } static const short da830_evm_mcasp1_pins[] = { @@ -252,31 +249,29 @@ static inline void da830_evm_init_mmc(void) ret = davinci_cfg_reg_list(da830_evm_mmc_sd_pins); if (ret) { - pr_warning("da830_evm_init: mmc/sd mux setup failed: %d\n", - ret); + pr_warn("%s: mmc/sd mux setup failed: %d\n", __func__, ret); return; } ret = gpio_request(DA830_MMCSD_WP_PIN, "MMC WP"); if (ret) { - pr_warning("da830_evm_init: can not open GPIO %d\n", - DA830_MMCSD_WP_PIN); + pr_warn("%s: can not open GPIO %d\n", + __func__, DA830_MMCSD_WP_PIN); return; } gpio_direction_input(DA830_MMCSD_WP_PIN); ret = gpio_request(DA830_MMCSD_CD_PIN, "MMC CD\n"); if (ret) { - pr_warning("da830_evm_init: can not open GPIO %d\n", - DA830_MMCSD_CD_PIN); + pr_warn("%s: can not open GPIO %d\n", + __func__, DA830_MMCSD_CD_PIN); return; } gpio_direction_input(DA830_MMCSD_CD_PIN); ret = da8xx_register_mmcsd0(&da830_evm_mmc_config); if (ret) { - pr_warning("da830_evm_init: mmc/sd registration failed: %d\n", - ret); + pr_warn("%s: mmc/sd registration failed: %d\n", __func__, ret); gpio_free(DA830_MMCSD_WP_PIN); } } @@ -404,23 +399,21 @@ static inline void da830_evm_init_nand(int mux_mode) int ret; if (HAS_MMC) { - pr_warning("WARNING: both MMC/SD and NAND are " - "enabled, but they share AEMIF pins.\n" - "\tDisable MMC/SD for NAND support.\n"); + pr_warn("WARNING: both MMC/SD and NAND are enabled, but they share AEMIF pins\n" + "\tDisable MMC/SD for NAND support\n"); return; } ret = davinci_cfg_reg_list(da830_evm_emif25_pins); if (ret) - pr_warning("da830_evm_init: emif25 mux setup failed: %d\n", - ret); + pr_warn("%s: emif25 mux setup failed: %d\n", __func__, ret); ret = platform_device_register(&da830_evm_nand_device); if (ret) - pr_warning("da830_evm_init: NAND device not registered.\n"); + pr_warn("%s: NAND device not registered\n", __func__); if (davinci_aemif_setup(&da830_evm_nand_device)) - pr_warn("%s: Cannot configure AEMIF.\n", __func__); + pr_warn("%s: Cannot configure AEMIF\n", __func__); gpio_direction_output(mux_mode, 1); } @@ -435,12 +428,11 @@ static inline void da830_evm_init_lcdc(int mux_mode) ret = davinci_cfg_reg_list(da830_lcdcntl_pins); if (ret) - pr_warning("da830_evm_init: lcdcntl mux setup failed: %d\n", - ret); + pr_warn("%s: lcdcntl mux setup failed: %d\n", __func__, ret); ret = da8xx_register_lcdc(&sharp_lcd035q3dg01_pdata); if (ret) - pr_warning("da830_evm_init: lcd setup failed: %d\n", ret); + pr_warn("%s: lcd setup failed: %d\n", __func__, ret); gpio_direction_output(mux_mode, 0); } @@ -598,22 +590,19 @@ static __init void da830_evm_init(void) ret = da830_register_gpio(); if (ret) - pr_warn("da830_evm_init: GPIO init failed: %d\n", ret); + pr_warn("%s: GPIO init failed: %d\n", __func__, ret); ret = da830_register_edma(da830_edma_rsv); if (ret) - pr_warning("da830_evm_init: edma registration failed: %d\n", - ret); + pr_warn("%s: edma registration failed: %d\n", __func__, ret); ret = davinci_cfg_reg_list(da830_i2c0_pins); if (ret) - pr_warning("da830_evm_init: i2c0 mux setup failed: %d\n", - ret); + pr_warn("%s: i2c0 mux setup failed: %d\n", __func__, ret); ret = da8xx_register_i2c(0, &da830_evm_i2c_0_pdata); if (ret) - pr_warning("da830_evm_init: i2c0 registration failed: %d\n", - ret); + pr_warn("%s: i2c0 registration failed: %d\n", __func__, ret); da830_evm_usb_init(); @@ -622,18 +611,16 @@ static __init void da830_evm_init(void) ret = davinci_cfg_reg_list(da830_cpgmac_pins); if (ret) - pr_warning("da830_evm_init: cpgmac mux setup failed: %d\n", - ret); + pr_warn("%s: cpgmac mux setup failed: %d\n", __func__, ret); ret = da8xx_register_emac(); if (ret) - pr_warning("da830_evm_init: emac registration failed: %d\n", - ret); + pr_warn("%s: emac registration failed: %d\n", __func__, ret); ret = da8xx_register_watchdog(); if (ret) - pr_warning("da830_evm_init: watchdog registration failed: %d\n", - ret); + pr_warn("%s: watchdog registration failed: %d\n", + __func__, ret); davinci_serial_init(da8xx_serial_device); i2c_register_board_info(1, da830_evm_i2c_devices, @@ -641,8 +628,7 @@ static __init void da830_evm_init(void) ret = davinci_cfg_reg_list(da830_evm_mcasp1_pins); if (ret) - pr_warning("da830_evm_init: mcasp1 mux setup failed: %d\n", - ret); + pr_warn("%s: mcasp1 mux setup failed: %d\n", __func__, ret); da8xx_register_mcasp(1, &da830_evm_snd_data); @@ -650,18 +636,17 @@ static __init void da830_evm_init(void) ret = da8xx_register_rtc(); if (ret) - pr_warning("da830_evm_init: rtc setup failed: %d\n", ret); + pr_warn("%s: rtc setup failed: %d\n", __func__, ret); ret = spi_register_board_info(da830evm_spi_info, ARRAY_SIZE(da830evm_spi_info)); if (ret) - pr_warn("%s: spi info registration failed: %d\n", __func__, - ret); + pr_warn("%s: spi info registration failed: %d\n", + __func__, ret); ret = da8xx_register_spi_bus(0, ARRAY_SIZE(da830evm_spi_info)); if (ret) - pr_warning("da830_evm_init: spi 0 registration failed: %d\n", - ret); + pr_warn("%s: spi 0 registration failed: %d\n", __func__, ret); } #ifdef CONFIG_SERIAL_8250_CONSOLE diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index fa11415e906a..6b5a97da9fe3 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -452,8 +452,7 @@ static void da850_evm_ui_keys_init(unsigned gpio) for (i = 0; i < DA850_N_UI_PB; i++) { button = &da850_evm_ui_keys[i]; button->code = KEY_F8 - i; - button->desc = (char *) - da850_evm_ui_exp[DA850_EVM_UI_EXP_PB8 + i]; + button->desc = da850_evm_ui_exp[DA850_EVM_UI_EXP_PB8 + i]; button->gpio = gpio + DA850_EVM_UI_EXP_PB8 + i; } } @@ -628,15 +627,13 @@ static void da850_evm_bb_keys_init(unsigned gpio) struct gpio_keys_button *button; button = &da850_evm_bb_keys[0]; - button->desc = (char *) - da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_PB1]; + button->desc = da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_PB1]; button->gpio = gpio + DA850_EVM_BB_EXP_USER_PB1; for (i = 0; i < DA850_N_BB_USER_SW; i++) { button = &da850_evm_bb_keys[i + 1]; button->code = SW_LID + i; - button->desc = (char *) - da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_SW1 + i]; + button->desc = da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_SW1 + i]; button->gpio = gpio + DA850_EVM_BB_EXP_USER_SW1 + i; } } diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index e583e58b5e1e..1a0898c1c17e 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -767,9 +767,8 @@ static __init void davinci_evm_init(void) if (HAS_ATA) { if (HAS_NAND || HAS_NOR) - pr_warning("WARNING: both IDE and Flash are " - "enabled, but they share AEMIF pins.\n" - "\tDisable IDE for NAND/NOR support.\n"); + pr_warn("WARNING: both IDE and Flash are enabled, but they share AEMIF pins\n" + "\tDisable IDE for NAND/NOR support\n"); davinci_init_ide(); } else if (HAS_NAND || HAS_NOR) { davinci_cfg_reg(DM644X_HPIEN_DISABLE); @@ -780,13 +779,12 @@ static __init void davinci_evm_init(void) platform_device_register(&davinci_evm_nandflash_device); if (davinci_aemif_setup(&davinci_evm_nandflash_device)) - pr_warn("%s: Cannot configure AEMIF.\n", + pr_warn("%s: Cannot configure AEMIF\n", __func__); evm_leds[7].default_trigger = "nand-disk"; if (HAS_NOR) - pr_warning("WARNING: both NAND and NOR flash " - "are enabled; disable one of them.\n"); + pr_warn("WARNING: both NAND and NOR flash are enabled; disable one of them.\n"); } else if (HAS_NOR) platform_device_register(&davinci_evm_norflash_device); } diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 96fc00a167f5..8cfbfe084535 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -8,6 +8,8 @@ * any kind, whether express or implied. */ +#define pr_fmt(fmt) "MityOMAPL138: " fmt + #include <linux/kernel.h> #include <linux/init.h> #include <linux/console.h> @@ -107,7 +109,7 @@ static void mityomapl138_cpufreq_init(const char *partnum) ret = da850_register_cpufreq("pll0_sysclk3"); if (ret) - pr_warning("cpufreq registration failed: %d\n", ret); + pr_warn("cpufreq registration failed: %d\n", ret); } #else static void mityomapl138_cpufreq_init(const char *partnum) { } @@ -121,33 +123,31 @@ static void read_factory_config(struct memory_accessor *a, void *context) ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config)); if (ret != sizeof(struct factory_config)) { - pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n", - ret); + pr_warn("Read Factory Config Failed: %d\n", ret); goto bad_config; } if (factory_config.magic != FACTORY_CONFIG_MAGIC) { - pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n", - factory_config.magic); + pr_warn("Factory Config Magic Wrong (%X)\n", + factory_config.magic); goto bad_config; } if (factory_config.version != FACTORY_CONFIG_VERSION) { - pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n", - factory_config.version); + pr_warn("Factory Config Version Wrong (%X)\n", + factory_config.version); goto bad_config; } - pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac); + pr_info("Found MAC = %pM\n", factory_config.mac); if (is_valid_ether_addr(factory_config.mac)) memcpy(soc_info->emac_pdata->mac_addr, factory_config.mac, ETH_ALEN); else - pr_warning("MityOMAPL138: Invalid MAC found " - "in factory config block\n"); + pr_warn("Invalid MAC found in factory config block\n"); partnum = factory_config.partnum; - pr_info("MityOMAPL138: Part Number = %s\n", partnum); + pr_info("Part Number = %s\n", partnum); bad_config: /* default maximum speed is valid for all platforms */ @@ -435,7 +435,7 @@ static void __init mityomapl138_setup_nand(void) ARRAY_SIZE(mityomapl138_devices)); if (davinci_aemif_setup(&mityomapl138_nandflash_device)) - pr_warn("%s: Cannot configure AEMIF.\n", __func__); + pr_warn("%s: Cannot configure AEMIF\n", __func__); } static const short mityomap_mii_pins[] = { @@ -478,7 +478,7 @@ static void __init mityomapl138_config_emac(void) } if (ret) { - pr_warning("mii/rmii mux setup failed: %d\n", ret); + pr_warn("mii/rmii mux setup failed: %d\n", ret); return; } @@ -489,7 +489,7 @@ static void __init mityomapl138_config_emac(void) ret = da8xx_register_emac(); if (ret) - pr_warning("emac registration failed: %d\n", ret); + pr_warn("emac registration failed: %d\n", ret); } static struct davinci_pm_config da850_pm_pdata = { @@ -511,21 +511,21 @@ static void __init mityomapl138_init(void) /* for now, no special EDMA channels are reserved */ ret = da850_register_edma(NULL); if (ret) - pr_warning("edma registration failed: %d\n", ret); + pr_warn("edma registration failed: %d\n", ret); ret = da8xx_register_watchdog(); if (ret) - pr_warning("watchdog registration failed: %d\n", ret); + pr_warn("watchdog registration failed: %d\n", ret); davinci_serial_init(da8xx_serial_device); ret = da8xx_register_i2c(0, &mityomap_i2c_0_pdata); if (ret) - pr_warning("i2c0 registration failed: %d\n", ret); + pr_warn("i2c0 registration failed: %d\n", ret); ret = pmic_tps65023_init(); if (ret) - pr_warning("TPS65023 PMIC init failed: %d\n", ret); + pr_warn("TPS65023 PMIC init failed: %d\n", ret); mityomapl138_setup_nand(); @@ -537,22 +537,21 @@ static void __init mityomapl138_init(void) ret = da8xx_register_spi_bus(1, ARRAY_SIZE(mityomapl138_spi_flash_info)); if (ret) - pr_warning("spi 1 registration failed: %d\n", ret); + pr_warn("spi 1 registration failed: %d\n", ret); mityomapl138_config_emac(); ret = da8xx_register_rtc(); if (ret) - pr_warning("rtc setup failed: %d\n", ret); + pr_warn("rtc setup failed: %d\n", ret); ret = da8xx_register_cpuidle(); if (ret) - pr_warning("cpuidle registration failed: %d\n", ret); + pr_warn("cpuidle registration failed: %d\n", ret); ret = da850_register_pm(&da850_pm_device); if (ret) - pr_warning("da850_evm_init: suspend registration failed: %d\n", - ret); + pr_warn("suspend registration failed: %d\n", ret); } #ifdef CONFIG_SERIAL_8250_CONSOLE diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index bb680af98374..8fcdcf87c47c 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -183,9 +183,8 @@ static __init void davinci_ntosd2_init(void) if (HAS_ATA) { if (HAS_NAND) - pr_warning("WARNING: both IDE and Flash are " - "enabled, but they share AEMIF pins.\n" - "\tDisable IDE for NAND/NOR support.\n"); + pr_warn("WARNING: both IDE and Flash are enabled, but they share AEMIF pins\n" + "\tDisable IDE for NAND/NOR support\n"); davinci_init_ide(); } else if (HAS_NAND) { davinci_cfg_reg(DM644X_HPIEN_DISABLE); diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 985e5fd00fb2..c70bb0a4dfb4 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -564,7 +564,7 @@ int davinci_set_refclk_rate(unsigned long rate) refclk = clk_get(NULL, "ref"); if (IS_ERR(refclk)) { - pr_err("%s: failed to get reference clock.\n", __func__); + pr_err("%s: failed to get reference clock\n", __func__); return PTR_ERR(refclk); } diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c index f34a8dcdae2b..a8eb909a2b6c 100644 --- a/arch/arm/mach-davinci/mux.c +++ b/arch/arm/mach-davinci/mux.c @@ -15,6 +15,9 @@ * * Copyright (C) 2008 Texas Instruments. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/io.h> #include <linux/module.h> #include <linux/spinlock.h> @@ -46,7 +49,7 @@ int __init_or_module davinci_cfg_reg(const unsigned long index) } if (index >= soc_info->pinmux_pins_num) { - printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n", + pr_err("Invalid pin mux index: %lu (%lu)\n", index, soc_info->pinmux_pins_num); dump_stack(); return -ENODEV; @@ -55,7 +58,7 @@ int __init_or_module davinci_cfg_reg(const unsigned long index) cfg = &soc_info->pinmux_pins[index]; if (cfg->name == NULL) { - printk(KERN_ERR "No entry for the specified index\n"); + pr_err("No entry for the specified index\n"); return -ENODEV; } @@ -82,15 +85,15 @@ int __init_or_module davinci_cfg_reg(const unsigned long index) if (warn) { #ifdef CONFIG_DAVINCI_MUX_WARNINGS - printk(KERN_WARNING "MUX: initialized %s\n", cfg->name); + pr_warn("initialized %s\n", cfg->name); #endif } #ifdef CONFIG_DAVINCI_MUX_DEBUG if (cfg->debug || warn) { - printk(KERN_WARNING "MUX: Setting register %s\n", cfg->name); - printk(KERN_WARNING " %s (0x%08x) = 0x%08x -> 0x%08x\n", - cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg); + pr_warn("Setting register %s\n", cfg->name); + pr_warn(" %s (0x%08x) = 0x%08x -> 0x%08x\n", + cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg); } #endif diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index 24ad30f32ae3..160c9602f490 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c @@ -342,8 +342,6 @@ void __init davinci_timer_init(void) struct davinci_soc_info *soc_info = &davinci_soc_info; unsigned int clockevent_id; unsigned int clocksource_id; - static char err[] __initdata = KERN_ERR - "%s: can't register clocksource!\n"; int i; clockevent_id = soc_info->timer_info->clockevent_id; @@ -364,12 +362,12 @@ void __init davinci_timer_init(void) /* Only bottom timers can use compare regs */ if (IS_TIMER_TOP(clockevent_id)) - pr_warning("davinci_timer_init: Invalid use" - " of system timers. Results unpredictable.\n"); + pr_warn("%s: Invalid use of system timers. Results unpredictable.\n", + __func__); else if ((dtip[event_timer].cmp_off == 0) || (dtip[event_timer].cmp_irq == 0)) - pr_warning("davinci_timer_init: Invalid timer instance" - " setup. Results unpredictable.\n"); + pr_warn("%s: Invalid timer instance setup. Results unpredictable.\n", + __func__); else { timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE; clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT; @@ -389,7 +387,8 @@ void __init davinci_timer_init(void) clocksource_davinci.name = id_to_name[clocksource_id]; if (clocksource_register_hz(&clocksource_davinci, davinci_clock_tick_rate)) - printk(err, clocksource_davinci.name); + pr_err("%s: can't register clocksource!\n", + clocksource_davinci.name); sched_clock_register(davinci_read_sched_clock, 32, davinci_clock_tick_rate); diff --git a/arch/arm/mach-ep93xx/dma.c b/arch/arm/mach-ep93xx/dma.c index d8bfd02f5047..88a4c9b089a5 100644 --- a/arch/arm/mach-ep93xx/dma.c +++ b/arch/arm/mach-ep93xx/dma.c @@ -66,11 +66,15 @@ static struct ep93xx_dma_platform_data ep93xx_dma_m2p_data = { .num_channels = ARRAY_SIZE(ep93xx_dma_m2p_channels), }; +static u64 ep93xx_dma_m2p_mask = DMA_BIT_MASK(32); + static struct platform_device ep93xx_dma_m2p_device = { .name = "ep93xx-dma-m2p", .id = -1, .dev = { - .platform_data = &ep93xx_dma_m2p_data, + .platform_data = &ep93xx_dma_m2p_data, + .dma_mask = &ep93xx_dma_m2p_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; @@ -93,11 +97,15 @@ static struct ep93xx_dma_platform_data ep93xx_dma_m2m_data = { .num_channels = ARRAY_SIZE(ep93xx_dma_m2m_channels), }; +static u64 ep93xx_dma_m2m_mask = DMA_BIT_MASK(32); + static struct platform_device ep93xx_dma_m2m_device = { .name = "ep93xx-dma-m2m", .id = -1, .dev = { - .platform_data = &ep93xx_dma_m2m_data, + .platform_data = &ep93xx_dma_m2m_data, + .dma_mask = &ep93xx_dma_m2m_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), }, }; diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 2d0240f241b8..b9e3f1c61baf 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -24,6 +24,7 @@ menuconfig ARCH_EXYNOS select PM_GENERIC_DOMAINS if PM_RUNTIME select S5P_DEV_MFC select SRAM + select MFD_SYSCON help Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5) @@ -75,6 +76,11 @@ config SOC_EXYNOS4412 default y depends on ARCH_EXYNOS4 +config SOC_EXYNOS4415 + bool "SAMSUNG EXYNOS4415" + default y + depends on ARCH_EXYNOS4 + config SOC_EXYNOS5250 bool "SAMSUNG EXYNOS5250" default y @@ -123,4 +129,9 @@ config EXYNOS5420_MCPM This is needed to provide CPU and cluster power management on Exynos5420 implementing big.LITTLE. +config EXYNOS_CPU_SUSPEND + bool + select ARM_CPU_SUSPEND + default PM_SLEEP || ARM_EXYNOS_CPUIDLE + endif diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 27ae6144679c..bcefb5473ee4 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -11,16 +11,15 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree) obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o -obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o +obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o +obj-$(CONFIG_PM_SLEEP) += suspend.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -CFLAGS_hotplug.o += -march=armv7-a - plus_sec := $(call as-instr,.arch_extension sec,+sec) AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec) obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o CFLAGS_mcpm-exynos.o += -march=armv7-a diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 47b904b3b973..865f878063cc 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -12,7 +12,6 @@ #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H #define __ARCH_ARM_MACH_EXYNOS_COMMON_H -#include <linux/reboot.h> #include <linux/of.h> #define EXYNOS3250_SOC_ID 0xE3472000 @@ -111,11 +110,19 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK) #define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \ soc_is_exynos5420() || soc_is_exynos5800()) +extern u32 cp15_save_diag; +extern u32 cp15_save_power; + extern void __iomem *sysram_ns_base_addr; extern void __iomem *sysram_base_addr; extern void __iomem *pmu_base_addr; void exynos_sysram_init(void); +enum { + FW_DO_IDLE_SLEEP, + FW_DO_IDLE_AFTR, +}; + void exynos_firmware_init(void); extern u32 exynos_get_eint_wake_mask(void); @@ -127,34 +134,20 @@ static inline void exynos_pm_init(void) {} #endif extern void exynos_cpu_resume(void); +extern void exynos_cpu_resume_ns(void); extern struct smp_operations exynos_smp_ops; -extern void exynos_cpu_die(unsigned int cpu); - -/* PMU(Power Management Unit) support */ - -#define PMU_TABLE_END (-1U) - -enum sys_powerdown { - SYS_AFTR, - SYS_LPA, - SYS_SLEEP, - NUM_SYS_POWERDOWN, -}; - -struct exynos_pmu_conf { - unsigned int offset; - unsigned int val[NUM_SYS_POWERDOWN]; -}; - -extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); extern void exynos_cpu_power_down(int cpu); extern void exynos_cpu_power_up(int cpu); extern int exynos_cpu_power_state(int cpu); extern void exynos_cluster_power_down(int cluster); extern void exynos_cluster_power_up(int cluster); extern int exynos_cluster_power_state(int cluster); +extern void exynos_cpu_save_register(void); +extern void exynos_cpu_restore_register(void); +extern void exynos_pm_central_suspend(void); +extern int exynos_pm_central_resume(void); extern void exynos_enter_aftr(void); extern void s5p_init_cpu(void __iomem *cpuid_addr); diff --git a/arch/arm/mach-exynos/exynos-pmu.h b/arch/arm/mach-exynos/exynos-pmu.h new file mode 100644 index 000000000000..a2ab0d52b230 --- /dev/null +++ b/arch/arm/mach-exynos/exynos-pmu.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Header for EXYNOS PMU Driver support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __EXYNOS_PMU_H +#define __EXYNOS_PMU_H + +enum sys_powerdown { + SYS_AFTR, + SYS_LPA, + SYS_SLEEP, + NUM_SYS_POWERDOWN, +}; + +extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); + +#endif /* __EXYNOS_PMU_H */ diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 6b283eb3202e..c13d0837fa8c 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c @@ -41,41 +41,11 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_64K, .type = MT_DEVICE, }, { - .virtual = (unsigned long)S3C_VA_TIMER, - .pfn = __phys_to_pfn(EXYNOS4_PA_TIMER), - .length = SZ_16K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S3C_VA_WATCHDOG, - .pfn = __phys_to_pfn(EXYNOS4_PA_WATCHDOG), - .length = SZ_4K, - .type = MT_DEVICE, - }, { .virtual = (unsigned long)S5P_VA_SROMC, .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC), .length = SZ_4K, .type = MT_DEVICE, }, { - .virtual = (unsigned long)S5P_VA_SYSTIMER, - .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER), - .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S5P_VA_COMBINER_BASE, - .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER), - .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S5P_VA_GIC_CPU, - .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_CPU), - .length = SZ_64K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S5P_VA_GIC_DIST, - .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_DIST), - .length = SZ_64K, - .type = MT_DEVICE, - }, { .virtual = (unsigned long)S5P_VA_CMU, .pfn = __phys_to_pfn(EXYNOS4_PA_CMU), .length = SZ_128K, @@ -86,11 +56,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_8K, .type = MT_DEVICE, }, { - .virtual = (unsigned long)S5P_VA_L2CC, - .pfn = __phys_to_pfn(EXYNOS4_PA_L2CC), - .length = SZ_4K, - .type = MT_DEVICE, - }, { .virtual = (unsigned long)S5P_VA_DMC0, .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0), .length = SZ_64K, @@ -100,11 +65,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .pfn = __phys_to_pfn(EXYNOS4_PA_DMC1), .length = SZ_64K, .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S3C_VA_USB_HSPHY, - .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY), - .length = SZ_4K, - .type = MT_DEVICE, }, }; @@ -115,16 +75,6 @@ static struct map_desc exynos5_iodesc[] __initdata = { .length = SZ_64K, .type = MT_DEVICE, }, { - .virtual = (unsigned long)S3C_VA_TIMER, - .pfn = __phys_to_pfn(EXYNOS5_PA_TIMER), - .length = SZ_16K, - .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S3C_VA_WATCHDOG, - .pfn = __phys_to_pfn(EXYNOS5_PA_WATCHDOG), - .length = SZ_4K, - .type = MT_DEVICE, - }, { .virtual = (unsigned long)S5P_VA_SROMC, .pfn = __phys_to_pfn(EXYNOS5_PA_SROMC), .length = SZ_4K, @@ -137,28 +87,6 @@ static struct map_desc exynos5_iodesc[] __initdata = { }, }; -static void exynos_restart(enum reboot_mode mode, const char *cmd) -{ - struct device_node *np; - u32 val = 0x1; - void __iomem *addr = pmu_base_addr + EXYNOS_SWRESET; - - if (of_machine_is_compatible("samsung,exynos5440")) { - u32 status; - np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock"); - - addr = of_iomap(np, 0) + 0xbc; - status = __raw_readl(addr); - - addr = of_iomap(np, 0) + 0xcc; - val = __raw_readl(addr); - - val = (val & 0xffff0000) | (status & 0xffff); - } - - __raw_writel(val, addr); -} - static struct platform_device exynos_cpuidle = { .name = "exynos_cpuidle", #ifdef CONFIG_ARM_EXYNOS_CPUIDLE @@ -252,6 +180,7 @@ static const struct of_device_id exynos_dt_pmu_match[] = { { .compatible = "samsung,exynos4210-pmu" }, { .compatible = "samsung,exynos4212-pmu" }, { .compatible = "samsung,exynos4412-pmu" }, + { .compatible = "samsung,exynos4415-pmu" }, { .compatible = "samsung,exynos5250-pmu" }, { .compatible = "samsung,exynos5260-pmu" }, { .compatible = "samsung,exynos5410-pmu" }, @@ -318,7 +247,10 @@ static void __init exynos_dt_machine_init(void) exynos_sysram_init(); if (of_machine_is_compatible("samsung,exynos4210") || - of_machine_is_compatible("samsung,exynos5250")) + of_machine_is_compatible("samsung,exynos4212") || + (of_machine_is_compatible("samsung,exynos4412") && + of_machine_is_compatible("samsung,trats2")) || + of_machine_is_compatible("samsung,exynos5250")) platform_device_register(&exynos_cpuidle); platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); @@ -333,6 +265,7 @@ static char const *exynos_dt_compat[] __initconst = { "samsung,exynos4210", "samsung,exynos4212", "samsung,exynos4412", + "samsung,exynos4415", "samsung,exynos5", "samsung,exynos5250", "samsung,exynos5260", @@ -378,7 +311,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") .init_machine = exynos_dt_machine_init, .init_late = exynos_init_late, .dt_compat = exynos_dt_compat, - .restart = exynos_restart, .reserve = exynos_reserve, .dt_fixup = exynos_dt_fixup, MACHINE_END diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index e8797bb78871..766f57d2f029 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c @@ -14,16 +14,44 @@ #include <linux/of.h> #include <linux/of_address.h> +#include <asm/cacheflush.h> +#include <asm/cputype.h> #include <asm/firmware.h> +#include <asm/suspend.h> #include <mach/map.h> #include "common.h" #include "smc.h" -static int exynos_do_idle(void) +#define EXYNOS_SLEEP_MAGIC 0x00000bad +#define EXYNOS_AFTR_MAGIC 0xfcba0d10 +#define EXYNOS_BOOT_ADDR 0x8 +#define EXYNOS_BOOT_FLAG 0xc + +static void exynos_save_cp15(void) { - exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + /* Save Power control and Diagnostic registers */ + asm ("mrc p15, 0, %0, c15, c0, 0\n" + "mrc p15, 0, %1, c15, c0, 1\n" + : "=r" (cp15_save_power), "=r" (cp15_save_diag) + : : "cc"); +} + +static int exynos_do_idle(unsigned long mode) +{ + switch (mode) { + case FW_DO_IDLE_AFTR: + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15(); + __raw_writel(virt_to_phys(exynos_cpu_resume_ns), + sysram_ns_base_addr + 0x24); + __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20); + exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); + break; + case FW_DO_IDLE_SLEEP: + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + } return 0; } @@ -69,10 +97,43 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) return 0; } +static int exynos_cpu_suspend(unsigned long arg) +{ + flush_cache_all(); + outer_flush_all(); + + exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); + + pr_info("Failed to suspend the system\n"); + writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + return 1; +} + +static int exynos_suspend(void) +{ + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_save_cp15(); + + writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + writel(virt_to_phys(exynos_cpu_resume_ns), + sysram_ns_base_addr + EXYNOS_BOOT_ADDR); + + return cpu_suspend(0, exynos_cpu_suspend); +} + +static int exynos_resume(void) +{ + writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); + + return 0; +} + static const struct firmware_ops exynos_firmware_ops = { - .do_idle = exynos_do_idle, + .do_idle = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_do_idle : NULL, .set_cpu_boot_addr = exynos_set_cpu_boot_addr, .cpu_boot = exynos_cpu_boot, + .suspend = IS_ENABLED(CONFIG_PM_SLEEP) ? exynos_suspend : NULL, + .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, }; void __init exynos_firmware_init(void) diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c deleted file mode 100644 index 4d86961a7957..000000000000 --- a/arch/arm/mach-exynos/hotplug.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Cloned from linux/arch/arm/mach-realview/hotplug.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/smp.h> -#include <linux/io.h> - -#include <asm/cacheflush.h> -#include <asm/cp15.h> -#include <asm/smp_plat.h> - -#include "common.h" -#include "regs-pmu.h" - -static inline void cpu_leave_lowpower(void) -{ - unsigned int v; - - asm volatile( - "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, %1\n" - " mcr p15, 0, %0, c1, c0, 0\n" - " mrc p15, 0, %0, c1, c0, 1\n" - " orr %0, %0, %2\n" - " mcr p15, 0, %0, c1, c0, 1\n" - : "=&r" (v) - : "Ir" (CR_C), "Ir" (0x40) - : "cc"); -} - -static inline void platform_do_lowpower(unsigned int cpu, int *spurious) -{ - u32 mpidr = cpu_logical_map(cpu); - u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); - - for (;;) { - - /* Turn the CPU off on next WFI instruction. */ - exynos_cpu_power_down(core_id); - - wfi(); - - if (pen_release == core_id) { - /* - * OK, proper wakeup, we're done - */ - break; - } - - /* - * Getting here, means that we have come out of WFI without - * having been woken up - this shouldn't happen - * - * Just note it happening - when we're woken, we can report - * its occurrence. - */ - (*spurious)++; - } -} - -/* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled - */ -void __ref exynos_cpu_die(unsigned int cpu) -{ - int spurious = 0; - - v7_exit_coherency_flush(louis); - - platform_do_lowpower(cpu, &spurious); - - /* - * bring this CPU back into the world of cache - * coherency, and then restore interrupts - */ - cpu_leave_lowpower(); - - if (spurious) - pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); -} diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index f0b7e92bad6c..1ad3f496ef56 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -30,40 +30,17 @@ #define EXYNOS4_PA_CMU 0x10030000 #define EXYNOS5_PA_CMU 0x10010000 -#define EXYNOS4_PA_SYSTIMER 0x10050000 - -#define EXYNOS4_PA_WATCHDOG 0x10060000 -#define EXYNOS5_PA_WATCHDOG 0x101D0000 - #define EXYNOS4_PA_DMC0 0x10400000 #define EXYNOS4_PA_DMC1 0x10410000 -#define EXYNOS4_PA_COMBINER 0x10440000 -#define EXYNOS5_PA_COMBINER 0x10440000 - -#define EXYNOS4_PA_GIC_CPU 0x10480000 -#define EXYNOS4_PA_GIC_DIST 0x10490000 -#define EXYNOS5_PA_GIC_CPU 0x10482000 -#define EXYNOS5_PA_GIC_DIST 0x10481000 - #define EXYNOS4_PA_COREPERI 0x10500000 #define EXYNOS4_PA_L2CC 0x10502000 #define EXYNOS4_PA_SROMC 0x12570000 #define EXYNOS5_PA_SROMC 0x12250000 -#define EXYNOS4_PA_HSPHY 0x125B0000 - -#define EXYNOS4_PA_UART 0x13800000 -#define EXYNOS5_PA_UART 0x12C00000 - -#define EXYNOS4_PA_TIMER 0x139D0000 -#define EXYNOS5_PA_TIMER 0x12DD0000 - /* Compatibility UART */ #define EXYNOS5440_PA_UART0 0x000B0000 -#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) - #endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c index dc9a764a7c37..b0d3c2e876fb 100644 --- a/arch/arm/mach-exynos/mcpm-exynos.c +++ b/arch/arm/mach-exynos/mcpm-exynos.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/of_address.h> +#include <linux/syscore_ops.h> #include <asm/cputype.h> #include <asm/cp15.h> @@ -30,6 +31,8 @@ #define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29) #define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30) +static void __iomem *ns_sram_base_addr; + /* * The common v7_exit_coherency_flush API could not be used because of the * Erratum 799270 workaround. This macro is the same as the common one (in @@ -318,10 +321,26 @@ static const struct of_device_id exynos_dt_mcpm_match[] = { {}, }; +static void exynos_mcpm_setup_entry_point(void) +{ + /* + * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr + * as part of secondary_cpu_start(). Let's redirect it to the + * mcpm_entry_point(). This is done during both secondary boot-up as + * well as system resume. + */ + __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */ + __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */ + __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8); +} + +static struct syscore_ops exynos_mcpm_syscore_ops = { + .resume = exynos_mcpm_setup_entry_point, +}; + static int __init exynos_mcpm_init(void) { struct device_node *node; - void __iomem *ns_sram_base_addr; unsigned int value, i; int ret; @@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void) pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i)); } - /* - * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr - * as part of secondary_cpu_start(). Let's redirect it to the - * mcpm_entry_point(). - */ - __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */ - __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */ - __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8); + exynos_mcpm_setup_entry_point(); - iounmap(ns_sram_base_addr); + register_syscore_ops(&exynos_mcpm_syscore_ops); return ret; } diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 41ae28d69e6f..7a1ebfeeeeb8 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c @@ -22,6 +22,7 @@ #include <linux/of_address.h> #include <asm/cacheflush.h> +#include <asm/cp15.h> #include <asm/smp_plat.h> #include <asm/smp_scu.h> #include <asm/firmware.h> @@ -33,6 +34,88 @@ extern void exynos4_secondary_startup(void); +/* + * Set or clear the USE_DELAYED_RESET_ASSERTION option, set on Exynos4 SoCs + * during hot-(un)plugging CPUx. + * + * The feature can be cleared safely during first boot of secondary CPU. + * + * Exynos4 SoCs require setting USE_DELAYED_RESET_ASSERTION during powering + * down a CPU so the CPU idle clock down feature could properly detect global + * idle state when CPUx is off. + */ +static void exynos_set_delayed_reset_assertion(u32 core_id, bool enable) +{ + if (soc_is_exynos4()) { + unsigned int tmp; + + tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id)); + if (enable) + tmp |= S5P_USE_DELAYED_RESET_ASSERTION; + else + tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION); + pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id)); + } +} + +#ifdef CONFIG_HOTPLUG_CPU +static inline void cpu_leave_lowpower(u32 core_id) +{ + unsigned int v; + + asm volatile( + "mrc p15, 0, %0, c1, c0, 0\n" + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" + " orr %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (CR_C), "Ir" (0x40) + : "cc"); + + exynos_set_delayed_reset_assertion(core_id, false); +} + +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +{ + u32 mpidr = cpu_logical_map(cpu); + u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); + + for (;;) { + + /* Turn the CPU off on next WFI instruction. */ + exynos_cpu_power_down(core_id); + + /* + * Exynos4 SoCs require setting + * USE_DELAYED_RESET_ASSERTION so the CPU idle + * clock down feature could properly detect + * global idle state when CPUx is off. + */ + exynos_set_delayed_reset_assertion(core_id, true); + + wfi(); + + if (pen_release == core_id) { + /* + * OK, proper wakeup, we're done + */ + break; + } + + /* + * Getting here, means that we have come out of WFI without + * having been woken up - this shouldn't happen + * + * Just note it happening - when we're woken, we can report + * its occurrence. + */ + (*spurious)++; + } +} +#endif /* CONFIG_HOTPLUG_CPU */ + /** * exynos_core_power_down : power down the specified cpu * @cpu : the cpu to power down @@ -43,6 +126,18 @@ extern void exynos4_secondary_startup(void); */ void exynos_cpu_power_down(int cpu) { + if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") || + of_machine_is_compatible("samsung,exynos5800"))) { + /* + * Bypass power down for CPU0 during suspend. Check for + * the SYS_PWR_REG value to decide if we are suspending + * the system. + */ + int val = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); + + if (!(val & S5P_CORE_LOCAL_PWR_EN)) + return; + } pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); } @@ -121,6 +216,26 @@ static inline void __iomem *cpu_boot_reg(int cpu) } /* + * Set wake up by local power mode and execute software reset for given core. + * + * Currently this is needed only when booting secondary CPU on Exynos3250. + */ +static void exynos_core_restart(u32 core_id) +{ + u32 val; + + if (!of_machine_is_compatible("samsung,exynos3250")) + return; + + val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id)); + val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG; + pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id)); + + pr_info("CPU%u: Software reset\n", core_id); + pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET); +} + +/* * Write pen_release in a way that is guaranteed to be visible to all * observers, irrespective of whether they're taking part in coherency * or not. This is necessary for the hotplug code to work reliably. @@ -196,6 +311,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) return -ETIMEDOUT; } } + + exynos_core_restart(core_id); + /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, @@ -237,6 +355,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) udelay(10); } + /* No harm if this is called during first boot of secondary CPU */ + exynos_set_delayed_reset_assertion(core_id, false); + /* * now the secondary core is starting up let it run its * calibrations, then wait for it to finish @@ -318,6 +439,33 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) } } +#ifdef CONFIG_HOTPLUG_CPU +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +static void exynos_cpu_die(unsigned int cpu) +{ + int spurious = 0; + u32 mpidr = cpu_logical_map(cpu); + u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); + + v7_exit_coherency_flush(louis); + + platform_do_lowpower(cpu, &spurious); + + /* + * bring this CPU back into the world of cache + * coherency, and then restore interrupts + */ + cpu_leave_lowpower(core_id); + + if (spurious) + pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} +#endif /* CONFIG_HOTPLUG_CPU */ + struct smp_operations exynos_smp_ops __initdata = { .smp_init_cpus = exynos_smp_init_cpus, .smp_prepare_cpus = exynos_smp_prepare_cpus, diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index abefacb45976..86f3ecd88f78 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * * EXYNOS - Power Management support @@ -15,109 +15,45 @@ #include <linux/init.h> #include <linux/suspend.h> -#include <linux/syscore_ops.h> #include <linux/cpu_pm.h> #include <linux/io.h> -#include <linux/irqchip/arm-gic.h> #include <linux/err.h> -#include <linux/clk.h> -#include <asm/cacheflush.h> -#include <asm/hardware/cache-l2x0.h> +#include <asm/firmware.h> #include <asm/smp_scu.h> #include <asm/suspend.h> #include <plat/pm-common.h> -#include <plat/regs-srom.h> - -#include <mach/map.h> #include "common.h" +#include "exynos-pmu.h" #include "regs-pmu.h" #include "regs-sys.h" -/** - * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping - * @hwirq: Hardware IRQ signal of the GIC - * @mask: Mask in PMU wake-up mask register - */ -struct exynos_wkup_irq { - unsigned int hwirq; - u32 mask; -}; - -static struct sleep_save exynos5_sys_save[] = { - SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), -}; - -static struct sleep_save exynos_core_save[] = { - /* SROM side */ - SAVE_ITEM(S5P_SROM_BW), - SAVE_ITEM(S5P_SROM_BC0), - SAVE_ITEM(S5P_SROM_BC1), - SAVE_ITEM(S5P_SROM_BC2), - SAVE_ITEM(S5P_SROM_BC3), -}; - -/* - * GIC wake-up support - */ - -static u32 exynos_irqwake_intmask = 0xffffffff; - -static const struct exynos_wkup_irq exynos4_wkup_irq[] = { - { 76, BIT(1) }, /* RTC alarm */ - { 77, BIT(2) }, /* RTC tick */ - { /* sentinel */ }, -}; - -static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { - { 75, BIT(1) }, /* RTC alarm */ - { 76, BIT(2) }, /* RTC tick */ - { /* sentinel */ }, -}; - -static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) +static inline void __iomem *exynos_boot_vector_addr(void) { - const struct exynos_wkup_irq *wkup_irq; - - if (soc_is_exynos5250()) - wkup_irq = exynos5250_wkup_irq; - else - wkup_irq = exynos4_wkup_irq; - - while (wkup_irq->mask) { - if (wkup_irq->hwirq == data->hwirq) { - if (!state) - exynos_irqwake_intmask |= wkup_irq->mask; - else - exynos_irqwake_intmask &= ~wkup_irq->mask; - return 0; - } - ++wkup_irq; - } - - return -ENOENT; + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM7; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x24; + return pmu_base_addr + S5P_INFORM0; } -#define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - pmu_base_addr + S5P_INFORM7 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x24) : \ - pmu_base_addr + S5P_INFORM0)) -#define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ - pmu_base_addr + S5P_INFORM6 : \ - (samsung_rev() == EXYNOS4210_REV_1_0 ? \ - (sysram_base_addr + 0x20) : \ - pmu_base_addr + S5P_INFORM1)) +static inline void __iomem *exynos_boot_vector_flag(void) +{ + if (samsung_rev() == EXYNOS4210_REV_1_1) + return pmu_base_addr + S5P_INFORM6; + else if (samsung_rev() == EXYNOS4210_REV_1_0) + return sysram_base_addr + 0x20; + return pmu_base_addr + S5P_INFORM1; +} #define S5P_CHECK_AFTR 0xFCBA0D10 -#define S5P_CHECK_SLEEP 0x00000BAD /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; -static void exynos_cpu_save_register(void) +void exynos_cpu_save_register(void) { unsigned long tmp; @@ -134,7 +70,7 @@ static void exynos_cpu_save_register(void) save_arm_register[1] = tmp; } -static void exynos_cpu_restore_register(void) +void exynos_cpu_restore_register(void) { unsigned long tmp; @@ -153,7 +89,7 @@ static void exynos_cpu_restore_register(void) : "cc"); } -static void exynos_pm_central_suspend(void) +void exynos_pm_central_suspend(void) { unsigned long tmp; @@ -161,9 +97,13 @@ static void exynos_pm_central_suspend(void) tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); tmp &= ~S5P_CENTRAL_LOWPWR_CFG; pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); + + /* Setting SEQ_OPTION register */ + pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, + S5P_CENTRAL_SEQ_OPTION); } -static int exynos_pm_central_resume(void) +int exynos_pm_central_resume(void) { unsigned long tmp; @@ -194,17 +134,26 @@ static void exynos_set_wakeupmask(long mask) static void exynos_cpu_set_boot_vector(long flags) { - __raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); - __raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); + __raw_writel(virt_to_phys(exynos_cpu_resume), + exynos_boot_vector_addr()); + __raw_writel(flags, exynos_boot_vector_flag()); } static int exynos_aftr_finisher(unsigned long flags) { + int ret; + exynos_set_wakeupmask(0x0000ff3e); - exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); /* Set value of power down register for aftr mode */ exynos_sys_powerdown_conf(SYS_AFTR); - cpu_do_idle(); + + ret = call_firmware_op(do_idle, FW_DO_IDLE_AFTR); + if (ret == -ENOSYS) { + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_save_register(); + exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); + cpu_do_idle(); + } return 1; } @@ -214,196 +163,16 @@ void exynos_enter_aftr(void) cpu_pm_enter(); exynos_pm_central_suspend(); - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_save_register(); cpu_suspend(0, exynos_aftr_finisher); if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { scu_enable(S5P_VA_SCU); - exynos_cpu_restore_register(); + if (call_firmware_op(resume) == -ENOSYS) + exynos_cpu_restore_register(); } exynos_pm_central_resume(); cpu_pm_exit(); } - -static int exynos_cpu_suspend(unsigned long arg) -{ -#ifdef CONFIG_CACHE_L2X0 - outer_flush_all(); -#endif - - if (soc_is_exynos5250()) - flush_cache_all(); - - /* issue the standby signal into the pm unit. */ - cpu_do_idle(); - - pr_info("Failed to suspend the system\n"); - return 1; /* Aborting suspend */ -} - -static void exynos_pm_prepare(void) -{ - unsigned int tmp; - - /* Set wake-up mask registers */ - pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); - pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); - - s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - - if (soc_is_exynos5250()) { - s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); - /* Disable USE_RETENTION of JPEG_MEM_OPTION */ - tmp = pmu_raw_readl(EXYNOS5_JPEG_MEM_OPTION); - tmp &= ~EXYNOS5_OPTION_USE_RETENTION; - pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION); - } - - /* Set value of power down register for sleep mode */ - - exynos_sys_powerdown_conf(SYS_SLEEP); - pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); - - /* ensure at least INFORM0 has the resume address */ - - pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); -} - -static int exynos_pm_suspend(void) -{ - unsigned long tmp; - - exynos_pm_central_suspend(); - - /* Setting SEQ_OPTION register */ - - tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); - pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); - - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_save_register(); - - return 0; -} - -static void exynos_pm_resume(void) -{ - if (exynos_pm_central_resume()) - goto early_wakeup; - - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - exynos_cpu_restore_register(); - - /* For release retention */ - - pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION); - pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION); - - if (soc_is_exynos5250()) - s3c_pm_do_restore(exynos5_sys_save, - ARRAY_SIZE(exynos5_sys_save)); - - s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); - - if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) - scu_enable(S5P_VA_SCU); - -early_wakeup: - - /* Clear SLEEP mode set in INFORM1 */ - pmu_raw_writel(0x0, S5P_INFORM1); - - return; -} - -static struct syscore_ops exynos_pm_syscore_ops = { - .suspend = exynos_pm_suspend, - .resume = exynos_pm_resume, -}; - -/* - * Suspend Ops - */ - -static int exynos_suspend_enter(suspend_state_t state) -{ - int ret; - - s3c_pm_debug_init(); - - S3C_PMDBG("%s: suspending the system...\n", __func__); - - S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, - exynos_irqwake_intmask, exynos_get_eint_wake_mask()); - - if (exynos_irqwake_intmask == -1U - && exynos_get_eint_wake_mask() == -1U) { - pr_err("%s: No wake-up sources!\n", __func__); - pr_err("%s: Aborting sleep\n", __func__); - return -EINVAL; - } - - s3c_pm_save_uarts(); - exynos_pm_prepare(); - flush_cache_all(); - s3c_pm_check_store(); - - ret = cpu_suspend(0, exynos_cpu_suspend); - if (ret) - return ret; - - s3c_pm_restore_uarts(); - - S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, - pmu_raw_readl(S5P_WAKEUP_STAT)); - - s3c_pm_check_restore(); - - S3C_PMDBG("%s: resuming the system...\n", __func__); - - return 0; -} - -static int exynos_suspend_prepare(void) -{ - s3c_pm_check_prepare(); - - return 0; -} - -static void exynos_suspend_finish(void) -{ - s3c_pm_check_cleanup(); -} - -static const struct platform_suspend_ops exynos_suspend_ops = { - .enter = exynos_suspend_enter, - .prepare = exynos_suspend_prepare, - .finish = exynos_suspend_finish, - .valid = suspend_valid_only_mem, -}; - -void __init exynos_pm_init(void) -{ - u32 tmp; - - /* Platform-specific GIC callback */ - gic_arch_extn.irq_set_wake = exynos_irq_set_wake; - - /* All wakeup disable */ - tmp = pmu_raw_readl(S5P_WAKEUP_MASK); - tmp |= ((0xFF << 8) | (0x1F << 1)); - pmu_raw_writel(tmp, S5P_WAKEUP_MASK); - - register_syscore_ops(&exynos_pm_syscore_ops); - suspend_set_ops(&exynos_suspend_ops); -} diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index ff9d23f0a7d9..c15761ca2f18 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * EXYNOS - CPU PMU(Power Management Unit) support @@ -10,12 +10,136 @@ */ #include <linux/io.h> -#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/notifier.h> +#include <linux/reboot.h> -#include "common.h" + +#include "exynos-pmu.h" #include "regs-pmu.h" -static const struct exynos_pmu_conf *exynos_pmu_config; +#define PMU_TABLE_END (-1U) + +struct exynos_pmu_conf { + unsigned int offset; + u8 val[NUM_SYS_POWERDOWN]; +}; + +struct exynos_pmu_data { + const struct exynos_pmu_conf *pmu_config; + const struct exynos_pmu_conf *pmu_config_extra; + + void (*pmu_init)(void); + void (*powerdown_conf)(enum sys_powerdown); + void (*powerdown_conf_extra)(enum sys_powerdown); +}; + +struct exynos_pmu_context { + struct device *dev; + const struct exynos_pmu_data *pmu_data; +}; + +static void __iomem *pmu_base_addr; +static struct exynos_pmu_context *pmu_context; + +static inline void pmu_raw_writel(u32 val, u32 offset) +{ + writel_relaxed(val, pmu_base_addr + offset); +} + +static inline u32 pmu_raw_readl(u32 offset) +{ + return readl_relaxed(pmu_base_addr + offset); +} + +static struct exynos_pmu_conf exynos3250_pmu_config[] = { + /* { .offset = offset, .val = { AFTR, W-AFTR, SLEEP } */ + { EXYNOS3_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, + { EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, + { EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS3_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, + { EXYNOS3_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x3} }, + { EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS3_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS3_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x3} }, + { EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG, { 0x3, 0x3, 0x3} }, + { EXYNOS3_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS3_CAM_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_LCD0_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_MAUDIO_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { PMU_TABLE_END,}, +}; static const struct exynos_pmu_conf exynos4210_pmu_config[] = { /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ @@ -264,6 +388,7 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_JPEG_MEM_OPTION, { 0x10, 0x10, 0x0} }, { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, @@ -315,6 +440,189 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { { PMU_TABLE_END,}, }; +static struct exynos_pmu_conf exynos5420_pmu_config[] = { + /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ + { EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_ARM_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_ARM_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_KFC_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, + { EXYNOS5_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x0} }, + { EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, + { EXYNOS5_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, + { EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, + { EXYNOS5420_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, + { EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, + { EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, + { EXYNOS5_GSCL_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_DISP1_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_MAU_SYS_PWR_REG, { 0x7, 0x7, 0x0} }, + { EXYNOS5420_G2D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_MSC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_FSYS_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_FSYS2_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_PSGEN_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_PERIC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5420_WCORE_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, + { PMU_TABLE_END,}, +}; + +static unsigned int const exynos3250_list_feed[] = { + EXYNOS3_ARM_CORE_OPTION(0), + EXYNOS3_ARM_CORE_OPTION(1), + EXYNOS3_ARM_CORE_OPTION(2), + EXYNOS3_ARM_CORE_OPTION(3), + EXYNOS3_ARM_COMMON_OPTION, + EXYNOS3_TOP_PWR_OPTION, + EXYNOS3_CORE_TOP_PWR_OPTION, + S5P_CAM_OPTION, + S5P_MFC_OPTION, + S5P_G3D_OPTION, + S5P_LCD0_OPTION, + S5P_ISP_OPTION, +}; + +static void exynos3250_powerdown_conf_extra(enum sys_powerdown mode) +{ + unsigned int i; + unsigned int tmp; + + /* Enable only SC_FEEDBACK */ + for (i = 0; i < ARRAY_SIZE(exynos3250_list_feed); i++) { + tmp = pmu_raw_readl(exynos3250_list_feed[i]); + tmp &= ~(EXYNOS3_OPTION_USE_SC_COUNTER); + tmp |= EXYNOS3_OPTION_USE_SC_FEEDBACK; + pmu_raw_writel(tmp, exynos3250_list_feed[i]); + } + + if (mode != SYS_SLEEP) + return; + + pmu_raw_writel(XUSBXTI_DURATION, EXYNOS3_XUSBXTI_DURATION); + pmu_raw_writel(XXTI_DURATION, EXYNOS3_XXTI_DURATION); + pmu_raw_writel(EXT_REGULATOR_DURATION, EXYNOS3_EXT_REGULATOR_DURATION); + pmu_raw_writel(EXT_REGULATOR_COREBLK_DURATION, + EXYNOS3_EXT_REGULATOR_COREBLK_DURATION); +} + static unsigned int const exynos5_list_both_cnt_feed[] = { EXYNOS5_ARM_CORE0_OPTION, EXYNOS5_ARM_CORE1_OPTION, @@ -329,13 +637,82 @@ static unsigned int const exynos5_list_both_cnt_feed[] = { EXYNOS5_TOP_PWR_SYSMEM_OPTION, }; -static unsigned int const exynos5_list_diable_wfi_wfe[] = { +static unsigned int const exynos5_list_disable_wfi_wfe[] = { EXYNOS5_ARM_CORE1_OPTION, EXYNOS5_FSYS_ARM_OPTION, EXYNOS5_ISP_ARM_OPTION, }; -static void exynos5_init_pmu(void) +static unsigned int const exynos5420_list_disable_pmu_reg[] = { + EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, + EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, + EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, + EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, + EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, + EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, + EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, + EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, + EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, + EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, + EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, + EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, +}; + +static void exynos5_power_off(void) +{ + unsigned int tmp; + + pr_info("Power down.\n"); + tmp = pmu_raw_readl(EXYNOS_PS_HOLD_CONTROL); + tmp ^= (1 << 8); + pmu_raw_writel(tmp, EXYNOS_PS_HOLD_CONTROL); + + /* Wait a little so we don't give a false warning below */ + mdelay(100); + + pr_err("Power down failed, please power off system manually.\n"); + while (1) + ; +} + +void exynos5420_powerdown_conf(enum sys_powerdown mode) +{ + u32 this_cluster; + + this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); + + /* + * set the cluster id to IROM register to ensure that we wake + * up with the current cluster. + */ + pmu_raw_writel(this_cluster, EXYNOS_IROM_DATA2); +} + + +static void exynos5_powerdown_conf(enum sys_powerdown mode) { unsigned int i; unsigned int tmp; @@ -343,7 +720,7 @@ static void exynos5_init_pmu(void) /* * Enable both SC_FEEDBACK and SC_COUNTER */ - for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) { + for (i = 0; i < ARRAY_SIZE(exynos5_list_both_cnt_feed); i++) { tmp = pmu_raw_readl(exynos5_list_both_cnt_feed[i]); tmp |= (EXYNOS5_USE_SC_FEEDBACK | EXYNOS5_USE_SC_COUNTER); @@ -360,11 +737,11 @@ static void exynos5_init_pmu(void) /* * Disable WFI/WFE on XXX_OPTION */ - for (i = 0 ; i < ARRAY_SIZE(exynos5_list_diable_wfi_wfe) ; i++) { - tmp = pmu_raw_readl(exynos5_list_diable_wfi_wfe[i]); + for (i = 0; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe); i++) { + tmp = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]); tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | EXYNOS5_OPTION_USE_STANDBYWFI); - pmu_raw_writel(tmp, exynos5_list_diable_wfi_wfe[i]); + pmu_raw_writel(tmp, exynos5_list_disable_wfi_wfe[i]); } } @@ -372,51 +749,257 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) { unsigned int i; - if (soc_is_exynos5250()) - exynos5_init_pmu(); + const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data; + + if (pmu_data->powerdown_conf) + pmu_data->powerdown_conf(mode); + + if (pmu_data->pmu_config) { + for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++) + pmu_raw_writel(pmu_data->pmu_config[i].val[mode], + pmu_data->pmu_config[i].offset); + } - for (i = 0; (exynos_pmu_config[i].offset != PMU_TABLE_END) ; i++) - pmu_raw_writel(exynos_pmu_config[i].val[mode], - exynos_pmu_config[i].offset); + if (pmu_data->powerdown_conf_extra) + pmu_data->powerdown_conf_extra(mode); - if (soc_is_exynos4412()) { - for (i = 0; exynos4412_pmu_config[i].offset != PMU_TABLE_END ; i++) - pmu_raw_writel(exynos4412_pmu_config[i].val[mode], - exynos4412_pmu_config[i].offset); + if (pmu_data->pmu_config_extra) { + for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) + pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], + pmu_data->pmu_config_extra[i].offset); } } -static int __init exynos_pmu_init(void) +static void exynos3250_pmu_init(void) +{ + unsigned int value; + + /* + * To prevent from issuing new bus request form L2 memory system + * If core status is power down, should be set '1' to L2 power down + */ + value = pmu_raw_readl(EXYNOS3_ARM_COMMON_OPTION); + value |= EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN; + pmu_raw_writel(value, EXYNOS3_ARM_COMMON_OPTION); + + /* Enable USE_STANDBY_WFI for all CORE */ + pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); + + /* + * Set PSHOLD port for output high + */ + value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); + value |= S5P_PS_HOLD_OUTPUT_HIGH; + pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); + + /* + * Enable signal for PSHOLD port + */ + value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); + value |= S5P_PS_HOLD_EN; + pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); +} + +static void exynos5250_pmu_init(void) { unsigned int value; + /* + * When SYS_WDTRESET is set, watchdog timer reset request + * is ignored by power management unit. + */ + value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); + value &= ~EXYNOS5_SYS_WDTRESET; + pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); + + value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); + value &= ~EXYNOS5_SYS_WDTRESET; + pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); +} + +static void exynos5420_pmu_init(void) +{ + unsigned int value; + int i; + + /* + * Set the CMU_RESET, CMU_SYSCLK and CMU_CLKSTOP registers + * for local power blocks to Low initially as per Table 8-4: + * "System-Level Power-Down Configuration Registers". + */ + for (i = 0; i < ARRAY_SIZE(exynos5420_list_disable_pmu_reg); i++) + pmu_raw_writel(0, exynos5420_list_disable_pmu_reg[i]); + + /* Enable USE_STANDBY_WFI for all CORE */ + pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); + + value = pmu_raw_readl(EXYNOS_L2_OPTION(0)); + value &= ~EXYNOS5_USE_RETENTION; + pmu_raw_writel(value, EXYNOS_L2_OPTION(0)); + + value = pmu_raw_readl(EXYNOS_L2_OPTION(1)); + value &= ~EXYNOS5_USE_RETENTION; + pmu_raw_writel(value, EXYNOS_L2_OPTION(1)); + + /* + * If L2_COMMON is turned off, clocks related to ATB async + * bridge are gated. Thus, when ISP power is gated, LPI + * may get stuck. + */ + value = pmu_raw_readl(EXYNOS5420_LPI_MASK); + value |= EXYNOS5420_ATB_ISP_ARM; + pmu_raw_writel(value, EXYNOS5420_LPI_MASK); + + value = pmu_raw_readl(EXYNOS5420_LPI_MASK1); + value |= EXYNOS5420_ATB_KFC; + pmu_raw_writel(value, EXYNOS5420_LPI_MASK1); + + /* Prevent issue of new bus request from L2 memory */ + value = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); + value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; + pmu_raw_writel(value, EXYNOS5420_ARM_COMMON_OPTION); + + value = pmu_raw_readl(EXYNOS5420_KFC_COMMON_OPTION); + value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; + pmu_raw_writel(value, EXYNOS5420_KFC_COMMON_OPTION); + + /* This setting is to reduce suspend/resume time */ + pmu_raw_writel(DUR_WAIT_RESET, EXYNOS5420_LOGIC_RESET_DURATION3); + + /* Serialized CPU wakeup of Eagle */ + pmu_raw_writel(SPREAD_ENABLE, EXYNOS5420_ARM_INTR_SPREAD_ENABLE); + + pmu_raw_writel(SPREAD_USE_STANDWFI, + EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI); + + pmu_raw_writel(0x1, EXYNOS5420_UP_SCHEDULER); + + pm_power_off = exynos5_power_off; + pr_info("EXYNOS5420 PMU initialized\n"); +} + +static int pmu_restart_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + pmu_raw_writel(0x1, EXYNOS_SWRESET); + + return NOTIFY_DONE; +} + +static const struct exynos_pmu_data exynos3250_pmu_data = { + .pmu_config = exynos3250_pmu_config, + .pmu_init = exynos3250_pmu_init, + .powerdown_conf_extra = exynos3250_powerdown_conf_extra, +}; - exynos_pmu_config = exynos4210_pmu_config; - - if (soc_is_exynos4210()) { - exynos_pmu_config = exynos4210_pmu_config; - pr_info("EXYNOS4210 PMU Initialize\n"); - } else if (soc_is_exynos4212() || soc_is_exynos4412()) { - exynos_pmu_config = exynos4x12_pmu_config; - pr_info("EXYNOS4x12 PMU Initialize\n"); - } else if (soc_is_exynos5250()) { - /* - * When SYS_WDTRESET is set, watchdog timer reset request - * is ignored by power management unit. - */ - value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); - value &= ~EXYNOS5_SYS_WDTRESET; - pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); - - value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); - value &= ~EXYNOS5_SYS_WDTRESET; - pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); - - exynos_pmu_config = exynos5250_pmu_config; - pr_info("EXYNOS5250 PMU Initialize\n"); - } else { - pr_info("EXYNOS: PMU not supported\n"); +static const struct exynos_pmu_data exynos4210_pmu_data = { + .pmu_config = exynos4210_pmu_config, +}; + +static const struct exynos_pmu_data exynos4212_pmu_data = { + .pmu_config = exynos4x12_pmu_config, +}; + +static const struct exynos_pmu_data exynos4412_pmu_data = { + .pmu_config = exynos4x12_pmu_config, + .pmu_config_extra = exynos4412_pmu_config, +}; + +static const struct exynos_pmu_data exynos5250_pmu_data = { + .pmu_config = exynos5250_pmu_config, + .pmu_init = exynos5250_pmu_init, + .powerdown_conf = exynos5_powerdown_conf, +}; + +static struct exynos_pmu_data exynos5420_pmu_data = { + .pmu_config = exynos5420_pmu_config, + .pmu_init = exynos5420_pmu_init, + .powerdown_conf = exynos5420_powerdown_conf, +}; + +/* + * PMU platform driver and devicetree bindings. + */ +static const struct of_device_id exynos_pmu_of_device_ids[] = { + { + .compatible = "samsung,exynos3250-pmu", + .data = &exynos3250_pmu_data, + }, { + .compatible = "samsung,exynos4210-pmu", + .data = &exynos4210_pmu_data, + }, { + .compatible = "samsung,exynos4212-pmu", + .data = &exynos4212_pmu_data, + }, { + .compatible = "samsung,exynos4412-pmu", + .data = &exynos4412_pmu_data, + }, { + .compatible = "samsung,exynos5250-pmu", + .data = &exynos5250_pmu_data, + }, { + .compatible = "samsung,exynos5420-pmu", + .data = &exynos5420_pmu_data, + }, + { /*sentinel*/ }, +}; + +/* + * Exynos PMU restart notifier, handles restart functionality + */ +static struct notifier_block pmu_restart_handler = { + .notifier_call = pmu_restart_notify, + .priority = 128, +}; + +static int exynos_pmu_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct device *dev = &pdev->dev; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pmu_base_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(pmu_base_addr)) + return PTR_ERR(pmu_base_addr); + + pmu_context = devm_kzalloc(&pdev->dev, + sizeof(struct exynos_pmu_context), + GFP_KERNEL); + if (!pmu_context) { + dev_err(dev, "Cannot allocate memory.\n"); + return -ENOMEM; } + pmu_context->dev = dev; + + match = of_match_node(exynos_pmu_of_device_ids, dev->of_node); + + pmu_context->pmu_data = match->data; + + if (pmu_context->pmu_data->pmu_init) + pmu_context->pmu_data->pmu_init(); + + platform_set_drvdata(pdev, pmu_context); + ret = register_restart_handler(&pmu_restart_handler); + if (ret) + dev_warn(dev, "can't register restart handler err=%d\n", ret); + + dev_dbg(dev, "Exynos PMU Driver probe done\n"); return 0; } -arch_initcall(exynos_pmu_init); + +static struct platform_driver exynos_pmu_driver = { + .driver = { + .name = "exynos-pmu", + .owner = THIS_MODULE, + .of_match_table = exynos_pmu_of_device_ids, + }, + .probe = exynos_pmu_probe, +}; + +static int __init exynos_pmu_init(void) +{ + return platform_driver_register(&exynos_pmu_driver); + +} +postcore_initcall(exynos_pmu_init); diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 96a1569262b5..b5f4406fc1b5 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -19,8 +19,24 @@ #define S5P_CENTRAL_SEQ_OPTION 0x0208 #define S5P_USE_STANDBY_WFI0 (1 << 16) +#define S5P_USE_STANDBY_WFI1 (1 << 17) +#define S5P_USE_STANDBY_WFI2 (1 << 19) +#define S5P_USE_STANDBY_WFI3 (1 << 20) #define S5P_USE_STANDBY_WFE0 (1 << 24) +#define S5P_USE_STANDBY_WFE1 (1 << 25) +#define S5P_USE_STANDBY_WFE2 (1 << 27) +#define S5P_USE_STANDBY_WFE3 (1 << 28) +#define S5P_USE_STANDBY_WFI_ALL \ + (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFI1 | \ + S5P_USE_STANDBY_WFI2 | S5P_USE_STANDBY_WFI3 | \ + S5P_USE_STANDBY_WFE0 | S5P_USE_STANDBY_WFE1 | \ + S5P_USE_STANDBY_WFE2 | S5P_USE_STANDBY_WFE3) + +#define S5P_USE_DELAYED_RESET_ASSERTION BIT(12) + +#define EXYNOS_CORE_PO_RESET(n) ((1 << 4) << n) +#define EXYNOS_WAKEUP_FROM_LOWPWR (1 << 28) #define EXYNOS_SWRESET 0x0400 #define EXYNOS5440_SWRESET 0x00C4 @@ -35,6 +51,7 @@ #define S5P_INFORM7 0x081C #define S5P_PMU_SPARE3 0x090C +#define EXYNOS_IROM_DATA2 0x0988 #define S5P_ARM_CORE0_LOWPWR 0x1000 #define S5P_DIS_IRQ_CORE0 0x1004 #define S5P_DIS_IRQ_CENTRAL0 0x1008 @@ -106,6 +123,8 @@ (EXYNOS_ARM_CORE0_CONFIGURATION + (0x80 * (_nr))) #define EXYNOS_ARM_CORE_STATUS(_nr) \ (EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4) +#define EXYNOS_ARM_CORE_OPTION(_nr) \ + (EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x8) #define EXYNOS_ARM_COMMON_CONFIGURATION 0x2500 #define EXYNOS_COMMON_CONFIGURATION(_nr) \ @@ -115,6 +134,31 @@ #define EXYNOS_COMMON_OPTION(_nr) \ (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) +#define EXYNOS_CORE_LOCAL_PWR_EN 0x3 + +#define EXYNOS_ARM_COMMON_STATUS 0x2504 +#define EXYNOS_COMMON_OPTION(_nr) \ + (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) + +#define EXYNOS_ARM_L2_CONFIGURATION 0x2600 +#define EXYNOS_L2_CONFIGURATION(_nr) \ + (EXYNOS_ARM_L2_CONFIGURATION + ((_nr) * 0x80)) +#define EXYNOS_L2_STATUS(_nr) \ + (EXYNOS_L2_CONFIGURATION(_nr) + 0x4) +#define EXYNOS_L2_OPTION(_nr) \ + (EXYNOS_L2_CONFIGURATION(_nr) + 0x8) +#define EXYNOS_L2_COMMON_PWR_EN 0x3 + +#define EXYNOS_ARM_CORE_X_STATUS_OFFSET 0x4 + +#define EXYNOS5_APLL_SYSCLK_CONFIGURATION 0x2A00 +#define EXYNOS5_APLL_SYSCLK_STATUS 0x2A04 + +#define EXYNOS5_ARM_L2_OPTION 0x2608 +#define EXYNOS5_USE_RETENTION BIT(4) + +#define EXYNOS5_L2RSTDISABLE_VALUE BIT(3) + #define S5P_PAD_RET_MAUDIO_OPTION 0x3028 #define S5P_PAD_RET_GPIO_OPTION 0x3108 #define S5P_PAD_RET_UART_OPTION 0x3128 @@ -123,7 +167,19 @@ #define S5P_PAD_RET_EBIA_OPTION 0x3188 #define S5P_PAD_RET_EBIB_OPTION 0x31A8 +#define S5P_PS_HOLD_CONTROL 0x330C +#define S5P_PS_HOLD_EN (1 << 31) +#define S5P_PS_HOLD_OUTPUT_HIGH (3 << 8) + +#define S5P_CAM_OPTION 0x3C08 +#define S5P_MFC_OPTION 0x3C48 +#define S5P_G3D_OPTION 0x3C68 +#define S5P_LCD0_OPTION 0x3C88 +#define S5P_LCD1_OPTION 0x3CA8 +#define S5P_ISP_OPTION S5P_LCD1_OPTION + #define S5P_CORE_LOCAL_PWR_EN 0x3 +#define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8) /* Only for EXYNOS4210 */ #define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154 @@ -182,11 +238,116 @@ #define S5P_DIS_IRQ_CORE3 0x1034 #define S5P_DIS_IRQ_CENTRAL3 0x1038 +/* Only for EXYNOS3XXX */ +#define EXYNOS3_ARM_CORE0_SYS_PWR_REG 0x1000 +#define EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG 0x1004 +#define EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG 0x1008 +#define EXYNOS3_ARM_CORE1_SYS_PWR_REG 0x1010 +#define EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG 0x1014 +#define EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG 0x1018 +#define EXYNOS3_ISP_ARM_SYS_PWR_REG 0x1050 +#define EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1054 +#define EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1058 +#define EXYNOS3_ARM_COMMON_SYS_PWR_REG 0x1080 +#define EXYNOS3_ARM_L2_SYS_PWR_REG 0x10C0 +#define EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG 0x1100 +#define EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG 0x1104 +#define EXYNOS3_CMU_RESET_SYS_PWR_REG 0x110C +#define EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG 0x1110 +#define EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG 0x1114 +#define EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG 0x111C +#define EXYNOS3_APLL_SYSCLK_SYS_PWR_REG 0x1120 +#define EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG 0x1124 +#define EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG 0x1128 +#define EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG 0x112C +#define EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG 0x1130 +#define EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG 0x1134 +#define EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG 0x1138 +#define EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140 +#define EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148 +#define EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C +#define EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150 +#define EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG 0x1154 +#define EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158 +#define EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG 0x1160 +#define EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG 0x1168 +#define EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG 0x116C +#define EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG 0x1170 +#define EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG 0x1174 +#define EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178 +#define EXYNOS3_TOP_BUS_SYS_PWR_REG 0x1180 +#define EXYNOS3_TOP_RETENTION_SYS_PWR_REG 0x1184 +#define EXYNOS3_TOP_PWR_SYS_PWR_REG 0x1188 +#define EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG 0x1190 +#define EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG 0x1194 +#define EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG 0x1198 +#define EXYNOS3_LOGIC_RESET_SYS_PWR_REG 0x11A0 +#define EXYNOS3_OSCCLK_GATE_SYS_PWR_REG 0x11A4 +#define EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG 0x11B0 +#define EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG 0x11B4 +#define EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200 +#define EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204 +#define EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG 0x1208 +#define EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1218 +#define EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220 +#define EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG 0x1224 +#define EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1228 +#define EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG 0x122C +#define EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230 +#define EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234 +#define EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1238 +#define EXYNOS3_PAD_ISOLATION_SYS_PWR_REG 0x1240 +#define EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG 0x1260 +#define EXYNOS3_XUSBXTI_SYS_PWR_REG 0x1280 +#define EXYNOS3_XXTI_SYS_PWR_REG 0x1284 +#define EXYNOS3_EXT_REGULATOR_SYS_PWR_REG 0x12C0 +#define EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG 0x12C4 +#define EXYNOS3_GPIO_MODE_SYS_PWR_REG 0x1300 +#define EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340 +#define EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG 0x1344 +#define EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG 0x1348 +#define EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG 0x1350 +#define EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG 0x1354 +#define EXYNOS3_CAM_SYS_PWR_REG 0x1380 +#define EXYNOS3_MFC_SYS_PWR_REG 0x1388 +#define EXYNOS3_G3D_SYS_PWR_REG 0x138C +#define EXYNOS3_LCD0_SYS_PWR_REG 0x1390 +#define EXYNOS3_ISP_SYS_PWR_REG 0x1394 +#define EXYNOS3_MAUDIO_SYS_PWR_REG 0x1398 +#define EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG 0x13B0 +#define EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG 0x13B4 +#define EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG 0x13B8 +#define EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG 0x13C0 +#define EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG 0x13C4 +#define EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG 0x13C8 + +#define EXYNOS3_ARM_CORE0_OPTION 0x2008 +#define EXYNOS3_ARM_CORE_OPTION(_nr) \ + (EXYNOS3_ARM_CORE0_OPTION + ((_nr) * 0x80)) + +#define EXYNOS3_ARM_COMMON_OPTION 0x2408 +#define EXYNOS3_TOP_PWR_OPTION 0x2C48 +#define EXYNOS3_CORE_TOP_PWR_OPTION 0x2CA8 +#define EXYNOS3_XUSBXTI_DURATION 0x341C +#define EXYNOS3_XXTI_DURATION 0x343C +#define EXYNOS3_EXT_REGULATOR_DURATION 0x361C +#define EXYNOS3_EXT_REGULATOR_COREBLK_DURATION 0x363C +#define XUSBXTI_DURATION 0x00000BB8 +#define XXTI_DURATION XUSBXTI_DURATION +#define EXT_REGULATOR_DURATION 0x00001D4C +#define EXT_REGULATOR_COREBLK_DURATION EXT_REGULATOR_DURATION + +/* for XXX_OPTION */ +#define EXYNOS3_OPTION_USE_SC_COUNTER (1 << 0) +#define EXYNOS3_OPTION_USE_SC_FEEDBACK (1 << 1) +#define EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN (1 << 7) + /* For EXYNOS5 */ #define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408 #define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C +#define EXYNOS5_USE_RETENTION BIT(4) #define EXYNOS5_SYS_WDTRESET (1 << 20) #define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000 @@ -326,4 +487,204 @@ static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr) + MPIDR_AFFINITY_LEVEL(mpidr, 0)); } +/* Only for EXYNOS5420 */ +#define EXYNOS5420_ISP_ARM_OPTION 0x2488 +#define EXYNOS5420_L2RSTDISABLE_VALUE BIT(3) + +#define EXYNOS5420_LPI_MASK 0x0004 +#define EXYNOS5420_LPI_MASK1 0x0008 +#define EXYNOS5420_UFS BIT(8) +#define EXYNOS5420_ATB_KFC BIT(13) +#define EXYNOS5420_ATB_ISP_ARM BIT(19) +#define EXYNOS5420_EMULATION BIT(31) +#define ATB_ISP_ARM BIT(12) +#define ATB_KFC BIT(13) +#define ATB_NOC BIT(14) + +#define EXYNOS5420_ARM_INTR_SPREAD_ENABLE 0x0100 +#define EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI 0x0104 +#define EXYNOS5420_UP_SCHEDULER 0x0120 +#define SPREAD_ENABLE 0xF +#define SPREAD_USE_STANDWFI 0xF + +#define EXYNOS5420_BB_CON1 0x0784 +#define EXYNOS5420_BB_SEL_EN BIT(31) +#define EXYNOS5420_BB_PMOS_EN BIT(7) +#define EXYNOS5420_BB_1300X 0XF + +#define EXYNOS5420_ARM_CORE2_SYS_PWR_REG 0x1020 +#define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024 +#define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028 +#define EXYNOS5420_ARM_CORE3_SYS_PWR_REG 0x1030 +#define EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG 0x1034 +#define EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG 0x1038 +#define EXYNOS5420_KFC_CORE0_SYS_PWR_REG 0x1040 +#define EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG 0x1044 +#define EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG 0x1048 +#define EXYNOS5420_KFC_CORE1_SYS_PWR_REG 0x1050 +#define EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG 0x1054 +#define EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG 0x1058 +#define EXYNOS5420_KFC_CORE2_SYS_PWR_REG 0x1060 +#define EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG 0x1064 +#define EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG 0x1068 +#define EXYNOS5420_KFC_CORE3_SYS_PWR_REG 0x1070 +#define EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG 0x1074 +#define EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG 0x1078 +#define EXYNOS5420_ISP_ARM_SYS_PWR_REG 0x1090 +#define EXYNOS5420_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1094 +#define EXYNOS5420_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1098 +#define EXYNOS5420_ARM_COMMON_SYS_PWR_REG 0x10A0 +#define EXYNOS5420_KFC_COMMON_SYS_PWR_REG 0x10B0 +#define EXYNOS5420_KFC_L2_SYS_PWR_REG 0x10D0 +#define EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG 0x1158 +#define EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG 0x115C +#define EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG 0x1160 +#define EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG 0x1174 +#define EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG 0x1178 +#define EXYNOS5420_INTRAM_MEM_SYS_PWR_REG 0x11B8 +#define EXYNOS5420_INTROM_MEM_SYS_PWR_REG 0x11BC +#define EXYNOS5420_ONENANDXL_MEM_SYS_PWR 0x11C0 +#define EXYNOS5420_USBDEV_MEM_SYS_PWR 0x11CC +#define EXYNOS5420_USBDEV1_MEM_SYS_PWR 0x11D0 +#define EXYNOS5420_SDMMC_MEM_SYS_PWR 0x11D4 +#define EXYNOS5420_CSSYS_MEM_SYS_PWR 0x11D8 +#define EXYNOS5420_SECSS_MEM_SYS_PWR 0x11DC +#define EXYNOS5420_ROTATOR_MEM_SYS_PWR 0x11E0 +#define EXYNOS5420_INTRAM_MEM_SYS_PWR 0x11E4 +#define EXYNOS5420_INTROM_MEM_SYS_PWR 0x11E8 +#define EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1208 +#define EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1210 +#define EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG 0x1214 +#define EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1218 +#define EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG 0x121C +#define EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1220 +#define EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG 0x1224 +#define EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1228 +#define EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG 0x122C +#define EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG 0x1230 +#define EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG 0x1234 +#define EXYNOS5420_DISP1_SYS_PWR_REG 0x1410 +#define EXYNOS5420_MAU_SYS_PWR_REG 0x1414 +#define EXYNOS5420_G2D_SYS_PWR_REG 0x1418 +#define EXYNOS5420_MSC_SYS_PWR_REG 0x141C +#define EXYNOS5420_FSYS_SYS_PWR_REG 0x1420 +#define EXYNOS5420_FSYS2_SYS_PWR_REG 0x1424 +#define EXYNOS5420_PSGEN_SYS_PWR_REG 0x1428 +#define EXYNOS5420_PERIC_SYS_PWR_REG 0x142C +#define EXYNOS5420_WCORE_SYS_PWR_REG 0x1430 +#define EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG 0x1490 +#define EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG 0x1494 +#define EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG 0x1498 +#define EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG 0x149C +#define EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG 0x14A0 +#define EXYNOS5420_CMU_CLKSTOP_FSYS2_SYS_PWR_REG 0x14A4 +#define EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG 0x14A8 +#define EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG 0x14AC +#define EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG 0x14B0 +#define EXYNOS5420_CMU_SYSCLK_TOPPWR_SYS_PWR_REG 0x14BC +#define EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG 0x14D0 +#define EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG 0x14D4 +#define EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG 0x14D8 +#define EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG 0x14DC +#define EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG 0x14E0 +#define EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG 0x14E4 +#define EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG 0x14E8 +#define EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG 0x14EC +#define EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG 0x14F0 +#define EXYNOS5420_CMU_SYSCLK_SYSMEM_TOPPWR_SYS_PWR_REG 0x14F4 +#define EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG 0x1570 +#define EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG 0x1574 +#define EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG 0x1578 +#define EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG 0x157C +#define EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG 0x1590 +#define EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG 0x1594 +#define EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG 0x1598 +#define EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG 0x159C +#define EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG 0x15A0 +#define EXYNOS5420_SFR_AXI_CGDIS1 0x15E4 +#define EXYNOS_ARM_CORE2_CONFIGURATION 0x2100 +#define EXYNOS5420_ARM_CORE2_OPTION 0x2108 +#define EXYNOS_ARM_CORE3_CONFIGURATION 0x2180 +#define EXYNOS5420_ARM_CORE3_OPTION 0x2188 +#define EXYNOS5420_ARM_COMMON_STATUS 0x2504 +#define EXYNOS5420_ARM_COMMON_OPTION 0x2508 +#define EXYNOS5420_KFC_COMMON_STATUS 0x2584 +#define EXYNOS5420_KFC_COMMON_OPTION 0x2588 +#define EXYNOS5420_LOGIC_RESET_DURATION3 0x2D1C + +#define EXYNOS5420_PAD_RET_GPIO_OPTION 0x30C8 +#define EXYNOS5420_PAD_RET_UART_OPTION 0x30E8 +#define EXYNOS5420_PAD_RET_MMCA_OPTION 0x3108 +#define EXYNOS5420_PAD_RET_MMCB_OPTION 0x3128 +#define EXYNOS5420_PAD_RET_MMCC_OPTION 0x3148 +#define EXYNOS5420_PAD_RET_HSI_OPTION 0x3168 +#define EXYNOS5420_PAD_RET_SPI_OPTION 0x31C8 +#define EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION 0x31E8 +#define EXYNOS_PAD_RET_DRAM_OPTION 0x3008 +#define EXYNOS_PAD_RET_MAUDIO_OPTION 0x3028 +#define EXYNOS_PAD_RET_JTAG_OPTION 0x3048 +#define EXYNOS_PAD_RET_GPIO_OPTION 0x3108 +#define EXYNOS_PAD_RET_UART_OPTION 0x3128 +#define EXYNOS_PAD_RET_MMCA_OPTION 0x3148 +#define EXYNOS_PAD_RET_MMCB_OPTION 0x3168 +#define EXYNOS_PAD_RET_EBIA_OPTION 0x3188 +#define EXYNOS_PAD_RET_EBIB_OPTION 0x31A8 + +#define EXYNOS_PS_HOLD_CONTROL 0x330C + +/* For SYS_PWR_REG */ +#define EXYNOS_SYS_PWR_CFG BIT(0) + +#define EXYNOS5420_MFC_CONFIGURATION 0x4060 +#define EXYNOS5420_MFC_STATUS 0x4064 +#define EXYNOS5420_MFC_OPTION 0x4068 +#define EXYNOS5420_G3D_CONFIGURATION 0x4080 +#define EXYNOS5420_G3D_STATUS 0x4084 +#define EXYNOS5420_G3D_OPTION 0x4088 +#define EXYNOS5420_DISP0_CONFIGURATION 0x40A0 +#define EXYNOS5420_DISP0_STATUS 0x40A4 +#define EXYNOS5420_DISP0_OPTION 0x40A8 +#define EXYNOS5420_DISP1_CONFIGURATION 0x40C0 +#define EXYNOS5420_DISP1_STATUS 0x40C4 +#define EXYNOS5420_DISP1_OPTION 0x40C8 +#define EXYNOS5420_MAU_CONFIGURATION 0x40E0 +#define EXYNOS5420_MAU_STATUS 0x40E4 +#define EXYNOS5420_MAU_OPTION 0x40E8 +#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) +#define EXYNOS5420_ARM_USE_STANDBY_WFI3 BIT(7) +#define EXYNOS5420_KFC_USE_STANDBY_WFI0 BIT(8) +#define EXYNOS5420_KFC_USE_STANDBY_WFI1 BIT(9) +#define EXYNOS5420_KFC_USE_STANDBY_WFI2 BIT(10) +#define EXYNOS5420_KFC_USE_STANDBY_WFI3 BIT(11) +#define EXYNOS5420_ARM_USE_STANDBY_WFE0 BIT(16) +#define EXYNOS5420_ARM_USE_STANDBY_WFE1 BIT(17) +#define EXYNOS5420_ARM_USE_STANDBY_WFE2 BIT(18) +#define EXYNOS5420_ARM_USE_STANDBY_WFE3 BIT(19) +#define EXYNOS5420_KFC_USE_STANDBY_WFE0 BIT(20) +#define EXYNOS5420_KFC_USE_STANDBY_WFE1 BIT(21) +#define EXYNOS5420_KFC_USE_STANDBY_WFE2 BIT(22) +#define EXYNOS5420_KFC_USE_STANDBY_WFE3 BIT(23) + +#define DUR_WAIT_RESET 0xF + +#define EXYNOS5420_USE_STANDBY_WFI_ALL (EXYNOS5420_ARM_USE_STANDBY_WFI0 \ + | EXYNOS5420_ARM_USE_STANDBY_WFI1 \ + | EXYNOS5420_ARM_USE_STANDBY_WFI2 \ + | EXYNOS5420_ARM_USE_STANDBY_WFI3 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI0 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI1 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI2 \ + | EXYNOS5420_KFC_USE_STANDBY_WFI3) + #endif /* __ASM_ARCH_REGS_PMU_H */ diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S index 108a45f4bb62..e3c373082bbe 100644 --- a/arch/arm/mach-exynos/sleep.S +++ b/arch/arm/mach-exynos/sleep.S @@ -16,6 +16,7 @@ */ #include <linux/linkage.h> +#include "smc.h" #define CPU_MASK 0xff0ffff0 #define CPU_CORTEX_A9 0x410fc090 @@ -55,3 +56,30 @@ ENTRY(exynos_cpu_resume) #endif b cpu_resume ENDPROC(exynos_cpu_resume) + + .align + +ENTRY(exynos_cpu_resume_ns) + mrc p15, 0, r0, c0, c0, 0 + ldr r1, =CPU_MASK + and r0, r0, r1 + ldr r1, =CPU_CORTEX_A9 + cmp r0, r1 + bne skip_cp15 + + adr r0, cp15_save_power + ldr r1, [r0] + adr r0, cp15_save_diag + ldr r2, [r0] + mov r0, #SMC_CMD_C15RESUME + dsb + smc #0 +skip_cp15: + b cpu_resume +ENDPROC(exynos_cpu_resume_ns) + .globl cp15_save_diag +cp15_save_diag: + .long 0 @ cp15 diagnostic + .globl cp15_save_power +cp15_save_power: + .long 0 @ cp15 power control diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h index 13a1dc8ecbf2..f7b82f9c1e21 100644 --- a/arch/arm/mach-exynos/smc.h +++ b/arch/arm/mach-exynos/smc.h @@ -26,6 +26,10 @@ #define SMC_CMD_L2X0INVALL (-24) #define SMC_CMD_L2X0DEBUG (-25) +#ifndef __ASSEMBLY__ + extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); +#endif /* __ASSEMBLY__ */ + #endif diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c new file mode 100644 index 000000000000..f8e7dcd17055 --- /dev/null +++ b/arch/arm/mach-exynos/suspend.c @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - Suspend support + * + * Based on arch/arm/mach-s3c2410/pm.c + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/syscore_ops.h> +#include <linux/cpu_pm.h> +#include <linux/io.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> + +#include <asm/cacheflush.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/firmware.h> +#include <asm/mcpm.h> +#include <asm/smp_scu.h> +#include <asm/suspend.h> + +#include <plat/pm-common.h> +#include <plat/regs-srom.h> + +#include "common.h" +#include "regs-pmu.h" +#include "regs-sys.h" +#include "exynos-pmu.h" + +#define S5P_CHECK_SLEEP 0x00000BAD + +#define REG_TABLE_END (-1U) + +#define EXYNOS5420_CPU_STATE 0x28 + +/** + * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping + * @hwirq: Hardware IRQ signal of the GIC + * @mask: Mask in PMU wake-up mask register + */ +struct exynos_wkup_irq { + unsigned int hwirq; + u32 mask; +}; + +static struct sleep_save exynos5_sys_save[] = { + SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), +}; + +static struct sleep_save exynos_core_save[] = { + /* SROM side */ + SAVE_ITEM(S5P_SROM_BW), + SAVE_ITEM(S5P_SROM_BC0), + SAVE_ITEM(S5P_SROM_BC1), + SAVE_ITEM(S5P_SROM_BC2), + SAVE_ITEM(S5P_SROM_BC3), +}; + +struct exynos_pm_data { + const struct exynos_wkup_irq *wkup_irq; + struct sleep_save *extra_save; + int num_extra_save; + unsigned int wake_disable_mask; + unsigned int *release_ret_regs; + + void (*pm_prepare)(void); + void (*pm_resume_prepare)(void); + void (*pm_resume)(void); + int (*pm_suspend)(void); + int (*cpu_suspend)(unsigned long); +}; + +struct exynos_pm_data *pm_data; + +static int exynos5420_cpu_state; +static unsigned int exynos_pmu_spare3; + +/* + * GIC wake-up support + */ + +static u32 exynos_irqwake_intmask = 0xffffffff; + +static const struct exynos_wkup_irq exynos4_wkup_irq[] = { + { 76, BIT(1) }, /* RTC alarm */ + { 77, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { + { 75, BIT(1) }, /* RTC alarm */ + { 76, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +unsigned int exynos_release_ret_regs[] = { + S5P_PAD_RET_MAUDIO_OPTION, + S5P_PAD_RET_GPIO_OPTION, + S5P_PAD_RET_UART_OPTION, + S5P_PAD_RET_MMCA_OPTION, + S5P_PAD_RET_MMCB_OPTION, + S5P_PAD_RET_EBIA_OPTION, + S5P_PAD_RET_EBIB_OPTION, + REG_TABLE_END, +}; + +unsigned int exynos5420_release_ret_regs[] = { + EXYNOS_PAD_RET_DRAM_OPTION, + EXYNOS_PAD_RET_MAUDIO_OPTION, + EXYNOS_PAD_RET_JTAG_OPTION, + EXYNOS5420_PAD_RET_GPIO_OPTION, + EXYNOS5420_PAD_RET_UART_OPTION, + EXYNOS5420_PAD_RET_MMCA_OPTION, + EXYNOS5420_PAD_RET_MMCB_OPTION, + EXYNOS5420_PAD_RET_MMCC_OPTION, + EXYNOS5420_PAD_RET_HSI_OPTION, + EXYNOS_PAD_RET_EBIA_OPTION, + EXYNOS_PAD_RET_EBIB_OPTION, + EXYNOS5420_PAD_RET_SPI_OPTION, + EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION, + REG_TABLE_END, +}; + +static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) +{ + const struct exynos_wkup_irq *wkup_irq; + + if (!pm_data->wkup_irq) + return -ENOENT; + wkup_irq = pm_data->wkup_irq; + + while (wkup_irq->mask) { + if (wkup_irq->hwirq == data->hwirq) { + if (!state) + exynos_irqwake_intmask |= wkup_irq->mask; + else + exynos_irqwake_intmask &= ~wkup_irq->mask; + return 0; + } + ++wkup_irq; + } + + return -ENOENT; +} + +static int exynos_cpu_do_idle(void) +{ + /* issue the standby signal into the pm unit. */ + cpu_do_idle(); + + pr_info("Failed to suspend the system\n"); + return 1; /* Aborting suspend */ +} +static void exynos_flush_cache_all(void) +{ + flush_cache_all(); + outer_flush_all(); +} + +static int exynos_cpu_suspend(unsigned long arg) +{ + exynos_flush_cache_all(); + return exynos_cpu_do_idle(); +} + +static int exynos5420_cpu_suspend(unsigned long arg) +{ + /* MCPM works with HW CPU identifiers */ + unsigned int mpidr = read_cpuid_mpidr(); + unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); + + __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); + + if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) { + mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); + + /* + * Residency value passed to mcpm_cpu_suspend back-end + * has to be given clear semantics. Set to 0 as a + * temporary value. + */ + mcpm_cpu_suspend(0); + } + + pr_info("Failed to suspend the system\n"); + + /* return value != 0 means failure */ + return 1; +} + +static void exynos_pm_set_wakeup_mask(void) +{ + /* Set wake-up mask registers */ + pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); + pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); +} + +static void exynos_pm_enter_sleep_mode(void) +{ + /* Set value of power down register for sleep mode */ + exynos_sys_powerdown_conf(SYS_SLEEP); + pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); +} + +static void exynos_pm_prepare(void) +{ + /* Set wake-up mask registers */ + exynos_pm_set_wakeup_mask(); + + s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + if (pm_data->extra_save) + s3c_pm_do_save(pm_data->extra_save, + pm_data->num_extra_save); + + exynos_pm_enter_sleep_mode(); + + /* ensure at least INFORM0 has the resume address */ + pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); +} + +static void exynos5420_pm_prepare(void) +{ + unsigned int tmp; + + /* Set wake-up mask registers */ + exynos_pm_set_wakeup_mask(); + + s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); + /* + * The cpu state needs to be saved and restored so that the + * secondary CPUs will enter low power start. Though the U-Boot + * is setting the cpu state with low power flag, the kernel + * needs to restore it back in case, the primary cpu fails to + * suspend for any reason. + */ + exynos5420_cpu_state = __raw_readl(sysram_base_addr + + EXYNOS5420_CPU_STATE); + + exynos_pm_enter_sleep_mode(); + + /* ensure at least INFORM0 has the resume address */ + if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) + pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0); + + tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION); + tmp &= ~EXYNOS5_USE_RETENTION; + pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); + tmp |= EXYNOS5420_UFS; + pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); + + tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); + tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE; + pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); + tmp |= EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); + tmp |= EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); +} + + +static int exynos_pm_suspend(void) +{ + exynos_pm_central_suspend(); + + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_save_register(); + + return 0; +} + +static int exynos5420_pm_suspend(void) +{ + u32 this_cluster; + + exynos_pm_central_suspend(); + + /* Setting SEQ_OPTION register */ + + this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); + if (!this_cluster) + pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0, + S5P_CENTRAL_SEQ_OPTION); + else + pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0, + S5P_CENTRAL_SEQ_OPTION); + return 0; +} + +static void exynos_pm_release_retention(void) +{ + unsigned int i; + + for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++) + pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR, + pm_data->release_ret_regs[i]); +} + +static void exynos_pm_resume(void) +{ + u32 cpuid = read_cpuid_part(); + + if (exynos_pm_central_resume()) + goto early_wakeup; + + /* For release retention */ + exynos_pm_release_retention(); + + if (pm_data->extra_save) + s3c_pm_do_restore_core(pm_data->extra_save, + pm_data->num_extra_save); + + s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + + if (cpuid == ARM_CPU_PART_CORTEX_A9) + scu_enable(S5P_VA_SCU); + + if (call_firmware_op(resume) == -ENOSYS + && cpuid == ARM_CPU_PART_CORTEX_A9) + exynos_cpu_restore_register(); + +early_wakeup: + + /* Clear SLEEP mode set in INFORM1 */ + pmu_raw_writel(0x0, S5P_INFORM1); +} + +static void exynos5420_prepare_pm_resume(void) +{ + if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) + WARN_ON(mcpm_cpu_powered_up()); +} + +static void exynos5420_pm_resume(void) +{ + unsigned long tmp; + + /* Restore the CPU0 low power state register */ + tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); + pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN, + EXYNOS5_ARM_CORE0_SYS_PWR_REG); + + /* Restore the sysram cpu state register */ + __raw_writel(exynos5420_cpu_state, + sysram_base_addr + EXYNOS5420_CPU_STATE); + + pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, + S5P_CENTRAL_SEQ_OPTION); + + if (exynos_pm_central_resume()) + goto early_wakeup; + + /* For release retention */ + exynos_pm_release_retention(); + + pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3); + + s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + +early_wakeup: + + tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); + tmp &= ~EXYNOS5420_UFS; + pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); + + tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); + tmp &= ~EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); + + tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); + tmp &= ~EXYNOS5420_EMULATION; + pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); + + /* Clear SLEEP mode set in INFORM1 */ + pmu_raw_writel(0x0, S5P_INFORM1); +} + +/* + * Suspend Ops + */ + +static int exynos_suspend_enter(suspend_state_t state) +{ + int ret; + + s3c_pm_debug_init(); + + S3C_PMDBG("%s: suspending the system...\n", __func__); + + S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, + exynos_irqwake_intmask, exynos_get_eint_wake_mask()); + + if (exynos_irqwake_intmask == -1U + && exynos_get_eint_wake_mask() == -1U) { + pr_err("%s: No wake-up sources!\n", __func__); + pr_err("%s: Aborting sleep\n", __func__); + return -EINVAL; + } + + s3c_pm_save_uarts(); + if (pm_data->pm_prepare) + pm_data->pm_prepare(); + flush_cache_all(); + s3c_pm_check_store(); + + ret = call_firmware_op(suspend); + if (ret == -ENOSYS) + ret = cpu_suspend(0, pm_data->cpu_suspend); + if (ret) + return ret; + + if (pm_data->pm_resume_prepare) + pm_data->pm_resume_prepare(); + s3c_pm_restore_uarts(); + + S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, + pmu_raw_readl(S5P_WAKEUP_STAT)); + + s3c_pm_check_restore(); + + S3C_PMDBG("%s: resuming the system...\n", __func__); + + return 0; +} + +static int exynos_suspend_prepare(void) +{ + int ret; + + /* + * REVISIT: It would be better if struct platform_suspend_ops + * .prepare handler get the suspend_state_t as a parameter to + * avoid hard-coding the suspend to mem state. It's safe to do + * it now only because the suspend_valid_only_mem function is + * used as the .valid callback used to check if a given state + * is supported by the platform anyways. + */ + ret = regulator_suspend_prepare(PM_SUSPEND_MEM); + if (ret) { + pr_err("Failed to prepare regulators for suspend (%d)\n", ret); + return ret; + } + + s3c_pm_check_prepare(); + + return 0; +} + +static void exynos_suspend_finish(void) +{ + int ret; + + s3c_pm_check_cleanup(); + + ret = regulator_suspend_finish(); + if (ret) + pr_warn("Failed to resume regulators from suspend (%d)\n", ret); +} + +static const struct platform_suspend_ops exynos_suspend_ops = { + .enter = exynos_suspend_enter, + .prepare = exynos_suspend_prepare, + .finish = exynos_suspend_finish, + .valid = suspend_valid_only_mem, +}; + +static const struct exynos_pm_data exynos4_pm_data = { + .wkup_irq = exynos4_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static const struct exynos_pm_data exynos5250_pm_data = { + .wkup_irq = exynos5250_wkup_irq, + .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), + .release_ret_regs = exynos_release_ret_regs, + .extra_save = exynos5_sys_save, + .num_extra_save = ARRAY_SIZE(exynos5_sys_save), + .pm_suspend = exynos_pm_suspend, + .pm_resume = exynos_pm_resume, + .pm_prepare = exynos_pm_prepare, + .cpu_suspend = exynos_cpu_suspend, +}; + +static struct exynos_pm_data exynos5420_pm_data = { + .wkup_irq = exynos5250_wkup_irq, + .wake_disable_mask = (0x7F << 7) | (0x1F << 1), + .release_ret_regs = exynos5420_release_ret_regs, + .pm_resume_prepare = exynos5420_prepare_pm_resume, + .pm_resume = exynos5420_pm_resume, + .pm_suspend = exynos5420_pm_suspend, + .pm_prepare = exynos5420_pm_prepare, + .cpu_suspend = exynos5420_cpu_suspend, +}; + +static struct of_device_id exynos_pmu_of_device_ids[] = { + { + .compatible = "samsung,exynos4210-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4212-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos4412-pmu", + .data = &exynos4_pm_data, + }, { + .compatible = "samsung,exynos5250-pmu", + .data = &exynos5250_pm_data, + }, { + .compatible = "samsung,exynos5420-pmu", + .data = &exynos5420_pm_data, + }, + { /*sentinel*/ }, +}; + +static struct syscore_ops exynos_pm_syscore_ops; + +void __init exynos_pm_init(void) +{ + const struct of_device_id *match; + u32 tmp; + + of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); + if (!match) { + pr_err("Failed to find PMU node\n"); + return; + } + pm_data = (struct exynos_pm_data *) match->data; + + /* Platform-specific GIC callback */ + gic_arch_extn.irq_set_wake = exynos_irq_set_wake; + + /* All wakeup disable */ + tmp = pmu_raw_readl(S5P_WAKEUP_MASK); + tmp |= pm_data->wake_disable_mask; + pmu_raw_writel(tmp, S5P_WAKEUP_MASK); + + exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; + exynos_pm_syscore_ops.resume = pm_data->pm_resume; + + register_syscore_ops(&exynos_pm_syscore_ops); + suspend_set_ops(&exynos_suspend_ops); +} diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 11b2957f792b..e8627e04e1e6 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -633,12 +633,41 @@ config SOC_VF610 bool "Vybrid Family VF610 support" select ARM_GIC select PINCTRL_VF610 - select VF_PIT_TIMER select PL310_ERRATA_769419 if CACHE_L2X0 help This enable support for Freescale Vybrid VF610 processor. +choice + prompt "Clocksource for scheduler clock" + depends on SOC_VF610 + default VF_USE_ARM_GLOBAL_TIMER + + config VF_USE_ARM_GLOBAL_TIMER + bool "Use ARM Global Timer" + select ARM_GLOBAL_TIMER + select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK + help + Use the ARM Global Timer as clocksource + + config VF_USE_PIT_TIMER + bool "Use PIT timer" + select VF_PIT_TIMER + help + Use SoC Periodic Interrupt Timer (PIT) as clocksource + +endchoice + +config SOC_LS1021A + bool "Freescale LS1021A support" + select ARM_GIC + select HAVE_ARM_ARCH_TIMER + select PCI_DOMAINS if PCI + select ZONE_DMA if ARM_LPAE + + help + This enable support for Freescale LS1021A processor. + endif source "arch/arm/mach-imx/devices/Kconfig" diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 6e4fcd8339cd..f5ac685a29fc 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci- obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o imx5-pm-$(CONFIG_PM) += pm-imx5.o -obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o $(imx5-pm-y) +obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y) obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ clk-pfd.o clk-busy.o clk.o \ @@ -89,7 +89,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 -ifdef CONFIG_SOC_IMX6 +ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) AFLAGS_headsmp.o :=-Wa,-march=armv7-a obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o @@ -110,4 +110,6 @@ obj-$(CONFIG_SOC_IMX53) += mach-imx53.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o +obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o + obj-y += devices/ diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c index 8259a625a920..7f262fe4ba77 100644 --- a/arch/arm/mach-imx/anatop.c +++ b/arch/arm/mach-imx/anatop.c @@ -30,8 +30,11 @@ #define ANADIG_DIGPROG_IMX6SL 0x280 #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 +#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8 #define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 +/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */ +#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000 #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000 #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000 @@ -56,16 +59,43 @@ static void imx_anatop_enable_fet_odrive(bool enable) BM_ANADIG_REG_CORE_FET_ODRIVE); } +static inline void imx_anatop_enable_2p5_pulldown(bool enable) +{ + regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR), + BM_ANADIG_REG_2P5_ENABLE_PULLDOWN); +} + +static inline void imx_anatop_disconnect_high_snvs(bool enable) +{ + regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR), + BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); +} + void imx_anatop_pre_suspend(void) { - imx_anatop_enable_weak2p5(true); + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx_anatop_enable_2p5_pulldown(true); + else + imx_anatop_enable_weak2p5(true); + imx_anatop_enable_fet_odrive(true); + + if (cpu_is_imx6sl()) + imx_anatop_disconnect_high_snvs(true); } void imx_anatop_post_resume(void) { + if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) + imx_anatop_enable_2p5_pulldown(false); + else + imx_anatop_enable_weak2p5(false); + imx_anatop_enable_fet_odrive(false); - imx_anatop_enable_weak2p5(false); + + if (cpu_is_imx6sl()) + imx_anatop_disconnect_high_snvs(false); + } static void imx_anatop_usb_chrg_detect_disable(void) diff --git a/arch/arm/mach-imx/clk-cpu.c b/arch/arm/mach-imx/clk-cpu.c new file mode 100644 index 000000000000..aa1c345e2a19 --- /dev/null +++ b/arch/arm/mach-imx/clk-cpu.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/slab.h> + +struct clk_cpu { + struct clk_hw hw; + struct clk *div; + struct clk *mux; + struct clk *pll; + struct clk *step; +}; + +static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw) +{ + return container_of(hw, struct clk_cpu, hw); +} + +static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_cpu *cpu = to_clk_cpu(hw); + + return clk_get_rate(cpu->div); +} + +static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_cpu *cpu = to_clk_cpu(hw); + + return clk_round_rate(cpu->pll, rate); +} + +static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_cpu *cpu = to_clk_cpu(hw); + int ret; + + /* switch to PLL bypass clock */ + ret = clk_set_parent(cpu->mux, cpu->step); + if (ret) + return ret; + + /* reprogram PLL */ + ret = clk_set_rate(cpu->pll, rate); + if (ret) { + clk_set_parent(cpu->mux, cpu->pll); + return ret; + } + /* switch back to PLL clock */ + clk_set_parent(cpu->mux, cpu->pll); + + /* Ensure the divider is what we expect */ + clk_set_rate(cpu->div, rate); + + return 0; +} + +static const struct clk_ops clk_cpu_ops = { + .recalc_rate = clk_cpu_recalc_rate, + .round_rate = clk_cpu_round_rate, + .set_rate = clk_cpu_set_rate, +}; + +struct clk *imx_clk_cpu(const char *name, const char *parent_name, + struct clk *div, struct clk *mux, struct clk *pll, + struct clk *step) +{ + struct clk_cpu *cpu; + struct clk *clk; + struct clk_init_data init; + + cpu = kzalloc(sizeof(*cpu), GFP_KERNEL); + if (!cpu) + return ERR_PTR(-ENOMEM); + + cpu->div = div; + cpu->mux = mux; + cpu->pll = pll; + cpu->step = step; + + init.name = name; + init.ops = &clk_cpu_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + cpu->hw.init = &init; + + clk = clk_register(NULL, &cpu->hw); + if (IS_ERR(clk)) + kfree(cpu); + + return clk; +} diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index 72d65214223e..0f7e536147cb 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -125,6 +125,8 @@ static const char *mx53_spdif_xtal_sel[] = { "osc", "ckih", "ckih2", "pll4_sw", static const char *spdif_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "spdif_xtal_sel", }; static const char *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", }; static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_root_gate", }; +static const char *step_sels[] = { "lp_apm", }; +static const char *cpu_podf_sels[] = { "pll1_sw", "step_sel" }; static struct clk *clk[IMX5_CLK_END]; static struct clk_onecell_data clk_data; @@ -193,7 +195,9 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base) clk[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3); clk[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1, usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str)); - clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3); + clk[IMX5_CLK_STEP_SEL] = imx_clk_mux("step_sel", MXC_CCM_CCSR, 7, 2, step_sels, ARRAY_SIZE(step_sels)); + clk[IMX5_CLK_CPU_PODF_SEL] = imx_clk_mux("cpu_podf_sel", MXC_CCM_CCSR, 2, 1, cpu_podf_sels, ARRAY_SIZE(cpu_podf_sels)); + clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "cpu_podf_sel", MXC_CCM_CACRR, 0, 3); clk[IMX5_CLK_DI_PRED] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3); clk[IMX5_CLK_IIM_GATE] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30); clk[IMX5_CLK_UART1_IPG_GATE] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6); @@ -537,6 +541,11 @@ static void __init mx53_clocks_init(struct device_node *np) clk[IMX5_CLK_CKO2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24); clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2, mx53_spdif_xtal_sel, ARRAY_SIZE(mx53_spdif_xtal_sel)); + clk[IMX5_CLK_ARM] = imx_clk_cpu("arm", "cpu_podf", + clk[IMX5_CLK_CPU_PODF], + clk[IMX5_CLK_CPU_PODF_SEL], + clk[IMX5_CLK_PLL1_SW], + clk[IMX5_CLK_STEP_SEL]); imx_check_clocks(clk, ARRAY_SIZE(clk)); @@ -551,6 +560,9 @@ static void __init mx53_clocks_init(struct device_node *np) /* move can bus clk to 24MHz */ clk_set_parent(clk[IMX5_CLK_CAN_SEL], clk[IMX5_CLK_LP_APM]); + /* make sure step clock is running from 24MHz */ + clk_set_parent(clk[IMX5_CLK_STEP_SEL], clk[IMX5_CLK_LP_APM]); + clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]); imx_print_silicon_rev("i.MX53", mx53_revision()); clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]); diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index 4e79da7c5e30..5951660d1bd2 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -145,7 +145,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) post_div_table[2].div = 1; video_div_table[1].div = 1; video_div_table[2].div = 1; - }; + } clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c index 57de74da0acf..0ad6e5442fd8 100644 --- a/arch/arm/mach-imx/clk-pllv3.c +++ b/arch/arm/mach-imx/clk-pllv3.c @@ -69,7 +69,6 @@ static int clk_pllv3_prepare(struct clk_hw *hw) { struct clk_pllv3 *pll = to_clk_pllv3(hw); u32 val; - int ret; val = readl_relaxed(pll->base); if (pll->powerup_set) @@ -78,11 +77,7 @@ static int clk_pllv3_prepare(struct clk_hw *hw) val &= ~BM_PLL_POWER; writel_relaxed(val, pll->base); - ret = clk_pllv3_wait_lock(pll); - if (ret) - return ret; - - return 0; + return clk_pllv3_wait_lock(pll); } static void clk_pllv3_unprepare(struct clk_hw *hw) diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c index a17818475050..5937ddee1a99 100644 --- a/arch/arm/mach-imx/clk-vf610.c +++ b/arch/arm/mach-imx/clk-vf610.c @@ -58,8 +58,14 @@ #define PFD_PLL1_BASE (anatop_base + 0x2b0) #define PFD_PLL2_BASE (anatop_base + 0x100) #define PFD_PLL3_BASE (anatop_base + 0xf0) +#define PLL1_CTRL (anatop_base + 0x270) +#define PLL2_CTRL (anatop_base + 0x30) #define PLL3_CTRL (anatop_base + 0x10) +#define PLL4_CTRL (anatop_base + 0x70) +#define PLL5_CTRL (anatop_base + 0xe0) +#define PLL6_CTRL (anatop_base + 0xa0) #define PLL7_CTRL (anatop_base + 0x20) +#define ANA_MISC1 (anatop_base + 0x160) static void __iomem *anatop_base; static void __iomem *ccm_base; @@ -67,25 +73,34 @@ static void __iomem *ccm_base; /* sources for multiplexer clocks, this is used multiple times */ static const char *fast_sels[] = { "firc", "fxosc", }; static const char *slow_sels[] = { "sirc_32k", "sxosc", }; -static const char *pll1_sels[] = { "pll1_main", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", }; -static const char *pll2_sels[] = { "pll2_main", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", }; -static const char *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_main", "pll1_pfd_sel", "pll3_main", }; +static const char *pll1_sels[] = { "pll1_sys", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", }; +static const char *pll2_sels[] = { "pll2_bus", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", }; +static const char *pll_bypass_src_sels[] = { "fast_clk_sel", "lvds1_in", }; +static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; +static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; +static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; +static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; +static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", }; +static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", }; +static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; +static const char *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_bus", "pll1_pfd_sel", "pll3_usb_otg", }; static const char *ddr_sels[] = { "pll2_pfd2", "sys_sel", }; static const char *rmii_sels[] = { "enet_ext", "audio_ext", "enet_50m", "enet_25m", }; static const char *enet_ts_sels[] = { "enet_ext", "fxosc", "audio_ext", "usb", "enet_ts", "enet_25m", "enet_50m", }; -static const char *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; -static const char *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; +static const char *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", }; +static const char *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_audio_div", }; static const char *nfc_sels[] = { "platform_bus", "pll1_pfd1", "pll3_pfd1", "pll3_pfd3", }; -static const char *qspi_sels[] = { "pll3_main", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", }; -static const char *esdhc_sels[] = { "pll3_main", "pll3_pfd3", "pll1_pfd3", "platform_bus", }; -static const char *dcu_sels[] = { "pll1_pfd2", "pll3_main", }; +static const char *qspi_sels[] = { "pll3_usb_otg", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", }; +static const char *esdhc_sels[] = { "pll3_usb_otg", "pll3_pfd3", "pll1_pfd3", "platform_bus", }; +static const char *dcu_sels[] = { "pll1_pfd2", "pll3_usb_otg", }; static const char *gpu_sels[] = { "pll2_pfd2", "pll3_pfd2", }; -static const char *vadc_sels[] = { "pll6_main_div", "pll3_main_div", "pll3_main", }; +static const char *vadc_sels[] = { "pll6_video_div", "pll3_usb_otg_div", "pll3_usb_otg", }; /* FTM counter clock source, not module clock */ static const char *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ext", }; static const char *ftm_fix_sels[] = { "sxosc", "ipg_bus", }; -static struct clk_div_table pll4_main_div_table[] = { + +static struct clk_div_table pll4_audio_div_table[] = { { .val = 0, .div = 1 }, { .val = 1, .div = 2 }, { .val = 2, .div = 6 }, @@ -105,6 +120,17 @@ static unsigned int const clks_init_on[] __initconst = { VF610_CLK_DDR_SEL, }; +static struct clk * __init vf610_get_fixed_clock( + struct device_node *ccm_node, const char *name) +{ + struct clk *clk = of_clk_get_by_name(ccm_node, name); + + /* Backward compatibility if device tree is missing clks assignments */ + if (IS_ERR(clk)) + clk = imx_obtain_fixed_clock(name, 0); + return clk; +}; + static void __init vf610_clocks_init(struct device_node *ccm_node) { struct device_node *np; @@ -115,10 +141,13 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000); clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000); - clk[VF610_CLK_SXOSC] = imx_obtain_fixed_clock("sxosc", 0); - clk[VF610_CLK_FXOSC] = imx_obtain_fixed_clock("fxosc", 0); - clk[VF610_CLK_AUDIO_EXT] = imx_obtain_fixed_clock("audio_ext", 0); - clk[VF610_CLK_ENET_EXT] = imx_obtain_fixed_clock("enet_ext", 0); + clk[VF610_CLK_SXOSC] = vf610_get_fixed_clock(ccm_node, "sxosc"); + clk[VF610_CLK_FXOSC] = vf610_get_fixed_clock(ccm_node, "fxosc"); + clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(ccm_node, "audio_ext"); + clk[VF610_CLK_ENET_EXT] = vf610_get_fixed_clock(ccm_node, "enet_ext"); + + /* Clock source from external clock via LVDs PAD */ + clk[VF610_CLK_ANACLK1] = vf610_get_fixed_clock(ccm_node, "anaclk1"); clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2); @@ -133,31 +162,63 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_SLOW_CLK_SEL] = imx_clk_mux("slow_clk_sel", CCM_CCSR, 4, 1, slow_sels, ARRAY_SIZE(slow_sels)); clk[VF610_CLK_FASK_CLK_SEL] = imx_clk_mux("fast_clk_sel", CCM_CCSR, 5, 1, fast_sels, ARRAY_SIZE(fast_sels)); - clk[VF610_CLK_PLL1_MAIN] = imx_clk_fixed_factor("pll1_main", "fast_clk_sel", 22, 1); - clk[VF610_CLK_PLL1_PFD1] = imx_clk_pfd("pll1_pfd1", "pll1_main", PFD_PLL1_BASE, 0); - clk[VF610_CLK_PLL1_PFD2] = imx_clk_pfd("pll1_pfd2", "pll1_main", PFD_PLL1_BASE, 1); - clk[VF610_CLK_PLL1_PFD3] = imx_clk_pfd("pll1_pfd3", "pll1_main", PFD_PLL1_BASE, 2); - clk[VF610_CLK_PLL1_PFD4] = imx_clk_pfd("pll1_pfd4", "pll1_main", PFD_PLL1_BASE, 3); - - clk[VF610_CLK_PLL2_MAIN] = imx_clk_fixed_factor("pll2_main", "fast_clk_sel", 22, 1); - clk[VF610_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_main", PFD_PLL2_BASE, 0); - clk[VF610_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_main", PFD_PLL2_BASE, 1); - clk[VF610_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3", "pll2_main", PFD_PLL2_BASE, 2); - clk[VF610_CLK_PLL2_PFD4] = imx_clk_pfd("pll2_pfd4", "pll2_main", PFD_PLL2_BASE, 3); - - clk[VF610_CLK_PLL3_MAIN] = imx_clk_fixed_factor("pll3_main", "fast_clk_sel", 20, 1); - clk[VF610_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_main", PFD_PLL3_BASE, 0); - clk[VF610_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_main", PFD_PLL3_BASE, 1); - clk[VF610_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_main", PFD_PLL3_BASE, 2); - clk[VF610_CLK_PLL3_PFD4] = imx_clk_pfd("pll3_pfd4", "pll3_main", PFD_PLL3_BASE, 3); - - clk[VF610_CLK_PLL4_MAIN] = imx_clk_fixed_factor("pll4_main", "fast_clk_sel", 25, 1); - /* Enet pll: fixed 50Mhz */ - clk[VF610_CLK_PLL5_MAIN] = imx_clk_fixed_factor("pll5_main", "fast_clk_sel", 125, 6); - /* pll6: default 960Mhz */ - clk[VF610_CLK_PLL6_MAIN] = imx_clk_fixed_factor("pll6_main", "fast_clk_sel", 40, 1); - /* pll7: USB1 PLL at 480MHz */ - clk[VF610_CLK_PLL7_MAIN] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_main", "fast_clk_sel", PLL7_CTRL, 0x2); + clk[VF610_CLK_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", PLL1_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", PLL2_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", PLL3_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", PLL4_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", PLL5_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", PLL6_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clk[VF610_CLK_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", PLL7_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + + clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1); + clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1); + clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", PLL3_CTRL, 0x1); + clk[VF610_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", PLL4_CTRL, 0x7f); + clk[VF610_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll5", "pll5_bypass_src", PLL5_CTRL, 0x3); + clk[VF610_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_AV, "pll6", "pll6_bypass_src", PLL6_CTRL, 0x7f); + clk[VF610_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", PLL7_CTRL, 0x1); + + clk[VF610_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", PLL1_CTRL, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", PLL2_CTRL, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", PLL3_CTRL, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", PLL4_CTRL, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", PLL5_CTRL, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", PLL6_CTRL, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT); + clk[VF610_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", PLL7_CTRL, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT); + + /* Do not bypass PLLs initially */ + clk_set_parent(clk[VF610_PLL1_BYPASS], clk[VF610_CLK_PLL1]); + clk_set_parent(clk[VF610_PLL2_BYPASS], clk[VF610_CLK_PLL2]); + clk_set_parent(clk[VF610_PLL3_BYPASS], clk[VF610_CLK_PLL3]); + clk_set_parent(clk[VF610_PLL4_BYPASS], clk[VF610_CLK_PLL4]); + clk_set_parent(clk[VF610_PLL5_BYPASS], clk[VF610_CLK_PLL5]); + clk_set_parent(clk[VF610_PLL6_BYPASS], clk[VF610_CLK_PLL6]); + clk_set_parent(clk[VF610_PLL7_BYPASS], clk[VF610_CLK_PLL7]); + + clk[VF610_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", PLL1_CTRL, 13); + clk[VF610_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", PLL2_CTRL, 13); + clk[VF610_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", PLL3_CTRL, 13); + clk[VF610_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", PLL4_CTRL, 13); + clk[VF610_CLK_PLL5_ENET] = imx_clk_gate("pll5_enet", "pll5_bypass", PLL5_CTRL, 13); + clk[VF610_CLK_PLL6_VIDEO] = imx_clk_gate("pll6_video", "pll6_bypass", PLL6_CTRL, 13); + clk[VF610_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", PLL7_CTRL, 13); + + clk[VF610_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", ANA_MISC1, 12, BIT(10)); + + clk[VF610_CLK_PLL1_PFD1] = imx_clk_pfd("pll1_pfd1", "pll1_sys", PFD_PLL1_BASE, 0); + clk[VF610_CLK_PLL1_PFD2] = imx_clk_pfd("pll1_pfd2", "pll1_sys", PFD_PLL1_BASE, 1); + clk[VF610_CLK_PLL1_PFD3] = imx_clk_pfd("pll1_pfd3", "pll1_sys", PFD_PLL1_BASE, 2); + clk[VF610_CLK_PLL1_PFD4] = imx_clk_pfd("pll1_pfd4", "pll1_sys", PFD_PLL1_BASE, 3); + + clk[VF610_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus", PFD_PLL2_BASE, 0); + clk[VF610_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus", PFD_PLL2_BASE, 1); + clk[VF610_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3", "pll2_bus", PFD_PLL2_BASE, 2); + clk[VF610_CLK_PLL2_PFD4] = imx_clk_pfd("pll2_pfd4", "pll2_bus", PFD_PLL2_BASE, 3); + + clk[VF610_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", PFD_PLL3_BASE, 0); + clk[VF610_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", PFD_PLL3_BASE, 1); + clk[VF610_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", PFD_PLL3_BASE, 2); + clk[VF610_CLK_PLL3_PFD4] = imx_clk_pfd("pll3_pfd4", "pll3_usb_otg", PFD_PLL3_BASE, 3); clk[VF610_CLK_PLL1_PFD_SEL] = imx_clk_mux("pll1_pfd_sel", CCM_CCSR, 16, 3, pll1_sels, 5); clk[VF610_CLK_PLL2_PFD_SEL] = imx_clk_mux("pll2_pfd_sel", CCM_CCSR, 19, 3, pll2_sels, 5); @@ -167,12 +228,12 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_PLATFORM_BUS] = imx_clk_divider("platform_bus", "sys_bus", CCM_CACRR, 3, 3); clk[VF610_CLK_IPG_BUS] = imx_clk_divider("ipg_bus", "platform_bus", CCM_CACRR, 11, 2); - clk[VF610_CLK_PLL3_MAIN_DIV] = imx_clk_divider("pll3_main_div", "pll3_main", CCM_CACRR, 20, 1); - clk[VF610_CLK_PLL4_MAIN_DIV] = clk_register_divider_table(NULL, "pll4_main_div", "pll4_main", 0, CCM_CACRR, 6, 3, 0, pll4_main_div_table, &imx_ccm_lock); - clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_main_div", "pll6_main", CCM_CACRR, 21, 1); + clk[VF610_CLK_PLL3_MAIN_DIV] = imx_clk_divider("pll3_usb_otg_div", "pll3_usb_otg", CCM_CACRR, 20, 1); + clk[VF610_CLK_PLL4_MAIN_DIV] = clk_register_divider_table(NULL, "pll4_audio_div", "pll4_audio", 0, CCM_CACRR, 6, 3, 0, pll4_audio_div_table, &imx_ccm_lock); + clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_video_div", "pll6_video", CCM_CACRR, 21, 1); - clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_main", PLL3_CTRL, 6); - clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_main", PLL7_CTRL, 6); + clk[VF610_CLK_USBPHY0] = imx_clk_gate("usbphy0", "pll3_usb_otg", PLL3_CTRL, 6); + clk[VF610_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll7_usb_host", PLL7_CTRL, 6); clk[VF610_CLK_USBC0] = imx_clk_gate2("usbc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(4)); clk[VF610_CLK_USBC1] = imx_clk_gate2("usbc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(4)); @@ -191,8 +252,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_QSPI1_X1_DIV] = imx_clk_divider("qspi1_x1", "qspi1_x2", CCM_CSCDR3, 11, 1); clk[VF610_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_x1", CCM_CCGR8, CCM_CCGRx_CGn(4)); - clk[VF610_CLK_ENET_50M] = imx_clk_fixed_factor("enet_50m", "pll5_main", 1, 10); - clk[VF610_CLK_ENET_25M] = imx_clk_fixed_factor("enet_25m", "pll5_main", 1, 20); + clk[VF610_CLK_ENET_50M] = imx_clk_fixed_factor("enet_50m", "pll5_enet", 1, 10); + clk[VF610_CLK_ENET_25M] = imx_clk_fixed_factor("enet_25m", "pll5_enet", 1, 20); clk[VF610_CLK_ENET_SEL] = imx_clk_mux("enet_sel", CCM_CSCMR2, 4, 2, rmii_sels, 4); clk[VF610_CLK_ENET_TS_SEL] = imx_clk_mux("enet_ts_sel", CCM_CSCMR2, 0, 3, enet_ts_sels, 7); clk[VF610_CLK_ENET] = imx_clk_gate("enet", "enet_sel", CCM_CSCDR1, 24); diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h index 4cdf8b6a74e8..5ef82e2f8fc5 100644 --- a/arch/arm/mach-imx/clk.h +++ b/arch/arm/mach-imx/clk.h @@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, CLK_SET_RATE_PARENT, mult, div); } +struct clk *imx_clk_cpu(const char *name, const char *parent_name, + struct clk *div, struct clk *mux, struct clk *pll, + struct clk *step); + #endif diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 1dabf435c592..cfcdb623d78f 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -61,7 +61,6 @@ struct platform_device *mxc_register_gpio(char *name, int id, void mxc_set_cpu_type(unsigned int type); void mxc_restart(enum reboot_mode, const char *); void mxc_arch_reset_init(void __iomem *); -void mxc_arch_reset_init_dt(void); int mx51_revision(void); int mx53_revision(void); void imx_set_aips(void __iomem *); @@ -108,14 +107,15 @@ void imx_gpc_pre_suspend(bool arm_power_off); void imx_gpc_post_resume(void); void imx_gpc_mask_all(void); void imx_gpc_restore_all(void); -void imx_gpc_irq_mask(struct irq_data *d); -void imx_gpc_irq_unmask(struct irq_data *d); +void imx_gpc_hwirq_mask(unsigned int hwirq); +void imx_gpc_hwirq_unmask(unsigned int hwirq); void imx_anatop_init(void); void imx_anatop_pre_suspend(void); void imx_anatop_post_resume(void); int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); void imx6q_set_int_mem_clk_lpm(bool enable); void imx6sl_set_wait_clk(bool enter); +int imx_mmdc_get_ddr_type(void); void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); @@ -157,5 +157,6 @@ static inline void imx_init_l2cache(void) {} #endif extern struct smp_operations imx_smp_ops; +extern struct smp_operations ls1021a_smp_ops; #endif diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c index 82ea74e68482..5f3602ec74fa 100644 --- a/arch/arm/mach-imx/gpc.c +++ b/arch/arm/mach-imx/gpc.c @@ -56,14 +56,14 @@ void imx_gpc_post_resume(void) static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) { - unsigned int idx = d->irq / 32 - 1; + unsigned int idx = d->hwirq / 32 - 1; u32 mask; /* Sanity check for SPI irq */ - if (d->irq < 32) + if (d->hwirq < 32) return -EINVAL; - mask = 1 << d->irq % 32; + mask = 1 << d->hwirq % 32; gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask : gpc_wake_irqs[idx] & ~mask; @@ -91,34 +91,44 @@ void imx_gpc_restore_all(void) writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); } -void imx_gpc_irq_unmask(struct irq_data *d) +void imx_gpc_hwirq_unmask(unsigned int hwirq) { void __iomem *reg; u32 val; - /* Sanity check for SPI irq */ - if (d->irq < 32) - return; - - reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4; + reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4; val = readl_relaxed(reg); - val &= ~(1 << d->irq % 32); + val &= ~(1 << hwirq % 32); writel_relaxed(val, reg); } -void imx_gpc_irq_mask(struct irq_data *d) +void imx_gpc_hwirq_mask(unsigned int hwirq) { void __iomem *reg; u32 val; + reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4; + val = readl_relaxed(reg); + val |= 1 << (hwirq % 32); + writel_relaxed(val, reg); +} + +static void imx_gpc_irq_unmask(struct irq_data *d) +{ + /* Sanity check for SPI irq */ + if (d->hwirq < 32) + return; + + imx_gpc_hwirq_unmask(d->hwirq); +} + +static void imx_gpc_irq_mask(struct irq_data *d) +{ /* Sanity check for SPI irq */ - if (d->irq < 32) + if (d->hwirq < 32) return; - reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4; - val = readl_relaxed(reg); - val |= 1 << (d->irq % 32); - writel_relaxed(val, reg); + imx_gpc_hwirq_mask(d->hwirq); } void __init imx_gpc_init(void) diff --git a/arch/arm/mach-imx/imx25-dt.c b/arch/arm/mach-imx/imx25-dt.c index cf8032bae277..25defbdb06c4 100644 --- a/arch/arm/mach-imx/imx25-dt.c +++ b/arch/arm/mach-imx/imx25-dt.c @@ -17,13 +17,6 @@ #include "common.h" #include "mx25.h" -static void __init imx25_dt_init(void) -{ - mxc_arch_reset_init_dt(); - - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} - static const char * const imx25_dt_board_compat[] __initconst = { "fsl,imx25", NULL @@ -33,7 +26,5 @@ DT_MACHINE_START(IMX25_DT, "Freescale i.MX25 (Device Tree Support)") .map_io = mx25_map_io, .init_early = imx25_init_early, .init_irq = mx25_init_irq, - .init_machine = imx25_dt_init, .dt_compat = imx25_dt_board_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c index dc8f1a6f45f2..bd42d1bd10af 100644 --- a/arch/arm/mach-imx/imx27-dt.c +++ b/arch/arm/mach-imx/imx27-dt.c @@ -22,8 +22,6 @@ static void __init imx27_dt_init(void) { struct platform_device_info devinfo = { .name = "cpufreq-dt", }; - mxc_arch_reset_init_dt(); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); platform_device_register_full(&devinfo); @@ -40,5 +38,4 @@ DT_MACHINE_START(IMX27_DT, "Freescale i.MX27 (Device Tree Support)") .init_irq = mx27_init_irq, .init_machine = imx27_dt_init, .dt_compat = imx27_dt_board_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/imx31-dt.c b/arch/arm/mach-imx/imx31-dt.c index 418dbc82adc4..32100222a017 100644 --- a/arch/arm/mach-imx/imx31-dt.c +++ b/arch/arm/mach-imx/imx31-dt.c @@ -18,13 +18,6 @@ #include "common.h" #include "mx31.h" -static void __init imx31_dt_init(void) -{ - mxc_arch_reset_init_dt(); - - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} - static const char * const imx31_dt_board_compat[] __initconst = { "fsl,imx31", NULL @@ -40,7 +33,5 @@ DT_MACHINE_START(IMX31_DT, "Freescale i.MX31 (Device Tree Support)") .init_early = imx31_init_early, .init_irq = mx31_init_irq, .init_time = imx31_dt_timer_init, - .init_machine = imx31_dt_init, .dt_compat = imx31_dt_board_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/imx35-dt.c b/arch/arm/mach-imx/imx35-dt.c index 584fbe105579..e9396037235d 100644 --- a/arch/arm/mach-imx/imx35-dt.c +++ b/arch/arm/mach-imx/imx35-dt.c @@ -20,14 +20,6 @@ #include "common.h" #include "mx35.h" -static void __init imx35_dt_init(void) -{ - mxc_arch_reset_init_dt(); - - of_platform_populate(NULL, of_default_bus_match_table, - NULL, NULL); -} - static void __init imx35_irq_init(void) { imx_init_l2cache(); @@ -43,7 +35,5 @@ DT_MACHINE_START(IMX35_DT, "Freescale i.MX35 (Device Tree Support)") .map_io = mx35_map_io, .init_early = imx35_init_early, .init_irq = imx35_irq_init, - .init_machine = imx35_dt_init, .dt_compat = imx35_dt_board_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/iomux-imx31.c b/arch/arm/mach-imx/iomux-imx31.c index 1657fe64cd0f..d6a30753ca7c 100644 --- a/arch/arm/mach-imx/iomux-imx31.c +++ b/arch/arm/mach-imx/iomux-imx31.c @@ -44,9 +44,11 @@ static unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG]; /* * set the mode for a IOMUX pin. */ -int mxc_iomux_mode(unsigned int pin_mode) +void mxc_iomux_mode(unsigned int pin_mode) { - u32 field, l, mode, ret = 0; + u32 field; + u32 l; + u32 mode; void __iomem *reg; reg = IOMUXSW_MUX_CTL + (pin_mode & IOMUX_REG_MASK); @@ -61,8 +63,6 @@ int mxc_iomux_mode(unsigned int pin_mode) __raw_writel(l, reg); spin_unlock(&gpio_mux_lock); - - return ret; } /* diff --git a/arch/arm/mach-imx/iomux-mx3.h b/arch/arm/mach-imx/iomux-mx3.h index f79f78a1c0ed..0a5adba61e0b 100644 --- a/arch/arm/mach-imx/iomux-mx3.h +++ b/arch/arm/mach-imx/iomux-mx3.h @@ -144,7 +144,7 @@ void mxc_iomux_set_gpr(enum iomux_gp_func, bool en); * It is called by the setup functions and should not be called directly anymore. * It is here visible for backward compatibility */ -int mxc_iomux_mode(unsigned int pin_mode); +void mxc_iomux_mode(unsigned int pin_mode); #define IOMUX_PADNUM_MASK 0x1ff #define IOMUX_GPIONUM_SHIFT 9 diff --git a/arch/arm/mach-imx/mach-imx50.c b/arch/arm/mach-imx/mach-imx50.c index b1e56a94a382..ecf58b9e974b 100644 --- a/arch/arm/mach-imx/mach-imx50.c +++ b/arch/arm/mach-imx/mach-imx50.c @@ -16,13 +16,6 @@ #include "common.h" -static void __init imx50_dt_init(void) -{ - mxc_arch_reset_init_dt(); - - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} - static const char * const imx50_dt_board_compat[] __initconst = { "fsl,imx50", NULL @@ -30,7 +23,5 @@ static const char * const imx50_dt_board_compat[] __initconst = { DT_MACHINE_START(IMX50_DT, "Freescale i.MX50 (Device Tree Support)") .init_irq = tzic_init_irq, - .init_machine = imx50_dt_init, .dt_compat = imx50_dt_board_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx51.c b/arch/arm/mach-imx/mach-imx51.c index 2c5fcaf8675b..b015129e4045 100644 --- a/arch/arm/mach-imx/mach-imx51.c +++ b/arch/arm/mach-imx/mach-imx51.c @@ -53,7 +53,6 @@ static void __init imx51_dt_init(void) { struct platform_device_info devinfo = { .name = "cpufreq-dt", }; - mxc_arch_reset_init_dt(); imx51_ipu_mipi_setup(); imx_src_init(); @@ -78,5 +77,4 @@ DT_MACHINE_START(IMX51_DT, "Freescale i.MX51 (Device Tree Support)") .init_machine = imx51_dt_init, .init_late = imx51_init_late, .dt_compat = imx51_dt_board_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx53.c b/arch/arm/mach-imx/mach-imx53.c index 03dd6ea13acc..86316a979297 100644 --- a/arch/arm/mach-imx/mach-imx53.c +++ b/arch/arm/mach-imx/mach-imx53.c @@ -30,7 +30,6 @@ static void __init imx53_init_early(void) static void __init imx53_dt_init(void) { - mxc_arch_reset_init_dt(); imx_src_init(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); @@ -41,6 +40,8 @@ static void __init imx53_dt_init(void) static void __init imx53_init_late(void) { imx53_pm_init(); + + platform_device_register_simple("cpufreq-dt", -1, NULL, 0); } static const char * const imx53_dt_board_compat[] __initconst = { @@ -54,5 +55,4 @@ DT_MACHINE_START(IMX53_DT, "Freescale i.MX53 (Device Tree Support)") .init_machine = imx53_dt_init, .init_late = imx53_init_late, .dt_compat = imx53_dt_board_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index d51c6e99a2e9..5057d61298b7 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -268,8 +268,6 @@ static void __init imx6q_init_machine(void) imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", imx_get_soc_revision()); - mxc_arch_reset_init_dt(); - parent = imx_soc_device_init(); if (parent == NULL) pr_warn("failed to initialize soc device\n"); @@ -409,5 +407,4 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)") .init_machine = imx6q_init_machine, .init_late = imx6q_init_late, .dt_compat = imx6q_dt_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c index ed263a21d928..24bfaaf944c8 100644 --- a/arch/arm/mach-imx/mach-imx6sl.c +++ b/arch/arm/mach-imx/mach-imx6sl.c @@ -48,8 +48,6 @@ static void __init imx6sl_init_machine(void) { struct device *parent; - mxc_arch_reset_init_dt(); - parent = imx_soc_device_init(); if (parent == NULL) pr_warn("failed to initialize soc device\n"); @@ -76,10 +74,8 @@ static const char * const imx6sl_dt_compat[] __initconst = { }; DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)") - .map_io = debug_ll_io_init, .init_irq = imx6sl_init_irq, .init_machine = imx6sl_init_machine, .init_late = imx6sl_init_late, .dt_compat = imx6sl_dt_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c index 3de3b7369aef..7a96c6577234 100644 --- a/arch/arm/mach-imx/mach-imx6sx.c +++ b/arch/arm/mach-imx/mach-imx6sx.c @@ -8,24 +8,73 @@ #include <linux/irqchip.h> #include <linux/of_platform.h> +#include <linux/phy.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #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; + + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr"); + if (!IS_ERR(gpr)) { + regmap_update_bits(gpr, IOMUXC_GPR1, + IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK, 0); + regmap_update_bits(gpr, IOMUXC_GPR1, + IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK, 0); + } else { + pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n"); + } +} + +static inline void imx6sx_enet_init(void) +{ + imx6sx_enet_phy_init(); + imx6sx_enet_clk_sel(); +} + static void __init imx6sx_init_machine(void) { struct device *parent; - mxc_arch_reset_init_dt(); - parent = imx_soc_device_init(); if (parent == NULL) pr_warn("failed to initialize soc device\n"); of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); + imx6sx_enet_init(); imx_anatop_init(); imx6sx_pm_init(); } @@ -53,10 +102,8 @@ static const char * const imx6sx_dt_compat[] __initconst = { }; DT_MACHINE_START(IMX6SX, "Freescale i.MX6 SoloX (Device Tree)") - .map_io = debug_ll_io_init, .init_irq = imx6sx_init_irq, .init_machine = imx6sx_init_machine, .dt_compat = imx6sx_dt_compat, .init_late = imx6sx_init_late, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mach-ls1021a.c b/arch/arm/mach-imx/mach-ls1021a.c new file mode 100644 index 000000000000..b89c858ebfd6 --- /dev/null +++ b/arch/arm/mach-imx/mach-ls1021a.c @@ -0,0 +1,22 @@ +/* + * Copyright 2013-2014 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <asm/mach/arch.h> + +#include "common.h" + +static const char * const ls1021a_dt_compat[] __initconst = { + "fsl,ls1021a", + NULL, +}; + +DT_MACHINE_START(LS1021A, "Freescale LS1021A") + .smp = smp_ops(ls1021a_smp_ops), + .dt_compat = ls1021a_dt_compat, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-vf610.c b/arch/arm/mach-imx/mach-vf610.c index ee7e57b752a7..c11ab6a1dc87 100644 --- a/arch/arm/mach-imx/mach-vf610.c +++ b/arch/arm/mach-imx/mach-vf610.c @@ -12,14 +12,6 @@ #include <asm/mach/arch.h> #include <asm/hardware/cache-l2x0.h> -#include "common.h" - -static void __init vf610_init_machine(void) -{ - mxc_arch_reset_init_dt(); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} - static const char * const vf610_dt_compat[] __initconst = { "fsl,vf610", NULL, @@ -28,7 +20,5 @@ static const char * const vf610_dt_compat[] __initconst = { DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF610 (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, - .init_machine = vf610_init_machine, .dt_compat = vf610_dt_compat, - .restart = mxc_restart, MACHINE_END diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index 7a9686ad994c..3729d90cfa46 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -21,6 +21,12 @@ #define BP_MMDC_MAPSR_PSD 0 #define BP_MMDC_MAPSR_PSS 4 +#define MMDC_MDMISC 0x18 +#define BM_MMDC_MDMISC_DDR_TYPE 0x18 +#define BP_MMDC_MDMISC_DDR_TYPE 0x3 + +static int ddr_type; + static int imx_mmdc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -31,6 +37,12 @@ static int imx_mmdc_probe(struct platform_device *pdev) mmdc_base = of_iomap(np, 0); WARN_ON(!mmdc_base); + reg = mmdc_base + MMDC_MDMISC; + /* Get ddr type */ + val = readl_relaxed(reg); + ddr_type = (val & BM_MMDC_MDMISC_DDR_TYPE) >> + BP_MMDC_MDMISC_DDR_TYPE; + reg = mmdc_base + MMDC_MAPSR; /* Enable automatic power saving */ @@ -51,6 +63,11 @@ static int imx_mmdc_probe(struct platform_device *pdev) return 0; } +int imx_mmdc_get_ddr_type(void) +{ + return ddr_type; +} + static struct of_device_id imx_mmdc_dt_ids[] = { { .compatible = "fsl,imx6q-mmdc", }, { /* sentinel */ } diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 17a41ca65acf..4c1343df2ba4 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -55,6 +55,8 @@ #define IMX_CHIP_REVISION_3_3 0x33 #define IMX_CHIP_REVISION_UNKNOWN 0xff +#define IMX_DDR_TYPE_LPDDR2 1 + #ifndef __ASSEMBLY__ extern unsigned int __mxc_cpu_type; #endif diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c index 771bd25c1025..7f270015fe58 100644 --- a/arch/arm/mach-imx/platsmp.c +++ b/arch/arm/mach-imx/platsmp.c @@ -11,7 +11,10 @@ */ #include <linux/init.h> +#include <linux/of_address.h> +#include <linux/of.h> #include <linux/smp.h> + #include <asm/cacheflush.h> #include <asm/page.h> #include <asm/smp_scu.h> @@ -94,3 +97,33 @@ struct smp_operations imx_smp_ops __initdata = { .cpu_kill = imx_cpu_kill, #endif }; + +#define DCFG_CCSR_SCRATCHRW1 0x200 + +static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + return 0; +} + +static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *np; + void __iomem *dcfg_base; + unsigned long paddr; + + np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg"); + dcfg_base = of_iomap(np, 0); + BUG_ON(!dcfg_base); + + paddr = virt_to_phys(secondary_startup); + writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1); + + iounmap(dcfg_base); +} + +struct smp_operations ls1021a_smp_ops __initdata = { + .smp_prepare_cpus = ls1021a_smp_prepare_cpus, + .smp_boot_secondary = ls1021a_boot_secondary, +}; diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 5c3af8f993d0..5d2c1bd5f5ef 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -88,7 +88,7 @@ struct imx6_pm_base { }; struct imx6_pm_socdata { - u32 cpu_type; + u32 ddr_type; const char *mmdc_compat; const char *src_compat; const char *iomuxc_compat; @@ -138,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = { }; static const struct imx6_pm_socdata imx6q_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6Q, .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6q-iomuxc", @@ -148,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6DL, .mmdc_compat = "fsl,imx6q-mmdc", .src_compat = "fsl,imx6q-src", .iomuxc_compat = "fsl,imx6dl-iomuxc", @@ -158,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6SL, .mmdc_compat = "fsl,imx6sl-mmdc", .src_compat = "fsl,imx6sl-src", .iomuxc_compat = "fsl,imx6sl-iomuxc", @@ -168,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = { }; static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { - .cpu_type = MXC_CPU_IMX6SX, .mmdc_compat = "fsl,imx6sx-mmdc", .src_compat = "fsl,imx6sx-src", .iomuxc_compat = "fsl,imx6sx-iomuxc", @@ -187,7 +183,7 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = { struct imx6_cpu_pm_info { phys_addr_t pbase; /* The physical address of pm_info. */ phys_addr_t resume_addr; /* The physical resume address for asm code */ - u32 cpu_type; + u32 ddr_type; u32 pm_info_size; /* Size of pm_info. */ struct imx6_pm_base mmdc_base; struct imx6_pm_base src_base; @@ -261,7 +257,6 @@ static void imx6q_enable_wb(bool enable) int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) { - struct irq_data *iomuxc_irq_data = irq_get_irq_data(32); u32 val = readl_relaxed(ccm_base + CLPCR); val &= ~BM_CLPCR_LPM; @@ -316,9 +311,9 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) * 3) Software should mask IRQ #32 right after CCM Low-Power mode * is set (set bits 0-1 of CCM_CLPCR). */ - imx_gpc_irq_unmask(iomuxc_irq_data); + imx_gpc_hwirq_unmask(32); writel_relaxed(val, ccm_base + CLPCR); - imx_gpc_irq_mask(iomuxc_irq_data); + imx_gpc_hwirq_mask(32); return 0; } @@ -522,7 +517,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) goto pl310_cache_map_failed; } - pm_info->cpu_type = socdata->cpu_type; + pm_info->ddr_type = imx_mmdc_get_ddr_type(); pm_info->mmdc_io_num = socdata->mmdc_io_num; mmdc_offset_array = socdata->mmdc_io_offset; diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S index ca4ea2daf25b..b99987b023fa 100644 --- a/arch/arm/mach-imx/suspend-imx6.S +++ b/arch/arm/mach-imx/suspend-imx6.S @@ -45,7 +45,7 @@ */ #define PM_INFO_PBASE_OFFSET 0x0 #define PM_INFO_RESUME_ADDR_OFFSET 0x4 -#define PM_INFO_CPU_TYPE_OFFSET 0x8 +#define PM_INFO_DDR_TYPE_OFFSET 0x8 #define PM_INFO_PM_INFO_SIZE_OFFSET 0xC #define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 #define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 @@ -110,7 +110,7 @@ ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] - cmp r3, #MXC_CPU_IMX6SL + cmp r3, #IMX_DDR_TYPE_LPDDR2 bne 4f /* reset read FIFO, RST_RD_FIFO */ @@ -151,7 +151,7 @@ ENTRY(imx6_suspend) ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] - ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET] + ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] /* @@ -209,8 +209,8 @@ poll_dvfs_set: ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET add r8, r8, r0 - /* i.MX6SL's last 3 IOs need special setting */ - cmp r3, #MXC_CPU_IMX6SL + /* LPDDR2's last 3 IOs need special setting */ + cmp r3, #IMX_DDR_TYPE_LPDDR2 subeq r7, r7, #0x3 set_mmdc_io_lpm: ldr r9, [r8], #0x8 @@ -218,7 +218,7 @@ set_mmdc_io_lpm: subs r7, r7, #0x1 bne set_mmdc_io_lpm - cmp r3, #MXC_CPU_IMX6SL + cmp r3, #IMX_DDR_TYPE_LPDDR2 bne set_mmdc_io_lpm_done ldr r6, =0x1000 ldr r9, [r8], #0x8 @@ -324,7 +324,7 @@ resume: str r7, [r11, #MX6Q_SRC_GPR1] str r7, [r11, #MX6Q_SRC_GPR2] - ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET] + ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET] mov r5, #0x1 resume_mmdc diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c index d14c33fd6b03..51c35013b673 100644 --- a/arch/arm/mach-imx/system.c +++ b/arch/arm/mach-imx/system.c @@ -89,21 +89,6 @@ void __init mxc_arch_reset_init(void __iomem *base) clk_prepare(wdog_clk); } -void __init mxc_arch_reset_init_dt(void) -{ - struct device_node *np; - - np = of_find_compatible_node(NULL, NULL, "fsl,imx21-wdt"); - wdog_base = of_iomap(np, 0); - WARN_ON(!wdog_base); - - wdog_clk = of_clk_get(np, 0); - if (IS_ERR(wdog_clk)) - pr_warn("%s: failed to get wdog clock\n", __func__); - else - clk_prepare(wdog_clk); -} - #ifdef CONFIG_CACHE_L2X0 void __init imx_init_l2cache(void) { diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig index c455e974bbfe..02d083489a26 100644 --- a/arch/arm/mach-integrator/Kconfig +++ b/arch/arm/mach-integrator/Kconfig @@ -1,3 +1,26 @@ +config ARCH_INTEGRATOR + bool "ARM Ltd. Integrator family" if (ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6) + select ARM_AMBA + select ARM_PATCH_PHYS_VIRT if MMU + select AUTO_ZRELADDR + select COMMON_CLK + select COMMON_CLK_VERSATILE + select GENERIC_CLOCKEVENTS + select HAVE_TCM + select ICST + select MFD_SYSCON + select MULTI_IRQ_HANDLER + select PLAT_VERSATILE + select POWER_RESET + select POWER_RESET_VERSATILE + select POWER_SUPPLY + select SOC_INTEGRATOR_CM + select SPARSE_IRQ + select USE_OF + select VERSATILE_FPGA_IRQ + help + Support for ARM's Integrator platform. + if ARCH_INTEGRATOR menu "Integrator Options" diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile index ec759ded7b60..1ebe45356b09 100644 --- a/arch/arm/mach-integrator/Makefile +++ b/arch/arm/mach-integrator/Makefile @@ -4,7 +4,7 @@ # Object file lists. -obj-y := core.o lm.o leds.o +obj-y := core.o lm.o obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h index 4ecff7bff482..5b8ba8247f45 100644 --- a/arch/arm/mach-integrator/cm.h +++ b/arch/arm/mach-integrator/cm.h @@ -11,7 +11,6 @@ void cm_clear_irqs(void); #define CM_CTRL_LED (1 << 0) #define CM_CTRL_nMBDET (1 << 1) #define CM_CTRL_REMAP (1 << 2) -#define CM_CTRL_RESET (1 << 3) /* * Integrator/AP,PP2 specific diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h index ad0ac5547b2c..96c9dc56cabf 100644 --- a/arch/arm/mach-integrator/common.h +++ b/arch/arm/mach-integrator/common.h @@ -4,5 +4,3 @@ extern struct amba_pl010_data ap_uart_data; void integrator_init_early(void); int integrator_init(bool is_cp); void integrator_reserve(void); -void integrator_restart(enum reboot_mode, const char *); -void integrator_init_sysfs(struct device *parent, u32 id); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index e3f3aca43efb..948872a419c1 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set) raw_spin_unlock_irqrestore(&cm_lock, flags); } -static const char *integrator_arch_str(u32 id) -{ - switch ((id >> 16) & 0xff) { - case 0x00: - return "ASB little-endian"; - case 0x01: - return "AHB little-endian"; - case 0x03: - return "AHB-Lite system bus, bi-endian"; - case 0x04: - return "AHB"; - case 0x08: - return "AHB system bus, ASB processor bus"; - default: - return "Unknown"; - } -} - -static const char *integrator_fpga_str(u32 id) -{ - switch ((id >> 12) & 0xf) { - case 0x01: - return "XC4062"; - case 0x02: - return "XC4085"; - case 0x03: - return "XVC600"; - case 0x04: - return "EPM7256AE (Altera PLD)"; - default: - return "Unknown"; - } -} - void cm_clear_irqs(void) { /* disable core module IRQs */ @@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = { void cm_init(void) { struct device_node *cm = of_find_matching_node(NULL, cm_match); - u32 val; if (!cm) { pr_crit("no core module node found in device tree\n"); @@ -121,13 +86,6 @@ void cm_init(void) return; } cm_clear_irqs(); - val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET); - pr_info("Detected ARM core module:\n"); - pr_info(" Manufacturer: %02x\n", (val >> 24)); - pr_info(" Architecture: %s\n", integrator_arch_str(val)); - pr_info(" FPGA: %s\n", integrator_fpga_str(val)); - pr_info(" Build: %02x\n", (val >> 4) & 0xFF); - pr_info(" Rev: %c\n", ('A' + (val & 0x03))); } /* @@ -139,64 +97,3 @@ void __init integrator_reserve(void) { memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); } - -/* - * To reset, we hit the on-board reset register in the system FPGA - */ -void integrator_restart(enum reboot_mode mode, const char *cmd) -{ - cm_control(CM_CTRL_RESET, CM_CTRL_RESET); -} - -static u32 integrator_id; - -static ssize_t intcp_get_manf(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%02x\n", integrator_id >> 24); -} - -static struct device_attribute intcp_manf_attr = - __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL); - -static ssize_t intcp_get_arch(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", integrator_arch_str(integrator_id)); -} - -static struct device_attribute intcp_arch_attr = - __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL); - -static ssize_t intcp_get_fpga(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id)); -} - -static struct device_attribute intcp_fpga_attr = - __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL); - -static ssize_t intcp_get_build(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF); -} - -static struct device_attribute intcp_build_attr = - __ATTR(build, S_IRUGO, intcp_get_build, NULL); - - - -void integrator_init_sysfs(struct device *parent, u32 id) -{ - integrator_id = id; - device_create_file(parent, &intcp_manf_attr); - device_create_file(parent, &intcp_arch_attr); - device_create_file(parent, &intcp_fpga_attr); - device_create_file(parent, &intcp_build_attr); -} diff --git a/arch/arm/mach-integrator/include/mach/uncompress.h b/arch/arm/mach-integrator/include/mach/uncompress.h deleted file mode 100644 index 8f3cc9954c16..000000000000 --- a/arch/arm/mach-integrator/include/mach/uncompress.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * arch/arm/mach-integrator/include/mach/uncompress.h - * - * Copyright (C) 1999 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define AMBA_UART_DR (*(volatile unsigned char *)0x16000000) -#define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008) -#define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c) -#define AMBA_UART_LCRL (*(volatile unsigned char *)0x16000010) -#define AMBA_UART_CR (*(volatile unsigned char *)0x16000014) -#define AMBA_UART_FR (*(volatile unsigned char *)0x16000018) - -/* - * This does not append a newline - */ -static void putc(int c) -{ - while (AMBA_UART_FR & (1 << 5)) - barrier(); - - AMBA_UART_DR = c; -} - -static inline void flush(void) -{ - while (AMBA_UART_FR & (1 << 3)) - barrier(); -} - -/* - * nothing to do - */ -#define arch_decomp_setup() diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 8ca290b479b1..30003ba447a5 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -27,22 +27,15 @@ #include <linux/syscore_ops.h> #include <linux/amba/bus.h> #include <linux/amba/kmi.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <linux/interrupt.h> #include <linux/io.h> #include <linux/irqchip.h> #include <linux/mtd/physmap.h> -#include <linux/clk.h> #include <linux/platform_data/clk-integrator.h> #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/stat.h> -#include <linux/sys_soc.h> #include <linux/termios.h> -#include <linux/sched_clock.h> -#include <linux/clk-provider.h> #include <asm/hardware/arm_timer.h> #include <asm/setup.h> @@ -89,11 +82,6 @@ static void __iomem *ebi_base; static struct map_desc ap_io_desc[] __initdata __maybe_unused = { { - .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE), .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE), .length = SZ_4K, @@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = { .set_mctrl = integrator_uart_set_mctrl, }; -/* - * Where is the timer (VA)? - */ -#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE) -#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE) -#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE) - -static unsigned long timer_reload; - -static u64 notrace integrator_read_sched_clock(void) -{ - return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); -} - -static void integrator_clocksource_init(unsigned long inrate, - void __iomem *base) -{ - u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; - unsigned long rate = inrate; - - if (rate >= 1500000) { - rate /= 16; - ctrl |= TIMER_CTRL_DIV16; - } - - writel(0xffff, base + TIMER_LOAD); - writel(ctrl, base + TIMER_CTRL); - - clocksource_mmio_init(base + TIMER_VALUE, "timer2", - rate, 200, 16, clocksource_mmio_readl_down); - sched_clock_register(integrator_read_sched_clock, 16, rate); -} - -static void __iomem * clkevt_base; - -/* - * IRQ handler for the timer - */ -static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - - /* clear the interrupt */ - writel(1, clkevt_base + TIMER_INTCLR); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) -{ - u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; - - /* Disable timer */ - writel(ctrl, clkevt_base + TIMER_CTRL); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* Enable the timer and start the periodic tick */ - writel(timer_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Leave the timer disabled, .set_next_event will enable it */ - ctrl &= ~TIMER_CTRL_PERIODIC; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - default: - /* Just leave in disabled state */ - break; - } - -} - -static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) -{ - unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); - - writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); - writel(next, clkevt_base + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); - - return 0; -} - -static struct clock_event_device integrator_clockevent = { - .name = "timer1", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = clkevt_set_mode, - .set_next_event = clkevt_set_next_event, - .rating = 300, -}; - -static struct irqaction integrator_timer_irq = { - .name = "timer", - .flags = IRQF_TIMER | IRQF_IRQPOLL, - .handler = integrator_timer_interrupt, - .dev_id = &integrator_clockevent, -}; - -static void integrator_clockevent_init(unsigned long inrate, - void __iomem *base, int irq) -{ - unsigned long rate = inrate; - unsigned int ctrl = 0; - - clkevt_base = base; - /* Calculate and program a divisor */ - if (rate > 0x100000 * HZ) { - rate /= 256; - ctrl |= TIMER_CTRL_DIV256; - } else if (rate > 0x10000 * HZ) { - rate /= 16; - ctrl |= TIMER_CTRL_DIV16; - } - timer_reload = rate / HZ; - writel(ctrl, clkevt_base + TIMER_CTRL); - - setup_irq(irq, &integrator_timer_irq); - clockevents_config_and_register(&integrator_clockevent, - rate, - 1, - 0xffffU); -} - void __init ap_init_early(void) { } -static void __init ap_of_timer_init(void) -{ - struct device_node *node; - const char *path; - void __iomem *base; - int err; - int irq; - struct clk *clk; - unsigned long rate; - - of_clk_init(NULL); - - err = of_property_read_string(of_aliases, - "arm,timer-primary", &path); - if (WARN_ON(err)) - return; - node = of_find_node_by_path(path); - base = of_iomap(node, 0); - if (WARN_ON(!base)) - return; - - clk = of_clk_get(node, 0); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); - - writel(0, base + TIMER_CTRL); - integrator_clocksource_init(rate, base); - - err = of_property_read_string(of_aliases, - "arm,timer-secondary", &path); - if (WARN_ON(err)) - return; - node = of_find_node_by_path(path); - base = of_iomap(node, 0); - if (WARN_ON(!base)) - return; - irq = irq_of_parse_and_map(node, 0); - - clk = of_clk_get(node, 0); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); - - writel(0, base + TIMER_CTRL); - integrator_clockevent_init(rate, base, irq); -} - static void __init ap_init_irq_of(void) { cm_init(); @@ -477,10 +287,6 @@ static void __init ap_init_of(void) unsigned long sc_dec; struct device_node *syscon; struct device_node *ebi; - struct device *parent; - struct soc_device *soc_dev; - struct soc_device_attribute *soc_dev_attr; - u32 ap_sc_id; int i; syscon = of_find_matching_node(NULL, ap_syscon_match); @@ -500,28 +306,6 @@ static void __init ap_init_of(void) of_platform_populate(NULL, of_default_bus_match_table, ap_auxdata_lookup, NULL); - ap_sc_id = readl(ap_syscon_base); - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return; - - soc_dev_attr->soc_id = "XVC"; - soc_dev_attr->machine = "Integrator/AP"; - soc_dev_attr->family = "Integrator"; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", - 'A' + (ap_sc_id & 0x0f)); - - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); - return; - } - - parent = soc_device_to_device(soc_dev); - integrator_init_sysfs(parent, ap_sc_id); - sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET); for (i = 0; i < 4; i++) { struct lm_device *lmdev; @@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)") .map_io = ap_map_io, .init_early = ap_init_early, .init_irq = ap_init_irq_of, - .init_time = ap_of_timer_init, .init_machine = ap_init_of, - .restart = integrator_restart, .dt_compat = ap_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index cca02eb75eb5..b5fb71a36ee6 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -27,7 +27,6 @@ #include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/of_platform.h> -#include <linux/sys_soc.h> #include <linux/sched_clock.h> #include <asm/setup.h> @@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = { static void __init intcp_init_of(void) { struct device_node *cpcon; - struct device *parent; - struct soc_device *soc_dev; - struct soc_device_attribute *soc_dev_attr; - u32 intcp_sc_id; cpcon = of_find_matching_node(NULL, intcp_syscon_match); if (!cpcon) @@ -289,28 +284,6 @@ static void __init intcp_init_of(void) of_platform_populate(NULL, of_default_bus_match_table, intcp_auxdata_lookup, NULL); - - intcp_sc_id = readl(intcp_con_base); - - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); - if (!soc_dev_attr) - return; - - soc_dev_attr->soc_id = "XCV"; - soc_dev_attr->machine = "Integrator/CP"; - soc_dev_attr->family = "Integrator"; - soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c", - 'A' + (intcp_sc_id & 0x0f)); - - soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - kfree(soc_dev_attr->revision); - kfree(soc_dev_attr); - return; - } - - parent = soc_device_to_device(soc_dev); - integrator_init_sysfs(parent, intcp_sc_id); } static const char * intcp_dt_board_compat[] = { @@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)") .init_early = intcp_init_early, .init_irq = intcp_init_irq_of, .init_machine = intcp_init_of, - .restart = integrator_restart, .dt_compat = intcp_dt_board_compat, MACHINE_END diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c deleted file mode 100644 index f1dcb57a59e2..000000000000 --- a/arch/arm/mach-integrator/leds.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard - * Based on Versatile and RealView machine LED code - * - * License terms: GNU General Public License (GPL) version 2 - * Author: Bryan Wu <bryan.wu@canonical.com> - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/leds.h> - -#include "hardware.h" -#include "cm.h" - -#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS) - -#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE) -#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET) - -struct integrator_led { - struct led_classdev cdev; - u8 mask; -}; - -/* - * The triggers lines up below will only be used if the - * LED triggers are compiled in. - */ -static const struct { - const char *name; - const char *trigger; -} integrator_leds[] = { - { "integrator:green0", "heartbeat", }, - { "integrator:yellow", }, - { "integrator:red", }, - { "integrator:green1", }, - { "integrator:core_module", "cpu0", }, -}; - -static void integrator_led_set(struct led_classdev *cdev, - enum led_brightness b) -{ - struct integrator_led *led = container_of(cdev, - struct integrator_led, cdev); - u32 reg = __raw_readl(LEDREG); - - if (b != LED_OFF) - reg |= led->mask; - else - reg &= ~led->mask; - - while (__raw_readl(ALPHA_REG) & 1) - cpu_relax(); - - __raw_writel(reg, LEDREG); -} - -static enum led_brightness integrator_led_get(struct led_classdev *cdev) -{ - struct integrator_led *led = container_of(cdev, - struct integrator_led, cdev); - u32 reg = __raw_readl(LEDREG); - - return (reg & led->mask) ? LED_FULL : LED_OFF; -} - -static void cm_led_set(struct led_classdev *cdev, - enum led_brightness b) -{ - if (b != LED_OFF) - cm_control(CM_CTRL_LED, CM_CTRL_LED); - else - cm_control(CM_CTRL_LED, 0); -} - -static enum led_brightness cm_led_get(struct led_classdev *cdev) -{ - u32 reg = cm_get(); - - return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF; -} - -static int __init integrator_leds_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) { - struct integrator_led *led; - - led = kzalloc(sizeof(*led), GFP_KERNEL); - if (!led) - break; - - - led->cdev.name = integrator_leds[i].name; - - if (i == 4) { /* Setting for LED in core module */ - led->cdev.brightness_set = cm_led_set; - led->cdev.brightness_get = cm_led_get; - } else { - led->cdev.brightness_set = integrator_led_set; - led->cdev.brightness_get = integrator_led_get; - } - - led->cdev.default_trigger = integrator_leds[i].trigger; - led->mask = BIT(i); - - if (led_classdev_register(NULL, &led->cdev) < 0) { - kfree(led); - break; - } - } - - return 0; -} - -/* - * Since we may have triggers on any subsystem, defer registration - * until after subsystem_init. - */ -fs_initcall(integrator_leds_init); -#endif diff --git a/arch/arm/mach-ixp4xx/include/mach/io.h b/arch/arm/mach-ixp4xx/include/mach/io.h index 559c69a47731..7d11979da030 100644 --- a/arch/arm/mach-ixp4xx/include/mach/io.h +++ b/arch/arm/mach-ixp4xx/include/mach/io.h @@ -76,7 +76,7 @@ static inline void __indirect_writeb(u8 value, volatile void __iomem *p) u32 n, byte_enables, data; if (!is_pci_memory(addr)) { - __raw_writeb(value, addr); + __raw_writeb(value, p); return; } @@ -141,7 +141,7 @@ static inline unsigned char __indirect_readb(const volatile void __iomem *p) u32 n, byte_enables, data; if (!is_pci_memory(addr)) - return __raw_readb(addr); + return __raw_readb(p); n = addr % 4; byte_enables = (0xf & ~BIT(n)) << IXP4XX_PCI_NP_CBE_BESL; diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig index 2c043a210db0..f73f588f649c 100644 --- a/arch/arm/mach-mediatek/Kconfig +++ b/arch/arm/mach-mediatek/Kconfig @@ -1,6 +1,6 @@ config ARCH_MEDIATEK - bool "Mediatek MT6589 SoC" if ARCH_MULTI_V7 + bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7 select ARM_GIC select MTK_TIMER help - Support for Mediatek Cortex-A7 Quad-Core-SoC MT6589. + Support for Mediatek MT65xx & MT81xx SoCs diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig index 2c1154e1794a..18301dc9d2e7 100644 --- a/arch/arm/mach-meson/Kconfig +++ b/arch/arm/mach-meson/Kconfig @@ -2,6 +2,7 @@ menuconfig ARCH_MESON bool "Amlogic Meson SoCs" if ARCH_MULTI_V7 select GENERIC_IRQ_CHIP select ARM_GIC + select CACHE_L2X0 if ARCH_MESON @@ -10,4 +11,9 @@ config MACH_MESON6 default ARCH_MESON select MESON6_TIMER +config MACH_MESON8 + bool "Amlogic Meson8 SoCs support" + default ARCH_MESON + select MESON6_TIMER + endif diff --git a/arch/arm/mach-meson/meson.c b/arch/arm/mach-meson/meson.c index 5ee064f5a89f..5d6affe6a694 100644 --- a/arch/arm/mach-meson/meson.c +++ b/arch/arm/mach-meson/meson.c @@ -16,12 +16,14 @@ #include <linux/of_platform.h> #include <asm/mach/arch.h> -static const char * const m6_common_board_compat[] = { +static const char * const meson_common_board_compat[] = { "amlogic,meson6", + "amlogic,meson8", NULL, }; -DT_MACHINE_START(AML8726_MX, "Amlogic Meson6 platform") - .dt_compat = m6_common_board_compat, +DT_MACHINE_START(MESON, "Amlogic Meson platform") + .dt_compat = meson_common_board_compat, + .l2c_aux_val = 0, + .l2c_aux_mask = ~0, MACHINE_END - diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index e24136b42765..b4f01497ce0b 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o ifeq ($(CONFIG_MACH_MVEBU_V7),y) -obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o +obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o pm-board.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o endif diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index 84cd90d9b860..c55bbf81de0e 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h @@ -16,14 +16,8 @@ #define __MACH_ARMADA_370_XP_H #ifdef CONFIG_SMP -#include <linux/cpumask.h> - -#define ARMADA_XP_MAX_CPUS 4 - void armada_xp_secondary_startup(void); extern struct smp_operations armada_xp_smp_ops; #endif -int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); - #endif /* __MACH_ARMADA_370_XP_H */ diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 6478626e3ff6..89a139ed7d5b 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -16,10 +16,12 @@ #include <linux/init.h> #include <linux/clk-provider.h> #include <linux/of_address.h> +#include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/io.h> #include <linux/clocksource.h> #include <linux/dma-mapping.h> +#include <linux/memblock.h> #include <linux/mbus.h> #include <linux/signal.h> #include <linux/slab.h> @@ -57,6 +59,54 @@ void __iomem *mvebu_get_scu_base(void) } /* + * When returning from suspend, the platform goes through the + * bootloader, which executes its DDR3 training code. This code has + * the unfortunate idea of using the first 10 KB of each DRAM bank to + * exercise the RAM and calculate the optimal timings. Therefore, this + * area of RAM is overwritten, and shouldn't be used by the kernel if + * suspend/resume is supported. + */ + +#ifdef CONFIG_SUSPEND +#define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K) +static int __init mvebu_scan_mem(unsigned long node, const char *uname, + int depth, void *data) +{ + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + const __be32 *reg, *endp; + int l; + + if (type == NULL || strcmp(type, "memory")) + return 0; + + reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l); + if (reg == NULL) + reg = of_get_flat_dt_prop(node, "reg", &l); + if (reg == NULL) + return 0; + + endp = reg + (l / sizeof(__be32)); + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + u64 base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + + memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ); + } + + return 0; +} + +static void __init mvebu_memblock_reserve(void) +{ + of_scan_flat_dt(mvebu_scan_mem, NULL); +} +#else +static void __init mvebu_memblock_reserve(void) {} +#endif + +/* * Early versions of Armada 375 SoC have a bug where the BootROM * leaves an external data abort pending. The kernel is hit by this * data abort as soon as it enters userspace, because it unmasks the @@ -124,76 +174,12 @@ static void __init i2c_quirk(void) return; } -#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc - -static void __init thermal_quirk(void) -{ - struct device_node *np; - u32 dev, rev; - int res; - - /* - * The early SoC Z1 revision needs a quirk to be applied in order - * for the thermal controller to work properly. This quirk breaks - * the thermal support if applied on a SoC that doesn't need it, - * so we enforce the SoC revision to be known. - */ - res = mvebu_get_soc_id(&dev, &rev); - if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV)) - return; - - for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { - struct property *prop; - __be32 newval, *newprop, *oldprop; - int len; - - /* - * The register offset is at a wrong location. This quirk - * creates a new reg property as a clone of the previous - * one and corrects the offset. - */ - oldprop = (__be32 *)of_get_property(np, "reg", &len); - if (!oldprop) - continue; - - /* Create a duplicate of the 'reg' property */ - prop = kzalloc(sizeof(*prop), GFP_KERNEL); - prop->length = len; - prop->name = kstrdup("reg", GFP_KERNEL); - prop->value = kzalloc(len, GFP_KERNEL); - memcpy(prop->value, oldprop, len); - - /* Fixup the register offset of the second entry */ - oldprop += 2; - newprop = (__be32 *)prop->value + 2; - newval = cpu_to_be32(be32_to_cpu(*oldprop) - - A375_Z1_THERMAL_FIXUP_OFFSET); - *newprop = newval; - of_update_property(np, prop); - - /* - * The thermal controller needs some quirk too, so let's change - * the compatible string to reflect this and allow the driver - * the take the necessary action. - */ - prop = kzalloc(sizeof(*prop), GFP_KERNEL); - prop->name = kstrdup("compatible", GFP_KERNEL); - prop->length = sizeof("marvell,armada375-z1-thermal"); - prop->value = kstrdup("marvell,armada375-z1-thermal", - GFP_KERNEL); - of_update_property(np, prop); - } - return; -} - static void __init mvebu_dt_init(void) { - if (of_machine_is_compatible("plathome,openblocks-ax3-4")) + if (of_machine_is_compatible("marvell,armadaxp")) i2c_quirk(); - if (of_machine_is_compatible("marvell,a375-db")) { + if (of_machine_is_compatible("marvell,a375-db")) external_abort_quirk(); - thermal_quirk(); - } of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } @@ -206,10 +192,16 @@ static const char * const armada_370_xp_dt_compat[] = { DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, +/* + * The following field (.smp) is still needed to ensure backward + * compatibility with old Device Trees that were not specifying the + * cpus enable-method property. + */ .smp = smp_ops(armada_xp_smp_ops), .init_machine = mvebu_dt_init, .init_irq = mvebu_init_irq, .restart = mvebu_restart, + .reserve = mvebu_memblock_reserve, .dt_compat = armada_370_xp_dt_compat, MACHINE_END diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 2bdc3233abe2..3585cb394e9b 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -1,5 +1,6 @@ /* - * Coherency fabric (Aurora) support for Armada 370 and XP platforms. + * Coherency fabric (Aurora) support for Armada 370, 375, 38x and XP + * platforms. * * Copyright (C) 2012 Marvell * @@ -11,7 +12,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. * - * The Armada 370 and Armada XP SOCs have a coherency fabric which is + * The Armada 370, 375, 38x and XP SOCs have a coherency fabric which is * responsible for ensuring hardware coherency between all CPUs and between * CPUs and I/O masters. This file initializes the coherency fabric and * supplies basic routines for configuring and controlling hardware coherency @@ -28,12 +29,10 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/mbus.h> -#include <linux/clk.h> #include <linux/pci.h> #include <asm/smp_plat.h> #include <asm/cacheflush.h> #include <asm/mach/map.h> -#include "armada-370-xp.h" #include "coherency.h" #include "mvebu-soc-id.h" @@ -42,8 +41,6 @@ void __iomem *coherency_base; static void __iomem *coherency_cpu_base; /* Coherency fabric registers */ -#define COHERENCY_FABRIC_CFG_OFFSET 0x4 - #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 enum { @@ -79,157 +76,8 @@ int set_cpu_coherent(void) return ll_enable_coherency(); } -/* - * The below code implements the I/O coherency workaround on Armada - * 375. This workaround consists in using the two channels of the - * first XOR engine to trigger a XOR transaction that serves as the - * I/O coherency barrier. - */ - -static void __iomem *xor_base, *xor_high_base; -static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS]; -static void *coherency_wa_buf[CONFIG_NR_CPUS]; -static bool coherency_wa_enabled; - -#define XOR_CONFIG(chan) (0x10 + (chan * 4)) -#define XOR_ACTIVATION(chan) (0x20 + (chan * 4)) -#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) -#define WINDOW_BASE(w) (0x250 + ((w) << 2)) -#define WINDOW_SIZE(w) (0x270 + ((w) << 2)) -#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) -#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2)) -#define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4)) -#define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4)) -#define XOR_INIT_VALUE_LOW 0x2E0 -#define XOR_INIT_VALUE_HIGH 0x2E4 - -static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void) -{ - int idx = smp_processor_id(); - - /* Write '1' to the first word of the buffer */ - writel(0x1, coherency_wa_buf[idx]); - - /* Wait until the engine is idle */ - while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3) - ; - - dmb(); - - /* Trigger channel */ - writel(0x1, xor_base + XOR_ACTIVATION(idx)); - - /* Poll the data until it is cleared by the XOR transaction */ - while (readl(coherency_wa_buf[idx])) - ; -} - -static void __init armada_375_coherency_init_wa(void) -{ - const struct mbus_dram_target_info *dram; - struct device_node *xor_node; - struct property *xor_status; - struct clk *xor_clk; - u32 win_enable = 0; - int i; - - pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n"); - - /* - * Since the workaround uses one XOR engine, we grab a - * reference to its Device Tree node first. - */ - xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor"); - BUG_ON(!xor_node); - - /* - * Then we mark it as disabled so that the real XOR driver - * will not use it. - */ - xor_status = kzalloc(sizeof(struct property), GFP_KERNEL); - BUG_ON(!xor_status); - - xor_status->value = kstrdup("disabled", GFP_KERNEL); - BUG_ON(!xor_status->value); - - xor_status->length = 8; - xor_status->name = kstrdup("status", GFP_KERNEL); - BUG_ON(!xor_status->name); - - of_update_property(xor_node, xor_status); - - /* - * And we remap the registers, get the clock, and do the - * initial configuration of the XOR engine. - */ - xor_base = of_iomap(xor_node, 0); - xor_high_base = of_iomap(xor_node, 1); - - xor_clk = of_clk_get_by_name(xor_node, NULL); - BUG_ON(!xor_clk); - - clk_prepare_enable(xor_clk); - - dram = mv_mbus_dram_info(); - - for (i = 0; i < 8; i++) { - writel(0, xor_base + WINDOW_BASE(i)); - writel(0, xor_base + WINDOW_SIZE(i)); - if (i < 4) - writel(0, xor_base + WINDOW_REMAP_HIGH(i)); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - writel((cs->base & 0xffff0000) | - (cs->mbus_attr << 8) | - dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i)); - writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i)); - - win_enable |= (1 << i); - win_enable |= 3 << (16 + (2 * i)); - } - - writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0)); - writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1)); - writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0)); - writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1)); - - for (i = 0; i < CONFIG_NR_CPUS; i++) { - coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL); - BUG_ON(!coherency_wa_buf[i]); - - /* - * We can't use the DMA mapping API, since we don't - * have a valid 'struct device' pointer - */ - coherency_wa_buf_phys[i] = - virt_to_phys(coherency_wa_buf[i]); - BUG_ON(!coherency_wa_buf_phys[i]); - - /* - * Configure the XOR engine for memset operation, with - * a 128 bytes block size - */ - writel(0x444, xor_base + XOR_CONFIG(i)); - writel(128, xor_base + XOR_BLOCK_SIZE(i)); - writel(coherency_wa_buf_phys[i], - xor_base + XOR_DEST_POINTER(i)); - } - - writel(0x0, xor_base + XOR_INIT_VALUE_LOW); - writel(0x0, xor_base + XOR_INIT_VALUE_HIGH); - - coherency_wa_enabled = true; -} - static inline void mvebu_hwcc_sync_io_barrier(void) { - if (coherency_wa_enabled) { - mvebu_hwcc_armada375_sync_io_barrier_wa(); - return; - } - writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); } @@ -361,25 +209,41 @@ static int coherency_type(void) { struct device_node *np; const struct of_device_id *match; + int type; - np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); - if (np) { - int type = (int) match->data; + /* + * The coherency fabric is needed: + * - For coherency between processors on Armada XP, so only + * when SMP is enabled. + * - For coherency between the processor and I/O devices, but + * this coherency requires many pre-requisites (write + * allocate cache policy, shareable pages, SMP bit set) that + * are only meant in SMP situations. + * + * Note that this means that on Armada 370, there is currently + * no way to use hardware I/O coherency, because even when + * CONFIG_SMP is enabled, is_smp() returns false due to the + * Armada 370 being a single-core processor. To lift this + * limitation, we would have to find a way to make the cache + * policy set to write-allocate (on all Armada SoCs), and to + * set the shareable attribute in page tables (on all Armada + * SoCs except the Armada 370). Unfortunately, such decisions + * are taken very early in the kernel boot process, at a point + * where we don't know yet on which SoC we are running. - /* Armada 370/XP coherency works in both UP and SMP */ - if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) - return type; + */ + if (!is_smp()) + return COHERENCY_FABRIC_TYPE_NONE; - /* Armada 375 coherency works only on SMP */ - else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp()) - return type; + np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); + if (!np) + return COHERENCY_FABRIC_TYPE_NONE; - /* Armada 380 coherency works only on SMP */ - else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp()) - return type; - } + type = (int) match->data; - return COHERENCY_FABRIC_TYPE_NONE; + of_node_put(np); + + return type; } int coherency_available(void) @@ -400,27 +264,16 @@ int __init coherency_init(void) type == COHERENCY_FABRIC_TYPE_ARMADA_380) armada_375_380_coherency_init(np); + of_node_put(np); + return 0; } static int __init coherency_late_init(void) { - int type = coherency_type(); - - if (type == COHERENCY_FABRIC_TYPE_NONE) - return 0; - - if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) { - u32 dev, rev; - - if (mvebu_get_soc_id(&dev, &rev) == 0 && - rev == ARMADA_375_Z1_REV) - armada_375_coherency_init_wa(); - } - - bus_register_notifier(&platform_bus_type, - &mvebu_hwcc_nb); - + if (coherency_available()) + bus_register_notifier(&platform_bus_type, + &mvebu_hwcc_nb); return 0; } diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S index f5d881b5d0f7..8b2fbc8b6bc6 100644 --- a/arch/arm/mach-mvebu/coherency_ll.S +++ b/arch/arm/mach-mvebu/coherency_ll.S @@ -24,7 +24,10 @@ #include <asm/cp15.h> .text -/* Returns the coherency base address in r1 (r0 is untouched) */ +/* + * Returns the coherency base address in r1 (r0 is untouched), or 0 if + * the coherency fabric is not enabled. + */ ENTRY(ll_get_coherency_base) mrc p15, 0, r1, c1, c0, 0 tst r1, #CR_M @ Check MMU bit enabled @@ -32,8 +35,13 @@ ENTRY(ll_get_coherency_base) /* * MMU is disabled, use the physical address of the coherency - * base address. + * base address. However, if the coherency fabric isn't mapped + * (i.e its virtual address is zero), it means coherency is + * not enabled, so we return 0. */ + ldr r1, =coherency_base + cmp r1, #0 + beq 2f adr r1, 3f ldr r3, [r1] ldr r1, [r1, r3] @@ -85,6 +93,9 @@ ENTRY(ll_add_cpu_to_smp_group) */ mov r0, lr bl ll_get_coherency_base + /* Bail out if the coherency is not enabled */ + cmp r1, #0 + reteq r0 bl ll_get_coherency_cpumask mov lr, r0 add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET @@ -107,6 +118,9 @@ ENTRY(ll_enable_coherency) */ mov r0, lr bl ll_get_coherency_base + /* Bail out if the coherency is not enabled */ + cmp r1, #0 + reteq r0 bl ll_get_coherency_cpumask mov lr, r0 add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET @@ -131,6 +145,9 @@ ENTRY(ll_disable_coherency) */ mov r0, lr bl ll_get_coherency_base + /* Bail out if the coherency is not enabled */ + cmp r1, #0 + reteq r0 bl ll_get_coherency_cpumask mov lr, r0 add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 3ccb40c3bf94..3e0aca1f288a 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -25,4 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); void __iomem *mvebu_get_scu_base(void); +int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)); + #endif diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c index 60fb53787004..4a2cadd6b48e 100644 --- a/arch/arm/mach-mvebu/cpu-reset.c +++ b/arch/arm/mach-mvebu/cpu-reset.c @@ -15,7 +15,6 @@ #include <linux/of_address.h> #include <linux/io.h> #include <linux/resource.h> -#include "armada-370-xp.h" static void __iomem *cpu_reset_base; static size_t cpu_reset_size; diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S index be51c998c0cd..08d5ed46b996 100644 --- a/arch/arm/mach-mvebu/headsmp-a9.S +++ b/arch/arm/mach-mvebu/headsmp-a9.S @@ -22,5 +22,6 @@ ENTRY(mvebu_cortex_a9_secondary_startup) ARM_BE8(setend be) bl v7_invalidate_l1 + bl armada_38x_scu_power_up b secondary_startup ENDPROC(mvebu_cortex_a9_secondary_startup) diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index 47a71a924b96..2ec1a42b4321 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -43,21 +43,70 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, else mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); smp_wmb(); + + /* + * Doing this before deasserting the CPUs is needed to wake up CPUs + * in the offline state after using CPU hotplug. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + ret = mvebu_cpu_reset_deassert(hw_cpu); if (ret) { pr_err("Could not start the secondary CPU: %d\n", ret); return ret; } - arch_send_wakeup_ipi_mask(cpumask_of(cpu)); return 0; } +/* + * When a CPU is brought back online, either through CPU hotplug, or + * because of the boot of a kexec'ed kernel, the PMSU configuration + * for this CPU might be in the deep idle state, preventing this CPU + * from receiving interrupts. Here, we therefore take out the current + * CPU from this state, which was entered by armada_38x_cpu_die() + * below. + */ +static void armada_38x_secondary_init(unsigned int cpu) +{ + mvebu_v7_pmsu_idle_exit(); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void armada_38x_cpu_die(unsigned int cpu) +{ + /* + * CPU hotplug is implemented by putting offline CPUs into the + * deep idle sleep state. + */ + armada_38x_do_cpu_suspend(true); +} + +/* + * We need a dummy function, so that platform_can_cpu_hotplug() knows + * we support CPU hotplug. However, the function does not need to do + * anything, because CPUs going offline can enter the deep idle state + * by themselves, without any help from a still alive CPU. + */ +static int armada_38x_cpu_kill(unsigned int cpu) +{ + return 1; +} +#endif static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, }; +static struct smp_operations armada_38x_smp_ops __initdata = { + .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, + .smp_secondary_init = armada_38x_secondary_init, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = armada_38x_cpu_die, + .cpu_kill = armada_38x_cpu_kill, +#endif +}; + CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", &mvebu_cortex_a9_smp_ops); CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", - &mvebu_cortex_a9_smp_ops); + &armada_38x_smp_ops); diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index 895dc373c8a1..58cc8c1575eb 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -30,10 +30,12 @@ #include "pmsu.h" #include "coherency.h" +#define ARMADA_XP_MAX_CPUS 4 + #define AXP_BOOTROM_BASE 0xfff00000 #define AXP_BOOTROM_SIZE 0x100000 -static struct clk *__init get_cpu_clk(int cpu) +static struct clk *get_cpu_clk(int cpu) { struct clk *cpu_clk; struct device_node *np = of_get_cpu_node(cpu, NULL); @@ -46,29 +48,28 @@ static struct clk *__init get_cpu_clk(int cpu) return cpu_clk; } -static void __init set_secondary_cpus_clock(void) +static void set_secondary_cpu_clock(unsigned int cpu) { - int thiscpu, cpu; + int thiscpu; unsigned long rate; struct clk *cpu_clk; - thiscpu = smp_processor_id(); + thiscpu = get_cpu(); + cpu_clk = get_cpu_clk(thiscpu); if (!cpu_clk) - return; + goto out; clk_prepare_enable(cpu_clk); rate = clk_get_rate(cpu_clk); - /* set all the other CPU clk to the same rate than the boot CPU */ - for_each_possible_cpu(cpu) { - if (cpu == thiscpu) - continue; - cpu_clk = get_cpu_clk(cpu); - if (!cpu_clk) - return; - clk_set_rate(cpu_clk, rate); - clk_prepare_enable(cpu_clk); - } + cpu_clk = get_cpu_clk(cpu); + if (!cpu_clk) + goto out; + clk_set_rate(cpu_clk, rate); + clk_prepare_enable(cpu_clk); + +out: + put_cpu(); } static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) @@ -78,6 +79,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) pr_info("Booting CPU %d\n", cpu); hw_cpu = cpu_logical_map(cpu); + set_secondary_cpu_clock(hw_cpu); mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup); /* @@ -126,7 +128,6 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) struct resource res; int err; - set_secondary_cpus_clock(); flush_cache_all(); set_cpu_coherent(); diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c new file mode 100644 index 000000000000..6dfd4ab97b2a --- /dev/null +++ b/arch/arm/mach-mvebu/pm-board.c @@ -0,0 +1,141 @@ +/* + * Board-level suspend/resume support. + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> +#include "common.h" + +#define ARMADA_XP_GP_PIC_NR_GPIOS 3 + +static void __iomem *gpio_ctrl; +static int pic_gpios[ARMADA_XP_GP_PIC_NR_GPIOS]; +static int pic_raw_gpios[ARMADA_XP_GP_PIC_NR_GPIOS]; + +static void mvebu_armada_xp_gp_pm_enter(void __iomem *sdram_reg, u32 srcmd) +{ + u32 reg, ackcmd; + int i; + + /* Put 001 as value on the GPIOs */ + reg = readl(gpio_ctrl); + for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) + reg &= ~BIT(pic_raw_gpios[i]); + reg |= BIT(pic_raw_gpios[0]); + writel(reg, gpio_ctrl); + + /* Prepare writing 111 to the GPIOs */ + ackcmd = readl(gpio_ctrl); + for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) + ackcmd |= BIT(pic_raw_gpios[i]); + + /* + * Wait a while, the PIC needs quite a bit of time between the + * two GPIO commands. + */ + mdelay(3000); + + asm volatile ( + /* Align to a cache line */ + ".balign 32\n\t" + + /* Enter self refresh */ + "str %[srcmd], [%[sdram_reg]]\n\t" + + /* + * Wait 100 cycles for DDR to enter self refresh, by + * doing 50 times two instructions. + */ + "mov r1, #50\n\t" + "1: subs r1, r1, #1\n\t" + "bne 1b\n\t" + + /* Issue the command ACK */ + "str %[ackcmd], [%[gpio_ctrl]]\n\t" + + /* Trap the processor */ + "b .\n\t" + : : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg), + [ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1"); +} + +static int mvebu_armada_xp_gp_pm_init(void) +{ + struct device_node *np; + struct device_node *gpio_ctrl_np; + int ret = 0, i; + + if (!of_machine_is_compatible("marvell,axp-gp")) + return -ENODEV; + + np = of_find_node_by_name(NULL, "pm_pic"); + if (!np) + return -ENODEV; + + for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) { + char *name; + struct of_phandle_args args; + + pic_gpios[i] = of_get_named_gpio(np, "ctrl-gpios", i); + if (pic_gpios[i] < 0) { + ret = -ENODEV; + goto out; + } + + name = kasprintf(GFP_KERNEL, "pic-pin%d", i); + if (!name) { + ret = -ENOMEM; + goto out; + } + + ret = gpio_request(pic_gpios[i], name); + if (ret < 0) { + kfree(name); + goto out; + } + + ret = gpio_direction_output(pic_gpios[i], 0); + if (ret < 0) { + gpio_free(pic_gpios[i]); + kfree(name); + goto out; + } + + ret = of_parse_phandle_with_fixed_args(np, "ctrl-gpios", 2, + i, &args); + if (ret < 0) { + gpio_free(pic_gpios[i]); + kfree(name); + goto out; + } + + gpio_ctrl_np = args.np; + pic_raw_gpios[i] = args.args[0]; + } + + gpio_ctrl = of_iomap(gpio_ctrl_np, 0); + if (!gpio_ctrl) + return -ENOMEM; + + mvebu_pm_init(mvebu_armada_xp_gp_pm_enter); + +out: + of_node_put(np); + return ret; +} + +late_initcall(mvebu_armada_xp_gp_pm_init); diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c new file mode 100644 index 000000000000..6573a8f11f70 --- /dev/null +++ b/arch/arm/mach-mvebu/pm.c @@ -0,0 +1,218 @@ +/* + * Suspend/resume support. Currently supporting Armada XP only. + * + * Copyright (C) 2014 Marvell + * + * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/cpu_pm.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mbus.h> +#include <linux/of_address.h> +#include <linux/suspend.h> +#include <asm/cacheflush.h> +#include <asm/outercache.h> +#include <asm/suspend.h> + +#include "coherency.h" +#include "pmsu.h" + +#define SDRAM_CONFIG_OFFS 0x0 +#define SDRAM_CONFIG_SR_MODE_BIT BIT(24) +#define SDRAM_OPERATION_OFFS 0x18 +#define SDRAM_OPERATION_SELF_REFRESH 0x7 +#define SDRAM_DLB_EVICTION_OFFS 0x30c +#define SDRAM_DLB_EVICTION_THRESHOLD_MASK 0xff + +static void (*mvebu_board_pm_enter)(void __iomem *sdram_reg, u32 srcmd); +static void __iomem *sdram_ctrl; + +static int mvebu_pm_powerdown(unsigned long data) +{ + u32 reg, srcmd; + + flush_cache_all(); + outer_flush_all(); + + /* + * Issue a Data Synchronization Barrier instruction to ensure + * that all state saving has been completed. + */ + dsb(); + + /* Flush the DLB and wait ~7 usec */ + reg = readl(sdram_ctrl + SDRAM_DLB_EVICTION_OFFS); + reg &= ~SDRAM_DLB_EVICTION_THRESHOLD_MASK; + writel(reg, sdram_ctrl + SDRAM_DLB_EVICTION_OFFS); + + udelay(7); + + /* Set DRAM in battery backup mode */ + reg = readl(sdram_ctrl + SDRAM_CONFIG_OFFS); + reg &= ~SDRAM_CONFIG_SR_MODE_BIT; + writel(reg, sdram_ctrl + SDRAM_CONFIG_OFFS); + + /* Prepare to go to self-refresh */ + + srcmd = readl(sdram_ctrl + SDRAM_OPERATION_OFFS); + srcmd &= ~0x1F; + srcmd |= SDRAM_OPERATION_SELF_REFRESH; + + mvebu_board_pm_enter(sdram_ctrl + SDRAM_OPERATION_OFFS, srcmd); + + return 0; +} + +#define BOOT_INFO_ADDR 0x3000 +#define BOOT_MAGIC_WORD 0xdeadb002 +#define BOOT_MAGIC_LIST_END 0xffffffff + +/* + * Those registers are accessed before switching the internal register + * base, which is why we hardcode the 0xd0000000 base address, the one + * used by the SoC out of reset. + */ +#define MBUS_WINDOW_12_CTRL 0xd00200b0 +#define MBUS_INTERNAL_REG_ADDRESS 0xd0020080 + +#define SDRAM_WIN_BASE_REG(x) (0x20180 + (0x8*x)) +#define SDRAM_WIN_CTRL_REG(x) (0x20184 + (0x8*x)) + +static phys_addr_t mvebu_internal_reg_base(void) +{ + struct device_node *np; + __be32 in_addr[2]; + + np = of_find_node_by_name(NULL, "internal-regs"); + BUG_ON(!np); + + /* + * Ask the DT what is the internal register address on this + * platform. In the mvebu-mbus DT binding, 0xf0010000 + * corresponds to the internal register window. + */ + in_addr[0] = cpu_to_be32(0xf0010000); + in_addr[1] = 0x0; + + return of_translate_address(np, in_addr); +} + +static void mvebu_pm_store_bootinfo(void) +{ + u32 *store_addr; + phys_addr_t resume_pc; + + store_addr = phys_to_virt(BOOT_INFO_ADDR); + resume_pc = virt_to_phys(armada_370_xp_cpu_resume); + + /* + * The bootloader expects the first two words to be a magic + * value (BOOT_MAGIC_WORD), followed by the address of the + * resume code to jump to. Then, it expects a sequence of + * (address, value) pairs, which can be used to restore the + * value of certain registers. This sequence must end with the + * BOOT_MAGIC_LIST_END magic value. + */ + + writel(BOOT_MAGIC_WORD, store_addr++); + writel(resume_pc, store_addr++); + + /* + * Some platforms remap their internal register base address + * to 0xf1000000. However, out of reset, window 12 starts at + * 0xf0000000 and ends at 0xf7ffffff, which would overlap with + * the internal registers. Therefore, disable window 12. + */ + writel(MBUS_WINDOW_12_CTRL, store_addr++); + writel(0x0, store_addr++); + + /* + * Set the internal register base address to the value + * expected by Linux, as read from the Device Tree. + */ + writel(MBUS_INTERNAL_REG_ADDRESS, store_addr++); + writel(mvebu_internal_reg_base(), store_addr++); + + /* + * Ask the mvebu-mbus driver to store the SDRAM window + * configuration, which has to be restored by the bootloader + * before re-entering the kernel on resume. + */ + store_addr += mvebu_mbus_save_cpu_target(store_addr); + + writel(BOOT_MAGIC_LIST_END, store_addr); +} + +static int mvebu_pm_enter(suspend_state_t state) +{ + if (state != PM_SUSPEND_MEM) + return -EINVAL; + + cpu_pm_enter(); + + mvebu_pm_store_bootinfo(); + cpu_suspend(0, mvebu_pm_powerdown); + + outer_resume(); + + mvebu_v7_pmsu_idle_exit(); + + set_cpu_coherent(); + + cpu_pm_exit(); + + return 0; +} + +static const struct platform_suspend_ops mvebu_pm_ops = { + .enter = mvebu_pm_enter, + .valid = suspend_valid_only_mem, +}; + +int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)) +{ + struct device_node *np; + struct resource res; + + if (!of_machine_is_compatible("marvell,armadaxp")) + return -ENODEV; + + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-xp-sdram-controller"); + if (!np) + return -ENODEV; + + if (of_address_to_resource(np, 0, &res)) { + of_node_put(np); + return -ENODEV; + } + + if (!request_mem_region(res.start, resource_size(&res), + np->full_name)) { + of_node_put(np); + return -EBUSY; + } + + sdram_ctrl = ioremap(res.start, resource_size(&res)); + if (!sdram_ctrl) { + release_mem_region(res.start, resource_size(&res)); + of_node_put(np); + return -ENOMEM; + } + + of_node_put(np); + + mvebu_board_pm_enter = board_pm_enter; + + suspend_set_ops(&mvebu_pm_ops); + + return 0; +} diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index bbd8664d1bac..d8ab605a44fa 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -20,6 +20,7 @@ #include <linux/clk.h> #include <linux/cpu_pm.h> +#include <linux/cpufreq-dt.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/io.h> @@ -39,7 +40,6 @@ #include <asm/suspend.h> #include <asm/tlbflush.h> #include "common.h" -#include "armada-370-xp.h" #define PMSU_BASE_OFFSET 0x100 @@ -312,7 +312,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); } -static int armada_38x_do_cpu_suspend(unsigned long deepidle) +int armada_38x_do_cpu_suspend(unsigned long deepidle) { unsigned long flags = 0; @@ -572,6 +572,10 @@ int mvebu_pmsu_dfs_request(int cpu) return 0; } +struct cpufreq_dt_platform_data cpufreq_dt_pd = { + .independent_clocks = true, +}; + static int __init armada_xp_pmsu_cpufreq_init(void) { struct device_node *np; @@ -644,7 +648,8 @@ static int __init armada_xp_pmsu_cpufreq_init(void) } } - platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + platform_device_register_data(NULL, "cpufreq-dt", -1, + &cpufreq_dt_pd, sizeof(cpufreq_dt_pd)); return 0; } diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index 6b58c1fe2b0d..ea79269c2702 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -17,5 +17,8 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, phys_addr_t resume_addr_reg); void mvebu_v7_pmsu_idle_exit(void); +void armada_370_xp_cpu_resume(void); +int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); +int armada_38x_do_cpu_suspend(unsigned long deepidle); #endif /* __MACH_370_XP_PMSU_H */ diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index a945756cfb45..88651221dbdd 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -12,12 +12,32 @@ #include <linux/linkage.h> #include <asm/assembler.h> + +ENTRY(armada_38x_scu_power_up) + mrc p15, 4, r1, c15, c0 @ get SCU base address + orr r1, r1, #0x8 @ SCU CPU Power Status Register + mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID + and r0, r0, #15 + add r1, r1, r0 + mov r0, #0x0 + strb r0, [r1] @ switch SCU power state to Normal mode + ret lr +ENDPROC(armada_38x_scu_power_up) + /* * This is the entry point through which CPUs exiting cpuidle deep * idle state are going. */ ENTRY(armada_370_xp_cpu_resume) ARM_BE8(setend be ) @ go BE8 if entered LE + /* + * Disable the MMU that might have been enabled in BootROM if + * this code is used in the resume path of a suspend/resume + * cycle. + */ + mrc p15, 0, r1, c1, c0, 0 + bic r1, #1 + mcr p15, 0, r1, c1, c0, 0 bl ll_add_cpu_to_smp_group bl ll_enable_coherency b cpu_resume @@ -27,13 +47,7 @@ ENTRY(armada_38x_cpu_resume) /* do we need it for Armada 38x*/ ARM_BE8(setend be ) @ go BE8 if entered LE bl v7_invalidate_l1 - mrc p15, 4, r1, c15, c0 @ get SCU base address - orr r1, r1, #0x8 @ SCU CPU Power Status Register - mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID - and r0, r0, #15 - add r1, r1, r0 - mov r0, #0x0 - strb r0, [r1] @ switch SCU power state to Normal mode + bl armada_38x_scu_power_up b cpu_resume ENDPROC(armada_38x_cpu_resume) diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index d9e94122073e..3b653b3ac268 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -113,7 +113,7 @@ obj-y += prm_common.o cm_common.o obj-$(CONFIG_ARCH_OMAP2) += prm2xxx_3xxx.o prm2xxx.o cm2xxx.o obj-$(CONFIG_ARCH_OMAP3) += prm2xxx_3xxx.o prm3xxx.o cm3xxx.o obj-$(CONFIG_ARCH_OMAP3) += vc3xxx_data.o vp3xxx_data.o -omap-prcm-4-5-common = cminst44xx.o cm44xx.o prm44xx.o \ +omap-prcm-4-5-common = cminst44xx.o prm44xx.o \ prcm_mpu44xx.o prminst44xx.o \ vc44xx_data.o vp44xx_data.o obj-$(CONFIG_ARCH_OMAP4) += $(omap-prcm-4-5-common) diff --git a/arch/arm/mach-omap2/am33xx-restart.c b/arch/arm/mach-omap2/am33xx-restart.c index c88d8df753c2..5bace6a45ffb 100644 --- a/arch/arm/mach-omap2/am33xx-restart.c +++ b/arch/arm/mach-omap2/am33xx-restart.c @@ -9,8 +9,7 @@ #include <linux/reboot.h> #include "common.h" -#include "prm-regbits-33xx.h" -#include "prm33xx.h" +#include "prm.h" /** * am3xx_restart - trigger a software restart of the SoC @@ -24,12 +23,5 @@ void am33xx_restart(enum reboot_mode mode, const char *cmd) { /* TODO: Handle mode and cmd if necessary */ - am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, - AM33XX_RST_GLOBAL_WARM_SW_MASK, - AM33XX_PRM_DEVICE_MOD, - AM33XX_PRM_RSTCTRL_OFFSET); - - /* OCP barrier */ - (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD, - AM33XX_PRM_RSTCTRL_OFFSET); + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c index 97767a27ca9d..e0ad64fde20e 100644 --- a/arch/arm/mach-omap2/board-n8x0.c +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -21,8 +21,10 @@ #include <linux/i2c.h> #include <linux/spi/spi.h> #include <linux/usb/musb.h> +#include <linux/mmc/host.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include <linux/platform_data/mtd-onenand-omap2.h> +#include <linux/platform_data/mmc-omap.h> #include <linux/mfd/menelaus.h> #include <sound/tlv320aic3x.h> diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index ddfc8df83c6a..3d5040f82e90 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -484,7 +484,7 @@ static struct omap_mux_partition *partition; * Current flows to eMMC when eMMC is off and the data lines are pulled up, * so pull them down. N.B. we pull 8 lines because we are using 8 lines. */ -static void rx51_mmc2_remux(struct device *dev, int slot, int power_on) +static void rx51_mmc2_remux(struct device *dev, int power_on) { if (power_on) omap_mux_write_array(partition, rx51_mmc2_on_mux); @@ -500,7 +500,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = { .cover_only = true, .gpio_cd = 160, .gpio_wp = -EINVAL, - .power_saving = true, }, { .name = "internal", @@ -510,7 +509,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = { .gpio_cd = -EINVAL, .gpio_wp = -EINVAL, .nonremovable = true, - .power_saving = true, .remux = rx51_mmc2_remux, }, {} /* Terminator */ diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c index eb8c75ec3b1a..5c5ebb4db5f7 100644 --- a/arch/arm/mach-omap2/cclock3xxx_data.c +++ b/arch/arm/mach-omap2/cclock3xxx_data.c @@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_noncore_dpll_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; @@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = { .get_parent = &omap2_init_dpll_parent, .recalc_rate = &omap3_dpll_recalc, .set_rate = &omap3_dpll4_set_rate, + .set_parent = &omap3_noncore_dpll_set_parent, + .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent, + .determine_rate = &omap3_noncore_dpll_determine_rate, .round_rate = &omap2_dpll_round_rate, }; diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 500530d1364a..6ad5b4dbd33e 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -171,7 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk) _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), idlest_val, __clk_get_name(clk->hw.clk)); } else { - cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit); + omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id, + idlest_bit); }; } @@ -771,4 +772,8 @@ void __init ti_clk_init_features(void) ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; else if (cpu_is_omap34xx()) ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; + + /* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */ + if (omap_rev() == OMAP3430_REV_ES1_0) + ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 4592a2762592..641337c6cde9 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -234,6 +234,7 @@ struct ti_clk_features { }; #define TI_CLK_DPLL_HAS_FREQSEL (1 << 0) +#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1) extern struct ti_clk_features ti_clk_features; diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c index 0b02b4161d71..a9e86db5daf9 100644 --- a/arch/arm/mach-omap2/clock3xxx.c +++ b/arch/arm/mach-omap2/clock3xxx.c @@ -38,6 +38,18 @@ /* needed by omap3_core_dpll_m2_set_rate() */ struct clk *sdrc_ick_p, *arm_fck_p; + +/** + * omap3_dpll4_set_rate - set rate for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * + * Check if the current SoC supports the per-dpll reprogram operation + * or not, and then do the rate change if supported. Returns -EINVAL + * if not supported, 0 for success, and potential error codes from the + * clock rate change. + */ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -46,7 +58,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, * on 3430ES1 prevents us from changing DPLL multipliers or dividers * on DPLL4. */ - if (omap_rev() == OMAP3430_REV_ES1_0) { + if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); return -EINVAL; } @@ -54,6 +66,30 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); } +/** + * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * @index: parent index, 0 - reference clock, 1 - bypass clock + * + * Check if the current SoC support the per-dpll reprogram operation + * or not, and then do the rate + parent change if supported. Returns + * -EINVAL if not supported, 0 for success, and potential error codes + * from the clock rate change. + */ +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index) +{ + if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); + return -EINVAL; + } + + return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate, + index); +} + void __init omap3_clk_lock_dpll5(void) { struct clk *dpll5_clk; diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h index 93473f9a551c..6222e87a79b6 100644 --- a/arch/arm/mach-omap2/cm.h +++ b/arch/arm/mach-omap2/cm.h @@ -45,17 +45,29 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2); * struct cm_ll_data - fn ptrs to per-SoC CM function implementations * @split_idlest_reg: ptr to the SoC CM-specific split_idlest_reg impl * @wait_module_ready: ptr to the SoC CM-specific wait_module_ready impl + * @wait_module_idle: ptr to the SoC CM-specific wait_module_idle impl + * @module_enable: ptr to the SoC CM-specific module_enable impl + * @module_disable: ptr to the SoC CM-specific module_disable impl */ struct cm_ll_data { int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); - int (*wait_module_ready)(s16 prcm_mod, u8 idlest_id, u8 idlest_shift); + int (*wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); + int (*wait_module_idle)(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); + void (*module_enable)(u8 mode, u8 part, u16 inst, u16 clkctrl_offs); + void (*module_disable)(u8 part, u16 inst, u16 clkctrl_offs); }; extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, u8 *idlest_reg_id); -extern int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift); - +int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); +int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift); +int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs); +int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs); extern int cm_register(struct cm_ll_data *cld); extern int cm_unregister(struct cm_ll_data *cld); diff --git a/arch/arm/mach-omap2/cm1_44xx.h b/arch/arm/mach-omap2/cm1_44xx.h index 5ae8fe39d6ee..a5949927b661 100644 --- a/arch/arm/mach-omap2/cm1_44xx.h +++ b/arch/arm/mach-omap2/cm1_44xx.h @@ -25,8 +25,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_44XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define OMAP4430_CM1_BASE 0x4a004000 diff --git a/arch/arm/mach-omap2/cm1_54xx.h b/arch/arm/mach-omap2/cm1_54xx.h index 90b3348e6672..fd245dfa7391 100644 --- a/arch/arm/mach-omap2/cm1_54xx.h +++ b/arch/arm/mach-omap2/cm1_54xx.h @@ -22,8 +22,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_54XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define OMAP54XX_CM_CORE_AON_BASE 0x4a004000 diff --git a/arch/arm/mach-omap2/cm1_7xx.h b/arch/arm/mach-omap2/cm1_7xx.h index ca6fa1febaac..2f1c09eea021 100644 --- a/arch/arm/mach-omap2/cm1_7xx.h +++ b/arch/arm/mach-omap2/cm1_7xx.h @@ -23,8 +23,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM1_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM1_7XX_H -#include "cm_44xx_54xx.h" - /* CM1 base address */ #define DRA7XX_CM_CORE_AON_BASE 0x4a005000 diff --git a/arch/arm/mach-omap2/cm2_44xx.h b/arch/arm/mach-omap2/cm2_44xx.h index ee5136d7cdda..7521abf3d830 100644 --- a/arch/arm/mach-omap2/cm2_44xx.h +++ b/arch/arm/mach-omap2/cm2_44xx.h @@ -25,8 +25,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_44XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_44XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define OMAP4430_CM2_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2_54xx.h b/arch/arm/mach-omap2/cm2_54xx.h index 2683231b299b..ff4040c196d8 100644 --- a/arch/arm/mach-omap2/cm2_54xx.h +++ b/arch/arm/mach-omap2/cm2_54xx.h @@ -21,8 +21,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_54XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_54XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define OMAP54XX_CM_CORE_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2_7xx.h b/arch/arm/mach-omap2/cm2_7xx.h index e966e3a3c931..ce63fdb68056 100644 --- a/arch/arm/mach-omap2/cm2_7xx.h +++ b/arch/arm/mach-omap2/cm2_7xx.h @@ -22,8 +22,6 @@ #ifndef __ARCH_ARM_MACH_OMAP2_CM2_7XX_H #define __ARCH_ARM_MACH_OMAP2_CM2_7XX_H -#include "cm_44xx_54xx.h" - /* CM2 base address */ #define DRA7XX_CM_CORE_BASE 0x4a008000 diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index 8be6ea50c092..a96d901b1d5d 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c @@ -53,7 +53,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); } -bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) +static bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) { u32 v; @@ -64,12 +64,12 @@ bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; } -void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) +static void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask); } -void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) +static void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask); } @@ -150,7 +150,7 @@ static int _omap2xxx_apll_enable(u8 enable_bit, u8 status_bit) v |= m; omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN); - omap2xxx_cm_wait_module_ready(PLL_MOD, 1, status_bit); + omap2xxx_cm_wait_module_ready(0, PLL_MOD, 1, status_bit); /* * REVISIT: Should we return an error code if @@ -204,8 +204,9 @@ void omap2xxx_cm_apll96_disable(void) * XXX This function is only needed until absolute register addresses are * removed from the OMAP struct clk records. */ -int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, - u8 *idlest_reg_id) +static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, + s16 *prcm_inst, + u8 *idlest_reg_id) { unsigned long offs; u8 idlest_offs; @@ -238,6 +239,7 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, /** * omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition, ignored for OMAP2 * @prcm_mod: PRCM module offset * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_shift: shift of the bit in the CM_IDLEST* register to check @@ -246,7 +248,8 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * success or -EBUSY if the module doesn't enable in time. */ -int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h index 891d81c3c8f4..c89502b168ae 100644 --- a/arch/arm/mach-omap2/cm2xxx.h +++ b/arch/arm/mach-omap2/cm2xxx.h @@ -46,9 +46,6 @@ #ifndef __ASSEMBLER__ -extern void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask); -extern void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask); - extern void omap2xxx_cm_set_dpll_disable_autoidle(void); extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void); @@ -57,11 +54,8 @@ extern void omap2xxx_cm_set_apll54_auto_low_power_stop(void); extern void omap2xxx_cm_set_apll96_disable_autoidle(void); extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void); -extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); -extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, - u8 idlest_shift); -extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, - s16 *prcm_inst, u8 *idlest_reg_id); +int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift); extern int omap2xxx_cm_fclks_active(void); extern int omap2xxx_cm_mpu_retention_allowed(void); extern u32 omap2xxx_cm_get_core_clk_src(void); diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index b3f99e93def0..b9ad463a368a 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -96,13 +96,12 @@ static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask) /** * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * bit 0. */ -static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs) { u32 v = am33xx_cm_read_reg(inst, clkctrl_offs); v &= AM33XX_IDLEST_MASK; @@ -113,17 +112,16 @@ static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * _is_module_ready - can module registers be accessed without causing an abort? * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. */ -static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static bool _is_module_ready(u16 inst, u16 clkctrl_offs) { u32 v; - v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs); + v = _clkctrl_idlest(inst, clkctrl_offs); return (v == CLKCTRL_IDLEST_FUNCTIONAL || v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; @@ -158,7 +156,7 @@ static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs) * Returns true if the clockdomain referred to by (@inst, @cdoffs) * is in hardware-supervised idle mode, or 0 otherwise. */ -bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) +static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) { u32 v; @@ -177,7 +175,7 @@ bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@inst, @cdoffs) into * hardware-supervised idle mode. No return value. */ -void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs); } @@ -191,7 +189,7 @@ void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs) * software-supervised idle mode, i.e., controlled manually by the * Linux OMAP clockdomain code. No return value. */ -void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs); } @@ -204,7 +202,7 @@ void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@inst, @cdoffs) into idle * No return value. */ -void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs); } @@ -217,7 +215,7 @@ void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs) * Take a clockdomain referred to by (@inst, @cdoffs) out of idle, * waking it up. No return value. */ -void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) +static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs); } @@ -228,20 +226,22 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs) /** * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state + * @part: PRCM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for AM33xx * * Wait for the module IDLEST to be functional. If the idle state is in any * the non functional state (trans, idle or disabled), module and thus the * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; - omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs), + omap_test_timeout(_is_module_ready(inst, clkctrl_offs), MAX_MODULE_READY_TIME, i); return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; @@ -250,22 +250,24 @@ int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled' * state + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for AM33xx * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) == + omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) == CLKCTRL_IDLEST_DISABLED), MAX_MODULE_READY_TIME, i); @@ -275,13 +277,14 @@ int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL * @mode: Module mode (SW or HW) + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst, + u16 clkctrl_offs) { u32 v; @@ -293,13 +296,13 @@ void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs) /** * am33xx_cm_module_disable - Disable the module inside CLKCTRL + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs) +static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; @@ -362,3 +365,21 @@ struct clkdm_ops am33xx_clkdm_operations = { .clkdm_clk_enable = am33xx_clkdm_clk_enable, .clkdm_clk_disable = am33xx_clkdm_clk_disable, }; + +static struct cm_ll_data am33xx_cm_ll_data = { + .wait_module_ready = &am33xx_cm_wait_module_ready, + .wait_module_idle = &am33xx_cm_wait_module_idle, + .module_enable = &am33xx_cm_module_enable, + .module_disable = &am33xx_cm_module_disable, +}; + +int __init am33xx_cm_init(void) +{ + return cm_register(&am33xx_cm_ll_data); +} + +static void __exit am33xx_cm_exit(void) +{ + cm_unregister(&am33xx_cm_ll_data); +} +__exitcall(am33xx_cm_exit); diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index bd2441790779..046b4b2bc9d9 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -374,41 +374,6 @@ #ifndef __ASSEMBLER__ -bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs); -void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs); - -#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) -extern int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, - u16 clkctrl_offs); -#else -static inline int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ - return 0; -} -static inline void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ -} -static inline void am33xx_cm_module_disable(u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ -} -static inline int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, - u16 clkctrl_offs) -{ - return 0; -} -#endif - +int am33xx_cm_init(void); #endif /* ASSEMBLER */ #endif diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index 129a4e7f6ef5..ebead8f035f9 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c @@ -42,7 +42,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask) omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL); } -bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) +static bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) { u32 v; @@ -53,22 +53,22 @@ bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask) return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0; } -void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, module, mask); } -void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, module, mask); } -void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, module, mask); } -void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) +static void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) { _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask); } @@ -79,6 +79,7 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) /** * omap3xxx_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition, ignored for OMAP3 * @prcm_mod: PRCM module offset * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) * @idlest_shift: shift of the bit in the CM_IDLEST* register to check @@ -87,7 +88,8 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask) * (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon * success or -EBUSY if the module doesn't enable in time. */ -int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id, + u8 idlest_shift) { int ena = 0, i = 0; u8 cm_idlest_reg; @@ -116,8 +118,9 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) * XXX This function is only needed until absolute register addresses are * removed from the OMAP struct clk records. */ -int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, - u8 *idlest_reg_id) +static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, + s16 *prcm_inst, + u8 *idlest_reg_id) { unsigned long offs; u8 idlest_offs; diff --git a/arch/arm/mach-omap2/cm3xxx.h b/arch/arm/mach-omap2/cm3xxx.h index 7a16b5598127..734a8581c0c4 100644 --- a/arch/arm/mach-omap2/cm3xxx.h +++ b/arch/arm/mach-omap2/cm3xxx.h @@ -68,18 +68,6 @@ #ifndef __ASSEMBLER__ -extern void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask); -extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask); - -extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask); -extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, - u8 idlest_shift); - -extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, - s16 *prcm_inst, u8 *idlest_reg_id); - extern void omap3_cm_save_context(void); extern void omap3_cm_restore_context(void); extern void omap3_cm_save_scratchpad_contents(u32 *ptr); diff --git a/arch/arm/mach-omap2/cm44xx.c b/arch/arm/mach-omap2/cm44xx.c deleted file mode 100644 index fe5cc7bae489..000000000000 --- a/arch/arm/mach-omap2/cm44xx.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * OMAP4 CM1, CM2 module low-level functions - * - * Copyright (C) 2010 Nokia Corporation - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * These functions are intended to be used only by the cminst44xx.c file. - * XXX Perhaps we should just move them there and make them static. - */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/io.h> - -#include "cm.h" -#include "cm1_44xx.h" -#include "cm2_44xx.h" - -/* CM1 hardware module low-level functions */ - -/* Read a register in CM1 */ -u32 omap4_cm1_read_inst_reg(s16 inst, u16 reg) -{ - return readl_relaxed(cm_base + inst + reg); -} - -/* Write into a register in CM1 */ -void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 reg) -{ - writel_relaxed(val, cm_base + inst + reg); -} - -/* Read a register in CM2 */ -u32 omap4_cm2_read_inst_reg(s16 inst, u16 reg) -{ - return readl_relaxed(cm2_base + inst + reg); -} - -/* Write into a register in CM2 */ -void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg) -{ - writel_relaxed(val, cm2_base + inst + reg); -} diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h index 3380beeace6e..728d06a4af19 100644 --- a/arch/arm/mach-omap2/cm44xx.h +++ b/arch/arm/mach-omap2/cm44xx.h @@ -23,4 +23,7 @@ #define OMAP4_CM_CLKSTCTRL 0x0000 #define OMAP4_CM_STATICDEP 0x0004 +void omap_cm_base_init(void); +int omap4_cm_init(void); + #endif diff --git a/arch/arm/mach-omap2/cm_44xx_54xx.h b/arch/arm/mach-omap2/cm_44xx_54xx.h deleted file mode 100644 index cbb211690321..000000000000 --- a/arch/arm/mach-omap2/cm_44xx_54xx.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * OMAP44xx and OMAP54xx CM1/CM2 function prototypes - * - * Copyright (C) 2009-2013 Texas Instruments, Inc. - * Copyright (C) 2009-2010 Nokia Corporation - * - * Paul Walmsley (paul@pwsan.com) - * Rajendra Nayak (rnayak@ti.com) - * Benoit Cousson (b-cousson@ti.com) - * - * This file is automatically generated from the OMAP hardware databases. - * We respectfully ask that any modifications to this file be coordinated - * with the public linux-omap@vger.kernel.org mailing list and the - * authors above to ensure that the autogeneration scripts are kept - * up-to-date with the file contents. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CM_44XX_54XX_H -#define __ARCH_ARM_MACH_OMAP2_CM_44XX_55XX_H - -/* CM1 Function prototypes */ -extern u32 omap4_cm1_read_inst_reg(s16 inst, u16 idx); -extern void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_cm1_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - -/* CM2 Function prototypes */ -extern u32 omap4_cm2_read_inst_reg(s16 inst, u16 idx); -extern void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_cm2_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - -#endif diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c index 8f6c4710877e..8fe02fcedc48 100644 --- a/arch/arm/mach-omap2/cm_common.c +++ b/arch/arm/mach-omap2/cm_common.c @@ -72,9 +72,10 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, } /** - * cm_wait_module_ready - wait for a module to leave idle or standby + * omap_cm_wait_module_ready - wait for a module to leave idle or standby + * @part: PRCM partition * @prcm_mod: PRCM module offset - * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3) + * @idlest_reg: CM_IDLESTx register * @idlest_shift: shift of the bit in the CM_IDLEST* register to check * * Wait for the PRCM to indicate that the module identified by @@ -83,7 +84,8 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst, * no per-SoC wait_module_ready() function pointer has been registered * or if the idlest register is unknown on the SoC. */ -int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) +int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift) { if (!cm_ll_data->wait_module_ready) { WARN_ONCE(1, "cm: %s: no low-level function defined\n", @@ -91,7 +93,79 @@ int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) return -EINVAL; } - return cm_ll_data->wait_module_ready(prcm_mod, idlest_id, idlest_shift); + return cm_ll_data->wait_module_ready(part, prcm_mod, idlest_reg, + idlest_shift); +} + +/** + * omap_cm_wait_module_idle - wait for a module to enter idle or standby + * @part: PRCM partition + * @prcm_mod: PRCM module offset + * @idlest_reg: CM_IDLESTx register + * @idlest_shift: shift of the bit in the CM_IDLEST* register to check + * + * Wait for the PRCM to indicate that the module identified by + * (@prcm_mod, @idlest_id, @idlest_shift) is no longer clocked. Return + * 0 upon success, -EBUSY if the module doesn't enable in time, or + * -EINVAL if no per-SoC wait_module_idle() function pointer has been + * registered or if the idlest register is unknown on the SoC. + */ +int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg, + u8 idlest_shift) +{ + if (!cm_ll_data->wait_module_idle) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + return cm_ll_data->wait_module_idle(part, prcm_mod, idlest_reg, + idlest_shift); +} + +/** + * omap_cm_module_enable - enable a module + * @mode: target mode for the module + * @part: PRCM partition + * @inst: PRCM instance + * @clkctrl_offs: CM_CLKCTRL register offset for the module + * + * Enables clocks for a module identified by (@part, @inst, @clkctrl_offs) + * making its IO space accessible. Return 0 upon success, -EINVAL if no + * per-SoC module_enable() function pointer has been registered. + */ +int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs) +{ + if (!cm_ll_data->module_enable) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + cm_ll_data->module_enable(mode, part, inst, clkctrl_offs); + return 0; +} + +/** + * omap_cm_module_disable - disable a module + * @part: PRCM partition + * @inst: PRCM instance + * @clkctrl_offs: CM_CLKCTRL register offset for the module + * + * Disables clocks for a module identified by (@part, @inst, @clkctrl_offs) + * makings its IO space inaccessible. Return 0 upon success, -EINVAL if + * no per-SoC module_disable() function pointer has been registered. + */ +int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs) +{ + if (!cm_ll_data->module_disable) { + WARN_ONCE(1, "cm: %s: no low-level function defined\n", + __func__); + return -EINVAL; + } + + cm_ll_data->module_disable(part, inst, clkctrl_offs); + return 0; } /** diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 12aca56942c0..95a8cff66aff 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c @@ -26,7 +26,6 @@ #include "cm1_44xx.h" #include "cm2_44xx.h" #include "cm44xx.h" -#include "cminst44xx.h" #include "cm-regbits-34xx.h" #include "prcm44xx.h" #include "prm44xx.h" @@ -74,17 +73,18 @@ void omap_cm_base_init(void) /* Private functions */ +static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx); + /** * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to * bit 0. */ -static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs) { u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs); v &= OMAP4430_IDLEST_MASK; @@ -96,26 +96,23 @@ static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) * _is_module_ready - can module registers be accessed without causing an abort? * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise. */ -static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; - v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs); + v = _clkctrl_idlest(part, inst, clkctrl_offs); return (v == CLKCTRL_IDLEST_FUNCTIONAL || v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false; } -/* Public functions */ - /* Read a register in a CM instance */ -u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) +static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) { BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || part == OMAP4430_INVALID_PRCM_PARTITION || @@ -124,7 +121,7 @@ u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx) } /* Write into a register in a CM instance */ -void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) +static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) { BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS || part == OMAP4430_INVALID_PRCM_PARTITION || @@ -133,8 +130,8 @@ void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx) } /* Read-modify-write a register in CM1. Caller must lock */ -u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, - s16 idx) +static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, + s16 idx) { u32 v; @@ -146,17 +143,18 @@ u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst, return v; } -u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) +static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) { return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx); } -u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx) +static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, + s16 idx) { return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx); } -u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) +static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask) { u32 v; @@ -200,7 +198,7 @@ static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs) * Returns true if the clockdomain referred to by (@part, @inst, @cdoffs) * is in hardware-supervised idle mode, or 0 otherwise. */ -bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) +static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) { u32 v; @@ -220,7 +218,7 @@ bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs) * Put a clockdomain referred to by (@part, @inst, @cdoffs) into * hardware-supervised idle mode. No return value. */ -void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs); } @@ -235,7 +233,7 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs) * software-supervised idle mode, i.e., controlled manually by the * Linux OMAP clockdomain code. No return value. */ -void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs); } @@ -249,7 +247,7 @@ void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs) * Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle, * waking it up. No return value. */ -void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs); } @@ -258,7 +256,7 @@ void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs) * */ -void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) +static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) { _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs); } @@ -267,23 +265,23 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs) * omap4_cminst_wait_module_ready - wait for a module to be in 'func' state * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: bit shift for the register, ignored for OMAP4+ * * Wait for the module IDLEST to be functional. If the idle state is in any * the non functional state (trans, idle or disabled), module and thus the * sysconfig cannot be accessed and will probably lead to an "imprecise * external abort" */ -int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs), + omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs), MAX_MODULE_READY_TIME, i); return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; @@ -294,21 +292,22 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, * state * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) + * @bit_shift: Bit shift for the register, ignored for OMAP4+ * * Wait for the module IDLEST to be disabled. Some PRCM transition, * like reset assertion or parent clock de-activation must wait the * module to be fully disabled. */ -int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs) +static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs, + u8 bit_shift) { int i = 0; if (!clkctrl_offs) return 0; - omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) == + omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) == CLKCTRL_IDLEST_DISABLED), MAX_MODULE_DISABLE_TIME, i); @@ -320,13 +319,12 @@ int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_off * @mode: Module mode (SW or HW) * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, + u16 clkctrl_offs) { u32 v; @@ -340,13 +338,11 @@ void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, * omap4_cminst_module_disable - Disable the module inside CLKCTRL * @part: PRCM partition ID that the CM_CLKCTRL register exists in * @inst: CM instance register offset (*_INST macro) - * @cdoffs: Clockdomain register offset (*_CDOFFS macro) * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro) * * No return value. */ -void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs) +static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs) { u32 v; @@ -510,3 +506,21 @@ struct clkdm_ops am43xx_clkdm_operations = { .clkdm_clk_enable = omap4_clkdm_clk_enable, .clkdm_clk_disable = omap4_clkdm_clk_disable, }; + +static struct cm_ll_data omap4xxx_cm_ll_data = { + .wait_module_ready = &omap4_cminst_wait_module_ready, + .wait_module_idle = &omap4_cminst_wait_module_idle, + .module_enable = &omap4_cminst_module_enable, + .module_disable = &omap4_cminst_module_disable, +}; + +int __init omap4_cm_init(void) +{ + return cm_register(&omap4xxx_cm_ll_data); +} + +static void __exit omap4_cm_exit(void) +{ + cm_unregister(&omap4xxx_cm_ll_data); +} +__exitcall(omap4_cm_exit); diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h deleted file mode 100644 index 7f56ea444bc4..000000000000 --- a/arch/arm/mach-omap2/cminst44xx.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * OMAP4 Clock Management (CM) function prototypes - * - * Copyright (C) 2010 Nokia Corporation - * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __ARCH_ASM_MACH_OMAP2_CMINST44XX_H -#define __ARCH_ASM_MACH_OMAP2_CMINST44XX_H - -bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs); -void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs); -extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); -extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs, - u16 clkctrl_offs); -/* - * In an ideal world, we would not export these low-level functions, - * but this will probably take some time to fix properly - */ -u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx); -void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx); -u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, - u16 inst, s16 idx); -u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, - s16 idx); -u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, - s16 idx); -extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, - u32 mask); - -extern void omap_cm_base_init(void); - -#endif diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 324f02bf8a51..492ef1607115 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -49,7 +49,7 @@ static int __init omap3_l3_init(void) * To avoid code running on other OMAPs in * multi-omap builds */ - if (!(cpu_is_omap34xx())) + if (!(cpu_is_omap34xx()) || of_have_populated_dt()) return -ENODEV; snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main"); @@ -67,40 +67,6 @@ static int __init omap3_l3_init(void) } omap_postcore_initcall(omap3_l3_init); -static int __init omap4_l3_init(void) -{ - int i; - struct omap_hwmod *oh[3]; - struct platform_device *pdev; - char oh_name[L3_MODULES_MAX_LEN]; - - /* If dtb is there, the devices will be created dynamically */ - if (of_have_populated_dt()) - return -ENODEV; - - /* - * To avoid code running on other OMAPs in - * multi-omap builds - */ - if (!cpu_is_omap44xx() && !soc_is_omap54xx()) - return -ENODEV; - - for (i = 0; i < L3_MODULES; i++) { - snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main_%d", i+1); - - oh[i] = omap_hwmod_lookup(oh_name); - if (!(oh[i])) - pr_err("could not look up %s\n", oh_name); - } - - pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL, 0); - - WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name); - - return PTR_RET(pdev); -} -omap_postcore_initcall(omap4_l3_init); - #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE) static struct resource omap2cam_resources[] = { diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index ac3d789ac3cd..20e120d071dd 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) /* Non-CORE DPLL rate set code */ /** - * omap3_noncore_dpll_set_rate - set non-core DPLL rate - * @clk: struct clk * of DPLL to set - * @rate: rounded target rate + * omap3_noncore_dpll_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock * - * Set the DPLL CLKOUT to the target rate. If the DPLL can enter - * low-power bypass, and the target rate is the bypass source clock - * rate, then configure the DPLL for bypass. Otherwise, round the - * target rate if it hasn't been done already, then program and lock - * the DPLL. Returns -EINVAL upon error, or 0 upon success. + * Determines which DPLL mode to use for reaching a desired target rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. */ -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct clk *new_parent = NULL; - unsigned long rrate; - u16 freqsel = 0; struct dpll_data *dd; - int ret; if (!hw || !rate) return -EINVAL; @@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, if (__clk_get_rate(dd->clk_bypass) == rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - pr_debug("%s: %s: set rate: entering bypass.\n", - __func__, __clk_get_name(hw->clk)); + *best_parent_clk = dd->clk_bypass; + } else { + rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); + *best_parent_clk = dd->clk_ref; + } + + *best_parent_rate = rate; + + return rate; +} + +/** + * omap3_noncore_dpll_set_parent - set parent for a DPLL clock + * @hw: pointer to the clock to set parent for + * @index: parent index to select + * + * Sets parent for a DPLL clock. This sets the DPLL into bypass or + * locked mode. Returns 0 with success, negative error value otherwise. + */ +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int ret; - __clk_prepare(dd->clk_bypass); - clk_enable(dd->clk_bypass); + if (!hw) + return -EINVAL; + + if (index) ret = _omap3_noncore_dpll_bypass(clk); - if (!ret) - new_parent = dd->clk_bypass; - clk_disable(dd->clk_bypass); - __clk_unprepare(dd->clk_bypass); - } else { - __clk_prepare(dd->clk_ref); - clk_enable(dd->clk_ref); - - /* XXX this check is probably pointless in the CCF context */ - if (dd->last_rounded_rate != rate) { - rrate = __clk_round_rate(hw->clk, rate); - if (rrate != rate) { - pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n", - __func__, __clk_get_name(hw->clk), - rrate, rate); - rate = rrate; - } - } + else + ret = _omap3_noncore_dpll_lock(clk); - if (dd->last_rounded_rate == 0) - return -EINVAL; + return ret; +} - /* Freqsel is available only on OMAP343X devices */ - if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { - freqsel = _omap3_dpll_compute_freqsel(clk, - dd->last_rounded_n); - WARN_ON(!freqsel); - } +/** + * omap3_noncore_dpll_set_rate - set rate for a DPLL clock + * @hw: pointer to the clock to set parent for + * @rate: target rate for the clock + * @parent_rate: rate of the parent clock + * + * Sets rate for a DPLL clock. First checks if the clock parent is + * reference clock (in bypass mode, the rate of the clock can't be + * changed) and proceeds with the rate change operation. Returns 0 + * with success, negative error value otherwise. + */ +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + u16 freqsel = 0; + int ret; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; - pr_debug("%s: %s: set rate: locking rate to %lu.\n", - __func__, __clk_get_name(hw->clk), rate); + if (__clk_get_parent(hw->clk) != dd->clk_ref) + return -EINVAL; + + if (dd->last_rounded_rate == 0) + return -EINVAL; - ret = omap3_noncore_dpll_program(clk, freqsel); - if (!ret) - new_parent = dd->clk_ref; - clk_disable(dd->clk_ref); - __clk_unprepare(dd->clk_ref); + /* Freqsel is available only on OMAP343X devices */ + if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { + freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); + WARN_ON(!freqsel); } - /* - * FIXME - this is all wrong. common code handles reparenting and - * migrating prepare/enable counts. dplls should be a multiplexer - * clock and this should be a set_parent operation so that all of that - * stuff is inherited for free - */ - if (!ret && clk_get_parent(hw->clk) != new_parent) - __clk_reparent(hw->clk, new_parent); + pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, + __clk_get_name(hw->clk), rate); - return 0; + ret = omap3_noncore_dpll_program(clk, freqsel); + + return ret; +} + +/** + * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock + * @hw: pointer to the clock to set rate and parent for + * @rate: target rate for the DPLL + * @parent_rate: clock rate of the DPLL parent + * @index: new parent index for the DPLL, 0 - reference, 1 - bypass + * + * Sets rate and parent for a DPLL clock. If new parent is the bypass + * clock, only selects the parent. Otherwise proceeds with a rate + * change, as this will effectively also change the parent as the + * DPLL is put into locked mode. Returns 0 with success, negative error + * value otherwise. + */ +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index) +{ + int ret; + + if (!hw || !rate) + return -EINVAL; + + /* + * clk-ref at index[0], in which case we only need to set rate, + * the parent will be changed automatically with the lock sequence. + * With clk-bypass case we only need to change parent. + */ + if (index) + ret = omap3_noncore_dpll_set_parent(hw, index); + else + ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate); + + return ret; } /* DPLL autoidle read/set code */ diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index 4613f1e86988..535822fcf4bb 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -207,3 +207,44 @@ out: return dd->last_rounded_rate; } + +/** + * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock + * + * Determines which DPLL mode to use for reaching a desired rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. + */ +long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_rate(dd->clk_bypass) == rate && + (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { + *best_parent_clk = dd->clk_bypass; + } else { + rate = omap4_dpll_regm4xen_round_rate(hw, rate, + best_parent_rate); + *best_parent_clk = dd->clk_ref; + } + + *best_parent_rate = rate; + + return rate; +} diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 5fa3755261ce..8fb5bbce102f 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1394,8 +1394,6 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, if (gpmc_nand_data->elm_of_node == NULL) gpmc_nand_data->elm_of_node = of_parse_phandle(child, "elm_id", 0); - if (gpmc_nand_data->elm_of_node == NULL) - pr_warn("%s: ti,elm-id property not found\n", __func__); /* select ecc-scheme for NAND */ if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) { diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c index 07d4c7b35754..dc6e79c4484a 100644 --- a/arch/arm/mach-omap2/hsmmc.c +++ b/arch/arm/mach-omap2/hsmmc.c @@ -14,14 +14,15 @@ #include <linux/string.h> #include <linux/delay.h> #include <linux/gpio.h> +#include <linux/mmc/host.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/platform_data/hsmmc-omap.h> #include "soc.h" #include "omap_device.h" #include "omap-pm.h" #include "mux.h" -#include "mmc.h" #include "hsmmc.h" #include "control.h" @@ -32,25 +33,14 @@ static u16 control_devconf1_offset; #define HSMMC_NAME_LEN 9 -#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) - -static int hsmmc_get_context_loss(struct device *dev) -{ - return omap_pm_get_dev_context_loss_count(dev); -} - -#else -#define hsmmc_get_context_loss NULL -#endif - -static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, - int power_on, int vdd) +static void omap_hsmmc1_before_set_reg(struct device *dev, + int power_on, int vdd) { u32 reg, prog_io; - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_platform_data *mmc = dev->platform_data; - if (mmc->slots[0].remux) - mmc->slots[0].remux(dev, slot, power_on); + if (mmc->remux) + mmc->remux(dev, power_on); /* * Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the @@ -72,7 +62,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1); } - if (mmc->slots[0].internal_clock) { + if (mmc->internal_clock) { reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); reg |= OMAP2_MMCSDIO1ADPCLKISEL; omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0); @@ -96,8 +86,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot, } } -static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, - int power_on, int vdd) +static void omap_hsmmc1_after_set_reg(struct device *dev, int power_on, int vdd) { u32 reg; @@ -120,34 +109,32 @@ static void omap_hsmmc1_after_set_reg(struct device *dev, int slot, } } -static void hsmmc2_select_input_clk_src(struct omap_mmc_platform_data *mmc) +static void hsmmc2_select_input_clk_src(struct omap_hsmmc_platform_data *mmc) { u32 reg; reg = omap_ctrl_readl(control_devconf1_offset); - if (mmc->slots[0].internal_clock) + if (mmc->internal_clock) reg |= OMAP2_MMCSDIO2ADPCLKISEL; else reg &= ~OMAP2_MMCSDIO2ADPCLKISEL; omap_ctrl_writel(reg, control_devconf1_offset); } -static void hsmmc2_before_set_reg(struct device *dev, int slot, - int power_on, int vdd) +static void hsmmc2_before_set_reg(struct device *dev, int power_on, int vdd) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_platform_data *mmc = dev->platform_data; - if (mmc->slots[0].remux) - mmc->slots[0].remux(dev, slot, power_on); + if (mmc->remux) + mmc->remux(dev, power_on); if (power_on) hsmmc2_select_input_clk_src(mmc); } -static int am35x_hsmmc2_set_power(struct device *dev, int slot, - int power_on, int vdd) +static int am35x_hsmmc2_set_power(struct device *dev, int power_on, int vdd) { - struct omap_mmc_platform_data *mmc = dev->platform_data; + struct omap_hsmmc_platform_data *mmc = dev->platform_data; if (power_on) hsmmc2_select_input_clk_src(mmc); @@ -155,23 +142,22 @@ static int am35x_hsmmc2_set_power(struct device *dev, int slot, return 0; } -static int nop_mmc_set_power(struct device *dev, int slot, int power_on, - int vdd) +static int nop_mmc_set_power(struct device *dev, int power_on, int vdd) { return 0; } -static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, - int controller_nr) +static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data + *mmc_controller, int controller_nr) { - if (gpio_is_valid(mmc_controller->slots[0].switch_pin) && - (mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES)) - omap_mux_init_gpio(mmc_controller->slots[0].switch_pin, - OMAP_PIN_INPUT_PULLUP); - if (gpio_is_valid(mmc_controller->slots[0].gpio_wp) && - (mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES)) - omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp, - OMAP_PIN_INPUT_PULLUP); + if (gpio_is_valid(mmc_controller->switch_pin) && + (mmc_controller->switch_pin < OMAP_MAX_GPIO_LINES)) + omap_mux_init_gpio(mmc_controller->switch_pin, + OMAP_PIN_INPUT_PULLUP); + if (gpio_is_valid(mmc_controller->gpio_wp) && + (mmc_controller->gpio_wp < OMAP_MAX_GPIO_LINES)) + omap_mux_init_gpio(mmc_controller->gpio_wp, + OMAP_PIN_INPUT_PULLUP); if (cpu_is_omap34xx()) { if (controller_nr == 0) { omap_mux_init_signal("sdmmc1_clk", @@ -180,7 +166,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("sdmmc1_dat0", OMAP_PIN_INPUT_PULLUP); - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) { omap_mux_init_signal("sdmmc1_dat1", OMAP_PIN_INPUT_PULLUP); @@ -189,7 +175,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, omap_mux_init_signal("sdmmc1_dat3", OMAP_PIN_INPUT_PULLUP); } - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & MMC_CAP_8_BIT_DATA) { omap_mux_init_signal("sdmmc1_dat4", OMAP_PIN_INPUT_PULLUP); @@ -214,7 +200,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, * For 8 wire configurations, Lines DAT4, 5, 6 and 7 * need to be muxed in the board-*.c files */ - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) { omap_mux_init_signal("sdmmc2_dat1", OMAP_PIN_INPUT_PULLUP); @@ -223,7 +209,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, omap_mux_init_signal("sdmmc2_dat3", OMAP_PIN_INPUT_PULLUP); } - if (mmc_controller->slots[0].caps & + if (mmc_controller->caps & MMC_CAP_8_BIT_DATA) { omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4", OMAP_PIN_INPUT_PULLUP); @@ -243,7 +229,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller, } static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, - struct omap_mmc_platform_data *mmc) + struct omap_hsmmc_platform_data *mmc) { char *hc_name; @@ -259,38 +245,22 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, else snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i", c->mmc, 1); - mmc->slots[0].name = hc_name; - mmc->nr_slots = 1; - mmc->slots[0].caps = c->caps; - mmc->slots[0].pm_caps = c->pm_caps; - mmc->slots[0].internal_clock = !c->ext_clock; - mmc->max_freq = c->max_freq; + mmc->name = hc_name; + mmc->caps = c->caps; + mmc->internal_clock = !c->ext_clock; mmc->reg_offset = 0; - mmc->get_context_loss_count = hsmmc_get_context_loss; - mmc->slots[0].switch_pin = c->gpio_cd; - mmc->slots[0].gpio_wp = c->gpio_wp; + mmc->switch_pin = c->gpio_cd; + mmc->gpio_wp = c->gpio_wp; - mmc->slots[0].remux = c->remux; - mmc->slots[0].init_card = c->init_card; + mmc->remux = c->remux; + mmc->init_card = c->init_card; if (c->cover_only) - mmc->slots[0].cover = 1; + mmc->cover = 1; if (c->nonremovable) - mmc->slots[0].nonremovable = 1; - - if (c->power_saving) - mmc->slots[0].power_saving = 1; - - if (c->no_off) - mmc->slots[0].no_off = 1; - - if (c->no_off_init) - mmc->slots[0].no_regulator_off_init = c->no_off_init; - - if (c->vcc_aux_disable_is_sleep) - mmc->slots[0].vcc_aux_disable_is_sleep = 1; + mmc->nonremovable = 1; /* * NOTE: MMC slots should have a Vcc regulator set up. @@ -300,42 +270,42 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, * temporary HACK: ocr_mask instead of fixed supply */ if (soc_is_am35xx()) - mmc->slots[0].ocr_mask = MMC_VDD_165_195 | + mmc->ocr_mask = MMC_VDD_165_195 | MMC_VDD_26_27 | MMC_VDD_27_28 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32; else - mmc->slots[0].ocr_mask = c->ocr_mask; + mmc->ocr_mask = c->ocr_mask; if (!soc_is_am35xx()) - mmc->slots[0].features |= HSMMC_HAS_PBIAS; + mmc->features |= HSMMC_HAS_PBIAS; switch (c->mmc) { case 1: - if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { + if (mmc->features & HSMMC_HAS_PBIAS) { /* on-chip level shifting via PBIAS0/PBIAS1 */ - mmc->slots[0].before_set_reg = + mmc->before_set_reg = omap_hsmmc1_before_set_reg; - mmc->slots[0].after_set_reg = + mmc->after_set_reg = omap_hsmmc1_after_set_reg; } if (soc_is_am35xx()) - mmc->slots[0].set_power = nop_mmc_set_power; + mmc->set_power = nop_mmc_set_power; /* OMAP3630 HSMMC1 supports only 4-bit */ if (cpu_is_omap3630() && (c->caps & MMC_CAP_8_BIT_DATA)) { c->caps &= ~MMC_CAP_8_BIT_DATA; c->caps |= MMC_CAP_4_BIT_DATA; - mmc->slots[0].caps = c->caps; + mmc->caps = c->caps; } break; case 2: if (soc_is_am35xx()) - mmc->slots[0].set_power = am35x_hsmmc2_set_power; + mmc->set_power = am35x_hsmmc2_set_power; if (c->ext_clock) c->transceiver = 1; @@ -343,17 +313,17 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, c->caps &= ~MMC_CAP_8_BIT_DATA; c->caps |= MMC_CAP_4_BIT_DATA; } - if (mmc->slots[0].features & HSMMC_HAS_PBIAS) { + if (mmc->features & HSMMC_HAS_PBIAS) { /* off-chip level shifting, or none */ - mmc->slots[0].before_set_reg = hsmmc2_before_set_reg; - mmc->slots[0].after_set_reg = NULL; + mmc->before_set_reg = hsmmc2_before_set_reg; + mmc->after_set_reg = NULL; } break; case 3: case 4: case 5: - mmc->slots[0].before_set_reg = NULL; - mmc->slots[0].after_set_reg = NULL; + mmc->before_set_reg = NULL; + mmc->after_set_reg = NULL; break; default: pr_err("MMC%d configuration not supported!\n", c->mmc); @@ -368,7 +338,7 @@ static int omap_hsmmc_done; void omap_hsmmc_late_init(struct omap2_hsmmc_info *c) { struct platform_device *pdev; - struct omap_mmc_platform_data *mmc_pdata; + struct omap_hsmmc_platform_data *mmc_pdata; int res; if (omap_hsmmc_done != 1) @@ -388,8 +358,8 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c) if (!mmc_pdata) continue; - mmc_pdata->slots[0].switch_pin = c->gpio_cd; - mmc_pdata->slots[0].gpio_wp = c->gpio_wp; + mmc_pdata->switch_pin = c->gpio_cd; + mmc_pdata->gpio_wp = c->gpio_wp; res = omap_device_register(pdev); if (res) @@ -408,12 +378,12 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, struct omap_device *od; struct platform_device *pdev; char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN]; - struct omap_mmc_platform_data *mmc_data; - struct omap_mmc_dev_attr *mmc_dev_attr; + struct omap_hsmmc_platform_data *mmc_data; + struct omap_hsmmc_dev_attr *mmc_dev_attr; char *name; int res; - mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); + mmc_data = kzalloc(sizeof(*mmc_data), GFP_KERNEL); if (!mmc_data) { pr_err("Cannot allocate memory for mmc device!\n"); return; @@ -463,7 +433,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo, } res = platform_device_add_data(pdev, mmc_data, - sizeof(struct omap_mmc_platform_data)); + sizeof(struct omap_hsmmc_platform_data)); if (res) { pr_err("Could not add pdata for %s\n", name); goto put_pdev; @@ -489,7 +459,7 @@ put_pdev: platform_device_put(pdev); free_name: - kfree(mmc_data->slots[0].name); + kfree(mmc_data->name); free_mmc: kfree(mmc_data); diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h index 7f2e790e0929..148cd9b15499 100644 --- a/arch/arm/mach-omap2/hsmmc.h +++ b/arch/arm/mach-omap2/hsmmc.h @@ -12,25 +12,18 @@ struct omap2_hsmmc_info { u8 mmc; /* controller 1/2/3 */ u32 caps; /* 4/8 wires and any additional host * capabilities OR'd (ref. linux/mmc/host.h) */ - u32 pm_caps; /* PM capabilities */ bool transceiver; /* MMC-2 option */ bool ext_clock; /* use external pin for input clock */ bool cover_only; /* No card detect - just cover switch */ bool nonremovable; /* Nonremovable e.g. eMMC */ - bool power_saving; /* Try to sleep or power off when possible */ - bool no_off; /* power_saving and power is not to go off */ - bool no_off_init; /* no power off when not in MMC sleep state */ - bool vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */ bool deferred; /* mmc needs a deferred probe */ int gpio_cd; /* or -EINVAL */ int gpio_wp; /* or -EINVAL */ char *name; /* or NULL for default */ struct platform_device *pdev; /* mmc controller instance */ int ocr_mask; /* temporary HACK */ - int max_freq; /* maximum clock, if constrained by external - * circuitry, or 0 for default */ /* Remux (pad configuration) when powering on/off */ - void (*remux)(struct device *dev, int slot, int power_on); + void (*remux)(struct device *dev, int power_on); /* init some special card */ void (*init_card)(struct mmc_card *card); }; diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 03cbb16898a3..4fc838354e31 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -45,13 +45,15 @@ #include "sram.h" #include "cm2xxx.h" #include "cm3xxx.h" +#include "cm33xx.h" +#include "cm44xx.h" #include "prm.h" #include "cm.h" #include "prcm_mpu44xx.h" #include "prminst44xx.h" -#include "cminst44xx.h" #include "prm2xxx.h" #include "prm3xxx.h" +#include "prm33xx.h" #include "prm44xx.h" #include "opp2xxx.h" @@ -565,6 +567,8 @@ void __init am33xx_init_early(void) omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL); omap3xxx_check_revision(); am33xx_check_features(); + am33xx_prm_init(); + am33xx_cm_init(); am33xx_powerdomains_init(); am33xx_clockdomains_init(); am33xx_hwmod_init(); @@ -591,6 +595,8 @@ void __init am43xx_init_early(void) omap_cm_base_init(); omap3xxx_check_revision(); am33xx_check_features(); + omap44xx_prm_init(); + omap4_cm_init(); am43xx_powerdomains_init(); am43xx_clockdomains_init(); am43xx_hwmod_init(); @@ -620,6 +626,7 @@ void __init omap4430_init_early(void) omap_cm_base_init(); omap4xxx_check_revision(); omap4xxx_check_features(); + omap4_cm_init(); omap4_pm_init_early(); omap44xx_prm_init(); omap44xx_voltagedomains_init(); @@ -655,6 +662,7 @@ void __init omap5_init_early(void) omap_cm_base_init(); omap44xx_prm_init(); omap5xxx_check_revision(); + omap4_cm_init(); omap54xx_voltagedomains_init(); omap54xx_powerdomains_init(); omap54xx_clockdomains_init(); @@ -686,6 +694,7 @@ void __init dra7xx_init_early(void) omap_cm_base_init(); omap44xx_prm_init(); dra7xxx_check_revision(); + omap4_cm_init(); dra7xx_powerdomains_init(); dra7xx_clockdomains_init(); dra7xx_hwmod_init(); diff --git a/arch/arm/mach-omap2/mmc.h b/arch/arm/mach-omap2/mmc.h index 0cd4b089da9c..30d39b97e7dd 100644 --- a/arch/arm/mach-omap2/mmc.h +++ b/arch/arm/mach-omap2/mmc.h @@ -1,5 +1,3 @@ -#include <linux/mmc/host.h> -#include <linux/platform_data/mmc-omap.h> #define OMAP24XX_NR_MMC 2 #define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE @@ -7,14 +5,6 @@ #define OMAP4_MMC_REG_OFFSET 0x100 -#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) -void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data); -#else -static inline void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data) -{ -} -#endif - struct omap_hwmod; int omap_msdi_reset(struct omap_hwmod *oh); diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 6944ae3674e8..79f49d904a06 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c @@ -227,7 +227,7 @@ static void __init save_l2x0_context(void) int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) { struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); - unsigned int save_state = 0; + unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET; unsigned int wakeup_cpu; if (omap_rev() == OMAP4430_REV_ES1_0) @@ -239,6 +239,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) save_state = 0; break; case PWRDM_POWER_OFF: + cpu_logic_state = PWRDM_POWER_OFF; save_state = 1; break; case PWRDM_POWER_RET: @@ -270,6 +271,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) cpu_clear_prev_logic_pwrst(cpu); pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); + pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state); set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume)); omap_pm_ops.scu_prepare(cpu, power_state); l2x0_pwrst_prepare(cpu, save_state); diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c index 68423e26399d..d937b2e4040b 100644 --- a/arch/arm/mach-omap2/omap2-restart.c +++ b/arch/arm/mach-omap2/omap2-restart.c @@ -15,7 +15,7 @@ #include "soc.h" #include "common.h" -#include "prm2xxx.h" +#include "prm.h" /* * reset_virt_prcm_set_ck, reset_sys_ck: pointers to the virt_prcm_set @@ -40,8 +40,7 @@ void omap2xxx_restart(enum reboot_mode mode, const char *cmd) /* XXX Should save the cmd argument for use after the reboot */ - omap2xxx_prm_dpll_reset(); /* never returns */ - while (1); + omap_prm_reset_system(); } /** diff --git a/arch/arm/mach-omap2/omap3-restart.c b/arch/arm/mach-omap2/omap3-restart.c index 5de2a0c2979d..103a49f68bcb 100644 --- a/arch/arm/mach-omap2/omap3-restart.c +++ b/arch/arm/mach-omap2/omap3-restart.c @@ -14,10 +14,8 @@ #include <linux/init.h> #include <linux/reboot.h> -#include "iomap.h" -#include "common.h" #include "control.h" -#include "prm3xxx.h" +#include "prm.h" /* Global address base setup code */ @@ -32,6 +30,5 @@ void omap3xxx_restart(enum reboot_mode mode, const char *cmd) { omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0)); - omap3xxx_prm_dpll3_reset(); /* never returns */ - while (1); + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 16b20cedc38d..b7cb44abe49b 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -36,7 +36,6 @@ #include "soc.h" #include "iomap.h" #include "common.h" -#include "mmc.h" #include "prminst44xx.h" #include "prcm_mpu44xx.h" #include "omap4-sar-layout.h" diff --git a/arch/arm/mach-omap2/omap4-restart.c b/arch/arm/mach-omap2/omap4-restart.c index 41dfd7da8170..a99e7f7fb5be 100644 --- a/arch/arm/mach-omap2/omap4-restart.c +++ b/arch/arm/mach-omap2/omap4-restart.c @@ -9,7 +9,7 @@ #include <linux/types.h> #include <linux/reboot.h> -#include "prminst44xx.h" +#include "prm.h" /** * omap44xx_restart - trigger a software restart of the SoC @@ -22,7 +22,5 @@ void omap44xx_restart(enum reboot_mode mode, const char *cmd) { /* XXX Should save 'cmd' into scratchpad for use after reboot */ - omap4_prminst_global_warm_sw_reset(); /* never returns */ - while (1) - ; + omap_prm_reset_system(); } diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c index d22c30d3ccfa..8c58b71c2727 100644 --- a/arch/arm/mach-omap2/omap_device.c +++ b/arch/arm/mach-omap2/omap_device.c @@ -917,6 +917,10 @@ static int __init omap_device_late_idle(struct device *dev, void *data) static int __init omap_device_late_init(void) { bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle); + + WARN(!of_have_populated_dt(), + "legacy booting deprecated, please update to boot with .dts\n"); + return 0; } omap_late_initcall_sync(omap_device_late_init); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 716247ed9e0c..cbb908dc5cf0 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -153,7 +153,6 @@ #include "powerdomain.h" #include "cm2xxx.h" #include "cm3xxx.h" -#include "cminst44xx.h" #include "cm33xx.h" #include "prm.h" #include "prm3xxx.h" @@ -979,31 +978,9 @@ static void _omap4_enable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s: %d\n", oh->name, __func__, oh->prcm.omap4.modulemode); - omap4_cminst_module_enable(oh->prcm.omap4.modulemode, - oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Enables the PRCM module mode related to the hwmod @oh. - * No return value. - */ -static void _am33xx_enable_module(struct omap_hwmod *oh) -{ - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return; - - pr_debug("omap_hwmod: %s: %s: %d\n", - oh->name, __func__, oh->prcm.omap4.modulemode); - - am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_enable(oh->prcm.omap4.modulemode, + oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs); } /** @@ -1026,35 +1003,9 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) if (oh->flags & HWMOD_NO_IDLEST) return 0; - return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to enter slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully enters - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_idle() function. - */ -static int _am33xx_wait_target_disable(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->_int_flags & _HWMOD_NO_MPU_PORT) - return 0; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_idle(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -1859,10 +1810,8 @@ static int _omap4_disable_module(struct omap_hwmod *oh) pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - omap4_cminst_module_disable(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs); v = _omap4_wait_target_disable(oh); if (v) @@ -1873,36 +1822,6 @@ static int _omap4_disable_module(struct omap_hwmod *oh) } /** - * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX - * @oh: struct omap_hwmod * - * - * Disable the PRCM module mode related to the hwmod @oh. - * Return EINVAL if the modulemode is not supported and 0 in case of success. - */ -static int _am33xx_disable_module(struct omap_hwmod *oh) -{ - int v; - - if (!oh->clkdm || !oh->prcm.omap4.modulemode) - return -EINVAL; - - pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); - - if (_are_any_hardreset_lines_asserted(oh)) - return 0; - - am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); - - v = _am33xx_wait_target_disable(oh); - if (v) - pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", - oh->name); - - return 0; -} - -/** * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit * @oh: struct omap_hwmod * * @@ -2065,10 +1984,7 @@ static void _reconfigure_io_chain(void) spin_lock_irqsave(&io_chain_lock, flags); - if (cpu_is_omap34xx()) - omap3xxx_prm_reconfigure_io_chain(); - else if (cpu_is_omap44xx()) - omap44xx_prm_reconfigure_io_chain(); + omap_prm_reconfigure_io_chain(); spin_unlock_irqrestore(&io_chain_lock, flags); } @@ -2719,11 +2635,33 @@ static int __init _setup(struct omap_hwmod *oh, void *data) if (oh->_state != _HWMOD_STATE_INITIALIZED) return 0; + if (oh->parent_hwmod) { + int r; + + r = _enable(oh->parent_hwmod); + WARN(r, "hwmod: %s: setup: failed to enable parent hwmod %s\n", + oh->name, oh->parent_hwmod->name); + } + _setup_iclk_autoidle(oh); if (!_setup_reset(oh)) _setup_postsetup(oh); + if (oh->parent_hwmod) { + u8 postsetup_state; + + postsetup_state = oh->parent_hwmod->_postsetup_state; + + if (postsetup_state == _HWMOD_STATE_IDLE) + _idle(oh->parent_hwmod); + else if (postsetup_state == _HWMOD_STATE_DISABLED) + _shutdown(oh->parent_hwmod); + else if (postsetup_state != _HWMOD_STATE_ENABLED) + WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", + oh->parent_hwmod->name, postsetup_state); + } + return 0; } @@ -2832,12 +2770,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi) _alloc_links(&ml, &sl); ml->ocp_if = oi; - INIT_LIST_HEAD(&ml->node); list_add(&ml->node, &oi->master->master_ports); oi->master->masters_cnt++; sl->ocp_if = oi; - INIT_LIST_HEAD(&sl->node); list_add(&sl->node, &oi->slave->slave_ports); oi->slave->slaves_cnt++; @@ -2927,34 +2863,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois) /* Static functions intended only for use in soc_ops field function pointers */ /** - * _omap2xxx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - - return omap2xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); -} - -/** - * _omap3xxx_wait_target_ready - wait for a module to leave slave idle + * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle * @oh: struct omap_hwmod * * * Wait for a module @oh to leave slave idle. Returns 0 if the module @@ -2962,7 +2871,7 @@ static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh) * slave idle; otherwise, pass along the return value of the * appropriate *_cm*_wait_module_ready() function. */ -static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh) +static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh) { if (!oh) return -EINVAL; @@ -2975,9 +2884,9 @@ static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status, enabled clocks */ - return omap3xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs, - oh->prcm.omap2.idlest_reg_id, - oh->prcm.omap2.idlest_idle_bit); + return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs, + oh->prcm.omap2.idlest_reg_id, + oh->prcm.omap2.idlest_idle_bit); } /** @@ -3002,37 +2911,9 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) /* XXX check module SIDLEMODE, hardreset status */ - return omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition, - oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); -} - -/** - * _am33xx_wait_target_ready - wait for a module to leave slave idle - * @oh: struct omap_hwmod * - * - * Wait for a module @oh to leave slave idle. Returns 0 if the module - * does not have an IDLEST bit or if the module successfully leaves - * slave idle; otherwise, pass along the return value of the - * appropriate *_cm*_wait_module_ready() function. - */ -static int _am33xx_wait_target_ready(struct omap_hwmod *oh) -{ - if (!oh || !oh->clkdm) - return -EINVAL; - - if (oh->flags & HWMOD_NO_IDLEST) - return 0; - - if (!_find_mpu_rt_port(oh)) - return 0; - - /* XXX check module SIDLEMODE, hardreset status */ - - return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst, - oh->clkdm->clkdm_offs, - oh->prcm.omap4.clkctrl_offs); + return omap_cm_wait_module_ready(oh->clkdm->prcm_partition, + oh->clkdm->cm_inst, + oh->prcm.omap4.clkctrl_offs, 0); } /** @@ -3049,8 +2930,8 @@ static int _am33xx_wait_target_ready(struct omap_hwmod *oh) static int _omap2_assert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift); + return omap_prm_assert_hardreset(ohri->rst_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -3067,9 +2948,8 @@ static int _omap2_assert_hardreset(struct omap_hwmod *oh, static int _omap2_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, - ohri->rst_shift, - ohri->st_shift); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0, 0); } /** @@ -3087,8 +2967,8 @@ static int _omap2_deassert_hardreset(struct omap_hwmod *oh, static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, - ohri->st_shift); + return omap_prm_is_hardreset_asserted(ohri->st_shift, 0, + oh->prcm.omap2.module_offs, 0); } /** @@ -3109,10 +2989,10 @@ static int _omap4_assert_hardreset(struct omap_hwmod *oh, if (!oh->clkdm) return -EINVAL; - return omap4_prminst_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_assert_hardreset(ohri->rst_shift, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3136,10 +3016,10 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh, if (ohri->st_shift) pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", oh->name, ohri->name); - return omap4_prminst_deassert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, 0); } /** @@ -3160,10 +3040,11 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh, if (!oh->clkdm) return -EINVAL; - return omap4_prminst_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_partition, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_is_hardreset_asserted(ohri->rst_shift, + oh->clkdm->pwrdm.ptr-> + prcm_partition, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3182,9 +3063,9 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_assert_hardreset(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_assert_hardreset(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /** @@ -3202,11 +3083,10 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh, static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_deassert_hardreset(ohri->rst_shift, - ohri->st_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs, - oh->prcm.omap4.rstst_offs); + return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs, + oh->prcm.omap4.rstst_offs); } /** @@ -3224,9 +3104,9 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, struct omap_hwmod_rst_info *ohri) { - return am33xx_prm_is_hardreset_asserted(ohri->rst_shift, - oh->clkdm->pwrdm.ptr->prcm_offs, - oh->prcm.omap4.rstctrl_offs); + return omap_prm_is_hardreset_asserted(ohri->rst_shift, 0, + oh->clkdm->pwrdm.ptr->prcm_offs, + oh->prcm.omap4.rstctrl_offs); } /* Public functions */ @@ -4234,12 +4114,12 @@ int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx) void __init omap_hwmod_init(void) { if (cpu_is_omap24xx()) { - soc_ops.wait_target_ready = _omap2xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; } else if (cpu_is_omap34xx()) { - soc_ops.wait_target_ready = _omap3xxx_wait_target_ready; + soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready; soc_ops.assert_hardreset = _omap2_assert_hardreset; soc_ops.deassert_hardreset = _omap2_deassert_hardreset; soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted; @@ -4258,14 +4138,14 @@ void __init omap_hwmod_init(void) soc_ops.enable_module = _omap4_enable_module; soc_ops.disable_module = _omap4_disable_module; soc_ops.wait_target_ready = _omap4_wait_target_ready; - soc_ops.assert_hardreset = _am33xx_assert_hardreset; - soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; - soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; + soc_ops.assert_hardreset = _omap4_assert_hardreset; + soc_ops.deassert_hardreset = _omap4_deassert_hardreset; + soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; soc_ops.init_clkdm = _init_clkdm; } else if (soc_is_am33xx()) { - soc_ops.enable_module = _am33xx_enable_module; - soc_ops.disable_module = _am33xx_disable_module; - soc_ops.wait_target_ready = _am33xx_wait_target_ready; + soc_ops.enable_module = _omap4_enable_module; + soc_ops.disable_module = _omap4_disable_module; + soc_ops.wait_target_ready = _omap4_wait_target_ready; soc_ops.assert_hardreset = _am33xx_assert_hardreset; soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 512f809a3f4d..35ca6efbec31 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -633,6 +633,7 @@ struct omap_hwmod_link { * @flags: hwmod flags (documented below) * @_lock: spinlock serializing operations on this hwmod * @node: list node for hwmod list (internal use) + * @parent_hwmod: (temporary) a pointer to the hierarchical parent of this hwmod * * @main_clk refers to this module's "main clock," which for our * purposes is defined as "the functional clock needed for register @@ -643,6 +644,12 @@ struct omap_hwmod_link { * the omap_hwmod code and should not be set during initialization. * * @masters and @slaves are now deprecated. + * + * @parent_hwmod is temporary; there should be no need for it, as this + * information should already be expressed in the OCP interface + * structures. @parent_hwmod is present as a workaround until we improve + * handling for hwmods with multiple parents (e.g., OMAP4+ DSS with + * multiple register targets across different interconnects). */ struct omap_hwmod { const char *name; @@ -680,6 +687,7 @@ struct omap_hwmod { u8 _int_flags; u8 _state; u8 _postsetup_state; + struct omap_hwmod *parent_hwmod; }; struct omap_hwmod *omap_hwmod_lookup(const char *name); diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index c2555cb95e71..79127b35fe60 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c @@ -15,12 +15,12 @@ #include <linux/i2c-omap.h> #include <linux/platform_data/asoc-ti-mcbsp.h> +#include <linux/platform_data/hsmmc-omap.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include <linux/omap-dma.h> #include <plat/dmtimer.h> #include "omap_hwmod.h" -#include "mmc.h" #include "l3_2xxx.h" #include "soc.h" @@ -372,7 +372,7 @@ static struct omap_hwmod_opt_clk omap2430_mmc1_opt_clks[] = { { .role = "dbck", .clk = "mmchsdb1_fck" }, }; -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c index a579b89ce9b7..cabc5695b504 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c @@ -15,10 +15,10 @@ */ #include <linux/platform_data/gpio-omap.h> +#include <linux/platform_data/hsmmc-omap.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include "omap_hwmod.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "cm33xx.h" #include "prm33xx.h" @@ -836,7 +836,7 @@ static struct omap_hwmod_class am33xx_mmc_hwmod_class = { }; /* mmc0 */ -static struct omap_mmc_dev_attr am33xx_mmc0_dev_attr = { +static struct omap_hsmmc_dev_attr am33xx_mmc0_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; @@ -854,7 +854,7 @@ struct omap_hwmod am33xx_mmc0_hwmod = { }; /* mmc1 */ -static struct omap_mmc_dev_attr am33xx_mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr am33xx_mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; @@ -872,7 +872,7 @@ struct omap_hwmod am33xx_mmc1_hwmod = { }; /* mmc2 */ -static struct omap_mmc_dev_attr am33xx_mmc2_dev_attr = { +static struct omap_hsmmc_dev_attr am33xx_mmc2_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; struct omap_hwmod am33xx_mmc2_hwmod = { diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c index 6b406ca4bd3b..0cf7b563dcd1 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c @@ -27,7 +27,6 @@ #include "prm33xx.h" #include "prm-regbits-33xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "omap_hwmod_33xx_43xx_common_data.h" diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 2a78b093c0ce..11468eea3871 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -18,6 +18,7 @@ #include <linux/i2c-omap.h> #include <linux/power/smartreflex.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/platform_data/hsmmc-omap.h> #include <linux/omap-dma.h> #include "l3_3xxx.h" @@ -37,7 +38,6 @@ #include "cm-regbits-34xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "serial.h" @@ -1786,12 +1786,12 @@ static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = { { .role = "dbck", .clk = "omap_32k_fck", }, }; -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; /* See 35xx errata 2.1.1.128 in SPRZ278F */ -static struct omap_mmc_dev_attr mmc1_pre_es3_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_pre_es3_dev_attr = { .flags = (OMAP_HSMMC_SUPPORTS_DUAL_VOLT | OMAP_HSMMC_BROKEN_MULTIBLOCK_READ), }; @@ -1854,7 +1854,7 @@ static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = { }; /* See 35xx errata 2.1.1.128 in SPRZ278F */ -static struct omap_mmc_dev_attr mmc2_pre_es3_dev_attr = { +static struct omap_hsmmc_dev_attr mmc2_pre_es3_dev_attr = { .flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c index fea01aa3ef42..5c6c8410160e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c @@ -417,6 +417,37 @@ static struct omap_hwmod am43xx_qspi_hwmod = { }, }; +/* + * 'adc/tsc' class + * TouchScreen Controller (Analog-To-Digital Converter) + */ +static struct omap_hwmod_class_sysconfig am43xx_adc_tsc_sysc = { + .rev_offs = 0x00, + .sysc_offs = 0x10, + .sysc_flags = SYSC_HAS_SIDLEMODE, + .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | + SIDLE_SMART_WKUP), + .sysc_fields = &omap_hwmod_sysc_type2, +}; + +static struct omap_hwmod_class am43xx_adc_tsc_hwmod_class = { + .name = "adc_tsc", + .sysc = &am43xx_adc_tsc_sysc, +}; + +static struct omap_hwmod am43xx_adc_tsc_hwmod = { + .name = "adc_tsc", + .class = &am43xx_adc_tsc_hwmod_class, + .clkdm_name = "l3s_tsc_clkdm", + .main_clk = "adc_tsc_fck", + .prcm = { + .omap4 = { + .clkctrl_offs = AM43XX_CM_WKUP_ADC_TSC_CLKCTRL_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + /* dss */ static struct omap_hwmod am43xx_dss_core_hwmod = { @@ -547,6 +578,13 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__gpio0 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +static struct omap_hwmod_ocp_if am43xx_l4_wkup__adc_tsc = { + .master = &am33xx_l4_wkup_hwmod, + .slave = &am43xx_adc_tsc_hwmod, + .clk = "dpll_core_m4_div2_ck", + .user = OCP_USER_MPU, +}; + static struct omap_hwmod_ocp_if am43xx_l4_hs__cpgmac0 = { .master = &am43xx_l4_hs_hwmod, .slave = &am33xx_cpgmac0_hwmod, @@ -789,6 +827,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = { &am43xx_l4_wkup__i2c1, &am43xx_l4_wkup__gpio0, &am43xx_l4_wkup__wd_timer1, + &am43xx_l4_wkup__adc_tsc, &am43xx_l3_s__qspi, &am33xx_l4_per__dcan0, &am33xx_l4_per__dcan1, diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 44e5634bba34..c314b3c31117 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -22,6 +22,7 @@ #include <linux/io.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/platform_data/hsmmc-omap.h> #include <linux/power/smartreflex.h> #include <linux/i2c-omap.h> @@ -39,7 +40,6 @@ #include "prm44xx.h" #include "prm-regbits-44xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" /* Base offset for all OMAP4 interrupts external to MPUSS */ @@ -589,6 +589,7 @@ static struct omap_hwmod omap44xx_dss_hwmod = { .omap4 = { .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET, .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, }, }, .opt_clks = dss_opt_clks, @@ -647,7 +648,8 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = { .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, }, }, - .dev_attr = &omap44xx_dss_dispc_dev_attr + .dev_attr = &omap44xx_dss_dispc_dev_attr, + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -701,6 +703,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = { }, .opt_clks = dss_dsi1_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* dss_dsi2 */ @@ -733,6 +736,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = { }, .opt_clks = dss_dsi2_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi2_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -790,6 +794,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = { }, .opt_clks = dss_hdmi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -819,7 +824,7 @@ static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = { }; static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = { - { .role = "ick", .clk = "dss_fck" }, + { .role = "ick", .clk = "l3_div_ck" }, }; static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { @@ -836,6 +841,7 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = { }, .opt_clks = dss_rfbi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks), + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -859,6 +865,7 @@ static struct omap_hwmod omap44xx_dss_venc_hwmod = { .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET, }, }, + .parent_hwmod = &omap44xx_dss_hwmod, }; /* @@ -1952,7 +1959,7 @@ static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = { }; /* mmc1 dev_attr */ -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; @@ -3671,7 +3678,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3707,7 +3714,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_dispc_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dispc_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3743,7 +3750,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_dsi1_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dsi1_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3779,7 +3786,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_dsi2_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_dsi2_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3815,7 +3822,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_hdmi_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_hdmi_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3851,7 +3858,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_rfbi_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_rfbi_dma_addrs, .user = OCP_USER_SDMA, }; @@ -3887,7 +3894,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = { static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_dss_venc_hwmod, - .clk = "dss_fck", + .clk = "l3_div_ck", .addr = omap44xx_dss_venc_dma_addrs, .user = OCP_USER_SDMA, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c index 1103aa0e0d29..3e9523084b2a 100644 --- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c @@ -19,6 +19,7 @@ #include <linux/io.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/platform_data/hsmmc-omap.h> #include <linux/power/smartreflex.h> #include <linux/i2c-omap.h> @@ -33,7 +34,6 @@ #include "cm2_54xx.h" #include "prm54xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" /* Base offset for all OMAP5 interrupts external to MPUSS */ @@ -421,6 +421,7 @@ static struct omap_hwmod omap54xx_dss_dispc_hwmod = { .opt_clks = dss_dispc_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dispc_opt_clks), .dev_attr = &dss_dispc_dev_attr, + .parent_hwmod = &omap54xx_dss_hwmod, }; /* @@ -462,6 +463,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_a_hwmod = { }, .opt_clks = dss_dsi1_a_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_a_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* dss_dsi1_c */ @@ -482,6 +484,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_c_hwmod = { }, .opt_clks = dss_dsi1_c_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_dsi1_c_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* @@ -521,6 +524,7 @@ static struct omap_hwmod omap54xx_dss_hdmi_hwmod = { }, .opt_clks = dss_hdmi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* @@ -560,6 +564,7 @@ static struct omap_hwmod omap54xx_dss_rfbi_hwmod = { }, .opt_clks = dss_rfbi_opt_clks, .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks), + .parent_hwmod = &omap54xx_dss_hwmod, }; /* @@ -1269,7 +1274,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = { }; /* mmc1 dev_attr */ -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c index 5684f112654b..ffd6604cd546 100644 --- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c @@ -19,6 +19,7 @@ #include <linux/io.h> #include <linux/platform_data/gpio-omap.h> +#include <linux/platform_data/hsmmc-omap.h> #include <linux/power/smartreflex.h> #include <linux/i2c-omap.h> @@ -33,7 +34,6 @@ #include "cm2_7xx.h" #include "prm7xx.h" #include "i2c.h" -#include "mmc.h" #include "wd_timer.h" #include "soc.h" @@ -1301,7 +1301,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = { }; /* mmc1 dev_attr */ -static struct omap_mmc_dev_attr mmc1_dev_attr = { +static struct omap_hsmmc_dev_attr mmc1_dev_attr = { .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT, }; @@ -2075,6 +2075,70 @@ static struct omap_hwmod dra7xx_uart6_hwmod = { }, }; +/* uart7 */ +static struct omap_hwmod dra7xx_uart7_hwmod = { + .name = "uart7", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "l4per2_clkdm", + .main_clk = "uart7_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_L4PER2_UART7_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_UART7_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + +/* uart8 */ +static struct omap_hwmod dra7xx_uart8_hwmod = { + .name = "uart8", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "l4per2_clkdm", + .main_clk = "uart8_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_L4PER2_UART8_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_UART8_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + +/* uart9 */ +static struct omap_hwmod dra7xx_uart9_hwmod = { + .name = "uart9", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "l4per2_clkdm", + .main_clk = "uart9_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_L4PER2_UART9_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_L4PER2_UART9_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + +/* uart10 */ +static struct omap_hwmod dra7xx_uart10_hwmod = { + .name = "uart10", + .class = &dra7xx_uart_hwmod_class, + .clkdm_name = "wkupaon_clkdm", + .main_clk = "uart10_gfclk_mux", + .flags = HWMOD_SWSUP_SIDLE_ACT, + .prcm = { + .omap4 = { + .clkctrl_offs = DRA7XX_CM_WKUPAON_UART10_CLKCTRL_OFFSET, + .context_offs = DRA7XX_RM_WKUPAON_UART10_CONTEXT_OFFSET, + .modulemode = MODULEMODE_SWCTRL, + }, + }, +}; + /* * 'usb_otg_ss' class * @@ -3095,6 +3159,38 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart6 = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_per2 -> uart7 */ +static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart7 = { + .master = &dra7xx_l4_per2_hwmod, + .slave = &dra7xx_uart7_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* l4_per2 -> uart8 */ +static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart8 = { + .master = &dra7xx_l4_per2_hwmod, + .slave = &dra7xx_uart8_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* l4_per2 -> uart9 */ +static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart9 = { + .master = &dra7xx_l4_per2_hwmod, + .slave = &dra7xx_uart9_hwmod, + .clk = "l3_iclk_div", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + +/* l4_wkup -> uart10 */ +static struct omap_hwmod_ocp_if dra7xx_l4_wkup__uart10 = { + .master = &dra7xx_l4_wkup_hwmod, + .slave = &dra7xx_uart10_hwmod, + .clk = "wkupaon_iclk_mux", + .user = OCP_USER_MPU | OCP_USER_SDMA, +}; + /* l4_per3 -> usb_otg_ss1 */ static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss1 = { .master = &dra7xx_l4_per3_hwmod, @@ -3259,6 +3355,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = { &dra7xx_l4_per1__uart4, &dra7xx_l4_per1__uart5, &dra7xx_l4_per1__uart6, + &dra7xx_l4_per2__uart7, + &dra7xx_l4_per2__uart8, + &dra7xx_l4_per2__uart9, + &dra7xx_l4_wkup__uart10, &dra7xx_l4_per3__usb_otg_ss1, &dra7xx_l4_per3__usb_otg_ss2, &dra7xx_l4_per3__usb_otg_ss3, diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c index 50640b38f0bf..1a19fa096bab 100644 --- a/arch/arm/mach-omap2/omap_phy_internal.c +++ b/arch/arm/mach-omap2/omap_phy_internal.c @@ -21,6 +21,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/types.h> #include <linux/delay.h> #include <linux/clk.h> @@ -97,13 +99,13 @@ void am35x_musb_phy_power(u8 on) omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); - pr_info(KERN_INFO "Waiting for PHY clock good...\n"); + pr_info("Waiting for PHY clock good...\n"); while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2) & CONF2_PHYCLKGD)) { cpu_relax(); if (time_after(jiffies, timeout)) { - pr_err(KERN_ERR "musb PHY clock good timed out\n"); + pr_err("musb PHY clock good timed out\n"); break; } } @@ -145,7 +147,7 @@ void am35x_set_mode(u8 musb_mode) devconf2 |= CONF2_NO_OVERRIDE; break; default: - pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode); + pr_info("Unsupported mode %u\n", musb_mode); } omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 503097c72b82..d697cecf762b 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -37,6 +37,16 @@ struct power_state { struct list_head node; }; +/** + * struct static_dep_map - Static dependency map + * @from: from clockdomain + * @to: to clockdomain + */ +struct static_dep_map { + const char *from; + const char *to; +}; + static u32 cpu_suspend_state = PWRDM_POWER_OFF; static LIST_HEAD(pwrst_list); @@ -148,94 +158,61 @@ static void omap_default_idle(void) omap_do_wfi(); } -/** - * omap4_init_static_deps - Add OMAP4 static dependencies - * - * Add needed static clockdomain dependencies on OMAP4 devices. - * Return: 0 on success or 'err' on failures +/* + * The dynamic dependency between MPUSS -> MEMIF and + * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as + * expected. The hardware recommendation is to enable static + * dependencies for these to avoid system lock ups or random crashes. + * The L4 wakeup depedency is added to workaround the OCP sync hardware + * BUG with 32K synctimer which lead to incorrect timer value read + * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which + * are part of L4 wakeup clockdomain. */ -static inline int omap4_init_static_deps(void) -{ - struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm; - struct clockdomain *ducati_clkdm, *l3_2_clkdm; - int ret = 0; - - if (omap_rev() == OMAP4430_REV_ES1_0) { - WARN(1, "Power Management not supported on OMAP4430 ES1.0\n"); - return -ENODEV; - } - - pr_err("Power Management for TI OMAP4.\n"); - /* - * OMAP4 chip PM currently works only with certain (newer) - * versions of bootloaders. This is due to missing code in the - * kernel to properly reset and initialize some devices. - * http://www.spinics.net/lists/arm-kernel/msg218641.html - */ - pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n"); - - ret = pwrdm_for_each(pwrdms_setup, NULL); - if (ret) { - pr_err("Failed to setup powerdomains\n"); - return ret; - } - - /* - * The dynamic dependency between MPUSS -> MEMIF and - * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as - * expected. The hardware recommendation is to enable static - * dependencies for these to avoid system lock ups or random crashes. - * The L4 wakeup depedency is added to workaround the OCP sync hardware - * BUG with 32K synctimer which lead to incorrect timer value read - * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which - * are part of L4 wakeup clockdomain. - */ - mpuss_clkdm = clkdm_lookup("mpuss_clkdm"); - emif_clkdm = clkdm_lookup("l3_emif_clkdm"); - l3_1_clkdm = clkdm_lookup("l3_1_clkdm"); - l3_2_clkdm = clkdm_lookup("l3_2_clkdm"); - ducati_clkdm = clkdm_lookup("ducati_clkdm"); - if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) || - (!l3_2_clkdm) || (!ducati_clkdm)) - return -EINVAL; - - ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); - ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm); - ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm); - ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm); - ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm); - if (ret) { - pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n"); - return -EINVAL; - } +static const struct static_dep_map omap4_static_dep_map[] = { + {.from = "mpuss_clkdm", .to = "l3_emif_clkdm"}, + {.from = "mpuss_clkdm", .to = "l3_1_clkdm"}, + {.from = "mpuss_clkdm", .to = "l3_2_clkdm"}, + {.from = "ducati_clkdm", .to = "l3_1_clkdm"}, + {.from = "ducati_clkdm", .to = "l3_2_clkdm"}, + {.from = NULL} /* TERMINATION */ +}; - return ret; -} +static const struct static_dep_map omap5_dra7_static_dep_map[] = { + {.from = "mpu_clkdm", .to = "emif_clkdm"}, + {.from = NULL} /* TERMINATION */ +}; /** - * omap5_dra7_init_static_deps - Init static clkdm dependencies on OMAP5 and - * DRA7 - * - * The dynamic dependency between MPUSS -> EMIF is broken and has - * not worked as expected. The hardware recommendation is to - * enable static dependencies for these to avoid system - * lock ups or random crashes. + * omap4plus_init_static_deps() - Initialize a static dependency map + * @map: Mapping of clock domains */ -static inline int omap5_dra7_init_static_deps(void) +static inline int omap4plus_init_static_deps(const struct static_dep_map *map) { - struct clockdomain *mpuss_clkdm, *emif_clkdm; int ret; + struct clockdomain *from, *to; + + if (!map) + return 0; - mpuss_clkdm = clkdm_lookup("mpu_clkdm"); - emif_clkdm = clkdm_lookup("emif_clkdm"); - if (!mpuss_clkdm || !emif_clkdm) - return -EINVAL; + while (map->from) { + from = clkdm_lookup(map->from); + to = clkdm_lookup(map->to); + if (!from || !to) { + pr_err("Failed lookup %s or %s for wakeup dependency\n", + map->from, map->to); + return -EINVAL; + } + ret = clkdm_add_wkdep(from, to); + if (ret) { + pr_err("Failed to add %s -> %s wakeup dependency(%d)\n", + map->from, map->to, ret); + return ret; + } - ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm); - if (ret) - pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n"); + map++; + }; - return ret; + return 0; } /** @@ -272,6 +249,15 @@ int __init omap4_pm_init(void) pr_info("Power Management for TI OMAP4+ devices.\n"); + /* + * OMAP4 chip PM currently works only with certain (newer) + * versions of bootloaders. This is due to missing code in the + * kernel to properly reset and initialize some devices. + * http://www.spinics.net/lists/arm-kernel/msg218641.html + */ + if (cpu_is_omap44xx()) + pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n"); + ret = pwrdm_for_each(pwrdms_setup, NULL); if (ret) { pr_err("Failed to setup powerdomains.\n"); @@ -279,9 +265,9 @@ int __init omap4_pm_init(void) } if (cpu_is_omap44xx()) - ret = omap4_init_static_deps(); + ret = omap4plus_init_static_deps(omap4_static_dep_map); else if (soc_is_omap54xx() || soc_is_dra7xx()) - ret = omap5_dra7_init_static_deps(); + ret = omap4plus_init_static_deps(omap5_dra7_static_dep_map); if (ret) { pr_err("Failed to initialise static dependencies.\n"); diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 48480d557b61..77752e49d8d4 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h @@ -29,6 +29,7 @@ int of_prcm_init(void); * PRM_HAS_VOLTAGE: has voltage domains */ #define PRM_HAS_IO_WAKEUP (1 << 0) +#define PRM_HAS_VOLTAGE (1 << 1) /* * MAX_MODULE_SOFTRESET_WAIT: Maximum microseconds to wait for OMAP @@ -127,6 +128,8 @@ struct prm_reset_src_map { * @was_any_context_lost_old: ptr to the SoC PRM context loss test fn * @clear_context_loss_flags_old: ptr to the SoC PRM context loss flag clear fn * @late_init: ptr to the late init function + * @assert_hardreset: ptr to the SoC PRM hardreset assert impl + * @deassert_hardreset: ptr to the SoC PRM hardreset deassert impl * * XXX @was_any_context_lost_old and @clear_context_loss_flags_old are * deprecated. @@ -136,14 +139,27 @@ struct prm_ll_data { bool (*was_any_context_lost_old)(u8 part, s16 inst, u16 idx); void (*clear_context_loss_flags_old)(u8 part, s16 inst, u16 idx); int (*late_init)(void); + int (*assert_hardreset)(u8 shift, u8 part, s16 prm_mod, u16 offset); + int (*deassert_hardreset)(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset); + int (*is_hardreset_asserted)(u8 shift, u8 part, s16 prm_mod, + u16 offset); + void (*reset_system)(void); }; extern int prm_register(struct prm_ll_data *pld); extern int prm_unregister(struct prm_ll_data *pld); +int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset); +int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset); +int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset); extern u32 prm_read_reset_sources(void); extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx); extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx); +void omap_prm_reset_system(void); + +void omap_prm_reconfigure_io_chain(void); #endif diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c index 86958050547a..af0f15278fc2 100644 --- a/arch/arm/mach-omap2/prm2xxx.c +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -106,7 +106,7 @@ static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) * Set the DPLL reset bit, which should reboot the SoC. This is the * recommended way to restart the SoC. No return value. */ -void omap2xxx_prm_dpll_reset(void) +static void omap2xxx_prm_dpll_reset(void) { omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, OMAP2_RM_RSTCTRL); @@ -212,6 +212,10 @@ struct pwrdm_ops omap2_pwrdm_operations = { static struct prm_ll_data omap2xxx_prm_ll_data = { .read_reset_sources = &omap2xxx_prm_read_reset_sources, + .assert_hardreset = &omap2_prm_assert_hardreset, + .deassert_hardreset = &omap2_prm_deassert_hardreset, + .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, + .reset_system = &omap2xxx_prm_dpll_reset, }; int __init omap2xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm2xxx.h b/arch/arm/mach-omap2/prm2xxx.h index d73414139292..1d51643062f7 100644 --- a/arch/arm/mach-omap2/prm2xxx.h +++ b/arch/arm/mach-omap2/prm2xxx.h @@ -124,7 +124,6 @@ extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm); extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm); -extern void omap2xxx_prm_dpll_reset(void); void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask); extern int __init omap2xxx_prm_init(void); diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index c13b4e293ffa..cc3341f263cd 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c @@ -24,14 +24,16 @@ /** * omap2_prm_is_hardreset_asserted - read the HW reset line state of * submodules contained in the hwmod module - * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @shift: register bit shift corresponding to the reset line to check + * @part: PRM partition, ignored for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @offset: register offset, ignored for OMAP2 * * Returns 1 if the (sub)module hardreset line is currently asserted, * 0 if the (sub)module hardreset line is not currently asserted, or * -EINVAL if called while running on a non-OMAP2/3 chip. */ -int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) +int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) { return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, (1 << shift)); @@ -39,8 +41,10 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) /** * omap2_prm_assert_hardreset - assert the HW reset line of a submodule - * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @shift: register bit shift corresponding to the reset line to assert + * @part: PRM partition, ignored for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @offset: register offset, ignored for OMAP2 * * Some IPs like dsp or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -49,7 +53,7 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) * place the submodule into reset. Returns 0 upon success or -EINVAL * upon an argument error. */ -int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) +int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) { u32 mask; @@ -64,6 +68,10 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) * @prm_mod: PRM submodule base (e.g. CORE_MOD) * @rst_shift: register bit shift corresponding to the reset line to deassert * @st_shift: register bit shift for the status of the deasserted submodule + * @part: PRM partition, not used for OMAP2 + * @prm_mod: PRM submodule base (e.g. CORE_MOD) + * @rst_offset: reset register offset, not used for OMAP2 + * @st_offset: reset status register offset, not used for OMAP2 * * Some IPs like dsp or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -74,7 +82,8 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift) +int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, + s16 prm_mod, u16 rst_offset, u16 st_offset) { u32 rst, st; int c; diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index 1a3a96392b97..f57e29b0e041 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h @@ -100,9 +100,12 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) } /* These omap2_ PRM functions apply to both OMAP2 and 3 */ -extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); -extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); -extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); +int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset); +int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, + u16 offset); +int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part, + s16 prm_mod, u16 reset_offset, + u16 st_offset); extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst); extern int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm); diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 62709cd2f9c5..02f628601b09 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -23,20 +23,24 @@ #include "prm33xx.h" #include "prm-regbits-33xx.h" +#define AM33XX_PRM_RSTCTRL_OFFSET 0x0000 + +#define AM33XX_RST_GLOBAL_WARM_SW_MASK (1 << 0) + /* Read a register in a PRM instance */ -u32 am33xx_prm_read_reg(s16 inst, u16 idx) +static u32 am33xx_prm_read_reg(s16 inst, u16 idx) { return readl_relaxed(prm_base + inst + idx); } /* Write into a register in a PRM instance */ -void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) +static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx) { writel_relaxed(val, prm_base + inst + idx); } /* Read-modify-write a register in PRM. Caller must lock */ -u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) +static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) { u32 v; @@ -52,6 +56,7 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) * am33xx_prm_is_hardreset_asserted - read the HW reset line state of * submodules contained in the hwmod module * @shift: register bit shift corresponding to the reset line to check + * @part: PRM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_offs: RM_RSTCTRL register address offset for this module * @@ -59,7 +64,8 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx) * 0 if the (sub)module hardreset line is not currently asserted, or * -EINVAL upon parameter error. */ -int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) +static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst, + u16 rstctrl_offs) { u32 v; @@ -73,6 +79,7 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) /** * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule * @shift: register bit shift corresponding to the reset line to assert + * @part: CM partition, ignored for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_reg: RM_RSTCTRL register address for this module * @@ -83,7 +90,8 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs) * place the submodule into reset. Returns 0 upon success or -EINVAL * upon an argument error. */ -int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) +static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst, + u16 rstctrl_offs) { u32 mask = 1 << shift; @@ -96,6 +104,8 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and * wait * @shift: register bit shift corresponding to the reset line to deassert + * @st_shift: reset status register bit shift corresponding to the reset line + * @part: PRM partition, not used for AM33xx * @inst: CM instance register offset (*_INST macro) * @rstctrl_reg: RM_RSTCTRL register address for this module * @rstst_reg: RM_RSTST register address for this module @@ -109,14 +119,15 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs) * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, - u16 rstctrl_offs, u16 rstst_offs) +static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, + s16 inst, u16 rstctrl_offs, + u16 rstst_offs) { int c; u32 mask = 1 << st_shift; /* Check the current status to avoid de-asserting the line twice */ - if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0) + if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0) return -EEXIST; /* Clear the reset status by writing 1 to the status bit */ @@ -128,7 +139,7 @@ int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs); /* wait the status to be set */ - omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, inst, + omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst, rstst_offs), MAX_MODULE_HARDRESET_WAIT, c); @@ -325,6 +336,23 @@ static int am33xx_check_vcvp(void) return 0; } +/** + * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset + * + * Immediately reboots the device through warm reset. + */ +static void am33xx_prm_global_warm_sw_reset(void) +{ + am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK, + AM33XX_RST_GLOBAL_WARM_SW_MASK, + AM33XX_PRM_DEVICE_MOD, + AM33XX_PRM_RSTCTRL_OFFSET); + + /* OCP barrier */ + (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD, + AM33XX_PRM_RSTCTRL_OFFSET); +} + struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst, .pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst, @@ -342,3 +370,21 @@ struct pwrdm_ops am33xx_pwrdm_operations = { .pwrdm_wait_transition = am33xx_pwrdm_wait_transition, .pwrdm_has_voltdm = am33xx_check_vcvp, }; + +static struct prm_ll_data am33xx_prm_ll_data = { + .assert_hardreset = am33xx_prm_assert_hardreset, + .deassert_hardreset = am33xx_prm_deassert_hardreset, + .is_hardreset_asserted = am33xx_prm_is_hardreset_asserted, + .reset_system = am33xx_prm_global_warm_sw_reset, +}; + +int __init am33xx_prm_init(void) +{ + return prm_register(&am33xx_prm_ll_data); +} + +static void __exit am33xx_prm_exit(void) +{ + prm_unregister(&am33xx_prm_ll_data); +} +__exitcall(am33xx_prm_exit); diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index 9b9918dfb119..98ac41f271da 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -118,14 +118,7 @@ #define AM33XX_PM_CEFUSE_PWRSTST AM33XX_PRM_REGADDR(AM33XX_PRM_CEFUSE_MOD, 0x0004) #ifndef __ASSEMBLER__ -extern u32 am33xx_prm_read_reg(s16 inst, u16 idx); -extern void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx); -extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); -extern void am33xx_prm_global_warm_sw_reset(void); -extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, - u16 rstctrl_offs); -extern int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs); -extern int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst, - u16 rstctrl_offs, u16 rstst_offs); +int am33xx_prm_init(void); + #endif /* ASSEMBLER */ #endif diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c index ff08da385a2d..c5e00c6714b1 100644 --- a/arch/arm/mach-omap2/prm3xxx.c +++ b/arch/arm/mach-omap2/prm3xxx.c @@ -30,6 +30,11 @@ #include "cm3xxx.h" #include "cm-regbits-34xx.h" +static void omap3xxx_prm_read_pending_irqs(unsigned long *events); +static void omap3xxx_prm_ocp_barrier(void); +static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); +static void omap3xxx_prm_restore_irqen(u32 *saved_mask); + static const struct omap_prcm_irq omap3_prcm_irqs[] = { OMAP_PRCM_IRQ("wkup", 0, 0), OMAP_PRCM_IRQ("io", 9, 1), @@ -131,7 +136,7 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset) * recommended way to restart the SoC, considering Errata i520. No * return value. */ -void omap3xxx_prm_dpll3_reset(void) +static void omap3xxx_prm_dpll3_reset(void) { omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, OMAP3430_GR_MOD, OMAP2_RM_RSTCTRL); @@ -147,7 +152,7 @@ void omap3xxx_prm_dpll3_reset(void) * MPU IRQs, and store the result into the u32 pointed to by @events. * No return value. */ -void omap3xxx_prm_read_pending_irqs(unsigned long *events) +static void omap3xxx_prm_read_pending_irqs(unsigned long *events) { u32 mask, st; @@ -166,7 +171,7 @@ void omap3xxx_prm_read_pending_irqs(unsigned long *events) * block, to avoid race conditions after acknowledging or clearing IRQ * bits. No return value. */ -void omap3xxx_prm_ocp_barrier(void) +static void omap3xxx_prm_ocp_barrier(void) { omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET); } @@ -182,7 +187,7 @@ void omap3xxx_prm_ocp_barrier(void) * returning; otherwise, spurious interrupts might occur. No return * value. */ -void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) +static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) { saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); @@ -202,7 +207,7 @@ void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask) * barrier should be needed here; any pending PRM interrupts will fire * once the writes reach the PRM. No return value. */ -void omap3xxx_prm_restore_irqen(u32 *saved_mask) +static void omap3xxx_prm_restore_irqen(u32 *saved_mask) { omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); @@ -375,7 +380,7 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva) * The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only * thing we can do is toggle EN_IO bit for earlier omaps. */ -void omap3430_pre_es3_1_reconfigure_io_chain(void) +static void omap3430_pre_es3_1_reconfigure_io_chain(void) { omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN); @@ -393,7 +398,7 @@ void omap3430_pre_es3_1_reconfigure_io_chain(void) * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No * return value. These registers are only available in 3430 es3.1 and later. */ -void omap3_prm_reconfigure_io_chain(void) +static void omap3_prm_reconfigure_io_chain(void) { int i = 0; @@ -416,15 +421,6 @@ void omap3_prm_reconfigure_io_chain(void) } /** - * omap3xxx_prm_reconfigure_io_chain - reconfigure I/O chain - */ -void omap3xxx_prm_reconfigure_io_chain(void) -{ - if (omap3_prcm_irq_setup.reconfigure_io_chain) - omap3_prcm_irq_setup.reconfigure_io_chain(); -} - -/** * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches * * Activates the I/O wakeup event latches and allows events logged by @@ -664,6 +660,10 @@ static int omap3xxx_prm_late_init(void); static struct prm_ll_data omap3xxx_prm_ll_data = { .read_reset_sources = &omap3xxx_prm_read_reset_sources, .late_init = &omap3xxx_prm_late_init, + .assert_hardreset = &omap2_prm_assert_hardreset, + .deassert_hardreset = &omap2_prm_deassert_hardreset, + .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, + .reset_system = &omap3xxx_prm_dpll3_reset, }; int __init omap3xxx_prm_init(void) diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h index bc37d42a8704..cfde3f4a03cc 100644 --- a/arch/arm/mach-omap2/prm3xxx.h +++ b/arch/arm/mach-omap2/prm3xxx.h @@ -144,22 +144,6 @@ extern u32 omap3_prm_vcvp_read(u8 offset); extern void omap3_prm_vcvp_write(u32 val, u8 offset); extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); -#ifdef CONFIG_ARCH_OMAP3 -void omap3xxx_prm_reconfigure_io_chain(void); -#else -static inline void omap3xxx_prm_reconfigure_io_chain(void) -{ -} -#endif - -/* PRM interrupt-related functions */ -extern void omap3xxx_prm_read_pending_irqs(unsigned long *events); -extern void omap3xxx_prm_ocp_barrier(void); -extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); -extern void omap3xxx_prm_restore_irqen(u32 *saved_mask); - -extern void omap3xxx_prm_dpll3_reset(void); - extern int __init omap3xxx_prm_init(void); extern u32 omap3xxx_prm_get_reset_sources(void); int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits); diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index 0958d070d3db..cc170fb81ff7 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c @@ -32,6 +32,12 @@ /* Static data */ +static void omap44xx_prm_read_pending_irqs(unsigned long *events); +static void omap44xx_prm_ocp_barrier(void); +static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask); +static void omap44xx_prm_restore_irqen(u32 *saved_mask); +static void omap44xx_prm_reconfigure_io_chain(void); + static const struct omap_prcm_irq omap4_prcm_irqs[] = { OMAP_PRCM_IRQ("io", 9, 1), }; @@ -80,19 +86,19 @@ static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = { /* PRM low-level functions */ /* Read a register in a CM/PRM instance in the PRM module */ -u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) +static u32 omap4_prm_read_inst_reg(s16 inst, u16 reg) { return readl_relaxed(prm_base + inst + reg); } /* Write into a register in a CM/PRM instance in the PRM module */ -void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) +static void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg) { writel_relaxed(val, prm_base + inst + reg); } /* Read-modify-write a register in a PRM module. Caller must lock */ -u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) +static u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg) { u32 v; @@ -207,7 +213,7 @@ static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs) * MPU IRQs, and store the result into the two u32s pointed to by @events. * No return value. */ -void omap44xx_prm_read_pending_irqs(unsigned long *events) +static void omap44xx_prm_read_pending_irqs(unsigned long *events) { events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET, OMAP4_PRM_IRQSTATUS_MPU_OFFSET); @@ -224,7 +230,7 @@ void omap44xx_prm_read_pending_irqs(unsigned long *events) * block, to avoid race conditions after acknowledging or clearing IRQ * bits. No return value. */ -void omap44xx_prm_ocp_barrier(void) +static void omap44xx_prm_ocp_barrier(void) { omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_REVISION_PRM_OFFSET); @@ -241,7 +247,7 @@ void omap44xx_prm_ocp_barrier(void) * interrupts reaches the PRM before returning; otherwise, spurious * interrupts might occur. No return value. */ -void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) +static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) { saved_mask[0] = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST, @@ -270,7 +276,7 @@ void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask) * No OCP barrier should be needed here; any pending PRM interrupts will fire * once the writes reach the PRM. No return value. */ -void omap44xx_prm_restore_irqen(u32 *saved_mask) +static void omap44xx_prm_restore_irqen(u32 *saved_mask) { omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_OCP_SOCKET_INST, OMAP4_PRM_IRQENABLE_MPU_OFFSET); @@ -287,7 +293,7 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask) * deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted. * No return value. XXX Are the final two steps necessary? */ -void omap44xx_prm_reconfigure_io_chain(void) +static void omap44xx_prm_reconfigure_io_chain(void) { int i = 0; s32 inst = omap4_prmst_get_prm_dev_inst(); @@ -652,11 +658,10 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm) static int omap4_check_vcvp(void) { - /* No VC/VP on dra7xx devices */ - if (soc_is_dra7xx()) - return 0; + if (prm_features & PRM_HAS_VOLTAGE) + return 1; - return 1; + return 0; } struct pwrdm_ops omap4_pwrdm_operations = { @@ -689,6 +694,10 @@ static struct prm_ll_data omap44xx_prm_ll_data = { .was_any_context_lost_old = &omap44xx_prm_was_any_context_lost_old, .clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old, .late_init = &omap44xx_prm_late_init, + .assert_hardreset = omap4_prminst_assert_hardreset, + .deassert_hardreset = omap4_prminst_deassert_hardreset, + .is_hardreset_asserted = omap4_prminst_is_hardreset_asserted, + .reset_system = omap4_prminst_global_warm_sw_reset, }; int __init omap44xx_prm_init(void) @@ -696,6 +705,9 @@ int __init omap44xx_prm_init(void) if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) prm_features |= PRM_HAS_IO_WAKEUP; + if (!soc_is_dra7xx()) + prm_features |= PRM_HAS_VOLTAGE; + return prm_register(&omap44xx_prm_ll_data); } diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h index 8d95aa543ef5..f7512515fde5 100644 --- a/arch/arm/mach-omap2/prm44xx_54xx.h +++ b/arch/arm/mach-omap2/prm44xx_54xx.h @@ -26,10 +26,6 @@ /* Function prototypes */ #ifndef __ASSEMBLER__ -extern u32 omap4_prm_read_inst_reg(s16 inst, u16 idx); -extern void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 idx); -extern u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx); - /* OMAP4/OMAP5-specific VP functions */ u32 omap4_prm_vp_check_txdone(u8 vp_id); void omap4_prm_vp_clear_txdone(u8 vp_id); @@ -42,21 +38,6 @@ extern u32 omap4_prm_vcvp_read(u8 offset); extern void omap4_prm_vcvp_write(u32 val, u8 offset); extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); -#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ - defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX) -void omap44xx_prm_reconfigure_io_chain(void); -#else -static inline void omap44xx_prm_reconfigure_io_chain(void) -{ -} -#endif - -/* PRM interrupt-related functions */ -extern void omap44xx_prm_read_pending_irqs(unsigned long *events); -extern void omap44xx_prm_ocp_barrier(void); -extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask); -extern void omap44xx_prm_restore_irqen(u32 *saved_mask); - extern int __init omap44xx_prm_init(void); extern u32 omap44xx_prm_get_reset_sources(void); diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c index ee2b5222eac0..779940cb6e56 100644 --- a/arch/arm/mach-omap2/prm_common.c +++ b/arch/arm/mach-omap2/prm_common.c @@ -423,6 +423,105 @@ void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx) } /** + * omap_prm_assert_hardreset - assert hardreset for an IP block + * @shift: register bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * + * Asserts a hardware reset line for an IP block. + */ +int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset) +{ + if (!prm_ll_data->assert_hardreset) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset); +} + +/** + * omap_prm_deassert_hardreset - deassert hardreset for an IP block + * @shift: register bit shift corresponding to the reset line + * @st_shift: reset status bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * @st_offset: status register offset + * + * Deasserts a hardware reset line for an IP block. + */ +int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod, + u16 offset, u16 st_offset) +{ + if (!prm_ll_data->deassert_hardreset) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->deassert_hardreset(shift, st_shift, part, prm_mod, + offset, st_offset); +} + +/** + * omap_prm_is_hardreset_asserted - check the hardreset status for an IP block + * @shift: register bit shift corresponding to the reset line + * @part: PRM partition + * @prm_mod: PRM submodule base or instance offset + * @offset: register offset + * + * Checks if a hardware reset line for an IP block is enabled or not. + */ +int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset) +{ + if (!prm_ll_data->is_hardreset_asserted) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return -EINVAL; + } + + return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset); +} + +/** + * omap_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain + * + * Clear any previously-latched I/O wakeup events and ensure that the + * I/O wakeup gates are aligned with the current mux settings. + * Calls SoC specific I/O chain reconfigure function if available, + * otherwise does nothing. + */ +void omap_prm_reconfigure_io_chain(void) +{ + if (!prcm_irq_setup || !prcm_irq_setup->reconfigure_io_chain) + return; + + prcm_irq_setup->reconfigure_io_chain(); +} + +/** + * omap_prm_reset_system - trigger global SW reset + * + * Triggers SoC specific global warm reset to reboot the device. + */ +void omap_prm_reset_system(void) +{ + if (!prm_ll_data->reset_system) { + WARN_ONCE(1, "prm: %s: no mapping function defined\n", + __func__); + return; + } + + prm_ll_data->reset_system(); + + while (1) + cpu_relax(); +} + +/** * prm_register - register per-SoC low-level data with the PRM * @pld: low-level per-SoC OMAP PRM data & function pointers to register * diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c index 225e0258d76d..8adf7b1a1dce 100644 --- a/arch/arm/mach-omap2/prminst44xx.c +++ b/arch/arm/mach-omap2/prminst44xx.c @@ -148,8 +148,12 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, /** * omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and * wait - * @rstctrl_reg: RM_RSTCTRL register address for this module * @shift: register bit shift corresponding to the reset line to deassert + * @st_shift: status bit offset, not used for OMAP4+ + * @part: PRM partition + * @inst: PRM instance offset + * @rstctrl_offs: reset register offset + * @st_offs: reset status register offset, not used for OMAP4+ * * Some IPs like dsp, ipu or iva contain processors that require an HW * reset line to be asserted / deasserted in order to fully enable the @@ -160,8 +164,8 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, * -EINVAL upon an argument error, -EEXIST if the submodule was already out * of reset, or -EBUSY if the submodule did not exit reset promptly. */ -int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, - u16 rstctrl_offs) +int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst, + u16 rstctrl_offs, u16 st_offs) { int c; u32 mask = 1 << shift; diff --git a/arch/arm/mach-omap2/prminst44xx.h b/arch/arm/mach-omap2/prminst44xx.h index 583aa3774571..fb1c9d7a2f9d 100644 --- a/arch/arm/mach-omap2/prminst44xx.h +++ b/arch/arm/mach-omap2/prminst44xx.h @@ -30,8 +30,9 @@ extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst, u16 rstctrl_offs); extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst, u16 rstctrl_offs); -extern int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst, - u16 rstctrl_offs); +int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, + s16 inst, u16 rstctrl_offs, + u16 rstst_offs); extern void omap_prm_base_init(void); diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index a388f8c1bcb3..57dee0c7cd2b 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -263,9 +263,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, omap_up.dma_rx_timeout = info->dma_rx_timeout; omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate; omap_up.autosuspend_timeout = info->autosuspend_timeout; - omap_up.DTR_gpio = info->DTR_gpio; - omap_up.DTR_inverted = info->DTR_inverted; - omap_up.DTR_present = info->DTR_present; pdata = &omap_up; pdata_size = sizeof(struct omap_uart_port_info); diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index e6690a44917d..83efe914bf7d 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -4,6 +4,17 @@ menu "Intel PXA2xx/PXA3xx Implementations" comment "Intel/Marvell Dev Platforms (sorted by hardware release time)" +config MACH_PXA27X_DT + bool "Support PXA27x platforms from device tree" + select CPU_PXA27x + select POWER_SUPPLY + select PXA27x + select USE_OF + help + Include support for Marvell PXA27x based platforms using + the device tree. Needn't select any other machine while + MACH_PXA27X_DT is enabled. + config MACH_PXA3XX_DT bool "Support PXA3xx platforms from device tree" select CPU_PXA300 diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 2fe1824c6dcb..eb0bf7678a99 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o # Device Tree support obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o +obj-$(CONFIG_MACH_PXA27X_DT) += pxa-dt.o # Intel/Marvell Dev Platforms obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 6915a9f6b3a3..51531ecffca8 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -378,7 +378,7 @@ static void __init em_x270_init_nand(void) err = gpio_request(GPIO11_NAND_CS, "NAND CS"); if (err) { - pr_warning("EM-X270: failed to request NAND CS gpio\n"); + pr_warn("EM-X270: failed to request NAND CS gpio\n"); return; } @@ -386,7 +386,7 @@ static void __init em_x270_init_nand(void) err = gpio_request(nand_rb, "NAND R/B"); if (err) { - pr_warning("EM-X270: failed to request NAND R/B gpio\n"); + pr_warn("EM-X270: failed to request NAND R/B gpio\n"); gpio_free(GPIO11_NAND_CS); return; } diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index 8963984d1f43..7a9fa1aa4e41 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h @@ -13,11 +13,11 @@ struct irq_data; -extern void pxa_timer_init(void); - -extern void __init pxa_map_io(void); - extern unsigned int get_clk_frequency_khz(int info); +extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, + unsigned int)); +extern void __init pxa_map_io(void); +extern void pxa_timer_init(void); #define SET_BANK(__nr,__start,__size) \ mi->bank[__nr].start = (__start), \ @@ -25,6 +25,43 @@ extern unsigned int get_clk_frequency_khz(int info); #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) +#define pxa25x_handle_irq icip_handle_irq +extern void __init pxa25x_init_irq(void); +extern void __init pxa25x_map_io(void); +extern void __init pxa26x_init_irq(void); + +#define pxa27x_handle_irq ichp_handle_irq +extern void __init pxa27x_dt_init_irq(void); +extern unsigned pxa27x_get_clk_frequency_khz(int); +extern void __init pxa27x_init_irq(void); +extern void __init pxa27x_map_io(void); + +#define pxa3xx_handle_irq ichp_handle_irq +extern void __init pxa3xx_dt_init_irq(void); +extern void __init pxa3xx_init_irq(void); +extern void __init pxa3xx_map_io(void); + +extern struct syscore_ops pxa_irq_syscore_ops; +extern struct syscore_ops pxa2xx_mfp_syscore_ops; +extern struct syscore_ops pxa3xx_mfp_syscore_ops; + +void __init pxa_set_ffuart_info(void *info); +void __init pxa_set_btuart_info(void *info); +void __init pxa_set_stuart_info(void *info); +void __init pxa_set_hwuart_info(void *info); + +void pxa_restart(enum reboot_mode, const char *); + +#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) +extern void pxa2xx_clear_reset_status(unsigned int); +#else +static inline void pxa2xx_clear_reset_status(unsigned int mask) {} +#endif + +/* + * Once fully converted to the clock framework, all these functions should be + * removed, and replaced with a clk_get(NULL, "core"). + */ #ifdef CONFIG_PXA25x extern unsigned pxa25x_get_clk_frequency_khz(int); #else @@ -32,30 +69,12 @@ extern unsigned pxa25x_get_clk_frequency_khz(int); #endif #ifdef CONFIG_PXA27x -extern unsigned pxa27x_get_clk_frequency_khz(int); #else #define pxa27x_get_clk_frequency_khz(x) (0) #endif -#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x) -extern void pxa2xx_clear_reset_status(unsigned int); -#else -static inline void pxa2xx_clear_reset_status(unsigned int mask) {} -#endif - #ifdef CONFIG_PXA3xx -extern unsigned pxa3xx_get_clk_frequency_khz(int); +extern unsigned pxa3xx_get_clk_frequency_khz(int); #else #define pxa3xx_get_clk_frequency_khz(x) (0) #endif - -extern struct syscore_ops pxa_irq_syscore_ops; -extern struct syscore_ops pxa2xx_mfp_syscore_ops; -extern struct syscore_ops pxa3xx_mfp_syscore_ops; - -void __init pxa_set_ffuart_info(void *info); -void __init pxa_set_btuart_info(void *info); -void __init pxa_set_stuart_info(void *info); -void __init pxa_set_hwuart_info(void *info); - -void pxa_restart(enum reboot_mode, const char *); diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c index 00b92dad7b81..f6c76a3ee3b2 100644 --- a/arch/arm/mach-pxa/gumstix.c +++ b/arch/arm/mach-pxa/gumstix.c @@ -140,8 +140,7 @@ static void gumstix_setup_bt_clock(void) int timeout = 500; if (!(OSCC & OSCC_OOK)) - pr_warning("32kHz clock was not on. Bootloader may need to " - "be updated\n"); + pr_warn("32kHz clock was not on. Bootloader may need to be updated\n"); else return; diff --git a/arch/arm/mach-pxa/include/mach/addr-map.h b/arch/arm/mach-pxa/include/mach/addr-map.h index bbf9df37ad4b..d28fe291233a 100644 --- a/arch/arm/mach-pxa/include/mach/addr-map.h +++ b/arch/arm/mach-pxa/include/mach/addr-map.h @@ -39,6 +39,11 @@ #define DMEMC_SIZE 0x00100000 /* + * Reserved space for low level debug virtual addresses within + * 0xf6200000..0xf6201000 + */ + +/* * Internal Memory Controller (PXA27x and later) */ #define IMEMC_PHYS 0x58000000 diff --git a/arch/arm/mach-pxa/include/mach/pxa25x.h b/arch/arm/mach-pxa/include/mach/pxa25x.h index 3ac0baac7350..5a341752e32c 100644 --- a/arch/arm/mach-pxa/include/mach/pxa25x.h +++ b/arch/arm/mach-pxa/include/mach/pxa25x.h @@ -6,12 +6,4 @@ #include <mach/mfp-pxa25x.h> #include <mach/irqs.h> -extern void __init pxa25x_map_io(void); -extern void __init pxa25x_init_irq(void); -#ifdef CONFIG_CPU_PXA26x -extern void __init pxa26x_init_irq(void); -#endif - -#define pxa25x_handle_irq icip_handle_irq - #endif /* __MACH_PXA25x_H */ diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h index 7cff640582b8..599b925a657c 100644 --- a/arch/arm/mach-pxa/include/mach/pxa27x.h +++ b/arch/arm/mach-pxa/include/mach/pxa27x.h @@ -19,11 +19,7 @@ #define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */ #define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */ -extern void __init pxa27x_map_io(void); -extern void __init pxa27x_init_irq(void); extern int __init pxa27x_set_pwrmode(unsigned int mode); extern void pxa27x_cpu_pm_enter(suspend_state_t state); -#define pxa27x_handle_irq ichp_handle_irq - #endif /* __MACH_PXA27x_H */ diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx.h b/arch/arm/mach-pxa/include/mach/pxa3xx.h index 6dd7fa163e29..b4143fb6631f 100644 --- a/arch/arm/mach-pxa/include/mach/pxa3xx.h +++ b/arch/arm/mach-pxa/include/mach/pxa3xx.h @@ -5,9 +5,4 @@ #include <mach/pxa3xx-regs.h> #include <mach/irqs.h> -extern void __init pxa3xx_map_io(void); -extern void __init pxa3xx_init_irq(void); - -#define pxa3xx_handle_irq ichp_handle_irq - #endif /* __MACH_PXA3XX_H */ diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index ef0426a159d4..666b78972c40 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -93,8 +93,8 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) break; default: /* warning and fall through, treat as MFP_LPM_DEFAULT */ - pr_warning("%s: GPIO%d: unsupported low power mode\n", - __func__, gpio); + pr_warn("%s: GPIO%d: unsupported low power mode\n", + __func__, gpio); break; } @@ -107,14 +107,12 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) * configurations of those pins not able to wakeup */ if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) { - pr_warning("%s: GPIO%d unable to wakeup\n", - __func__, gpio); + pr_warn("%s: GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } if ((c & MFP_LPM_CAN_WAKEUP) && is_out) { - pr_warning("%s: output GPIO%d unable to wakeup\n", - __func__, gpio); + pr_warn("%s: output GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } @@ -126,7 +124,7 @@ static inline int __mfp_validate(int mfp) int gpio = mfp_to_gpio(mfp); if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) { - pr_warning("%s: GPIO%d is invalid pin\n", __func__, gpio); + pr_warn("%s: GPIO%d is invalid pin\n", __func__, gpio); return -1; } diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 131991629116..29019beae591 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -446,7 +446,7 @@ static void __init poodle_init(void) ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret) - pr_warning("poodle: Unable to register LoCoMo device\n"); + pr_warn("poodle: Unable to register LoCoMo device\n"); pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info); pxa_set_udc_info(&udc_info); diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c index f6a2c4b1c1dc..7e0e5bd0c9de 100644 --- a/arch/arm/mach-pxa/pxa-dt.c +++ b/arch/arm/mach-pxa/pxa-dt.c @@ -15,13 +15,10 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h> #include <mach/irqs.h> -#include <mach/pxa3xx.h> #include "generic.h" #ifdef CONFIG_PXA3xx -extern void __init pxa3xx_dt_init_irq(void); - static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL), OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL), @@ -61,3 +58,18 @@ DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)") .dt_compat = pxa3xx_dt_board_compat, MACHINE_END #endif + +#ifdef CONFIG_PXA27x +static const char * const pxa27x_dt_board_compat[] __initconst = { + "marvell,pxa270", + NULL, +}; + +DT_MACHINE_START(PXA27X_DT, "Marvell PXA2xx (Device Tree Support)") + .map_io = pxa27x_map_io, + .init_irq = pxa27x_dt_init_irq, + .handle_irq = pxa27x_handle_irq, + .restart = pxa_restart, + .dt_compat = pxa27x_dt_board_compat, +MACHINE_END +#endif diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index b040d7d14888..af423a48c2e3 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -398,6 +398,12 @@ void __init pxa27x_init_irq(void) pxa_init_irq(34, pxa27x_set_wake); } +void __init pxa27x_dt_init_irq(void) +{ + if (IS_ENABLED(CONFIG_OF)) + pxa_dt_irq_init(pxa27x_set_wake); +} + static struct map_desc pxa27x_io_desc[] __initdata = { { /* Mem Ctl */ .virtual = (unsigned long)SMEMC_VIRT, diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c index e329ccefd364..614003e8b081 100644 --- a/arch/arm/mach-pxa/pxa3xx-ulpi.c +++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c @@ -74,7 +74,7 @@ static int pxa310_ulpi_poll(void) cpu_relax(); } - pr_warning("%s: ULPI access timed out!\n", __func__); + pr_warn("%s: ULPI access timed out!\n", __func__); return -ETIMEDOUT; } @@ -84,7 +84,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) int err; if (pxa310_ulpi_get_phymode() != SYNCH) { - pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); + pr_warn("%s: PHY is not in SYNCH mode!\n", __func__); return -EBUSY; } @@ -101,7 +101,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg) static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg) { if (pxa310_ulpi_get_phymode() != SYNCH) { - pr_warning("%s: PHY is not in SYNCH mode!\n", __func__); + pr_warn("%s: PHY is not in SYNCH mode!\n", __func__); return -EBUSY; } diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c index 8386dc30b3e4..a762b23ac830 100644 --- a/arch/arm/mach-pxa/raumfeld.c +++ b/arch/arm/mach-pxa/raumfeld.c @@ -521,7 +521,7 @@ static void __init raumfeld_w1_init(void) "W1 external pullup enable"); if (ret < 0) - pr_warning("Unable to request GPIO_W1_PULLUP_ENABLE\n"); + pr_warn("Unable to request GPIO_W1_PULLUP_ENABLE\n"); else gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0); @@ -600,7 +600,7 @@ static void __init raumfeld_lcd_init(void) ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable"); if (ret < 0) - pr_warning("Unable to request GPIO_TFT_VA_EN\n"); + pr_warn("Unable to request GPIO_TFT_VA_EN\n"); else gpio_direction_output(GPIO_TFT_VA_EN, 1); @@ -608,7 +608,7 @@ static void __init raumfeld_lcd_init(void) ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable"); if (ret < 0) - pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n"); + pr_warn("Unable to request GPIO_DISPLAY_ENABLE\n"); else gpio_direction_output(GPIO_DISPLAY_ENABLE, 1); @@ -814,17 +814,17 @@ static void __init raumfeld_power_init(void) /* Set PEN2 high to enable maximum charge current */ ret = gpio_request(GPIO_CHRG_PEN2, "CHRG_PEN2"); if (ret < 0) - pr_warning("Unable to request GPIO_CHRG_PEN2\n"); + pr_warn("Unable to request GPIO_CHRG_PEN2\n"); else gpio_direction_output(GPIO_CHRG_PEN2, 1); ret = gpio_request(GPIO_CHARGE_DC_OK, "CABLE_DC_OK"); if (ret < 0) - pr_warning("Unable to request GPIO_CHARGE_DC_OK\n"); + pr_warn("Unable to request GPIO_CHARGE_DC_OK\n"); ret = gpio_request(GPIO_CHARGE_USB_SUSP, "CHARGE_USB_SUSP"); if (ret < 0) - pr_warning("Unable to request GPIO_CHARGE_USB_SUSP\n"); + pr_warn("Unable to request GPIO_CHARGE_USB_SUSP\n"); else gpio_direction_output(GPIO_CHARGE_USB_SUSP, 0); @@ -976,19 +976,19 @@ static void __init raumfeld_audio_init(void) ret = gpio_request(GPIO_CODEC_RESET, "cs4270 reset"); if (ret < 0) - pr_warning("unable to request GPIO_CODEC_RESET\n"); + pr_warn("unable to request GPIO_CODEC_RESET\n"); else gpio_direction_output(GPIO_CODEC_RESET, 1); ret = gpio_request(GPIO_SPDIF_RESET, "ak4104 s/pdif reset"); if (ret < 0) - pr_warning("unable to request GPIO_SPDIF_RESET\n"); + pr_warn("unable to request GPIO_SPDIF_RESET\n"); else gpio_direction_output(GPIO_SPDIF_RESET, 1); ret = gpio_request(GPIO_MCLK_RESET, "MCLK reset"); if (ret < 0) - pr_warning("unable to request GPIO_MCLK_RESET\n"); + pr_warn("unable to request GPIO_MCLK_RESET\n"); else gpio_direction_output(GPIO_MCLK_RESET, 1); @@ -1019,20 +1019,20 @@ static void __init raumfeld_common_init(void) ret = gpio_request(GPIO_W2W_RESET, "Wi2Wi reset"); if (ret < 0) - pr_warning("Unable to request GPIO_W2W_RESET\n"); + pr_warn("Unable to request GPIO_W2W_RESET\n"); else gpio_direction_output(GPIO_W2W_RESET, 0); ret = gpio_request(GPIO_W2W_PDN, "Wi2Wi powerup"); if (ret < 0) - pr_warning("Unable to request GPIO_W2W_PDN\n"); + pr_warn("Unable to request GPIO_W2W_PDN\n"); else gpio_direction_output(GPIO_W2W_PDN, 0); /* this can be used to switch off the device */ ret = gpio_request(GPIO_SHUTDOWN_SUPPLY, "supply shutdown"); if (ret < 0) - pr_warning("Unable to request GPIO_SHUTDOWN_SUPPLY\n"); + pr_warn("Unable to request GPIO_SHUTDOWN_SUPPLY\n"); else gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0); @@ -1051,7 +1051,7 @@ static void __init raumfeld_controller_init(void) ret = gpio_request(GPIO_SHUTDOWN_BATT, "battery shutdown"); if (ret < 0) - pr_warning("Unable to request GPIO_SHUTDOWN_BATT\n"); + pr_warn("Unable to request GPIO_SHUTDOWN_BATT\n"); else gpio_direction_output(GPIO_SHUTDOWN_BATT, 0); diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index c158a6e3e0aa..7780d1faa06f 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -30,7 +30,7 @@ #include <linux/gpio_keys.h> #include <linux/input.h> #include <linux/gpio.h> -#include <linux/pda_power.h> +#include <linux/power/gpio-charger.h> #include <linux/spi/spi.h> #include <linux/spi/pxa2xx_spi.h> #include <linux/input/matrix_keypad.h> @@ -361,44 +361,17 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = { /* * Tosa AC IN */ -static int tosa_power_init(struct device *dev) -{ - int ret = gpio_request(TOSA_GPIO_AC_IN, "ac in"); - if (ret) - goto err_gpio_req; - - ret = gpio_direction_input(TOSA_GPIO_AC_IN); - if (ret) - goto err_gpio_in; - - return 0; - -err_gpio_in: - gpio_free(TOSA_GPIO_AC_IN); -err_gpio_req: - return ret; -} - -static void tosa_power_exit(struct device *dev) -{ - gpio_free(TOSA_GPIO_AC_IN); -} - -static int tosa_power_ac_online(void) -{ - return gpio_get_value(TOSA_GPIO_AC_IN) == 0; -} - static char *tosa_ac_supplied_to[] = { "main-battery", "backup-battery", "jacket-battery", }; -static struct pda_power_pdata tosa_power_data = { - .init = tosa_power_init, - .is_ac_online = tosa_power_ac_online, - .exit = tosa_power_exit, +static struct gpio_charger_platform_data tosa_power_data = { + .name = "charger", + .type = POWER_SUPPLY_TYPE_MAINS, + .gpio = TOSA_GPIO_AC_IN, + .gpio_active_low = 1, .supplied_to = tosa_ac_supplied_to, .num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to), }; @@ -415,7 +388,7 @@ static struct resource tosa_power_resource[] = { }; static struct platform_device tosa_power_device = { - .name = "pda-power", + .name = "gpio-charger", .id = -1, .dev.platform_data = &tosa_power_data, .resource = tosa_power_resource, diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S index 73206e360e31..46c22dedf632 100644 --- a/arch/arm/mach-rockchip/headsmp.S +++ b/arch/arm/mach-rockchip/headsmp.S @@ -16,7 +16,10 @@ #include <linux/init.h> ENTRY(rockchip_secondary_startup) - bl v7_invalidate_l1 + mrc p15, 0, r0, c0, c0, 0 @ read main ID register + ldr r1, =0x00000c09 @ Cortex-A9 primary part number + teq r0, r1 + beq v7_invalidate_l1 b secondary_startup ENDPROC(rockchip_secondary_startup) diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 189684f55927..f26fcdca2445 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c @@ -19,7 +19,11 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/reset.h> +#include <linux/cpu.h> #include <asm/cacheflush.h> #include <asm/cp15.h> #include <asm/smp_scu.h> @@ -37,23 +41,78 @@ static int ncores; #define PMU_PWRDN_SCU 4 -static void __iomem *pmu_base_addr; +static struct regmap *pmu; -static inline bool pmu_power_domain_is_on(int pd) +static int pmu_power_domain_is_on(int pd) { - return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd)); + u32 val; + int ret; + + ret = regmap_read(pmu, PMU_PWRDN_ST, &val); + if (ret < 0) + return ret; + + return !(val & BIT(pd)); } -static void pmu_set_power_domain(int pd, bool on) +struct reset_control *rockchip_get_core_reset(int cpu) { - u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON); - if (on) - val &= ~BIT(pd); + struct device *dev = get_cpu_device(cpu); + struct device_node *np; + + /* The cpu device is only available after the initial core bringup */ + if (dev) + np = dev->of_node; else - val |= BIT(pd); - writel(val, pmu_base_addr + PMU_PWRDN_CON); + np = of_get_cpu_node(cpu, 0); - while (pmu_power_domain_is_on(pd) != on) { } + return of_reset_control_get(np, NULL); +} + +static int pmu_set_power_domain(int pd, bool on) +{ + u32 val = (on) ? 0 : BIT(pd); + int ret; + + /* + * We need to soft reset the cpu when we turn off the cpu power domain, + * or else the active processors might be stalled when the individual + * processor is powered down. + */ + if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) { + struct reset_control *rstc = rockchip_get_core_reset(pd); + + if (IS_ERR(rstc)) { + pr_err("%s: could not get reset control for core %d\n", + __func__, pd); + return PTR_ERR(rstc); + } + + if (on) + reset_control_deassert(rstc); + else + reset_control_assert(rstc); + + reset_control_put(rstc); + } + + ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val); + if (ret < 0) { + pr_err("%s: could not update power domain\n", __func__); + return ret; + } + + ret = -1; + while (ret != on) { + ret = pmu_power_domain_is_on(pd); + if (ret < 0) { + pr_err("%s: could not read power domain state\n", + __func__); + return ret; + } + } + + return 0; } /* @@ -63,7 +122,9 @@ static void pmu_set_power_domain(int pd, bool on) static int __cpuinit rockchip_boot_secondary(unsigned int cpu, struct task_struct *idle) { - if (!sram_base_addr || !pmu_base_addr) { + int ret; + + if (!sram_base_addr || !pmu) { pr_err("%s: sram or pmu missing for cpu boot\n", __func__); return -ENXIO; } @@ -75,7 +136,24 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu, } /* start the core */ - pmu_set_power_domain(0 + cpu, true); + ret = pmu_set_power_domain(0 + cpu, true); + if (ret < 0) + return ret; + + if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) { + /* We communicate with the bootrom to active the cpus other + * than cpu0, after a blob of initialize code, they will + * stay at wfe state, once they are actived, they will check + * the mailbox: + * sram_base_addr + 4: 0xdeadbeaf + * sram_base_addr + 8: start address for pc + * */ + udelay(10); + writel(virt_to_phys(rockchip_secondary_startup), + sram_base_addr + 8); + writel(0xDEADBEAF, sram_base_addr + 4); + dsb_sev(); + } return 0; } @@ -110,8 +188,6 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) return -EINVAL; } - sram_base_addr = of_iomap(node, 0); - /* set the boot function for the sram code */ rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup); @@ -125,54 +201,115 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) return 0; } -static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) +static struct regmap_config rockchip_pmu_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int __init rockchip_smp_prepare_pmu(void) { struct device_node *node; - unsigned int i; + void __iomem *pmu_base; - node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); + /* + * This function is only called via smp_ops->smp_prepare_cpu(). + * That only happens if a "/cpus" device tree node exists + * and has an "enable-method" property that selects the SMP + * operations defined herein. + */ + node = of_find_node_by_path("/cpus"); + + pmu = syscon_regmap_lookup_by_phandle(node, "rockchip,pmu"); + of_node_put(node); + if (!IS_ERR(pmu)) + return 0; + + pmu = syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu"); + if (!IS_ERR(pmu)) + return 0; + + /* fallback, create our own regmap for the pmu area */ + pmu = NULL; + node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu"); if (!node) { - pr_err("%s: missing scu\n", __func__); - return; + pr_err("%s: could not find pmu dt node\n", __func__); + return -ENODEV; } - scu_base_addr = of_iomap(node, 0); - if (!scu_base_addr) { - pr_err("%s: could not map scu registers\n", __func__); - return; + pmu_base = of_iomap(node, 0); + if (!pmu_base) { + pr_err("%s: could not map pmu registers\n", __func__); + return -ENOMEM; } - node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram"); - if (!node) { - pr_err("%s: could not find sram dt node\n", __func__); - return; + pmu = regmap_init_mmio(NULL, pmu_base, &rockchip_pmu_regmap_config); + if (IS_ERR(pmu)) { + int ret = PTR_ERR(pmu); + + iounmap(pmu_base); + pmu = NULL; + pr_err("%s: regmap init failed\n", __func__); + return ret; } - if (rockchip_smp_prepare_sram(node)) - return; + return 0; +} - node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu"); +static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *node; + unsigned int i; + + node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram"); if (!node) { - pr_err("%s: could not find pmu dt node\n", __func__); + pr_err("%s: could not find sram dt node\n", __func__); return; } - pmu_base_addr = of_iomap(node, 0); - if (!pmu_base_addr) { - pr_err("%s: could not map pmu registers\n", __func__); + sram_base_addr = of_iomap(node, 0); + if (!sram_base_addr) { + pr_err("%s: could not map sram registers\n", __func__); return; } - /* enable the SCU power domain */ - pmu_set_power_domain(PMU_PWRDN_SCU, true); - - /* - * While the number of cpus is gathered from dt, also get the number - * of cores from the scu to verify this value when booting the cores. - */ - ncores = scu_get_core_count(scu_base_addr); + if (rockchip_smp_prepare_pmu()) + return; - scu_enable(scu_base_addr); + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { + if (rockchip_smp_prepare_sram(node)) + return; + + /* enable the SCU power domain */ + pmu_set_power_domain(PMU_PWRDN_SCU, true); + + node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); + if (!node) { + pr_err("%s: missing scu\n", __func__); + return; + } + + scu_base_addr = of_iomap(node, 0); + if (!scu_base_addr) { + pr_err("%s: could not map scu registers\n", __func__); + return; + } + + /* + * While the number of cpus is gathered from dt, also get the + * number of cores from the scu to verify this value when + * booting the cores. + */ + ncores = scu_get_core_count(scu_base_addr); + pr_err("%s: ncores %d\n", __func__, ncores); + + scu_enable(scu_base_addr); + } else { + unsigned int l2ctlr; + + asm ("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr)); + ncores = ((l2ctlr >> 24) & 0x3) + 1; + } /* Make sure that all cores except the first are really off */ for (i = 1; i < ncores; i++) diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c index 8ab9e0e7ff04..d226b71d21d5 100644 --- a/arch/arm/mach-rockchip/rockchip.c +++ b/arch/arm/mach-rockchip/rockchip.c @@ -24,6 +24,12 @@ #include <asm/hardware/cache-l2x0.h> #include "core.h" +static void __init rockchip_dt_init(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + platform_device_register_simple("cpufreq-dt", 0, NULL, 0); +} + static const char * const rockchip_board_dt_compat[] = { "rockchip,rk2928", "rockchip,rk3066a", @@ -37,4 +43,5 @@ DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)") .l2c_aux_val = 0, .l2c_aux_mask = ~0, .dt_compat = rockchip_board_dt_compat, + .init_machine = rockchip_dt_init, MACHINE_END diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 21f457b56c01..1b4fafe524ff 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -1,5 +1,6 @@ config ARCH_SHMOBILE bool + select ZONE_DMA if ARM_LPAE config PM_RCAR bool @@ -18,6 +19,7 @@ config ARCH_RCAR_GEN2 select PM_RCAR if PM || SMP select RENESAS_IRQC select SYS_SUPPORTS_SH_CMT + select PCI_DOMAINS if PCI config ARCH_RMOBILE bool @@ -36,7 +38,6 @@ menuconfig ARCH_SHMOBILE_MULTI select NO_IOPORT_MAP select PINCTRL select ARCH_REQUIRE_GPIOLIB - select ARCH_HAS_OPP if ARCH_SHMOBILE_MULTI @@ -73,11 +74,6 @@ config ARCH_R8A7794 comment "Renesas ARM SoCs Board Type" -config MACH_KOELSCH - bool "Koelsch board" - depends on ARCH_R8A7791 - select MICREL_PHY if SH_ETH - config MACH_LAGER bool "Lager board" depends on ARCH_R8A7790 @@ -145,14 +141,6 @@ config ARCH_R8A7790 select MIGHT_HAVE_PCI select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE -config ARCH_R8A7791 - bool "R-Car M2-W (R8A77910)" - select ARCH_RCAR_GEN2 - select ARCH_WANT_OPTIONAL_GPIOLIB - select ARM_GIC - select MIGHT_HAVE_PCI - select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE - comment "Renesas ARM SoCs Board Type" config MACH_APE6EVM @@ -227,12 +215,6 @@ config MACH_LAGER select MICREL_PHY if SH_ETH select SND_SOC_AK4642 if SND_SIMPLE_CARD -config MACH_KOELSCH - bool "Koelsch board" - depends on ARCH_R8A7791 - select USE_OF - select MICREL_PHY if SH_ETH - config MACH_KZM9G bool "KZM-A9-GT board" depends on ARCH_SH73A0 diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index e20f2786ec72..b55cac0e5b2b 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -19,8 +19,8 @@ obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o obj-$(CONFIG_ARCH_R7S72100) += setup-r7s72100.o # Clock objects -obj-y += clock.o ifndef CONFIG_COMMON_CLK +obj-y += clock.o obj-$(CONFIG_ARCH_SH7372) += clock-sh7372.o obj-$(CONFIG_ARCH_SH73A0) += clock-sh73a0.o obj-$(CONFIG_ARCH_R8A73A4) += clock-r8a73a4.o @@ -28,7 +28,6 @@ obj-$(CONFIG_ARCH_R8A7740) += clock-r8a7740.o obj-$(CONFIG_ARCH_R8A7778) += clock-r8a7778.o obj-$(CONFIG_ARCH_R8A7779) += clock-r8a7779.o obj-$(CONFIG_ARCH_R8A7790) += clock-r8a7790.o -obj-$(CONFIG_ARCH_R8A7791) += clock-r8a7791.o endif # CPU reset vector handling objects @@ -36,6 +35,7 @@ cpu-y := platsmp.o headsmp.o # Shared SoC family objects obj-$(CONFIG_ARCH_RCAR_GEN2) += setup-rcar-gen2.o platsmp-apmu.o $(cpu-y) +CFLAGS_setup-rcar-gen2.o += -march=armv7-a # SMP objects smp-y := $(cpu-y) @@ -57,7 +57,6 @@ obj-$(CONFIG_ARCH_SH7372) += entry-intc.o sleep-sh7372.o # Board objects ifdef CONFIG_ARCH_SHMOBILE_MULTI -obj-$(CONFIG_MACH_KOELSCH) += board-koelsch-reference.o obj-$(CONFIG_MACH_LAGER) += board-lager-reference.o obj-$(CONFIG_MACH_MARZEN) += board-marzen-reference.o else @@ -69,7 +68,6 @@ obj-$(CONFIG_MACH_BOCKW_REFERENCE) += board-bockw-reference.o obj-$(CONFIG_MACH_MARZEN) += board-marzen.o obj-$(CONFIG_MACH_LAGER) += board-lager.o obj-$(CONFIG_MACH_ARMADILLO800EVA) += board-armadillo800eva.o -obj-$(CONFIG_MACH_KOELSCH) += board-koelsch.o obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o obj-$(CONFIG_MACH_KZM9G_REFERENCE) += board-kzm9g-reference.o endif diff --git a/arch/arm/mach-shmobile/Makefile.boot b/arch/arm/mach-shmobile/Makefile.boot index de9a23852fc8..57d00ed6ec0c 100644 --- a/arch/arm/mach-shmobile/Makefile.boot +++ b/arch/arm/mach-shmobile/Makefile.boot @@ -5,7 +5,6 @@ loadaddr-$(CONFIG_MACH_APE6EVM_REFERENCE) += 0x40008000 loadaddr-$(CONFIG_MACH_ARMADILLO800EVA) += 0x40008000 loadaddr-$(CONFIG_MACH_BOCKW) += 0x60008000 loadaddr-$(CONFIG_MACH_BOCKW_REFERENCE) += 0x60008000 -loadaddr-$(CONFIG_MACH_KOELSCH) += 0x40008000 loadaddr-$(CONFIG_MACH_KZM9G) += 0x41008000 loadaddr-$(CONFIG_MACH_KZM9G_REFERENCE) += 0x41008000 loadaddr-$(CONFIG_MACH_LAGER) += 0x40008000 diff --git a/arch/arm/mach-shmobile/board-ape6evm-reference.c b/arch/arm/mach-shmobile/board-ape6evm-reference.c index a6503d8c77de..004ed92ee598 100644 --- a/arch/arm/mach-shmobile/board-ape6evm-reference.c +++ b/arch/arm/mach-shmobile/board-ape6evm-reference.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/gpio.h> diff --git a/arch/arm/mach-shmobile/board-ape6evm.c b/arch/arm/mach-shmobile/board-ape6evm.c index b222f68d55b7..66f67816a844 100644 --- a/arch/arm/mach-shmobile/board-ape6evm.c +++ b/arch/arm/mach-shmobile/board-ape6evm.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/gpio.h> diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e70983534403..6d949f1c850b 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -12,53 +12,48 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/kernel.h> -#include <linux/input.h> -#include <linux/platform_data/st1232_pdata.h> -#include <linux/irq.h> -#include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/gpio_keys.h> -#include <linux/regulator/driver.h> +#include <linux/i2c-gpio.h> +#include <linux/input.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/mfd/tmio.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sh_mmcif.h> +#include <linux/mmc/sh_mobile_sdhi.h> #include <linux/pinctrl/machine.h> +#include <linux/platform_data/st1232_pdata.h> +#include <linux/platform_device.h> #include <linux/pwm.h> #include <linux/pwm_backlight.h> +#include <linux/reboot.h> +#include <linux/regulator/driver.h> #include <linux/regulator/fixed.h> #include <linux/regulator/gpio-regulator.h> #include <linux/regulator/machine.h> #include <linux/sh_eth.h> -#include <linux/videodev2.h> #include <linux/usb/renesas_usbhs.h> -#include <linux/mfd/tmio.h> -#include <linux/mmc/host.h> -#include <linux/mmc/sh_mmcif.h> -#include <linux/mmc/sh_mobile_sdhi.h> -#include <linux/i2c-gpio.h> -#include <linux/reboot.h> +#include <linux/videodev2.h> -#include <media/mt9t112.h> -#include <media/sh_mobile_ceu.h> -#include <media/soc_camera.h> -#include <asm/page.h> +#include <asm/hardware/cache-l2x0.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/time.h> -#include <asm/hardware/cache-l2x0.h> -#include <video/sh_mobile_lcdc.h> -#include <video/sh_mobile_hdmi.h> +#include <asm/page.h> +#include <media/mt9t112.h> +#include <media/sh_mobile_ceu.h> +#include <media/soc_camera.h> #include <sound/sh_fsi.h> #include <sound/simple_card.h> +#include <video/sh_mobile_hdmi.h> +#include <video/sh_mobile_lcdc.h> #include "common.h" #include "irqs.h" @@ -1234,8 +1229,15 @@ static void __init eva_init(void) static struct pm_domain_device domain_devices[] __initdata = { { "A4LC", &lcdc0_device }, { "A4LC", &hdmi_lcdc_device }, + { "A4MP", &hdmi_device }, + { "A4MP", &fsi_device }, + { "A4R", &ceu0_device }, + { "A4S", &sh_eth_device }, + { "A3SP", &pwm_device }, + { "A3SP", &sdhi0_device }, + { "A3SP", &sh_mmcif_device }, }; - struct platform_device *usb = NULL; + struct platform_device *usb = NULL, *sdhi1 = NULL; regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers, ARRAY_SIZE(fixed3v3_power_consumers), 3300000); @@ -1304,6 +1306,7 @@ static void __init eva_init(void) platform_device_register(&vcc_sdhi1); platform_device_register(&sdhi1_device); + sdhi1 = &sdhi1_device; } @@ -1324,6 +1327,8 @@ static void __init eva_init(void) ARRAY_SIZE(domain_devices)); if (usb) rmobile_add_device_to_domain("A3SP", usb); + if (sdhi1) + rmobile_add_device_to_domain("A3SP", sdhi1); r8a7740_pm_init(); } diff --git a/arch/arm/mach-shmobile/board-bockw-reference.c b/arch/arm/mach-shmobile/board-bockw-reference.c index 79c47847f200..d649ade4a202 100644 --- a/arch/arm/mach-shmobile/board-bockw-reference.c +++ b/arch/arm/mach-shmobile/board-bockw-reference.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/of_platform.h> diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index 1cf2c75dacfb..f27b5a833bf0 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/mfd/tmio.h> diff --git a/arch/arm/mach-shmobile/board-koelsch-reference.c b/arch/arm/mach-shmobile/board-koelsch-reference.c deleted file mode 100644 index 46aa540133d6..000000000000 --- a/arch/arm/mach-shmobile/board-koelsch-reference.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Koelsch board support - Reference DT implementation - * - * Copyright (C) 2013 Renesas Electronics Corporation - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/dma-mapping.h> -#include <linux/kernel.h> -#include <linux/of_platform.h> -#include <linux/platform_data/rcar-du.h> - -#include <asm/mach/arch.h> - -#include "clock.h" -#include "common.h" -#include "irqs.h" -#include "r8a7791.h" -#include "rcar-gen2.h" - -/* DU */ -static struct rcar_du_encoder_data koelsch_du_encoders[] = { - { - .type = RCAR_DU_ENCODER_NONE, - .output = RCAR_DU_OUTPUT_LVDS0, - .connector.lvds.panel = { - .width_mm = 210, - .height_mm = 158, - .mode = { - .pixelclock = 65000000, - .hactive = 1024, - .hfront_porch = 20, - .hback_porch = 160, - .hsync_len = 136, - .vactive = 768, - .vfront_porch = 3, - .vback_porch = 29, - .vsync_len = 6, - }, - }, - }, -}; - -static struct rcar_du_platform_data koelsch_du_pdata = { - .encoders = koelsch_du_encoders, - .num_encoders = ARRAY_SIZE(koelsch_du_encoders), -}; - -static const struct resource du_resources[] __initconst = { - DEFINE_RES_MEM(0xfeb00000, 0x40000), - DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"), - DEFINE_RES_IRQ(gic_spi(256)), - DEFINE_RES_IRQ(gic_spi(268)), -}; - -static void __init koelsch_add_du_device(void) -{ - struct platform_device_info info = { - .name = "rcar-du-r8a7791", - .id = -1, - .res = du_resources, - .num_res = ARRAY_SIZE(du_resources), - .data = &koelsch_du_pdata, - .size_data = sizeof(koelsch_du_pdata), - .dma_mask = DMA_BIT_MASK(32), - }; - - platform_device_register_full(&info); -} - -/* - * This is a really crude hack to provide clkdev support to platform - * devices until they get moved to DT. - */ -static const struct clk_name clk_names[] __initconst = { - { "du0", "du.0", "rcar-du-r8a7791" }, - { "du1", "du.1", "rcar-du-r8a7791" }, - { "lvds0", "lvds.0", "rcar-du-r8a7791" }, -}; - -static void __init koelsch_add_standard_devices(void) -{ - shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - - koelsch_add_du_device(); -} - -static const char * const koelsch_boards_compat_dt[] __initconst = { - "renesas,koelsch", - "renesas,koelsch-reference", - NULL, -}; - -DT_MACHINE_START(KOELSCH_DT, "koelsch") - .smp = smp_ops(r8a7791_smp_ops), - .init_early = shmobile_init_delay, - .init_time = rcar_gen2_timer_init, - .init_machine = koelsch_add_standard_devices, - .init_late = shmobile_init_late, - .reserve = rcar_gen2_reserve, - .dt_compat = koelsch_boards_compat_dt, -MACHINE_END diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c deleted file mode 100644 index 7111b5c1d67b..000000000000 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Koelsch board support - * - * Copyright (C) 2013 Renesas Electronics Corporation - * Copyright (C) 2013-2014 Renesas Solutions Corp. - * Copyright (C) 2013 Magnus Damm - * Copyright (C) 2014 Cogent Embedded, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <linux/dma-mapping.h> -#include <linux/gpio.h> -#include <linux/gpio_keys.h> -#include <linux/input.h> -#include <linux/irq.h> -#include <linux/kernel.h> -#include <linux/leds.h> -#include <linux/mfd/tmio.h> -#include <linux/mmc/host.h> -#include <linux/mmc/sh_mobile_sdhi.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/phy.h> -#include <linux/pinctrl/machine.h> -#include <linux/platform_data/gpio-rcar.h> -#include <linux/platform_data/rcar-du.h> -#include <linux/platform_device.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/fixed.h> -#include <linux/regulator/gpio-regulator.h> -#include <linux/regulator/machine.h> -#include <linux/sh_eth.h> -#include <linux/spi/flash.h> -#include <linux/spi/rspi.h> -#include <linux/spi/spi.h> - -#include <asm/mach-types.h> -#include <asm/mach/arch.h> - -#include "common.h" -#include "irqs.h" -#include "r8a7791.h" -#include "rcar-gen2.h" - -/* DU */ -static struct rcar_du_encoder_data koelsch_du_encoders[] = { - { - .type = RCAR_DU_ENCODER_NONE, - .output = RCAR_DU_OUTPUT_LVDS0, - .connector.lvds.panel = { - .width_mm = 210, - .height_mm = 158, - .mode = { - .pixelclock = 65000000, - .hactive = 1024, - .hfront_porch = 20, - .hback_porch = 160, - .hsync_len = 136, - .vactive = 768, - .vfront_porch = 3, - .vback_porch = 29, - .vsync_len = 6, - }, - }, - }, -}; - -static const struct rcar_du_platform_data koelsch_du_pdata __initconst = { - .encoders = koelsch_du_encoders, - .num_encoders = ARRAY_SIZE(koelsch_du_encoders), -}; - -static const struct resource du_resources[] __initconst = { - DEFINE_RES_MEM(0xfeb00000, 0x40000), - DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"), - DEFINE_RES_IRQ(gic_spi(256)), - DEFINE_RES_IRQ(gic_spi(268)), -}; - -static void __init koelsch_add_du_device(void) -{ - struct platform_device_info info = { - .name = "rcar-du-r8a7791", - .id = -1, - .res = du_resources, - .num_res = ARRAY_SIZE(du_resources), - .data = &koelsch_du_pdata, - .size_data = sizeof(koelsch_du_pdata), - .dma_mask = DMA_BIT_MASK(32), - }; - - platform_device_register_full(&info); -} - -/* Ether */ -static const struct sh_eth_plat_data ether_pdata __initconst = { - .phy = 0x1, - .phy_irq = irq_pin(0), - .edmac_endian = EDMAC_LITTLE_ENDIAN, - .phy_interface = PHY_INTERFACE_MODE_RMII, - .ether_link_active_low = 1, -}; - -static const struct resource ether_resources[] __initconst = { - DEFINE_RES_MEM(0xee700000, 0x400), - DEFINE_RES_IRQ(gic_spi(162)), -}; - -static const struct platform_device_info ether_info __initconst = { - .name = "r8a7791-ether", - .id = -1, - .res = ether_resources, - .num_res = ARRAY_SIZE(ether_resources), - .data = ðer_pdata, - .size_data = sizeof(ether_pdata), - .dma_mask = DMA_BIT_MASK(32), -}; - -/* LEDS */ -static struct gpio_led koelsch_leds[] = { - { - .name = "led8", - .gpio = RCAR_GP_PIN(2, 21), - .default_state = LEDS_GPIO_DEFSTATE_ON, - }, { - .name = "led7", - .gpio = RCAR_GP_PIN(2, 20), - .default_state = LEDS_GPIO_DEFSTATE_ON, - }, { - .name = "led6", - .gpio = RCAR_GP_PIN(2, 19), - .default_state = LEDS_GPIO_DEFSTATE_ON, - }, -}; - -static const struct gpio_led_platform_data koelsch_leds_pdata __initconst = { - .leds = koelsch_leds, - .num_leds = ARRAY_SIZE(koelsch_leds), -}; - -/* GPIO KEY */ -#define GPIO_KEY(c, g, d, ...) \ - { .code = c, .gpio = g, .desc = d, .active_low = 1, \ - .wakeup = 1, .debounce_interval = 20 } - -static struct gpio_keys_button gpio_buttons[] = { - GPIO_KEY(KEY_4, RCAR_GP_PIN(5, 3), "SW2-pin4"), - GPIO_KEY(KEY_3, RCAR_GP_PIN(5, 2), "SW2-pin3"), - GPIO_KEY(KEY_2, RCAR_GP_PIN(5, 1), "SW2-pin2"), - GPIO_KEY(KEY_1, RCAR_GP_PIN(5, 0), "SW2-pin1"), - GPIO_KEY(KEY_G, RCAR_GP_PIN(7, 6), "SW36"), - GPIO_KEY(KEY_F, RCAR_GP_PIN(7, 5), "SW35"), - GPIO_KEY(KEY_E, RCAR_GP_PIN(7, 4), "SW34"), - GPIO_KEY(KEY_D, RCAR_GP_PIN(7, 3), "SW33"), - GPIO_KEY(KEY_C, RCAR_GP_PIN(7, 2), "SW32"), - GPIO_KEY(KEY_B, RCAR_GP_PIN(7, 1), "SW31"), - GPIO_KEY(KEY_A, RCAR_GP_PIN(7, 0), "SW30"), -}; - -static const struct gpio_keys_platform_data koelsch_keys_pdata __initconst = { - .buttons = gpio_buttons, - .nbuttons = ARRAY_SIZE(gpio_buttons), -}; - -/* QSPI */ -static const struct resource qspi_resources[] __initconst = { - DEFINE_RES_MEM(0xe6b10000, 0x1000), - DEFINE_RES_IRQ_NAMED(gic_spi(184), "mux"), -}; - -static const struct rspi_plat_data qspi_pdata __initconst = { - .num_chipselect = 1, -}; - -/* SPI Flash memory (Spansion S25FL512SAGMFIG11 64 MiB) */ -static struct mtd_partition spi_flash_part[] = { - { - .name = "loader", - .offset = 0x00000000, - .size = 512 * 1024, - .mask_flags = MTD_WRITEABLE, - }, - { - .name = "bootenv", - .offset = MTDPART_OFS_APPEND, - .size = 512 * 1024, - .mask_flags = MTD_WRITEABLE, - }, - { - .name = "data", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - }, -}; - -static const struct flash_platform_data spi_flash_data = { - .name = "m25p80", - .parts = spi_flash_part, - .nr_parts = ARRAY_SIZE(spi_flash_part), - .type = "s25fl512s", -}; - -static const struct spi_board_info spi_info[] __initconst = { - { - .modalias = "m25p80", - .platform_data = &spi_flash_data, - .mode = SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD, - .max_speed_hz = 30000000, - .bus_num = 0, - .chip_select = 0, - }, -}; - -/* SATA0 */ -static const struct resource sata0_resources[] __initconst = { - DEFINE_RES_MEM(0xee300000, 0x2000), - DEFINE_RES_IRQ(gic_spi(105)), -}; - -static const struct platform_device_info sata0_info __initconst = { - .name = "sata-r8a7791", - .id = 0, - .res = sata0_resources, - .num_res = ARRAY_SIZE(sata0_resources), - .dma_mask = DMA_BIT_MASK(32), -}; - -/* I2C */ -static const struct resource i2c_resources[] __initconst = { - /* I2C0 */ - DEFINE_RES_MEM(0xE6508000, 0x40), - DEFINE_RES_IRQ(gic_spi(287)), - /* I2C1 */ - DEFINE_RES_MEM(0xE6518000, 0x40), - DEFINE_RES_IRQ(gic_spi(288)), - /* I2C2 */ - DEFINE_RES_MEM(0xE6530000, 0x40), - DEFINE_RES_IRQ(gic_spi(286)), - /* I2C3 */ - DEFINE_RES_MEM(0xE6540000, 0x40), - DEFINE_RES_IRQ(gic_spi(290)), - /* I2C4 */ - DEFINE_RES_MEM(0xE6520000, 0x40), - DEFINE_RES_IRQ(gic_spi(19)), - /* I2C5 */ - DEFINE_RES_MEM(0xE6528000, 0x40), - DEFINE_RES_IRQ(gic_spi(20)), -}; - -static void __init koelsch_add_i2c(unsigned idx) -{ - unsigned res_idx = idx * 2; - - BUG_ON(res_idx >= ARRAY_SIZE(i2c_resources)); - - platform_device_register_simple("i2c-rcar_gen2", idx, - i2c_resources + res_idx, 2); -} - -#define SDHI_REGULATOR(idx, vdd_pin, vccq_pin) \ -static struct regulator_consumer_supply vcc_sdhi##idx##_consumer = \ - REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi." #idx); \ - \ -static struct regulator_init_data vcc_sdhi##idx##_init_data = { \ - .constraints = { \ - .valid_ops_mask = REGULATOR_CHANGE_STATUS, \ - }, \ - .consumer_supplies = &vcc_sdhi##idx##_consumer, \ - .num_consumer_supplies = 1, \ -}; \ - \ -static const struct fixed_voltage_config vcc_sdhi##idx##_info __initconst = {\ - .supply_name = "SDHI" #idx "Vcc", \ - .microvolts = 3300000, \ - .gpio = vdd_pin, \ - .enable_high = 1, \ - .init_data = &vcc_sdhi##idx##_init_data, \ -}; \ - \ -static struct regulator_consumer_supply vccq_sdhi##idx##_consumer = \ - REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi." #idx); \ - \ -static struct regulator_init_data vccq_sdhi##idx##_init_data = { \ - .constraints = { \ - .input_uV = 3300000, \ - .min_uV = 1800000, \ - .max_uV = 3300000, \ - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | \ - REGULATOR_CHANGE_STATUS, \ - }, \ - .consumer_supplies = &vccq_sdhi##idx##_consumer, \ - .num_consumer_supplies = 1, \ -}; \ - \ -static struct gpio vccq_sdhi##idx##_gpio = \ - { vccq_pin, GPIOF_OUT_INIT_HIGH, "vccq-sdhi" #idx }; \ - \ -static struct gpio_regulator_state vccq_sdhi##idx##_states[] = { \ - { .value = 1800000, .gpios = 0 }, \ - { .value = 3300000, .gpios = 1 }, \ -}; \ - \ -static const struct gpio_regulator_config vccq_sdhi##idx##_info __initconst = {\ - .supply_name = "vqmmc", \ - .gpios = &vccq_sdhi##idx##_gpio, \ - .nr_gpios = 1, \ - .states = vccq_sdhi##idx##_states, \ - .nr_states = ARRAY_SIZE(vccq_sdhi##idx##_states), \ - .type = REGULATOR_VOLTAGE, \ - .init_data = &vccq_sdhi##idx##_init_data, \ -}; - -SDHI_REGULATOR(0, RCAR_GP_PIN(7, 17), RCAR_GP_PIN(2, 12)); -SDHI_REGULATOR(1, RCAR_GP_PIN(7, 18), RCAR_GP_PIN(2, 13)); -SDHI_REGULATOR(2, RCAR_GP_PIN(7, 19), RCAR_GP_PIN(2, 26)); - -/* SDHI0 */ -static struct sh_mobile_sdhi_info sdhi0_info __initdata = { - .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | - MMC_CAP_POWER_OFF_CARD, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, -}; - -static struct resource sdhi0_resources[] __initdata = { - DEFINE_RES_MEM(0xee100000, 0x200), - DEFINE_RES_IRQ(gic_spi(165)), -}; - -/* SDHI1 */ -static struct sh_mobile_sdhi_info sdhi1_info __initdata = { - .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | - MMC_CAP_POWER_OFF_CARD, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, -}; - -static struct resource sdhi1_resources[] __initdata = { - DEFINE_RES_MEM(0xee140000, 0x100), - DEFINE_RES_IRQ(gic_spi(167)), -}; - -/* SDHI2 */ -static struct sh_mobile_sdhi_info sdhi2_info __initdata = { - .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | - MMC_CAP_POWER_OFF_CARD, - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | - TMIO_MMC_WRPROTECT_DISABLE, -}; - -static struct resource sdhi2_resources[] __initdata = { - DEFINE_RES_MEM(0xee160000, 0x100), - DEFINE_RES_IRQ(gic_spi(168)), -}; - -static const struct pinctrl_map koelsch_pinctrl_map[] = { - /* DU */ - PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791", - "du_rgb666", "du"), - PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791", - "du_sync", "du"), - PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791", - "du_clk_out_0", "du"), - /* Ether */ - PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791", - "eth_link", "eth"), - PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791", - "eth_mdio", "eth"), - PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791", - "eth_rmii", "eth"), - PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791", - "intc_irq0", "intc"), - /* QSPI */ - PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7791", - "qspi_ctrl", "qspi"), - PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7791", - "qspi_data4", "qspi"), - /* SCIF0 (CN19: DEBUG SERIAL0) */ - PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.6", "pfc-r8a7791", - "scif0_data_d", "scif0"), - /* SCIF1 (CN20: DEBUG SERIAL1) */ - PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.7", "pfc-r8a7791", - "scif1_data_d", "scif1"), - /* I2C1 */ - PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.1", "pfc-r8a7791", - "i2c1_e", "i2c1"), - /* I2C2 */ - PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.2", "pfc-r8a7791", - "i2c2", "i2c2"), - /* I2C4 */ - PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.4", "pfc-r8a7791", - "i2c4_c", "i2c4"), - /* SDHI0 */ - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791", - "sdhi0_data4", "sdhi0"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791", - "sdhi0_ctrl", "sdhi0"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791", - "sdhi0_cd", "sdhi0"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791", - "sdhi0_wp", "sdhi0"), - /* SDHI2 */ - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791", - "sdhi1_data4", "sdhi1"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791", - "sdhi1_ctrl", "sdhi1"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791", - "sdhi1_cd", "sdhi1"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791", - "sdhi1_wp", "sdhi1"), - /* SDHI2 */ - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7791", - "sdhi2_data4", "sdhi2"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7791", - "sdhi2_ctrl", "sdhi2"), - PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7791", - "sdhi2_cd", "sdhi2"), -}; - -static void __init koelsch_add_standard_devices(void) -{ - r8a7791_clock_init(); - pinctrl_register_mappings(koelsch_pinctrl_map, - ARRAY_SIZE(koelsch_pinctrl_map)); - r8a7791_pinmux_init(); - r8a7791_add_standard_devices(); - platform_device_register_full(ðer_info); - platform_device_register_data(NULL, "leds-gpio", -1, - &koelsch_leds_pdata, - sizeof(koelsch_leds_pdata)); - platform_device_register_data(NULL, "gpio-keys", -1, - &koelsch_keys_pdata, - sizeof(koelsch_keys_pdata)); - platform_device_register_resndata(NULL, "qspi", 0, - qspi_resources, - ARRAY_SIZE(qspi_resources), - &qspi_pdata, sizeof(qspi_pdata)); - spi_register_board_info(spi_info, ARRAY_SIZE(spi_info)); - - koelsch_add_du_device(); - - platform_device_register_full(&sata0_info); - - koelsch_add_i2c(1); - koelsch_add_i2c(2); - koelsch_add_i2c(4); - koelsch_add_i2c(5); - - platform_device_register_data(NULL, "reg-fixed-voltage", 0, - &vcc_sdhi0_info, sizeof(struct fixed_voltage_config)); - platform_device_register_data(NULL, "reg-fixed-voltage", 1, - &vcc_sdhi1_info, sizeof(struct fixed_voltage_config)); - platform_device_register_data(NULL, "reg-fixed-voltage", 2, - &vcc_sdhi2_info, sizeof(struct fixed_voltage_config)); - platform_device_register_data(NULL, "gpio-regulator", 0, - &vccq_sdhi0_info, sizeof(struct gpio_regulator_config)); - platform_device_register_data(NULL, "gpio-regulator", 1, - &vccq_sdhi1_info, sizeof(struct gpio_regulator_config)); - platform_device_register_data(NULL, "gpio-regulator", 2, - &vccq_sdhi2_info, sizeof(struct gpio_regulator_config)); - - platform_device_register_resndata(NULL, "sh_mobile_sdhi", 0, - sdhi0_resources, ARRAY_SIZE(sdhi0_resources), - &sdhi0_info, sizeof(struct sh_mobile_sdhi_info)); - - platform_device_register_resndata(NULL, "sh_mobile_sdhi", 1, - sdhi1_resources, ARRAY_SIZE(sdhi1_resources), - &sdhi1_info, sizeof(struct sh_mobile_sdhi_info)); - - platform_device_register_resndata(NULL, "sh_mobile_sdhi", 2, - sdhi2_resources, ARRAY_SIZE(sdhi2_resources), - &sdhi2_info, sizeof(struct sh_mobile_sdhi_info)); - -} - -/* - * Ether LEDs on the Koelsch board are named LINK and ACTIVE which corresponds - * to non-default 01 setting of the Micrel KSZ8041 PHY control register 1 bits - * 14-15. We have to set them back to 01 from the default 00 value each time - * the PHY is reset. It's also important because the PHY's LED0 signal is - * connected to SoC's ETH_LINK signal and in the PHY's default mode it will - * bounce on and off after each packet, which we apparently want to avoid. - */ -static int koelsch_ksz8041_fixup(struct phy_device *phydev) -{ - u16 phyctrl1 = phy_read(phydev, 0x1e); - - phyctrl1 &= ~0xc000; - phyctrl1 |= 0x4000; - return phy_write(phydev, 0x1e, phyctrl1); -} - -static void __init koelsch_init(void) -{ - koelsch_add_standard_devices(); - - irq_set_irq_type(irq_pin(0), IRQ_TYPE_LEVEL_LOW); - - if (IS_ENABLED(CONFIG_PHYLIB)) - phy_register_fixup_for_id("r8a7791-ether-ff:01", - koelsch_ksz8041_fixup); -} - -static const char * const koelsch_boards_compat_dt[] __initconst = { - "renesas,koelsch", - NULL, -}; - -DT_MACHINE_START(KOELSCH_DT, "koelsch") - .smp = smp_ops(r8a7791_smp_ops), - .init_early = shmobile_init_delay, - .init_time = rcar_gen2_timer_init, - .init_machine = koelsch_init, - .init_late = shmobile_init_late, - .reserve = rcar_gen2_reserve, - .dt_compat = koelsch_boards_compat_dt, -MACHINE_END diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c index d9cdf9a97e23..2e82e44ab852 100644 --- a/arch/arm/mach-shmobile/board-kzm9g-reference.c +++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/delay.h> @@ -43,6 +39,13 @@ static void __init kzm_init(void) #endif } +#define RESCNT2 IOMEM(0xe6188020) +static void kzm9g_restart(enum reboot_mode mode, const char *cmd) +{ + /* Do soft power on reset */ + writel((1 << 31), RESCNT2); +} + static const char *kzm9g_boards_compat_dt[] __initdata = { "renesas,kzm9g-reference", NULL, @@ -54,5 +57,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference") .init_early = shmobile_init_delay, .init_machine = kzm_init, .init_late = shmobile_init_late, + .restart = kzm9g_restart, .dt_compat = kzm9g_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 77e36fa0b142..7c9b63bdde9f 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/delay.h> diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c index bc4b48357dde..fa06bdba61df 100644 --- a/arch/arm/mach-shmobile/board-lager-reference.c +++ b/arch/arm/mach-shmobile/board-lager-reference.c @@ -12,100 +12,17 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <linux/dma-mapping.h> #include <linux/init.h> #include <linux/of_platform.h> -#include <linux/platform_data/rcar-du.h> #include <asm/mach/arch.h> -#include "clock.h" #include "common.h" -#include "irqs.h" #include "r8a7790.h" #include "rcar-gen2.h" -/* DU */ -static struct rcar_du_encoder_data lager_du_encoders[] = { - { - .type = RCAR_DU_ENCODER_VGA, - .output = RCAR_DU_OUTPUT_DPAD0, - }, { - .type = RCAR_DU_ENCODER_NONE, - .output = RCAR_DU_OUTPUT_LVDS1, - .connector.lvds.panel = { - .width_mm = 210, - .height_mm = 158, - .mode = { - .pixelclock = 65000000, - .hactive = 1024, - .hfront_porch = 20, - .hback_porch = 160, - .hsync_len = 136, - .vactive = 768, - .vfront_porch = 3, - .vback_porch = 29, - .vsync_len = 6, - }, - }, - }, -}; - -static struct rcar_du_platform_data lager_du_pdata = { - .encoders = lager_du_encoders, - .num_encoders = ARRAY_SIZE(lager_du_encoders), -}; - -static const struct resource du_resources[] __initconst = { - DEFINE_RES_MEM(0xfeb00000, 0x70000), - DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"), - DEFINE_RES_MEM_NAMED(0xfeb94000, 0x1c, "lvds.1"), - DEFINE_RES_IRQ(gic_spi(256)), - DEFINE_RES_IRQ(gic_spi(268)), - DEFINE_RES_IRQ(gic_spi(269)), -}; - -static void __init lager_add_du_device(void) -{ - struct platform_device_info info = { - .name = "rcar-du-r8a7790", - .id = -1, - .res = du_resources, - .num_res = ARRAY_SIZE(du_resources), - .data = &lager_du_pdata, - .size_data = sizeof(lager_du_pdata), - .dma_mask = DMA_BIT_MASK(32), - }; - - platform_device_register_full(&info); -} - -/* - * This is a really crude hack to provide clkdev support to platform - * devices until they get moved to DT. - */ -static const struct clk_name clk_names[] __initconst = { - { "du0", "du.0", "rcar-du-r8a7790" }, - { "du1", "du.1", "rcar-du-r8a7790" }, - { "du2", "du.2", "rcar-du-r8a7790" }, - { "lvds0", "lvds.0", "rcar-du-r8a7790" }, - { "lvds1", "lvds.1", "rcar-du-r8a7790" }, -}; - -static void __init lager_add_standard_devices(void) -{ - shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - - lager_add_du_device(); -} - static const char *lager_boards_compat_dt[] __initdata = { "renesas,lager", "renesas,lager-reference", @@ -116,7 +33,6 @@ DT_MACHINE_START(LAGER_DT, "lager") .smp = smp_ops(r8a7790_smp_ops), .init_early = shmobile_init_delay, .init_time = rcar_gen2_timer_init, - .init_machine = lager_add_standard_devices, .init_late = shmobile_init_late, .reserve = rcar_gen2_reserve, .dt_compat = lager_boards_compat_dt, diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index 571327b1c942..b47262afb240 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/gpio.h> diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index ca5d34b92aa7..ed1087031c5d 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -16,10 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/delay.h> #include <linux/kernel.h> diff --git a/arch/arm/mach-shmobile/board-marzen-reference.c b/arch/arm/mach-shmobile/board-marzen-reference.c index 38d9cdd26587..b15eb923263f 100644 --- a/arch/arm/mach-shmobile/board-marzen-reference.c +++ b/arch/arm/mach-shmobile/board-marzen-reference.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/clk/shmobile.h> @@ -26,7 +22,6 @@ #include <asm/irq.h> #include <asm/mach/arch.h> -#include "clock.h" #include "common.h" #include "irqs.h" #include "r8a7779.h" diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index ce33d7825c49..994dc7d86ae2 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> diff --git a/arch/arm/mach-shmobile/clock-r8a73a4.c b/arch/arm/mach-shmobile/clock-r8a73a4.c index c2330ea1802c..1cf44dc6d718 100644 --- a/arch/arm/mach-shmobile/clock-r8a73a4.c +++ b/arch/arm/mach-shmobile/clock-r8a73a4.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/init.h> #include <linux/io.h> diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c index 0794f0426e70..9cac8247c72b 100644 --- a/arch/arm/mach-shmobile/clock-r8a7740.c +++ b/arch/arm/mach-shmobile/clock-r8a7740.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h> #include <linux/kernel.h> @@ -455,7 +451,7 @@ enum { MSTP128, MSTP127, MSTP125, MSTP116, MSTP111, MSTP100, MSTP117, - MSTP230, + MSTP230, MSTP229, MSTP222, MSTP218, MSTP217, MSTP216, MSTP214, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, @@ -474,11 +470,12 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP127] = SH_CLK_MSTP32(&div4_clks[DIV4_S], SMSTPCR1, 27, 0), /* CEU20 */ [MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */ [MSTP117] = SH_CLK_MSTP32(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ - [MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ + [MSTP116] = SH_CLK_MSTP32(&div4_clks[DIV4_HPP], SMSTPCR1, 16, 0), /* IIC0 */ [MSTP111] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 11, 0), /* TMU1 */ [MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */ [MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 30, 0), /* SCIFA6 */ + [MSTP229] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 29, 0), /* INTCA */ [MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 22, 0), /* SCIFA7 */ [MSTP218] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */ [MSTP217] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */ @@ -575,6 +572,10 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP222]), CLKDEV_DEV_ID("e6cd0000.serial", &mstp_clks[MSTP222]), + CLKDEV_DEV_ID("renesas_intc_irqpin.0", &mstp_clks[MSTP229]), + CLKDEV_DEV_ID("renesas_intc_irqpin.1", &mstp_clks[MSTP229]), + CLKDEV_DEV_ID("renesas_intc_irqpin.2", &mstp_clks[MSTP229]), + CLKDEV_DEV_ID("renesas_intc_irqpin.3", &mstp_clks[MSTP229]), CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]), CLKDEV_DEV_ID("e6cc0000.serial", &mstp_clks[MSTP230]), diff --git a/arch/arm/mach-shmobile/clock-r8a7778.c b/arch/arm/mach-shmobile/clock-r8a7778.c index 67980a08a601..e8510c35558c 100644 --- a/arch/arm/mach-shmobile/clock-r8a7778.c +++ b/arch/arm/mach-shmobile/clock-r8a7778.c @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index c51f9db3f66f..fa8ab2cc9187 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/bitops.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index 126ddafad526..f9bbc5f0a9a1 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/init.h> #include <linux/io.h> @@ -68,7 +64,7 @@ #define SDCKCR 0xE6150074 #define SD2CKCR 0xE6150078 -#define SD3CKCR 0xE615007C +#define SD3CKCR 0xE615026C #define MMC0CKCR 0xE6150240 #define MMC1CKCR 0xE6150244 #define SSPCKCR 0xE6150248 diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c deleted file mode 100644 index 453b23129cfa..000000000000 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * r8a7791 clock framework support - * - * Copyright (C) 2013 Renesas Electronics Corporation - * Copyright (C) 2013 Renesas Solutions Corp. - * Copyright (C) 2013 Magnus Damm - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include <linux/init.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/sh_clk.h> -#include <linux/clkdev.h> -#include "clock.h" -#include "common.h" -#include "rcar-gen2.h" - -/* - * MD EXTAL PLL0 PLL1 PLL3 - * 14 13 19 (MHz) *1 *1 - *--------------------------------------------------- - * 0 0 0 15 x 1 x172/2 x208/2 x106 - * 0 0 1 15 x 1 x172/2 x208/2 x88 - * 0 1 0 20 x 1 x130/2 x156/2 x80 - * 0 1 1 20 x 1 x130/2 x156/2 x66 - * 1 0 0 26 / 2 x200/2 x240/2 x122 - * 1 0 1 26 / 2 x200/2 x240/2 x102 - * 1 1 0 30 / 2 x172/2 x208/2 x106 - * 1 1 1 30 / 2 x172/2 x208/2 x88 - * - * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2) - * see "p1 / 2" on R8A7791_CLOCK_ROOT() below - */ - -#define CPG_BASE 0xe6150000 -#define CPG_LEN 0x1000 - -#define SMSTPCR0 0xE6150130 -#define SMSTPCR1 0xE6150134 -#define SMSTPCR2 0xe6150138 -#define SMSTPCR3 0xE615013C -#define SMSTPCR5 0xE6150144 -#define SMSTPCR7 0xe615014c -#define SMSTPCR8 0xE6150990 -#define SMSTPCR9 0xE6150994 -#define SMSTPCR10 0xE6150998 -#define SMSTPCR11 0xE615099C - -#define MSTPSR1 IOMEM(0xe6150038) -#define MSTPSR2 IOMEM(0xe6150040) -#define MSTPSR3 IOMEM(0xe6150048) -#define MSTPSR5 IOMEM(0xe615003c) -#define MSTPSR7 IOMEM(0xe61501c4) -#define MSTPSR8 IOMEM(0xe61509a0) -#define MSTPSR9 IOMEM(0xe61509a4) -#define MSTPSR11 IOMEM(0xe61509ac) - -#define SDCKCR 0xE6150074 -#define SD1CKCR 0xE6150078 -#define SD2CKCR 0xE615026c -#define MMC0CKCR 0xE6150240 -#define MMC1CKCR 0xE6150244 -#define SSPCKCR 0xE6150248 -#define SSPRSCKCR 0xE615024C - -static struct clk_mapping cpg_mapping = { - .phys = CPG_BASE, - .len = CPG_LEN, -}; - -static struct clk extal_clk = { - /* .rate will be updated on r8a7791_clock_init() */ - .mapping = &cpg_mapping, -}; - -static struct sh_clk_ops followparent_clk_ops = { - .recalc = followparent_recalc, -}; - -static struct clk main_clk = { - /* .parent will be set r8a73a4_clock_init */ - .ops = &followparent_clk_ops, -}; - -/* - * clock ratio of these clock will be updated - * on r8a7791_clock_init() - */ -SH_FIXED_RATIO_CLK_SET(pll1_clk, main_clk, 1, 1); -SH_FIXED_RATIO_CLK_SET(pll3_clk, main_clk, 1, 1); -SH_FIXED_RATIO_CLK_SET(qspi_clk, pll1_clk, 1, 1); - -/* fixed ratio clock */ -SH_FIXED_RATIO_CLK_SET(extal_div2_clk, extal_clk, 1, 2); -SH_FIXED_RATIO_CLK_SET(cp_clk, extal_clk, 1, 2); - -SH_FIXED_RATIO_CLK_SET(pll1_div2_clk, pll1_clk, 1, 2); -SH_FIXED_RATIO_CLK_SET(hp_clk, pll1_clk, 1, 12); -SH_FIXED_RATIO_CLK_SET(p_clk, pll1_clk, 1, 24); -SH_FIXED_RATIO_CLK_SET(rclk_clk, pll1_clk, 1, (48 * 1024)); -SH_FIXED_RATIO_CLK_SET(mp_clk, pll1_div2_clk, 1, 15); -SH_FIXED_RATIO_CLK_SET(zg_clk, pll1_clk, 1, 3); -SH_FIXED_RATIO_CLK_SET(zx_clk, pll1_clk, 1, 3); -SH_FIXED_RATIO_CLK_SET(zs_clk, pll1_clk, 1, 6); - -static struct clk *main_clks[] = { - &extal_clk, - &extal_div2_clk, - &main_clk, - &pll1_clk, - &pll1_div2_clk, - &pll3_clk, - &hp_clk, - &p_clk, - &qspi_clk, - &rclk_clk, - &mp_clk, - &cp_clk, - &zg_clk, - &zx_clk, - &zs_clk, -}; - -/* SDHI (DIV4) clock */ -static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, 24, 0, 36, 48, 10 }; - -static struct clk_div_mult_table div4_div_mult_table = { - .divisors = divisors, - .nr_divisors = ARRAY_SIZE(divisors), -}; - -static struct clk_div4_table div4_table = { - .div_mult_table = &div4_div_mult_table, -}; - -enum { - DIV4_SDH, DIV4_SD0, - DIV4_NR -}; - -static struct clk div4_clks[DIV4_NR] = { - [DIV4_SDH] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 8, 0x0dff, CLK_ENABLE_ON_INIT), - [DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1df0, CLK_ENABLE_ON_INIT), -}; - -/* DIV6 clocks */ -enum { - DIV6_SD1, DIV6_SD2, - DIV6_NR -}; - -static struct clk div6_clks[DIV6_NR] = { - [DIV6_SD1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0), - [DIV6_SD2] = SH_CLK_DIV6(&pll1_div2_clk, SD2CKCR, 0), -}; - -/* MSTP */ -enum { - MSTP1108, MSTP1107, MSTP1106, - MSTP931, MSTP930, MSTP929, MSTP928, MSTP927, MSTP925, - MSTP917, - MSTP815, MSTP814, - MSTP813, - MSTP811, MSTP810, MSTP809, - MSTP726, MSTP724, MSTP723, MSTP721, MSTP720, - MSTP719, MSTP718, MSTP715, MSTP714, - MSTP522, - MSTP314, MSTP312, MSTP311, - MSTP216, MSTP207, MSTP206, - MSTP204, MSTP203, MSTP202, - MSTP124, - MSTP_NR -}; - -static struct clk mstp_clks[MSTP_NR] = { - [MSTP1108] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 8, MSTPSR11, 0), /* SCIFA5 */ - [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA4 */ - [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA3 */ - [MSTP931] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */ - [MSTP930] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */ - [MSTP929] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */ - [MSTP928] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */ - [MSTP927] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */ - [MSTP925] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */ - [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */ - [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */ - [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */ - [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */ - [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */ - [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */ - [MSTP809] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 9, MSTPSR8, 0), /* VIN2 */ - [MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */ - [MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */ - [MSTP723] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 23, MSTPSR7, 0), /* DU1 */ - [MSTP721] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 21, MSTPSR7, 0), /* SCIF0 */ - [MSTP720] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 20, MSTPSR7, 0), /* SCIF1 */ - [MSTP719] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 19, MSTPSR7, 0), /* SCIF2 */ - [MSTP718] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 18, MSTPSR7, 0), /* SCIF3 */ - [MSTP715] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 15, MSTPSR7, 0), /* SCIF4 */ - [MSTP714] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 14, MSTPSR7, 0), /* SCIF5 */ - [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */ - [MSTP314] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD0], SMSTPCR3, 14, MSTPSR3, 0), /* SDHI0 */ - [MSTP312] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD1], SMSTPCR3, 12, MSTPSR3, 0), /* SDHI1 */ - [MSTP311] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD2], SMSTPCR3, 11, MSTPSR3, 0), /* SDHI2 */ - [MSTP216] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 16, MSTPSR2, 0), /* SCIFB2 */ - [MSTP207] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 7, MSTPSR2, 0), /* SCIFB1 */ - [MSTP206] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 6, MSTPSR2, 0), /* SCIFB0 */ - [MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */ - [MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */ - [MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */ - [MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */ -}; - -static struct clk_lookup lookups[] = { - - /* main clocks */ - CLKDEV_CON_ID("extal", &extal_clk), - CLKDEV_CON_ID("extal_div2", &extal_div2_clk), - CLKDEV_CON_ID("main", &main_clk), - CLKDEV_CON_ID("pll1", &pll1_clk), - CLKDEV_CON_ID("pll1_div2", &pll1_div2_clk), - CLKDEV_CON_ID("pll3", &pll3_clk), - CLKDEV_CON_ID("zg", &zg_clk), - CLKDEV_CON_ID("zs", &zs_clk), - CLKDEV_CON_ID("hp", &hp_clk), - CLKDEV_CON_ID("p", &p_clk), - CLKDEV_CON_ID("qspi", &qspi_clk), - CLKDEV_CON_ID("rclk", &rclk_clk), - CLKDEV_CON_ID("mp", &mp_clk), - CLKDEV_CON_ID("cp", &cp_clk), - CLKDEV_CON_ID("peripheral_clk", &hp_clk), - - /* MSTP */ - CLKDEV_ICK_ID("lvds.0", "rcar-du-r8a7791", &mstp_clks[MSTP726]), - CLKDEV_ICK_ID("du.0", "rcar-du-r8a7791", &mstp_clks[MSTP724]), - CLKDEV_ICK_ID("du.1", "rcar-du-r8a7791", &mstp_clks[MSTP723]), - CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */ - CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */ - CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP206]), /* SCIFB0 */ - CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP207]), /* SCIFB1 */ - CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP216]), /* SCIFB2 */ - CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP202]), /* SCIFA2 */ - CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP721]), /* SCIF0 */ - CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP720]), /* SCIF1 */ - CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP719]), /* SCIF2 */ - CLKDEV_DEV_ID("sh-sci.9", &mstp_clks[MSTP718]), /* SCIF3 */ - CLKDEV_DEV_ID("sh-sci.10", &mstp_clks[MSTP715]), /* SCIF4 */ - CLKDEV_DEV_ID("sh-sci.11", &mstp_clks[MSTP714]), /* SCIF5 */ - CLKDEV_DEV_ID("sh-sci.12", &mstp_clks[MSTP1106]), /* SCIFA3 */ - CLKDEV_DEV_ID("sh-sci.13", &mstp_clks[MSTP1107]), /* SCIFA4 */ - CLKDEV_DEV_ID("sh-sci.14", &mstp_clks[MSTP1108]), /* SCIFA5 */ - CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), - CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP312]), - CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), - CLKDEV_ICK_ID("fck", "sh-cmt-48-gen2.0", &mstp_clks[MSTP124]), - CLKDEV_DEV_ID("qspi.0", &mstp_clks[MSTP917]), - CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]), - CLKDEV_DEV_ID("i2c-rcar_gen2.0", &mstp_clks[MSTP931]), - CLKDEV_DEV_ID("i2c-rcar_gen2.1", &mstp_clks[MSTP930]), - CLKDEV_DEV_ID("i2c-rcar_gen2.2", &mstp_clks[MSTP929]), - CLKDEV_DEV_ID("i2c-rcar_gen2.3", &mstp_clks[MSTP928]), - CLKDEV_DEV_ID("i2c-rcar_gen2.4", &mstp_clks[MSTP927]), - CLKDEV_DEV_ID("i2c-rcar_gen2.5", &mstp_clks[MSTP925]), - CLKDEV_DEV_ID("r8a7791-ether", &mstp_clks[MSTP813]), /* Ether */ - CLKDEV_DEV_ID("r8a7791-vin.0", &mstp_clks[MSTP811]), - CLKDEV_DEV_ID("r8a7791-vin.1", &mstp_clks[MSTP810]), - CLKDEV_DEV_ID("r8a7791-vin.2", &mstp_clks[MSTP809]), - CLKDEV_DEV_ID("sata-r8a7791.0", &mstp_clks[MSTP815]), - CLKDEV_DEV_ID("sata-r8a7791.1", &mstp_clks[MSTP814]), -}; - -#define R8A7791_CLOCK_ROOT(e, m, p0, p1, p30, p31) \ - extal_clk.rate = e * 1000 * 1000; \ - main_clk.parent = m; \ - SH_CLK_SET_RATIO(&pll1_clk_ratio, p1 / 2, 1); \ - if (mode & MD(19)) \ - SH_CLK_SET_RATIO(&pll3_clk_ratio, p31, 1); \ - else \ - SH_CLK_SET_RATIO(&pll3_clk_ratio, p30, 1) - - -void __init r8a7791_clock_init(void) -{ - u32 mode = rcar_gen2_read_mode_pins(); - int k, ret = 0; - - switch (mode & (MD(14) | MD(13))) { - case 0: - R8A7791_CLOCK_ROOT(15, &extal_clk, 172, 208, 106, 88); - break; - case MD(13): - R8A7791_CLOCK_ROOT(20, &extal_clk, 130, 156, 80, 66); - break; - case MD(14): - R8A7791_CLOCK_ROOT(26, &extal_div2_clk, 200, 240, 122, 102); - break; - case MD(13) | MD(14): - R8A7791_CLOCK_ROOT(30, &extal_div2_clk, 172, 208, 106, 88); - break; - } - - if ((mode & (MD(3) | MD(2) | MD(1))) == MD(2)) - SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 16); - else - SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 20); - - for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) - ret = clk_register(main_clks[k]); - - if (!ret) - ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); - - if (!ret) - ret = sh_clk_div6_register(div6_clks, DIV6_NR); - - if (!ret) - ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); - - clkdev_add_table(lookups, ARRAY_SIZE(lookups)); - - if (!ret) - shmobile_clk_init(); - else - goto epanic; - - return; - -epanic: - panic("failed to setup r8a7791 clocks\n"); -} diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 7071676145c4..3bc92f46060e 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h> #include <linux/kernel.h> diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 02a6f45a0b9e..6b4c1f313cc9 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h> #include <linux/kernel.h> diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c index 806f94038cc4..34f056fc3756 100644 --- a/arch/arm/mach-shmobile/clock.c +++ b/arch/arm/mach-shmobile/clock.c @@ -14,41 +14,13 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ + +#include <linux/export.h> #include <linux/kernel.h> #include <linux/init.h> - -#ifdef CONFIG_COMMON_CLK -#include <linux/clk.h> -#include <linux/clkdev.h> -#include "clock.h" - -void __init shmobile_clk_workaround(const struct clk_name *clks, - int nr_clks, bool enable) -{ - const struct clk_name *clkn; - struct clk *clk; - unsigned int i; - - for (i = 0; i < nr_clks; ++i) { - clkn = clks + i; - clk = clk_get(NULL, clkn->clk); - if (!IS_ERR(clk)) { - clk_register_clkdev(clk, clkn->con_id, clkn->dev_id); - if (enable) - clk_prepare_enable(clk); - clk_put(clk); - } - } -} - -#else /* CONFIG_COMMON_CLK */ #include <linux/sh_clk.h> -#include <linux/export.h> + #include "clock.h" #include "common.h" @@ -84,5 +56,3 @@ void __clk_put(struct clk *clk) { } EXPORT_SYMBOL(__clk_put); - -#endif /* CONFIG_COMMON_CLK */ diff --git a/arch/arm/mach-shmobile/clock.h b/arch/arm/mach-shmobile/clock.h index 31b6417463e6..cf3552ea1019 100644 --- a/arch/arm/mach-shmobile/clock.h +++ b/arch/arm/mach-shmobile/clock.h @@ -1,19 +1,6 @@ #ifndef CLOCK_H #define CLOCK_H -#ifdef CONFIG_COMMON_CLK -/* temporary clock configuration helper for platform devices */ - -struct clk_name { - const char *clk; - const char *con_id; - const char *dev_id; -}; - -void shmobile_clk_workaround(const struct clk_name *clks, int nr_clks, - bool enable); - -#else /* CONFIG_COMMON_CLK */ /* legacy clock implementation */ struct clk; @@ -52,5 +39,4 @@ do { \ (p)->div = d; \ } while (0) -#endif /* CONFIG_COMMON_CLK */ #endif diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h index 72087c79ad7b..309025efd4cf 100644 --- a/arch/arm/mach-shmobile/common.h +++ b/arch/arm/mach-shmobile/common.h @@ -19,11 +19,6 @@ extern void shmobile_boot_scu(void); extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus); extern void shmobile_smp_scu_cpu_die(unsigned int cpu); extern int shmobile_smp_scu_cpu_kill(unsigned int cpu); -extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus); -extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, - struct task_struct *idle); -extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); -extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); struct clk; extern int shmobile_clk_init(void); extern void shmobile_handle_irq_intc(struct pt_regs *); diff --git a/arch/arm/mach-shmobile/console.c b/arch/arm/mach-shmobile/console.c index f2e79f2376e1..e329ccbd0a67 100644 --- a/arch/arm/mach-shmobile/console.c +++ b/arch/arm/mach-shmobile/console.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/headsmp-scu.S b/arch/arm/mach-shmobile/headsmp-scu.S index f45dde701d7b..69df8bfac167 100644 --- a/arch/arm/mach-shmobile/headsmp-scu.S +++ b/arch/arm/mach-shmobile/headsmp-scu.S @@ -12,11 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA */ #include <linux/linkage.h> diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index e2af00b1bd9d..1ccf49cb485f 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 44457a94897b..9e3618028acc 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c index 2c06810d3a70..f483b560b066 100644 --- a/arch/arm/mach-shmobile/platsmp-apmu.c +++ b/arch/arm/mach-shmobile/platsmp-apmu.c @@ -1,6 +1,7 @@ /* * SMP support for SoCs with APMU * + * Copyright (C) 2014 Renesas Electronics Corporation * Copyright (C) 2013 Magnus Damm * * This program is free software; you can redistribute it and/or modify @@ -22,6 +23,7 @@ #include <asm/smp_plat.h> #include <asm/suspend.h> #include "common.h" +#include "platsmp-apmu.h" static struct { void __iomem *iomem; @@ -83,28 +85,15 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit) pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res); } -static struct { - struct resource iomem; - int cpus[4]; -} apmu_config[] = { - { - .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), - .cpus = { 0, 1, 2, 3 }, - }, - { - .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), - .cpus = { 0x100, 0x101, 0x102, 0x103 }, - } -}; - -static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) +static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit), + struct rcar_apmu_config *apmu_config, int num) { u32 id; int k; int bit, index; bool is_allowed; - for (k = 0; k < ARRAY_SIZE(apmu_config); k++) { + for (k = 0; k < num; k++) { /* only enable the cluster that includes the boot CPU */ is_allowed = false; for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) { @@ -128,14 +117,16 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) } } -void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus) +void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, + struct rcar_apmu_config *apmu_config, + int num) { /* install boot code shared by all CPUs */ shmobile_boot_fn = virt_to_phys(shmobile_smp_boot); shmobile_boot_arg = MPIDR_HWID_BITMASK; /* perform per-cpu setup */ - apmu_parse_cfg(apmu_init_cpu); + apmu_parse_cfg(apmu_init_cpu, apmu_config, num); } #ifdef CONFIG_SMP diff --git a/arch/arm/mach-shmobile/platsmp-apmu.h b/arch/arm/mach-shmobile/platsmp-apmu.h new file mode 100644 index 000000000000..76512c9a2545 --- /dev/null +++ b/arch/arm/mach-shmobile/platsmp-apmu.h @@ -0,0 +1,32 @@ +/* + * rmobile apmu definition + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef PLATSMP_APMU_H +#define PLATSMP_APMU_H + +struct rcar_apmu_config { + struct resource iomem; + int cpus[4]; +}; + +extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus, + struct rcar_apmu_config *apmu_config, + int num); +extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, + struct task_struct *idle); +extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); +extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); + +#endif /* PLATSMP_APMU_H */ diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c index e3f146448237..ac2eecd6f5ea 100644 --- a/arch/arm/mach-shmobile/pm-r8a7740.c +++ b/arch/arm/mach-shmobile/pm-r8a7740.c @@ -14,10 +14,10 @@ #include "pm-rmobile.h" #if defined(CONFIG_PM) && !defined(CONFIG_ARCH_MULTIPLATFORM) -static int r8a7740_pd_a4s_suspend(void) +static int r8a7740_pd_a3sm_suspend(void) { /* - * The A4S domain contains the CPU core and therefore it should + * The A3SM domain contains the CPU core and therefore it should * only be turned off if the CPU is not in use. */ return -EBUSY; @@ -32,29 +32,65 @@ static int r8a7740_pd_a3sp_suspend(void) return console_suspend_enabled ? 0 : -EBUSY; } +static int r8a7740_pd_d4_suspend(void) +{ + /* + * The D4 domain contains the Coresight-ETM hardware block and + * therefore it should only be turned off if the debug module is + * not in use. + */ + return -EBUSY; +} + static struct rmobile_pm_domain r8a7740_pm_domains[] = { { .genpd.name = "A4LC", .bit_shift = 1, }, { + .genpd.name = "A4MP", + .bit_shift = 2, + }, { + .genpd.name = "D4", + .bit_shift = 3, + .gov = &pm_domain_always_on_gov, + .suspend = r8a7740_pd_d4_suspend, + }, { + .genpd.name = "A4R", + .bit_shift = 5, + }, { + .genpd.name = "A3RV", + .bit_shift = 6, + }, { .genpd.name = "A4S", .bit_shift = 10, - .gov = &pm_domain_always_on_gov, .no_debug = true, - .suspend = r8a7740_pd_a4s_suspend, }, { .genpd.name = "A3SP", .bit_shift = 11, .gov = &pm_domain_always_on_gov, .no_debug = true, .suspend = r8a7740_pd_a3sp_suspend, + }, { + .genpd.name = "A3SM", + .bit_shift = 12, + .gov = &pm_domain_always_on_gov, + .suspend = r8a7740_pd_a3sm_suspend, + }, { + .genpd.name = "A3SG", + .bit_shift = 13, + }, { + .genpd.name = "A4SU", + .bit_shift = 20, }, }; void __init r8a7740_init_pm_domains(void) { rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains)); + pm_genpd_add_subdomain_names("A4R", "A3RV"); pm_genpd_add_subdomain_names("A4S", "A3SP"); + pm_genpd_add_subdomain_names("A4S", "A3SM"); + pm_genpd_add_subdomain_names("A4S", "A3SG"); } #endif /* CONFIG_PM && !CONFIG_ARCH_MULTIPLATFORM */ diff --git a/arch/arm/mach-shmobile/r8a7740.h b/arch/arm/mach-shmobile/r8a7740.h index f369b4b0863d..ca7805ad7ea3 100644 --- a/arch/arm/mach-shmobile/r8a7740.h +++ b/arch/arm/mach-shmobile/r8a7740.h @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __ASM_R8A7740_H__ diff --git a/arch/arm/mach-shmobile/r8a7778.h b/arch/arm/mach-shmobile/r8a7778.h index f4076a50e970..f64fedb1f2cc 100644 --- a/arch/arm/mach-shmobile/r8a7778.h +++ b/arch/arm/mach-shmobile/r8a7778.h @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __ASM_R8A7778_H__ #define __ASM_R8A7778_H__ @@ -71,7 +67,6 @@ extern void r8a7778_add_standard_devices_dt(void); extern void r8a7778_add_dt_devices(void); extern void r8a7778_init_late(void); -extern void r8a7778_init_delay(void); extern void r8a7778_init_irq_dt(void); extern void r8a7778_clock_init(void); extern void r8a7778_init_irq_extpin(int irlm); diff --git a/arch/arm/mach-shmobile/r8a7791.h b/arch/arm/mach-shmobile/r8a7791.h index c1bf7abefa5a..6cf11eb69d10 100644 --- a/arch/arm/mach-shmobile/r8a7791.h +++ b/arch/arm/mach-shmobile/r8a7791.h @@ -1,9 +1,6 @@ #ifndef __ASM_R8A7791_H__ #define __ASM_R8A7791_H__ -void r8a7791_add_standard_devices(void); -void r8a7791_clock_init(void); -void r8a7791_pinmux_init(void); void r8a7791_pm_init(void); extern struct smp_operations r8a7791_smp_ops; diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index b06a9e8f59a5..aad97be9cbe1 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/setup-r7s72100.c b/arch/arm/mach-shmobile/setup-r7s72100.c index 4122104359f9..171174777b6f 100644 --- a/arch/arm/mach-shmobile/setup-r7s72100.c +++ b/arch/arm/mach-shmobile/setup-r7s72100.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> diff --git a/arch/arm/mach-shmobile/setup-r8a73a4.c b/arch/arm/mach-shmobile/setup-r8a73a4.c index 53f40b70680d..b88b88a40a3c 100644 --- a/arch/arm/mach-shmobile/setup-r8a73a4.c +++ b/arch/arm/mach-shmobile/setup-r8a73a4.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/irq.h> #include <linux/kernel.h> diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8894e1b7ab0e..79ad93dfdae4 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -71,6 +67,7 @@ static struct map_desc r8a7740_io_desc[] __initdata = { void __init r8a7740_map_io(void) { + debug_ll_io_init(); iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc)); } @@ -746,6 +743,12 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev) void __init r8a7740_add_standard_devices(void) { static struct pm_domain_device domain_devices[] __initdata = { + { "A4R", &tmu0_device }, + { "A4R", &i2c0_device }, + { "A4S", &irqpin0_device }, + { "A4S", &irqpin1_device }, + { "A4S", &irqpin2_device }, + { "A4S", &irqpin3_device }, { "A3SP", &scif0_device }, { "A3SP", &scif1_device }, { "A3SP", &scif2_device }, @@ -756,6 +759,11 @@ void __init r8a7740_add_standard_devices(void) { "A3SP", &scif7_device }, { "A3SP", &scif8_device }, { "A3SP", &i2c1_device }, + { "A3SP", &ipmmu_device }, + { "A3SP", &dma0_device }, + { "A3SP", &dma1_device }, + { "A3SP", &dma2_device }, + { "A3SP", &usb_dma_device }, }; /* I2C work-around */ diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c index 85fe016d6a87..45bd3588fa15 100644 --- a/arch/arm/mach-shmobile/setup-r8a7778.c +++ b/arch/arm/mach-shmobile/setup-r8a7778.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> @@ -572,11 +568,6 @@ void __init r8a7778_init_irq_extpin(int irlm) &irqpin_platform_data, sizeof(irqpin_platform_data)); } -void __init r8a7778_init_delay(void) -{ - shmobile_init_delay(); -} - #ifdef CONFIG_USE_OF #define INT2SMSKCR0 0x82288 /* 0xfe782288 */ #define INT2SMSKCR1 0x8228c /* 0xfe78228c */ @@ -608,7 +599,7 @@ static const char *r8a7778_compat_dt[] __initdata = { }; DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)") - .init_early = r8a7778_init_delay, + .init_early = shmobile_init_delay, .init_irq = r8a7778_init_irq_dt, .init_late = shmobile_init_late, .dt_compat = r8a7778_compat_dt, diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 136078ab9407..6156d172cf31 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> @@ -52,14 +48,14 @@ #include "r8a7779.h" static struct map_desc r8a7779_io_desc[] __initdata = { - /* 2M entity map for 0xf0000000 (MPCORE) */ + /* 2M identity mapping for 0xf0000000 (MPCORE) */ { .virtual = 0xf0000000, .pfn = __phys_to_pfn(0xf0000000), .length = SZ_2M, .type = MT_DEVICE_NONSHARED }, - /* 16M entity map for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */ + /* 16M identity mapping for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */ { .virtual = 0xfe000000, .pfn = __phys_to_pfn(0xfe000000), @@ -70,6 +66,7 @@ static struct map_desc r8a7779_io_desc[] __initdata = { void __init r8a7779_map_io(void) { + debug_ll_io_init(); iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc)); } @@ -683,7 +680,7 @@ void __init r8a7779_add_early_devices(void) /* Early serial console setup is not included here due to * memory map collisions. The SCIF serial ports in r8a7779 - * are difficult to entity map 1:1 due to collision with the + * are difficult to identity map 1:1 due to collision with the * virtual memory range used by the coherent DMA code on ARM. * * Anyone wanting to debug early can remove UPF_IOREMAP from diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index 877fdeb985d0..ec7d97dca4de 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/irq.h> diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c index 35d78639244f..ef8eb3af586d 100644 --- a/arch/arm/mach-shmobile/setup-r8a7791.c +++ b/arch/arm/mach-shmobile/setup-r8a7791.c @@ -13,198 +13,16 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <linux/irq.h> -#include <linux/kernel.h> -#include <linux/of_platform.h> -#include <linux/platform_data/gpio-rcar.h> -#include <linux/platform_data/irq-renesas-irqc.h> -#include <linux/serial_sci.h> -#include <linux/sh_timer.h> +#include <linux/init.h> #include <asm/mach/arch.h> #include "common.h" -#include "irqs.h" #include "r8a7791.h" #include "rcar-gen2.h" -static const struct resource pfc_resources[] __initconst = { - DEFINE_RES_MEM(0xe6060000, 0x250), -}; - -#define r8a7791_register_pfc() \ - platform_device_register_simple("pfc-r8a7791", -1, pfc_resources, \ - ARRAY_SIZE(pfc_resources)) - -#define R8A7791_GPIO(idx, base, nr) \ -static const struct resource r8a7791_gpio##idx##_resources[] __initconst = { \ - DEFINE_RES_MEM((base), 0x50), \ - DEFINE_RES_IRQ(gic_spi(4 + (idx))), \ -}; \ - \ -static const struct gpio_rcar_config \ -r8a7791_gpio##idx##_platform_data __initconst = { \ - .gpio_base = 32 * (idx), \ - .irq_base = 0, \ - .number_of_pins = (nr), \ - .pctl_name = "pfc-r8a7791", \ - .has_both_edge_trigger = 1, \ -}; \ - -R8A7791_GPIO(0, 0xe6050000, 32); -R8A7791_GPIO(1, 0xe6051000, 32); -R8A7791_GPIO(2, 0xe6052000, 32); -R8A7791_GPIO(3, 0xe6053000, 32); -R8A7791_GPIO(4, 0xe6054000, 32); -R8A7791_GPIO(5, 0xe6055000, 32); -R8A7791_GPIO(6, 0xe6055400, 32); -R8A7791_GPIO(7, 0xe6055800, 26); - -#define r8a7791_register_gpio(idx) \ - platform_device_register_resndata(NULL, "gpio_rcar", idx, \ - r8a7791_gpio##idx##_resources, \ - ARRAY_SIZE(r8a7791_gpio##idx##_resources), \ - &r8a7791_gpio##idx##_platform_data, \ - sizeof(r8a7791_gpio##idx##_platform_data)) - -void __init r8a7791_pinmux_init(void) -{ - r8a7791_register_pfc(); - r8a7791_register_gpio(0); - r8a7791_register_gpio(1); - r8a7791_register_gpio(2); - r8a7791_register_gpio(3); - r8a7791_register_gpio(4); - r8a7791_register_gpio(5); - r8a7791_register_gpio(6); - r8a7791_register_gpio(7); -} - -#define __R8A7791_SCIF(scif_type, index, baseaddr, irq) \ -static struct plat_sci_port scif##index##_platform_data = { \ - .type = scif_type, \ - .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, \ - .scscr = SCSCR_RE | SCSCR_TE, \ -}; \ - \ -static struct resource scif##index##_resources[] = { \ - DEFINE_RES_MEM(baseaddr, 0x100), \ - DEFINE_RES_IRQ(irq), \ -} - -#define R8A7791_SCIF(index, baseaddr, irq) \ - __R8A7791_SCIF(PORT_SCIF, index, baseaddr, irq) - -#define R8A7791_SCIFA(index, baseaddr, irq) \ - __R8A7791_SCIF(PORT_SCIFA, index, baseaddr, irq) - -#define R8A7791_SCIFB(index, baseaddr, irq) \ - __R8A7791_SCIF(PORT_SCIFB, index, baseaddr, irq) - -R8A7791_SCIFA(0, 0xe6c40000, gic_spi(144)); /* SCIFA0 */ -R8A7791_SCIFA(1, 0xe6c50000, gic_spi(145)); /* SCIFA1 */ -R8A7791_SCIFB(2, 0xe6c20000, gic_spi(148)); /* SCIFB0 */ -R8A7791_SCIFB(3, 0xe6c30000, gic_spi(149)); /* SCIFB1 */ -R8A7791_SCIFB(4, 0xe6ce0000, gic_spi(150)); /* SCIFB2 */ -R8A7791_SCIFA(5, 0xe6c60000, gic_spi(151)); /* SCIFA2 */ -R8A7791_SCIF(6, 0xe6e60000, gic_spi(152)); /* SCIF0 */ -R8A7791_SCIF(7, 0xe6e68000, gic_spi(153)); /* SCIF1 */ -R8A7791_SCIF(8, 0xe6e58000, gic_spi(22)); /* SCIF2 */ -R8A7791_SCIF(9, 0xe6ea8000, gic_spi(23)); /* SCIF3 */ -R8A7791_SCIF(10, 0xe6ee0000, gic_spi(24)); /* SCIF4 */ -R8A7791_SCIF(11, 0xe6ee8000, gic_spi(25)); /* SCIF5 */ -R8A7791_SCIFA(12, 0xe6c70000, gic_spi(29)); /* SCIFA3 */ -R8A7791_SCIFA(13, 0xe6c78000, gic_spi(30)); /* SCIFA4 */ -R8A7791_SCIFA(14, 0xe6c80000, gic_spi(31)); /* SCIFA5 */ - -#define r8a7791_register_scif(index) \ - platform_device_register_resndata(NULL, "sh-sci", index, \ - scif##index##_resources, \ - ARRAY_SIZE(scif##index##_resources), \ - &scif##index##_platform_data, \ - sizeof(scif##index##_platform_data)) - -static struct sh_timer_config cmt0_platform_data = { - .channels_mask = 0x60, -}; - -static struct resource cmt0_resources[] = { - DEFINE_RES_MEM(0xffca0000, 0x1004), - DEFINE_RES_IRQ(gic_spi(142)), -}; - -#define r8a7791_register_cmt(idx) \ - platform_device_register_resndata(NULL, "sh-cmt-48-gen2", \ - idx, cmt##idx##_resources, \ - ARRAY_SIZE(cmt##idx##_resources), \ - &cmt##idx##_platform_data, \ - sizeof(struct sh_timer_config)) - -static struct renesas_irqc_config irqc0_data = { - .irq_base = irq_pin(0), /* IRQ0 -> IRQ9 */ -}; - -static struct resource irqc0_resources[] = { - DEFINE_RES_MEM(0xe61c0000, 0x200), /* IRQC Event Detector Block_0 */ - DEFINE_RES_IRQ(gic_spi(0)), /* IRQ0 */ - DEFINE_RES_IRQ(gic_spi(1)), /* IRQ1 */ - DEFINE_RES_IRQ(gic_spi(2)), /* IRQ2 */ - DEFINE_RES_IRQ(gic_spi(3)), /* IRQ3 */ - DEFINE_RES_IRQ(gic_spi(12)), /* IRQ4 */ - DEFINE_RES_IRQ(gic_spi(13)), /* IRQ5 */ - DEFINE_RES_IRQ(gic_spi(14)), /* IRQ6 */ - DEFINE_RES_IRQ(gic_spi(15)), /* IRQ7 */ - DEFINE_RES_IRQ(gic_spi(16)), /* IRQ8 */ - DEFINE_RES_IRQ(gic_spi(17)), /* IRQ9 */ -}; - -#define r8a7791_register_irqc(idx) \ - platform_device_register_resndata(NULL, "renesas_irqc", \ - idx, irqc##idx##_resources, \ - ARRAY_SIZE(irqc##idx##_resources), \ - &irqc##idx##_data, \ - sizeof(struct renesas_irqc_config)) - -static const struct resource thermal_resources[] __initconst = { - DEFINE_RES_MEM(0xe61f0000, 0x14), - DEFINE_RES_MEM(0xe61f0100, 0x38), - DEFINE_RES_IRQ(gic_spi(69)), -}; - -#define r8a7791_register_thermal() \ - platform_device_register_simple("rcar_thermal", -1, \ - thermal_resources, \ - ARRAY_SIZE(thermal_resources)) - -void __init r8a7791_add_standard_devices(void) -{ - r8a7791_register_scif(0); - r8a7791_register_scif(1); - r8a7791_register_scif(2); - r8a7791_register_scif(3); - r8a7791_register_scif(4); - r8a7791_register_scif(5); - r8a7791_register_scif(6); - r8a7791_register_scif(7); - r8a7791_register_scif(8); - r8a7791_register_scif(9); - r8a7791_register_scif(10); - r8a7791_register_scif(11); - r8a7791_register_scif(12); - r8a7791_register_scif(13); - r8a7791_register_scif(14); - r8a7791_register_cmt(0); - r8a7791_register_irqc(0); - r8a7791_register_thermal(); -} - -#ifdef CONFIG_USE_OF static const char *r8a7791_boards_compat_dt[] __initdata = { "renesas,r8a7791", NULL, @@ -218,4 +36,3 @@ DT_MACHINE_START(R8A7791_DT, "Generic R8A7791 (Flattened Device Tree)") .reserve = rcar_gen2_reserve, .dt_compat = r8a7791_boards_compat_dt, MACHINE_END -#endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index 42d5b4308923..3dd6edd9bd1d 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Renesas Solutions Corp. * Copyright (C) 2013 Magnus Damm + * Copyright (C) 2014 Ulrich Hecht * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/clk/shmobile.h> @@ -24,6 +21,7 @@ #include <linux/dma-contiguous.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/of.h> #include <linux/of_fdt.h> #include <asm/mach/arch.h> #include "common.h" @@ -54,37 +52,61 @@ void __init rcar_gen2_timer_init(void) { #if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK) u32 mode = rcar_gen2_read_mode_pins(); + bool is_e2 = (bool)of_find_compatible_node(NULL, NULL, + "renesas,r8a7794"); #endif #ifdef CONFIG_ARM_ARCH_TIMER void __iomem *base; int extal_mhz = 0; u32 freq; - /* At Linux boot time the r8a7790 arch timer comes up - * with the counter disabled. Moreover, it may also report - * a potentially incorrect fixed 13 MHz frequency. To be - * correct these registers need to be updated to use the - * frequency EXTAL / 2 which can be determined by the MD pins. - */ - - switch (mode & (MD(14) | MD(13))) { - case 0: - extal_mhz = 15; - break; - case MD(13): - extal_mhz = 20; - break; - case MD(14): - extal_mhz = 26; - break; - case MD(13) | MD(14): - extal_mhz = 30; - break; + if (is_e2) { + freq = 260000000 / 8; /* ZS / 8 */ + /* CNTVOFF has to be initialized either from non-secure + * Hypervisor mode or secure Monitor mode with SCR.NS==1. + * If TrustZone is enabled then it should be handled by the + * secure code. + */ + asm volatile( + " cps 0x16\n" + " mrc p15, 0, r1, c1, c1, 0\n" + " orr r0, r1, #1\n" + " mcr p15, 0, r0, c1, c1, 0\n" + " isb\n" + " mov r0, #0\n" + " mcrr p15, 4, r0, r0, c14\n" + " isb\n" + " mcr p15, 0, r1, c1, c1, 0\n" + " isb\n" + " cps 0x13\n" + : : : "r0", "r1"); + } else { + /* At Linux boot time the r8a7790 arch timer comes up + * with the counter disabled. Moreover, it may also report + * a potentially incorrect fixed 13 MHz frequency. To be + * correct these registers need to be updated to use the + * frequency EXTAL / 2 which can be determined by the MD pins. + */ + + switch (mode & (MD(14) | MD(13))) { + case 0: + extal_mhz = 15; + break; + case MD(13): + extal_mhz = 20; + break; + case MD(14): + extal_mhz = 26; + break; + case MD(13) | MD(14): + extal_mhz = 30; + break; + } + + /* The arch timer frequency equals EXTAL / 2 */ + freq = extal_mhz * (1000000 / 2); } - /* The arch timer frequency equals EXTAL / 2 */ - freq = extal_mhz * (1000000 / 2); - /* Remap "armgcnt address map" space */ base = ioremap(0xe6080000, PAGE_SIZE); diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index d646c8d12423..458a2cfad417 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> @@ -47,7 +43,7 @@ #include "sh7372.h" static struct map_desc sh7372_io_desc[] __initdata = { - /* create a 1:1 entity map for 0xe6xxxxxx + /* create a 1:1 identity mapping for 0xe6xxxxxx * used by CPGA, INTC and PFC. */ { @@ -60,6 +56,7 @@ static struct map_desc sh7372_io_desc[] __initdata = { void __init sh7372_map_io(void) { + debug_ll_io_init(); iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc)); } @@ -1012,6 +1009,7 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)") .init_irq = sh7372_init_irq, .handle_irq = shmobile_handle_irq_intc, .init_machine = sh7372_add_standard_devices_dt, + .init_late = shmobile_init_late, .dt_compat = sh7372_boards_compat_dt, MACHINE_END diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index b7bd8e509668..93ebe3430bfe 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> @@ -26,6 +22,7 @@ #include <linux/of_platform.h> #include <linux/delay.h> #include <linux/input.h> +#include <linux/i2c/i2c-sh_mobile.h> #include <linux/io.h> #include <linux/serial_sci.h> #include <linux/sh_dma.h> @@ -45,7 +42,7 @@ #include "sh73a0.h" static struct map_desc sh73a0_io_desc[] __initdata = { - /* create a 1:1 entity map for 0xe6xxxxxx + /* create a 1:1 identity mapping for 0xe6xxxxxx * used by CPGA, INTC and PFC. */ { @@ -58,6 +55,7 @@ static struct map_desc sh73a0_io_desc[] __initdata = { void __init sh73a0_map_io(void) { + debug_ll_io_init(); iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc)); } @@ -192,11 +190,18 @@ static struct resource i2c4_resources[] = { }, }; +static struct i2c_sh_mobile_platform_data i2c_platform_data = { + .clks_per_count = 2, +}; + static struct platform_device i2c0_device = { .name = "i2c-sh_mobile", .id = 0, .resource = i2c0_resources, .num_resources = ARRAY_SIZE(i2c0_resources), + .dev = { + .platform_data = &i2c_platform_data, + }, }; static struct platform_device i2c1_device = { @@ -204,6 +209,9 @@ static struct platform_device i2c1_device = { .id = 1, .resource = i2c1_resources, .num_resources = ARRAY_SIZE(i2c1_resources), + .dev = { + .platform_data = &i2c_platform_data, + }, }; static struct platform_device i2c2_device = { @@ -211,6 +219,9 @@ static struct platform_device i2c2_device = { .id = 2, .resource = i2c2_resources, .num_resources = ARRAY_SIZE(i2c2_resources), + .dev = { + .platform_data = &i2c_platform_data, + }, }; static struct platform_device i2c3_device = { @@ -218,6 +229,9 @@ static struct platform_device i2c3_device = { .id = 3, .resource = i2c3_resources, .num_resources = ARRAY_SIZE(i2c3_resources), + .dev = { + .platform_data = &i2c_platform_data, + }, }; static struct platform_device i2c4_device = { @@ -225,6 +239,9 @@ static struct platform_device i2c4_device = { .id = 4, .resource = i2c4_resources, .num_resources = ARRAY_SIZE(i2c4_resources), + .dev = { + .platform_data = &i2c_platform_data, + }, }; static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = { @@ -740,17 +757,12 @@ void __init sh73a0_add_standard_devices(void) ARRAY_SIZE(sh73a0_late_devices)); } -void __init sh73a0_init_delay(void) -{ - shmobile_init_delay(); -} - /* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */ void __init __weak sh73a0_register_twd(void) { } void __init sh73a0_earlytimer_init(void) { - sh73a0_init_delay(); + shmobile_init_delay(); sh73a0_clock_init(); shmobile_earlytimer_init(); sh73a0_register_twd(); @@ -775,6 +787,13 @@ void __init sh73a0_add_standard_devices_dt(void) of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } +#define RESCNT2 IOMEM(0xe6188020) +static void sh73a0_restart(enum reboot_mode mode, const char *cmd) +{ + /* Do soft power on reset */ + writel((1 << 31), RESCNT2); +} + static const char *sh73a0_boards_compat_dt[] __initdata = { "renesas,sh73a0", NULL, @@ -783,9 +802,10 @@ static const char *sh73a0_boards_compat_dt[] __initdata = { DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)") .smp = smp_ops(sh73a0_smp_ops), .map_io = sh73a0_map_io, - .init_early = sh73a0_init_delay, + .init_early = shmobile_init_delay, .init_machine = sh73a0_add_standard_devices_dt, .init_late = shmobile_init_late, + .restart = sh73a0_restart, .dt_compat = sh73a0_boards_compat_dt, MACHINE_END #endif /* CONFIG_USE_OF */ diff --git a/arch/arm/mach-shmobile/sh73a0.h b/arch/arm/mach-shmobile/sh73a0.h index 359b582dc270..f037c64b14fc 100644 --- a/arch/arm/mach-shmobile/sh73a0.h +++ b/arch/arm/mach-shmobile/sh73a0.h @@ -71,7 +71,6 @@ enum { #define SH73A0_PINT0_IRQ(irq) ((irq) + 700) #define SH73A0_PINT1_IRQ(irq) ((irq) + 732) -extern void sh73a0_init_delay(void); extern void sh73a0_init_irq(void); extern void sh73a0_init_irq_dt(void); extern void sh73a0_map_io(void); diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S index 9782862899e8..146b8de16432 100644 --- a/arch/arm/mach-shmobile/sleep-sh7372.S +++ b/arch/arm/mach-shmobile/sleep-sh7372.S @@ -22,11 +22,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA */ #include <linux/linkage.h> diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c index 6ff1df1df9a7..baff3b5efed8 100644 --- a/arch/arm/mach-shmobile/smp-emev2.c +++ b/arch/arm/mach-shmobile/smp-emev2.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index 3100e355c3fd..3f761f839043 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/smp-r8a7790.c b/arch/arm/mach-shmobile/smp-r8a7790.c index 2311694636e1..9c3da1345b8b 100644 --- a/arch/arm/mach-shmobile/smp-r8a7790.c +++ b/arch/arm/mach-shmobile/smp-r8a7790.c @@ -21,6 +21,7 @@ #include <asm/smp_plat.h> #include "common.h" +#include "platsmp-apmu.h" #include "pm-rcar.h" #include "r8a7790.h" @@ -34,10 +35,23 @@ static struct rcar_sysc_ch r8a7790_ca7_scu = { .isr_bit = 21, /* CA7-SCU */ }; +static struct rcar_apmu_config r8a7790_apmu_config[] = { + { + .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), + .cpus = { 0, 1, 2, 3 }, + }, + { + .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), + .cpus = { 0x100, 0x0101, 0x102, 0x103 }, + } +}; + static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus) { /* let APMU code install data related to shmobile_boot_vector */ - shmobile_smp_apmu_prepare_cpus(max_cpus); + shmobile_smp_apmu_prepare_cpus(max_cpus, + r8a7790_apmu_config, + ARRAY_SIZE(r8a7790_apmu_config)); /* turn on power to SCU */ r8a7790_pm_init(); diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c index f743386166fb..7e49e0a52e32 100644 --- a/arch/arm/mach-shmobile/smp-r8a7791.c +++ b/arch/arm/mach-shmobile/smp-r8a7791.c @@ -21,13 +21,23 @@ #include <asm/smp_plat.h> #include "common.h" +#include "platsmp-apmu.h" #include "r8a7791.h" #include "rcar-gen2.h" +static struct rcar_apmu_config r8a7791_apmu_config[] = { + { + .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), + .cpus = { 0, 1 }, + } +}; + static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus) { /* let APMU code install data related to shmobile_boot_vector */ - shmobile_smp_apmu_prepare_cpus(max_cpus); + shmobile_smp_apmu_prepare_cpus(max_cpus, + r8a7791_apmu_config, + ARRAY_SIZE(r8a7791_apmu_config)); r8a7791_pm_init(); } diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 22d8f87b23e9..c16dbfe9836c 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <linux/kernel.h> #include <linux/init.h> diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 87c6be1e79bd..f1d027aa7a81 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -12,11 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/platform_device.h> #include <linux/clocksource.h> @@ -45,6 +40,7 @@ void __init shmobile_init_delay(void) struct device_node *np, *cpus; bool is_a7_a8_a9 = false; bool is_a15 = false; + bool has_arch_timer = false; u32 max_freq = 0; cpus = of_find_node_by_path("/cpus"); @@ -57,12 +53,16 @@ void __init shmobile_init_delay(void) if (!of_property_read_u32(np, "clock-frequency", &freq)) max_freq = max(max_freq, freq); - if (of_device_is_compatible(np, "arm,cortex-a7") || - of_device_is_compatible(np, "arm,cortex-a8") || - of_device_is_compatible(np, "arm,cortex-a9")) + if (of_device_is_compatible(np, "arm,cortex-a8") || + of_device_is_compatible(np, "arm,cortex-a9")) { is_a7_a8_a9 = true; - else if (of_device_is_compatible(np, "arm,cortex-a15")) + } else if (of_device_is_compatible(np, "arm,cortex-a7")) { + is_a7_a8_a9 = true; + has_arch_timer = true; + } else if (of_device_is_compatible(np, "arm,cortex-a15")) { is_a15 = true; + has_arch_timer = true; + } } of_node_put(cpus); @@ -70,10 +70,12 @@ void __init shmobile_init_delay(void) if (!max_freq) return; - if (is_a7_a8_a9) - shmobile_setup_delay_hz(max_freq, 1, 3); - else if (is_a15 && !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) - shmobile_setup_delay_hz(max_freq, 2, 4); + if (!has_arch_timer || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) { + if (is_a7_a8_a9) + shmobile_setup_delay_hz(max_freq, 1, 3); + else if (is_a15) + shmobile_setup_delay_hz(max_freq, 2, 4); + } } static void __init shmobile_late_time_init(void) diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h index 60c443dadb58..483cb467bf65 100644 --- a/arch/arm/mach-socfpga/core.h +++ b/arch/arm/mach-socfpga/core.h @@ -21,6 +21,7 @@ #define __MACH_CORE_H #define SOCFPGA_RSTMGR_CTRL 0x04 +#define SOCFPGA_RSTMGR_MODMPURST 0x10 #define SOCFPGA_RSTMGR_MODPERRST 0x14 #define SOCFPGA_RSTMGR_BRGMODRST 0x1c @@ -28,6 +29,8 @@ #define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */ #define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */ +#define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */ + extern void socfpga_secondary_startup(void); extern void __iomem *socfpga_scu_base_addr; diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c index 16ca97b039f9..c64d89b7c0ca 100644 --- a/arch/arm/mach-socfpga/platsmp.c +++ b/arch/arm/mach-socfpga/platsmp.c @@ -34,17 +34,21 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle) int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; if (socfpga_cpu1start_addr) { + /* This will put CPU #1 into reset. */ + writel(RSTMGR_MPUMODRST_CPU1, + rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST); + memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); - __raw_writel(virt_to_phys(socfpga_secondary_startup), - (sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff))); + writel(virt_to_phys(socfpga_secondary_startup), + sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff)); flush_cache_all(); smp_wmb(); outer_clean_range(0, trampoline_size); - /* This will release CPU #1 out of reset.*/ - __raw_writel(0, rst_manager_base_addr + 0x10); + /* This will release CPU #1 out of reset. */ + writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST); } return 0; @@ -86,10 +90,9 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus) */ static void socfpga_cpu_die(unsigned int cpu) { - cpu_do_idle(); - - /* We should have never returned from idle */ - panic("cpu %d unexpectedly exit from shutdown\n", cpu); + /* Do WFI. If we wake up early, go back into WFI */ + while (1) + cpu_do_idle(); } struct smp_operations socfpga_smp_ops __initdata = { diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index 1aaa1e15ef70..a77604fbaf25 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -42,4 +42,11 @@ config MACH_SUN8I select MFD_SUN6I_PRCM select RESET_CONTROLLER +config MACH_SUN9I + bool "Allwinner (sun9i) SoCs support" + default ARCH_SUNXI + select ARCH_HAS_RESET_CONTROLLER + select ARM_GIC + select RESET_CONTROLLER + endif diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c index c53077bb8c3f..e44d028555a4 100644 --- a/arch/arm/mach-sunxi/platsmp.c +++ b/arch/arm/mach-sunxi/platsmp.c @@ -116,7 +116,7 @@ static int sun6i_smp_boot_secondary(unsigned int cpu, return 0; } -struct smp_operations sun6i_smp_ops __initdata = { +static struct smp_operations sun6i_smp_ops __initdata = { .smp_prepare_cpus = sun6i_smp_prepare_cpus, .smp_boot_secondary = sun6i_smp_boot_secondary, }; diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c index d7598aeed803..1f986758784a 100644 --- a/arch/arm/mach-sunxi/sunxi.c +++ b/arch/arm/mach-sunxi/sunxi.c @@ -63,3 +63,12 @@ static const char * const sun8i_board_dt_compat[] = { DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family") .dt_compat = sun8i_board_dt_compat, MACHINE_END + +static const char * const sun9i_board_dt_compat[] = { + "allwinner,sun9i-a80", + NULL, +}; + +DT_MACHINE_START(SUN9I_DT, "Allwinner sun9i Family") + .dt_compat = sun9i_board_dt_compat, +MACHINE_END diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3ebdce3e71f..425b6c8f0cb0 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, call_firmware_op(prepare_idle); /* Do suspend by ourselves if the firmware does not implement it */ - if (call_firmware_op(do_idle) == -ENOSYS) + if (call_firmware_op(do_idle, 0) == -ENOSYS) cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index da7be13aecce..ab95f5391a2b 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -99,42 +99,42 @@ static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) static void tegra_mask(struct irq_data *d) { - if (d->irq < FIRST_LEGACY_IRQ) + if (d->hwirq < FIRST_LEGACY_IRQ) return; - tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR); + tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_CLR); } static void tegra_unmask(struct irq_data *d) { - if (d->irq < FIRST_LEGACY_IRQ) + if (d->hwirq < FIRST_LEGACY_IRQ) return; - tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET); + tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_SET); } static void tegra_ack(struct irq_data *d) { - if (d->irq < FIRST_LEGACY_IRQ) + if (d->hwirq < FIRST_LEGACY_IRQ) return; - tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); + tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR); } static void tegra_eoi(struct irq_data *d) { - if (d->irq < FIRST_LEGACY_IRQ) + if (d->hwirq < FIRST_LEGACY_IRQ) return; - tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); + tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR); } static int tegra_retrigger(struct irq_data *d) { - if (d->irq < FIRST_LEGACY_IRQ) + if (d->hwirq < FIRST_LEGACY_IRQ) return 0; - tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET); + tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_SET); return 1; } @@ -142,7 +142,7 @@ static int tegra_retrigger(struct irq_data *d) #ifdef CONFIG_PM_SLEEP static int tegra_set_wake(struct irq_data *d, unsigned int enable) { - u32 irq = d->irq; + u32 irq = d->hwirq; u32 index, mask; if (irq < FIRST_LEGACY_IRQ || diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index 7b2baab0f0bd..71be4af5e975 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -51,6 +51,7 @@ ENTRY(tegra_resume) THUMB( it ne ) bne cpu_resume @ no + tegra_get_soc_id TEGRA_APB_MISC_BASE, r6 /* Are we on Tegra20? */ cmp r6, #TEGRA20 beq 1f @ Yes diff --git a/arch/arm/mach-u300/dummyspichip.c b/arch/arm/mach-u300/dummyspichip.c index ec0283cf9a32..131996805690 100644 --- a/arch/arm/mach-u300/dummyspichip.c +++ b/arch/arm/mach-u300/dummyspichip.c @@ -80,8 +80,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode\n"); status = spi_w8r8(spi, 0xAA); if (status < 0) - pr_warning("Siple test 1: FAILURE: spi_write_then_read " - "failed with status %d\n", status); + pr_warn("Simple test 1: FAILURE: spi_write_then_read failed with status %d\n", + status); else pr_info("Simple test 1: SUCCESS!\n"); @@ -89,8 +89,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode (full FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 2: FAILURE: spi_write_then_read() " - "failed with status %d\n", status); + pr_warn("Simple test 2: FAILURE: spi_write_then_read() failed with status %d\n", + status); else pr_info("Simple test 2: SUCCESS!\n"); @@ -98,8 +98,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 8bit mode (see if we overflow FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 3: FAILURE: failed with status %d " - "(probably FIFO overrun)\n", status); + pr_warn("Simple test 3: FAILURE: failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 3: SUCCESS!\n"); @@ -107,14 +107,14 @@ static ssize_t dummy_looptest(struct device *dev, "bytes garbage with spi_read() in 8bit mode\n"); status = spi_write(spi, &txbuf[0], 8); if (status < 0) - pr_warning("Simple test 4 step 1: FAILURE: spi_write() " - "failed with status %d\n", status); + pr_warn("Simple test 4 step 1: FAILURE: spi_write() failed with status %d\n", + status); else pr_info("Simple test 4 step 1: SUCCESS!\n"); status = spi_read(spi, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 4 step 2: FAILURE: spi_read() " - "failed with status %d\n", status); + pr_warn("Simple test 4 step 2: FAILURE: spi_read() failed with status %d\n", + status); else pr_info("Simple test 4 step 2: SUCCESS!\n"); @@ -122,16 +122,14 @@ static ssize_t dummy_looptest(struct device *dev, "14 bytes garbage with spi_read() in 8bit mode\n"); status = spi_write(spi, &txbuf[0], 14); if (status < 0) - pr_warning("Simple test 5 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 5 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 5 step 1: SUCCESS!\n"); status = spi_read(spi, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 5 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 5 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 5: SUCCESS!\n"); @@ -140,16 +138,14 @@ static ssize_t dummy_looptest(struct device *dev, DMA_TEST_SIZE, DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 6 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 6 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 6 step 1: SUCCESS!\n"); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 6 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 6 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 6: SUCCESS!\n"); @@ -169,18 +165,17 @@ static ssize_t dummy_looptest(struct device *dev, pr_info("Simple test 7: SUCCESS! (expected failure with " "status EIO)\n"); else if (status < 0) - pr_warning("Siple test 7: FAILURE: spi_write_then_read " - "failed with status %d\n", status); + pr_warn("Simple test 7: FAILURE: spi_write_then_read failed with status %d\n", + status); else - pr_warning("Siple test 7: FAILURE: spi_write_then_read " - "succeeded but it was expected to fail!\n"); + pr_warn("Simple test 7: FAILURE: spi_write_then_read succeeded but it was expected to fail!\n"); pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage " "in 16bit mode (full FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8); if (status < 0) - pr_warning("Simple test 8: FAILURE: spi_write_then_read() " - "failed with status %d\n", status); + pr_warn("Simple test 8: FAILURE: spi_write_then_read() failed with status %d\n", + status); else pr_info("Simple test 8: SUCCESS!\n"); @@ -188,8 +183,8 @@ static ssize_t dummy_looptest(struct device *dev, "in 16bit mode (see if we overflow FIFO)\n"); status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14); if (status < 0) - pr_warning("Simple test 9: FAILURE: failed with status %d " - "(probably FIFO overrun)\n", status); + pr_warn("Simple test 9: FAILURE: failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 9: SUCCESS!\n"); @@ -198,17 +193,15 @@ static ssize_t dummy_looptest(struct device *dev, DMA_TEST_SIZE, DMA_TEST_SIZE); status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 10 step 1: FAILURE: spi_write() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 10 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 10 step 1: SUCCESS!\n"); status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE); if (status < 0) - pr_warning("Simple test 10 step 2: FAILURE: spi_read() " - "failed with status %d (probably FIFO overrun)\n", - status); + pr_warn("Simple test 10 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n", + status); else pr_info("Simple test 10: SUCCESS!\n"); diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 699e8601dbf0..c9ac19b24e5a 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -32,6 +32,7 @@ config UX500_SOC_DB8500 select PINCTRL_AB8540 select REGULATOR select REGULATOR_DB8500_PRCMU + select PM_GENERIC_DOMAINS if PM config MACH_MOP500 bool "U8500 Development platform, MOP500 versions" diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index 9741de956b3e..4418a5078833 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \ board-mop500-audio.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o CFLAGS_hotplug.o += -march=armv7-a diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c index b80a9a2e356e..2cb587b50905 100644 --- a/arch/arm/mach-ux500/pm.c +++ b/arch/arm/mach-ux500/pm.c @@ -17,6 +17,7 @@ #include <linux/platform_data/arm-ux500-pm.h> #include "db8500-regs.h" +#include "pm_domains.h" /* ARM WFI Standby signal register */ #define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130) @@ -191,4 +192,7 @@ void __init ux500_pm_init(u32 phy_base, u32 size) /* Set up ux500 suspend callbacks. */ suspend_set_ops(UX500_SUSPEND_OPS); + + /* Initialize ux500 power domains */ + ux500_pm_domains_init(); } diff --git a/arch/arm/mach-ux500/pm_domains.c b/arch/arm/mach-ux500/pm_domains.c new file mode 100644 index 000000000000..0d4b5b46f15b --- /dev/null +++ b/arch/arm/mach-ux500/pm_domains.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * License terms: GNU General Public License (GPL) version 2 + * + * Implements PM domains using the generic PM domain for ux500. + */ +#include <linux/printk.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/pm_domain.h> + +#include <dt-bindings/arm/ux500_pm_domains.h> +#include "pm_domains.h" + +static int pd_power_off(struct generic_pm_domain *domain) +{ + /* + * Handle the gating of the PM domain regulator here. + * + * Drivers/subsystems handling devices in the PM domain needs to perform + * register context save/restore from their respective runtime PM + * callbacks, to be able to enable PM domain gating/ungating. + */ + return 0; +} + +static int pd_power_on(struct generic_pm_domain *domain) +{ + /* + * Handle the ungating of the PM domain regulator here. + * + * Drivers/subsystems handling devices in the PM domain needs to perform + * register context save/restore from their respective runtime PM + * callbacks, to be able to enable PM domain gating/ungating. + */ + return 0; +} + +static struct generic_pm_domain ux500_pm_domain_vape = { + .name = "VAPE", + .power_off = pd_power_off, + .power_on = pd_power_on, +}; + +static struct generic_pm_domain *ux500_pm_domains[NR_DOMAINS] = { + [DOMAIN_VAPE] = &ux500_pm_domain_vape, +}; + +static struct of_device_id ux500_pm_domain_matches[] = { + { .compatible = "stericsson,ux500-pm-domains", }, + { }, +}; + +int __init ux500_pm_domains_init(void) +{ + struct device_node *np; + struct genpd_onecell_data *genpd_data; + int i; + + np = of_find_matching_node(NULL, ux500_pm_domain_matches); + if (!np) + return -ENODEV; + + genpd_data = kzalloc(sizeof(*genpd_data), GFP_KERNEL); + if (!genpd_data) + return -ENOMEM; + + genpd_data->domains = ux500_pm_domains; + genpd_data->num_domains = ARRAY_SIZE(ux500_pm_domains); + + for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i) + pm_genpd_init(ux500_pm_domains[i], NULL, false); + + of_genpd_add_provider_onecell(np, genpd_data); + return 0; +} diff --git a/arch/arm/mach-ux500/pm_domains.h b/arch/arm/mach-ux500/pm_domains.h new file mode 100644 index 000000000000..263d3ba97177 --- /dev/null +++ b/arch/arm/mach-ux500/pm_domains.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2014 Linaro Ltd. + * + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * License terms: GNU General Public License (GPL) version 2 + */ + +#ifndef __MACH_UX500_PM_DOMAINS_H +#define __MACH_UX500_PM_DOMAINS_H + +#ifdef CONFIG_PM_GENERIC_DOMAINS +extern int __init ux500_pm_domains_init(void); +#else +static inline int ux500_pm_domains_init(void) { return 0; } +#endif + +#endif diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index b2cfba16c4e8..d6b16d9a7838 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -16,6 +16,7 @@ menuconfig ARCH_VEXPRESS select POWER_RESET select POWER_RESET_VEXPRESS select POWER_SUPPLY + select REGULATOR if MMC_ARMMMCI select REGULATOR_FIXED_VOLTAGE if REGULATOR select VEXPRESS_CONFIG select VEXPRESS_SYSCFG @@ -49,9 +50,6 @@ config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA build a working kernel, you must also enable relevant core tile support or Flattened Device Tree based support options. -config ARCH_VEXPRESS_CA9X4 - bool "Versatile Express Cortex-A9x4 tile" - config ARCH_VEXPRESS_DCSCB bool "Dual Cluster System Control Block (DCSCB) support" depends on MCPM diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index fc649bc09d0c..f5c1006dd6a1 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile @@ -1,11 +1,10 @@ # # Makefile for the linux kernel. # -ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ +ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := \ -I$(srctree)/arch/arm/plat-versatile/include obj-y := v2m.o -obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o CFLAGS_dcscb.o += -march=armv7-a CFLAGS_REMOVE_dcscb.o = -pg diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h index 152fad91b3ae..2a11d3ac8c68 100644 --- a/arch/arm/mach-vexpress/core.h +++ b/arch/arm/mach-vexpress/core.h @@ -1,12 +1,5 @@ -/* 2MB large area for motherboard's peripherals static mapping */ -#define V2M_PERIPH 0xf8000000 - -/* Tile's peripherals static mappings should start here */ -#define V2T_PERIPH 0xf8200000 - bool vexpress_smp_init_ops(void); -extern struct smp_operations vexpress_smp_ops; extern struct smp_operations vexpress_smp_dt_ops; extern void vexpress_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c deleted file mode 100644 index 27bea049380a..000000000000 --- a/arch/arm/mach-vexpress/ct-ca9x4.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Versatile Express Core Tile Cortex A9x4 Support - */ -#include <linux/init.h> -#include <linux/gfp.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> -#include <linux/amba/bus.h> -#include <linux/amba/clcd.h> -#include <linux/platform_data/video-clcd-versatile.h> -#include <linux/clkdev.h> -#include <linux/vexpress.h> -#include <linux/irqchip/arm-gic.h> - -#include <asm/hardware/arm_timer.h> -#include <asm/hardware/cache-l2x0.h> -#include <asm/smp_scu.h> -#include <asm/smp_twd.h> - -#include <mach/ct-ca9x4.h> - -#include <asm/hardware/timer-sp.h> - -#include <asm/mach/map.h> -#include <asm/mach/time.h> - -#include "core.h" - -#include <mach/motherboard.h> -#include <mach/irqs.h> - -static struct map_desc ct_ca9x4_io_desc[] __initdata = { - { - .virtual = V2T_PERIPH, - .pfn = __phys_to_pfn(CT_CA9X4_MPIC), - .length = SZ_8K, - .type = MT_DEVICE, - }, -}; - -static void __init ct_ca9x4_map_io(void) -{ - iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc)); -} - -static void __init ca9x4_l2_init(void) -{ -#ifdef CONFIG_CACHE_L2X0 - void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); - - if (l2x0_base) { - /* set RAM latencies to 1 cycle for this core tile. */ - writel(0, l2x0_base + L310_TAG_LATENCY_CTRL); - writel(0, l2x0_base + L310_DATA_LATENCY_CTRL); - - l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); - } else { - pr_err("L2C: unable to map L2 cache controller\n"); - } -#endif -} - -#ifdef CONFIG_HAVE_ARM_TWD -static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER); - -static void __init ca9x4_twd_init(void) -{ - int err = twd_local_timer_register(&twd_local_timer); - if (err) - pr_err("twd_local_timer_register failed %d\n", err); -} -#else -#define ca9x4_twd_init() do {} while(0) -#endif - -static void __init ct_ca9x4_init_irq(void) -{ - gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K), - ioremap(A9_MPCORE_GIC_CPU, SZ_256)); - ca9x4_twd_init(); - ca9x4_l2_init(); -} - -static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) -{ - unsigned long framesize = 1024 * 768 * 2; - - fb->panel = versatile_clcd_get_panel("XVGA"); - if (!fb->panel) - return -EINVAL; - - return versatile_clcd_setup_dma(fb, framesize); -} - -static struct clcd_board ct_ca9x4_clcd_data = { - .name = "CT-CA9X4", - .caps = CLCD_CAP_5551 | CLCD_CAP_565, - .check = clcdfb_check, - .decode = clcdfb_decode, - .setup = ct_ca9x4_clcd_setup, - .mmap = versatile_clcd_mmap_dma, - .remove = versatile_clcd_remove_dma, -}; - -static AMBA_AHB_DEVICE(clcd, "ct:clcd", 0, CT_CA9X4_CLCDC, IRQ_CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data); -static AMBA_APB_DEVICE(dmc, "ct:dmc", 0, CT_CA9X4_DMC, IRQ_CT_CA9X4_DMC, NULL); -static AMBA_APB_DEVICE(smc, "ct:smc", 0, CT_CA9X4_SMC, IRQ_CT_CA9X4_SMC, NULL); -static AMBA_APB_DEVICE(gpio, "ct:gpio", 0, CT_CA9X4_GPIO, IRQ_CT_CA9X4_GPIO, NULL); - -static struct amba_device *ct_ca9x4_amba_devs[] __initdata = { - &clcd_device, - &dmc_device, - &smc_device, - &gpio_device, -}; - -static struct resource pmu_resources[] = { - [0] = { - .start = IRQ_CT_CA9X4_PMU_CPU0, - .end = IRQ_CT_CA9X4_PMU_CPU0, - .flags = IORESOURCE_IRQ, - }, - [1] = { - .start = IRQ_CT_CA9X4_PMU_CPU1, - .end = IRQ_CT_CA9X4_PMU_CPU1, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = IRQ_CT_CA9X4_PMU_CPU2, - .end = IRQ_CT_CA9X4_PMU_CPU2, - .flags = IORESOURCE_IRQ, - }, - [3] = { - .start = IRQ_CT_CA9X4_PMU_CPU3, - .end = IRQ_CT_CA9X4_PMU_CPU3, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device pmu_device = { - .name = "arm-pmu", - .id = -1, - .num_resources = ARRAY_SIZE(pmu_resources), - .resource = pmu_resources, -}; - -static struct clk_lookup osc1_lookup = { - .dev_id = "ct:clcd", -}; - -static struct platform_device osc1_device = { - .name = "vexpress-osc", - .id = 1, - .num_resources = 1, - .resource = (struct resource []) { - VEXPRESS_RES_FUNC(0xf, 1), - }, - .dev.platform_data = &osc1_lookup, -}; - -static void __init ct_ca9x4_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) - amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); - - platform_device_register(&pmu_device); - vexpress_syscfg_device_register(&osc1_device); -} - -#ifdef CONFIG_SMP -static void *ct_ca9x4_scu_base __initdata; - -static void __init ct_ca9x4_init_cpu_map(void) -{ - int i, ncores; - - ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128); - if (WARN_ON(!ct_ca9x4_scu_base)) - return; - - ncores = scu_get_core_count(ct_ca9x4_scu_base); - - if (ncores > nr_cpu_ids) { - pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", - ncores, nr_cpu_ids); - ncores = nr_cpu_ids; - } - - for (i = 0; i < ncores; ++i) - set_cpu_possible(i, true); -} - -static void __init ct_ca9x4_smp_enable(unsigned int max_cpus) -{ - scu_enable(ct_ca9x4_scu_base); -} -#endif - -struct ct_desc ct_ca9x4_desc __initdata = { - .id = V2M_CT_ID_CA9, - .name = "CA9x4", - .map_io = ct_ca9x4_map_io, - .init_irq = ct_ca9x4_init_irq, - .init_tile = ct_ca9x4_init, -#ifdef CONFIG_SMP - .init_cpu_map = ct_ca9x4_init_cpu_map, - .smp_enable = ct_ca9x4_smp_enable, -#endif -}; diff --git a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h deleted file mode 100644 index 84acf8439d4b..000000000000 --- a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __MACH_CT_CA9X4_H -#define __MACH_CT_CA9X4_H - -/* - * Physical base addresses - */ -#define CT_CA9X4_CLCDC (0x10020000) -#define CT_CA9X4_AXIRAM (0x10060000) -#define CT_CA9X4_DMC (0x100e0000) -#define CT_CA9X4_SMC (0x100e1000) -#define CT_CA9X4_SCC (0x100e2000) -#define CT_CA9X4_SP804_TIMER (0x100e4000) -#define CT_CA9X4_SP805_WDT (0x100e5000) -#define CT_CA9X4_TZPC (0x100e6000) -#define CT_CA9X4_GPIO (0x100e8000) -#define CT_CA9X4_FASTAXI (0x100e9000) -#define CT_CA9X4_SLOWAXI (0x100ea000) -#define CT_CA9X4_TZASC (0x100ec000) -#define CT_CA9X4_CORESIGHT (0x10200000) -#define CT_CA9X4_MPIC (0x1e000000) -#define CT_CA9X4_SYSTIMER (0x1e004000) -#define CT_CA9X4_SYSWDT (0x1e007000) -#define CT_CA9X4_L2CC (0x1e00a000) - -#define A9_MPCORE_SCU (CT_CA9X4_MPIC + 0x0000) -#define A9_MPCORE_GIC_CPU (CT_CA9X4_MPIC + 0x0100) -#define A9_MPCORE_GIT (CT_CA9X4_MPIC + 0x0200) -#define A9_MPCORE_TWD (CT_CA9X4_MPIC + 0x0600) -#define A9_MPCORE_GIC_DIST (CT_CA9X4_MPIC + 0x1000) - -/* - * Interrupts. Those in {} are for AMBA devices - */ -#define IRQ_CT_CA9X4_CLCDC { 76 } -#define IRQ_CT_CA9X4_DMC { 0 } -#define IRQ_CT_CA9X4_SMC { 77, 78 } -#define IRQ_CT_CA9X4_TIMER0 80 -#define IRQ_CT_CA9X4_TIMER1 81 -#define IRQ_CT_CA9X4_GPIO { 82 } -#define IRQ_CT_CA9X4_PMU_CPU0 92 -#define IRQ_CT_CA9X4_PMU_CPU1 93 -#define IRQ_CT_CA9X4_PMU_CPU2 94 -#define IRQ_CT_CA9X4_PMU_CPU3 95 - -extern struct ct_desc ct_ca9x4_desc; - -#endif diff --git a/arch/arm/mach-vexpress/include/mach/hardware.h b/arch/arm/mach-vexpress/include/mach/hardware.h deleted file mode 100644 index 40a8c178f10d..000000000000 --- a/arch/arm/mach-vexpress/include/mach/hardware.h +++ /dev/null @@ -1 +0,0 @@ -/* empty */ diff --git a/arch/arm/mach-vexpress/include/mach/irqs.h b/arch/arm/mach-vexpress/include/mach/irqs.h deleted file mode 100644 index f8f7f782eb55..000000000000 --- a/arch/arm/mach-vexpress/include/mach/irqs.h +++ /dev/null @@ -1,6 +0,0 @@ -#define IRQ_LOCALTIMER 29 -#define IRQ_LOCALWDOG 30 - -#ifndef CONFIG_SPARSE_IRQ -#define NR_IRQS 256 -#endif diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h deleted file mode 100644 index 68abc8b72781..000000000000 --- a/arch/arm/mach-vexpress/include/mach/motherboard.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef __MACH_MOTHERBOARD_H -#define __MACH_MOTHERBOARD_H - -/* - * Physical addresses, offset from V2M_PA_CS0-3 - */ -#define V2M_NOR0 (V2M_PA_CS0) -#define V2M_NOR1 (V2M_PA_CS1) -#define V2M_SRAM (V2M_PA_CS2) -#define V2M_VIDEO_SRAM (V2M_PA_CS3 + 0x00000000) -#define V2M_LAN9118 (V2M_PA_CS3 + 0x02000000) -#define V2M_ISP1761 (V2M_PA_CS3 + 0x03000000) - -/* - * Physical addresses, offset from V2M_PA_CS7 - */ -#define V2M_SYSREGS (V2M_PA_CS7 + 0x00000000) -#define V2M_SYSCTL (V2M_PA_CS7 + 0x00001000) -#define V2M_SERIAL_BUS_PCI (V2M_PA_CS7 + 0x00002000) - -#define V2M_AACI (V2M_PA_CS7 + 0x00004000) -#define V2M_MMCI (V2M_PA_CS7 + 0x00005000) -#define V2M_KMI0 (V2M_PA_CS7 + 0x00006000) -#define V2M_KMI1 (V2M_PA_CS7 + 0x00007000) - -#define V2M_UART0 (V2M_PA_CS7 + 0x00009000) -#define V2M_UART1 (V2M_PA_CS7 + 0x0000a000) -#define V2M_UART2 (V2M_PA_CS7 + 0x0000b000) -#define V2M_UART3 (V2M_PA_CS7 + 0x0000c000) - -#define V2M_WDT (V2M_PA_CS7 + 0x0000f000) - -#define V2M_TIMER01 (V2M_PA_CS7 + 0x00011000) -#define V2M_TIMER23 (V2M_PA_CS7 + 0x00012000) - -#define V2M_SERIAL_BUS_DVI (V2M_PA_CS7 + 0x00016000) -#define V2M_RTC (V2M_PA_CS7 + 0x00017000) - -#define V2M_CF (V2M_PA_CS7 + 0x0001a000) -#define V2M_CLCD (V2M_PA_CS7 + 0x0001f000) - - -/* - * Interrupts. Those in {} are for AMBA devices - */ -#define IRQ_V2M_WDT { (32 + 0) } -#define IRQ_V2M_TIMER0 (32 + 2) -#define IRQ_V2M_TIMER1 (32 + 2) -#define IRQ_V2M_TIMER2 (32 + 3) -#define IRQ_V2M_TIMER3 (32 + 3) -#define IRQ_V2M_RTC { (32 + 4) } -#define IRQ_V2M_UART0 { (32 + 5) } -#define IRQ_V2M_UART1 { (32 + 6) } -#define IRQ_V2M_UART2 { (32 + 7) } -#define IRQ_V2M_UART3 { (32 + 8) } -#define IRQ_V2M_MMCI { (32 + 9), (32 + 10) } -#define IRQ_V2M_AACI { (32 + 11) } -#define IRQ_V2M_KMI0 { (32 + 12) } -#define IRQ_V2M_KMI1 { (32 + 13) } -#define IRQ_V2M_CLCD { (32 + 14) } -#define IRQ_V2M_LAN9118 (32 + 15) -#define IRQ_V2M_ISP1761 (32 + 16) -#define IRQ_V2M_PCIE (32 + 17) - - -/* - * Core tile IDs - */ -#define V2M_CT_ID_CA9 0x0c000191 -#define V2M_CT_ID_UNSUPPORTED 0xff000191 -#define V2M_CT_ID_MASK 0xff000fff - -struct ct_desc { - u32 id; - const char *name; - void (*map_io)(void); - void (*init_early)(void); - void (*init_irq)(void); - void (*init_tile)(void); -#ifdef CONFIG_SMP - void (*init_cpu_map)(void); - void (*smp_enable)(unsigned int); -#endif -}; - -extern struct ct_desc *ct_desc; - -#endif diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c index a1f3804fd5a5..83188cf1875d 100644 --- a/arch/arm/mach-vexpress/platsmp.c +++ b/arch/arm/mach-vexpress/platsmp.c @@ -19,48 +19,10 @@ #include <asm/smp_scu.h> #include <asm/mach/map.h> -#include <mach/motherboard.h> - #include <plat/platsmp.h> #include "core.h" -/* - * Initialise the CPU possible map early - this describes the CPUs - * which may be present or become present in the system. - */ -static void __init vexpress_smp_init_cpus(void) -{ - ct_desc->init_cpu_map(); -} - -static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus) -{ - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - ct_desc->smp_enable(max_cpus); - - /* - * Write the address of secondary startup into the - * system-wide flags register. The boot monitor waits - * until it receives a soft interrupt, and then the - * secondary CPU branches to this address. - */ - vexpress_flags_set(virt_to_phys(versatile_secondary_startup)); -} - -struct smp_operations __initdata vexpress_smp_ops = { - .smp_init_cpus = vexpress_smp_init_cpus, - .smp_prepare_cpus = vexpress_smp_prepare_cpus, - .smp_secondary_init = versatile_secondary_init, - .smp_boot_secondary = versatile_boot_secondary, -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = vexpress_cpu_die, -#endif -}; - bool __init vexpress_smp_init_ops(void) { #ifdef CONFIG_MCPM @@ -79,8 +41,6 @@ bool __init vexpress_smp_init_ops(void) return false; } -#if defined(CONFIG_OF) - static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = { { .compatible = "arm,cortex-a5-scu", }, { .compatible = "arm,cortex-a9-scu", }, @@ -112,5 +72,3 @@ struct smp_operations __initdata vexpress_smp_dt_ops = { .cpu_die = vexpress_cpu_die, #endif }; - -#endif diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 6ff681a24ba7..a0400f4cca89 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c @@ -1,380 +1,7 @@ -/* - * Versatile Express V2M Motherboard Support - */ -#include <linux/device.h> -#include <linux/amba/bus.h> -#include <linux/amba/mmci.h> -#include <linux/io.h> -#include <linux/smp.h> -#include <linux/init.h> -#include <linux/of_address.h> -#include <linux/of_fdt.h> -#include <linux/of_irq.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> -#include <linux/ata_platform.h> -#include <linux/smsc911x.h> -#include <linux/spinlock.h> -#include <linux/usb/isp1760.h> -#include <linux/mtd/physmap.h> -#include <linux/regulator/fixed.h> -#include <linux/regulator/machine.h> -#include <linux/vexpress.h> -#include <linux/clkdev.h> - -#include <asm/mach-types.h> -#include <asm/sizes.h> #include <asm/mach/arch.h> -#include <asm/mach/map.h> -#include <asm/mach/time.h> -#include <asm/hardware/arm_timer.h> -#include <asm/hardware/cache-l2x0.h> -#include <asm/hardware/timer-sp.h> - -#include <mach/ct-ca9x4.h> -#include <mach/motherboard.h> - -#include <plat/sched_clock.h> -#include <plat/platsmp.h> #include "core.h" -#define V2M_PA_CS0 0x40000000 -#define V2M_PA_CS1 0x44000000 -#define V2M_PA_CS2 0x48000000 -#define V2M_PA_CS3 0x4c000000 -#define V2M_PA_CS7 0x10000000 - -static struct map_desc v2m_io_desc[] __initdata = { - { - .virtual = V2M_PERIPH, - .pfn = __phys_to_pfn(V2M_PA_CS7), - .length = SZ_128K, - .type = MT_DEVICE, - }, -}; - -static void __init v2m_sp804_init(void __iomem *base, unsigned int irq) -{ - if (WARN_ON(!base || irq == NO_IRQ)) - return; - - sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1"); - sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0"); -} - - -static struct resource v2m_pcie_i2c_resource = { - .start = V2M_SERIAL_BUS_PCI, - .end = V2M_SERIAL_BUS_PCI + SZ_4K - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device v2m_pcie_i2c_device = { - .name = "versatile-i2c", - .id = 0, - .num_resources = 1, - .resource = &v2m_pcie_i2c_resource, -}; - -static struct resource v2m_ddc_i2c_resource = { - .start = V2M_SERIAL_BUS_DVI, - .end = V2M_SERIAL_BUS_DVI + SZ_4K - 1, - .flags = IORESOURCE_MEM, -}; - -static struct platform_device v2m_ddc_i2c_device = { - .name = "versatile-i2c", - .id = 1, - .num_resources = 1, - .resource = &v2m_ddc_i2c_resource, -}; - -static struct resource v2m_eth_resources[] = { - { - .start = V2M_LAN9118, - .end = V2M_LAN9118 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_V2M_LAN9118, - .end = IRQ_V2M_LAN9118, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct smsc911x_platform_config v2m_eth_config = { - .flags = SMSC911X_USE_32BIT, - .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, - .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, - .phy_interface = PHY_INTERFACE_MODE_MII, -}; - -static struct platform_device v2m_eth_device = { - .name = "smsc911x", - .id = -1, - .resource = v2m_eth_resources, - .num_resources = ARRAY_SIZE(v2m_eth_resources), - .dev.platform_data = &v2m_eth_config, -}; - -static struct regulator_consumer_supply v2m_eth_supplies[] = { - REGULATOR_SUPPLY("vddvario", "smsc911x"), - REGULATOR_SUPPLY("vdd33a", "smsc911x"), -}; - -static struct resource v2m_usb_resources[] = { - { - .start = V2M_ISP1761, - .end = V2M_ISP1761 + SZ_128K - 1, - .flags = IORESOURCE_MEM, - }, { - .start = IRQ_V2M_ISP1761, - .end = IRQ_V2M_ISP1761, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct isp1760_platform_data v2m_usb_config = { - .is_isp1761 = true, - .bus_width_16 = false, - .port1_otg = true, - .analog_oc = false, - .dack_polarity_high = false, - .dreq_polarity_high = false, -}; - -static struct platform_device v2m_usb_device = { - .name = "isp1760", - .id = -1, - .resource = v2m_usb_resources, - .num_resources = ARRAY_SIZE(v2m_usb_resources), - .dev.platform_data = &v2m_usb_config, -}; - -static struct physmap_flash_data v2m_flash_data = { - .width = 4, -}; - -static struct resource v2m_flash_resources[] = { - { - .start = V2M_NOR0, - .end = V2M_NOR0 + SZ_64M - 1, - .flags = IORESOURCE_MEM, - }, { - .start = V2M_NOR1, - .end = V2M_NOR1 + SZ_64M - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device v2m_flash_device = { - .name = "physmap-flash", - .id = -1, - .resource = v2m_flash_resources, - .num_resources = ARRAY_SIZE(v2m_flash_resources), - .dev.platform_data = &v2m_flash_data, -}; - -static struct pata_platform_info v2m_pata_data = { - .ioport_shift = 2, -}; - -static struct resource v2m_pata_resources[] = { - { - .start = V2M_CF, - .end = V2M_CF + 0xff, - .flags = IORESOURCE_MEM, - }, { - .start = V2M_CF + 0x100, - .end = V2M_CF + SZ_4K - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device v2m_cf_device = { - .name = "pata_platform", - .id = -1, - .resource = v2m_pata_resources, - .num_resources = ARRAY_SIZE(v2m_pata_resources), - .dev.platform_data = &v2m_pata_data, -}; - -static struct mmci_platform_data v2m_mmci_data = { - .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, - .status = vexpress_get_mci_cardin, - .gpio_cd = -1, - .gpio_wp = -1, -}; - -static struct resource v2m_sysreg_resources[] = { - { - .start = V2M_SYSREGS, - .end = V2M_SYSREGS + 0xfff, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device v2m_sysreg_device = { - .name = "vexpress-sysreg", - .id = -1, - .resource = v2m_sysreg_resources, - .num_resources = ARRAY_SIZE(v2m_sysreg_resources), -}; - -static struct platform_device v2m_muxfpga_device = { - .name = "vexpress-muxfpga", - .id = 0, - .num_resources = 1, - .resource = (struct resource []) { - VEXPRESS_RES_FUNC(0, 7), - } -}; - -static struct platform_device v2m_shutdown_device = { - .name = "vexpress-shutdown", - .id = 0, - .num_resources = 1, - .resource = (struct resource []) { - VEXPRESS_RES_FUNC(0, 8), - } -}; - -static struct platform_device v2m_reboot_device = { - .name = "vexpress-reboot", - .id = 0, - .num_resources = 1, - .resource = (struct resource []) { - VEXPRESS_RES_FUNC(0, 9), - } -}; - -static struct platform_device v2m_dvimode_device = { - .name = "vexpress-dvimode", - .id = 0, - .num_resources = 1, - .resource = (struct resource []) { - VEXPRESS_RES_FUNC(0, 11), - } -}; - -static AMBA_APB_DEVICE(aaci, "mb:aaci", 0, V2M_AACI, IRQ_V2M_AACI, NULL); -static AMBA_APB_DEVICE(mmci, "mb:mmci", 0, V2M_MMCI, IRQ_V2M_MMCI, &v2m_mmci_data); -static AMBA_APB_DEVICE(kmi0, "mb:kmi0", 0, V2M_KMI0, IRQ_V2M_KMI0, NULL); -static AMBA_APB_DEVICE(kmi1, "mb:kmi1", 0, V2M_KMI1, IRQ_V2M_KMI1, NULL); -static AMBA_APB_DEVICE(uart0, "mb:uart0", 0, V2M_UART0, IRQ_V2M_UART0, NULL); -static AMBA_APB_DEVICE(uart1, "mb:uart1", 0, V2M_UART1, IRQ_V2M_UART1, NULL); -static AMBA_APB_DEVICE(uart2, "mb:uart2", 0, V2M_UART2, IRQ_V2M_UART2, NULL); -static AMBA_APB_DEVICE(uart3, "mb:uart3", 0, V2M_UART3, IRQ_V2M_UART3, NULL); -static AMBA_APB_DEVICE(wdt, "mb:wdt", 0, V2M_WDT, IRQ_V2M_WDT, NULL); -static AMBA_APB_DEVICE(rtc, "mb:rtc", 0, V2M_RTC, IRQ_V2M_RTC, NULL); - -static struct amba_device *v2m_amba_devs[] __initdata = { - &aaci_device, - &mmci_device, - &kmi0_device, - &kmi1_device, - &uart0_device, - &uart1_device, - &uart2_device, - &uart3_device, - &wdt_device, - &rtc_device, -}; - -static void __init v2m_timer_init(void) -{ - vexpress_clk_init(ioremap(V2M_SYSCTL, SZ_4K)); - v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0); -} - -static void __init v2m_init_early(void) -{ - if (ct_desc->init_early) - ct_desc->init_early(); - versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000); -} - -struct ct_desc *ct_desc; - -static struct ct_desc *ct_descs[] __initdata = { -#ifdef CONFIG_ARCH_VEXPRESS_CA9X4 - &ct_ca9x4_desc, -#endif -}; - -static void __init v2m_populate_ct_desc(void) -{ - int i; - u32 current_tile_id; - - ct_desc = NULL; - current_tile_id = vexpress_get_procid(VEXPRESS_SITE_MASTER) - & V2M_CT_ID_MASK; - - for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i) - if (ct_descs[i]->id == current_tile_id) - ct_desc = ct_descs[i]; - - if (!ct_desc) - panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n" - "You may need a device tree blob or a different kernel to boot on this board.\n", - current_tile_id); -} - -static void __init v2m_map_io(void) -{ - iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc)); - vexpress_sysreg_early_init(ioremap(V2M_SYSREGS, SZ_4K)); - v2m_populate_ct_desc(); - ct_desc->map_io(); -} - -static void __init v2m_init_irq(void) -{ - ct_desc->init_irq(); -} - -static void __init v2m_init(void) -{ - int i; - - regulator_register_fixed(0, v2m_eth_supplies, - ARRAY_SIZE(v2m_eth_supplies)); - - platform_device_register(&v2m_sysreg_device); - platform_device_register(&v2m_pcie_i2c_device); - platform_device_register(&v2m_ddc_i2c_device); - platform_device_register(&v2m_flash_device); - platform_device_register(&v2m_cf_device); - platform_device_register(&v2m_eth_device); - platform_device_register(&v2m_usb_device); - - for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++) - amba_device_register(v2m_amba_devs[i], &iomem_resource); - - vexpress_syscfg_device_register(&v2m_muxfpga_device); - vexpress_syscfg_device_register(&v2m_shutdown_device); - vexpress_syscfg_device_register(&v2m_reboot_device); - vexpress_syscfg_device_register(&v2m_dvimode_device); - - ct_desc->init_tile(); -} - -MACHINE_START(VEXPRESS, "ARM-Versatile Express") - .atag_offset = 0x100, - .smp = smp_ops(vexpress_smp_ops), - .map_io = v2m_map_io, - .init_early = v2m_init_early, - .init_irq = v2m_init_irq, - .init_time = v2m_timer_init, - .init_machine = v2m_init, -MACHINE_END - -static void __init v2m_dt_init(void) -{ - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} - static const char * const v2m_dt_match[] __initconst = { "arm,vexpress", NULL, @@ -386,5 +13,4 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") .l2c_aux_mask = 0xfe0fffff, .smp = smp_ops(vexpress_smp_dt_ops), .smp_init = smp_init_ops(vexpress_smp_init_ops), - .init_machine = v2m_dt_init, MACHINE_END diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile index c85fb3f7d5cd..b03a97eb7501 100644 --- a/arch/arm/mach-zynq/Makefile +++ b/arch/arm/mach-zynq/Makefile @@ -4,6 +4,4 @@ # Common support obj-y := common.o slcr.o pm.o -CFLAGS_REMOVE_hotplug.o =-march=armv6k -CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9 obj-$(CONFIG_SMP) += headsmp.o platsmp.o diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 2bc71273c73c..382c60e9aa16 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -29,7 +29,6 @@ extern void zynq_slcr_cpu_state_write(int cpu, bool die); extern u32 zynq_slcr_get_device_id(void); #ifdef CONFIG_SMP -extern void secondary_startup(void); extern char zynq_secondary_trampoline; extern char zynq_secondary_trampoline_jump; extern char zynq_secondary_trampoline_end; diff --git a/arch/arm/mach-zynq/hotplug.c b/arch/arm/mach-zynq/hotplug.c deleted file mode 100644 index b685c89f11e4..000000000000 --- a/arch/arm/mach-zynq/hotplug.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) 2012-2013 Xilinx - * - * based on linux/arch/arm/mach-realview/hotplug.c - * - * Copyright (C) 2002 ARM Ltd. - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <asm/proc-fns.h> - diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index ae69809a9e47..ab906b801047 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -21,7 +21,7 @@ config CPU_ARM7TDMI # ARM720T config CPU_ARM720T - bool "Support ARM720T processor" if ARCH_INTEGRATOR + bool "Support ARM720T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_LV4T select CPU_CACHE_V4 @@ -39,7 +39,7 @@ config CPU_ARM720T # ARM740T config CPU_ARM740T - bool "Support ARM740T processor" if ARCH_INTEGRATOR + bool "Support ARM740T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) depends on !MMU select CPU_32v4T select CPU_ABRT_LV4T @@ -71,7 +71,7 @@ config CPU_ARM9TDMI # ARM920T config CPU_ARM920T - bool "Support ARM920T processor" if ARCH_INTEGRATOR + bool "Support ARM920T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -89,7 +89,7 @@ config CPU_ARM920T # ARM922T config CPU_ARM922T - bool "Support ARM922T processor" if ARCH_INTEGRATOR + bool "Support ARM922T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) select CPU_32v4T select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -127,7 +127,7 @@ config CPU_ARM925T # ARM926T config CPU_ARM926T - bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB + bool "Support ARM926T processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V5) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB) select CPU_32v5 select CPU_ABRT_EV5TJ select CPU_CACHE_VIVT @@ -163,7 +163,7 @@ config CPU_FA526 # ARM940T config CPU_ARM940T - bool "Support ARM940T processor" if ARCH_INTEGRATOR + bool "Support ARM940T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR) depends on !MMU select CPU_32v4T select CPU_ABRT_NOMMU @@ -181,7 +181,7 @@ config CPU_ARM940T # ARM946E-S config CPU_ARM946E - bool "Support ARM946E-S processor" if ARCH_INTEGRATOR + bool "Support ARM946E-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) depends on !MMU select CPU_32v5 select CPU_ABRT_NOMMU @@ -198,7 +198,7 @@ config CPU_ARM946E # ARM1020 - needs validating config CPU_ARM1020 - bool "Support ARM1020T (rev 0) processor" if ARCH_INTEGRATOR + bool "Support ARM1020T (rev 0) processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV4T select CPU_CACHE_V4WT @@ -216,7 +216,7 @@ config CPU_ARM1020 # ARM1020E - needs validating config CPU_ARM1020E - bool "Support ARM1020E processor" if ARCH_INTEGRATOR + bool "Support ARM1020E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) depends on n select CPU_32v5 select CPU_ABRT_EV4T @@ -229,7 +229,7 @@ config CPU_ARM1020E # ARM1022E config CPU_ARM1022 - bool "Support ARM1022E processor" if ARCH_INTEGRATOR + bool "Support ARM1022E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV4T select CPU_CACHE_VIVT @@ -247,7 +247,7 @@ config CPU_ARM1022 # ARM1026EJ-S config CPU_ARM1026 - bool "Support ARM1026EJ-S processor" if ARCH_INTEGRATOR + bool "Support ARM1026EJ-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR) select CPU_32v5 select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10 select CPU_CACHE_VIVT @@ -358,7 +358,7 @@ config CPU_PJ4B # ARMv6 config CPU_V6 - bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6 select CPU_ABRT_EV6 select CPU_CACHE_V6 @@ -371,7 +371,7 @@ config CPU_V6 # ARMv6k config CPU_V6K - bool "Support ARM V6K processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V6K processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6 select CPU_32v6K select CPU_ABRT_EV6 @@ -385,7 +385,7 @@ config CPU_V6K # ARMv7 config CPU_V7 - bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX + bool "Support ARM V7 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V7) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX) select CPU_32v6K select CPU_32v7 select CPU_ABRT_EV7 @@ -798,6 +798,7 @@ config NEED_KUSER_HELPERS config KUSER_HELPERS bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS + depends on MMU default y help Warning: disabling this option may break user programs. diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index b3a947863ac7..22ac2a6fbfe3 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -270,7 +270,6 @@ __v7_pj4b_setup: /* Auxiliary Debug Modes Control 1 Register */ #define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */ #define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */ -#define PJ4B_BCK_OFF_STREX (1 << 5) /* Enable the back off of STREX instr */ #define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */ /* Auxiliary Debug Modes Control 2 Register */ @@ -293,7 +292,6 @@ __v7_pj4b_setup: /* Auxiliary Debug Modes Control 1 Register */ mrc p15, 1, r0, c15, c1, 1 orr r0, r0, #PJ4B_CLEAN_LINE - orr r0, r0, #PJ4B_BCK_OFF_STREX orr r0, r0, #PJ4B_INTER_PARITY bic r0, r0, #PJ4B_STATIC_BP mcr p15, 1, r0, c15, c1, 1 diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 23259f104c66..afa2b3c4df4a 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -535,7 +535,7 @@ ENTRY(cpu_xscale_do_suspend) mrc p15, 0, r5, c15, c1, 0 @ CP access reg mrc p15, 0, r6, c13, c0, 0 @ PID mrc p15, 0, r7, c3, c0, 0 @ domain ID - mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg + mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg mrc p15, 0, r9, c1, c0, 0 @ control reg bic r4, r4, #2 @ clear frequency change bit stmia r0, {r4 - r9} @ store cp regs @@ -552,7 +552,7 @@ ENTRY(cpu_xscale_do_resume) mcr p15, 0, r6, c13, c0, 0 @ PID mcr p15, 0, r7, c3, c0, 0 @ domain ID mcr p15, 0, r1, c2, c0, 0 @ translation table base addr - mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg + mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg mov r0, r9 @ control register b cpu_resume_mmu ENDPROC(cpu_xscale_do_resume) diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index b61a3bcc2fa8..e048f6198d68 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c @@ -497,6 +497,34 @@ static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define orion_gpio_dbg_show NULL #endif +static void orion_gpio_unmask_irq(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + u32 reg_val; + u32 mask = d->mask; + + irq_gc_lock(gc); + reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask); + reg_val |= mask; + irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask); + irq_gc_unlock(gc); +} + +static void orion_gpio_mask_irq(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct irq_chip_type *ct = irq_data_get_chip_type(d); + u32 mask = d->mask; + u32 reg_val; + + irq_gc_lock(gc); + reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask); + reg_val &= ~mask; + irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask); + irq_gc_unlock(gc); +} + void __init orion_gpio_init(struct device_node *np, int gpio_base, int ngpio, void __iomem *base, int mask_offset, @@ -565,8 +593,8 @@ void __init orion_gpio_init(struct device_node *np, ct = gc->chip_types; ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_mask = orion_gpio_mask_irq; + ct->chip.irq_unmask = orion_gpio_unmask_irq; ct->chip.irq_set_type = gpio_irq_set_type; ct->chip.name = ochip->chip.label; @@ -575,8 +603,8 @@ void __init orion_gpio_init(struct device_node *np, ct->regs.ack = GPIO_EDGE_CAUSE_OFF; ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; ct->chip.irq_ack = irq_gc_ack_clr_bit; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->chip.irq_mask = orion_gpio_mask_irq; + ct->chip.irq_unmask = orion_gpio_unmask_irq; ct->chip.irq_set_type = gpio_irq_set_type; ct->handler = handle_edge_irq; ct->chip.name = ochip->chip.label; diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index f0a008496993..87746c37f030 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o # PM support obj-$(CONFIG_PM_SLEEP) += pm-common.o +obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm-common.o obj-$(CONFIG_SAMSUNG_PM) += pm.o obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o diff --git a/arch/arm/plat-samsung/include/plat/map-s5p.h b/arch/arm/plat-samsung/include/plat/map-s5p.h index f5b9d3ff9cd4..f5cf2bd208e0 100644 --- a/arch/arm/plat-samsung/include/plat/map-s5p.h +++ b/arch/arm/plat-samsung/include/plat/map-s5p.h @@ -15,43 +15,22 @@ #define S5P_VA_CHIPID S3C_ADDR(0x02000000) #define S5P_VA_CMU S3C_ADDR(0x02100000) -#define S5P_VA_GPIO S3C_ADDR(0x02200000) -#define S5P_VA_GPIO1 S5P_VA_GPIO -#define S5P_VA_GPIO2 S3C_ADDR(0x02240000) -#define S5P_VA_GPIO3 S3C_ADDR(0x02280000) -#define S5P_VA_SYSRAM S3C_ADDR(0x02400000) -#define S5P_VA_SYSRAM_NS S3C_ADDR(0x02410000) #define S5P_VA_DMC0 S3C_ADDR(0x02440000) #define S5P_VA_DMC1 S3C_ADDR(0x02480000) #define S5P_VA_SROMC S3C_ADDR(0x024C0000) -#define S5P_VA_SYSTIMER S3C_ADDR(0x02500000) -#define S5P_VA_L2CC S3C_ADDR(0x02600000) - -#define S5P_VA_COMBINER_BASE S3C_ADDR(0x02700000) -#define S5P_VA_COMBINER(x) (S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10) - #define S5P_VA_COREPERI_BASE S3C_ADDR(0x02800000) #define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x)) #define S5P_VA_SCU S5P_VA_COREPERI(0x0) #define S5P_VA_TWD S5P_VA_COREPERI(0x600) -#define S5P_VA_GIC_CPU S3C_ADDR(0x02810000) -#define S5P_VA_GIC_DIST S3C_ADDR(0x02820000) - #define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000)) #define VA_VIC0 VA_VIC(0) #define VA_VIC1 VA_VIC(1) #define VA_VIC2 VA_VIC(2) #define VA_VIC3 VA_VIC(3) -#define S5P_VA_UART(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) -#define S5P_VA_UART0 S5P_VA_UART(0) -#define S5P_VA_UART1 S5P_VA_UART(1) -#define S5P_VA_UART2 S5P_VA_UART(2) -#define S5P_VA_UART3 S5P_VA_UART(3) - #ifndef S3C_UART_OFFSET #define S3C_UART_OFFSET (0x400) #endif diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig index a301ca2c7d00..49b8ef91584a 100644 --- a/arch/arm/plat-versatile/Kconfig +++ b/arch/arm/plat-versatile/Kconfig @@ -4,6 +4,6 @@ config PLAT_VERSATILE_CLOCK bool config PLAT_VERSATILE_SCHED_CLOCK - def_bool y + bool endif diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index db1aa5446a57..6caad5428178 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -34,13 +34,16 @@ config ARM64 select GENERIC_TIME_VSYSCALL select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND + select HAVE_ALIGNED_STRUCT_PAGE if SLUB select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_KGDB + select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_BPF_JIT select HAVE_C_RECORDMCOUNT select HAVE_CC_STACKPROTECTOR + select HAVE_CMPXCHG_DOUBLE select HAVE_DEBUG_BUGVERBOSE select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_API_DEBUG @@ -190,6 +193,114 @@ endmenu menu "Kernel Features" +menu "ARM errata workarounds via the alternatives framework" + +config ARM64_ERRATUM_826319 + bool "Cortex-A53: 826319: System might deadlock if a write cannot complete until read data is accepted" + default y + help + This option adds an alternative code sequence to work around ARM + erratum 826319 on Cortex-A53 parts up to r0p2 with an AMBA 4 ACE or + AXI master interface and an L2 cache. + + If a Cortex-A53 uses an AMBA AXI4 ACE interface to other processors + and is unable to accept a certain write via this interface, it will + not progress on read data presented on the read data channel and the + system can deadlock. + + The workaround promotes data cache clean instructions to + data cache clean-and-invalidate. + Please note that this does not necessarily enable the workaround, + as it depends on the alternative framework, which will only patch + the kernel if an affected CPU is detected. + + If unsure, say Y. + +config ARM64_ERRATUM_827319 + bool "Cortex-A53: 827319: Data cache clean instructions might cause overlapping transactions to the interconnect" + default y + help + This option adds an alternative code sequence to work around ARM + erratum 827319 on Cortex-A53 parts up to r0p2 with an AMBA 5 CHI + master interface and an L2 cache. + + Under certain conditions this erratum can cause a clean line eviction + to occur at the same time as another transaction to the same address + on the AMBA 5 CHI interface, which can cause data corruption if the + interconnect reorders the two transactions. + + The workaround promotes data cache clean instructions to + data cache clean-and-invalidate. + Please note that this does not necessarily enable the workaround, + as it depends on the alternative framework, which will only patch + the kernel if an affected CPU is detected. + + If unsure, say Y. + +config ARM64_ERRATUM_824069 + bool "Cortex-A53: 824069: Cache line might not be marked as clean after a CleanShared snoop" + default y + help + This option adds an alternative code sequence to work around ARM + erratum 824069 on Cortex-A53 parts up to r0p2 when it is connected + to a coherent interconnect. + + If a Cortex-A53 processor is executing a store or prefetch for + write instruction at the same time as a processor in another + cluster is executing a cache maintenance operation to the same + address, then this erratum might cause a clean cache line to be + incorrectly marked as dirty. + + The workaround promotes data cache clean instructions to + data cache clean-and-invalidate. + Please note that this option does not necessarily enable the + workaround, as it depends on the alternative framework, which will + only patch the kernel if an affected CPU is detected. + + If unsure, say Y. + +config ARM64_ERRATUM_819472 + bool "Cortex-A53: 819472: Store exclusive instructions might cause data corruption" + default y + help + This option adds an alternative code sequence to work around ARM + erratum 819472 on Cortex-A53 parts up to r0p1 with an L2 cache + present when it is connected to a coherent interconnect. + + If the processor is executing a load and store exclusive sequence at + the same time as a processor in another cluster is executing a cache + maintenance operation to the same address, then this erratum might + cause data corruption. + + The workaround promotes data cache clean instructions to + data cache clean-and-invalidate. + Please note that this does not necessarily enable the workaround, + as it depends on the alternative framework, which will only patch + the kernel if an affected CPU is detected. + + If unsure, say Y. + +config ARM64_ERRATUM_832075 + bool "Cortex-A57: 832075: possible deadlock on mixing exclusive memory accesses with device loads" + default y + help + This option adds an alternative code sequence to work around ARM + erratum 832075 on Cortex-A57 parts up to r1p2. + + Affected Cortex-A57 parts might deadlock when exclusive load/store + instructions to Write-Back memory are mixed with Device loads. + + The workaround is to promote device loads to use Load-Acquire + semantics. + Please note that this does not necessarily enable the workaround, + as it depends on the alternative framework, which will only patch + the kernel if an affected CPU is detected. + + If unsure, say Y. + +endmenu + + choice prompt "Page size" default ARM64_4K_PAGES @@ -342,6 +453,19 @@ config ARCH_HAS_CACHE_LINE_SIZE source "mm/Kconfig" +config SECCOMP + bool "Enable seccomp to safely compute untrusted bytecode" + ---help--- + This kernel feature is useful for number crunching applications + that may need to compute untrusted bytecode during their + execution. By using pipes or other transports made available to + the process as file descriptors supporting the read/write + syscalls, it's possible to isolate those applications in + their own address space using seccomp. Once seccomp is + enabled via prctl(PR_SET_SECCOMP), it cannot be disabled + and the task is only allowed to execute a few safe syscalls + defined by each seccomp mode. + config XEN_DOM0 def_bool y depends on XEN @@ -358,6 +482,58 @@ config FORCE_MAX_ZONEORDER default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE) default "11" +menuconfig ARMV8_DEPRECATED + bool "Emulate deprecated/obsolete ARMv8 instructions" + depends on COMPAT + help + Legacy software support may require certain instructions + that have been deprecated or obsoleted in the architecture. + + Enable this config to enable selective emulation of these + features. + + If unsure, say Y + +if ARMV8_DEPRECATED + +config SWP_EMULATION + bool "Emulate SWP/SWPB instructions" + help + ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that + they are always undefined. Say Y here to enable software + emulation of these instructions for userspace using LDXR/STXR. + + In some older versions of glibc [<=2.8] SWP is used during futex + trylock() operations with the assumption that the code will not + be preempted. This invalid assumption may be more likely to fail + with SWP emulation enabled, leading to deadlock of the user + application. + + NOTE: when accessing uncached shared regions, LDXR/STXR rely + on an external transaction monitoring block called a global + monitor to maintain update atomicity. If your system does not + implement a global monitor, this option can cause programs that + perform SWP operations to uncached memory to deadlock. + + If unsure, say Y + +config CP15_BARRIER_EMULATION + bool "Emulate CP15 Barrier instructions" + help + The CP15 barrier instructions - CP15ISB, CP15DSB, and + CP15DMB - are deprecated in ARMv8 (and ARMv7). It is + strongly recommended to use the ISB, DSB, and DMB + instructions instead. + + Say Y here to enable software emulation of these + instructions for AArch32 userspace code. When this option is + enabled, CP15 barrier usage is traced which can help + identify software that needs updating. + + If unsure, say Y + +endif + endmenu menu "Boot options" @@ -398,6 +574,17 @@ config EFI allow the kernel to be booted as an EFI application. This is only useful on systems that have UEFI firmware. +config DMI + bool "Enable support for SMBIOS (DMI) tables" + depends on EFI + default y + help + This enables SMBIOS/DMI feature for systems. + + This option is only useful on systems that have UEFI firmware. + However, even with this option, the resultant kernel should + continue to boot on existing non-UEFI platforms. + endmenu menu "Userspace binary formats" diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index 0a12933e50ed..5fdd6dce8061 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -6,6 +6,18 @@ config FRAME_POINTER bool default y +config ARM64_PTDUMP + bool "Export kernel pagetable layout to userspace via debugfs" + depends on DEBUG_KERNEL + select DEBUG_FS + help + Say Y here if you want to show the kernel pagetable layout in a + debugfs file. This information is only useful for kernel developers + who are working in architecture specific areas of the kernel. + It is probably not a good idea to enable this feature in a production + kernel. + If in doubt, say "N" + config STRICT_DEVMEM bool "Filter access to /dev/mem" depends on MMU diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 20901ffed182..1c43cec971b5 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -70,8 +70,13 @@ zinstall install: vmlinux %.dtb: scripts $(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@ -dtbs: scripts - $(Q)$(MAKE) $(build)=$(boot)/dts dtbs +PHONY += dtbs dtbs_install + +dtbs: prepare scripts + $(Q)$(MAKE) $(build)=$(boot)/dts + +dtbs_install: + $(Q)$(MAKE) $(dtbinst)=$(boot)/dts PHONY += vdso_install vdso_install: @@ -85,6 +90,7 @@ define archhelp echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)' echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' echo '* dtbs - Build device tree blobs for enabled boards' + echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)' echo ' install - Install uncompressed kernel' echo ' zinstall - Install compressed kernel' echo ' Install using (your) ~/bin/installkernel or' diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index f8001a62029c..e8efc8ff3d58 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -1,10 +1,7 @@ -dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb -dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb -dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb +dts-dirs += apm +dts-dirs += arm +dts-dirs += cavium -targets += dtbs -targets += $(dtb-y) - -dtbs: $(addprefix $(obj)/, $(dtb-y)) - -clean-files := *.dtb +always := $(dtb-y) +subdir-y := $(dts-dirs) +clean-files := *.dtb diff --git a/arch/arm64/boot/dts/apm/Makefile b/arch/arm64/boot/dts/apm/Makefile new file mode 100644 index 000000000000..a2afabbc1717 --- /dev/null +++ b/arch/arm64/boot/dts/apm/Makefile @@ -0,0 +1,5 @@ +dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb + +always := $(dtb-y) +subdir-y := $(dts-dirs) +clean-files := *.dtb diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm/apm-mustang.dts index 2e25de0800b9..2e25de0800b9 100644 --- a/arch/arm64/boot/dts/apm-mustang.dts +++ b/arch/arm64/boot/dts/apm/apm-mustang.dts diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi index 295c72d52a1f..f1ad9c2ab2e9 100644 --- a/arch/arm64/boot/dts/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi @@ -599,7 +599,7 @@ compatible = "apm,xgene-enet"; status = "disabled"; reg = <0x0 0x17020000 0x0 0xd100>, - <0x0 0X17030000 0x0 0X400>, + <0x0 0X17030000 0x0 0Xc300>, <0x0 0X10000000 0x0 0X200>; reg-names = "enet_csr", "ring_csr", "ring_cmd"; interrupts = <0x0 0x3c 0x4>; @@ -624,9 +624,9 @@ sgenet0: ethernet@1f210000 { compatible = "apm,xgene-enet"; status = "disabled"; - reg = <0x0 0x1f210000 0x0 0x10000>, - <0x0 0x1f200000 0x0 0X10000>, - <0x0 0x1B000000 0x0 0X20000>; + reg = <0x0 0x1f210000 0x0 0xd100>, + <0x0 0x1f200000 0x0 0Xc300>, + <0x0 0x1B000000 0x0 0X200>; reg-names = "enet_csr", "ring_csr", "ring_cmd"; interrupts = <0x0 0xA0 0x4>; dma-coherent; @@ -639,7 +639,7 @@ compatible = "apm,xgene-enet"; status = "disabled"; reg = <0x0 0x1f610000 0x0 0xd100>, - <0x0 0x1f600000 0x0 0X400>, + <0x0 0x1f600000 0x0 0Xc300>, <0x0 0x18000000 0x0 0X200>; reg-names = "enet_csr", "ring_csr", "ring_cmd"; interrupts = <0x0 0x60 0x4>; diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile new file mode 100644 index 000000000000..43d1404bb3c1 --- /dev/null +++ b/arch/arm64/boot/dts/arm/Makefile @@ -0,0 +1,6 @@ +dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb +dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb + +always := $(dtb-y) +subdir-y := $(dts-dirs) +clean-files := *.dtb diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/arm/foundation-v8.dts index 4a060906809d..4a060906809d 100644 --- a/arch/arm64/boot/dts/foundation-v8.dts +++ b/arch/arm64/boot/dts/arm/foundation-v8.dts diff --git a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts index 572005ea2217..572005ea2217 100644 --- a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts +++ b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts diff --git a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi index c46cbb29f3c6..c46cbb29f3c6 100644 --- a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi +++ b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi diff --git a/arch/arm64/boot/dts/cavium/Makefile b/arch/arm64/boot/dts/cavium/Makefile new file mode 100644 index 000000000000..e34f89ddabb2 --- /dev/null +++ b/arch/arm64/boot/dts/cavium/Makefile @@ -0,0 +1,5 @@ +dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb + +always := $(dtb-y) +subdir-y := $(dts-dirs) +clean-files := *.dtb diff --git a/arch/arm64/boot/dts/thunder-88xx.dts b/arch/arm64/boot/dts/cavium/thunder-88xx.dts index 800ba65991f7..800ba65991f7 100644 --- a/arch/arm64/boot/dts/thunder-88xx.dts +++ b/arch/arm64/boot/dts/cavium/thunder-88xx.dts diff --git a/arch/arm64/boot/dts/thunder-88xx.dtsi b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi index d8c0bdc51882..d8c0bdc51882 100644 --- a/arch/arm64/boot/dts/thunder-88xx.dtsi +++ b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 4ce602c2c6de..dd301be89ecc 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -35,6 +35,9 @@ CONFIG_MODULE_UNLOAD=y CONFIG_ARCH_THUNDER=y CONFIG_ARCH_VEXPRESS=y CONFIG_ARCH_XGENE=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_XGENE=y CONFIG_SMP=y CONFIG_PREEMPT=y CONFIG_KSM=y @@ -52,6 +55,7 @@ CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set +CONFIG_BPF_JIT=y # CONFIG_WIRELESS is not set CONFIG_NET_9P=y CONFIG_NET_9P_VIRTIO=y @@ -65,16 +69,17 @@ CONFIG_VIRTIO_BLK=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y CONFIG_AHCI_XGENE=y -CONFIG_PHY_XGENE=y CONFIG_PATA_PLATFORM=y CONFIG_PATA_OF_PLATFORM=y CONFIG_NETDEVICES=y CONFIG_TUN=y CONFIG_VIRTIO_NET=y +CONFIG_NET_XGENE=y CONFIG_SMC91X=y CONFIG_SMSC911X=y -CONFIG_NET_XGENE=y # CONFIG_WLAN is not set CONFIG_INPUT_EVDEV=y # CONFIG_SERIO_SERPORT is not set @@ -87,6 +92,11 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_VIRTIO_CONSOLE=y # CONFIG_HW_RANDOM is not set +# CONFIG_HMC_DRV is not set +CONFIG_SPI=y +CONFIG_SPI_PL022=y +CONFIG_GPIO_PL061=y +CONFIG_GPIO_XGENE=y # CONFIG_HWMON is not set CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y @@ -97,13 +107,25 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y CONFIG_USB_ISP1760_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_STORAGE=y +CONFIG_USB_ULPI=y CONFIG_MMC=y CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SPI=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_EFI=y +CONFIG_RTC_DRV_XGENE=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_MMIO=y # CONFIG_IOMMU_SUPPORT is not set +CONFIG_PHY_XGENE=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index 5562652c5316..a38b02ce5f9a 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -27,20 +27,19 @@ config CRYPTO_AES_ARM64_CE tristate "AES core cipher using ARMv8 Crypto Extensions" depends on ARM64 && KERNEL_MODE_NEON select CRYPTO_ALGAPI - select CRYPTO_AES config CRYPTO_AES_ARM64_CE_CCM tristate "AES in CCM mode using ARMv8 Crypto Extensions" depends on ARM64 && KERNEL_MODE_NEON select CRYPTO_ALGAPI - select CRYPTO_AES + select CRYPTO_AES_ARM64_CE select CRYPTO_AEAD config CRYPTO_AES_ARM64_CE_BLK tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions" depends on ARM64 && KERNEL_MODE_NEON select CRYPTO_BLKCIPHER - select CRYPTO_AES + select CRYPTO_AES_ARM64_CE select CRYPTO_ABLK_HELPER config CRYPTO_AES_ARM64_NEON_BLK diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index 9e6cdde9b43d..0ac73b838fa3 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -16,6 +16,8 @@ #include <linux/crypto.h> #include <linux/module.h> +#include "aes-ce-setkey.h" + static int num_rounds(struct crypto_aes_ctx *ctx) { /* @@ -48,7 +50,7 @@ static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key, struct crypto_aes_ctx *ctx = crypto_aead_ctx(tfm); int ret; - ret = crypto_aes_expand_key(ctx, in_key, key_len); + ret = ce_aes_expandkey(ctx, in_key, key_len); if (!ret) return 0; diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher.c index 2075e1acae6b..ce47792a983d 100644 --- a/arch/arm64/crypto/aes-ce-cipher.c +++ b/arch/arm64/crypto/aes-ce-cipher.c @@ -14,6 +14,8 @@ #include <linux/crypto.h> #include <linux/module.h> +#include "aes-ce-setkey.h" + MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions"); MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); MODULE_LICENSE("GPL v2"); @@ -124,6 +126,114 @@ static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) kernel_neon_end(); } +/* + * aes_sub() - use the aese instruction to perform the AES sbox substitution + * on each byte in 'input' + */ +static u32 aes_sub(u32 input) +{ + u32 ret; + + __asm__("dup v1.4s, %w[in] ;" + "movi v0.16b, #0 ;" + "aese v0.16b, v1.16b ;" + "umov %w[out], v0.4s[0] ;" + + : [out] "=r"(ret) + : [in] "r"(input) + : "v0","v1"); + + return ret; +} + +int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, + unsigned int key_len) +{ + /* + * The AES key schedule round constants + */ + static u8 const rcon[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, + }; + + u32 kwords = key_len / sizeof(u32); + struct aes_block *key_enc, *key_dec; + int i, j; + + if (key_len != AES_KEYSIZE_128 && + key_len != AES_KEYSIZE_192 && + key_len != AES_KEYSIZE_256) + return -EINVAL; + + memcpy(ctx->key_enc, in_key, key_len); + ctx->key_length = key_len; + + kernel_neon_begin_partial(2); + for (i = 0; i < sizeof(rcon); i++) { + u32 *rki = ctx->key_enc + (i * kwords); + u32 *rko = rki + kwords; + + rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0]; + rko[1] = rko[0] ^ rki[1]; + rko[2] = rko[1] ^ rki[2]; + rko[3] = rko[2] ^ rki[3]; + + if (key_len == AES_KEYSIZE_192) { + if (i >= 7) + break; + rko[4] = rko[3] ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + } else if (key_len == AES_KEYSIZE_256) { + if (i >= 6) + break; + rko[4] = aes_sub(rko[3]) ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + rko[6] = rko[5] ^ rki[6]; + rko[7] = rko[6] ^ rki[7]; + } + } + + /* + * Generate the decryption keys for the Equivalent Inverse Cipher. + * This involves reversing the order of the round keys, and applying + * the Inverse Mix Columns transformation on all but the first and + * the last one. + */ + key_enc = (struct aes_block *)ctx->key_enc; + key_dec = (struct aes_block *)ctx->key_dec; + j = num_rounds(ctx); + + key_dec[0] = key_enc[j]; + for (i = 1, j--; j > 0; i++, j--) + __asm__("ld1 {v0.16b}, %[in] ;" + "aesimc v1.16b, v0.16b ;" + "st1 {v1.16b}, %[out] ;" + + : [out] "=Q"(key_dec[i]) + : [in] "Q"(key_enc[j]) + : "v0","v1"); + key_dec[i] = key_enc[0]; + + kernel_neon_end(); + return 0; +} +EXPORT_SYMBOL(ce_aes_expandkey); + +int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); + int ret; + + ret = ce_aes_expandkey(ctx, in_key, key_len); + if (!ret) + return 0; + + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; +} +EXPORT_SYMBOL(ce_aes_setkey); + static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_driver_name = "aes-ce", @@ -135,7 +245,7 @@ static struct crypto_alg aes_alg = { .cra_cipher = { .cia_min_keysize = AES_MIN_KEY_SIZE, .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = crypto_aes_set_key, + .cia_setkey = ce_aes_setkey, .cia_encrypt = aes_cipher_encrypt, .cia_decrypt = aes_cipher_decrypt } diff --git a/arch/arm64/crypto/aes-ce-setkey.h b/arch/arm64/crypto/aes-ce-setkey.h new file mode 100644 index 000000000000..f08a6471d034 --- /dev/null +++ b/arch/arm64/crypto/aes-ce-setkey.h @@ -0,0 +1,5 @@ + +int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len); +int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, + unsigned int key_len); diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index 79cd911ef88c..801aae32841f 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -16,9 +16,13 @@ #include <linux/module.h> #include <linux/cpufeature.h> +#include "aes-ce-setkey.h" + #ifdef USE_V8_CRYPTO_EXTENSIONS #define MODE "ce" #define PRIO 300 +#define aes_setkey ce_aes_setkey +#define aes_expandkey ce_aes_expandkey #define aes_ecb_encrypt ce_aes_ecb_encrypt #define aes_ecb_decrypt ce_aes_ecb_decrypt #define aes_cbc_encrypt ce_aes_cbc_encrypt @@ -30,6 +34,8 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); #else #define MODE "neon" #define PRIO 200 +#define aes_setkey crypto_aes_set_key +#define aes_expandkey crypto_aes_expand_key #define aes_ecb_encrypt neon_aes_ecb_encrypt #define aes_ecb_decrypt neon_aes_ecb_decrypt #define aes_cbc_encrypt neon_aes_cbc_encrypt @@ -79,10 +85,10 @@ static int xts_set_key(struct crypto_tfm *tfm, const u8 *in_key, struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); int ret; - ret = crypto_aes_expand_key(&ctx->key1, in_key, key_len / 2); + ret = aes_expandkey(&ctx->key1, in_key, key_len / 2); if (!ret) - ret = crypto_aes_expand_key(&ctx->key2, &in_key[key_len / 2], - key_len / 2); + ret = aes_expandkey(&ctx->key2, &in_key[key_len / 2], + key_len / 2); if (!ret) return 0; @@ -288,7 +294,7 @@ static struct crypto_alg aes_algs[] = { { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, - .setkey = crypto_aes_set_key, + .setkey = aes_setkey, .encrypt = ecb_encrypt, .decrypt = ecb_decrypt, }, @@ -306,7 +312,7 @@ static struct crypto_alg aes_algs[] = { { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, - .setkey = crypto_aes_set_key, + .setkey = aes_setkey, .encrypt = cbc_encrypt, .decrypt = cbc_decrypt, }, @@ -324,7 +330,7 @@ static struct crypto_alg aes_algs[] = { { .min_keysize = AES_MIN_KEY_SIZE, .max_keysize = AES_MAX_KEY_SIZE, .ivsize = AES_BLOCK_SIZE, - .setkey = crypto_aes_set_key, + .setkey = aes_setkey, .encrypt = ctr_encrypt, .decrypt = ctr_encrypt, }, diff --git a/arch/arm64/include/asm/alternative-asm.h b/arch/arm64/include/asm/alternative-asm.h new file mode 100644 index 000000000000..919a67855b63 --- /dev/null +++ b/arch/arm64/include/asm/alternative-asm.h @@ -0,0 +1,29 @@ +#ifndef __ASM_ALTERNATIVE_ASM_H +#define __ASM_ALTERNATIVE_ASM_H + +#ifdef __ASSEMBLY__ + +.macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len + .word \orig_offset - . + .word \alt_offset - . + .hword \feature + .byte \orig_len + .byte \alt_len +.endm + +.macro alternative_insn insn1 insn2 cap +661: \insn1 +662: .pushsection .altinstructions, "a" + altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f + .popsection + .pushsection .altinstr_replacement, "ax" +663: \insn2 +664: .popsection + .if ((664b-663b) != (662b-661b)) + .error "Alternatives instruction length mismatch" + .endif +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_ALTERNATIVE_ASM_H */ diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h new file mode 100644 index 000000000000..d261f01e2bae --- /dev/null +++ b/arch/arm64/include/asm/alternative.h @@ -0,0 +1,44 @@ +#ifndef __ASM_ALTERNATIVE_H +#define __ASM_ALTERNATIVE_H + +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/stringify.h> + +struct alt_instr { + s32 orig_offset; /* offset to original instruction */ + s32 alt_offset; /* offset to replacement instruction */ + u16 cpufeature; /* cpufeature bit set for replacement */ + u8 orig_len; /* size of original instruction(s) */ + u8 alt_len; /* size of new instruction(s), <= orig_len */ +}; + +void apply_alternatives_all(void); +void apply_alternatives(void *start, size_t length); +void free_alternatives_memory(void); + +#define ALTINSTR_ENTRY(feature) \ + " .word 661b - .\n" /* label */ \ + " .word 663f - .\n" /* new instruction */ \ + " .hword " __stringify(feature) "\n" /* feature bit */ \ + " .byte 662b-661b\n" /* source len */ \ + " .byte 664f-663f\n" /* replacement len */ + +/* alternative assembly primitive: */ +#define ALTERNATIVE(oldinstr, newinstr, feature) \ + "661:\n\t" \ + oldinstr "\n" \ + "662:\n" \ + ".pushsection .altinstructions,\"a\"\n" \ + ALTINSTR_ENTRY(feature) \ + ".popsection\n" \ + ".pushsection .altinstr_replacement, \"a\"\n" \ + "663:\n\t" \ + newinstr "\n" \ + "664:\n\t" \ + ".popsection\n\t" \ + ".if ((664b-663b) != (662b-661b))\n\t" \ + " .error \"Alternatives instruction length mismatch\"\n\t"\ + ".endif\n" + +#endif /* __ASM_ALTERNATIVE_H */ diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h index 88cc05b5f3ac..bde449936e2f 100644 --- a/arch/arm64/include/asm/cache.h +++ b/arch/arm64/include/asm/cache.h @@ -32,6 +32,8 @@ #ifndef __ASSEMBLY__ +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) + static inline int cache_line_size(void) { u32 cwg = cache_type_cwg(); diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index 689b6379188c..7ae31a2cc6c0 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -73,7 +73,7 @@ extern void flush_cache_all(void); extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_icache_range(unsigned long start, unsigned long end); extern void __flush_dcache_area(void *addr, size_t len); -extern void __flush_cache_user_range(unsigned long start, unsigned long end); +extern long __flush_cache_user_range(unsigned long start, unsigned long end); static inline void flush_cache_mm(struct mm_struct *mm) { diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index ddb9d7830558..cb9593079f29 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -19,6 +19,7 @@ #define __ASM_CMPXCHG_H #include <linux/bug.h> +#include <linux/mmdebug.h> #include <asm/barrier.h> @@ -152,6 +153,51 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, return oldval; } +#define system_has_cmpxchg_double() 1 + +static inline int __cmpxchg_double(volatile void *ptr1, volatile void *ptr2, + unsigned long old1, unsigned long old2, + unsigned long new1, unsigned long new2, int size) +{ + unsigned long loop, lost; + + switch (size) { + case 8: + VM_BUG_ON((unsigned long *)ptr2 - (unsigned long *)ptr1 != 1); + do { + asm volatile("// __cmpxchg_double8\n" + " ldxp %0, %1, %2\n" + " eor %0, %0, %3\n" + " eor %1, %1, %4\n" + " orr %1, %0, %1\n" + " mov %w0, #0\n" + " cbnz %1, 1f\n" + " stxp %w0, %5, %6, %2\n" + "1:\n" + : "=&r"(loop), "=&r"(lost), "+Q" (*(u64 *)ptr1) + : "r" (old1), "r"(old2), "r"(new1), "r"(new2)); + } while (loop); + break; + default: + BUILD_BUG(); + } + + return !lost; +} + +static inline int __cmpxchg_double_mb(volatile void *ptr1, volatile void *ptr2, + unsigned long old1, unsigned long old2, + unsigned long new1, unsigned long new2, int size) +{ + int ret; + + smp_mb(); + ret = __cmpxchg_double(ptr1, ptr2, old1, old2, new1, new2, size); + smp_mb(); + + return ret; +} + static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, unsigned long new, int size) { @@ -182,6 +228,33 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, __ret; \ }) +#define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \ +({\ + int __ret;\ + __ret = __cmpxchg_double_mb((ptr1), (ptr2), (unsigned long)(o1), \ + (unsigned long)(o2), (unsigned long)(n1), \ + (unsigned long)(n2), sizeof(*(ptr1)));\ + __ret; \ +}) + +#define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \ +({\ + int __ret;\ + __ret = __cmpxchg_double((ptr1), (ptr2), (unsigned long)(o1), \ + (unsigned long)(o2), (unsigned long)(n1), \ + (unsigned long)(n2), sizeof(*(ptr1)));\ + __ret; \ +}) + +#define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) +#define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) +#define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) +#define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n) + +#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \ + cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \ + o1, o2, n1, n2) + #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n)) #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n)) diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h index 56de5aadede2..3fb053fa6e98 100644 --- a/arch/arm64/include/asm/compat.h +++ b/arch/arm64/include/asm/compat.h @@ -205,6 +205,13 @@ typedef struct compat_siginfo { compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ int _fd; } _sigpoll; + + /* SIGSYS */ + struct { + compat_uptr_t _call_addr; /* calling user insn */ + int _syscall; /* triggering system call number */ + compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */ + } _sigsys; } _sifields; } compat_siginfo_t; diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h index 056443086019..ace70682499b 100644 --- a/arch/arm64/include/asm/cpu.h +++ b/arch/arm64/include/asm/cpu.h @@ -30,6 +30,8 @@ struct cpuinfo_arm64 { u32 reg_dczid; u32 reg_midr; + u64 reg_id_aa64dfr0; + u64 reg_id_aa64dfr1; u64 reg_id_aa64isar0; u64 reg_id_aa64isar1; u64 reg_id_aa64mmfr0; diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index cd4ac0516488..07547ccc1f2b 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -21,9 +21,38 @@ #define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) #define cpu_feature(x) ilog2(HWCAP_ ## x) +#define ARM64_WORKAROUND_CLEAN_CACHE 0 +#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1 + +#define ARM64_NCAPS 2 + +#ifndef __ASSEMBLY__ + +extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); + static inline bool cpu_have_feature(unsigned int num) { return elf_hwcap & (1UL << num); } +static inline bool cpus_have_cap(unsigned int num) +{ + if (num >= ARM64_NCAPS) + return false; + return test_bit(num, cpu_hwcaps); +} + +static inline void cpus_set_cap(unsigned int num) +{ + if (num >= ARM64_NCAPS) + pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n", + num, ARM64_NCAPS); + else + __set_bit(num, cpu_hwcaps); +} + +void check_local_cpu_errata(void); + +#endif /* __ASSEMBLY__ */ + #endif diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 379d0b874328..8adb986a3086 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -57,6 +57,11 @@ #define MIDR_IMPLEMENTOR(midr) \ (((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT) +#define MIDR_CPU_PART(imp, partnum) \ + (((imp) << MIDR_IMPLEMENTOR_SHIFT) | \ + (0xf << MIDR_ARCHITECTURE_SHIFT) | \ + ((partnum) << MIDR_PARTNUM_SHIFT)) + #define ARM_CPU_IMP_ARM 0x41 #define ARM_CPU_IMP_APM 0x50 diff --git a/arch/arm64/include/asm/dmi.h b/arch/arm64/include/asm/dmi.h new file mode 100644 index 000000000000..69d37d87b159 --- /dev/null +++ b/arch/arm64/include/asm/dmi.h @@ -0,0 +1,31 @@ +/* + * arch/arm64/include/asm/dmi.h + * + * Copyright (C) 2013 Linaro Limited. + * Written by: Yi Li (yi.li@linaro.org) + * + * based on arch/ia64/include/asm/dmi.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef __ASM_DMI_H +#define __ASM_DMI_H + +#include <linux/io.h> +#include <linux/slab.h> + +/* + * According to section 2.3.6 of the UEFI spec, the firmware should not + * request a virtual mapping for configuration tables such as SMBIOS. + * This means we have to map them before use. + */ +#define dmi_early_remap(x, l) ioremap_cache(x, l) +#define dmi_early_unmap(x, l) iounmap(x) +#define dmi_remap(x, l) ioremap_cache(x, l) +#define dmi_unmap(x) iounmap(x) +#define dmi_alloc(l) kzalloc(l, GFP_KERNEL) + +#endif diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index 5f7bfe6df723..9ef6eca905ca 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -31,6 +31,7 @@ * */ enum fixed_addresses { + FIX_HOLE, FIX_EARLYCON_MEM_BASE, __end_of_permanent_fixed_addresses, @@ -56,10 +57,11 @@ enum fixed_addresses { #define FIXMAP_PAGE_IO __pgprot(PROT_DEVICE_nGnRE) -extern void __early_set_fixmap(enum fixed_addresses idx, - phys_addr_t phys, pgprot_t flags); +void __init early_fixmap_init(void); -#define __set_fixmap __early_set_fixmap +#define __early_set_fixmap __set_fixmap + +extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot); #include <asm-generic/fixmap.h> diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h index 024c46183c3c..0ad735166d9f 100644 --- a/arch/arm64/include/asm/hwcap.h +++ b/arch/arm64/include/asm/hwcap.h @@ -30,6 +30,7 @@ #define COMPAT_HWCAP_IDIVA (1 << 17) #define COMPAT_HWCAP_IDIVT (1 << 18) #define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT) +#define COMPAT_HWCAP_LPAE (1 << 20) #define COMPAT_HWCAP_EVTSTRM (1 << 21) #define COMPAT_HWCAP2_AES (1 << 0) diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 56a9e63b6c33..e2ff32a93b5c 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -354,6 +354,16 @@ bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn); int aarch64_insn_patch_text_nosync(void *addr, u32 insn); int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt); int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); + +bool aarch32_insn_is_wide(u32 insn); + +#define A32_RN_OFFSET 16 +#define A32_RT_OFFSET 12 +#define A32_RT2_OFFSET 0 + +u32 aarch32_insn_extract_reg_num(u32 insn, int offset); +u32 aarch32_insn_mcr_extract_opc2(u32 insn); +u32 aarch32_insn_mcr_extract_crm(u32 insn); #endif /* __ASSEMBLY__ */ #endif /* __ASM_INSN_H */ diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 79f1d519221f..75825b63464d 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -28,6 +28,8 @@ #include <asm/barrier.h> #include <asm/pgtable.h> #include <asm/early_ioremap.h> +#include <asm/alternative.h> +#include <asm/cpufeature.h> #include <xen/xen.h> @@ -57,28 +59,41 @@ static inline void __raw_writeq(u64 val, volatile void __iomem *addr) static inline u8 __raw_readb(const volatile void __iomem *addr) { u8 val; - asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr)); + asm volatile(ALTERNATIVE("ldrb %w0, [%1]", + "ldarb %w0, [%1]", + ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) + : "=r" (val) : "r" (addr)); return val; } static inline u16 __raw_readw(const volatile void __iomem *addr) { u16 val; - asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr)); + + asm volatile(ALTERNATIVE("ldrh %w0, [%1]", + "ldarh %w0, [%1]", + ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) + : "=r" (val) : "r" (addr)); return val; } static inline u32 __raw_readl(const volatile void __iomem *addr) { u32 val; - asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr)); + asm volatile(ALTERNATIVE("ldr %w0, [%1]", + "ldar %w0, [%1]", + ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) + : "=r" (val) : "r" (addr)); return val; } static inline u64 __raw_readq(const volatile void __iomem *addr) { u64 val; - asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr)); + asm volatile(ALTERNATIVE("ldr %0, [%1]", + "ldar %0, [%1]", + ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE) + : "=r" (val) : "r" (addr)); return val; } diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index e1f7ecdde11f..94c53674a31d 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -3,7 +3,8 @@ #include <asm-generic/irq.h> -extern void (*handle_arch_irq)(struct pt_regs *); +struct pt_regs; + extern void migrate_irqs(void); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 7fd3e27e3ccc..8afb863f5a9e 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -18,6 +18,7 @@ #ifndef __ARM64_KVM_ARM_H__ #define __ARM64_KVM_ARM_H__ +#include <asm/memory.h> #include <asm/types.h> /* Hyp Configuration Register (HCR) bits */ @@ -160,9 +161,9 @@ #endif #define VTTBR_BADDR_SHIFT (VTTBR_X - 1) -#define VTTBR_BADDR_MASK (((1LLU << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) -#define VTTBR_VMID_SHIFT (48LLU) -#define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT) +#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT) +#define VTTBR_VMID_SHIFT (UL(48)) +#define VTTBR_VMID_MASK (UL(0xFF) << VTTBR_VMID_SHIFT) /* Hyp System Trap Register */ #define HSTR_EL2_TTEE (1 << 16) @@ -185,13 +186,13 @@ /* Exception Syndrome Register (ESR) bits */ #define ESR_EL2_EC_SHIFT (26) -#define ESR_EL2_EC (0x3fU << ESR_EL2_EC_SHIFT) -#define ESR_EL2_IL (1U << 25) +#define ESR_EL2_EC (UL(0x3f) << ESR_EL2_EC_SHIFT) +#define ESR_EL2_IL (UL(1) << 25) #define ESR_EL2_ISS (ESR_EL2_IL - 1) #define ESR_EL2_ISV_SHIFT (24) -#define ESR_EL2_ISV (1U << ESR_EL2_ISV_SHIFT) +#define ESR_EL2_ISV (UL(1) << ESR_EL2_ISV_SHIFT) #define ESR_EL2_SAS_SHIFT (22) -#define ESR_EL2_SAS (3U << ESR_EL2_SAS_SHIFT) +#define ESR_EL2_SAS (UL(3) << ESR_EL2_SAS_SHIFT) #define ESR_EL2_SSE (1 << 21) #define ESR_EL2_SRT_SHIFT (16) #define ESR_EL2_SRT_MASK (0x1f << ESR_EL2_SRT_SHIFT) @@ -205,16 +206,16 @@ #define ESR_EL2_FSC_TYPE (0x3c) #define ESR_EL2_CV_SHIFT (24) -#define ESR_EL2_CV (1U << ESR_EL2_CV_SHIFT) +#define ESR_EL2_CV (UL(1) << ESR_EL2_CV_SHIFT) #define ESR_EL2_COND_SHIFT (20) -#define ESR_EL2_COND (0xfU << ESR_EL2_COND_SHIFT) +#define ESR_EL2_COND (UL(0xf) << ESR_EL2_COND_SHIFT) #define FSC_FAULT (0x04) #define FSC_PERM (0x0c) /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */ -#define HPFAR_MASK (~0xFUL) +#define HPFAR_MASK (~UL(0xf)) #define ESR_EL2_EC_UNKNOWN (0x00) #define ESR_EL2_EC_WFI (0x01) diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index ccc7087d3c4e..a62cd077457b 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -142,7 +142,7 @@ static inline void *phys_to_virt(phys_addr_t x) * virt_to_page(k) convert a _valid_ virtual address to struct page * * virt_addr_valid(k) indicates whether a virtual address is valid */ -#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET +#define ARCH_PFN_OFFSET ((unsigned long)PHYS_PFN_OFFSET) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) diff --git a/arch/arm64/include/asm/opcodes.h b/arch/arm64/include/asm/opcodes.h new file mode 100644 index 000000000000..4e603ea36ad3 --- /dev/null +++ b/arch/arm64/include/asm/opcodes.h @@ -0,0 +1 @@ +#include <../../arm/include/asm/opcodes.h> diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 5279e5733386..09da25bc596f 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -44,6 +44,221 @@ static inline unsigned long __my_cpu_offset(void) #endif /* CONFIG_SMP */ +#define PERCPU_OP(op, asm_op) \ +static inline unsigned long __percpu_##op(void *ptr, \ + unsigned long val, int size) \ +{ \ + unsigned long loop, ret; \ + \ + switch (size) { \ + case 1: \ + do { \ + asm ("//__per_cpu_" #op "_1\n" \ + "ldxrb %w[ret], %[ptr]\n" \ + #asm_op " %w[ret], %w[ret], %w[val]\n" \ + "stxrb %w[loop], %w[ret], %[ptr]\n" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u8 *)ptr) \ + : [val] "Ir" (val)); \ + } while (loop); \ + break; \ + case 2: \ + do { \ + asm ("//__per_cpu_" #op "_2\n" \ + "ldxrh %w[ret], %[ptr]\n" \ + #asm_op " %w[ret], %w[ret], %w[val]\n" \ + "stxrh %w[loop], %w[ret], %[ptr]\n" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u16 *)ptr) \ + : [val] "Ir" (val)); \ + } while (loop); \ + break; \ + case 4: \ + do { \ + asm ("//__per_cpu_" #op "_4\n" \ + "ldxr %w[ret], %[ptr]\n" \ + #asm_op " %w[ret], %w[ret], %w[val]\n" \ + "stxr %w[loop], %w[ret], %[ptr]\n" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u32 *)ptr) \ + : [val] "Ir" (val)); \ + } while (loop); \ + break; \ + case 8: \ + do { \ + asm ("//__per_cpu_" #op "_8\n" \ + "ldxr %[ret], %[ptr]\n" \ + #asm_op " %[ret], %[ret], %[val]\n" \ + "stxr %w[loop], %[ret], %[ptr]\n" \ + : [loop] "=&r" (loop), [ret] "=&r" (ret), \ + [ptr] "+Q"(*(u64 *)ptr) \ + : [val] "Ir" (val)); \ + } while (loop); \ + break; \ + default: \ + BUILD_BUG(); \ + } \ + \ + return ret; \ +} + +PERCPU_OP(add, add) +PERCPU_OP(and, and) +PERCPU_OP(or, orr) +#undef PERCPU_OP + +static inline unsigned long __percpu_read(void *ptr, int size) +{ + unsigned long ret; + + switch (size) { + case 1: + ret = ACCESS_ONCE(*(u8 *)ptr); + break; + case 2: + ret = ACCESS_ONCE(*(u16 *)ptr); + break; + case 4: + ret = ACCESS_ONCE(*(u32 *)ptr); + break; + case 8: + ret = ACCESS_ONCE(*(u64 *)ptr); + break; + default: + BUILD_BUG(); + } + + return ret; +} + +static inline void __percpu_write(void *ptr, unsigned long val, int size) +{ + switch (size) { + case 1: + ACCESS_ONCE(*(u8 *)ptr) = (u8)val; + break; + case 2: + ACCESS_ONCE(*(u16 *)ptr) = (u16)val; + break; + case 4: + ACCESS_ONCE(*(u32 *)ptr) = (u32)val; + break; + case 8: + ACCESS_ONCE(*(u64 *)ptr) = (u64)val; + break; + default: + BUILD_BUG(); + } +} + +static inline unsigned long __percpu_xchg(void *ptr, unsigned long val, + int size) +{ + unsigned long ret, loop; + + switch (size) { + case 1: + do { + asm ("//__percpu_xchg_1\n" + "ldxrb %w[ret], %[ptr]\n" + "stxrb %w[loop], %w[val], %[ptr]\n" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u8 *)ptr) + : [val] "r" (val)); + } while (loop); + break; + case 2: + do { + asm ("//__percpu_xchg_2\n" + "ldxrh %w[ret], %[ptr]\n" + "stxrh %w[loop], %w[val], %[ptr]\n" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u16 *)ptr) + : [val] "r" (val)); + } while (loop); + break; + case 4: + do { + asm ("//__percpu_xchg_4\n" + "ldxr %w[ret], %[ptr]\n" + "stxr %w[loop], %w[val], %[ptr]\n" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u32 *)ptr) + : [val] "r" (val)); + } while (loop); + break; + case 8: + do { + asm ("//__percpu_xchg_8\n" + "ldxr %[ret], %[ptr]\n" + "stxr %w[loop], %[val], %[ptr]\n" + : [loop] "=&r"(loop), [ret] "=&r"(ret), + [ptr] "+Q"(*(u64 *)ptr) + : [val] "r" (val)); + } while (loop); + break; + default: + BUILD_BUG(); + } + + return ret; +} + +#define _percpu_add(pcp, val) \ + __percpu_add(raw_cpu_ptr(&(pcp)), val, sizeof(pcp)) + +#define _percpu_add_return(pcp, val) (typeof(pcp)) (_percpu_add(pcp, val)) + +#define _percpu_and(pcp, val) \ + __percpu_and(raw_cpu_ptr(&(pcp)), val, sizeof(pcp)) + +#define _percpu_or(pcp, val) \ + __percpu_or(raw_cpu_ptr(&(pcp)), val, sizeof(pcp)) + +#define _percpu_read(pcp) (typeof(pcp)) \ + (__percpu_read(raw_cpu_ptr(&(pcp)), sizeof(pcp))) + +#define _percpu_write(pcp, val) \ + __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp)) + +#define _percpu_xchg(pcp, val) (typeof(pcp)) \ + (__percpu_xchg(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp))) + +#define this_cpu_add_1(pcp, val) _percpu_add(pcp, val) +#define this_cpu_add_2(pcp, val) _percpu_add(pcp, val) +#define this_cpu_add_4(pcp, val) _percpu_add(pcp, val) +#define this_cpu_add_8(pcp, val) _percpu_add(pcp, val) + +#define this_cpu_add_return_1(pcp, val) _percpu_add_return(pcp, val) +#define this_cpu_add_return_2(pcp, val) _percpu_add_return(pcp, val) +#define this_cpu_add_return_4(pcp, val) _percpu_add_return(pcp, val) +#define this_cpu_add_return_8(pcp, val) _percpu_add_return(pcp, val) + +#define this_cpu_and_1(pcp, val) _percpu_and(pcp, val) +#define this_cpu_and_2(pcp, val) _percpu_and(pcp, val) +#define this_cpu_and_4(pcp, val) _percpu_and(pcp, val) +#define this_cpu_and_8(pcp, val) _percpu_and(pcp, val) + +#define this_cpu_or_1(pcp, val) _percpu_or(pcp, val) +#define this_cpu_or_2(pcp, val) _percpu_or(pcp, val) +#define this_cpu_or_4(pcp, val) _percpu_or(pcp, val) +#define this_cpu_or_8(pcp, val) _percpu_or(pcp, val) + +#define this_cpu_read_1(pcp) _percpu_read(pcp) +#define this_cpu_read_2(pcp) _percpu_read(pcp) +#define this_cpu_read_4(pcp) _percpu_read(pcp) +#define this_cpu_read_8(pcp) _percpu_read(pcp) + +#define this_cpu_write_1(pcp, val) _percpu_write(pcp, val) +#define this_cpu_write_2(pcp, val) _percpu_write(pcp, val) +#define this_cpu_write_4(pcp, val) _percpu_write(pcp, val) +#define this_cpu_write_8(pcp, val) _percpu_write(pcp, val) + +#define this_cpu_xchg_1(pcp, val) _percpu_xchg(pcp, val) +#define this_cpu_xchg_2(pcp, val) _percpu_xchg(pcp, val) +#define this_cpu_xchg_4(pcp, val) _percpu_xchg(pcp, val) +#define this_cpu_xchg_8(pcp, val) _percpu_xchg(pcp, val) + #include <asm-generic/percpu.h> #endif /* __ASM_PERCPU_H */ diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h index d5bed02073d6..e20df38a8ff3 100644 --- a/arch/arm64/include/asm/pgalloc.h +++ b/arch/arm64/include/asm/pgalloc.h @@ -26,11 +26,13 @@ #define check_pgt_cache() do { } while (0) +#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) + #if CONFIG_ARM64_PGTABLE_LEVELS > 2 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) { - return (pmd_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT); + return (pmd_t *)__get_free_page(PGALLOC_GFP); } static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) @@ -50,7 +52,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) { - return (pud_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT); + return (pud_t *)__get_free_page(PGALLOC_GFP); } static inline void pud_free(struct mm_struct *mm, pud_t *pud) @@ -69,8 +71,6 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) extern pgd_t *pgd_alloc(struct mm_struct *mm); extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); -#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) - static inline pte_t * pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) { diff --git a/arch/arm64/include/asm/seccomp.h b/arch/arm64/include/asm/seccomp.h new file mode 100644 index 000000000000..c76fac979629 --- /dev/null +++ b/arch/arm64/include/asm/seccomp.h @@ -0,0 +1,25 @@ +/* + * arch/arm64/include/asm/seccomp.h + * + * Copyright (C) 2014 Linaro Limited + * Author: AKASHI Takahiro <takahiro.akashi@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H + +#include <asm/unistd.h> + +#ifdef CONFIG_COMPAT +#define __NR_seccomp_read_32 __NR_compat_read +#define __NR_seccomp_write_32 __NR_compat_write +#define __NR_seccomp_exit_32 __NR_compat_exit +#define __NR_seccomp_sigreturn_32 __NR_compat_rt_sigreturn +#endif /* CONFIG_COMPAT */ + +#include <asm-generic/seccomp.h> + +#endif /* _ASM_SECCOMP_H */ diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h index a82c0c5c8b52..c028fe37456f 100644 --- a/arch/arm64/include/asm/tlb.h +++ b/arch/arm64/include/asm/tlb.h @@ -19,10 +19,6 @@ #ifndef __ASM_TLB_H #define __ASM_TLB_H -#define __tlb_remove_pmd_tlb_entry __tlb_remove_pmd_tlb_entry - -#include <asm-generic/tlb.h> - #include <linux/pagemap.h> #include <linux/swap.h> @@ -37,71 +33,22 @@ static inline void __tlb_remove_table(void *_table) #define tlb_remove_entry(tlb, entry) tlb_remove_page(tlb, entry) #endif /* CONFIG_HAVE_RCU_TABLE_FREE */ -/* - * There's three ways the TLB shootdown code is used: - * 1. Unmapping a range of vmas. See zap_page_range(), unmap_region(). - * tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called. - * 2. Unmapping all vmas. See exit_mmap(). - * tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called. - * Page tables will be freed. - * 3. Unmapping argument pages. See shift_arg_pages(). - * tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called. - */ +#include <asm-generic/tlb.h> + static inline void tlb_flush(struct mmu_gather *tlb) { if (tlb->fullmm) { flush_tlb_mm(tlb->mm); - } else if (tlb->end > 0) { + } else { struct vm_area_struct vma = { .vm_mm = tlb->mm, }; flush_tlb_range(&vma, tlb->start, tlb->end); - tlb->start = TASK_SIZE; - tlb->end = 0; - } -} - -static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr) -{ - if (!tlb->fullmm) { - tlb->start = min(tlb->start, addr); - tlb->end = max(tlb->end, addr + PAGE_SIZE); - } -} - -/* - * Memorize the range for the TLB flush. - */ -static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, - unsigned long addr) -{ - tlb_add_flush(tlb, addr); -} - -/* - * In the case of tlb vma handling, we can optimise these away in the - * case where we're doing a full MM flush. When we're doing a munmap, - * the vmas are adjusted to only cover the region to be torn down. - */ -static inline void tlb_start_vma(struct mmu_gather *tlb, - struct vm_area_struct *vma) -{ - if (!tlb->fullmm) { - tlb->start = TASK_SIZE; - tlb->end = 0; } } -static inline void tlb_end_vma(struct mmu_gather *tlb, - struct vm_area_struct *vma) -{ - if (!tlb->fullmm) - tlb_flush(tlb); -} - static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, unsigned long addr) { pgtable_page_dtor(pte); - tlb_add_flush(tlb, addr); tlb_remove_entry(tlb, pte); } @@ -109,7 +56,6 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr) { - tlb_add_flush(tlb, addr); tlb_remove_entry(tlb, virt_to_page(pmdp)); } #endif @@ -118,15 +64,8 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp, unsigned long addr) { - tlb_add_flush(tlb, addr); tlb_remove_entry(tlb, virt_to_page(pudp)); } #endif -static inline void __tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, - unsigned long address) -{ - tlb_add_flush(tlb, address); -} - #endif diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index 10ca8ff93cc2..232e4ba5d314 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -18,6 +18,22 @@ #ifndef __ASM_TRAP_H #define __ASM_TRAP_H +#include <linux/list.h> + +struct pt_regs; + +struct undef_hook { + struct list_head node; + u32 instr_mask; + u32 instr_val; + u64 pstate_mask; + u64 pstate_val; + int (*fn)(struct pt_regs *regs, u32 instr); +}; + +void register_undef_hook(struct undef_hook *hook); +void unregister_undef_hook(struct undef_hook *hook); + static inline int in_exception_text(unsigned long ptr) { extern char __exception_text_start[]; diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 6d2bf419431d..49c9aefd24a5 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -31,6 +31,9 @@ * Compat syscall numbers used by the AArch64 kernel. */ #define __NR_compat_restart_syscall 0 +#define __NR_compat_exit 1 +#define __NR_compat_read 3 +#define __NR_compat_write 4 #define __NR_compat_sigreturn 119 #define __NR_compat_rt_sigreturn 173 diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index da1f06b535e3..8893cebcea5b 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -787,8 +787,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr) __SYSCALL(__NR_sched_getattr, sys_sched_getattr) #define __NR_renameat2 382 __SYSCALL(__NR_renameat2, sys_renameat2) - /* 383 for seccomp */ +#define __NR_seccomp 383 +__SYSCALL(__NR_seccomp, sys_seccomp) #define __NR_getrandom 384 __SYSCALL(__NR_getrandom, sys_getrandom) #define __NR_memfd_create 385 __SYSCALL(__NR_memfd_create, sys_memfd_create) +#define __NR_bpf 386 +__SYSCALL(__NR_bpf, sys_bpf) diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 5bd029b43644..eaa77ed7766a 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -5,6 +5,7 @@ CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) +CFLAGS_armv8_deprecated.o := -I$(src) CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_insn.o = -pg @@ -15,10 +16,11 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ entry-fpsimd.o process.o ptrace.o setup.o signal.o \ sys.o stacktrace.o time.o traps.o io.o vdso.o \ hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \ - cpuinfo.o + cpuinfo.o cpu_errata.o alternative.o arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ - sys_compat.o + sys_compat.o \ + ../../arm/kernel/opcodes.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o @@ -31,6 +33,7 @@ arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o arm64-obj-$(CONFIG_KGDB) += kgdb.o arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o arm64-obj-$(CONFIG_PCI) += pci.o +arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c new file mode 100644 index 000000000000..ad7821d64a1d --- /dev/null +++ b/arch/arm64/kernel/alternative.c @@ -0,0 +1,85 @@ +/* + * alternative runtime patching + * inspired by the x86 version + * + * Copyright (C) 2014 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "alternatives: " fmt + +#include <linux/init.h> +#include <linux/cpu.h> +#include <asm/cacheflush.h> +#include <asm/alternative.h> +#include <asm/cpufeature.h> +#include <linux/stop_machine.h> + +extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; + +struct alt_region { + struct alt_instr *begin; + struct alt_instr *end; +}; + +static int __apply_alternatives(void *alt_region) +{ + struct alt_instr *alt; + struct alt_region *region = alt_region; + u8 *origptr, *replptr; + + for (alt = region->begin; alt < region->end; alt++) { + if (!cpus_have_cap(alt->cpufeature)) + continue; + + BUG_ON(alt->alt_len > alt->orig_len); + + pr_info_once("patching kernel code\n"); + + origptr = (u8 *)&alt->orig_offset + alt->orig_offset; + replptr = (u8 *)&alt->alt_offset + alt->alt_offset; + memcpy(origptr, replptr, alt->alt_len); + flush_icache_range((uintptr_t)origptr, + (uintptr_t)(origptr + alt->alt_len)); + } + + return 0; +} + +void apply_alternatives_all(void) +{ + struct alt_region region = { + .begin = __alt_instructions, + .end = __alt_instructions_end, + }; + + /* better not try code patching on a live SMP system */ + stop_machine(__apply_alternatives, ®ion, NULL); +} + +void apply_alternatives(void *start, size_t length) +{ + struct alt_region region = { + .begin = start, + .end = start + length, + }; + + __apply_alternatives(®ion); +} + +void free_alternatives_memory(void) +{ + free_reserved_area(__alt_instructions, __alt_instructions_end, + 0, "alternatives"); +} diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c new file mode 100644 index 000000000000..c363671d7509 --- /dev/null +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -0,0 +1,553 @@ +/* + * Copyright (C) 2014 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/cpu.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/perf_event.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/sysctl.h> + +#include <asm/insn.h> +#include <asm/opcodes.h> +#include <asm/system_misc.h> +#include <asm/traps.h> +#include <asm/uaccess.h> + +#define CREATE_TRACE_POINTS +#include "trace-events-emulation.h" + +/* + * The runtime support for deprecated instruction support can be in one of + * following three states - + * + * 0 = undef + * 1 = emulate (software emulation) + * 2 = hw (supported in hardware) + */ +enum insn_emulation_mode { + INSN_UNDEF, + INSN_EMULATE, + INSN_HW, +}; + +enum legacy_insn_status { + INSN_DEPRECATED, + INSN_OBSOLETE, +}; + +struct insn_emulation_ops { + const char *name; + enum legacy_insn_status status; + struct undef_hook *hooks; + int (*set_hw_mode)(bool enable); +}; + +struct insn_emulation { + struct list_head node; + struct insn_emulation_ops *ops; + int current_mode; + int min; + int max; +}; + +static LIST_HEAD(insn_emulation); +static int nr_insn_emulated; +static DEFINE_RAW_SPINLOCK(insn_emulation_lock); + +static void register_emulation_hooks(struct insn_emulation_ops *ops) +{ + struct undef_hook *hook; + + BUG_ON(!ops->hooks); + + for (hook = ops->hooks; hook->instr_mask; hook++) + register_undef_hook(hook); + + pr_notice("Registered %s emulation handler\n", ops->name); +} + +static void remove_emulation_hooks(struct insn_emulation_ops *ops) +{ + struct undef_hook *hook; + + BUG_ON(!ops->hooks); + + for (hook = ops->hooks; hook->instr_mask; hook++) + unregister_undef_hook(hook); + + pr_notice("Removed %s emulation handler\n", ops->name); +} + +static int update_insn_emulation_mode(struct insn_emulation *insn, + enum insn_emulation_mode prev) +{ + int ret = 0; + + switch (prev) { + case INSN_UNDEF: /* Nothing to be done */ + break; + case INSN_EMULATE: + remove_emulation_hooks(insn->ops); + break; + case INSN_HW: + if (insn->ops->set_hw_mode) { + insn->ops->set_hw_mode(false); + pr_notice("Disabled %s support\n", insn->ops->name); + } + break; + } + + switch (insn->current_mode) { + case INSN_UNDEF: + break; + case INSN_EMULATE: + register_emulation_hooks(insn->ops); + break; + case INSN_HW: + if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) + pr_notice("Enabled %s support\n", insn->ops->name); + else + ret = -EINVAL; + break; + } + + return ret; +} + +static void register_insn_emulation(struct insn_emulation_ops *ops) +{ + unsigned long flags; + struct insn_emulation *insn; + + insn = kzalloc(sizeof(*insn), GFP_KERNEL); + insn->ops = ops; + insn->min = INSN_UNDEF; + + switch (ops->status) { + case INSN_DEPRECATED: + insn->current_mode = INSN_EMULATE; + insn->max = INSN_HW; + break; + case INSN_OBSOLETE: + insn->current_mode = INSN_UNDEF; + insn->max = INSN_EMULATE; + break; + } + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_add(&insn->node, &insn_emulation); + nr_insn_emulated++; + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + + /* Register any handlers if required */ + update_insn_emulation_mode(insn, INSN_UNDEF); +} + +static int emulation_proc_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int ret = 0; + struct insn_emulation *insn = (struct insn_emulation *) table->data; + enum insn_emulation_mode prev_mode = insn->current_mode; + + table->data = &insn->current_mode; + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + + if (ret || !write || prev_mode == insn->current_mode) + goto ret; + + ret = update_insn_emulation_mode(insn, prev_mode); + if (ret) { + /* Mode change failed, revert to previous mode. */ + insn->current_mode = prev_mode; + update_insn_emulation_mode(insn, INSN_UNDEF); + } +ret: + table->data = insn; + return ret; +} + +static struct ctl_table ctl_abi[] = { + { + .procname = "abi", + .mode = 0555, + }, + { } +}; + +static void register_insn_emulation_sysctl(struct ctl_table *table) +{ + unsigned long flags; + int i = 0; + struct insn_emulation *insn; + struct ctl_table *insns_sysctl, *sysctl; + + insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1), + GFP_KERNEL); + + raw_spin_lock_irqsave(&insn_emulation_lock, flags); + list_for_each_entry(insn, &insn_emulation, node) { + sysctl = &insns_sysctl[i]; + + sysctl->mode = 0644; + sysctl->maxlen = sizeof(int); + + sysctl->procname = insn->ops->name; + sysctl->data = insn; + sysctl->extra1 = &insn->min; + sysctl->extra2 = &insn->max; + sysctl->proc_handler = emulation_proc_handler; + i++; + } + raw_spin_unlock_irqrestore(&insn_emulation_lock, flags); + + table->child = insns_sysctl; + register_sysctl_table(table); +} + +/* + * Implement emulation of the SWP/SWPB instructions using load-exclusive and + * store-exclusive. + * + * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>] + * Where: Rt = destination + * Rt2 = source + * Rn = address + */ + +/* + * Error-checking SWP macros implemented using ldxr{b}/stxr{b} + */ +#define __user_swpX_asm(data, addr, res, temp, B) \ + __asm__ __volatile__( \ + " mov %w2, %w1\n" \ + "0: ldxr"B" %w1, [%3]\n" \ + "1: stxr"B" %w0, %w2, [%3]\n" \ + " cbz %w0, 2f\n" \ + " mov %w0, %w4\n" \ + "2:\n" \ + " .pushsection .fixup,\"ax\"\n" \ + " .align 2\n" \ + "3: mov %w0, %w5\n" \ + " b 2b\n" \ + " .popsection" \ + " .pushsection __ex_table,\"a\"\n" \ + " .align 3\n" \ + " .quad 0b, 3b\n" \ + " .quad 1b, 3b\n" \ + " .popsection" \ + : "=&r" (res), "+r" (data), "=&r" (temp) \ + : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ + : "memory") + +#define __user_swp_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "") +#define __user_swpb_asm(data, addr, res, temp) \ + __user_swpX_asm(data, addr, res, temp, "b") + +/* + * Bit 22 of the instruction encoding distinguishes between + * the SWP and SWPB variants (bit set means SWPB). + */ +#define TYPE_SWPB (1 << 22) + +/* + * Set up process info to signal segmentation fault - called on access error. + */ +static void set_segfault(struct pt_regs *regs, unsigned long addr) +{ + siginfo_t info; + + down_read(¤t->mm->mmap_sem); + if (find_vma(current->mm, addr) == NULL) + info.si_code = SEGV_MAPERR; + else + info.si_code = SEGV_ACCERR; + up_read(¤t->mm->mmap_sem); + + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_addr = (void *) instruction_pointer(regs); + + pr_debug("SWP{B} emulation: access caused memory abort!\n"); + arm64_notify_die("Illegal memory access", regs, &info, 0); +} + +static int emulate_swpX(unsigned int address, unsigned int *data, + unsigned int type) +{ + unsigned int res = 0; + + if ((type != TYPE_SWPB) && (address & 0x3)) { + /* SWP to unaligned address not permitted */ + pr_debug("SWP instruction on unaligned pointer!\n"); + return -EFAULT; + } + + while (1) { + unsigned long temp; + + if (type == TYPE_SWPB) + __user_swpb_asm(*data, address, res, temp); + else + __user_swp_asm(*data, address, res, temp); + + if (likely(res != -EAGAIN) || signal_pending(current)) + break; + + cond_resched(); + } + + return res; +} + +/* + * swp_handler logs the id of calling process, dissects the instruction, sanity + * checks the memory location, calls emulate_swpX for the actual operation and + * deals with fixup/error handling before returning + */ +static int swp_handler(struct pt_regs *regs, u32 instr) +{ + u32 destreg, data, type, address = 0; + int rn, rt2, res = 0; + + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + type = instr & TYPE_SWPB; + + switch (arm_check_condition(instr, regs->pstate)) { + case ARM_OPCODE_CONDTEST_PASS: + break; + case ARM_OPCODE_CONDTEST_FAIL: + /* Condition failed - return to next instruction */ + goto ret; + case ARM_OPCODE_CONDTEST_UNCOND: + /* If unconditional encoding - not a SWP, undef */ + return -EFAULT; + default: + return -EINVAL; + } + + rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET); + rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET); + + address = (u32)regs->user_regs.regs[rn]; + data = (u32)regs->user_regs.regs[rt2]; + destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET); + + pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n", + rn, address, destreg, + aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data); + + /* Check access in reasonable access range for both SWP and SWPB */ + if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { + pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", + address); + goto fault; + } + + res = emulate_swpX(address, &data, type); + if (res == -EFAULT) + goto fault; + else if (res == 0) + regs->user_regs.regs[destreg] = data; + +ret: + if (type == TYPE_SWPB) + trace_instruction_emulation("swpb", regs->pc); + else + trace_instruction_emulation("swp", regs->pc); + + pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + regs->pc += 4; + return 0; + +fault: + set_segfault(regs, address); + + return 0; +} + +/* + * Only emulate SWP/SWPB executed in ARM state/User mode. + * The kernel must be SWP free and SWP{B} does not exist in Thumb. + */ +static struct undef_hook swp_hooks[] = { + { + .instr_mask = 0x0fb00ff0, + .instr_val = 0x01000090, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = swp_handler + }, + { } +}; + +static struct insn_emulation_ops swp_ops = { + .name = "swp", + .status = INSN_OBSOLETE, + .hooks = swp_hooks, + .set_hw_mode = NULL, +}; + +static int cp15barrier_handler(struct pt_regs *regs, u32 instr) +{ + perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); + + switch (arm_check_condition(instr, regs->pstate)) { + case ARM_OPCODE_CONDTEST_PASS: + break; + case ARM_OPCODE_CONDTEST_FAIL: + /* Condition failed - return to next instruction */ + goto ret; + case ARM_OPCODE_CONDTEST_UNCOND: + /* If unconditional encoding - not a barrier instruction */ + return -EFAULT; + default: + return -EINVAL; + } + + switch (aarch32_insn_mcr_extract_crm(instr)) { + case 10: + /* + * dmb - mcr p15, 0, Rt, c7, c10, 5 + * dsb - mcr p15, 0, Rt, c7, c10, 4 + */ + if (aarch32_insn_mcr_extract_opc2(instr) == 5) { + dmb(sy); + trace_instruction_emulation( + "mcr p15, 0, Rt, c7, c10, 5 ; dmb", regs->pc); + } else { + dsb(sy); + trace_instruction_emulation( + "mcr p15, 0, Rt, c7, c10, 4 ; dsb", regs->pc); + } + break; + case 5: + /* + * isb - mcr p15, 0, Rt, c7, c5, 4 + * + * Taking an exception or returning from one acts as an + * instruction barrier. So no explicit barrier needed here. + */ + trace_instruction_emulation( + "mcr p15, 0, Rt, c7, c5, 4 ; isb", regs->pc); + break; + } + +ret: + pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n", + current->comm, (unsigned long)current->pid, regs->pc); + + regs->pc += 4; + return 0; +} + +#define SCTLR_EL1_CP15BEN (1 << 5) + +static inline void config_sctlr_el1(u32 clear, u32 set) +{ + u32 val; + + asm volatile("mrs %0, sctlr_el1" : "=r" (val)); + val &= ~clear; + val |= set; + asm volatile("msr sctlr_el1, %0" : : "r" (val)); +} + +static void enable_cp15_ben(void *info) +{ + config_sctlr_el1(0, SCTLR_EL1_CP15BEN); +} + +static void disable_cp15_ben(void *info) +{ + config_sctlr_el1(SCTLR_EL1_CP15BEN, 0); +} + +static int cpu_hotplug_notify(struct notifier_block *b, + unsigned long action, void *hcpu) +{ + switch (action) { + case CPU_STARTING: + case CPU_STARTING_FROZEN: + enable_cp15_ben(NULL); + return NOTIFY_DONE; + case CPU_DYING: + case CPU_DYING_FROZEN: + disable_cp15_ben(NULL); + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +static struct notifier_block cpu_hotplug_notifier = { + .notifier_call = cpu_hotplug_notify, +}; + +static int cp15_barrier_set_hw_mode(bool enable) +{ + if (enable) { + register_cpu_notifier(&cpu_hotplug_notifier); + on_each_cpu(enable_cp15_ben, NULL, true); + } else { + unregister_cpu_notifier(&cpu_hotplug_notifier); + on_each_cpu(disable_cp15_ben, NULL, true); + } + + return true; +} + +static struct undef_hook cp15_barrier_hooks[] = { + { + .instr_mask = 0x0fff0fdf, + .instr_val = 0x0e070f9a, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = cp15barrier_handler, + }, + { + .instr_mask = 0x0fff0fff, + .instr_val = 0x0e070f95, + .pstate_mask = COMPAT_PSR_MODE_MASK, + .pstate_val = COMPAT_PSR_MODE_USR, + .fn = cp15barrier_handler, + }, + { } +}; + +static struct insn_emulation_ops cp15_barrier_ops = { + .name = "cp15_barrier", + .status = INSN_DEPRECATED, + .hooks = cp15_barrier_hooks, + .set_hw_mode = cp15_barrier_set_hw_mode, +}; + +/* + * Invoked as late_initcall, since not needed before init spawned. + */ +static int __init armv8_deprecated_init(void) +{ + if (IS_ENABLED(CONFIG_SWP_EMULATION)) + register_insn_emulation(&swp_ops); + + if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) + register_insn_emulation(&cp15_barrier_ops); + + register_insn_emulation_sysctl(ctl_abi); + + return 0; +} + +late_initcall(armv8_deprecated_init); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c new file mode 100644 index 000000000000..fa62637e63a8 --- /dev/null +++ b/arch/arm64/kernel/cpu_errata.c @@ -0,0 +1,111 @@ +/* + * Contains CPU specific errata definitions + * + * Copyright (C) 2014 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "alternatives: " fmt + +#include <linux/types.h> +#include <asm/cpu.h> +#include <asm/cputype.h> +#include <asm/cpufeature.h> + +#define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) +#define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) + +/* + * Add a struct or another datatype to the union below if you need + * different means to detect an affected CPU. + */ +struct arm64_cpu_capabilities { + const char *desc; + u16 capability; + bool (*is_affected)(struct arm64_cpu_capabilities *); + union { + struct { + u32 midr_model; + u32 midr_range_min, midr_range_max; + }; + }; +}; + +#define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \ + MIDR_ARCHITECTURE_MASK) + +static bool __maybe_unused +is_affected_midr_range(struct arm64_cpu_capabilities *entry) +{ + u32 midr = read_cpuid_id(); + + if ((midr & CPU_MODEL_MASK) != entry->midr_model) + return false; + + midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK; + + return (midr >= entry->midr_range_min && midr <= entry->midr_range_max); +} + +#define MIDR_RANGE(model, min, max) \ + .is_affected = is_affected_midr_range, \ + .midr_model = model, \ + .midr_range_min = min, \ + .midr_range_max = max + +struct arm64_cpu_capabilities arm64_errata[] = { +#if defined(CONFIG_ARM64_ERRATUM_826319) || \ + defined(CONFIG_ARM64_ERRATUM_827319) || \ + defined(CONFIG_ARM64_ERRATUM_824069) + { + /* Cortex-A53 r0p[012] */ + .desc = "ARM errata 826319, 827319, 824069", + .capability = ARM64_WORKAROUND_CLEAN_CACHE, + MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x02), + }, +#endif +#ifdef CONFIG_ARM64_ERRATUM_819472 + { + /* Cortex-A53 r0p[01] */ + .desc = "ARM errata 819472", + .capability = ARM64_WORKAROUND_CLEAN_CACHE, + MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x01), + }, +#endif +#ifdef CONFIG_ARM64_ERRATUM_832075 + { + /* Cortex-A57 r0p0 - r1p2 */ + .desc = "ARM erratum 832075", + .capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE, + MIDR_RANGE(MIDR_CORTEX_A57, 0x00, 0x12), + }, +#endif + { + } +}; + +void check_local_cpu_errata(void) +{ + struct arm64_cpu_capabilities *cpus = arm64_errata; + int i; + + for (i = 0; cpus[i].desc; i++) { + if (!cpus[i].is_affected(&cpus[i])) + continue; + + if (!cpus_have_cap(cpus[i].capability)) + pr_info("enabling workaround for %s\n", cpus[i].desc); + cpus_set_cap(cpus[i].capability); + } +} diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 504fdaa8367e..57b641747534 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -18,6 +18,7 @@ #include <asm/cachetype.h> #include <asm/cpu.h> #include <asm/cputype.h> +#include <asm/cpufeature.h> #include <linux/bitops.h> #include <linux/bug.h> @@ -111,6 +112,15 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur) diff |= CHECK(cntfrq, boot, cur, cpu); /* + * The kernel uses self-hosted debug features and expects CPUs to + * support identical debug features. We presently need CTX_CMPs, WRPs, + * and BRPs to be identical. + * ID_AA64DFR1 is currently RES0. + */ + diff |= CHECK(id_aa64dfr0, boot, cur, cpu); + diff |= CHECK(id_aa64dfr1, boot, cur, cpu); + + /* * Even in big.LITTLE, processors should be identical instruction-set * wise. */ @@ -143,7 +153,12 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur) diff |= CHECK(id_isar3, boot, cur, cpu); diff |= CHECK(id_isar4, boot, cur, cpu); diff |= CHECK(id_isar5, boot, cur, cpu); - diff |= CHECK(id_mmfr0, boot, cur, cpu); + /* + * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and + * ACTLR formats could differ across CPUs and therefore would have to + * be trapped for virtualization anyway. + */ + diff |= CHECK_MASK(id_mmfr0, 0xff0fffff, boot, cur, cpu); diff |= CHECK(id_mmfr1, boot, cur, cpu); diff |= CHECK(id_mmfr2, boot, cur, cpu); diff |= CHECK(id_mmfr3, boot, cur, cpu); @@ -155,7 +170,7 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur) * pretend to support them. */ WARN_TAINT_ONCE(diff, TAINT_CPU_OUT_OF_SPEC, - "Unsupported CPU feature variation."); + "Unsupported CPU feature variation.\n"); } static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) @@ -165,6 +180,8 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) info->reg_dczid = read_cpuid(DCZID_EL0); info->reg_midr = read_cpuid_id(); + info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1); + info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1); info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1); info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1); info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1); @@ -186,6 +203,8 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1); cpuinfo_detect_icache_policy(info); + + check_local_cpu_errata(); } void cpuinfo_store_cpu(void) diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S index 619b1dd7bcde..8ce9b0577442 100644 --- a/arch/arm64/kernel/efi-entry.S +++ b/arch/arm64/kernel/efi-entry.S @@ -54,18 +54,18 @@ ENTRY(efi_stub_entry) b.eq efi_load_fail /* - * efi_entry() will have relocated the kernel image if necessary - * and we return here with device tree address in x0 and the kernel - * entry point stored at *image_addr. Save those values in registers - * which are callee preserved. + * efi_entry() will have copied the kernel image if necessary and we + * return here with device tree address in x0 and the kernel entry + * point stored at *image_addr. Save those values in registers which + * are callee preserved. */ mov x20, x0 // DTB address ldr x0, [sp, #16] // relocated _text address - mov x21, x0 + ldr x21, =stext_offset + add x21, x0, x21 /* - * Flush dcache covering current runtime addresses - * of kernel text/data. Then flush all of icache. + * Calculate size of the kernel Image (same for original and copy). */ adrp x1, _text add x1, x1, #:lo12:_text @@ -73,9 +73,24 @@ ENTRY(efi_stub_entry) add x2, x2, #:lo12:_edata sub x1, x2, x1 + /* + * Flush the copied Image to the PoC, and ensure it is not shadowed by + * stale icache entries from before relocation. + */ bl __flush_dcache_area ic ialluis + /* + * Ensure that the rest of this function (in the original Image) is + * visible when the caches are disabled. The I-cache can't have stale + * entries for the VA range of the current image, so no maintenance is + * necessary. + */ + adr x0, efi_stub_entry + adr x1, efi_stub_entry_end + sub x1, x1, x0 + bl __flush_dcache_area + /* Turn off Dcache and MMU */ mrs x0, CurrentEL cmp x0, #CurrentEL_EL2 @@ -105,4 +120,5 @@ efi_load_fail: ldp x29, x30, [sp], #32 ret +efi_stub_entry_end: ENDPROC(efi_stub_entry) diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 95c49ebc660d..6fac253bc783 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -11,6 +11,7 @@ * */ +#include <linux/dmi.h> #include <linux/efi.h> #include <linux/export.h> #include <linux/memblock.h> @@ -112,8 +113,6 @@ static int __init uefi_init(void) efi.systab->hdr.revision & 0xffff, vendor); retval = efi_config_init(NULL); - if (retval == 0) - set_bit(EFI_CONFIG_TABLES, &efi.flags); out: early_memunmap(efi.systab, sizeof(efi_system_table_t)); @@ -125,17 +124,17 @@ out: */ static __init int is_reserve_region(efi_memory_desc_t *md) { - if (!is_normal_ram(md)) + switch (md->type) { + case EFI_LOADER_CODE: + case EFI_LOADER_DATA: + case EFI_BOOT_SERVICES_CODE: + case EFI_BOOT_SERVICES_DATA: + case EFI_CONVENTIONAL_MEMORY: return 0; - - if (md->attribute & EFI_MEMORY_RUNTIME) - return 1; - - if (md->type == EFI_ACPI_RECLAIM_MEMORY || - md->type == EFI_RESERVED_TYPE) - return 1; - - return 0; + default: + break; + } + return is_normal_ram(md); } static __init void reserve_regions(void) @@ -471,3 +470,17 @@ err_unmap: return -1; } early_initcall(arm64_enter_virtual_mode); + +static int __init arm64_dmi_init(void) +{ + /* + * On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to + * be called early because dmi_id_init(), which is an arch_initcall + * itself, depends on dmi_scan_machine() having been called already. + */ + dmi_scan_machine(); + if (dmi_available) + dmi_set_dump_stack_arch_desc(); + return 0; +} +core_initcall(arm64_dmi_init); diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S index 38e704e597f7..08cafc518b9a 100644 --- a/arch/arm64/kernel/entry-ftrace.S +++ b/arch/arm64/kernel/entry-ftrace.S @@ -98,8 +98,8 @@ ENTRY(_mcount) mcount_enter - ldr x0, =ftrace_trace_function - ldr x2, [x0] + adrp x0, ftrace_trace_function + ldr x2, [x0, #:lo12:ftrace_trace_function] adr x0, ftrace_stub cmp x0, x2 // if (ftrace_trace_function b.eq skip_ftrace_call // != ftrace_stub) { @@ -115,14 +115,15 @@ skip_ftrace_call: // return; mcount_exit // return; // } skip_ftrace_call: - ldr x1, =ftrace_graph_return - ldr x2, [x1] // if ((ftrace_graph_return - cmp x0, x2 // != ftrace_stub) - b.ne ftrace_graph_caller - - ldr x1, =ftrace_graph_entry // || (ftrace_graph_entry - ldr x2, [x1] // != ftrace_graph_entry_stub)) - ldr x0, =ftrace_graph_entry_stub + adrp x1, ftrace_graph_return + ldr x2, [x1, #:lo12:ftrace_graph_return] + cmp x0, x2 // if ((ftrace_graph_return + b.ne ftrace_graph_caller // != ftrace_stub) + + adrp x1, ftrace_graph_entry // || (ftrace_graph_entry + adrp x0, ftrace_graph_entry_stub // != ftrace_graph_entry_stub)) + ldr x2, [x1, #:lo12:ftrace_graph_entry] + add x0, x0, #:lo12:ftrace_graph_entry_stub cmp x0, x2 b.ne ftrace_graph_caller // ftrace_graph_caller(); diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 726b910fe6ec..fd4fa374e5d2 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -64,25 +64,26 @@ #define BAD_ERROR 3 .macro kernel_entry, el, regsize = 64 - sub sp, sp, #S_FRAME_SIZE - S_LR // room for LR, SP, SPSR, ELR + sub sp, sp, #S_FRAME_SIZE .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0 .endif - push x28, x29 - push x26, x27 - push x24, x25 - push x22, x23 - push x20, x21 - push x18, x19 - push x16, x17 - push x14, x15 - push x12, x13 - push x10, x11 - push x8, x9 - push x6, x7 - push x4, x5 - push x2, x3 - push x0, x1 + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + .if \el == 0 mrs x21, sp_el0 get_thread_info tsk // Ensure MDSCR_EL1.SS is clear, @@ -118,33 +119,31 @@ .if \el == 0 ct_user_enter ldr x23, [sp, #S_SP] // load return stack pointer + msr sp_el0, x23 .endif + msr elr_el1, x21 // set up the return data + msr spsr_el1, x22 .if \ret ldr x1, [sp, #S_X1] // preserve x0 (syscall return) - add sp, sp, S_X2 .else - pop x0, x1 + ldp x0, x1, [sp, #16 * 0] .endif - pop x2, x3 // load the rest of the registers - pop x4, x5 - pop x6, x7 - pop x8, x9 - msr elr_el1, x21 // set up the return data - msr spsr_el1, x22 - .if \el == 0 - msr sp_el0, x23 - .endif - pop x10, x11 - pop x12, x13 - pop x14, x15 - pop x16, x17 - pop x18, x19 - pop x20, x21 - pop x22, x23 - pop x24, x25 - pop x26, x27 - pop x28, x29 - ldr lr, [sp], #S_FRAME_SIZE - S_LR // load LR and restore SP + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + ldr lr, [sp, #S_LR] + add sp, sp, #S_FRAME_SIZE // restore sp eret // return to kernel .endm @@ -168,7 +167,8 @@ tsk .req x28 // current thread_info * Interrupt handling. */ .macro irq_handler - ldr x1, handle_arch_irq + adrp x1, handle_arch_irq + ldr x1, [x1, #:lo12:handle_arch_irq] mov x0, sp blr x1 .endm @@ -455,8 +455,8 @@ el0_da: bic x0, x26, #(0xff << 56) mov x1, x25 mov x2, sp - adr lr, ret_to_user - b do_mem_abort + bl do_mem_abort + b ret_to_user el0_ia: /* * Instruction abort handling @@ -468,8 +468,8 @@ el0_ia: mov x0, x26 orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts mov x2, sp - adr lr, ret_to_user - b do_mem_abort + bl do_mem_abort + b ret_to_user el0_fpsimd_acc: /* * Floating Point or Advanced SIMD access @@ -478,8 +478,8 @@ el0_fpsimd_acc: ct_user_exit mov x0, x25 mov x1, sp - adr lr, ret_to_user - b do_fpsimd_acc + bl do_fpsimd_acc + b ret_to_user el0_fpsimd_exc: /* * Floating Point or Advanced SIMD exception @@ -488,8 +488,8 @@ el0_fpsimd_exc: ct_user_exit mov x0, x25 mov x1, sp - adr lr, ret_to_user - b do_fpsimd_exc + bl do_fpsimd_exc + b ret_to_user el0_sp_pc: /* * Stack or PC alignment exception handling @@ -500,8 +500,8 @@ el0_sp_pc: mov x0, x26 mov x1, x25 mov x2, sp - adr lr, ret_to_user - b do_sp_pc_abort + bl do_sp_pc_abort + b ret_to_user el0_undef: /* * Undefined instruction @@ -510,8 +510,8 @@ el0_undef: enable_dbg_and_irq ct_user_exit mov x0, sp - adr lr, ret_to_user - b do_undefinstr + bl do_undefinstr + b ret_to_user el0_dbg: /* * Debug exception handling @@ -530,8 +530,8 @@ el0_inv: mov x0, sp mov x1, #BAD_SYNC mrs x2, esr_el1 - adr lr, ret_to_user - b bad_mode + bl bad_mode + b ret_to_user ENDPROC(el0_sync) .align 6 @@ -653,14 +653,15 @@ el0_svc_naked: // compat entry point ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks tst x16, #_TIF_SYSCALL_WORK b.ne __sys_trace - adr lr, ret_fast_syscall // return address cmp scno, sc_nr // check upper syscall limit b.hs ni_sys ldr x16, [stbl, scno, lsl #3] // address in the syscall table - br x16 // call sys_* routine + blr x16 // call sys_* routine + b ret_fast_syscall ni_sys: mov x0, sp - b do_ni_syscall + bl do_ni_syscall + b ret_fast_syscall ENDPROC(el0_svc) /* @@ -668,26 +669,38 @@ ENDPROC(el0_svc) * switches, and waiting for our parent to respond. */ __sys_trace: - mov x0, sp + mov w0, #-1 // set default errno for + cmp scno, x0 // user-issued syscall(-1) + b.ne 1f + mov x0, #-ENOSYS + str x0, [sp, #S_X0] +1: mov x0, sp bl syscall_trace_enter - adr lr, __sys_trace_return // return address + cmp w0, #-1 // skip the syscall? + b.eq __sys_trace_return_skipped uxtw scno, w0 // syscall number (possibly new) mov x1, sp // pointer to regs cmp scno, sc_nr // check upper syscall limit - b.hs ni_sys + b.hs __ni_sys_trace ldp x0, x1, [sp] // restore the syscall args ldp x2, x3, [sp, #S_X2] ldp x4, x5, [sp, #S_X4] ldp x6, x7, [sp, #S_X6] ldr x16, [stbl, scno, lsl #3] // address in the syscall table - br x16 // call sys_* routine + blr x16 // call sys_* routine __sys_trace_return: - str x0, [sp] // save returned x0 + str x0, [sp, #S_X0] // save returned x0 +__sys_trace_return_skipped: mov x0, sp bl syscall_trace_exit b ret_to_user +__ni_sys_trace: + mov x0, sp + bl do_ni_syscall + b __sys_trace_return + /* * Special system call wrappers. */ @@ -695,6 +708,3 @@ ENTRY(sys_rt_sigreturn_wrapper) mov x0, sp b sys_rt_sigreturn ENDPROC(sys_rt_sigreturn_wrapper) - -ENTRY(handle_arch_irq) - .quad 0 diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 0a6e4f924df8..8ce88e08c030 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -132,6 +132,8 @@ efi_head: #endif #ifdef CONFIG_EFI + .globl stext_offset + .set stext_offset, stext - efi_head .align 3 pe_header: .ascii "PE" @@ -155,12 +157,12 @@ optional_header: .long 0 // SizeOfInitializedData .long 0 // SizeOfUninitializedData .long efi_stub_entry - efi_head // AddressOfEntryPoint - .long stext - efi_head // BaseOfCode + .long stext_offset // BaseOfCode extra_header_fields: .quad 0 // ImageBase - .long 0x20 // SectionAlignment - .long 0x8 // FileAlignment + .long 0x1000 // SectionAlignment + .long PECOFF_FILE_ALIGNMENT // FileAlignment .short 0 // MajorOperatingSystemVersion .short 0 // MinorOperatingSystemVersion .short 0 // MajorImageVersion @@ -172,7 +174,7 @@ extra_header_fields: .long _end - efi_head // SizeOfImage // Everything before the kernel image is considered part of the header - .long stext - efi_head // SizeOfHeaders + .long stext_offset // SizeOfHeaders .long 0 // CheckSum .short 0xa // Subsystem (EFI application) .short 0 // DllCharacteristics @@ -217,16 +219,24 @@ section_table: .byte 0 .byte 0 // end of 0 padding of section name .long _end - stext // VirtualSize - .long stext - efi_head // VirtualAddress + .long stext_offset // VirtualAddress .long _edata - stext // SizeOfRawData - .long stext - efi_head // PointerToRawData + .long stext_offset // PointerToRawData .long 0 // PointerToRelocations (0 for executables) .long 0 // PointerToLineNumbers (0 for executables) .short 0 // NumberOfRelocations (0 for executables) .short 0 // NumberOfLineNumbers (0 for executables) .long 0xe0500020 // Characteristics (section flags) - .align 5 + + /* + * EFI will load stext onwards at the 4k section alignment + * described in the PE/COFF header. To ensure that instruction + * sequences using an adrp and a :lo12: immediate will function + * correctly at this alignment, we must ensure that stext is + * placed at a 4k boundary in the Image to begin with. + */ + .align 12 #endif ENTRY(stext) @@ -238,7 +248,13 @@ ENTRY(stext) mov x0, x22 bl lookup_processor_type mov x23, x0 // x23=current cpu_table - cbz x23, __error_p // invalid processor (x23=0)? + /* + * __error_p may end up out of range for cbz if text areas are + * aligned up to section sizes. + */ + cbnz x23, 1f // invalid processor (x23=0)? + b __error_p +1: bl __vet_fdt bl __create_page_tables // x25=TTBR0, x26=TTBR1 /* @@ -250,13 +266,214 @@ ENTRY(stext) */ ldr x27, __switch_data // address to jump to after // MMU has been enabled - adr lr, __enable_mmu // return (PIC) address + adrp lr, __enable_mmu // return (PIC) address + add lr, lr, #:lo12:__enable_mmu ldr x12, [x23, #CPU_INFO_SETUP] add x12, x12, x28 // __virt_to_phys br x12 // initialise processor ENDPROC(stext) /* + * Determine validity of the x21 FDT pointer. + * The dtb must be 8-byte aligned and live in the first 512M of memory. + */ +__vet_fdt: + tst x21, #0x7 + b.ne 1f + cmp x21, x24 + b.lt 1f + mov x0, #(1 << 29) + add x0, x0, x24 + cmp x21, x0 + b.ge 1f + ret +1: + mov x21, #0 + ret +ENDPROC(__vet_fdt) +/* + * Macro to create a table entry to the next page. + * + * tbl: page table address + * virt: virtual address + * shift: #imm page table shift + * ptrs: #imm pointers per table page + * + * Preserves: virt + * Corrupts: tmp1, tmp2 + * Returns: tbl -> next level table page address + */ + .macro create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2 + lsr \tmp1, \virt, #\shift + and \tmp1, \tmp1, #\ptrs - 1 // table index + add \tmp2, \tbl, #PAGE_SIZE + orr \tmp2, \tmp2, #PMD_TYPE_TABLE // address of next table and entry type + str \tmp2, [\tbl, \tmp1, lsl #3] + add \tbl, \tbl, #PAGE_SIZE // next level table page + .endm + +/* + * Macro to populate the PGD (and possibily PUD) for the corresponding + * block entry in the next level (tbl) for the given virtual address. + * + * Preserves: tbl, next, virt + * Corrupts: tmp1, tmp2 + */ + .macro create_pgd_entry, tbl, virt, tmp1, tmp2 + create_table_entry \tbl, \virt, PGDIR_SHIFT, PTRS_PER_PGD, \tmp1, \tmp2 +#if SWAPPER_PGTABLE_LEVELS == 3 + create_table_entry \tbl, \virt, TABLE_SHIFT, PTRS_PER_PTE, \tmp1, \tmp2 +#endif + .endm + +/* + * Macro to populate block entries in the page table for the start..end + * virtual range (inclusive). + * + * Preserves: tbl, flags + * Corrupts: phys, start, end, pstate + */ + .macro create_block_map, tbl, flags, phys, start, end + lsr \phys, \phys, #BLOCK_SHIFT + lsr \start, \start, #BLOCK_SHIFT + and \start, \start, #PTRS_PER_PTE - 1 // table index + orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry + lsr \end, \end, #BLOCK_SHIFT + and \end, \end, #PTRS_PER_PTE - 1 // table end index +9999: str \phys, [\tbl, \start, lsl #3] // store the entry + add \start, \start, #1 // next entry + add \phys, \phys, #BLOCK_SIZE // next block + cmp \start, \end + b.ls 9999b + .endm + +/* + * Setup the initial page tables. We only setup the barest amount which is + * required to get the kernel running. The following sections are required: + * - identity mapping to enable the MMU (low address, TTBR0) + * - first few MB of the kernel linear mapping to jump to once the MMU has + * been enabled, including the FDT blob (TTBR1) + * - pgd entry for fixed mappings (TTBR1) + */ +__create_page_tables: + pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses + mov x27, lr + + /* + * Invalidate the idmap and swapper page tables to avoid potential + * dirty cache lines being evicted. + */ + mov x0, x25 + add x1, x26, #SWAPPER_DIR_SIZE + bl __inval_cache_range + + /* + * Clear the idmap and swapper page tables. + */ + mov x0, x25 + add x6, x26, #SWAPPER_DIR_SIZE +1: stp xzr, xzr, [x0], #16 + stp xzr, xzr, [x0], #16 + stp xzr, xzr, [x0], #16 + stp xzr, xzr, [x0], #16 + cmp x0, x6 + b.lo 1b + + ldr x7, =MM_MMUFLAGS + + /* + * Create the identity mapping. + */ + mov x0, x25 // idmap_pg_dir + ldr x3, =KERNEL_START + add x3, x3, x28 // __pa(KERNEL_START) + create_pgd_entry x0, x3, x5, x6 + ldr x6, =KERNEL_END + mov x5, x3 // __pa(KERNEL_START) + add x6, x6, x28 // __pa(KERNEL_END) + create_block_map x0, x7, x3, x5, x6 + + /* + * Map the kernel image (starting with PHYS_OFFSET). + */ + mov x0, x26 // swapper_pg_dir + mov x5, #PAGE_OFFSET + create_pgd_entry x0, x5, x3, x6 + ldr x6, =KERNEL_END + mov x3, x24 // phys offset + create_block_map x0, x7, x3, x5, x6 + + /* + * Map the FDT blob (maximum 2MB; must be within 512MB of + * PHYS_OFFSET). + */ + mov x3, x21 // FDT phys address + and x3, x3, #~((1 << 21) - 1) // 2MB aligned + mov x6, #PAGE_OFFSET + sub x5, x3, x24 // subtract PHYS_OFFSET + tst x5, #~((1 << 29) - 1) // within 512MB? + csel x21, xzr, x21, ne // zero the FDT pointer + b.ne 1f + add x5, x5, x6 // __va(FDT blob) + add x6, x5, #1 << 21 // 2MB for the FDT blob + sub x6, x6, #1 // inclusive range + create_block_map x0, x7, x3, x5, x6 +1: + /* + * Since the page tables have been populated with non-cacheable + * accesses (MMU disabled), invalidate the idmap and swapper page + * tables again to remove any speculatively loaded cache lines. + */ + mov x0, x25 + add x1, x26, #SWAPPER_DIR_SIZE + bl __inval_cache_range + + mov lr, x27 + ret +ENDPROC(__create_page_tables) + .ltorg + + .align 3 + .type __switch_data, %object +__switch_data: + .quad __mmap_switched + .quad __bss_start // x6 + .quad __bss_stop // x7 + .quad processor_id // x4 + .quad __fdt_pointer // x5 + .quad memstart_addr // x6 + .quad init_thread_union + THREAD_START_SP // sp + +/* + * The following fragment of code is executed with the MMU on in MMU mode, and + * uses absolute addresses; this is not position independent. + */ +__mmap_switched: + adr x3, __switch_data + 8 + + ldp x6, x7, [x3], #16 +1: cmp x6, x7 + b.hs 2f + str xzr, [x6], #8 // Clear BSS + b 1b +2: + ldp x4, x5, [x3], #16 + ldr x6, [x3], #8 + ldr x16, [x3] + mov sp, x16 + str x22, [x4] // Save processor ID + str x21, [x5] // Save FDT pointer + str x24, [x6] // Save PHYS_OFFSET + mov x29, #0 + b start_kernel +ENDPROC(__mmap_switched) + +/* + * end early head section, begin head code that is also used for + * hotplug and needs to have the same protections as the text region + */ + .section ".text","ax" +/* * If we're fortunate enough to boot at EL2, ensure that the world is * sane before dropping to EL1. * @@ -331,7 +548,8 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems msr vttbr_el2, xzr /* Hypervisor stub */ - adr x0, __hyp_stub_vectors + adrp x0, __hyp_stub_vectors + add x0, x0, #:lo12:__hyp_stub_vectors msr vbar_el2, x0 /* spsr */ @@ -492,183 +710,6 @@ ENDPROC(__calc_phys_offset) .quad PAGE_OFFSET /* - * Macro to create a table entry to the next page. - * - * tbl: page table address - * virt: virtual address - * shift: #imm page table shift - * ptrs: #imm pointers per table page - * - * Preserves: virt - * Corrupts: tmp1, tmp2 - * Returns: tbl -> next level table page address - */ - .macro create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2 - lsr \tmp1, \virt, #\shift - and \tmp1, \tmp1, #\ptrs - 1 // table index - add \tmp2, \tbl, #PAGE_SIZE - orr \tmp2, \tmp2, #PMD_TYPE_TABLE // address of next table and entry type - str \tmp2, [\tbl, \tmp1, lsl #3] - add \tbl, \tbl, #PAGE_SIZE // next level table page - .endm - -/* - * Macro to populate the PGD (and possibily PUD) for the corresponding - * block entry in the next level (tbl) for the given virtual address. - * - * Preserves: tbl, next, virt - * Corrupts: tmp1, tmp2 - */ - .macro create_pgd_entry, tbl, virt, tmp1, tmp2 - create_table_entry \tbl, \virt, PGDIR_SHIFT, PTRS_PER_PGD, \tmp1, \tmp2 -#if SWAPPER_PGTABLE_LEVELS == 3 - create_table_entry \tbl, \virt, TABLE_SHIFT, PTRS_PER_PTE, \tmp1, \tmp2 -#endif - .endm - -/* - * Macro to populate block entries in the page table for the start..end - * virtual range (inclusive). - * - * Preserves: tbl, flags - * Corrupts: phys, start, end, pstate - */ - .macro create_block_map, tbl, flags, phys, start, end - lsr \phys, \phys, #BLOCK_SHIFT - lsr \start, \start, #BLOCK_SHIFT - and \start, \start, #PTRS_PER_PTE - 1 // table index - orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry - lsr \end, \end, #BLOCK_SHIFT - and \end, \end, #PTRS_PER_PTE - 1 // table end index -9999: str \phys, [\tbl, \start, lsl #3] // store the entry - add \start, \start, #1 // next entry - add \phys, \phys, #BLOCK_SIZE // next block - cmp \start, \end - b.ls 9999b - .endm - -/* - * Setup the initial page tables. We only setup the barest amount which is - * required to get the kernel running. The following sections are required: - * - identity mapping to enable the MMU (low address, TTBR0) - * - first few MB of the kernel linear mapping to jump to once the MMU has - * been enabled, including the FDT blob (TTBR1) - * - pgd entry for fixed mappings (TTBR1) - */ -__create_page_tables: - pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses - mov x27, lr - - /* - * Invalidate the idmap and swapper page tables to avoid potential - * dirty cache lines being evicted. - */ - mov x0, x25 - add x1, x26, #SWAPPER_DIR_SIZE - bl __inval_cache_range - - /* - * Clear the idmap and swapper page tables. - */ - mov x0, x25 - add x6, x26, #SWAPPER_DIR_SIZE -1: stp xzr, xzr, [x0], #16 - stp xzr, xzr, [x0], #16 - stp xzr, xzr, [x0], #16 - stp xzr, xzr, [x0], #16 - cmp x0, x6 - b.lo 1b - - ldr x7, =MM_MMUFLAGS - - /* - * Create the identity mapping. - */ - mov x0, x25 // idmap_pg_dir - ldr x3, =KERNEL_START - add x3, x3, x28 // __pa(KERNEL_START) - create_pgd_entry x0, x3, x5, x6 - ldr x6, =KERNEL_END - mov x5, x3 // __pa(KERNEL_START) - add x6, x6, x28 // __pa(KERNEL_END) - create_block_map x0, x7, x3, x5, x6 - - /* - * Map the kernel image (starting with PHYS_OFFSET). - */ - mov x0, x26 // swapper_pg_dir - mov x5, #PAGE_OFFSET - create_pgd_entry x0, x5, x3, x6 - ldr x6, =KERNEL_END - mov x3, x24 // phys offset - create_block_map x0, x7, x3, x5, x6 - - /* - * Map the FDT blob (maximum 2MB; must be within 512MB of - * PHYS_OFFSET). - */ - mov x3, x21 // FDT phys address - and x3, x3, #~((1 << 21) - 1) // 2MB aligned - mov x6, #PAGE_OFFSET - sub x5, x3, x24 // subtract PHYS_OFFSET - tst x5, #~((1 << 29) - 1) // within 512MB? - csel x21, xzr, x21, ne // zero the FDT pointer - b.ne 1f - add x5, x5, x6 // __va(FDT blob) - add x6, x5, #1 << 21 // 2MB for the FDT blob - sub x6, x6, #1 // inclusive range - create_block_map x0, x7, x3, x5, x6 -1: - /* - * Since the page tables have been populated with non-cacheable - * accesses (MMU disabled), invalidate the idmap and swapper page - * tables again to remove any speculatively loaded cache lines. - */ - mov x0, x25 - add x1, x26, #SWAPPER_DIR_SIZE - bl __inval_cache_range - - mov lr, x27 - ret -ENDPROC(__create_page_tables) - .ltorg - - .align 3 - .type __switch_data, %object -__switch_data: - .quad __mmap_switched - .quad __bss_start // x6 - .quad __bss_stop // x7 - .quad processor_id // x4 - .quad __fdt_pointer // x5 - .quad memstart_addr // x6 - .quad init_thread_union + THREAD_START_SP // sp - -/* - * The following fragment of code is executed with the MMU on in MMU mode, and - * uses absolute addresses; this is not position independent. - */ -__mmap_switched: - adr x3, __switch_data + 8 - - ldp x6, x7, [x3], #16 -1: cmp x6, x7 - b.hs 2f - str xzr, [x6], #8 // Clear BSS - b 1b -2: - ldp x4, x5, [x3], #16 - ldr x6, [x3], #8 - ldr x16, [x3] - mov sp, x16 - str x22, [x4] // Save processor ID - str x21, [x5] // Save FDT pointer - str x24, [x6] // Save PHYS_OFFSET - mov x29, #0 - b start_kernel -ENDPROC(__mmap_switched) - -/* * Exception handling. Something went wrong and we can't proceed. We ought to * tell the user, but since we don't have any guarantee that we're even * running on the right architecture, we do virtually nothing. @@ -715,22 +756,3 @@ __lookup_processor_type_data: .quad . .quad cpu_table .size __lookup_processor_type_data, . - __lookup_processor_type_data - -/* - * Determine validity of the x21 FDT pointer. - * The dtb must be 8-byte aligned and live in the first 512M of memory. - */ -__vet_fdt: - tst x21, #0x7 - b.ne 1f - cmp x21, x24 - b.lt 1f - mov x0, #(1 << 29) - add x0, x0, x24 - cmp x21, x0 - b.ge 1f - ret -1: - mov x21, #0 - ret -ENDPROC(__vet_fdt) diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index e007714ded04..7e9327a0986d 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -163,9 +163,10 @@ static int __kprobes aarch64_insn_patch_text_cb(void *arg) * which ends with "dsb; isb" pair guaranteeing global * visibility. */ - atomic_set(&pp->cpu_count, -1); + /* Notify other processors with an additional increment. */ + atomic_inc(&pp->cpu_count); } else { - while (atomic_read(&pp->cpu_count) != -1) + while (atomic_read(&pp->cpu_count) <= num_online_cpus()) cpu_relax(); isb(); } @@ -959,3 +960,29 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst, return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift); } + +bool aarch32_insn_is_wide(u32 insn) +{ + return insn >= 0xe800; +} + +/* + * Macros/defines for extracting register numbers from instruction. + */ +u32 aarch32_insn_extract_reg_num(u32 insn, int offset) +{ + return (insn & (0xf << offset)) >> offset; +} + +#define OPC2_MASK 0x7 +#define OPC2_OFFSET 5 +u32 aarch32_insn_mcr_extract_opc2(u32 insn) +{ + return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET; +} + +#define CRM_MASK 0xf +u32 aarch32_insn_mcr_extract_crm(u32 insn) +{ + return insn & CRM_MASK; +} diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c index 7d37ead4d199..354be2a872ae 100644 --- a/arch/arm64/kernel/io.c +++ b/arch/arm64/kernel/io.c @@ -25,12 +25,26 @@ */ void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) { - unsigned char *t = to; - while (count) { + while (count && (!IS_ALIGNED((unsigned long)from, 8) || + !IS_ALIGNED((unsigned long)to, 8))) { + *(u8 *)to = __raw_readb(from); + from++; + to++; count--; - *t = readb(from); - t++; + } + + while (count >= 8) { + *(u64 *)to = __raw_readq(from); + from += 8; + to += 8; + count -= 8; + } + + while (count) { + *(u8 *)to = __raw_readb(from); from++; + to++; + count--; } } EXPORT_SYMBOL(__memcpy_fromio); @@ -40,12 +54,26 @@ EXPORT_SYMBOL(__memcpy_fromio); */ void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) { - const unsigned char *f = from; - while (count) { + while (count && (!IS_ALIGNED((unsigned long)to, 8) || + !IS_ALIGNED((unsigned long)from, 8))) { + __raw_writeb(*(volatile u8 *)from, to); + from++; + to++; count--; - writeb(*f, to); - f++; + } + + while (count >= 8) { + __raw_writeq(*(volatile u64 *)from, to); + from += 8; + to += 8; + count -= 8; + } + + while (count) { + __raw_writeb(*(volatile u8 *)from, to); + from++; to++; + count--; } } EXPORT_SYMBOL(__memcpy_toio); @@ -55,10 +83,28 @@ EXPORT_SYMBOL(__memcpy_toio); */ void __memset_io(volatile void __iomem *dst, int c, size_t count) { - while (count) { + u64 qc = (u8)c; + + qc |= qc << 8; + qc |= qc << 16; + qc |= qc << 32; + + while (count && !IS_ALIGNED((unsigned long)dst, 8)) { + __raw_writeb(c, dst); + dst++; count--; - writeb(c, dst); + } + + while (count >= 8) { + __raw_writeq(qc, dst); + dst += 8; + count -= 8; + } + + while (count) { + __raw_writeb(c, dst); dst++; + count--; } } EXPORT_SYMBOL(__memset_io); diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 071a6ec13bd8..240b75c0e94f 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -40,6 +40,8 @@ int arch_show_interrupts(struct seq_file *p, int prec) return 0; } +void (*handle_arch_irq)(struct pt_regs *) = NULL; + void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) { if (handle_arch_irq) diff --git a/arch/arm64/kernel/jump_label.c b/arch/arm64/kernel/jump_label.c index 263a166291fb..4f1fec7a46db 100644 --- a/arch/arm64/kernel/jump_label.c +++ b/arch/arm64/kernel/jump_label.c @@ -22,9 +22,8 @@ #ifdef HAVE_JUMP_LABEL -static void __arch_jump_label_transform(struct jump_entry *entry, - enum jump_label_type type, - bool is_static) +void arch_jump_label_transform(struct jump_entry *entry, + enum jump_label_type type) { void *addr = (void *)entry->code; u32 insn; @@ -37,22 +36,18 @@ static void __arch_jump_label_transform(struct jump_entry *entry, insn = aarch64_insn_gen_nop(); } - if (is_static) - aarch64_insn_patch_text_nosync(addr, insn); - else - aarch64_insn_patch_text(&addr, &insn, 1); -} - -void arch_jump_label_transform(struct jump_entry *entry, - enum jump_label_type type) -{ - __arch_jump_label_transform(entry, type, false); + aarch64_insn_patch_text(&addr, &insn, 1); } void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type) { - __arch_jump_label_transform(entry, type, true); + /* + * We use the architected A64 NOP in arch_static_branch, so there's no + * need to patch an identical A64 NOP over the top of it here. The core + * will call arch_jump_label_transform from a module notifier if the + * NOP needs to be replaced by a branch. + */ } #endif /* HAVE_JUMP_LABEL */ diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 1eb1cc955139..fd027b101de5 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -26,6 +26,7 @@ #include <linux/moduleloader.h> #include <linux/vmalloc.h> #include <asm/insn.h> +#include <asm/sections.h> #define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX #define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16 @@ -394,3 +395,20 @@ overflow: me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); return -ENOEXEC; } + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + const Elf_Shdr *s, *se; + const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) { + if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) { + apply_alternatives((void *)s->sh_addr, s->sh_size); + return 0; + } + } + + return 0; +} diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index aa29ecb4f800..25a5308744b1 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -169,8 +169,14 @@ armpmu_event_set_period(struct perf_event *event, ret = 1; } - if (left > (s64)armpmu->max_period) - left = armpmu->max_period; + /* + * Limit the maximum period to prevent the counter value + * from overtaking the one we are about to program. In + * effect we are reducing max_period to account for + * interrupt latency (and we are being very conservative). + */ + if (left > (armpmu->max_period >> 1)) + left = armpmu->max_period >> 1; local64_set(&hwc->prev_count, (u64)-left); diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 866c1c821860..663da771580a 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -528,7 +528,7 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) if (WARN_ON_ONCE(!index)) return -EINVAL; - if (state->type == PSCI_POWER_STATE_TYPE_STANDBY) + if (state[index - 1].type == PSCI_POWER_STATE_TYPE_STANDBY) ret = psci_ops.cpu_suspend(state[index - 1], 0); else ret = __cpu_suspend(index, psci_suspend_finisher); diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 8a4ae8e73213..d882b833dbdb 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -27,6 +27,7 @@ #include <linux/smp.h> #include <linux/ptrace.h> #include <linux/user.h> +#include <linux/seccomp.h> #include <linux/security.h> #include <linux/init.h> #include <linux/signal.h> @@ -551,6 +552,32 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset, return ret; } +static int system_call_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int syscallno = task_pt_regs(target)->syscallno; + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &syscallno, 0, -1); +} + +static int system_call_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int syscallno, ret; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &syscallno, 0, -1); + if (ret) + return ret; + + task_pt_regs(target)->syscallno = syscallno; + return ret; +} + enum aarch64_regset { REGSET_GPR, REGSET_FPR, @@ -559,6 +586,7 @@ enum aarch64_regset { REGSET_HW_BREAK, REGSET_HW_WATCH, #endif + REGSET_SYSTEM_CALL, }; static const struct user_regset aarch64_regsets[] = { @@ -608,6 +636,14 @@ static const struct user_regset aarch64_regsets[] = { .set = hw_break_set, }, #endif + [REGSET_SYSTEM_CALL] = { + .core_note_type = NT_ARM_SYSTEM_CALL, + .n = 1, + .size = sizeof(int), + .align = sizeof(int), + .get = system_call_get, + .set = system_call_set, + }, }; static const struct user_regset_view user_aarch64_view = { @@ -1114,6 +1150,10 @@ static void tracehook_report_syscall(struct pt_regs *regs, asmlinkage int syscall_trace_enter(struct pt_regs *regs) { + /* Do the secure computing check first; failures should be fast. */ + if (secure_computing() == -1) + return -1; + if (test_thread_flag(TIF_SYSCALL_TRACE)) tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 2437196cc5d4..b80991166754 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -43,12 +43,14 @@ #include <linux/of_fdt.h> #include <linux/of_platform.h> #include <linux/efi.h> +#include <linux/personality.h> #include <asm/fixmap.h> #include <asm/cpu.h> #include <asm/cputype.h> #include <asm/elf.h> #include <asm/cputable.h> +#include <asm/cpufeature.h> #include <asm/cpu_ops.h> #include <asm/sections.h> #include <asm/setup.h> @@ -72,13 +74,15 @@ EXPORT_SYMBOL_GPL(elf_hwcap); COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\ COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\ COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\ - COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV) + COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\ + COMPAT_HWCAP_LPAE) unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT; unsigned int compat_elf_hwcap2 __read_mostly; #endif +DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); + static const char *cpu_name; -static const char *machine_name; phys_addr_t __fdt_pointer __initdata; /* @@ -116,12 +120,16 @@ void __init early_print(const char *str, ...) void __init smp_setup_processor_id(void) { + u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; + cpu_logical_map(0) = mpidr; + /* * clear __my_cpu_offset on boot CPU to avoid hang caused by * using percpu variable early, for example, lockdep will * access percpu variable inside lock_release */ set_my_cpu_offset(0); + pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr); } bool arch_match_cpu_phys_id(int cpu, u64 phys_id) @@ -311,7 +319,7 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) cpu_relax(); } - machine_name = of_flat_dt_get_machine_name(); + dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name()); } /* @@ -376,6 +384,7 @@ void __init setup_arch(char **cmdline_p) *cmdline_p = boot_command_line; + early_fixmap_init(); early_ioremap_init(); parse_early_param(); @@ -398,7 +407,6 @@ void __init setup_arch(char **cmdline_p) psci_init(); - cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; cpu_read_bootcpu_ops(); #ifdef CONFIG_SMP smp_init_cpus(); @@ -447,14 +455,50 @@ static const char *hwcap_str[] = { NULL }; +#ifdef CONFIG_COMPAT +static const char *compat_hwcap_str[] = { + "swp", + "half", + "thumb", + "26bit", + "fastmult", + "fpa", + "vfp", + "edsp", + "java", + "iwmmxt", + "crunch", + "thumbee", + "neon", + "vfpv3", + "vfpv3d16", + "tls", + "vfpv4", + "idiva", + "idivt", + "vfpd32", + "lpae", + "evtstrm" +}; + +static const char *compat_hwcap2_str[] = { + "aes", + "pmull", + "sha1", + "sha2", + "crc32", + NULL +}; +#endif /* CONFIG_COMPAT */ + static int c_show(struct seq_file *m, void *v) { - int i; - - seq_printf(m, "Processor\t: %s rev %d (%s)\n", - cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); + int i, j; for_each_online_cpu(i) { + struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i); + u32 midr = cpuinfo->reg_midr; + /* * glibc reads /proc/cpuinfo to determine the number of * online processors, looking for lines beginning with @@ -463,24 +507,38 @@ static int c_show(struct seq_file *m, void *v) #ifdef CONFIG_SMP seq_printf(m, "processor\t: %d\n", i); #endif - } - - /* dump out the processor features */ - seq_puts(m, "Features\t: "); - - for (i = 0; hwcap_str[i]; i++) - if (elf_hwcap & (1 << i)) - seq_printf(m, "%s ", hwcap_str[i]); - - seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); - seq_printf(m, "CPU architecture: AArch64\n"); - seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15); - seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff); - seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); - seq_puts(m, "\n"); - - seq_printf(m, "Hardware\t: %s\n", machine_name); + /* + * Dump out the common processor features in a single line. + * Userspace should read the hwcaps with getauxval(AT_HWCAP) + * rather than attempting to parse this, but there's a body of + * software which does already (at least for 32-bit). + */ + seq_puts(m, "Features\t:"); + if (personality(current->personality) == PER_LINUX32) { +#ifdef CONFIG_COMPAT + for (j = 0; compat_hwcap_str[j]; j++) + if (compat_elf_hwcap & (1 << j)) + seq_printf(m, " %s", compat_hwcap_str[j]); + + for (j = 0; compat_hwcap2_str[j]; j++) + if (compat_elf_hwcap2 & (1 << j)) + seq_printf(m, " %s", compat_hwcap2_str[j]); +#endif /* CONFIG_COMPAT */ + } else { + for (j = 0; hwcap_str[j]; j++) + if (elf_hwcap & (1 << j)) + seq_printf(m, " %s", hwcap_str[j]); + } + seq_puts(m, "\n"); + + seq_printf(m, "CPU implementer\t: 0x%02x\n", + MIDR_IMPLEMENTOR(midr)); + seq_printf(m, "CPU architecture: 8\n"); + seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr)); + seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr)); + seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr)); + } return 0; } diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 1b9ad02837cf..5a1ba6e80d4e 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -186,6 +186,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr); break; + case __SI_SYS: + err |= __put_user((compat_uptr_t)(unsigned long) + from->si_call_addr, &to->si_call_addr); + err |= __put_user(from->si_syscall, &to->si_syscall); + err |= __put_user(from->si_arch, &to->si_arch); + break; default: /* this is just in case for now ... */ err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index a564b440416a..ede186cdd452 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -147,14 +147,12 @@ cpu_resume_after_mmu: ret ENDPROC(cpu_resume_after_mmu) - .data ENTRY(cpu_resume) bl el2_setup // if in EL2 drop to EL1 cleanly #ifdef CONFIG_SMP mrs x1, mpidr_el1 - adr x4, mpidr_hash_ptr - ldr x5, [x4] - add x8, x4, x5 // x8 = struct mpidr_hash phys address + adrp x8, mpidr_hash + add x8, x8, #:lo12:mpidr_hash // x8 = struct mpidr_hash phys address /* retrieve mpidr_hash members to compute the hash */ ldr x2, [x8, #MPIDR_HASH_MASK] ldp w3, w4, [x8, #MPIDR_HASH_SHIFTS] @@ -164,14 +162,15 @@ ENTRY(cpu_resume) #else mov x7, xzr #endif - adr x0, sleep_save_sp + adrp x0, sleep_save_sp + add x0, x0, #:lo12:sleep_save_sp ldr x0, [x0, #SLEEP_SAVE_SP_PHYS] ldr x0, [x0, x7, lsl #3] /* load sp from context */ ldr x2, [x0, #CPU_CTX_SP] - adr x1, sleep_idmap_phys + adrp x1, sleep_idmap_phys /* load physical address of identity map page table in x1 */ - ldr x1, [x1] + ldr x1, [x1, #:lo12:sleep_idmap_phys] mov sp, x2 /* * cpu_do_resume expects x0 to contain context physical address @@ -180,26 +179,3 @@ ENTRY(cpu_resume) bl cpu_do_resume // PC relative jump, MMU off b cpu_resume_mmu // Resume MMU, never returns ENDPROC(cpu_resume) - - .align 3 -mpidr_hash_ptr: - /* - * offset of mpidr_hash symbol from current location - * used to obtain run-time mpidr_hash address with MMU off - */ - .quad mpidr_hash - . -/* - * physical address of identity mapped page tables - */ - .type sleep_idmap_phys, #object -ENTRY(sleep_idmap_phys) - .quad 0 -/* - * struct sleep_save_sp { - * phys_addr_t *save_ptr_stash; - * phys_addr_t save_ptr_stash_phys; - * }; - */ - .type sleep_save_sp, #object -ENTRY(sleep_save_sp) - .space SLEEP_SAVE_SP_SZ // struct sleep_save_sp diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index b06d1d90ee8c..7ae6ee085261 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -37,6 +37,7 @@ #include <linux/of.h> #include <linux/irq_work.h> +#include <asm/alternative.h> #include <asm/atomic.h> #include <asm/cacheflush.h> #include <asm/cpu.h> @@ -309,6 +310,7 @@ void cpu_die(void) void __init smp_cpus_done(unsigned int max_cpus) { pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); + apply_alternatives_all(); } void __init smp_prepare_boot_cpu(void) diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 13ad4dbb1615..3771b72b6569 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c @@ -126,8 +126,8 @@ int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) return ret; } -extern struct sleep_save_sp sleep_save_sp; -extern phys_addr_t sleep_idmap_phys; +struct sleep_save_sp sleep_save_sp; +phys_addr_t sleep_idmap_phys; static int __init cpu_suspend_init(void) { diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c index dc47e53e9e28..28c511b06edf 100644 --- a/arch/arm64/kernel/sys_compat.c +++ b/arch/arm64/kernel/sys_compat.c @@ -28,29 +28,39 @@ #include <asm/cacheflush.h> #include <asm/unistd.h> -static inline void -do_compat_cache_op(unsigned long start, unsigned long end, int flags) +static long +__do_compat_cache_op(unsigned long start, unsigned long end) { - struct mm_struct *mm = current->active_mm; - struct vm_area_struct *vma; + long ret; - if (end < start || flags) - return; + do { + unsigned long chunk = min(PAGE_SIZE, end - start); - down_read(&mm->mmap_sem); - vma = find_vma(mm, start); - if (vma && vma->vm_start < end) { - if (start < vma->vm_start) - start = vma->vm_start; - if (end > vma->vm_end) - end = vma->vm_end; - up_read(&mm->mmap_sem); - __flush_cache_user_range(start & PAGE_MASK, PAGE_ALIGN(end)); - return; - } - up_read(&mm->mmap_sem); + if (fatal_signal_pending(current)) + return 0; + + ret = __flush_cache_user_range(start, start + chunk); + if (ret) + return ret; + + cond_resched(); + start += chunk; + } while (start < end); + + return 0; } +static inline long +do_compat_cache_op(unsigned long start, unsigned long end, int flags) +{ + if (end < start || flags) + return -EINVAL; + + if (!access_ok(VERIFY_READ, start, end - start)) + return -EFAULT; + + return __do_compat_cache_op(start, end); +} /* * Handle all unrecognised system calls. */ @@ -74,8 +84,7 @@ long compat_arm_syscall(struct pt_regs *regs) * the specified region). */ case __ARM_NR_compat_cacheflush: - do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]); - return 0; + return do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]); case __ARM_NR_compat_set_tls: current->thread.tp_value = regs->regs[0]; diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index b6ee26b0939a..fcb8f7b42271 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -255,12 +255,15 @@ void store_cpu_topology(unsigned int cpuid) /* Multiprocessor system : Multi-threads per core */ cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1); - cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2); + cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) | + MPIDR_AFFINITY_LEVEL(mpidr, 3) << 8; } else { /* Multiprocessor system : Single-thread per core */ cpuid_topo->thread_id = -1; cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); - cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1); + cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) | + MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8 | + MPIDR_AFFINITY_LEVEL(mpidr, 3) << 16; } pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n", diff --git a/arch/arm64/kernel/trace-events-emulation.h b/arch/arm64/kernel/trace-events-emulation.h new file mode 100644 index 000000000000..ae1dd598ea65 --- /dev/null +++ b/arch/arm64/kernel/trace-events-emulation.h @@ -0,0 +1,35 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM emulation + +#if !defined(_TRACE_EMULATION_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_EMULATION_H + +#include <linux/tracepoint.h> + +TRACE_EVENT(instruction_emulation, + + TP_PROTO(const char *instr, u64 addr), + TP_ARGS(instr, addr), + + TP_STRUCT__entry( + __string(instr, instr) + __field(u64, addr) + ), + + TP_fast_assign( + __assign_str(instr, instr); + __entry->addr = addr; + ), + + TP_printk("instr=\"%s\" addr=0x%llx", __get_str(instr), __entry->addr) +); + +#endif /* _TRACE_EMULATION_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . + +#define TRACE_INCLUDE_FILE trace-events-emulation +#include <trace/define_trace.h> diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index de1b085e7963..0a801e3743d5 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -259,6 +259,69 @@ void arm64_notify_die(const char *str, struct pt_regs *regs, } } +static LIST_HEAD(undef_hook); +static DEFINE_RAW_SPINLOCK(undef_lock); + +void register_undef_hook(struct undef_hook *hook) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&undef_lock, flags); + list_add(&hook->node, &undef_hook); + raw_spin_unlock_irqrestore(&undef_lock, flags); +} + +void unregister_undef_hook(struct undef_hook *hook) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&undef_lock, flags); + list_del(&hook->node); + raw_spin_unlock_irqrestore(&undef_lock, flags); +} + +static int call_undef_hook(struct pt_regs *regs) +{ + struct undef_hook *hook; + unsigned long flags; + u32 instr; + int (*fn)(struct pt_regs *regs, u32 instr) = NULL; + void __user *pc = (void __user *)instruction_pointer(regs); + + if (!user_mode(regs)) + return 1; + + if (compat_thumb_mode(regs)) { + /* 16-bit Thumb instruction */ + if (get_user(instr, (u16 __user *)pc)) + goto exit; + instr = le16_to_cpu(instr); + if (aarch32_insn_is_wide(instr)) { + u32 instr2; + + if (get_user(instr2, (u16 __user *)(pc + 2))) + goto exit; + instr2 = le16_to_cpu(instr2); + instr = (instr << 16) | instr2; + } + } else { + /* 32-bit ARM instruction */ + if (get_user(instr, (u32 __user *)pc)) + goto exit; + instr = le32_to_cpu(instr); + } + + raw_spin_lock_irqsave(&undef_lock, flags); + list_for_each_entry(hook, &undef_hook, node) + if ((instr & hook->instr_mask) == hook->instr_val && + (regs->pstate & hook->pstate_mask) == hook->pstate_val) + fn = hook->fn; + + raw_spin_unlock_irqrestore(&undef_lock, flags); +exit: + return fn ? fn(regs, instr) : 1; +} + asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { siginfo_t info; @@ -268,6 +331,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) if (!aarch32_break_handler(regs)) return; + if (call_undef_hook(regs) == 0) + return; + if (show_unhandled_signals && unhandled_signal(current, SIGILL) && printk_ratelimit()) { pr_info("%s[%d]: undefined instruction: pc=%p\n", diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index edf8715ba39b..9965ec87cbec 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -11,8 +11,9 @@ #include "image.h" -#define ARM_EXIT_KEEP(x) -#define ARM_EXIT_DISCARD(x) x +/* .exit.text needed in case of alternative patching */ +#define ARM_EXIT_KEEP(x) x +#define ARM_EXIT_DISCARD(x) OUTPUT_ARCH(aarch64) ENTRY(_text) @@ -32,6 +33,22 @@ jiffies = jiffies_64; *(.hyp.text) \ VMLINUX_SYMBOL(__hyp_text_end) = .; +/* + * The size of the PE/COFF section that covers the kernel image, which + * runs from stext to _edata, must be a round multiple of the PE/COFF + * FileAlignment, which we set to its minimum value of 0x200. 'stext' + * itself is 4 KB aligned, so padding out _edata to a 0x200 aligned + * boundary should be sufficient. + */ +PECOFF_FILE_ALIGNMENT = 0x200; + +#ifdef CONFIG_EFI +#define PECOFF_EDATA_PADDING \ + .pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); } +#else +#define PECOFF_EDATA_PADDING +#endif + SECTIONS { /* @@ -100,9 +117,21 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_end = .; + . = ALIGN(4); + .altinstructions : { + __alt_instructions = .; + *(.altinstructions) + __alt_instructions_end = .; + } + .altinstr_replacement : { + *(.altinstr_replacement) + } + + . = ALIGN(PAGE_SIZE); _data = .; _sdata = .; RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE) + PECOFF_EDATA_PADDING _edata = .; BSS_SECTION(0, 0, 0) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index b72aa9f9215c..fbe909fb0a1a 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -761,10 +761,10 @@ .macro activate_traps ldr x2, [x0, #VCPU_HCR_EL2] msr hcr_el2, x2 - ldr x2, =(CPTR_EL2_TTA) + mov x2, #CPTR_EL2_TTA msr cptr_el2, x2 - ldr x2, =(1 << 15) // Trap CP15 Cr=15 + mov x2, #(1 << 15) // Trap CP15 Cr=15 msr hstr_el2, x2 mrs x2, mdcr_el2 diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4cc3b719208e..3d7c2df89946 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -424,6 +424,11 @@ static const struct sys_reg_desc sys_reg_descs[] = { /* VBAR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000), NULL, reset_val, VBAR_EL1, 0 }, + + /* ICC_SRE_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b101), + trap_raz_wi }, + /* CONTEXTIDR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 }, @@ -690,6 +695,10 @@ static const struct sys_reg_desc cp15_regs[] = { { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR }, { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 }, { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 }, + + /* ICC_SRE */ + { Op1( 0), CRn(12), CRm(12), Op2( 5), trap_raz_wi }, + { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID }, }; diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index 6e0ed93d51fe..c17967fdf5f6 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -46,7 +46,7 @@ USER(9f, strh wzr, [x0], #2 ) sub x1, x1, #2 4: adds x1, x1, #1 b.mi 5f - strb wzr, [x0] +USER(9f, strb wzr, [x0] ) 5: mov x0, #0 ret ENDPROC(__clear_user) diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile index c56179ed2c09..773d37a14039 100644 --- a/arch/arm64/mm/Makefile +++ b/arch/arm64/mm/Makefile @@ -3,3 +3,4 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ ioremap.o mmap.o pgd.o mmu.o \ context.o proc.o pageattr.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o +obj-$(CONFIG_ARM64_PTDUMP) += dump.o diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 23663837acff..2560e1e1562e 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -17,9 +17,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <linux/errno.h> #include <linux/linkage.h> #include <linux/init.h> #include <asm/assembler.h> +#include <asm/cpufeature.h> +#include <asm/alternative-asm.h> #include "proc-macros.S" @@ -138,9 +141,12 @@ USER(9f, ic ivau, x4 ) // invalidate I line PoU add x4, x4, x2 cmp x4, x1 b.lo 1b -9: // ignore any faulting cache operation dsb ish isb + mov x0, #0 + ret +9: + mov x0, #-EFAULT ret ENDPROC(flush_icache_range) ENDPROC(__flush_cache_user_range) @@ -210,7 +216,7 @@ __dma_clean_range: dcache_line_size x2, x3 sub x3, x2, #1 bic x0, x0, x3 -1: dc cvac, x0 // clean D / U line +1: alternative_insn "dc cvac, x0", "dc civac, x0", ARM64_WORKAROUND_CLEAN_CACHE add x0, x0, x2 cmp x0, x1 b.lo 1b diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c new file mode 100644 index 000000000000..bf69601be546 --- /dev/null +++ b/arch/arm64/mm/dump.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Debug helper to dump the current kernel pagetables of the system + * so that we can see what the various memory ranges are set to. + * + * Derived from x86 and arm implementation: + * (C) Copyright 2008 Intel Corporation + * + * Author: Arjan van de Ven <arjan@linux.intel.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ +#include <linux/debugfs.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/seq_file.h> + +#include <asm/fixmap.h> +#include <asm/pgtable.h> + +#define LOWEST_ADDR (UL(0xffffffffffffffff) << VA_BITS) + +struct addr_marker { + unsigned long start_address; + const char *name; +}; + +enum address_markers_idx { + VMALLOC_START_NR = 0, + VMALLOC_END_NR, +#ifdef CONFIG_SPARSEMEM_VMEMMAP + VMEMMAP_START_NR, + VMEMMAP_END_NR, +#endif + PCI_START_NR, + PCI_END_NR, + FIXADDR_START_NR, + FIXADDR_END_NR, + MODULES_START_NR, + MODUELS_END_NR, + KERNEL_SPACE_NR, +}; + +static struct addr_marker address_markers[] = { + { VMALLOC_START, "vmalloc() Area" }, + { VMALLOC_END, "vmalloc() End" }, +#ifdef CONFIG_SPARSEMEM_VMEMMAP + { 0, "vmemmap start" }, + { 0, "vmemmap end" }, +#endif + { (unsigned long) PCI_IOBASE, "PCI I/O start" }, + { (unsigned long) PCI_IOBASE + SZ_16M, "PCI I/O end" }, + { FIXADDR_START, "Fixmap start" }, + { FIXADDR_TOP, "Fixmap end" }, + { MODULES_VADDR, "Modules start" }, + { MODULES_END, "Modules end" }, + { PAGE_OFFSET, "Kernel Mapping" }, + { -1, NULL }, +}; + +struct pg_state { + struct seq_file *seq; + const struct addr_marker *marker; + unsigned long start_address; + unsigned level; + u64 current_prot; +}; + +struct prot_bits { + u64 mask; + u64 val; + const char *set; + const char *clear; +}; + +static const struct prot_bits pte_bits[] = { + { + .mask = PTE_USER, + .val = PTE_USER, + .set = "USR", + .clear = " ", + }, { + .mask = PTE_RDONLY, + .val = PTE_RDONLY, + .set = "ro", + .clear = "RW", + }, { + .mask = PTE_PXN, + .val = PTE_PXN, + .set = "NX", + .clear = "x ", + }, { + .mask = PTE_SHARED, + .val = PTE_SHARED, + .set = "SHD", + .clear = " ", + }, { + .mask = PTE_AF, + .val = PTE_AF, + .set = "AF", + .clear = " ", + }, { + .mask = PTE_NG, + .val = PTE_NG, + .set = "NG", + .clear = " ", + }, { + .mask = PTE_UXN, + .val = PTE_UXN, + .set = "UXN", + }, { + .mask = PTE_ATTRINDX_MASK, + .val = PTE_ATTRINDX(MT_DEVICE_nGnRnE), + .set = "DEVICE/nGnRnE", + }, { + .mask = PTE_ATTRINDX_MASK, + .val = PTE_ATTRINDX(MT_DEVICE_nGnRE), + .set = "DEVICE/nGnRE", + }, { + .mask = PTE_ATTRINDX_MASK, + .val = PTE_ATTRINDX(MT_DEVICE_GRE), + .set = "DEVICE/GRE", + }, { + .mask = PTE_ATTRINDX_MASK, + .val = PTE_ATTRINDX(MT_NORMAL_NC), + .set = "MEM/NORMAL-NC", + }, { + .mask = PTE_ATTRINDX_MASK, + .val = PTE_ATTRINDX(MT_NORMAL), + .set = "MEM/NORMAL", + } +}; + +struct pg_level { + const struct prot_bits *bits; + size_t num; + u64 mask; +}; + +static struct pg_level pg_level[] = { + { + }, { /* pgd */ + .bits = pte_bits, + .num = ARRAY_SIZE(pte_bits), + }, { /* pud */ + .bits = pte_bits, + .num = ARRAY_SIZE(pte_bits), + }, { /* pmd */ + .bits = pte_bits, + .num = ARRAY_SIZE(pte_bits), + }, { /* pte */ + .bits = pte_bits, + .num = ARRAY_SIZE(pte_bits), + }, +}; + +static void dump_prot(struct pg_state *st, const struct prot_bits *bits, + size_t num) +{ + unsigned i; + + for (i = 0; i < num; i++, bits++) { + const char *s; + + if ((st->current_prot & bits->mask) == bits->val) + s = bits->set; + else + s = bits->clear; + + if (s) + seq_printf(st->seq, " %s", s); + } +} + +static void note_page(struct pg_state *st, unsigned long addr, unsigned level, + u64 val) +{ + static const char units[] = "KMGTPE"; + u64 prot = val & pg_level[level].mask; + + if (addr < LOWEST_ADDR) + return; + + if (!st->level) { + st->level = level; + st->current_prot = prot; + st->start_address = addr; + seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); + } else if (prot != st->current_prot || level != st->level || + addr >= st->marker[1].start_address) { + const char *unit = units; + unsigned long delta; + + if (st->current_prot) { + seq_printf(st->seq, "0x%16lx-0x%16lx ", + st->start_address, addr); + + delta = (addr - st->start_address) >> 10; + while (!(delta & 1023) && unit[1]) { + delta >>= 10; + unit++; + } + seq_printf(st->seq, "%9lu%c", delta, *unit); + if (pg_level[st->level].bits) + dump_prot(st, pg_level[st->level].bits, + pg_level[st->level].num); + seq_puts(st->seq, "\n"); + } + + if (addr >= st->marker[1].start_address) { + st->marker++; + seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); + } + + st->start_address = addr; + st->current_prot = prot; + st->level = level; + } + + if (addr >= st->marker[1].start_address) { + st->marker++; + seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); + } + +} + +static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start) +{ + pte_t *pte = pte_offset_kernel(pmd, 0); + unsigned long addr; + unsigned i; + + for (i = 0; i < PTRS_PER_PTE; i++, pte++) { + addr = start + i * PAGE_SIZE; + note_page(st, addr, 4, pte_val(*pte)); + } +} + +static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start) +{ + pmd_t *pmd = pmd_offset(pud, 0); + unsigned long addr; + unsigned i; + + for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { + addr = start + i * PMD_SIZE; + if (pmd_none(*pmd) || pmd_sect(*pmd) || pmd_bad(*pmd)) + note_page(st, addr, 3, pmd_val(*pmd)); + else + walk_pte(st, pmd, addr); + } +} + +static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start) +{ + pud_t *pud = pud_offset(pgd, 0); + unsigned long addr; + unsigned i; + + for (i = 0; i < PTRS_PER_PUD; i++, pud++) { + addr = start + i * PUD_SIZE; + if (pud_none(*pud) || pud_sect(*pud) || pud_bad(*pud)) + note_page(st, addr, 2, pud_val(*pud)); + else + walk_pmd(st, pud, addr); + } +} + +static void walk_pgd(struct pg_state *st, struct mm_struct *mm, unsigned long start) +{ + pgd_t *pgd = pgd_offset(mm, 0); + unsigned i; + unsigned long addr; + + for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { + addr = start + i * PGDIR_SIZE; + if (pgd_none(*pgd) || pgd_bad(*pgd)) + note_page(st, addr, 1, pgd_val(*pgd)); + else + walk_pud(st, pgd, addr); + } +} + +static int ptdump_show(struct seq_file *m, void *v) +{ + struct pg_state st = { + .seq = m, + .marker = address_markers, + }; + + walk_pgd(&st, &init_mm, LOWEST_ADDR); + + note_page(&st, 0, 0, 0); + return 0; +} + +static int ptdump_open(struct inode *inode, struct file *file) +{ + return single_open(file, ptdump_show, NULL); +} + +static const struct file_operations ptdump_fops = { + .open = ptdump_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int ptdump_init(void) +{ + struct dentry *pe; + unsigned i, j; + + for (i = 0; i < ARRAY_SIZE(pg_level); i++) + if (pg_level[i].bits) + for (j = 0; j < pg_level[i].num; j++) + pg_level[i].mask |= pg_level[i].bits[j].mask; + + address_markers[VMEMMAP_START_NR].start_address = + (unsigned long)virt_to_page(PAGE_OFFSET); + address_markers[VMEMMAP_END_NR].start_address = + (unsigned long)virt_to_page(high_memory); + + pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, + &ptdump_fops); + return pe ? 0 : -ENOMEM; +} +device_initcall(ptdump_init); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 41cb6d3d6075..c11cd27ca8f5 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -380,7 +380,7 @@ static struct fault_info { { do_bad, SIGBUS, 0, "level 1 address size fault" }, { do_bad, SIGBUS, 0, "level 2 address size fault" }, { do_bad, SIGBUS, 0, "level 3 address size fault" }, - { do_translation_fault, SIGSEGV, SEGV_MAPERR, "input address range fault" }, + { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" }, { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 494297c698ca..bac492c12fcc 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -39,6 +39,7 @@ #include <asm/setup.h> #include <asm/sizes.h> #include <asm/tlb.h> +#include <asm/alternative.h> #include "mm.h" @@ -325,6 +326,7 @@ void __init mem_init(void) void free_initmem(void) { free_initmem_default(0); + free_alternatives_memory(); } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c index 4a07630a6616..cbb99c8f1e04 100644 --- a/arch/arm64/mm/ioremap.c +++ b/arch/arm64/mm/ioremap.c @@ -103,97 +103,10 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size) } EXPORT_SYMBOL(ioremap_cache); -static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss; -#if CONFIG_ARM64_PGTABLE_LEVELS > 2 -static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss; -#endif -#if CONFIG_ARM64_PGTABLE_LEVELS > 3 -static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss; -#endif - -static inline pud_t * __init early_ioremap_pud(unsigned long addr) -{ - pgd_t *pgd; - - pgd = pgd_offset_k(addr); - BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd)); - - return pud_offset(pgd, addr); -} - -static inline pmd_t * __init early_ioremap_pmd(unsigned long addr) -{ - pud_t *pud = early_ioremap_pud(addr); - - BUG_ON(pud_none(*pud) || pud_bad(*pud)); - - return pmd_offset(pud, addr); -} - -static inline pte_t * __init early_ioremap_pte(unsigned long addr) -{ - pmd_t *pmd = early_ioremap_pmd(addr); - - BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd)); - - return pte_offset_kernel(pmd, addr); -} - +/* + * Must be called after early_fixmap_init + */ void __init early_ioremap_init(void) { - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - unsigned long addr = fix_to_virt(FIX_BTMAP_BEGIN); - - pgd = pgd_offset_k(addr); - pgd_populate(&init_mm, pgd, bm_pud); - pud = pud_offset(pgd, addr); - pud_populate(&init_mm, pud, bm_pmd); - pmd = pmd_offset(pud, addr); - pmd_populate_kernel(&init_mm, pmd, bm_pte); - - /* - * The boot-ioremap range spans multiple pmds, for which - * we are not prepared: - */ - BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT) - != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT)); - - if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) { - WARN_ON(1); - pr_warn("pmd %p != %p\n", - pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))); - pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n", - fix_to_virt(FIX_BTMAP_BEGIN)); - pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n", - fix_to_virt(FIX_BTMAP_END)); - - pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END); - pr_warn("FIX_BTMAP_BEGIN: %d\n", - FIX_BTMAP_BEGIN); - } - early_ioremap_setup(); } - -void __init __early_set_fixmap(enum fixed_addresses idx, - phys_addr_t phys, pgprot_t flags) -{ - unsigned long addr = __fix_to_virt(idx); - pte_t *pte; - - if (idx >= __end_of_fixed_addresses) { - BUG(); - return; - } - - pte = early_ioremap_pte(addr); - - if (pgprot_val(flags)) - set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); - else { - pte_clear(&init_mm, addr, pte); - flush_tlb_kernel_range(addr, addr+PAGE_SIZE); - } -} diff --git a/arch/arm64/mm/mm.h b/arch/arm64/mm/mm.h index d519f4f50c8c..50c3351df9c7 100644 --- a/arch/arm64/mm/mm.h +++ b/arch/arm64/mm/mm.h @@ -1,2 +1 @@ extern void __init bootmem_init(void); -extern void __init arm64_swiotlb_init(void); diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c index 1d73662f00ff..54922d1275b8 100644 --- a/arch/arm64/mm/mmap.c +++ b/arch/arm64/mm/mmap.c @@ -47,22 +47,14 @@ static int mmap_is_legacy(void) return sysctl_legacy_va_layout; } -/* - * Since get_random_int() returns the same value within a 1 jiffy window, we - * will almost always get the same randomisation for the stack and mmap - * region. This will mean the relative distance between stack and mmap will be - * the same. - * - * To avoid this we can shift the randomness by 1 bit. - */ static unsigned long mmap_rnd(void) { unsigned long rnd = 0; if (current->flags & PF_RANDOMIZE) - rnd = (long)get_random_int() & (STACK_RND_MASK >> 1); + rnd = (long)get_random_int() & STACK_RND_MASK; - return rnd << (PAGE_SHIFT + 1); + return rnd << PAGE_SHIFT; } static unsigned long mmap_base(void) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 0bf90d26e745..6032f3e3056a 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -28,6 +28,7 @@ #include <linux/io.h> #include <asm/cputype.h> +#include <asm/fixmap.h> #include <asm/sections.h> #include <asm/setup.h> #include <asm/sizes.h> @@ -202,7 +203,7 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, } static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, - unsigned long end, unsigned long phys, + unsigned long end, phys_addr_t phys, int map_io) { pud_t *pud; @@ -463,3 +464,96 @@ void vmemmap_free(unsigned long start, unsigned long end) { } #endif /* CONFIG_SPARSEMEM_VMEMMAP */ + +static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss; +#if CONFIG_ARM64_PGTABLE_LEVELS > 2 +static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss; +#endif +#if CONFIG_ARM64_PGTABLE_LEVELS > 3 +static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss; +#endif + +static inline pud_t * fixmap_pud(unsigned long addr) +{ + pgd_t *pgd = pgd_offset_k(addr); + + BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd)); + + return pud_offset(pgd, addr); +} + +static inline pmd_t * fixmap_pmd(unsigned long addr) +{ + pud_t *pud = fixmap_pud(addr); + + BUG_ON(pud_none(*pud) || pud_bad(*pud)); + + return pmd_offset(pud, addr); +} + +static inline pte_t * fixmap_pte(unsigned long addr) +{ + pmd_t *pmd = fixmap_pmd(addr); + + BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd)); + + return pte_offset_kernel(pmd, addr); +} + +void __init early_fixmap_init(void) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + unsigned long addr = FIXADDR_START; + + pgd = pgd_offset_k(addr); + pgd_populate(&init_mm, pgd, bm_pud); + pud = pud_offset(pgd, addr); + pud_populate(&init_mm, pud, bm_pmd); + pmd = pmd_offset(pud, addr); + pmd_populate_kernel(&init_mm, pmd, bm_pte); + + /* + * The boot-ioremap range spans multiple pmds, for which + * we are not preparted: + */ + BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT) + != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT)); + + if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN))) + || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) { + WARN_ON(1); + pr_warn("pmd %p != %p, %p\n", + pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)), + fixmap_pmd(fix_to_virt(FIX_BTMAP_END))); + pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n", + fix_to_virt(FIX_BTMAP_BEGIN)); + pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n", + fix_to_virt(FIX_BTMAP_END)); + + pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END); + pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN); + } +} + +void __set_fixmap(enum fixed_addresses idx, + phys_addr_t phys, pgprot_t flags) +{ + unsigned long addr = __fix_to_virt(idx); + pte_t *pte; + + if (idx >= __end_of_fixed_addresses) { + BUG(); + return; + } + + pte = fixmap_pte(addr); + + if (pgprot_val(flags)) { + set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); + } else { + pte_clear(&init_mm, addr, pte); + flush_tlb_kernel_range(addr, addr+PAGE_SIZE); + } +} diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c index 6682b361d3ac..71ca104f97bd 100644 --- a/arch/arm64/mm/pgd.c +++ b/arch/arm64/mm/pgd.c @@ -35,9 +35,9 @@ static struct kmem_cache *pgd_cache; pgd_t *pgd_alloc(struct mm_struct *mm) { if (PGD_SIZE == PAGE_SIZE) - return (pgd_t *)get_zeroed_page(GFP_KERNEL); + return (pgd_t *)__get_free_page(PGALLOC_GFP); else - return kmem_cache_zalloc(pgd_cache, GFP_KERNEL); + return kmem_cache_alloc(pgd_cache, PGALLOC_GFP); } void pgd_free(struct mm_struct *mm, pgd_t *pgd) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 41f1e3e2ea24..edba042b2325 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -60,7 +60,7 @@ struct jit_ctx { const struct bpf_prog *prog; int idx; int tmp_used; - int body_offset; + int epilogue_offset; int *offset; u32 *image; }; @@ -130,8 +130,8 @@ static void jit_fill_hole(void *area, unsigned int size) static inline int epilogue_offset(const struct jit_ctx *ctx) { - int to = ctx->offset[ctx->prog->len - 1]; - int from = ctx->idx - ctx->body_offset; + int to = ctx->epilogue_offset; + int from = ctx->idx; return to - from; } @@ -463,6 +463,8 @@ emit_cond_jmp: } /* function return */ case BPF_JMP | BPF_EXIT: + /* Optimization: when last instruction is EXIT, + simply fallthrough to epilogue. */ if (i == ctx->prog->len - 1) break; jmp_offset = epilogue_offset(ctx); @@ -685,11 +687,13 @@ void bpf_int_jit_compile(struct bpf_prog *prog) /* 1. Initial fake pass to compute ctx->idx. */ - /* Fake pass to fill in ctx->offset. */ + /* Fake pass to fill in ctx->offset and ctx->tmp_used. */ if (build_body(&ctx)) goto out; build_prologue(&ctx); + + ctx.epilogue_offset = ctx.idx; build_epilogue(&ctx); /* Now we know the actual image size. */ @@ -706,7 +710,6 @@ void bpf_int_jit_compile(struct bpf_prog *prog) build_prologue(&ctx); - ctx.body_offset = ctx.idx; if (build_body(&ctx)) { bpf_jit_binary_free(header); goto out; diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c index 37b75602adf6..cc92cdb9994c 100644 --- a/arch/avr32/mach-at32ap/at32ap700x.c +++ b/arch/avr32/mach-at32ap/at32ap700x.c @@ -17,7 +17,7 @@ #include <linux/spi/spi.h> #include <linux/usb/atmel_usba_udc.h> -#include <mach/atmel-mci.h> +#include <linux/platform_data/mmc-atmel-mci.h> #include <linux/atmel-mci.h> #include <asm/io.h> diff --git a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h b/arch/avr32/mach-at32ap/include/mach/atmel-mci.h deleted file mode 100644 index 11d7f4b28dc8..000000000000 --- a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __MACH_ATMEL_MCI_H -#define __MACH_ATMEL_MCI_H - -#include <linux/platform_data/dma-dw.h> - -/** - * struct mci_dma_data - DMA data for MCI interface - */ -struct mci_dma_data { - struct dw_dma_slave sdata; -}; - -/* accessor macros */ -#define slave_data_ptr(s) (&(s)->sdata) -#define find_slave_dev(s) ((s)->sdata.dma_dev) - -#endif /* __MACH_ATMEL_MCI_H */ diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index ec6b9acb6bea..dbe46f43884d 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -1563,7 +1563,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, for (i = 0; i < npages; i++) { pfn = gfn_to_pfn(kvm, base_gfn + i); - if (!kvm_is_mmio_pfn(pfn)) { + if (!kvm_is_reserved_pfn(pfn)) { kvm_set_pmt_entry(kvm, base_gfn + i, pfn << PAGE_SHIFT, _PAGE_AR_RWX | _PAGE_MA_WB); diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index 01a62161b08a..192b00f098f4 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -858,6 +858,24 @@ static struct platform_device *atari_netusbee_devices[] __initdata = { }; #endif /* CONFIG_ATARI_ETHERNEC */ +#ifdef CONFIG_ATARI_SCSI +static const struct resource atari_scsi_st_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_MFP_FSCSI, + .end = IRQ_MFP_FSCSI, + }, +}; + +static const struct resource atari_scsi_tt_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_TT_MFP_SCSI, + .end = IRQ_TT_MFP_SCSI, + }, +}; +#endif + int __init atari_platform_init(void) { int rv = 0; @@ -892,6 +910,15 @@ int __init atari_platform_init(void) } #endif +#ifdef CONFIG_ATARI_SCSI + if (ATARIHW_PRESENT(ST_SCSI)) + platform_device_register_simple("atari_scsi", -1, + atari_scsi_st_rsrc, ARRAY_SIZE(atari_scsi_st_rsrc)); + else if (ATARIHW_PRESENT(TT_SCSI)) + platform_device_register_simple("atari_scsi", -1, + atari_scsi_tt_rsrc, ARRAY_SIZE(atari_scsi_tt_rsrc)); +#endif + return rv; } diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index ddbf43ca8858..e5a66596b116 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -59,6 +59,31 @@ static irqreturn_t stdma_int (int irq, void *dummy); /************************* End of Prototypes **************************/ +/** + * stdma_try_lock - attempt to acquire ST DMA interrupt "lock" + * @handler: interrupt handler to use after acquisition + * + * Returns !0 if lock was acquired; otherwise 0. + */ + +int stdma_try_lock(irq_handler_t handler, void *data) +{ + unsigned long flags; + + local_irq_save(flags); + if (stdma_locked) { + local_irq_restore(flags); + return 0; + } + + stdma_locked = 1; + stdma_isr = handler; + stdma_isr_data = data; + local_irq_restore(flags); + return 1; +} +EXPORT_SYMBOL(stdma_try_lock); + /* * Function: void stdma_lock( isrfunc isr, void *data ) @@ -78,19 +103,10 @@ static irqreturn_t stdma_int (int irq, void *dummy); void stdma_lock(irq_handler_t handler, void *data) { - unsigned long flags; - - local_irq_save(flags); /* protect lock */ - /* Since the DMA is used for file system purposes, we have to sleep uninterruptible (there may be locked buffers) */ - wait_event(stdma_wait, !stdma_locked); - - stdma_locked = 1; - stdma_isr = handler; - stdma_isr_data = data; - local_irq_restore(flags); + wait_event(stdma_wait, stdma_try_lock(handler, data)); } EXPORT_SYMBOL(stdma_lock); @@ -122,22 +138,25 @@ void stdma_release(void) EXPORT_SYMBOL(stdma_release); -/* - * Function: int stdma_others_waiting( void ) - * - * Purpose: Check if someone waits for the ST-DMA lock. - * - * Inputs: none - * - * Returns: 0 if no one is waiting, != 0 otherwise +/** + * stdma_is_locked_by - allow lock holder to check whether it needs to release. + * @handler: interrupt handler previously used to acquire lock. * + * Returns !0 if locked for the given handler; 0 otherwise. */ -int stdma_others_waiting(void) +int stdma_is_locked_by(irq_handler_t handler) { - return waitqueue_active(&stdma_wait); + unsigned long flags; + int result; + + local_irq_save(flags); + result = stdma_locked && (stdma_isr == handler); + local_irq_restore(flags); + + return result; } -EXPORT_SYMBOL(stdma_others_waiting); +EXPORT_SYMBOL(stdma_is_locked_by); /* diff --git a/arch/m68k/include/asm/atari_stdma.h b/arch/m68k/include/asm/atari_stdma.h index 8e389b7fa70c..d24e34d870dc 100644 --- a/arch/m68k/include/asm/atari_stdma.h +++ b/arch/m68k/include/asm/atari_stdma.h @@ -8,11 +8,11 @@ /***************************** Prototypes *****************************/ +int stdma_try_lock(irq_handler_t, void *); void stdma_lock(irq_handler_t handler, void *data); void stdma_release( void ); -int stdma_others_waiting( void ); int stdma_islocked( void ); -void *stdma_locked_by( void ); +int stdma_is_locked_by(irq_handler_t); void stdma_init( void ); /************************* End of Prototypes **************************/ diff --git a/arch/m68k/include/asm/macintosh.h b/arch/m68k/include/asm/macintosh.h index d323b2c2d07d..29c7c6c3a5f2 100644 --- a/arch/m68k/include/asm/macintosh.h +++ b/arch/m68k/include/asm/macintosh.h @@ -53,6 +53,10 @@ struct mac_model #define MAC_SCSI_QUADRA 2 #define MAC_SCSI_QUADRA2 3 #define MAC_SCSI_QUADRA3 4 +#define MAC_SCSI_IIFX 5 +#define MAC_SCSI_DUO 6 +#define MAC_SCSI_CCL 7 +#define MAC_SCSI_LATE 8 #define MAC_IDE_NONE 0 #define MAC_IDE_QUADRA 1 diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 4ef7a54813e6..75e75d7b1702 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -4,7 +4,7 @@ #include <uapi/asm/unistd.h> -#define NR_syscalls 354 +#define NR_syscalls 355 #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT diff --git a/arch/m68k/include/uapi/asm/unistd.h b/arch/m68k/include/uapi/asm/unistd.h index b419c6b7ac37..2c1bec9a14b6 100644 --- a/arch/m68k/include/uapi/asm/unistd.h +++ b/arch/m68k/include/uapi/asm/unistd.h @@ -359,5 +359,6 @@ #define __NR_renameat2 351 #define __NR_getrandom 352 #define __NR_memfd_create 353 +#define __NR_bpf 354 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */ diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 05b46c2b08b8..2ca219e184cd 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -374,4 +374,5 @@ ENTRY(sys_call_table) .long sys_renameat2 .long sys_getrandom .long sys_memfd_create + .long sys_bpf diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index a471eab1a4dd..e9c3756139fc 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -278,7 +278,7 @@ static struct mac_model mac_data_table[] = { .name = "IIfx", .adb_type = MAC_ADB_IOP, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_IIFX, .scc_type = MAC_SCC_IOP, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_IOP, @@ -329,7 +329,7 @@ static struct mac_model mac_data_table[] = { .name = "Color Classic", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_CCL, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -338,7 +338,7 @@ static struct mac_model mac_data_table[] = { .name = "Color Classic II", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_CCL, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -526,7 +526,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 520", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_CCL, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -535,7 +535,7 @@ static struct mac_model mac_data_table[] = { .name = "Performa 550", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_CCL, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -567,7 +567,7 @@ static struct mac_model mac_data_table[] = { .name = "TV", .adb_type = MAC_ADB_CUDA, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_CCL, .scc_type = MAC_SCC_II, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -712,7 +712,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook 190", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_QUADRA, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LATE, .ide_type = MAC_IDE_BABOON, .scc_type = MAC_SCC_QUADRA, .nubus_type = MAC_NUBUS, @@ -722,7 +722,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook 520", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_QUADRA, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_LATE, .scc_type = MAC_SCC_QUADRA, .ether_type = MAC_ETHER_SONIC, .nubus_type = MAC_NUBUS, @@ -740,7 +740,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook Duo 210", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -749,7 +749,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook Duo 230", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -758,7 +758,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook Duo 250", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -767,7 +767,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook Duo 270c", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -776,7 +776,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook Duo 280", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -785,7 +785,7 @@ static struct mac_model mac_data_table[] = { .name = "PowerBook Duo 280c", .adb_type = MAC_ADB_PB2, .via_type = MAC_VIA_IICI, - .scsi_type = MAC_SCSI_OLD, + .scsi_type = MAC_SCSI_DUO, .scc_type = MAC_SCC_QUADRA, .nubus_type = MAC_NUBUS, .floppy_type = MAC_FLOPPY_SWIM_ADDR2, @@ -929,6 +929,70 @@ static struct platform_device swim_pdev = { .resource = &swim_rsrc, }; +static const struct resource mac_scsi_iifx_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_MAC_SCSI, + .end = IRQ_MAC_SCSI, + }, { + .flags = IORESOURCE_MEM, + .start = 0x50008000, + .end = 0x50009FFF, + }, +}; + +static const struct resource mac_scsi_duo_rsrc[] __initconst = { + { + .flags = IORESOURCE_MEM, + .start = 0xFEE02000, + .end = 0xFEE03FFF, + }, +}; + +static const struct resource mac_scsi_old_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_MAC_SCSI, + .end = IRQ_MAC_SCSI, + }, { + .flags = IORESOURCE_MEM, + .start = 0x50010000, + .end = 0x50011FFF, + }, { + .flags = IORESOURCE_MEM, + .start = 0x50006000, + .end = 0x50007FFF, + }, +}; + +static const struct resource mac_scsi_late_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_MAC_SCSI, + .end = IRQ_MAC_SCSI, + }, { + .flags = IORESOURCE_MEM, + .start = 0x50010000, + .end = 0x50011FFF, + }, +}; + +static const struct resource mac_scsi_ccl_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = IRQ_MAC_SCSI, + .end = IRQ_MAC_SCSI, + }, { + .flags = IORESOURCE_MEM, + .start = 0x50F10000, + .end = 0x50F11FFF, + }, { + .flags = IORESOURCE_MEM, + .start = 0x50F06000, + .end = 0x50F07FFF, + }, +}; + static struct platform_device esp_0_pdev = { .name = "mac_esp", .id = 0, @@ -1000,6 +1064,60 @@ int __init mac_platform_init(void) (macintosh_config->ident == MAC_MODEL_Q950)) platform_device_register(&esp_1_pdev); break; + case MAC_SCSI_IIFX: + /* Addresses from The Guide to Mac Family Hardware. + * $5000 8000 - $5000 9FFF: SCSI DMA + * $5000 C000 - $5000 DFFF: Alternate SCSI (DMA) + * $5000 E000 - $5000 FFFF: Alternate SCSI (Hsk) + * The SCSI DMA custom IC embeds the 53C80 core. mac_scsi does + * not make use of its DMA or hardware handshaking logic. + */ + platform_device_register_simple("mac_scsi", 0, + mac_scsi_iifx_rsrc, ARRAY_SIZE(mac_scsi_iifx_rsrc)); + break; + case MAC_SCSI_DUO: + /* Addresses from the Duo Dock II Developer Note. + * $FEE0 2000 - $FEE0 3FFF: normal mode + * $FEE0 4000 - $FEE0 5FFF: pseudo DMA without /DRQ + * $FEE0 6000 - $FEE0 7FFF: pseudo DMA with /DRQ + * The NetBSD code indicates that both 5380 chips share + * an IRQ (?) which would need careful handling (see mac_esp). + */ + platform_device_register_simple("mac_scsi", 1, + mac_scsi_duo_rsrc, ARRAY_SIZE(mac_scsi_duo_rsrc)); + /* fall through */ + case MAC_SCSI_OLD: + /* Addresses from Developer Notes for Duo System, + * PowerBook 180 & 160, 140 & 170, Macintosh IIsi + * and also from The Guide to Mac Family Hardware for + * SE/30, II, IIx, IIcx, IIci. + * $5000 6000 - $5000 7FFF: pseudo-DMA with /DRQ + * $5001 0000 - $5001 1FFF: normal mode + * $5001 2000 - $5001 3FFF: pseudo-DMA without /DRQ + * GMFH says that $5000 0000 - $50FF FFFF "wraps + * $5000 0000 - $5001 FFFF eight times" (!) + * mess.org says IIci and Color Classic do not alias + * I/O address space. + */ + platform_device_register_simple("mac_scsi", 0, + mac_scsi_old_rsrc, ARRAY_SIZE(mac_scsi_old_rsrc)); + break; + case MAC_SCSI_LATE: + /* PDMA logic in 68040 PowerBooks is somehow different to + * '030 models. It's probably more like Quadras (see mac_esp). + */ + platform_device_register_simple("mac_scsi", 0, + mac_scsi_late_rsrc, ARRAY_SIZE(mac_scsi_late_rsrc)); + break; + case MAC_SCSI_CCL: + /* Addresses from the Color Classic Developer Note. + * $50F0 6000 - $50F0 7FFF: SCSI handshake + * $50F1 0000 - $50F1 1FFF: SCSI + * $50F1 2000 - $50F1 3FFF: SCSI DMA + */ + platform_device_register_simple("mac_scsi", 0, + mac_scsi_ccl_rsrc, ARRAY_SIZE(mac_scsi_ccl_rsrc)); + break; } /* diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index acaff6a49e35..b09a3cb29b68 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -94,7 +94,6 @@ void __init paging_init(void) high_memory = (void *) end_mem; empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); - memset(empty_zero_page, 0, PAGE_SIZE); /* * Set up SFC/DFC registers (user data space). diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index f59ec58083f8..a8b942bf7163 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -16,6 +16,7 @@ #include <linux/console.h> #include <linux/init.h> #include <linux/bootmem.h> +#include <linux/platform_device.h> #include <asm/oplib.h> #include <asm/setup.h> @@ -27,6 +28,7 @@ #include <asm/sun3mmu.h> #include <asm/rtc.h> #include <asm/machdep.h> +#include <asm/machines.h> #include <asm/idprom.h> #include <asm/intersil.h> #include <asm/irq.h> @@ -169,3 +171,61 @@ static void __init sun3_sched_init(irq_handler_t timer_routine) intersil_clear(); } +#ifdef CONFIG_SUN3_SCSI + +static const struct resource sun3_scsi_vme_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = SUN3_VEC_VMESCSI0, + .end = SUN3_VEC_VMESCSI0, + }, { + .flags = IORESOURCE_MEM, + .start = 0xff200000, + .end = 0xff200021, + }, { + .flags = IORESOURCE_IRQ, + .start = SUN3_VEC_VMESCSI1, + .end = SUN3_VEC_VMESCSI1, + }, { + .flags = IORESOURCE_MEM, + .start = 0xff204000, + .end = 0xff204021, + }, +}; + +/* + * Int: level 2 autovector + * IO: type 1, base 0x00140000, 5 bits phys space: A<4..0> + */ +static const struct resource sun3_scsi_rsrc[] __initconst = { + { + .flags = IORESOURCE_IRQ, + .start = 2, + .end = 2, + }, { + .flags = IORESOURCE_MEM, + .start = 0x00140000, + .end = 0x0014001f, + }, +}; + +int __init sun3_platform_init(void) +{ + switch (idprom->id_machtype) { + case SM_SUN3 | SM_3_160: + case SM_SUN3 | SM_3_260: + platform_device_register_simple("sun3_scsi_vme", -1, + sun3_scsi_vme_rsrc, ARRAY_SIZE(sun3_scsi_vme_rsrc)); + break; + case SM_SUN3 | SM_3_50: + case SM_SUN3 | SM_3_60: + platform_device_register_simple("sun3_scsi", -1, + sun3_scsi_rsrc, ARRAY_SIZE(sun3_scsi_rsrc)); + break; + } + return 0; +} + +arch_initcall(sun3_platform_init); + +#endif diff --git a/arch/microblaze/include/asm/tlb.h b/arch/microblaze/include/asm/tlb.h index 8aa97817cc8c..99b6ded54849 100644 --- a/arch/microblaze/include/asm/tlb.h +++ b/arch/microblaze/include/asm/tlb.h @@ -14,7 +14,6 @@ #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) #include <linux/pagemap.h> -#include <asm-generic/tlb.h> #ifdef CONFIG_MMU #define tlb_start_vma(tlb, vma) do { } while (0) @@ -22,4 +21,6 @@ #define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0) #endif +#include <asm-generic/tlb.h> + #endif /* _ASM_MICROBLAZE_TLB_H */ diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f43aa536c517..9536ef912f59 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2101,9 +2101,17 @@ config 64BIT_PHYS_ADDR config ARCH_PHYS_ADDR_T_64BIT def_bool 64BIT_PHYS_ADDR +choice + prompt "SmartMIPS or microMIPS ASE support" + +config CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS + bool "None" + help + Select this if you want neither microMIPS nor SmartMIPS support + config CPU_HAS_SMARTMIPS depends on SYS_SUPPORTS_SMARTMIPS - bool "Support for the SmartMIPS ASE" + bool "SmartMIPS" help SmartMIPS is a extension of the MIPS32 architecture aimed at increased security at both hardware and software level for @@ -2115,11 +2123,13 @@ config CPU_HAS_SMARTMIPS config CPU_MICROMIPS depends on SYS_SUPPORTS_MICROMIPS - bool "Build kernel using microMIPS ISA" + bool "microMIPS" help When this option is enabled the kernel will be built using the microMIPS ISA +endchoice + config CPU_HAS_MSA bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)" depends on CPU_SUPPORTS_MSA diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 23cb94806fbc..58076472bdd8 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -93,6 +93,15 @@ LDFLAGS_vmlinux += -G 0 -static -n -nostdlib KBUILD_AFLAGS_MODULE += -mlong-calls KBUILD_CFLAGS_MODULE += -mlong-calls +# +# pass -msoft-float to GAS if it supports it. However on newer binutils +# (specifically newer than 2.24.51.20140728) we then also need to explicitly +# set ".set hardfloat" in all files which manipulate floating point registers. +# +ifneq ($(call as-option,-Wa$(comma)-msoft-float,),) + cflags-y += -DGAS_HAS_SET_HARDFLOAT -Wa,-msoft-float +endif + cflags-y += -ffreestanding # diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 741734049675..2bc4aa95944e 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -809,6 +809,7 @@ static struct irq_chip octeon_irq_chip_ciu_gpio_v2 = { .irq_set_type = octeon_irq_ciu_gpio_set_type, #ifdef CONFIG_SMP .irq_set_affinity = octeon_irq_ciu_set_affinity_v2, + .irq_cpu_offline = octeon_irq_cpu_offline_ciu, #endif .flags = IRQCHIP_SET_TYPE_MASKED, }; @@ -823,6 +824,7 @@ static struct irq_chip octeon_irq_chip_ciu_gpio = { .irq_set_type = octeon_irq_ciu_gpio_set_type, #ifdef CONFIG_SMP .irq_set_affinity = octeon_irq_ciu_set_affinity, + .irq_cpu_offline = octeon_irq_cpu_offline_ciu, #endif .flags = IRQCHIP_SET_TYPE_MASKED, }; diff --git a/arch/mips/include/asm/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h index e38c2811d4e2..cdac7b3eeaf7 100644 --- a/arch/mips/include/asm/asmmacro-32.h +++ b/arch/mips/include/asm/asmmacro-32.h @@ -13,6 +13,8 @@ #include <asm/mipsregs.h> .macro fpu_save_single thread tmp=t0 + .set push + SET_HARDFLOAT cfc1 \tmp, fcr31 swc1 $f0, THREAD_FPR0_LS64(\thread) swc1 $f1, THREAD_FPR1_LS64(\thread) @@ -47,9 +49,12 @@ swc1 $f30, THREAD_FPR30_LS64(\thread) swc1 $f31, THREAD_FPR31_LS64(\thread) sw \tmp, THREAD_FCR31(\thread) + .set pop .endm .macro fpu_restore_single thread tmp=t0 + .set push + SET_HARDFLOAT lw \tmp, THREAD_FCR31(\thread) lwc1 $f0, THREAD_FPR0_LS64(\thread) lwc1 $f1, THREAD_FPR1_LS64(\thread) @@ -84,6 +89,7 @@ lwc1 $f30, THREAD_FPR30_LS64(\thread) lwc1 $f31, THREAD_FPR31_LS64(\thread) ctc1 \tmp, fcr31 + .set pop .endm .macro cpu_save_nonscratch thread diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index cd9a98bc8f60..6caf8766b80f 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -57,6 +57,8 @@ #endif /* CONFIG_CPU_MIPSR2 */ .macro fpu_save_16even thread tmp=t0 + .set push + SET_HARDFLOAT cfc1 \tmp, fcr31 sdc1 $f0, THREAD_FPR0_LS64(\thread) sdc1 $f2, THREAD_FPR2_LS64(\thread) @@ -75,11 +77,13 @@ sdc1 $f28, THREAD_FPR28_LS64(\thread) sdc1 $f30, THREAD_FPR30_LS64(\thread) sw \tmp, THREAD_FCR31(\thread) + .set pop .endm .macro fpu_save_16odd thread .set push .set mips64r2 + SET_HARDFLOAT sdc1 $f1, THREAD_FPR1_LS64(\thread) sdc1 $f3, THREAD_FPR3_LS64(\thread) sdc1 $f5, THREAD_FPR5_LS64(\thread) @@ -110,6 +114,8 @@ .endm .macro fpu_restore_16even thread tmp=t0 + .set push + SET_HARDFLOAT lw \tmp, THREAD_FCR31(\thread) ldc1 $f0, THREAD_FPR0_LS64(\thread) ldc1 $f2, THREAD_FPR2_LS64(\thread) @@ -133,6 +139,7 @@ .macro fpu_restore_16odd thread .set push .set mips64r2 + SET_HARDFLOAT ldc1 $f1, THREAD_FPR1_LS64(\thread) ldc1 $f3, THREAD_FPR3_LS64(\thread) ldc1 $f5, THREAD_FPR5_LS64(\thread) @@ -277,6 +284,7 @@ .macro cfcmsa rd, cs .set push .set noat + SET_HARDFLOAT .insn .word CFC_MSA_INSN | (\cs << 11) move \rd, $1 @@ -286,6 +294,7 @@ .macro ctcmsa cd, rs .set push .set noat + SET_HARDFLOAT move $1, \rs .word CTC_MSA_INSN | (\cd << 6) .set pop @@ -294,6 +303,7 @@ .macro ld_d wd, off, base .set push .set noat + SET_HARDFLOAT add $1, \base, \off .word LDD_MSA_INSN | (\wd << 6) .set pop @@ -302,6 +312,7 @@ .macro st_d wd, off, base .set push .set noat + SET_HARDFLOAT add $1, \base, \off .word STD_MSA_INSN | (\wd << 6) .set pop @@ -310,6 +321,7 @@ .macro copy_u_w rd, ws, n .set push .set noat + SET_HARDFLOAT .insn .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11) /* move triggers an assembler bug... */ @@ -320,6 +332,7 @@ .macro copy_u_d rd, ws, n .set push .set noat + SET_HARDFLOAT .insn .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11) /* move triggers an assembler bug... */ @@ -330,6 +343,7 @@ .macro insert_w wd, n, rs .set push .set noat + SET_HARDFLOAT /* move triggers an assembler bug... */ or $1, \rs, zero .word INSERT_W_MSA_INSN | (\n << 16) | (\wd << 6) @@ -339,6 +353,7 @@ .macro insert_d wd, n, rs .set push .set noat + SET_HARDFLOAT /* move triggers an assembler bug... */ or $1, \rs, zero .word INSERT_D_MSA_INSN | (\n << 16) | (\wd << 6) @@ -381,6 +396,7 @@ st_d 31, THREAD_FPR31, \thread .set push .set noat + SET_HARDFLOAT cfcmsa $1, MSA_CSR sw $1, THREAD_MSA_CSR(\thread) .set pop @@ -389,6 +405,7 @@ .macro msa_restore_all thread .set push .set noat + SET_HARDFLOAT lw $1, THREAD_MSA_CSR(\thread) ctcmsa MSA_CSR, $1 .set pop @@ -441,6 +458,7 @@ .macro msa_init_all_upper .set push .set noat + SET_HARDFLOAT not $1, zero msa_init_upper 0 .set pop diff --git a/arch/mips/include/asm/fpregdef.h b/arch/mips/include/asm/fpregdef.h index 429481f9028d..f184ba088532 100644 --- a/arch/mips/include/asm/fpregdef.h +++ b/arch/mips/include/asm/fpregdef.h @@ -14,6 +14,20 @@ #include <asm/sgidefs.h> +/* + * starting with binutils 2.24.51.20140729, MIPS binutils warn about mixing + * hardfloat and softfloat object files. The kernel build uses soft-float by + * default, so we also need to pass -msoft-float along to GAS if it supports it. + * But this in turn causes assembler errors in files which access hardfloat + * registers. We detect if GAS supports "-msoft-float" in the Makefile and + * explicitly put ".set hardfloat" where floating point registers are touched. + */ +#ifdef GAS_HAS_SET_HARDFLOAT +#define SET_HARDFLOAT .set hardfloat +#else +#define SET_HARDFLOAT +#endif + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 4d0aeda68397..dd562414cd5e 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -145,8 +145,8 @@ static inline void lose_fpu(int save) if (is_msa_enabled()) { if (save) { save_msa(current); - asm volatile("cfc1 %0, $31" - : "=r"(current->thread.fpu.fcr31)); + current->thread.fpu.fcr31 = + read_32bit_cp1_register(CP1_STATUS); } disable_msa(); clear_thread_flag(TIF_USEDMSA); diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h index e194f957ca8c..fdbff44e5482 100644 --- a/arch/mips/include/asm/jump_label.h +++ b/arch/mips/include/asm/jump_label.h @@ -20,9 +20,15 @@ #define WORD_INSN ".word" #endif +#ifdef CONFIG_CPU_MICROMIPS +#define NOP_INSN "nop32" +#else +#define NOP_INSN "nop" +#endif + static __always_inline bool arch_static_branch(struct static_key *key) { - asm_volatile_goto("1:\tnop\n\t" + asm_volatile_goto("1:\t" NOP_INSN "\n\t" "nop\n\t" ".pushsection __jump_table, \"aw\"\n\t" WORD_INSN " 1b, %l[l_yes], %0\n\t" diff --git a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h index 7d28f95b0512..6d69332f21ec 100644 --- a/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-loongson/cpu-feature-overrides.h @@ -41,10 +41,8 @@ #define cpu_has_mcheck 0 #define cpu_has_mdmx 0 #define cpu_has_mips16 0 -#define cpu_has_mips32r1 0 #define cpu_has_mips32r2 0 #define cpu_has_mips3d 0 -#define cpu_has_mips64r1 0 #define cpu_has_mips64r2 0 #define cpu_has_mipsmt 0 #define cpu_has_prefetch 0 diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index cf3b580c3df6..22a135ac91de 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -661,6 +661,8 @@ #define MIPS_CONF6_SYND (_ULCAST_(1) << 13) /* proAptiv FTLB on/off bit */ #define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15) +/* FTLB probability bits */ +#define MIPS_CONF6_FTLBP_SHIFT (16) #define MIPS_CONF7_WII (_ULCAST_(1) << 31) @@ -1324,7 +1326,7 @@ do { \ /* * Macros to access the floating point coprocessor control registers */ -#define read_32bit_cp1_register(source) \ +#define _read_32bit_cp1_register(source, gas_hardfloat) \ ({ \ int __res; \ \ @@ -1334,12 +1336,21 @@ do { \ " # gas fails to assemble cfc1 for some archs, \n" \ " # like Octeon. \n" \ " .set mips1 \n" \ + " "STR(gas_hardfloat)" \n" \ " cfc1 %0,"STR(source)" \n" \ " .set pop \n" \ : "=r" (__res)); \ __res; \ }) +#ifdef GAS_HAS_SET_HARDFLOAT +#define read_32bit_cp1_register(source) \ + _read_32bit_cp1_register(source, .set hardfloat) +#else +#define read_32bit_cp1_register(source) \ + _read_32bit_cp1_register(source, ) +#endif + #ifdef HAVE_AS_DSP #define rddsp(mask) \ ({ \ diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index 4520adc8699b..cd6e0afc6833 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -257,7 +257,11 @@ static inline void protected_flush_icache_line(unsigned long addr) */ static inline void protected_writeback_dcache_line(unsigned long addr) { +#ifdef CONFIG_EVA + protected_cachee_op(Hit_Writeback_Inv_D, addr); +#else protected_cache_op(Hit_Writeback_Inv_D, addr); +#endif } static inline void protected_writeback_scache_line(unsigned long addr) diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index a10951090234..22a5624e2fd2 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -301,7 +301,8 @@ do { \ __get_kernel_common((x), size, __gu_ptr); \ else \ __get_user_common((x), size, __gu_ptr); \ - } \ + } else \ + (x) = 0; \ \ __gu_err; \ }) @@ -316,6 +317,7 @@ do { \ " .insn \n" \ " .section .fixup,\"ax\" \n" \ "3: li %0, %4 \n" \ + " move %1, $0 \n" \ " j 2b \n" \ " .previous \n" \ " .section __ex_table,\"a\" \n" \ @@ -630,6 +632,7 @@ do { \ " .insn \n" \ " .section .fixup,\"ax\" \n" \ "3: li %0, %4 \n" \ + " move %1, $0 \n" \ " j 2b \n" \ " .previous \n" \ " .section __ex_table,\"a\" \n" \ @@ -773,10 +776,11 @@ extern void __put_user_unaligned_unknown(void); "jal\t" #destination "\n\t" #endif -#ifndef CONFIG_CPU_DADDI_WORKAROUNDS -#define DADDI_SCRATCH "$0" -#else +#if defined(CONFIG_CPU_DADDI_WORKAROUNDS) || (defined(CONFIG_EVA) && \ + defined(CONFIG_CPU_HAS_PREFETCH)) #define DADDI_SCRATCH "$3" +#else +#define DADDI_SCRATCH "$0" #endif extern size_t __copy_user(void *__to, const void *__from, size_t __n); @@ -1418,7 +1422,7 @@ static inline long __strnlen_user(const char __user *s, long n) } /* - * strlen_user: - Get the size of a string in user space. + * strnlen_user: - Get the size of a string in user space. * @str: The string to measure. * * Context: User context only. This function may sleep. @@ -1427,9 +1431,7 @@ static inline long __strnlen_user(const char __user *s, long n) * * Returns the size of the string INCLUDING the terminating NUL. * On exception, returns 0. - * - * If there is a limit on the length of a valid string, you may wish to - * consider using strnlen_user() instead. + * If the string is too long, returns a value greater than @n. */ static inline long strnlen_user(const char __user *s, long n) { diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h index fdb4923777d1..d001bb1ad177 100644 --- a/arch/mips/include/uapi/asm/unistd.h +++ b/arch/mips/include/uapi/asm/unistd.h @@ -375,16 +375,17 @@ #define __NR_seccomp (__NR_Linux + 352) #define __NR_getrandom (__NR_Linux + 353) #define __NR_memfd_create (__NR_Linux + 354) +#define __NR_bpf (__NR_Linux + 355) /* * Offset of the last Linux o32 flavoured syscall */ -#define __NR_Linux_syscalls 354 +#define __NR_Linux_syscalls 355 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ #define __NR_O32_Linux 4000 -#define __NR_O32_Linux_syscalls 354 +#define __NR_O32_Linux_syscalls 355 #if _MIPS_SIM == _MIPS_SIM_ABI64 @@ -707,16 +708,17 @@ #define __NR_seccomp (__NR_Linux + 312) #define __NR_getrandom (__NR_Linux + 313) #define __NR_memfd_create (__NR_Linux + 314) +#define __NR_bpf (__NR_Linux + 315) /* * Offset of the last Linux 64-bit flavoured syscall */ -#define __NR_Linux_syscalls 314 +#define __NR_Linux_syscalls 315 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ #define __NR_64_Linux 5000 -#define __NR_64_Linux_syscalls 314 +#define __NR_64_Linux_syscalls 315 #if _MIPS_SIM == _MIPS_SIM_NABI32 @@ -1043,15 +1045,16 @@ #define __NR_seccomp (__NR_Linux + 316) #define __NR_getrandom (__NR_Linux + 317) #define __NR_memfd_create (__NR_Linux + 318) +#define __NR_bpf (__NR_Linux + 319) /* * Offset of the last N32 flavoured syscall */ -#define __NR_Linux_syscalls 318 +#define __NR_Linux_syscalls 319 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ #define __NR_N32_Linux 6000 -#define __NR_N32_Linux_syscalls 318 +#define __NR_N32_Linux_syscalls 319 #endif /* _UAPI_ASM_UNISTD_H */ diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S index 290c23b51678..86495072a922 100644 --- a/arch/mips/kernel/bmips_vec.S +++ b/arch/mips/kernel/bmips_vec.S @@ -208,7 +208,6 @@ bmips_reset_nmi_vec_end: END(bmips_reset_nmi_vec) .set pop - .previous /*********************************************************************** * CPU1 warm restart vector (used for second and subsequent boots). @@ -281,5 +280,3 @@ LEAF(bmips_enable_xks01) jr ra END(bmips_enable_xks01) - - .previous diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 7b2df224f041..4d7d99d601cc 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -144,7 +144,7 @@ int __mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, case mm_bc1t_op: preempt_disable(); if (is_fpu_owner()) - asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); + fcr31 = read_32bit_cp1_register(CP1_STATUS); else fcr31 = current->thread.fpu.fcr31; preempt_enable(); @@ -562,11 +562,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs, case cop1_op: preempt_disable(); if (is_fpu_owner()) - asm volatile( - ".set push\n" - "\t.set mips1\n" - "\tcfc1\t%0,$31\n" - "\t.set pop" : "=r" (fcr31)); + fcr31 = read_32bit_cp1_register(CP1_STATUS); else fcr31 = current->thread.fpu.fcr31; preempt_enable(); diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index e6e97d2a5c9e..0384b05ab5a0 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -229,6 +229,7 @@ LEAF(mips_cps_core_init) nop .set push + .set mips32r2 .set mt /* Only allow 1 TC per VPE to execute... */ @@ -345,6 +346,7 @@ LEAF(mips_cps_boot_vpes) nop .set push + .set mips32r2 .set mt 1: /* Enter VPE configuration state */ diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 94c4a0c0a577..dc49cf30c2db 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -193,6 +193,32 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa) static char unknown_isa[] = KERN_ERR \ "Unsupported ISA type, c0.config0: %d."; +static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) +{ + + unsigned int probability = c->tlbsize / c->tlbsizevtlb; + + /* + * 0 = All TLBWR instructions go to FTLB + * 1 = 15:1: For every 16 TBLWR instructions, 15 go to the + * FTLB and 1 goes to the VTLB. + * 2 = 7:1: As above with 7:1 ratio. + * 3 = 3:1: As above with 3:1 ratio. + * + * Use the linear midpoint as the probability threshold. + */ + if (probability >= 12) + return 1; + else if (probability >= 6) + return 2; + else + /* + * So FTLB is less than 4 times bigger than VTLB. + * A 3:1 ratio can still be useful though. + */ + return 3; +} + static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) { unsigned int config6; @@ -203,9 +229,14 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) case CPU_P5600: /* proAptiv & related cores use Config6 to enable the FTLB */ config6 = read_c0_config6(); + /* Clear the old probability value */ + config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); if (enable) /* Enable FTLB */ - write_c0_config6(config6 | MIPS_CONF6_FTLBEN); + write_c0_config6(config6 | + (calculate_ftlb_probability(c) + << MIPS_CONF6_FTLBP_SHIFT) + | MIPS_CONF6_FTLBEN); else /* Disable FTLB */ write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); @@ -757,31 +788,34 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_LOONGSON2; __cpu_name[cpu] = "ICT Loongson-2"; set_elf_platform(cpu, "loongson2e"); + set_isa(c, MIPS_CPU_ISA_III); break; case PRID_REV_LOONGSON2F: c->cputype = CPU_LOONGSON2; __cpu_name[cpu] = "ICT Loongson-2"; set_elf_platform(cpu, "loongson2f"); + set_isa(c, MIPS_CPU_ISA_III); break; case PRID_REV_LOONGSON3A: c->cputype = CPU_LOONGSON3; - c->writecombine = _CACHE_UNCACHED_ACCELERATED; __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3a"); + set_isa(c, MIPS_CPU_ISA_M64R1); break; case PRID_REV_LOONGSON3B_R1: case PRID_REV_LOONGSON3B_R2: c->cputype = CPU_LOONGSON3; __cpu_name[cpu] = "ICT Loongson-3"; set_elf_platform(cpu, "loongson3b"); + set_isa(c, MIPS_CPU_ISA_M64R1); break; } - set_isa(c, MIPS_CPU_ISA_III); c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC | MIPS_CPU_32FPR; c->tlbsize = 64; + c->writecombine = _CACHE_UNCACHED_ACCELERATED; break; case PRID_IMP_LOONGSON_32: /* Loongson-1 */ decode_configs(c); diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index ac35e12cb1f3..a5e26dd90592 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -358,6 +358,7 @@ NESTED(nmi_handler, PT_SIZE, sp) .set push /* gas fails to assemble cfc1 for some archs (octeon).*/ \ .set mips1 + SET_HARDFLOAT cfc1 a1, fcr31 li a2, ~(0x3f << 12) and a2, a1 diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c index 6001610cfe55..dda800e9e731 100644 --- a/arch/mips/kernel/jump_label.c +++ b/arch/mips/kernel/jump_label.c @@ -18,31 +18,53 @@ #ifdef HAVE_JUMP_LABEL -#define J_RANGE_MASK ((1ul << 28) - 1) +/* + * Define parameters for the standard MIPS and the microMIPS jump + * instruction encoding respectively: + * + * - the ISA bit of the target, either 0 or 1 respectively, + * + * - the amount the jump target address is shifted right to fit in the + * immediate field of the machine instruction, either 2 or 1, + * + * - the mask determining the size of the jump region relative to the + * delay-slot instruction, either 256MB or 128MB, + * + * - the jump target alignment, either 4 or 2 bytes. + */ +#define J_ISA_BIT IS_ENABLED(CONFIG_CPU_MICROMIPS) +#define J_RANGE_SHIFT (2 - J_ISA_BIT) +#define J_RANGE_MASK ((1ul << (26 + J_RANGE_SHIFT)) - 1) +#define J_ALIGN_MASK ((1ul << J_RANGE_SHIFT) - 1) void arch_jump_label_transform(struct jump_entry *e, enum jump_label_type type) { + union mips_instruction *insn_p; union mips_instruction insn; - union mips_instruction *insn_p = - (union mips_instruction *)(unsigned long)e->code; - /* Jump only works within a 256MB aligned region. */ - BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK)); + insn_p = (union mips_instruction *)msk_isa16_mode(e->code); + + /* Jump only works within an aligned region its delay slot is in. */ + BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK)); - /* Target must have 4 byte alignment. */ - BUG_ON((e->target & 3) != 0); + /* Target must have the right alignment and ISA must be preserved. */ + BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT); if (type == JUMP_LABEL_ENABLE) { - insn.j_format.opcode = j_op; - insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; + insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op; + insn.j_format.target = e->target >> J_RANGE_SHIFT; } else { insn.word = 0; /* nop */ } get_online_cpus(); mutex_lock(&text_mutex); - *insn_p = insn; + if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) { + insn_p->halfword[0] = insn.word >> 16; + insn_p->halfword[1] = insn.word; + } else + *insn_p = insn; flush_icache_range((unsigned long)insn_p, (unsigned long)insn_p + sizeof(*insn_p)); diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S index f31063dbdaeb..5ce3b746cedc 100644 --- a/arch/mips/kernel/r2300_fpu.S +++ b/arch/mips/kernel/r2300_fpu.S @@ -28,6 +28,8 @@ .set mips1 /* Save floating point context */ LEAF(_save_fp_context) + .set push + SET_HARDFLOAT li v0, 0 # assume success cfc1 t1,fcr31 EX(swc1 $f0,(SC_FPREGS+0)(a0)) @@ -65,6 +67,7 @@ LEAF(_save_fp_context) EX(sw t1,(SC_FPC_CSR)(a0)) cfc1 t0,$0 # implementation/version jr ra + .set pop .set nomacro EX(sw t0,(SC_FPC_EIR)(a0)) .set macro @@ -80,6 +83,8 @@ LEAF(_save_fp_context) * stack frame which might have been changed by the user. */ LEAF(_restore_fp_context) + .set push + SET_HARDFLOAT li v0, 0 # assume success EX(lw t0,(SC_FPC_CSR)(a0)) EX(lwc1 $f0,(SC_FPREGS+0)(a0)) @@ -116,6 +121,7 @@ LEAF(_restore_fp_context) EX(lwc1 $f31,(SC_FPREGS+248)(a0)) jr ra ctc1 t0,fcr31 + .set pop END(_restore_fp_context) .set reorder diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index 20b7b040e76f..435ea652f5fa 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S @@ -120,6 +120,9 @@ LEAF(_restore_fp) #define FPU_DEFAULT 0x00000000 + .set push + SET_HARDFLOAT + LEAF(_init_fpu) mfc0 t0, CP0_STATUS li t1, ST0_CU1 @@ -165,3 +168,5 @@ LEAF(_init_fpu) mtc1 t0, $f31 jr ra END(_init_fpu) + + .set pop diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 8352523568e6..6c160c67984c 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -19,8 +19,12 @@ #include <asm/asm-offsets.h> #include <asm/regdef.h> +/* preprocessor replaces the fp in ".set fp=64" with $30 otherwise */ +#undef fp + .macro EX insn, reg, src .set push + SET_HARDFLOAT .set nomacro .ex\@: \insn \reg, \src .set pop @@ -33,12 +37,17 @@ .set arch=r4000 LEAF(_save_fp_context) + .set push + SET_HARDFLOAT cfc1 t1, fcr31 + .set pop #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) .set push + SET_HARDFLOAT #ifdef CONFIG_CPU_MIPS32_R2 - .set mips64r2 + .set mips32r2 + .set fp=64 mfc0 t0, CP0_STATUS sll t0, t0, 5 bgez t0, 1f # skip storing odd if FR=0 @@ -64,6 +73,8 @@ LEAF(_save_fp_context) 1: .set pop #endif + .set push + SET_HARDFLOAT /* Store the 16 even double precision registers */ EX sdc1 $f0, SC_FPREGS+0(a0) EX sdc1 $f2, SC_FPREGS+16(a0) @@ -84,11 +95,14 @@ LEAF(_save_fp_context) EX sw t1, SC_FPC_CSR(a0) jr ra li v0, 0 # success + .set pop END(_save_fp_context) #ifdef CONFIG_MIPS32_COMPAT /* Save 32-bit process floating point context */ LEAF(_save_fp_context32) + .set push + SET_HARDFLOAT cfc1 t1, fcr31 mfc0 t0, CP0_STATUS @@ -134,6 +148,7 @@ LEAF(_save_fp_context32) EX sw t1, SC32_FPC_CSR(a0) cfc1 t0, $0 # implementation/version EX sw t0, SC32_FPC_EIR(a0) + .set pop jr ra li v0, 0 # success @@ -150,8 +165,10 @@ LEAF(_restore_fp_context) #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) .set push + SET_HARDFLOAT #ifdef CONFIG_CPU_MIPS32_R2 - .set mips64r2 + .set mips32r2 + .set fp=64 mfc0 t0, CP0_STATUS sll t0, t0, 5 bgez t0, 1f # skip loading odd if FR=0 @@ -175,6 +192,8 @@ LEAF(_restore_fp_context) EX ldc1 $f31, SC_FPREGS+248(a0) 1: .set pop #endif + .set push + SET_HARDFLOAT EX ldc1 $f0, SC_FPREGS+0(a0) EX ldc1 $f2, SC_FPREGS+16(a0) EX ldc1 $f4, SC_FPREGS+32(a0) @@ -192,6 +211,7 @@ LEAF(_restore_fp_context) EX ldc1 $f28, SC_FPREGS+224(a0) EX ldc1 $f30, SC_FPREGS+240(a0) ctc1 t1, fcr31 + .set pop jr ra li v0, 0 # success END(_restore_fp_context) @@ -199,6 +219,8 @@ LEAF(_restore_fp_context) #ifdef CONFIG_MIPS32_COMPAT LEAF(_restore_fp_context32) /* Restore an o32 sigcontext. */ + .set push + SET_HARDFLOAT EX lw t1, SC32_FPC_CSR(a0) mfc0 t0, CP0_STATUS @@ -242,6 +264,7 @@ LEAF(_restore_fp_context32) ctc1 t1, fcr31 jr ra li v0, 0 # success + .set pop END(_restore_fp_context32) #endif diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 4c4ec1812420..64591e671878 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -22,6 +22,9 @@ #include <asm/asmmacro.h> +/* preprocessor replaces the fp in ".set fp=64" with $30 otherwise */ +#undef fp + /* * Offset to the current process status flags, the first 32 bytes of the * stack are not used. @@ -65,8 +68,12 @@ bgtz a3, 1f /* Save 128b MSA vector context + scalar FP control & status. */ + .set push + SET_HARDFLOAT cfc1 t1, fcr31 msa_save_all a0 + .set pop /* SET_HARDFLOAT */ + sw t1, THREAD_FCR31(a0) b 2f @@ -161,6 +168,9 @@ LEAF(_init_msa_upper) #define FPU_DEFAULT 0x00000000 + .set push + SET_HARDFLOAT + LEAF(_init_fpu) mfc0 t0, CP0_STATUS li t1, ST0_CU1 @@ -232,7 +242,8 @@ LEAF(_init_fpu) #ifdef CONFIG_CPU_MIPS32_R2 .set push - .set mips64r2 + .set mips32r2 + .set fp=64 sll t0, t0, 5 # is Status.FR set? bgez t0, 1f # no: skip setting upper 32b @@ -291,3 +302,5 @@ LEAF(_init_fpu) #endif jr ra END(_init_fpu) + + .set pop /* SET_HARDFLOAT */ diff --git a/arch/mips/kernel/r6000_fpu.S b/arch/mips/kernel/r6000_fpu.S index da0fbe46d83b..47077380c15c 100644 --- a/arch/mips/kernel/r6000_fpu.S +++ b/arch/mips/kernel/r6000_fpu.S @@ -18,6 +18,9 @@ .set noreorder .set mips2 + .set push + SET_HARDFLOAT + /* Save floating point context */ LEAF(_save_fp_context) mfc0 t0,CP0_STATUS @@ -85,3 +88,5 @@ 1: jr ra nop END(_restore_fp_context) + + .set pop /* SET_HARDFLOAT */ diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 31b1b763cb29..c5c4fd54d797 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -94,12 +94,12 @@ int rtlx_open(int index, int can_sleep) int ret = 0; if (index >= RTLX_CHANNELS) { - pr_debug(KERN_DEBUG "rtlx_open index out of range\n"); + pr_debug("rtlx_open index out of range\n"); return -ENOSYS; } if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { - pr_debug(KERN_DEBUG "rtlx_open channel %d already opened\n", index); + pr_debug("rtlx_open channel %d already opened\n", index); ret = -EBUSY; goto out_fail; } diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 744cd10ba599..00cad1005a16 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -579,3 +579,4 @@ EXPORT(sys_call_table) PTR sys_seccomp PTR sys_getrandom PTR sys_memfd_create + PTR sys_bpf /* 4355 */ diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 002b1bc09c38..5251565e344b 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -434,4 +434,5 @@ EXPORT(sys_call_table) PTR sys_seccomp PTR sys_getrandom PTR sys_memfd_create + PTR sys_bpf /* 5315 */ .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index ca6cbbe9805b..77e74398b828 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -427,4 +427,5 @@ EXPORT(sysn32_call_table) PTR sys_seccomp PTR sys_getrandom PTR sys_memfd_create + PTR sys_bpf .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 9e10d11fbb84..6f8db9f728e8 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -564,4 +564,5 @@ EXPORT(sys32_call_table) PTR sys_seccomp PTR sys_getrandom PTR sys_memfd_create + PTR sys_bpf /* 4355 */ .size sys32_call_table,.-sys32_call_table diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index b3b8f0d9d4a7..f3b635f86c39 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -485,7 +485,7 @@ static void __init bootmem_init(void) * NOTE: historically plat_mem_setup did the entire platform initialization. * This was rather impractical because it meant plat_mem_setup had to * get away without any kind of memory allocator. To keep old code from - * breaking plat_setup was just renamed to plat_setup and a second platform + * breaking plat_setup was just renamed to plat_mem_setup and a second platform * initialization hook for anything else was introduced. */ @@ -493,7 +493,7 @@ static int usermem __initdata; static int __init early_parse_mem(char *p) { - unsigned long start, size; + phys_t start, size; /* * If a user specifies memory size, we @@ -683,7 +683,8 @@ static void __init arch_mem_init(char **cmdline_p) dma_contiguous_reserve(PFN_PHYS(max_low_pfn)); /* Tell bootmem about cma reserved memblock section */ for_each_memblock(reserved, reg) - reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT); + if (reg->size != 0) + reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT); } static void __init resource_init(void) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 1d57605e4615..16f1e4f2bf3c 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -658,13 +658,13 @@ static int signal_setup(void) save_fp_context = _save_fp_context; restore_fp_context = _restore_fp_context; } else { - save_fp_context = copy_fp_from_sigcontext; - restore_fp_context = copy_fp_to_sigcontext; + save_fp_context = copy_fp_to_sigcontext; + restore_fp_context = copy_fp_from_sigcontext; } #endif /* CONFIG_SMP */ #else - save_fp_context = copy_fp_from_sigcontext;; - restore_fp_context = copy_fp_to_sigcontext; + save_fp_context = copy_fp_to_sigcontext; + restore_fp_context = copy_fp_from_sigcontext; #endif return 0; diff --git a/arch/mips/lib/memcpy.S b/arch/mips/lib/memcpy.S index c17ef80cf65a..5d3238af9b5c 100644 --- a/arch/mips/lib/memcpy.S +++ b/arch/mips/lib/memcpy.S @@ -503,6 +503,7 @@ STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@) .Ldone\@: jr ra + nop .if __memcpy == 1 END(memcpy) .set __memcpy, 0 diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index 91615c2ef0cf..1ef365ab3cd3 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -34,7 +34,7 @@ static void dump_tlb(int first, int last) entrylo0 = read_c0_entrylo0(); /* Unused entries have a virtual address of KSEG0. */ - if ((entryhi & 0xffffe000) != 0x80000000 + if ((entryhi & 0xfffff000) != 0x80000000 && (entryhi & 0xfc0) == asid) { /* * Only print entries in use @@ -43,7 +43,7 @@ static void dump_tlb(int first, int last) printk("va=%08lx asid=%08lx" " [pa=%06lx n=%d d=%d v=%d g=%d]", - (entryhi & 0xffffe000), + (entryhi & 0xfffff000), entryhi & 0xfc0, entrylo0 & PAGE_MASK, (entrylo0 & (1 << 11)) ? 1 : 0, diff --git a/arch/mips/lib/strnlen_user.S b/arch/mips/lib/strnlen_user.S index f3af6995e2a6..7d12c0dded3d 100644 --- a/arch/mips/lib/strnlen_user.S +++ b/arch/mips/lib/strnlen_user.S @@ -40,9 +40,11 @@ FEXPORT(__strnlen_\func\()_nocheck_asm) .else EX(lbe, t0, (v0), .Lfault\@) .endif - PTR_ADDIU v0, 1 + .set noreorder bnez t0, 1b -1: PTR_SUBU v0, a0 +1: PTR_ADDIU v0, 1 + .set reorder + PTR_SUBU v0, a0 jr ra END(__strnlen_\func\()_asm) diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile index 0bb9cc9dc621..d87e03330b29 100644 --- a/arch/mips/loongson/common/Makefile +++ b/arch/mips/loongson/common/Makefile @@ -11,7 +11,8 @@ obj-$(CONFIG_PCI) += pci.o # Serial port support # obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_SERIAL_8250) += serial.o +loongson-serial-$(CONFIG_SERIAL_8250) := serial.o +obj-y += $(loongson-serial-m) $(loongson-serial-y) obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o obj-$(CONFIG_LOONGSON_MC146818) += rtc.o diff --git a/arch/mips/loongson/loongson-3/numa.c b/arch/mips/loongson/loongson-3/numa.c index 37ed184398c6..42323bcc5d28 100644 --- a/arch/mips/loongson/loongson-3/numa.c +++ b/arch/mips/loongson/loongson-3/numa.c @@ -33,6 +33,7 @@ static struct node_data prealloc__node_data[MAX_NUMNODES]; unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; +EXPORT_SYMBOL(__node_distances); struct node_data *__node_data[MAX_NUMNODES]; EXPORT_SYMBOL(__node_data); diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 51a0fde4bec1..cac529a405b8 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -584,11 +584,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, if (insn.i_format.rs == bc_op) { preempt_disable(); if (is_fpu_owner()) - asm volatile( - ".set push\n" - "\t.set mips1\n" - "\tcfc1\t%0,$31\n" - "\t.set pop" : "=r" (fcr31)); + fcr31 = read_32bit_cp1_register(CP1_STATUS); else fcr31 = current->thread.fpu.fcr31; preempt_enable(); diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index fa6ebd4bc9e9..c3917e251f59 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -299,6 +299,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) local_irq_save(flags); + htw_stop(); pid = read_c0_entryhi() & ASID_MASK; address &= (PAGE_MASK << 1); write_c0_entryhi(address | pid); @@ -346,6 +347,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) tlb_write_indexed(); } tlbw_use_hazard(); + htw_start(); flush_itlb_vm(vma); local_irq_restore(flags); } @@ -422,6 +424,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, local_irq_save(flags); /* Save old context and create impossible VPN2 value */ + htw_stop(); old_ctx = read_c0_entryhi(); old_pagemask = read_c0_pagemask(); wired = read_c0_wired(); @@ -443,6 +446,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, write_c0_entryhi(old_ctx); write_c0_pagemask(old_pagemask); + htw_start(); out: local_irq_restore(flags); return ret; diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index b5f228e7eae6..e3328a96e809 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -1872,8 +1872,16 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l, uasm_l_smp_pgtable_change(l, *p); #endif iPTE_LW(p, wr.r1, wr.r2); /* get even pte */ - if (!m4kc_tlbp_war()) + if (!m4kc_tlbp_war()) { build_tlb_probe_entry(p); + if (cpu_has_htw) { + /* race condition happens, leaving */ + uasm_i_ehb(p); + uasm_i_mfc0(p, wr.r3, C0_INDEX); + uasm_il_bltz(p, r, wr.r3, label_leave); + uasm_i_nop(p); + } + } return wr; } diff --git a/arch/mips/mti-sead3/sead3-leds.c b/arch/mips/mti-sead3/sead3-leds.c index 20102a6d4141..c427c5778186 100644 --- a/arch/mips/mti-sead3/sead3-leds.c +++ b/arch/mips/mti-sead3/sead3-leds.c @@ -5,7 +5,7 @@ * * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ -#include <linux/module.h> +#include <linux/init.h> #include <linux/leds.h> #include <linux/platform_device.h> @@ -76,8 +76,4 @@ static int __init led_init(void) return platform_device_register(&fled_device); } -module_init(led_init); - -MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("LED probe driver for SEAD-3"); +device_initcall(led_init); diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile index be358a8050c5..6b43af0a34d9 100644 --- a/arch/mips/netlogic/xlp/Makefile +++ b/arch/mips/netlogic/xlp/Makefile @@ -1,6 +1,10 @@ obj-y += setup.o nlm_hal.o cop2-ex.o dt.o obj-$(CONFIG_SMP) += wakeup.o -obj-$(CONFIG_USB) += usb-init.o -obj-$(CONFIG_USB) += usb-init-xlp2.o -obj-$(CONFIG_SATA_AHCI) += ahci-init.o -obj-$(CONFIG_SATA_AHCI) += ahci-init-xlp2.o +ifdef CONFIG_USB +obj-y += usb-init.o +obj-y += usb-init-xlp2.o +endif +ifdef CONFIG_SATA_AHCI +obj-y += ahci-init.o +obj-y += ahci-init-xlp2.o +endif diff --git a/arch/mips/oprofile/backtrace.c b/arch/mips/oprofile/backtrace.c index 6854ed5097d2..83a1dfd8f0e3 100644 --- a/arch/mips/oprofile/backtrace.c +++ b/arch/mips/oprofile/backtrace.c @@ -92,7 +92,7 @@ static inline int unwind_user_frame(struct stackframe *old_frame, /* This marks the end of the previous function, which means we overran. */ break; - stack_size = (unsigned) stack_adjustment; + stack_size = (unsigned long) stack_adjustment; } else if (is_ra_save_ins(&ip)) { int ra_slot = ip.i_format.simmediate; if (ra_slot < 0) diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c index fa374fe3746b..f7ac3edda1b2 100644 --- a/arch/mips/pci/msi-xlp.c +++ b/arch/mips/pci/msi-xlp.c @@ -443,10 +443,8 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link, msg.data = 0xc00 | msixvec; ret = irq_set_msi_desc(xirq, desc); - if (ret < 0) { - destroy_irq(xirq); + if (ret < 0) return ret; - } write_msi_msg(xirq, &msg); return 0; diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index a95c00f5fb96..a304bcc37e4f 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -107,6 +107,7 @@ static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth) } unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES]; +EXPORT_SYMBOL(__node_distances); static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b) { diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig new file mode 100644 index 000000000000..2361acf6d2b1 --- /dev/null +++ b/arch/nios2/Kconfig @@ -0,0 +1,206 @@ +config NIOS2 + def_bool y + select ARCH_WANT_OPTIONAL_GPIOLIB + select CLKSRC_OF + select GENERIC_ATOMIC64 + select GENERIC_CLOCKEVENTS + select GENERIC_CPU_DEVICES + select GENERIC_IRQ_PROBE + select GENERIC_IRQ_SHOW + select HAVE_ARCH_TRACEHOOK + select IRQ_DOMAIN + select MODULES_USE_ELF_RELA + select OF + select OF_EARLY_FLATTREE + select SOC_BUS + select SPARSE_IRQ + select USB_ARCH_HAS_HCD if USB_SUPPORT + +config GENERIC_CSUM + def_bool y + +config GENERIC_HWEIGHT + def_bool y + +config GENERIC_CALIBRATE_DELAY + def_bool y + +config NO_IOPORT_MAP + def_bool y + +config HAS_DMA + def_bool y + +config FPU + def_bool n + +config SWAP + def_bool n + +config RWSEM_GENERIC_SPINLOCK + def_bool y + +config TRACE_IRQFLAGS_SUPPORT + def_bool n + +source "init/Kconfig" + +menu "Kernel features" + +source "kernel/Kconfig.preempt" + +source "kernel/Kconfig.freezer" + +source "kernel/Kconfig.hz" + +source "mm/Kconfig" + +config FORCE_MAX_ZONEORDER + int "Maximum zone order" + range 9 20 + default "11" + help + The kernel memory allocator divides physically contiguous memory + blocks into "zones", where each zone is a power of two number of + pages. This option selects the largest power of two that the kernel + keeps in the memory allocator. If you need to allocate very large + blocks of physically contiguous memory, then you may need to + increase this value. + + This config option is actually maximum order plus one. For example, + a value of 11 means that the largest free memory block is 2^10 pages. + +endmenu + +source "arch/nios2/platform/Kconfig.platform" + +menu "Processor type and features" + +config MMU + def_bool y + +config NR_CPUS + int + default "1" + +config NIOS2_ALIGNMENT_TRAP + bool "Catch alignment trap" + default y + help + Nios II CPUs cannot fetch/store data which is not bus aligned, + i.e., a 2 or 4 byte fetch must start at an address divisible by + 2 or 4. Any non-aligned load/store instructions will be trapped and + emulated in software if you say Y here, which has a performance + impact. + +comment "Boot options" + +config CMDLINE_BOOL + bool "Default bootloader kernel arguments" + default y + +config CMDLINE + string "Default kernel command string" + default "" + depends on CMDLINE_BOOL + help + On some platforms, there is currently no way for the boot loader to + pass arguments to the kernel. For these platforms, you can supply + some command-line options at build time by entering them here. In + other cases you can specify kernel args so that you don't have + to set them up in board prom initialization routines. + +config CMDLINE_FORCE + bool "Force default kernel command string" + depends on CMDLINE_BOOL + help + Set this to have arguments from the default kernel command string + override those passed by the boot loader. + +config NIOS2_CMDLINE_IGNORE_DTB + bool "Ignore kernel command string from DTB" + depends on CMDLINE_BOOL + depends on !CMDLINE_FORCE + default y + help + Set this to ignore the bootargs property from the devicetree's + chosen node and fall back to CMDLINE if nothing is passed. + +config NIOS2_PASS_CMDLINE + bool "Passed kernel command line from u-boot" + default n + help + Use bootargs env variable from u-boot for kernel command line. + will override "Default kernel command string". + Say N if you are unsure. + +endmenu + +menu "Advanced setup" + +config ADVANCED_OPTIONS + bool "Prompt for advanced kernel configuration options" + help + +comment "Default settings for advanced configuration options are used" + depends on !ADVANCED_OPTIONS + +config NIOS2_KERNEL_MMU_REGION_BASE_BOOL + bool "Set custom kernel MMU region base address" + depends on ADVANCED_OPTIONS + help + This option allows you to set the virtual address of the kernel MMU region. + + Say N here unless you know what you are doing. + +config NIOS2_KERNEL_MMU_REGION_BASE + hex "Virtual base address of the kernel MMU region " if NIOS2_KERNEL_MMU_REGION_BASE_BOOL + default "0x80000000" + help + This option allows you to set the virtual base address of the kernel MMU region. + +config NIOS2_KERNEL_REGION_BASE_BOOL + bool "Set custom kernel region base address" + depends on ADVANCED_OPTIONS + help + This option allows you to set the virtual address of the kernel region. + + Say N here unless you know what you are doing. + +config NIOS2_KERNEL_REGION_BASE + hex "Virtual base address of the kernel region " if NIOS2_KERNEL_REGION_BASE_BOOL + default "0xc0000000" + +config NIOS2_IO_REGION_BASE_BOOL + bool "Set custom I/O region base address" + depends on ADVANCED_OPTIONS + help + This option allows you to set the virtual address of the I/O region. + + Say N here unless you know what you are doing. + +config NIOS2_IO_REGION_BASE + hex "Virtual base address of the I/O region" if NIOS2_IO_REGION_BASE_BOOL + default "0xe0000000" + +endmenu + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +endmenu + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "arch/nios2/Kconfig.debug" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" diff --git a/arch/nios2/Kconfig.debug b/arch/nios2/Kconfig.debug new file mode 100644 index 000000000000..8d4e6bacd997 --- /dev/null +++ b/arch/nios2/Kconfig.debug @@ -0,0 +1,17 @@ +menu "Kernel hacking" + +config TRACE_IRQFLAGS_SUPPORT + def_bool y + +source "lib/Kconfig.debug" + +config DEBUG_STACK_USAGE + bool "Enable stack utilization instrumentation" + depends on DEBUG_KERNEL + help + Enables the display of the minimum amount of free stack which each + task has ever had available in the sysrq-T and sysrq-P debug output. + + This option will slow down process creation somewhat. + +endmenu diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile new file mode 100644 index 000000000000..e142c9ee51fa --- /dev/null +++ b/arch/nios2/Makefile @@ -0,0 +1,73 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 2013 Altera Corporation +# Copyright (C) 1994, 95, 96, 2003 by Wind River Systems +# Written by Fredrik Markstrom +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" cleaning up for this architecture. +# +# Nios2 port by Wind River Systems Inc trough: +# fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + +UTS_SYSNAME = Linux + +export MMU + +LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) + +KBUILD_CFLAGS += -pipe -D__linux__ -D__ELF__ +KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_HW_MUL_SUPPORT),-mhw-mul,-mno-hw-mul) +KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_HW_MULX_SUPPORT),-mhw-mulx,-mno-hw-mulx) +KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_HW_DIV_SUPPORT),-mhw-div,-mno-hw-div) +KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_FPU_SUPPORT),-mcustom-fpu-cfg=60-1,) + +KBUILD_CFLAGS += -fno-optimize-sibling-calls +KBUILD_CFLAGS += -DUTS_SYSNAME=\"$(UTS_SYSNAME)\" +KBUILD_CFLAGS += -fno-builtin +KBUILD_CFLAGS += -G 0 + +head-y := arch/nios2/kernel/head.o +libs-y += arch/nios2/lib/ $(LIBGCC) +core-y += arch/nios2/kernel/ arch/nios2/mm/ +core-y += arch/nios2/platform/ + +INSTALL_PATH ?= /tftpboot +nios2-boot := arch/$(ARCH)/boot +BOOT_TARGETS = vmImage zImage +PHONY += $(BOOT_TARGETS) install +KBUILD_IMAGE := $(nios2-boot)/vmImage + +ifneq ($(CONFIG_NIOS2_DTB_SOURCE),"") + core-y += $(nios2-boot)/ +endif + +all: vmImage + +archclean: + $(Q)$(MAKE) $(clean)=$(nios2-boot) + +%.dtb: + $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ + +dtbs: + $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ + +$(BOOT_TARGETS): vmlinux + $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@ + +install: + $(Q)$(MAKE) $(build)=$(nios2-boot) BOOTIMAGE=$(KBUILD_IMAGE) install + +define archhelp + echo '* vmImage - Kernel-only image for U-Boot ($(KBUILD_IMAGE))' + echo ' install - Install kernel using' + echo ' (your) ~/bin/$(INSTALLKERNEL) or' + echo ' (distribution) /sbin/$(INSTALLKERNEL) or' + echo ' install to $$(INSTALL_PATH)' + echo ' dtbs - Build device tree blobs for enabled boards' +endef diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile new file mode 100644 index 000000000000..59392dc0bdcb --- /dev/null +++ b/arch/nios2/boot/Makefile @@ -0,0 +1,52 @@ +# +# arch/nios2/boot/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +UIMAGE_LOADADDR = $(shell $(NM) vmlinux | awk '$$NF == "_stext" {print $$1}') +UIMAGE_ENTRYADDR = $(shell $(NM) vmlinux | awk '$$NF == "_start" {print $$1}') +UIMAGE_COMPRESSION = gzip + +OBJCOPYFLAGS_vmlinux.bin := -O binary + +targets += vmlinux.bin vmlinux.gz vmImage + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +$(obj)/vmImage: $(obj)/vmlinux.gz + $(call if_changed,uimage) + @$(kecho) 'Kernel: $@ is ready' + +# Rule to build device tree blobs +DTB_SRC := $(patsubst "%",%,$(CONFIG_NIOS2_DTB_SOURCE)) + +# Make sure the generated dtb gets removed during clean +extra-$(CONFIG_NIOS2_DTB_SOURCE_BOOL) += system.dtb + +$(obj)/system.dtb: $(DTB_SRC) FORCE + $(call cmd,dtc) + +# Ensure system.dtb exists +$(obj)/linked_dtb.o: $(obj)/system.dtb + +obj-$(CONFIG_NIOS2_DTB_SOURCE_BOOL) += linked_dtb.o + +targets += $(dtb-y) + +# Rule to build device tree blobs with make command +$(obj)/%.dtb: $(src)/dts/%.dts FORCE + $(call if_changed_dep,dtc) + +$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y)) + +clean-files := *.dtb + +install: + sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" diff --git a/arch/nios2/boot/dts/3c120_devboard.dts b/arch/nios2/boot/dts/3c120_devboard.dts new file mode 100644 index 000000000000..31c51f9a2f09 --- /dev/null +++ b/arch/nios2/boot/dts/3c120_devboard.dts @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2013 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file is generated by sopc2dts. + */ + +/dts-v1/; + +/ { + model = "altr,qsys_ghrd_3c120"; + compatible = "altr,qsys_ghrd_3c120"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu: cpu@0x0 { + device_type = "cpu"; + compatible = "altr,nios2-1.0"; + reg = <0x00000000>; + interrupt-controller; + #interrupt-cells = <1>; + clock-frequency = <125000000>; + dcache-line-size = <32>; + icache-line-size = <32>; + dcache-size = <32768>; + icache-size = <32768>; + altr,implementation = "fast"; + altr,pid-num-bits = <8>; + altr,tlb-num-ways = <16>; + altr,tlb-num-entries = <128>; + altr,tlb-ptr-sz = <7>; + altr,has-div = <1>; + altr,has-mul = <1>; + altr,reset-addr = <0xc2800000>; + altr,fast-tlb-miss-addr = <0xc7fff400>; + altr,exception-addr = <0xd0000020>; + altr,has-initda = <1>; + altr,has-mmu = <1>; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x10000000 0x08000000>, + <0x07fff400 0x00000400>; + }; + + sopc@0 { + device_type = "soc"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,avalon", "simple-bus"; + bus-frequency = <125000000>; + + pb_cpu_to_io: bridge@0x8000000 { + compatible = "simple-bus"; + reg = <0x08000000 0x00800000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00002000 0x08002000 0x00002000>, + <0x00004000 0x08004000 0x00000400>, + <0x00004400 0x08004400 0x00000040>, + <0x00004800 0x08004800 0x00000040>, + <0x00004c80 0x08004c80 0x00000020>, + <0x00004d50 0x08004d50 0x00000008>, + <0x00008000 0x08008000 0x00000020>, + <0x00400000 0x08400000 0x00000020>; + + timer_1ms: timer@0x400000 { + compatible = "altr,timer-1.0"; + reg = <0x00400000 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <11>; + clock-frequency = <125000000>; + }; + + timer_0: timer@0x8000 { + compatible = "altr,timer-1.0"; + reg = < 0x00008000 0x00000020 >; + interrupt-parent = < &cpu >; + interrupts = < 5 >; + clock-frequency = < 125000000 >; + }; + + jtag_uart: serial@0x4d50 { + compatible = "altr,juart-1.0"; + reg = <0x00004d50 0x00000008>; + interrupt-parent = <&cpu>; + interrupts = <1>; + }; + + tse_mac: ethernet@0x4000 { + compatible = "altr,tse-1.0"; + reg = <0x00004000 0x00000400>, + <0x00004400 0x00000040>, + <0x00004800 0x00000040>, + <0x00002000 0x00002000>; + reg-names = "control_port", "rx_csr", "tx_csr", "s1"; + interrupt-parent = <&cpu>; + interrupts = <2 3>; + interrupt-names = "rx_irq", "tx_irq"; + rx-fifo-depth = <8192>; + tx-fifo-depth = <8192>; + max-frame-size = <1518>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; + tse_mac_mdio: mdio { + compatible = "altr,tse-mdio"; + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@18 { + reg = <18>; + device_type = "ethernet-phy"; + }; + }; + }; + + uart: serial@0x4c80 { + compatible = "altr,uart-1.0"; + reg = <0x00004c80 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <10>; + current-speed = <115200>; + clock-frequency = <62500000>; + }; + }; + + cfi_flash_64m: flash@0x0 { + compatible = "cfi-flash"; + reg = <0x00000000 0x04000000>; + bank-width = <2>; + device-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + + partition@800000 { + reg = <0x00800000 0x01e00000>; + label = "JFFS2 Filesystem"; + }; + }; + }; + + chosen { + bootargs = "debug console=ttyJ0,115200"; + }; +}; diff --git a/arch/nios2/boot/install.sh b/arch/nios2/boot/install.sh new file mode 100644 index 000000000000..3cb3f468bc51 --- /dev/null +++ b/arch/nios2/boot/install.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# +# "make install" script for nios2 architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +verify () { + if [ ! -f "$1" ]; then + echo "" 1>&2 + echo " *** Missing file: $1" 1>&2 + echo ' *** You need to run "make" before "make install".' 1>&2 + echo "" 1>&2 + exit 1 + fi +} + +# Make sure the files actually exist +verify "$2" +verify "$3" + +# User may have a custom install script + +if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi +if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi + +# Default install - same as make zlilo + +if [ -f $4/vmlinuz ]; then + mv $4/vmlinuz $4/vmlinuz.old +fi + +if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old +fi + +cat $2 > $4/vmlinuz +cp $3 $4/System.map + +sync diff --git a/arch/nios2/boot/linked_dtb.S b/arch/nios2/boot/linked_dtb.S new file mode 100644 index 000000000000..071f922db338 --- /dev/null +++ b/arch/nios2/boot/linked_dtb.S @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +.section .dtb.init.rodata,"a" +.incbin "arch/nios2/boot/system.dtb" diff --git a/arch/nios2/configs/3c120_defconfig b/arch/nios2/configs/3c120_defconfig new file mode 100644 index 000000000000..87541f0a5d6e --- /dev/null +++ b/arch/nios2/configs/3c120_defconfig @@ -0,0 +1,77 @@ +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_ELF_CORE is not set +# CONFIG_EPOLL is not set +# CONFIG_SIGNALFD is not set +# CONFIG_TIMERFD is not set +# CONFIG_EVENTFD is not set +# CONFIG_SHMEM is not set +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_NIOS2_MEM_BASE=0x10000000 +CONFIG_NIOS2_HW_MUL_SUPPORT=y +CONFIG_NIOS2_HW_DIV_SUPPORT=y +CONFIG_CUSTOM_CACHE_SETTINGS=y +CONFIG_NIOS2_DCACHE_SIZE=0x8000 +CONFIG_NIOS2_ICACHE_SIZE=0x8000 +# CONFIG_NIOS2_CMDLINE_IGNORE_DTB is not set +CONFIG_NIOS2_PASS_CMDLINE=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FW_LOADER is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_NETDEVICES=y +CONFIG_ALTERA_TSE=y +CONFIG_MARVELL_PHY=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +CONFIG_SERIAL_ALTERA_JTAGUART=y +CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE=y +CONFIG_SERIAL_ALTERA_UART=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY_USER is not set +CONFIG_JFFS2_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_ROOT_NFS=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild new file mode 100644 index 000000000000..bb160be0dc28 --- /dev/null +++ b/arch/nios2/include/asm/Kbuild @@ -0,0 +1,66 @@ +generic-y += atomic.h +generic-y += auxvec.h +generic-y += barrier.h +generic-y += bitops.h +generic-y += bitsperlong.h +generic-y += bug.h +generic-y += bugs.h +generic-y += clkdev.h +generic-y += cputime.h +generic-y += current.h +generic-y += device.h +generic-y += div64.h +generic-y += dma.h +generic-y += emergency-restart.h +generic-y += errno.h +generic-y += exec.h +generic-y += fb.h +generic-y += fcntl.h +generic-y += ftrace.h +generic-y += futex.h +generic-y += hardirq.h +generic-y += hash.h +generic-y += hw_irq.h +generic-y += ioctl.h +generic-y += ioctls.h +generic-y += ipcbuf.h +generic-y += irq_regs.h +generic-y += irq_work.h +generic-y += kdebug.h +generic-y += kmap_types.h +generic-y += kvm_para.h +generic-y += local.h +generic-y += mcs_spinlock.h +generic-y += mman.h +generic-y += module.h +generic-y += msgbuf.h +generic-y += param.h +generic-y += pci.h +generic-y += percpu.h +generic-y += poll.h +generic-y += posix_types.h +generic-y += preempt.h +generic-y += resource.h +generic-y += scatterlist.h +generic-y += sections.h +generic-y += segment.h +generic-y += sembuf.h +generic-y += serial.h +generic-y += shmbuf.h +generic-y += shmparam.h +generic-y += siginfo.h +generic-y += signal.h +generic-y += socket.h +generic-y += sockios.h +generic-y += spinlock.h +generic-y += stat.h +generic-y += statfs.h +generic-y += termbits.h +generic-y += termios.h +generic-y += topology.h +generic-y += trace_clock.h +generic-y += types.h +generic-y += unaligned.h +generic-y += user.h +generic-y += vga.h +generic-y += xor.h diff --git a/arch/nios2/include/asm/asm-macros.h b/arch/nios2/include/asm/asm-macros.h new file mode 100644 index 000000000000..29fa2e4d7b00 --- /dev/null +++ b/arch/nios2/include/asm/asm-macros.h @@ -0,0 +1,309 @@ +/* + * Macro used to simplify coding multi-line assembler. + * Some of the bit test macro can simplify down to one line + * depending on the mask value. + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + */ +#ifndef _ASM_NIOS2_ASMMACROS_H +#define _ASM_NIOS2_ASMMACROS_H +/* + * ANDs reg2 with mask and places the result in reg1. + * + * You cannnot use the same register for reg1 & reg2. + */ + +.macro ANDI32 reg1, reg2, mask +.if \mask & 0xffff + .if \mask & 0xffff0000 + movhi \reg1, %hi(\mask) + movui \reg1, %lo(\mask) + and \reg1, \reg1, \reg2 + .else + andi \reg1, \reg2, %lo(\mask) + .endif +.else + andhi \reg1, \reg2, %hi(\mask) +.endif +.endm + +/* + * ORs reg2 with mask and places the result in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro ORI32 reg1, reg2, mask +.if \mask & 0xffff + .if \mask & 0xffff0000 + orhi \reg1, \reg2, %hi(\mask) + ori \reg1, \reg2, %lo(\mask) + .else + ori \reg1, \reg2, %lo(\mask) + .endif +.else + orhi \reg1, \reg2, %hi(\mask) +.endif +.endm + +/* + * XORs reg2 with mask and places the result in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro XORI32 reg1, reg2, mask +.if \mask & 0xffff + .if \mask & 0xffff0000 + xorhi \reg1, \reg2, %hi(\mask) + xori \reg1, \reg1, %lo(\mask) + .else + xori \reg1, \reg2, %lo(\mask) + .endif +.else + xorhi \reg1, \reg2, %hi(\mask) +.endif +.endm + +/* + * This is a support macro for BTBZ & BTBNZ. It checks + * the bit to make sure it is valid 32 value. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BT reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and branches to label if the + * bit is zero. The result of the bit test is stored in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BTBZ reg1, reg2, bit, label + BT \reg1, \reg2, \bit + beq \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and branches to label if the + * bit is non-zero. The result of the bit test is stored in reg1. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro BTBNZ reg1, reg2, bit, label + BT \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTC reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + xori \reg2, \reg2, (1 << \bit) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + xorhi \reg2, \reg2, (1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTS reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + ori \reg2, \reg2, (1 << \bit) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + orhi \reg2, \reg2, (1 << (\bit - 16)) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTR reg1, reg2, bit +.if \bit > 31 + .err +.else + .if \bit < 16 + andi \reg1, \reg2, (1 << \bit) + andi \reg2, \reg2, %lo(~(1 << \bit)) + .else + andhi \reg1, \reg2, (1 << (\bit - 16)) + andhi \reg2, \reg2, %lo(~(1 << (\bit - 16))) + .endif +.endif +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTCBZ reg1, reg2, bit, label + BTC \reg1, \reg2, \bit + beq \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then compliments the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTCBNZ reg1, reg2, bit, label + BTC \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTSBZ reg1, reg2, bit, label + BTS \reg1, \reg2, \bit + beq \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then sets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTSBNZ reg1, reg2, bit, label + BTS \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTRBZ reg1, reg2, bit, label + BTR \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bit in reg2 and then resets the bit in reg2. + * The result of the bit test is stored in reg1. If the + * original bit was non-zero it branches to label. + * + * It is NOT safe to use the same register for reg1 & reg2. + */ + +.macro BTRBNZ reg1, reg2, bit, label + BTR \reg1, \reg2, \bit + bne \reg1, r0, \label +.endm + +/* + * Tests the bits in mask against reg2 stores the result in reg1. + * If the all the bits in the mask are zero it branches to label. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro TSTBZ reg1, reg2, mask, label + ANDI32 \reg1, \reg2, \mask + beq \reg1, r0, \label +.endm + +/* + * Tests the bits in mask against reg2 stores the result in reg1. + * If the any of the bits in the mask are 1 it branches to label. + * + * It is safe to use the same register for reg1 & reg2. + */ + +.macro TSTBNZ reg1, reg2, mask, label + ANDI32 \reg1, \reg2, \mask + bne \reg1, r0, \label +.endm + +/* + * Pushes reg onto the stack. + */ + +.macro PUSH reg + addi sp, sp, -4 + stw \reg, 0(sp) +.endm + +/* + * Pops the top of the stack into reg. + */ + +.macro POP reg + ldw \reg, 0(sp) + addi sp, sp, 4 +.endm + + +#endif /* _ASM_NIOS2_ASMMACROS_H */ diff --git a/arch/nios2/include/asm/asm-offsets.h b/arch/nios2/include/asm/asm-offsets.h new file mode 100644 index 000000000000..5b9f5e04a058 --- /dev/null +++ b/arch/nios2/include/asm/asm-offsets.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <generated/asm-offsets.h> diff --git a/arch/nios2/include/asm/cache.h b/arch/nios2/include/asm/cache.h new file mode 100644 index 000000000000..2293cf57e307 --- /dev/null +++ b/arch/nios2/include/asm/cache.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef _ASM_NIOS2_CACHE_H +#define _ASM_NIOS2_CACHE_H + +#define NIOS2_DCACHE_SIZE CONFIG_NIOS2_DCACHE_SIZE +#define NIOS2_ICACHE_SIZE CONFIG_NIOS2_ICACHE_SIZE +#define NIOS2_DCACHE_LINE_SIZE CONFIG_NIOS2_DCACHE_LINE_SIZE +#define NIOS2_ICACHE_LINE_SHIFT 5 +#define NIOS2_ICACHE_LINE_SIZE (1 << NIOS2_ICACHE_LINE_SHIFT) + +/* bytes per L1 cache line */ +#define L1_CACHE_SHIFT NIOS2_ICACHE_LINE_SHIFT +#define L1_CACHE_BYTES NIOS2_ICACHE_LINE_SIZE + +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES + +#define __cacheline_aligned +#define ____cacheline_aligned + +#endif diff --git a/arch/nios2/include/asm/cacheflush.h b/arch/nios2/include/asm/cacheflush.h new file mode 100644 index 000000000000..52abba973dc2 --- /dev/null +++ b/arch/nios2/include/asm/cacheflush.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003 Microtronix Datacom Ltd. + * Copyright (C) 2000-2002 Greg Ungerer <gerg@snapgear.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_CACHEFLUSH_H +#define _ASM_NIOS2_CACHEFLUSH_H + +#include <linux/mm_types.h> + +/* + * This flag is used to indicate that the page pointed to by a pte is clean + * and does not require cleaning before returning it to the user. + */ +#define PG_dcache_clean PG_arch_1 + +struct mm_struct; + +extern void flush_cache_all(void); +extern void flush_cache_mm(struct mm_struct *mm); +extern void flush_cache_dup_mm(struct mm_struct *mm); +extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, + unsigned long pfn); +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 +extern void flush_dcache_page(struct page *page); + +extern void flush_icache_range(unsigned long start, unsigned long end); +extern void flush_icache_page(struct vm_area_struct *vma, struct page *page); + +#define flush_cache_vmap(start, end) flush_dcache_range(start, end) +#define flush_cache_vunmap(start, end) flush_dcache_range(start, end) + +extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, + void *dst, void *src, int len); +extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, + void *dst, void *src, int len); + +extern void flush_dcache_range(unsigned long start, unsigned long end); +extern void invalidate_dcache_range(unsigned long start, unsigned long end); + +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) + +#endif /* _ASM_NIOS2_CACHEFLUSH_H */ diff --git a/arch/nios2/include/asm/checksum.h b/arch/nios2/include/asm/checksum.h new file mode 100644 index 000000000000..6bc1f0d5df7b --- /dev/null +++ b/arch/nios2/include/asm/checksum.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS_CHECKSUM_H +#define _ASM_NIOS_CHECKSUM_H + +/* Take these from lib/checksum.c */ +extern __wsum csum_partial(const void *buff, int len, __wsum sum); +extern __wsum csum_partial_copy(const void *src, void *dst, int len, + __wsum sum); +extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst, + int len, __wsum sum, int *csum_err); +#define csum_partial_copy_nocheck(src, dst, len, sum) \ + csum_partial_copy((src), (dst), (len), (sum)) + +extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl); +extern __sum16 ip_compute_csum(const void *buff, int len); + +/* + * Fold a partial checksum + */ +static inline __sum16 csum_fold(__wsum sum) +{ + __asm__ __volatile__( + "add %0, %1, %0\n" + "cmpltu r8, %0, %1\n" + "srli %0, %0, 16\n" + "add %0, %0, r8\n" + "nor %0, %0, %0\n" + : "=r" (sum) + : "r" (sum << 16), "0" (sum) + : "r8"); + return (__force __sum16) sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +#define csum_tcpudp_nofold csum_tcpudp_nofold +static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, + __wsum sum) +{ + __asm__ __volatile__( + "add %0, %1, %0\n" + "cmpltu r8, %0, %1\n" + "add %0, %0, r8\n" /* add carry */ + "add %0, %2, %0\n" + "cmpltu r8, %0, %2\n" + "add %0, %0, r8\n" /* add carry */ + "add %0, %3, %0\n" + "cmpltu r8, %0, %3\n" + "add %0, %0, r8\n" /* add carry */ + : "=r" (sum), "=r" (saddr) + : "r" (daddr), "r" ((ntohs(len) << 16) + (proto * 256)), + "0" (sum), + "1" (saddr) + : "r8"); + + return sum; +} + +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, __wsum sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); +} + +#endif /* _ASM_NIOS_CHECKSUM_H */ diff --git a/arch/nios2/include/asm/cmpxchg.h b/arch/nios2/include/asm/cmpxchg.h new file mode 100644 index 000000000000..85938711542d --- /dev/null +++ b/arch/nios2/include/asm/cmpxchg.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_CMPXCHG_H +#define _ASM_NIOS2_CMPXCHG_H + +#include <linux/irqflags.h> + +#define xchg(ptr, x) \ + ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((volatile struct __xchg_dummy *)(x)) + +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + unsigned long tmp, flags; + + local_irq_save(flags); + + switch (size) { + case 1: + __asm__ __volatile__( + "ldb %0, %2\n" + "stb %1, %2\n" + : "=&r" (tmp) + : "r" (x), "m" (*__xg(ptr)) + : "memory"); + break; + case 2: + __asm__ __volatile__( + "ldh %0, %2\n" + "sth %1, %2\n" + : "=&r" (tmp) + : "r" (x), "m" (*__xg(ptr)) + : "memory"); + break; + case 4: + __asm__ __volatile__( + "ldw %0, %2\n" + "stw %1, %2\n" + : "=&r" (tmp) + : "r" (x), "m" (*__xg(ptr)) + : "memory"); + break; + } + + local_irq_restore(flags); + return tmp; +} + +#include <asm-generic/cmpxchg.h> +#include <asm-generic/cmpxchg-local.h> + +#endif /* _ASM_NIOS2_CMPXCHG_H */ diff --git a/arch/nios2/include/asm/cpuinfo.h b/arch/nios2/include/asm/cpuinfo.h new file mode 100644 index 000000000000..e88fcae464d9 --- /dev/null +++ b/arch/nios2/include/asm/cpuinfo.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _ASM_NIOS2_CPUINFO_H +#define _ASM_NIOS2_CPUINFO_H + +#include <linux/types.h> + +struct cpuinfo { + /* Core CPU configuration */ + char cpu_impl[12]; + u32 cpu_clock_freq; + u32 mmu; + u32 has_div; + u32 has_mul; + u32 has_mulx; + + /* CPU caches */ + u32 icache_line_size; + u32 icache_size; + u32 dcache_line_size; + u32 dcache_size; + + /* TLB */ + u32 tlb_pid_num_bits; /* number of bits used for the PID in TLBMISC */ + u32 tlb_num_ways; + u32 tlb_num_ways_log2; + u32 tlb_num_entries; + u32 tlb_num_lines; + u32 tlb_ptr_sz; + + /* Addresses */ + u32 reset_addr; + u32 exception_addr; + u32 fast_tlb_miss_exc_addr; +}; + +extern struct cpuinfo cpuinfo; + +extern void setup_cpuinfo(void); + +#endif /* _ASM_NIOS2_CPUINFO_H */ diff --git a/arch/nios2/include/asm/delay.h b/arch/nios2/include/asm/delay.h new file mode 100644 index 000000000000..098e49bf3aa3 --- /dev/null +++ b/arch/nios2/include/asm/delay.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 Altera Corporation + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_DELAY_H +#define _ASM_NIOS2_DELAY_H + +#include <asm-generic/delay.h> + +/* Undefined functions to get compile-time errors */ +extern void __bad_udelay(void); +extern void __bad_ndelay(void); + +extern unsigned long loops_per_jiffy; + +#endif /* _ASM_NIOS2_DELAY_H */ diff --git a/arch/nios2/include/asm/dma-mapping.h b/arch/nios2/include/asm/dma-mapping.h new file mode 100644 index 000000000000..b5567233f7f1 --- /dev/null +++ b/arch/nios2/include/asm/dma-mapping.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef _ASM_NIOS2_DMA_MAPPING_H +#define _ASM_NIOS2_DMA_MAPPING_H + +#include <linux/scatterlist.h> +#include <linux/cache.h> +#include <asm/cacheflush.h> + +static inline void __dma_sync_for_device(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + switch (direction) { + case DMA_FROM_DEVICE: + invalidate_dcache_range((unsigned long)vaddr, + (unsigned long)(vaddr + size)); + break; + case DMA_TO_DEVICE: + /* + * We just need to flush the caches here , but Nios2 flush + * instruction will do both writeback and invalidate. + */ + case DMA_BIDIRECTIONAL: /* flush and invalidate */ + flush_dcache_range((unsigned long)vaddr, + (unsigned long)(vaddr + size)); + break; + default: + BUG(); + } +} + +static inline void __dma_sync_for_cpu(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + switch (direction) { + case DMA_BIDIRECTIONAL: + case DMA_FROM_DEVICE: + invalidate_dcache_range((unsigned long)vaddr, + (unsigned long)(vaddr + size)); + break; + case DMA_TO_DEVICE: + break; + default: + BUG(); + } +} + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); + +void dma_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle); + +static inline dma_addr_t dma_map_single(struct device *dev, void *ptr, + size_t size, + enum dma_data_direction direction) +{ + BUG_ON(!valid_dma_direction(direction)); + __dma_sync_for_device(ptr, size, direction); + return virt_to_phys(ptr); +} + +static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction direction) +{ +} + +extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction); +extern dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction direction); +extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, enum dma_data_direction direction); +extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nhwentries, enum dma_data_direction direction); +extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction); +extern void dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); +extern void dma_sync_single_range_for_cpu(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction); +extern void dma_sync_single_range_for_device(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction direction); +extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction direction); +extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction direction); + +static inline int dma_supported(struct device *dev, u64 mask) +{ + return 1; +} + +static inline int dma_set_mask(struct device *dev, u64 mask) +{ + if (!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + + *dev->dma_mask = mask; + + return 0; +} + +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return 0; +} + +/* +* dma_alloc_noncoherent() returns non-cacheable memory, so there's no need to +* do any flushing here. +*/ +static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction) +{ +} + +/* drivers/base/dma-mapping.c */ +extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size); +extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, + size_t size); + +#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s) +#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s) + +#endif /* _ASM_NIOS2_DMA_MAPPING_H */ diff --git a/arch/nios2/include/asm/elf.h b/arch/nios2/include/asm/elf.h new file mode 100644 index 000000000000..b7d655dff731 --- /dev/null +++ b/arch/nios2/include/asm/elf.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _ASM_NIOS2_ELF_H +#define _ASM_NIOS2_ELF_H + +#include <uapi/asm/elf.h> + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_ALTERA_NIOS2) + +#define ELF_PLAT_INIT(_r, load_addr) + +#define CORE_DUMP_USE_REGSET +#define ELF_EXEC_PAGESIZE 4096 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE 0xD0000000UL + +/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is + now struct_user_regs, they are different) */ + +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 +struct linux_binprm; +extern int arch_setup_additional_pages(struct linux_binprm *bprm, + int uses_interp); +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ +{ do { \ + /* Bleech. */ \ + pr_reg[0] = regs->r8; \ + pr_reg[1] = regs->r9; \ + pr_reg[2] = regs->r10; \ + pr_reg[3] = regs->r11; \ + pr_reg[4] = regs->r12; \ + pr_reg[5] = regs->r13; \ + pr_reg[6] = regs->r14; \ + pr_reg[7] = regs->r15; \ + pr_reg[8] = regs->r1; \ + pr_reg[9] = regs->r2; \ + pr_reg[10] = regs->r3; \ + pr_reg[11] = regs->r4; \ + pr_reg[12] = regs->r5; \ + pr_reg[13] = regs->r6; \ + pr_reg[14] = regs->r7; \ + pr_reg[15] = regs->orig_r2; \ + pr_reg[16] = regs->ra; \ + pr_reg[17] = regs->fp; \ + pr_reg[18] = regs->sp; \ + pr_reg[19] = regs->gp; \ + pr_reg[20] = regs->estatus; \ + pr_reg[21] = regs->ea; \ + pr_reg[22] = regs->orig_r7; \ + { \ + struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ + pr_reg[23] = sw->r16; \ + pr_reg[24] = sw->r17; \ + pr_reg[25] = sw->r18; \ + pr_reg[26] = sw->r19; \ + pr_reg[27] = sw->r20; \ + pr_reg[28] = sw->r21; \ + pr_reg[29] = sw->r22; \ + pr_reg[30] = sw->r23; \ + pr_reg[31] = sw->fp; \ + pr_reg[32] = sw->gp; \ + pr_reg[33] = sw->ra; \ + } \ +} while (0); } + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +#define ELF_PLATFORM (NULL) + +#endif /* _ASM_NIOS2_ELF_H */ diff --git a/arch/nios2/include/asm/entry.h b/arch/nios2/include/asm/entry.h new file mode 100644 index 000000000000..cf37f55efbc2 --- /dev/null +++ b/arch/nios2/include/asm/entry.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_ENTRY_H +#define _ASM_NIOS2_ENTRY_H + +#ifdef __ASSEMBLY__ + +#include <asm/processor.h> +#include <asm/registers.h> +#include <asm/asm-offsets.h> + +/* + * Standard Nios2 interrupt entry and exit macros. + * Must be called with interrupts disabled. + */ +.macro SAVE_ALL + rdctl r24, estatus + andi r24, r24, ESTATUS_EU + beq r24, r0, 1f /* In supervisor mode, already on kernel stack */ + + movia r24, _current_thread /* Switch to current kernel stack */ + ldw r24, 0(r24) /* using the thread_info */ + addi r24, r24, THREAD_SIZE-PT_REGS_SIZE + stw sp, PT_SP(r24) /* Save user stack before changing */ + mov sp, r24 + br 2f + +1 : mov r24, sp + addi sp, sp, -PT_REGS_SIZE /* Backup the kernel stack pointer */ + stw r24, PT_SP(sp) +2 : stw r1, PT_R1(sp) + stw r2, PT_R2(sp) + stw r3, PT_R3(sp) + stw r4, PT_R4(sp) + stw r5, PT_R5(sp) + stw r6, PT_R6(sp) + stw r7, PT_R7(sp) + stw r8, PT_R8(sp) + stw r9, PT_R9(sp) + stw r10, PT_R10(sp) + stw r11, PT_R11(sp) + stw r12, PT_R12(sp) + stw r13, PT_R13(sp) + stw r14, PT_R14(sp) + stw r15, PT_R15(sp) + stw r2, PT_ORIG_R2(sp) + stw r7, PT_ORIG_R7(sp) + + stw ra, PT_RA(sp) + stw fp, PT_FP(sp) + stw gp, PT_GP(sp) + rdctl r24, estatus + stw r24, PT_ESTATUS(sp) + stw ea, PT_EA(sp) +.endm + +.macro RESTORE_ALL + ldw r1, PT_R1(sp) /* Restore registers */ + ldw r2, PT_R2(sp) + ldw r3, PT_R3(sp) + ldw r4, PT_R4(sp) + ldw r5, PT_R5(sp) + ldw r6, PT_R6(sp) + ldw r7, PT_R7(sp) + ldw r8, PT_R8(sp) + ldw r9, PT_R9(sp) + ldw r10, PT_R10(sp) + ldw r11, PT_R11(sp) + ldw r12, PT_R12(sp) + ldw r13, PT_R13(sp) + ldw r14, PT_R14(sp) + ldw r15, PT_R15(sp) + ldw ra, PT_RA(sp) + ldw fp, PT_FP(sp) + ldw gp, PT_GP(sp) + ldw r24, PT_ESTATUS(sp) + wrctl estatus, r24 + ldw ea, PT_EA(sp) + ldw sp, PT_SP(sp) /* Restore sp last */ +.endm + +.macro SAVE_SWITCH_STACK + addi sp, sp, -SWITCH_STACK_SIZE + stw r16, SW_R16(sp) + stw r17, SW_R17(sp) + stw r18, SW_R18(sp) + stw r19, SW_R19(sp) + stw r20, SW_R20(sp) + stw r21, SW_R21(sp) + stw r22, SW_R22(sp) + stw r23, SW_R23(sp) + stw fp, SW_FP(sp) + stw gp, SW_GP(sp) + stw ra, SW_RA(sp) +.endm + +.macro RESTORE_SWITCH_STACK + ldw r16, SW_R16(sp) + ldw r17, SW_R17(sp) + ldw r18, SW_R18(sp) + ldw r19, SW_R19(sp) + ldw r20, SW_R20(sp) + ldw r21, SW_R21(sp) + ldw r22, SW_R22(sp) + ldw r23, SW_R23(sp) + ldw fp, SW_FP(sp) + ldw gp, SW_GP(sp) + ldw ra, SW_RA(sp) + addi sp, sp, SWITCH_STACK_SIZE +.endm + +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_NIOS2_ENTRY_H */ diff --git a/arch/nios2/include/asm/io.h b/arch/nios2/include/asm/io.h new file mode 100644 index 000000000000..9102bfd3fa1c --- /dev/null +++ b/arch/nios2/include/asm/io.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014 Altera Corporation + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_IO_H +#define _ASM_NIOS2_IO_H + +#include <linux/types.h> +#include <asm/pgtable-bits.h> + +/* PCI is not supported in nios2, set this to 0. */ +#define IO_SPACE_LIMIT 0 + +#define readb_relaxed(addr) readb(addr) +#define readw_relaxed(addr) readw(addr) +#define readl_relaxed(addr) readl(addr) + +#define writeb_relaxed(x, addr) writeb(x, addr) +#define writew_relaxed(x, addr) writew(x, addr) +#define writel_relaxed(x, addr) writel(x, addr) + +extern void __iomem *__ioremap(unsigned long physaddr, unsigned long size, + unsigned long cacheflag); +extern void __iounmap(void __iomem *addr); + +static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size) +{ + return __ioremap(physaddr, size, 0); +} + +static inline void __iomem *ioremap_nocache(unsigned long physaddr, + unsigned long size) +{ + return __ioremap(physaddr, size, 0); +} + +static inline void iounmap(void __iomem *addr) +{ + __iounmap(addr); +} + +/* Pages to physical address... */ +#define page_to_phys(page) virt_to_phys(page_to_virt(page)) +#define page_to_bus(page) page_to_virt(page) + +/* Macros used for converting between virtual and physical mappings. */ +#define phys_to_virt(vaddr) \ + ((void *)((unsigned long)(vaddr) | CONFIG_NIOS2_KERNEL_REGION_BASE)) +/* Clear top 3 bits */ +#define virt_to_phys(vaddr) \ + ((unsigned long)((unsigned long)(vaddr) & ~0xE0000000)) + +#include <asm-generic/io.h> + +#endif /* _ASM_NIOS2_IO_H */ diff --git a/arch/nios2/include/asm/irq.h b/arch/nios2/include/asm/irq.h new file mode 100644 index 000000000000..8e40fd94a36c --- /dev/null +++ b/arch/nios2/include/asm/irq.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _ASM_NIOS2_IRQ_H +#define _ASM_NIOS2_IRQ_H + +#define NIOS2_CPU_NR_IRQS 32 + +#include <asm-generic/irq.h> +#include <linux/irqdomain.h> + +#endif diff --git a/arch/nios2/include/asm/irqflags.h b/arch/nios2/include/asm/irqflags.h new file mode 100644 index 000000000000..75ab92e639f8 --- /dev/null +++ b/arch/nios2/include/asm/irqflags.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#ifndef _ASM_IRQFLAGS_H +#define _ASM_IRQFLAGS_H + +#include <asm/registers.h> + +static inline unsigned long arch_local_save_flags(void) +{ + return RDCTL(CTL_STATUS); +} + +/* + * This will restore ALL status register flags, not only the interrupt + * mask flag. + */ +static inline void arch_local_irq_restore(unsigned long flags) +{ + WRCTL(CTL_STATUS, flags); +} + +static inline void arch_local_irq_disable(void) +{ + unsigned long flags; + + flags = arch_local_save_flags(); + arch_local_irq_restore(flags & ~STATUS_PIE); +} + +static inline void arch_local_irq_enable(void) +{ + unsigned long flags; + + flags = arch_local_save_flags(); + arch_local_irq_restore(flags | STATUS_PIE); +} + +static inline int arch_irqs_disabled_flags(unsigned long flags) +{ + return (flags & STATUS_PIE) == 0; +} + +static inline int arch_irqs_disabled(void) +{ + return arch_irqs_disabled_flags(arch_local_save_flags()); +} + +static inline unsigned long arch_local_irq_save(void) +{ + unsigned long flags; + + flags = arch_local_save_flags(); + arch_local_irq_restore(flags & ~STATUS_PIE); + return flags; +} + +#endif /* _ASM_IRQFLAGS_H */ diff --git a/arch/nios2/include/asm/linkage.h b/arch/nios2/include/asm/linkage.h new file mode 100644 index 000000000000..e0c6decd7d58 --- /dev/null +++ b/arch/nios2/include/asm/linkage.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw> + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef _ASM_NIOS2_LINKAGE_H +#define _ASM_NIOS2_LINKAGE_H + +/* This file is required by include/linux/linkage.h */ +#define __ALIGN .align 4 +#define __ALIGN_STR ".align 4" + +#endif diff --git a/arch/nios2/include/asm/mmu.h b/arch/nios2/include/asm/mmu.h new file mode 100644 index 000000000000..d9c0b1010f26 --- /dev/null +++ b/arch/nios2/include/asm/mmu.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_MMU_H +#define _ASM_NIOS2_MMU_H + +/* Default "unsigned long" context */ +typedef unsigned long mm_context_t; + +#endif /* _ASM_NIOS2_MMU_H */ diff --git a/arch/nios2/include/asm/mmu_context.h b/arch/nios2/include/asm/mmu_context.h new file mode 100644 index 000000000000..294b4b1f81d4 --- /dev/null +++ b/arch/nios2/include/asm/mmu_context.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * based on MIPS asm/mmu_context.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_MMU_CONTEXT_H +#define _ASM_NIOS2_MMU_CONTEXT_H + +#include <asm-generic/mm_hooks.h> + +extern void mmu_context_init(void); +extern unsigned long get_pid_from_context(mm_context_t *ctx); + +/* + * For the fast tlb miss handlers, we keep a pointer to the current pgd. + * processor. + */ +extern pgd_t *pgd_current; + +static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) +{ +} + +/* + * Initialize the context related info for a new mm_struct instance. + * + * Set all new contexts to 0, that way the generation will never match + * the currently running generation when this context is switched in. + */ +static inline int init_new_context(struct task_struct *tsk, + struct mm_struct *mm) +{ + mm->context = 0; + return 0; +} + +/* + * Destroy context related info for an mm_struct that is about + * to be put to rest. + */ +static inline void destroy_context(struct mm_struct *mm) +{ +} + +void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk); + +static inline void deactivate_mm(struct task_struct *tsk, + struct mm_struct *mm) +{ +} + +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +void activate_mm(struct mm_struct *prev, struct mm_struct *next); + +#endif /* _ASM_NIOS2_MMU_CONTEXT_H */ diff --git a/arch/nios2/include/asm/mutex.h b/arch/nios2/include/asm/mutex.h new file mode 100644 index 000000000000..ff6101aa2c71 --- /dev/null +++ b/arch/nios2/include/asm/mutex.h @@ -0,0 +1 @@ +#include <asm-generic/mutex-dec.h> diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h new file mode 100644 index 000000000000..4b32d6fd9d98 --- /dev/null +++ b/arch/nios2/include/asm/page.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * MMU support based on asm/page.h from mips which is: + * + * Copyright (C) 1994 - 1999, 2000, 03 Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_PAGE_H +#define _ASM_NIOS2_PAGE_H + +#include <linux/pfn.h> +#include <linux/const.h> + +/* + * PAGE_SHIFT determines the page size + */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) + +/* + * PAGE_OFFSET -- the first address of the first page of memory. + */ +#define PAGE_OFFSET \ + (CONFIG_NIOS2_MEM_BASE + CONFIG_NIOS2_KERNEL_REGION_BASE) + +#ifndef __ASSEMBLY__ + +/* + * This gives the physical RAM offset. + */ +#define PHYS_OFFSET CONFIG_NIOS2_MEM_BASE + +/* + * It's normally defined only for FLATMEM config but it's + * used in our early mem init code for all memory models. + * So always define it. + */ +#define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET) + +#define clear_page(page) memset((page), 0, PAGE_SIZE) +#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) + +struct page; + +extern void clear_user_page(void *addr, unsigned long vaddr, struct page *page); +extern void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *to); + +/* + * These are used to make use of C type-checking. + */ +typedef struct page *pgtable_t; +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pte_val(x) ((x).pte) +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) }) +#define __pgd(x) ((pgd_t) { (x) }) +#define __pgprot(x) ((pgprot_t) { (x) }) + +extern unsigned long memory_start; +extern unsigned long memory_end; +extern unsigned long memory_size; + +extern struct page *mem_map; + +#endif /* !__ASSEMBLY__ */ + +# define __pa(x) \ + ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET) +# define __va(x) \ + ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET)) + +#define page_to_virt(page) \ + ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) + +# define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) +# define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && \ + (pfn) < max_mapnr) + +# define virt_to_page(vaddr) pfn_to_page(PFN_DOWN(virt_to_phys(vaddr))) +# define virt_addr_valid(vaddr) pfn_valid(PFN_DOWN(virt_to_phys(vaddr))) + +# define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +# define UNCAC_ADDR(addr) \ + ((void *)((unsigned)(addr) | CONFIG_NIOS2_IO_REGION_BASE)) +# define CAC_ADDR(addr) \ + ((void *)(((unsigned)(addr) & ~CONFIG_NIOS2_IO_REGION_BASE) | \ + CONFIG_NIOS2_KERNEL_REGION_BASE)) + +#include <asm-generic/memory_model.h> + +#include <asm-generic/getorder.h> + +#endif /* _ASM_NIOS2_PAGE_H */ diff --git a/arch/nios2/include/asm/pgalloc.h b/arch/nios2/include/asm/pgalloc.h new file mode 100644 index 000000000000..6e2985e0a7b9 --- /dev/null +++ b/arch/nios2/include/asm/pgalloc.h @@ -0,0 +1,86 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994 - 2001, 2003 by Ralf Baechle + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. + */ + +#ifndef _ASM_NIOS2_PGALLOC_H +#define _ASM_NIOS2_PGALLOC_H + +#include <linux/mm.h> + +static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, + pte_t *pte) +{ + set_pmd(pmd, __pmd((unsigned long)pte)); +} + +static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, + pgtable_t pte) +{ + set_pmd(pmd, __pmd((unsigned long)page_address(pte))); +} +#define pmd_pgtable(pmd) pmd_page(pmd) + +/* + * Initialize a new pmd table with invalid pointers. + */ +extern void pmd_init(unsigned long page, unsigned long pagetable); + +extern pgd_t *pgd_alloc(struct mm_struct *mm); + +static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + free_pages((unsigned long)pgd, PGD_ORDER); +} + +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, + PTE_ORDER); + + return pte; +} + +static inline pgtable_t pte_alloc_one(struct mm_struct *mm, + unsigned long address) +{ + struct page *pte; + + pte = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER); + if (pte) { + if (!pgtable_page_ctor(pte)) { + __free_page(pte); + return NULL; + } + clear_highpage(pte); + } + return pte; +} + +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + free_pages((unsigned long)pte, PTE_ORDER); +} + +static inline void pte_free(struct mm_struct *mm, struct page *pte) +{ + pgtable_page_dtor(pte); + __free_pages(pte, PTE_ORDER); +} + +#define __pte_free_tlb(tlb, pte, addr) \ + do { \ + pgtable_page_dtor(pte); \ + tlb_remove_page((tlb), (pte)); \ + } while (0) + +#define check_pgt_cache() do { } while (0) + +#endif /* _ASM_NIOS2_PGALLOC_H */ diff --git a/arch/nios2/include/asm/pgtable-bits.h b/arch/nios2/include/asm/pgtable-bits.h new file mode 100644 index 000000000000..ce9e7069aa96 --- /dev/null +++ b/arch/nios2/include/asm/pgtable-bits.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_PGTABLE_BITS_H +#define _ASM_NIOS2_PGTABLE_BITS_H + +/* + * These are actual hardware defined protection bits in the tlbacc register + * which looks like this: + * + * 31 30 ... 26 25 24 23 22 21 20 19 18 ... 1 0 + * ignored........ C R W X G PFN............ + */ +#define _PAGE_GLOBAL (1<<20) +#define _PAGE_EXEC (1<<21) +#define _PAGE_WRITE (1<<22) +#define _PAGE_READ (1<<23) +#define _PAGE_CACHED (1<<24) /* C: data access cacheable */ + +/* + * Software defined bits. They are ignored by the hardware and always read back + * as zero, but can be written as non-zero. + */ +#define _PAGE_PRESENT (1<<25) /* PTE contains a translation */ +#define _PAGE_ACCESSED (1<<26) /* page referenced */ +#define _PAGE_DIRTY (1<<27) /* dirty page */ +#define _PAGE_FILE (1<<28) /* PTE used for file mapping or swap */ + +#endif /* _ASM_NIOS2_PGTABLE_BITS_H */ diff --git a/arch/nios2/include/asm/pgtable.h b/arch/nios2/include/asm/pgtable.h new file mode 100644 index 000000000000..ccbaffd47671 --- /dev/null +++ b/arch/nios2/include/asm/pgtable.h @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * + * Based on asm/pgtable-32.h from mips which is: + * + * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2003 Ralf Baechle + * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_PGTABLE_H +#define _ASM_NIOS2_PGTABLE_H + +#include <linux/io.h> +#include <linux/bug.h> +#include <asm/page.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> + +#include <asm/pgtable-bits.h> +#include <asm-generic/pgtable-nopmd.h> + +#define FIRST_USER_ADDRESS 0 + +#define VMALLOC_START CONFIG_NIOS2_KERNEL_MMU_REGION_BASE +#define VMALLOC_END (CONFIG_NIOS2_KERNEL_REGION_BASE - 1) + +struct mm_struct; + +/* Helper macro */ +#define MKP(x, w, r) __pgprot(_PAGE_PRESENT | _PAGE_CACHED | \ + ((x) ? _PAGE_EXEC : 0) | \ + ((r) ? _PAGE_READ : 0) | \ + ((w) ? _PAGE_WRITE : 0)) +/* + * These are the macros that generic kernel code needs + * (to populate protection_map[]) + */ + +/* Remove W bit on private pages for COW support */ +#define __P000 MKP(0, 0, 0) +#define __P001 MKP(0, 0, 1) +#define __P010 MKP(0, 0, 0) /* COW */ +#define __P011 MKP(0, 0, 1) /* COW */ +#define __P100 MKP(1, 0, 0) +#define __P101 MKP(1, 0, 1) +#define __P110 MKP(1, 0, 0) /* COW */ +#define __P111 MKP(1, 0, 1) /* COW */ + +/* Shared pages can have exact HW mapping */ +#define __S000 MKP(0, 0, 0) +#define __S001 MKP(0, 0, 1) +#define __S010 MKP(0, 1, 0) +#define __S011 MKP(0, 1, 1) +#define __S100 MKP(1, 0, 0) +#define __S101 MKP(1, 0, 1) +#define __S110 MKP(1, 1, 0) +#define __S111 MKP(1, 1, 1) + +/* Used all over the kernel */ +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_CACHED | _PAGE_READ | \ + _PAGE_WRITE | _PAGE_EXEC | _PAGE_GLOBAL) + +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_CACHED | _PAGE_READ | \ + _PAGE_WRITE | _PAGE_ACCESSED) + +#define PAGE_COPY MKP(0, 0, 1) + +#define PGD_ORDER 0 +#define PTE_ORDER 0 + +#define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t)) +#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t)) + +#define USER_PTRS_PER_PGD \ + (CONFIG_NIOS2_KERNEL_MMU_REGION_BASE / PGDIR_SIZE) + +#define PGDIR_SHIFT 22 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; +#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)]; + +/* + * (pmds are folded into puds so this doesn't get actually called, + * but the define is needed for a generic inline function.) + */ +static inline void set_pmd(pmd_t *pmdptr, pmd_t pmdval) +{ + pmdptr->pud.pgd.pgd = pmdval.pud.pgd.pgd; +} + +/* to find an entry in a page-table-directory */ +#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) +#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr)) + +static inline int pte_write(pte_t pte) \ + { return pte_val(pte) & _PAGE_WRITE; } +static inline int pte_dirty(pte_t pte) \ + { return pte_val(pte) & _PAGE_DIRTY; } +static inline int pte_young(pte_t pte) \ + { return pte_val(pte) & _PAGE_ACCESSED; } +static inline int pte_file(pte_t pte) \ + { return pte_val(pte) & _PAGE_FILE; } +static inline int pte_special(pte_t pte) { return 0; } + +#define pgprot_noncached pgprot_noncached + +static inline pgprot_t pgprot_noncached(pgprot_t _prot) +{ + unsigned long prot = pgprot_val(_prot); + + prot &= ~_PAGE_CACHED; + + return __pgprot(prot); +} + +static inline int pte_none(pte_t pte) +{ + return !(pte_val(pte) & ~(_PAGE_GLOBAL|0xf)); +} + +static inline int pte_present(pte_t pte) \ + { return pte_val(pte) & _PAGE_PRESENT; } + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +static inline pte_t pte_wrprotect(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_WRITE; + return pte; +} + +static inline pte_t pte_mkclean(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_DIRTY; + return pte; +} + +static inline pte_t pte_mkold(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_ACCESSED; + return pte; +} + +static inline pte_t pte_mkwrite(pte_t pte) +{ + pte_val(pte) |= _PAGE_WRITE; + return pte; +} + +static inline pte_t pte_mkdirty(pte_t pte) +{ + pte_val(pte) |= _PAGE_DIRTY; + return pte; +} + +static inline pte_t pte_mkspecial(pte_t pte) { return pte; } + +static inline pte_t pte_mkyoung(pte_t pte) +{ + pte_val(pte) |= _PAGE_ACCESSED; + return pte; +} + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + const unsigned long mask = _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC; + + pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); + return pte; +} + +static inline int pmd_present(pmd_t pmd) +{ + return (pmd_val(pmd) != (unsigned long) invalid_pte_table) + && (pmd_val(pmd) != 0UL); +} + +static inline void pmd_clear(pmd_t *pmdp) +{ + pmd_val(*pmdp) = (unsigned long) invalid_pte_table; +} + +#define pte_pfn(pte) (pte_val(pte) & 0xfffff) +#define pfn_pte(pfn, prot) (__pte(pfn | pgprot_val(prot))) +#define pte_page(pte) (pfn_to_page(pte_pfn(pte))) + +/* + * Store a linux PTE into the linux page table. + */ +static inline void set_pte(pte_t *ptep, pte_t pteval) +{ + *ptep = pteval; +} + +static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pteval) +{ + unsigned long paddr = page_to_virt(pte_page(pteval)); + + flush_dcache_range(paddr, paddr + PAGE_SIZE); + set_pte(ptep, pteval); +} + +static inline int pmd_none(pmd_t pmd) +{ + return (pmd_val(pmd) == + (unsigned long) invalid_pte_table) || (pmd_val(pmd) == 0UL); +} + +#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK) + +static inline void pte_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + pte_t null; + + pte_val(null) = (addr >> PAGE_SHIFT) & 0xf; + + set_pte_at(mm, addr, ptep, null); + flush_tlb_one(addr); +} + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +#define mk_pte(page, prot) (pfn_pte(page_to_pfn(page), prot)) + +#define pte_unmap(pte) do { } while (0) + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +#define pmd_phys(pmd) virt_to_phys((void *)pmd_val(pmd)) +#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT)) +#define pmd_page_vaddr(pmd) pmd_val(pmd) + +#define pte_offset_map(dir, addr) \ + ((pte_t *) page_address(pmd_page(*dir)) + \ + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))) + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(addr) pgd_offset(&init_mm, addr) + +/* Get the address to the PTE for a vaddr in specific directory */ +#define pte_offset_kernel(dir, addr) \ + ((pte_t *) pmd_page_vaddr(*(dir)) + \ + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))) + +#define pte_ERROR(e) \ + pr_err("%s:%d: bad pte %08lx.\n", \ + __FILE__, __LINE__, pte_val(e)) +#define pgd_ERROR(e) \ + pr_err("%s:%d: bad pgd %08lx.\n", \ + __FILE__, __LINE__, pgd_val(e)) + +/* + * Encode and decode a swap entry (must be !pte_none(pte) && !pte_present(pte) + * && !pte_file(pte)): + * + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 ... 1 0 + * 0 0 0 0 type. 0 0 0 0 0 0 offset......... + * + * This gives us up to 2**2 = 4 swap files and 2**20 * 4K = 4G per swap file. + * + * Note that the offset field is always non-zero, thus !pte_none(pte) is always + * true. + */ +#define __swp_type(swp) (((swp).val >> 26) & 0x3) +#define __swp_offset(swp) ((swp).val & 0xfffff) +#define __swp_entry(type, off) ((swp_entry_t) { (((type) & 0x3) << 26) \ + | ((off) & 0xfffff) }) +#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) + +/* Encode and decode a nonlinear file mapping entry */ +#define PTE_FILE_MAX_BITS 25 +#define pte_to_pgoff(pte) (pte_val(pte) & 0x1ffffff) +#define pgoff_to_pte(off) __pte(((off) & 0x1ffffff) | _PAGE_FILE) + +#define kern_addr_valid(addr) (1) + +#include <asm-generic/pgtable.h> + +#define pgtable_cache_init() do { } while (0) + +extern void __init paging_init(void); +extern void __init mmu_init(void); + +extern void update_mmu_cache(struct vm_area_struct *vma, + unsigned long address, pte_t *pte); + +#endif /* _ASM_NIOS2_PGTABLE_H */ diff --git a/arch/nios2/include/asm/processor.h b/arch/nios2/include/asm/processor.h new file mode 100644 index 000000000000..3bd349473b06 --- /dev/null +++ b/arch/nios2/include/asm/processor.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd + * Copyright (C) 2001 Ken Hill (khill@microtronix.com) + * Vic Phillips (vic@microtronix.com) + * + * based on SPARC asm/processor_32.h which is: + * + * Copyright (C) 1994 David S. Miller + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_PROCESSOR_H +#define _ASM_NIOS2_PROCESSOR_H + +#include <asm/ptrace.h> +#include <asm/registers.h> +#include <asm/page.h> + +#define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */ + +#define NIOS2_OP_NOP 0x1883a +#define NIOS2_OP_BREAK 0x3da03a + +#ifdef __KERNEL__ + +#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP + +#endif /* __KERNEL__ */ + +/* Kuser helpers is mapped to this user space address */ +#define KUSER_BASE 0x1000 +#define KUSER_SIZE (PAGE_SIZE) +#ifndef __ASSEMBLY__ + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l; }) + +# define TASK_SIZE 0x7FFF0000UL +# define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) + +/* The Nios processor specific thread struct. */ +struct thread_struct { + struct pt_regs *kregs; + + /* Context switch saved kernel state. */ + unsigned long ksp; + unsigned long kpsr; +}; + +#define INIT_MMAP \ + { &init_mm, (0), (0), __pgprot(0x0), VM_READ | VM_WRITE | VM_EXEC } + +# define INIT_THREAD { \ + .kregs = NULL, \ + .ksp = 0, \ + .kpsr = 0, \ +} + +extern void start_thread(struct pt_regs *regs, unsigned long pc, + unsigned long sp); + +struct task_struct; + +/* Free all resources held by a thread. */ +static inline void release_thread(struct task_struct *dead_task) +{ +} + +/* Free current thread data structures etc.. */ +static inline void exit_thread(void) +{ +} + +/* Return saved PC of a blocked thread. */ +#define thread_saved_pc(tsk) ((tsk)->thread.kregs->ea) + +extern unsigned long get_wchan(struct task_struct *p); + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while (0) + +#define task_pt_regs(p) \ + ((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1) + +/* Used by procfs */ +#define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea) +#define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp) + +#define cpu_relax() barrier() +#define cpu_relax_lowlatency() cpu_relax() + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_NIOS2_PROCESSOR_H */ diff --git a/arch/nios2/include/asm/ptrace.h b/arch/nios2/include/asm/ptrace.h new file mode 100644 index 000000000000..20fb1cf2dab6 --- /dev/null +++ b/arch/nios2/include/asm/ptrace.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * based on m68k asm/processor.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_PTRACE_H +#define _ASM_NIOS2_PTRACE_H + +#include <uapi/asm/ptrace.h> + +#ifndef __ASSEMBLY__ +#define user_mode(regs) (((regs)->estatus & ESTATUS_EU)) + +#define instruction_pointer(regs) ((regs)->ra) +#define profile_pc(regs) instruction_pointer(regs) +#define user_stack_pointer(regs) ((regs)->sp) +extern void show_regs(struct pt_regs *); + +#define current_pt_regs() \ + ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE)\ + - 1) + +int do_syscall_trace_enter(void); +void do_syscall_trace_exit(void); +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_NIOS2_PTRACE_H */ diff --git a/arch/nios2/include/asm/registers.h b/arch/nios2/include/asm/registers.h new file mode 100644 index 000000000000..615bce19b546 --- /dev/null +++ b/arch/nios2/include/asm/registers.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _ASM_NIOS2_REGISTERS_H +#define _ASM_NIOS2_REGISTERS_H + +#ifndef __ASSEMBLY__ +#include <asm/cpuinfo.h> +#endif + +/* control register numbers */ +#define CTL_STATUS 0 +#define CTL_ESTATUS 1 +#define CTL_BSTATUS 2 +#define CTL_IENABLE 3 +#define CTL_IPENDING 4 +#define CTL_CPUID 5 +#define CTL_RSV1 6 +#define CTL_EXCEPTION 7 +#define CTL_PTEADDR 8 +#define CTL_TLBACC 9 +#define CTL_TLBMISC 10 +#define CTL_RSV2 11 +#define CTL_BADADDR 12 +#define CTL_CONFIG 13 +#define CTL_MPUBASE 14 +#define CTL_MPUACC 15 + +/* access control registers using GCC builtins */ +#define RDCTL(r) __builtin_rdctl(r) +#define WRCTL(r, v) __builtin_wrctl(r, v) + +/* status register bits */ +#define STATUS_PIE (1 << 0) /* processor interrupt enable */ +#define STATUS_U (1 << 1) /* user mode */ +#define STATUS_EH (1 << 2) /* Exception mode */ + +/* estatus register bits */ +#define ESTATUS_EPIE (1 << 0) /* processor interrupt enable */ +#define ESTATUS_EU (1 << 1) /* user mode */ +#define ESTATUS_EH (1 << 2) /* Exception mode */ + +/* tlbmisc register bits */ +#define TLBMISC_PID_SHIFT 4 +#ifndef __ASSEMBLY__ +#define TLBMISC_PID_MASK ((1UL << cpuinfo.tlb_pid_num_bits) - 1) +#endif +#define TLBMISC_WAY_MASK 0xf +#define TLBMISC_WAY_SHIFT 20 + +#define TLBMISC_PID (TLBMISC_PID_MASK << TLBMISC_PID_SHIFT) /* TLB PID */ +#define TLBMISC_WE (1 << 18) /* TLB write enable */ +#define TLBMISC_RD (1 << 19) /* TLB read */ +#define TLBMISC_WAY (TLBMISC_WAY_MASK << TLBMISC_WAY_SHIFT) /* TLB way */ + +#endif /* _ASM_NIOS2_REGISTERS_H */ diff --git a/arch/nios2/include/asm/setup.h b/arch/nios2/include/asm/setup.h new file mode 100644 index 000000000000..dcbf8cf1a344 --- /dev/null +++ b/arch/nios2/include/asm/setup.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _ASM_NIOS2_SETUP_H +#define _ASM_NIOS2_SETUP_H + +#include <asm-generic/setup.h> + +#ifndef __ASSEMBLY__ +#ifdef __KERNEL__ + +extern char exception_handler_hook[]; +extern char fast_handler[]; +extern char fast_handler_end[]; + +extern void pagetable_init(void); + +extern void setup_early_printk(void); + +#endif/* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_NIOS2_SETUP_H */ diff --git a/arch/nios2/include/asm/signal.h b/arch/nios2/include/asm/signal.h new file mode 100644 index 000000000000..bbcf11eecb01 --- /dev/null +++ b/arch/nios2/include/asm/signal.h @@ -0,0 +1,22 @@ +/* + * Copyright Altera Corporation (C) 2013. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#ifndef _NIOS2_SIGNAL_H +#define _NIOS2_SIGNAL_H + +#include <uapi/asm/signal.h> + +#endif /* _NIOS2_SIGNAL_H */ diff --git a/arch/nios2/include/asm/string.h b/arch/nios2/include/asm/string.h new file mode 100644 index 000000000000..14dd570d64f7 --- /dev/null +++ b/arch/nios2/include/asm/string.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_STRING_H +#define _ASM_NIOS2_STRING_H + +#ifdef __KERNEL__ + +#define __HAVE_ARCH_MEMSET +#define __HAVE_ARCH_MEMCPY +#define __HAVE_ARCH_MEMMOVE + +extern void *memset(void *s, int c, size_t count); +extern void *memcpy(void *d, const void *s, size_t count); +extern void *memmove(void *d, const void *s, size_t count); + +#endif /* __KERNEL__ */ + +#endif /* _ASM_NIOS2_STRING_H */ diff --git a/arch/nios2/include/asm/switch_to.h b/arch/nios2/include/asm/switch_to.h new file mode 100644 index 000000000000..c47b3f4afbcd --- /dev/null +++ b/arch/nios2/include/asm/switch_to.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef _ASM_NIOS2_SWITCH_TO_H +#define _ASM_NIOS2_SWITCH_TO_H + +/* + * switch_to(n) should switch tasks to task ptr, first checking that + * ptr isn't the current task, in which case it does nothing. This + * also clears the TS-flag if the task we switched to has used the + * math co-processor latest. + */ +#define switch_to(prev, next, last) \ +{ \ + void *_last; \ + __asm__ __volatile__ ( \ + "mov r4, %1\n" \ + "mov r5, %2\n" \ + "call resume\n" \ + "mov %0,r4\n" \ + : "=r" (_last) \ + : "r" (prev), "r" (next) \ + : "r4", "r5", "r7", "r8", "ra"); \ + (last) = _last; \ +} + +#endif /* _ASM_NIOS2_SWITCH_TO_H */ diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h new file mode 100644 index 000000000000..9de220854c4a --- /dev/null +++ b/arch/nios2/include/asm/syscall.h @@ -0,0 +1,138 @@ +/* + * Copyright Altera Corporation (C) <2014>. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ASM_NIOS2_SYSCALL_H__ +#define __ASM_NIOS2_SYSCALL_H__ + +#include <linux/err.h> +#include <linux/sched.h> + +static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs) +{ + return regs->r2; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + regs->r2 = regs->orig_r2; + regs->r7 = regs->orig_r7; +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->r7 ? regs->r2 : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->r2; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, int error, long val) +{ + if (error) { + /* error < 0, but nios2 uses > 0 return value */ + regs->r2 = -error; + regs->r7 = 1; + } else { + regs->r2 = val; + regs->r7 = 0; + } +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, unsigned int i, unsigned int n, + unsigned long *args) +{ + BUG_ON(i + n > 6); + + switch (i) { + case 0: + if (!n--) + break; + *args++ = regs->r4; + case 1: + if (!n--) + break; + *args++ = regs->r5; + case 2: + if (!n--) + break; + *args++ = regs->r6; + case 3: + if (!n--) + break; + *args++ = regs->r7; + case 4: + if (!n--) + break; + *args++ = regs->r8; + case 5: + if (!n--) + break; + *args++ = regs->r9; + case 6: + if (!n--) + break; + default: + BUG(); + } +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, unsigned int i, unsigned int n, + const unsigned long *args) +{ + BUG_ON(i + n > 6); + + switch (i) { + case 0: + if (!n--) + break; + regs->r4 = *args++; + case 1: + if (!n--) + break; + regs->r5 = *args++; + case 2: + if (!n--) + break; + regs->r6 = *args++; + case 3: + if (!n--) + break; + regs->r7 = *args++; + case 4: + if (!n--) + break; + regs->r8 = *args++; + case 5: + if (!n--) + break; + regs->r9 = *args++; + case 6: + if (!n) + break; + default: + BUG(); + } +} + +#endif diff --git a/arch/nios2/include/asm/syscalls.h b/arch/nios2/include/asm/syscalls.h new file mode 100644 index 000000000000..0245d780351b --- /dev/null +++ b/arch/nios2/include/asm/syscalls.h @@ -0,0 +1,25 @@ +/* + * Copyright Altera Corporation (C) 2013. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#ifndef __ASM_NIOS2_SYSCALLS_H +#define __ASM_NIOS2_SYSCALLS_H + +int sys_cacheflush(unsigned long addr, unsigned long len, + unsigned int op); + +#include <asm-generic/syscalls.h> + +#endif /* __ASM_NIOS2_SYSCALLS_H */ diff --git a/arch/nios2/include/asm/thread_info.h b/arch/nios2/include/asm/thread_info.h new file mode 100644 index 000000000000..1f266575beb5 --- /dev/null +++ b/arch/nios2/include/asm/thread_info.h @@ -0,0 +1,120 @@ +/* + * NiosII low-level thread information + * + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * Based on asm/thread_info_no.h from m68k which is: + * + * Copyright (C) 2002 David Howells <dhowells@redhat.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_THREAD_INFO_H +#define _ASM_NIOS2_THREAD_INFO_H + +#ifdef __KERNEL__ + +/* + * Size of the kernel stack for each process. + */ +#define THREAD_SIZE_ORDER 1 +#define THREAD_SIZE 8192 /* 2 * PAGE_SIZE */ + +#ifndef __ASSEMBLY__ + +typedef struct { + unsigned long seg; +} mm_segment_t; + +/* + * low level task data that entry.S needs immediate access to + * - this struct should fit entirely inside of one cache line + * - this struct shares the supervisor stack pages + * - if the contents of this structure are changed, the assembly constants + * must also be changed + */ +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + __u32 cpu; /* current CPU */ + int preempt_count; /* 0 => preemptable,<0 => BUG */ + mm_segment_t addr_limit; /* thread address space: + 0-0x7FFFFFFF for user-thead + 0-0xFFFFFFFF for kernel-thread + */ + struct restart_block restart_block; + struct pt_regs *regs; +}; + +/* + * macros/functions for gaining access to the thread information structure + * + * preempt_count needs to be 1 initially, until the scheduler is functional. + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + register unsigned long sp asm("sp"); + + return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); +} +#endif /* !__ASSEMBLY__ */ + +/* + * thread information flags + * - these are process state flags that various assembly files may need to + * access + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_MEMDIE 4 /* is terminating due to OOM killer */ +#define TIF_SECCOMP 5 /* secure computing */ +#define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ +#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ + +#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling + TIF_NEED_RESCHED */ + +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) + +/* work to do on interrupt/exception return */ +#define _TIF_WORK_MASK 0x0000FFFE + +/* work to do on any return to u-space */ +# define _TIF_ALLWORK_MASK 0x0000FFFF + +#endif /* __KERNEL__ */ + +#endif /* _ASM_NIOS2_THREAD_INFO_H */ diff --git a/arch/nios2/include/asm/timex.h b/arch/nios2/include/asm/timex.h new file mode 100644 index 000000000000..2f2abb28ec2f --- /dev/null +++ b/arch/nios2/include/asm/timex.h @@ -0,0 +1,24 @@ +/* Copyright Altera Corporation (C) 2014. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _ASM_NIOS2_TIMEX_H +#define _ASM_NIOS2_TIMEX_H + +typedef unsigned long cycles_t; + +extern cycles_t get_cycles(void); + +#endif diff --git a/arch/nios2/include/asm/tlb.h b/arch/nios2/include/asm/tlb.h new file mode 100644 index 000000000000..d3bc648e08b5 --- /dev/null +++ b/arch/nios2/include/asm/tlb.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_TLB_H +#define _ASM_NIOS2_TLB_H + +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +extern void set_mmu_pid(unsigned long pid); + +/* + * NiosII doesn't need any special per-pte or per-vma handling, except + * we need to flush cache for the area to be unmapped. + */ +#define tlb_start_vma(tlb, vma) \ + do { \ + if (!tlb->fullmm) \ + flush_cache_range(vma, vma->vm_start, vma->vm_end); \ + } while (0) + +#define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) + +#include <linux/pagemap.h> +#include <asm-generic/tlb.h> + +#endif /* _ASM_NIOS2_TLB_H */ diff --git a/arch/nios2/include/asm/tlbflush.h b/arch/nios2/include/asm/tlbflush.h new file mode 100644 index 000000000000..e19652fca1c6 --- /dev/null +++ b/arch/nios2/include/asm/tlbflush.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef _ASM_NIOS2_TLBFLUSH_H +#define _ASM_NIOS2_TLBFLUSH_H + +struct mm_struct; + +/* + * TLB flushing: + * + * - flush_tlb_all() flushes all processes TLB entries + * - flush_tlb_mm(mm) flushes the specified mm context TLB entries + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages + */ +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); +extern void flush_tlb_one(unsigned long vaddr); + +static inline void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + flush_tlb_one(addr); +} + +#endif /* _ASM_NIOS2_TLBFLUSH_H */ diff --git a/arch/nios2/include/asm/traps.h b/arch/nios2/include/asm/traps.h new file mode 100644 index 000000000000..82a48473280d --- /dev/null +++ b/arch/nios2/include/asm/traps.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_TRAPS_H +#define _ASM_NIOS2_TRAPS_H + +#define TRAP_ID_SYSCALL 0 + +#ifndef __ASSEMBLY__ +void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr); +#endif + +#endif /* _ASM_NIOS2_TRAPS_H */ diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h new file mode 100644 index 000000000000..acedc0a2860e --- /dev/null +++ b/arch/nios2/include/asm/uaccess.h @@ -0,0 +1,231 @@ +/* + * User space memory access functions for Nios II + * + * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009, Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_UACCESS_H +#define _ASM_NIOS2_UACCESS_H + +#include <linux/errno.h> +#include <linux/thread_info.h> +#include <linux/string.h> + +#include <asm/page.h> + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ +struct exception_table_entry { + unsigned long insn; + unsigned long fixup; +}; + +extern int fixup_exception(struct pt_regs *regs); + +/* + * Segment stuff + */ +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) +#define USER_DS MAKE_MM_SEG(0x80000000UL) +#define KERNEL_DS MAKE_MM_SEG(0) + +#define get_ds() (KERNEL_DS) + +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(seg) (current_thread_info()->addr_limit = (seg)) + +#define segment_eq(a, b) ((a).seg == (b).seg) + +#define __access_ok(addr, len) \ + (((signed long)(((long)get_fs().seg) & \ + ((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0) + +#define access_ok(type, addr, len) \ + likely(__access_ok((unsigned long)(addr), (unsigned long)(len))) + +# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n" + +/* + * Zero Userspace + */ + +static inline unsigned long __must_check __clear_user(void __user *to, + unsigned long n) +{ + __asm__ __volatile__ ( + "1: stb zero, 0(%1)\n" + " addi %0, %0, -1\n" + " addi %1, %1, 1\n" + " bne %0, zero, 1b\n" + "2:\n" + __EX_TABLE_SECTION + ".word 1b, 2b\n" + ".previous\n" + : "=r" (n), "=r" (to) + : "0" (n), "1" (to) + ); + + return n; +} + +static inline unsigned long __must_check clear_user(void __user *to, + unsigned long n) +{ + if (!access_ok(VERIFY_WRITE, to, n)) + return n; + return __clear_user(to, n); +} + +extern long __copy_from_user(void *to, const void __user *from, + unsigned long n); +extern long __copy_to_user(void __user *to, const void *from, unsigned long n); + +static inline long copy_from_user(void *to, const void __user *from, + unsigned long n) +{ + if (!access_ok(VERIFY_READ, from, n)) + return n; + return __copy_from_user(to, from, n); +} + +static inline long copy_to_user(void __user *to, const void *from, + unsigned long n) +{ + if (!access_ok(VERIFY_WRITE, to, n)) + return n; + return __copy_to_user(to, from, n); +} + +extern long strncpy_from_user(char *__to, const char __user *__from, + long __len); +extern long strnlen_user(const char __user *s, long n); + +#define __copy_from_user_inatomic __copy_from_user +#define __copy_to_user_inatomic __copy_to_user + +/* Optimized macros */ +#define __get_user_asm(val, insn, addr, err) \ +{ \ + __asm__ __volatile__( \ + " movi %0, %3\n" \ + "1: " insn " %1, 0(%2)\n" \ + " movi %0, 0\n" \ + "2:\n" \ + " .section __ex_table,\"a\"\n" \ + " .word 1b, 2b\n" \ + " .previous" \ + : "=&r" (err), "=r" (val) \ + : "r" (addr), "i" (-EFAULT)); \ +} + +#define __get_user_unknown(val, size, ptr, err) do { \ + err = 0; \ + if (copy_from_user(&(val), ptr, size)) { \ + err = -EFAULT; \ + } \ + } while (0) + +#define __get_user_common(val, size, ptr, err) \ +do { \ + switch (size) { \ + case 1: \ + __get_user_asm(val, "ldbu", ptr, err); \ + break; \ + case 2: \ + __get_user_asm(val, "ldhu", ptr, err); \ + break; \ + case 4: \ + __get_user_asm(val, "ldw", ptr, err); \ + break; \ + default: \ + __get_user_unknown(val, size, ptr, err); \ + break; \ + } \ +} while (0) + +#define __get_user(x, ptr) \ + ({ \ + long __gu_err = -EFAULT; \ + const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + unsigned long __gu_val; \ + __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\ + (x) = (__typeof__(x))__gu_val; \ + __gu_err; \ + }) + +#define get_user(x, ptr) \ +({ \ + long __gu_err = -EFAULT; \ + const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + unsigned long __gu_val = 0; \ + if (access_ok(VERIFY_READ, __gu_ptr, sizeof(*__gu_ptr))) \ + __get_user_common(__gu_val, sizeof(*__gu_ptr), \ + __gu_ptr, __gu_err); \ + (x) = (__typeof__(x))__gu_val; \ + __gu_err; \ +}) + +#define __put_user_asm(val, insn, ptr, err) \ +{ \ + __asm__ __volatile__( \ + " movi %0, %3\n" \ + "1: " insn " %1, 0(%2)\n" \ + " movi %0, 0\n" \ + "2:\n" \ + " .section __ex_table,\"a\"\n" \ + " .word 1b, 2b\n" \ + " .previous\n" \ + : "=&r" (err) \ + : "r" (val), "r" (ptr), "i" (-EFAULT)); \ +} + +#define put_user(x, ptr) \ +({ \ + long __pu_err = -EFAULT; \ + __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \ + __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x); \ + if (access_ok(VERIFY_WRITE, __pu_ptr, sizeof(*__pu_ptr))) { \ + switch (sizeof(*__pu_ptr)) { \ + case 1: \ + __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \ + break; \ + case 2: \ + __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \ + break; \ + case 4: \ + __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \ + break; \ + default: \ + /* XXX: This looks wrong... */ \ + __pu_err = 0; \ + if (copy_to_user(__pu_ptr, &(__pu_val), \ + sizeof(*__pu_ptr))) \ + __pu_err = -EFAULT; \ + break; \ + } \ + } \ + __pu_err; \ +}) + +#define __put_user(x, ptr) put_user(x, ptr) + +#endif /* _ASM_NIOS2_UACCESS_H */ diff --git a/arch/nios2/include/asm/ucontext.h b/arch/nios2/include/asm/ucontext.h new file mode 100644 index 000000000000..2c87614b0f6e --- /dev/null +++ b/arch/nios2/include/asm/ucontext.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _ASM_NIOS2_UCONTEXT_H +#define _ASM_NIOS2_UCONTEXT_H + +typedef int greg_t; +#define NGREG 32 +typedef greg_t gregset_t[NGREG]; + +struct mcontext { + int version; + gregset_t gregs; +}; + +#define MCONTEXT_VERSION 2 + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct mcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif diff --git a/arch/nios2/include/uapi/asm/Kbuild b/arch/nios2/include/uapi/asm/Kbuild new file mode 100644 index 000000000000..4f07ca3f8d10 --- /dev/null +++ b/arch/nios2/include/uapi/asm/Kbuild @@ -0,0 +1,4 @@ +include include/uapi/asm-generic/Kbuild.asm + +header-y += elf.h +header-y += ucontext.h diff --git a/arch/nios2/include/uapi/asm/byteorder.h b/arch/nios2/include/uapi/asm/byteorder.h new file mode 100644 index 000000000000..3ab5dc20d757 --- /dev/null +++ b/arch/nios2/include/uapi/asm/byteorder.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw> + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _ASM_NIOS2_BYTEORDER_H +#define _ASM_NIOS2_BYTEORDER_H + +#include <linux/byteorder/little_endian.h> + +#endif diff --git a/arch/nios2/include/uapi/asm/elf.h b/arch/nios2/include/uapi/asm/elf.h new file mode 100644 index 000000000000..a5b91ae5cf56 --- /dev/null +++ b/arch/nios2/include/uapi/asm/elf.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#ifndef _UAPI_ASM_NIOS2_ELF_H +#define _UAPI_ASM_NIOS2_ELF_H + +#include <linux/ptrace.h> + +/* Relocation types */ +#define R_NIOS2_NONE 0 +#define R_NIOS2_S16 1 +#define R_NIOS2_U16 2 +#define R_NIOS2_PCREL16 3 +#define R_NIOS2_CALL26 4 +#define R_NIOS2_IMM5 5 +#define R_NIOS2_CACHE_OPX 6 +#define R_NIOS2_IMM6 7 +#define R_NIOS2_IMM8 8 +#define R_NIOS2_HI16 9 +#define R_NIOS2_LO16 10 +#define R_NIOS2_HIADJ16 11 +#define R_NIOS2_BFD_RELOC_32 12 +#define R_NIOS2_BFD_RELOC_16 13 +#define R_NIOS2_BFD_RELOC_8 14 +#define R_NIOS2_GPREL 15 +#define R_NIOS2_GNU_VTINHERIT 16 +#define R_NIOS2_GNU_VTENTRY 17 +#define R_NIOS2_UJMP 18 +#define R_NIOS2_CJMP 19 +#define R_NIOS2_CALLR 20 +#define R_NIOS2_ALIGN 21 +/* Keep this the last entry. */ +#define R_NIOS2_NUM 22 + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG \ + ((sizeof(struct pt_regs) + sizeof(struct switch_stack)) / \ + sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef unsigned long elf_fpregset_t; + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_ALTERA_NIOS2 + +#endif /* _UAPI_ASM_NIOS2_ELF_H */ diff --git a/arch/nios2/include/uapi/asm/ptrace.h b/arch/nios2/include/uapi/asm/ptrace.h new file mode 100644 index 000000000000..e83a7c9d1c36 --- /dev/null +++ b/arch/nios2/include/uapi/asm/ptrace.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * based on m68k asm/processor.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef _UAPI_ASM_NIOS2_PTRACE_H +#define _UAPI_ASM_NIOS2_PTRACE_H + +#ifndef __ASSEMBLY__ + +/* + * Register numbers used by 'ptrace' system call interface. + */ + +/* GP registers */ +#define PTR_R0 0 +#define PTR_R1 1 +#define PTR_R2 2 +#define PTR_R3 3 +#define PTR_R4 4 +#define PTR_R5 5 +#define PTR_R6 6 +#define PTR_R7 7 +#define PTR_R8 8 +#define PTR_R9 9 +#define PTR_R10 10 +#define PTR_R11 11 +#define PTR_R12 12 +#define PTR_R13 13 +#define PTR_R14 14 +#define PTR_R15 15 +#define PTR_R16 16 +#define PTR_R17 17 +#define PTR_R18 18 +#define PTR_R19 19 +#define PTR_R20 20 +#define PTR_R21 21 +#define PTR_R22 22 +#define PTR_R23 23 +#define PTR_R24 24 +#define PTR_R25 25 +#define PTR_GP 26 +#define PTR_SP 27 +#define PTR_FP 28 +#define PTR_EA 29 +#define PTR_BA 30 +#define PTR_RA 31 +/* Control registers */ +#define PTR_PC 32 +#define PTR_STATUS 33 +#define PTR_ESTATUS 34 +#define PTR_BSTATUS 35 +#define PTR_IENABLE 36 +#define PTR_IPENDING 37 +#define PTR_CPUID 38 +#define PTR_CTL6 39 +#define PTR_CTL7 40 +#define PTR_PTEADDR 41 +#define PTR_TLBACC 42 +#define PTR_TLBMISC 43 + +#define NUM_PTRACE_REG (PTR_TLBMISC + 1) + +/* this struct defines the way the registers are stored on the + stack during a system call. + + There is a fake_regs in setup.c that has to match pt_regs.*/ + +struct pt_regs { + unsigned long r8; /* r8-r15 Caller-saved GP registers */ + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long r14; + unsigned long r15; + unsigned long r1; /* Assembler temporary */ + unsigned long r2; /* Retval LS 32bits */ + unsigned long r3; /* Retval MS 32bits */ + unsigned long r4; /* r4-r7 Register arguments */ + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long orig_r2; /* Copy of r2 ?? */ + unsigned long ra; /* Return address */ + unsigned long fp; /* Frame pointer */ + unsigned long sp; /* Stack pointer */ + unsigned long gp; /* Global pointer */ + unsigned long estatus; + unsigned long ea; /* Exception return address (pc) */ + unsigned long orig_r7; +}; + +/* + * This is the extended stack used by signal handlers and the context + * switcher: it's pushed after the normal "struct pt_regs". + */ +struct switch_stack { + unsigned long r16; /* r16-r23 Callee-saved GP registers */ + unsigned long r17; + unsigned long r18; + unsigned long r19; + unsigned long r20; + unsigned long r21; + unsigned long r22; + unsigned long r23; + unsigned long fp; + unsigned long gp; + unsigned long ra; +}; + +#endif /* __ASSEMBLY__ */ +#endif /* _UAPI_ASM_NIOS2_PTRACE_H */ diff --git a/arch/nios2/include/uapi/asm/sigcontext.h b/arch/nios2/include/uapi/asm/sigcontext.h new file mode 100644 index 000000000000..7b8bb41867d4 --- /dev/null +++ b/arch/nios2/include/uapi/asm/sigcontext.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004, Microtronix Datacom Ltd. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef _ASM_NIOS2_SIGCONTEXT_H +#define _ASM_NIOS2_SIGCONTEXT_H + +#include <asm/ptrace.h> + +struct sigcontext { + struct pt_regs regs; + unsigned long sc_mask; /* old sigmask */ +}; + +#endif diff --git a/arch/nios2/include/uapi/asm/signal.h b/arch/nios2/include/uapi/asm/signal.h new file mode 100644 index 000000000000..f29ee6314481 --- /dev/null +++ b/arch/nios2/include/uapi/asm/signal.h @@ -0,0 +1,23 @@ +/* + * Copyright Altera Corporation (C) 2013. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#ifndef _ASM_NIOS2_SIGNAL_H +#define _ASM_NIOS2_SIGNAL_H + +#define SA_RESTORER 0x04000000 +#include <asm-generic/signal.h> + +#endif /* _ASM_NIOS2_SIGNAL_H */ diff --git a/arch/nios2/include/uapi/asm/swab.h b/arch/nios2/include/uapi/asm/swab.h new file mode 100644 index 000000000000..b4e22ebaeb17 --- /dev/null +++ b/arch/nios2/include/uapi/asm/swab.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2011 Pyramid Technical Consultants, Inc. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#ifndef _ASM_NIOS2_SWAB_H +#define _ASM_NIOS2_SWAB_H + +#include <linux/types.h> +#include <asm-generic/swab.h> + +#ifdef CONFIG_NIOS2_CI_SWAB_SUPPORT +#ifdef __GNUC__ + +#define __nios2_swab(x) \ + __builtin_custom_ini(CONFIG_NIOS2_CI_SWAB_NO, (x)) + +static inline __attribute__((const)) __u16 __arch_swab16(__u16 x) +{ + return (__u16) __nios2_swab(((__u32) x) << 16); +} +#define __arch_swab16 __arch_swab16 + +static inline __attribute__((const)) __u32 __arch_swab32(__u32 x) +{ + return (__u32) __nios2_swab(x); +} +#define __arch_swab32 __arch_swab32 + +#endif /* __GNUC__ */ +#endif /* CONFIG_NIOS2_CI_SWAB_SUPPORT */ + +#endif /* _ASM_NIOS2_SWAB_H */ diff --git a/arch/nios2/include/uapi/asm/unistd.h b/arch/nios2/include/uapi/asm/unistd.h new file mode 100644 index 000000000000..c4bf79510461 --- /dev/null +++ b/arch/nios2/include/uapi/asm/unistd.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2013 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + + #define sys_mmap2 sys_mmap_pgoff + +/* Use the standard ABI for syscalls */ +#include <asm-generic/unistd.h> + +/* Additional Nios II specific syscalls. */ +#define __NR_cacheflush (__NR_arch_specific_syscall) +__SYSCALL(__NR_cacheflush, sys_cacheflush) diff --git a/arch/nios2/kernel/Makefile b/arch/nios2/kernel/Makefile new file mode 100644 index 000000000000..8ae76823ff93 --- /dev/null +++ b/arch/nios2/kernel/Makefile @@ -0,0 +1,24 @@ +# +# Makefile for the nios2 linux kernel. +# + +extra-y += head.o +extra-y += vmlinux.lds + +obj-y += cpuinfo.o +obj-y += entry.o +obj-y += insnemu.o +obj-y += irq.o +obj-y += nios2_ksyms.o +obj-y += process.o +obj-y += prom.o +obj-y += ptrace.o +obj-y += setup.o +obj-y += signal.o +obj-y += sys_nios2.o +obj-y += syscall_table.o +obj-y += time.o +obj-y += traps.o + +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_NIOS2_ALIGNMENT_TRAP) += misaligned.o diff --git a/arch/nios2/kernel/asm-offsets.c b/arch/nios2/kernel/asm-offsets.c new file mode 100644 index 000000000000..c3ee73c18b71 --- /dev/null +++ b/arch/nios2/kernel/asm-offsets.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/stddef.h> +#include <linux/sched.h> +#include <linux/kernel_stat.h> +#include <linux/ptrace.h> +#include <linux/hardirq.h> +#include <linux/thread_info.h> +#include <linux/kbuild.h> + +int main(void) +{ + /* struct task_struct */ + OFFSET(TASK_THREAD, task_struct, thread); + BLANK(); + + /* struct thread_struct */ + OFFSET(THREAD_KSP, thread_struct, ksp); + OFFSET(THREAD_KPSR, thread_struct, kpsr); + BLANK(); + + /* struct pt_regs */ + OFFSET(PT_ORIG_R2, pt_regs, orig_r2); + OFFSET(PT_ORIG_R7, pt_regs, orig_r7); + + OFFSET(PT_R1, pt_regs, r1); + OFFSET(PT_R2, pt_regs, r2); + OFFSET(PT_R3, pt_regs, r3); + OFFSET(PT_R4, pt_regs, r4); + OFFSET(PT_R5, pt_regs, r5); + OFFSET(PT_R6, pt_regs, r6); + OFFSET(PT_R7, pt_regs, r7); + OFFSET(PT_R8, pt_regs, r8); + OFFSET(PT_R9, pt_regs, r9); + OFFSET(PT_R10, pt_regs, r10); + OFFSET(PT_R11, pt_regs, r11); + OFFSET(PT_R12, pt_regs, r12); + OFFSET(PT_R13, pt_regs, r13); + OFFSET(PT_R14, pt_regs, r14); + OFFSET(PT_R15, pt_regs, r15); + OFFSET(PT_EA, pt_regs, ea); + OFFSET(PT_RA, pt_regs, ra); + OFFSET(PT_FP, pt_regs, fp); + OFFSET(PT_SP, pt_regs, sp); + OFFSET(PT_GP, pt_regs, gp); + OFFSET(PT_ESTATUS, pt_regs, estatus); + DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); + BLANK(); + + /* struct switch_stack */ + OFFSET(SW_R16, switch_stack, r16); + OFFSET(SW_R17, switch_stack, r17); + OFFSET(SW_R18, switch_stack, r18); + OFFSET(SW_R19, switch_stack, r19); + OFFSET(SW_R20, switch_stack, r20); + OFFSET(SW_R21, switch_stack, r21); + OFFSET(SW_R22, switch_stack, r22); + OFFSET(SW_R23, switch_stack, r23); + OFFSET(SW_FP, switch_stack, fp); + OFFSET(SW_GP, switch_stack, gp); + OFFSET(SW_RA, switch_stack, ra); + DEFINE(SWITCH_STACK_SIZE, sizeof(struct switch_stack)); + BLANK(); + + /* struct thread_info */ + OFFSET(TI_FLAGS, thread_info, flags); + OFFSET(TI_PREEMPT_COUNT, thread_info, preempt_count); + BLANK(); + + return 0; +} diff --git a/arch/nios2/kernel/cpuinfo.c b/arch/nios2/kernel/cpuinfo.c new file mode 100644 index 000000000000..51d5bb90d3e5 --- /dev/null +++ b/arch/nios2/kernel/cpuinfo.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * + * Based on cpuinfo.c from microblaze + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/string.h> +#include <linux/of.h> +#include <asm/cpuinfo.h> + +struct cpuinfo cpuinfo; + +#define err_cpu(x) \ + pr_err("ERROR: Nios II " x " different for kernel and DTS\n") + +static inline u32 fcpu(struct device_node *cpu, const char *n) +{ + u32 val = 0; + + of_property_read_u32(cpu, n, &val); + + return val; +} + +static inline u32 fcpu_has(struct device_node *cpu, const char *n) +{ + return of_get_property(cpu, n, NULL) ? 1 : 0; +} + +void __init setup_cpuinfo(void) +{ + struct device_node *cpu; + const char *str; + int len; + + cpu = of_find_node_by_type(NULL, "cpu"); + if (!cpu) + panic("%s: No CPU found in devicetree!\n", __func__); + + if (!fcpu_has(cpu, "altr,has-initda")) + panic("initda instruction is unimplemented. Please update your " + "hardware system to have more than 4-byte line data " + "cache\n"); + + cpuinfo.cpu_clock_freq = fcpu(cpu, "clock-frequency"); + + str = of_get_property(cpu, "altr,implementation", &len); + if (str) + strlcpy(cpuinfo.cpu_impl, str, sizeof(cpuinfo.cpu_impl)); + else + strcpy(cpuinfo.cpu_impl, "<unknown>"); + + cpuinfo.has_div = fcpu_has(cpu, "altr,has-div"); + cpuinfo.has_mul = fcpu_has(cpu, "altr,has-mul"); + cpuinfo.has_mulx = fcpu_has(cpu, "altr,has-mulx"); + + if (IS_ENABLED(CONFIG_NIOS2_HW_DIV_SUPPORT) && !cpuinfo.has_div) + err_cpu("DIV"); + + if (IS_ENABLED(CONFIG_NIOS2_HW_MUL_SUPPORT) && !cpuinfo.has_mul) + err_cpu("MUL"); + + if (IS_ENABLED(CONFIG_NIOS2_HW_MULX_SUPPORT) && !cpuinfo.has_mulx) + err_cpu("MULX"); + + cpuinfo.tlb_num_ways = fcpu(cpu, "altr,tlb-num-ways"); + if (!cpuinfo.tlb_num_ways) + panic("altr,tlb-num-ways can't be 0. Please check your hardware " + "system\n"); + cpuinfo.icache_line_size = fcpu(cpu, "icache-line-size"); + cpuinfo.icache_size = fcpu(cpu, "icache-size"); + if (CONFIG_NIOS2_ICACHE_SIZE != cpuinfo.icache_size) + pr_warn("Warning: icache size configuration mismatch " + "(0x%x vs 0x%x) of CONFIG_NIOS2_ICACHE_SIZE vs " + "device tree icache-size\n", + CONFIG_NIOS2_ICACHE_SIZE, cpuinfo.icache_size); + + cpuinfo.dcache_line_size = fcpu(cpu, "dcache-line-size"); + if (CONFIG_NIOS2_DCACHE_LINE_SIZE != cpuinfo.dcache_line_size) + pr_warn("Warning: dcache line size configuration mismatch " + "(0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_LINE_SIZE vs " + "device tree dcache-line-size\n", + CONFIG_NIOS2_DCACHE_LINE_SIZE, cpuinfo.dcache_line_size); + cpuinfo.dcache_size = fcpu(cpu, "dcache-size"); + if (CONFIG_NIOS2_DCACHE_SIZE != cpuinfo.dcache_size) + pr_warn("Warning: dcache size configuration mismatch " + "(0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_SIZE vs " + "device tree dcache-size\n", + CONFIG_NIOS2_DCACHE_SIZE, cpuinfo.dcache_size); + + cpuinfo.tlb_pid_num_bits = fcpu(cpu, "altr,pid-num-bits"); + cpuinfo.tlb_num_ways_log2 = ilog2(cpuinfo.tlb_num_ways); + cpuinfo.tlb_num_entries = fcpu(cpu, "altr,tlb-num-entries"); + cpuinfo.tlb_num_lines = cpuinfo.tlb_num_entries / cpuinfo.tlb_num_ways; + cpuinfo.tlb_ptr_sz = fcpu(cpu, "altr,tlb-ptr-sz"); + + cpuinfo.reset_addr = fcpu(cpu, "altr,reset-addr"); + cpuinfo.exception_addr = fcpu(cpu, "altr,exception-addr"); + cpuinfo.fast_tlb_miss_exc_addr = fcpu(cpu, "altr,fast-tlb-miss-addr"); +} + +#ifdef CONFIG_PROC_FS + +/* + * Get CPU information for use by the procfs. + */ +static int show_cpuinfo(struct seq_file *m, void *v) +{ + int count = 0; + const u32 clockfreq = cpuinfo.cpu_clock_freq; + + count = seq_printf(m, + "CPU:\t\tNios II/%s\n" + "MMU:\t\t%s\n" + "FPU:\t\tnone\n" + "Clocking:\t%u.%02u MHz\n" + "BogoMips:\t%lu.%02lu\n" + "Calibration:\t%lu loops\n", + cpuinfo.cpu_impl, + cpuinfo.mmu ? "present" : "none", + clockfreq / 1000000, (clockfreq / 100000) % 10, + (loops_per_jiffy * HZ) / 500000, + ((loops_per_jiffy * HZ) / 5000) % 100, + (loops_per_jiffy * HZ)); + + count += seq_printf(m, + "HW:\n" + " MUL:\t\t%s\n" + " MULX:\t\t%s\n" + " DIV:\t\t%s\n", + cpuinfo.has_mul ? "yes" : "no", + cpuinfo.has_mulx ? "yes" : "no", + cpuinfo.has_div ? "yes" : "no"); + + count += seq_printf(m, + "Icache:\t\t%ukB, line length: %u\n", + cpuinfo.icache_size >> 10, + cpuinfo.icache_line_size); + + count += seq_printf(m, + "Dcache:\t\t%ukB, line length: %u\n", + cpuinfo.dcache_size >> 10, + cpuinfo.dcache_line_size); + + count += seq_printf(m, + "TLB:\t\t%u ways, %u entries, %u PID bits\n", + cpuinfo.tlb_num_ways, + cpuinfo.tlb_num_entries, + cpuinfo.tlb_pid_num_bits); + + return 0; +} + +static void *cpuinfo_start(struct seq_file *m, loff_t *pos) +{ + unsigned long i = *pos; + + return i < num_possible_cpus() ? (void *) (i + 1) : NULL; +} + +static void *cpuinfo_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return cpuinfo_start(m, pos); +} + +static void cpuinfo_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start = cpuinfo_start, + .next = cpuinfo_next, + .stop = cpuinfo_stop, + .show = show_cpuinfo +}; + +#endif /* CONFIG_PROC_FS */ diff --git a/arch/nios2/kernel/entry.S b/arch/nios2/kernel/entry.S new file mode 100644 index 000000000000..83bca17d1008 --- /dev/null +++ b/arch/nios2/kernel/entry.S @@ -0,0 +1,555 @@ +/* + * linux/arch/nios2/kernel/entry.S + * + * Copyright (C) 2013-2014 Altera Corporation + * Copyright (C) 2009, Wind River Systems Inc + * + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Linux/m68k support by Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * ColdFire support by Greg Ungerer (gerg@snapgear.com) + * 5307 fixes by David W. Miller + * linux 2.4 support David McCullough <davidm@snapgear.com> + */ + +#include <linux/sys.h> +#include <linux/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/asm-macros.h> +#include <asm/thread_info.h> +#include <asm/errno.h> +#include <asm/setup.h> +#include <asm/entry.h> +#include <asm/unistd.h> +#include <asm/processor.h> + +.macro GET_THREAD_INFO reg +.if THREAD_SIZE & 0xffff0000 + andhi \reg, sp, %hi(~(THREAD_SIZE-1)) +.else + addi \reg, r0, %lo(~(THREAD_SIZE-1)) + and \reg, \reg, sp +.endif +.endm + +.macro kuser_cmpxchg_check + /* + * Make sure our user space atomic helper is restarted if it was + * interrupted in a critical region. + * ea-4 = address of interrupted insn (ea must be preserved). + * sp = saved regs. + * cmpxchg_ldw = first critical insn, cmpxchg_stw = last critical insn. + * If ea <= cmpxchg_stw and ea > cmpxchg_ldw then saved EA is set to + * cmpxchg_ldw + 4. + */ + /* et = cmpxchg_stw + 4 */ + movui et, (KUSER_BASE + 4 + (cmpxchg_stw - __kuser_helper_start)) + bgtu ea, et, 1f + + subi et, et, (cmpxchg_stw - cmpxchg_ldw) /* et = cmpxchg_ldw + 4 */ + bltu ea, et, 1f + stw et, PT_EA(sp) /* fix up EA */ + mov ea, et +1: +.endm + +.section .rodata +.align 4 +exception_table: + .word unhandled_exception /* 0 - Reset */ + .word unhandled_exception /* 1 - Processor-only Reset */ + .word external_interrupt /* 2 - Interrupt */ + .word handle_trap /* 3 - Trap Instruction */ + + .word instruction_trap /* 4 - Unimplemented instruction */ + .word handle_illegal /* 5 - Illegal instruction */ + .word handle_unaligned /* 6 - Misaligned data access */ + .word handle_unaligned /* 7 - Misaligned destination address */ + + .word handle_diverror /* 8 - Division error */ + .word protection_exception_ba /* 9 - Supervisor-only instr. address */ + .word protection_exception_instr /* 10 - Supervisor only instruction */ + .word protection_exception_ba /* 11 - Supervisor only data address */ + + .word unhandled_exception /* 12 - Double TLB miss (data) */ + .word protection_exception_pte /* 13 - TLB permission violation (x) */ + .word protection_exception_pte /* 14 - TLB permission violation (r) */ + .word protection_exception_pte /* 15 - TLB permission violation (w) */ + + .word unhandled_exception /* 16 - MPU region violation */ + +trap_table: + .word handle_system_call /* 0 */ + .word instruction_trap /* 1 */ + .word instruction_trap /* 2 */ + .word instruction_trap /* 3 */ + .word instruction_trap /* 4 */ + .word instruction_trap /* 5 */ + .word instruction_trap /* 6 */ + .word instruction_trap /* 7 */ + .word instruction_trap /* 8 */ + .word instruction_trap /* 9 */ + .word instruction_trap /* 10 */ + .word instruction_trap /* 11 */ + .word instruction_trap /* 12 */ + .word instruction_trap /* 13 */ + .word instruction_trap /* 14 */ + .word instruction_trap /* 15 */ + .word instruction_trap /* 16 */ + .word instruction_trap /* 17 */ + .word instruction_trap /* 18 */ + .word instruction_trap /* 19 */ + .word instruction_trap /* 20 */ + .word instruction_trap /* 21 */ + .word instruction_trap /* 22 */ + .word instruction_trap /* 23 */ + .word instruction_trap /* 24 */ + .word instruction_trap /* 25 */ + .word instruction_trap /* 26 */ + .word instruction_trap /* 27 */ + .word instruction_trap /* 28 */ + .word instruction_trap /* 29 */ + .word instruction_trap /* 30 */ + .word handle_breakpoint /* 31 */ + +.text +.set noat +.set nobreak + +ENTRY(inthandler) + SAVE_ALL + + kuser_cmpxchg_check + + /* Clear EH bit before we get a new excpetion in the kernel + * and after we have saved it to the exception frame. This is done + * whether it's trap, tlb-miss or interrupt. If we don't do this + * estatus is not updated the next exception. + */ + rdctl r24, status + movi r9, %lo(~STATUS_EH) + and r24, r24, r9 + wrctl status, r24 + + /* Read cause and vector and branch to the associated handler */ + mov r4, sp + rdctl r5, exception + movia r9, exception_table + add r24, r9, r5 + ldw r24, 0(r24) + jmp r24 + + +/*********************************************************************** + * Handle traps + *********************************************************************** + */ +ENTRY(handle_trap) + ldw r24, -4(ea) /* instruction that caused the exception */ + srli r24, r24, 4 + andi r24, r24, 0x7c + movia r9,trap_table + add r24, r24, r9 + ldw r24, 0(r24) + jmp r24 + + +/*********************************************************************** + * Handle system calls + *********************************************************************** + */ +ENTRY(handle_system_call) + /* Enable interrupts */ + rdctl r10, status + ori r10, r10, STATUS_PIE + wrctl status, r10 + + /* Reload registers destroyed by common code. */ + ldw r4, PT_R4(sp) + ldw r5, PT_R5(sp) + +local_restart: + /* Check that the requested system call is within limits */ + movui r1, __NR_syscalls + bgeu r2, r1, ret_invsyscall + slli r1, r2, 2 + movhi r11, %hiadj(sys_call_table) + add r1, r1, r11 + ldw r1, %lo(sys_call_table)(r1) + beq r1, r0, ret_invsyscall + + /* Check if we are being traced */ + GET_THREAD_INFO r11 + ldw r11,TI_FLAGS(r11) + BTBNZ r11,r11,TIF_SYSCALL_TRACE,traced_system_call + + /* Execute the system call */ + callr r1 + + /* If the syscall returns a negative result: + * Set r7 to 1 to indicate error, + * Negate r2 to get a positive error code + * If the syscall returns zero or a positive value: + * Set r7 to 0. + * The sigreturn system calls will skip the code below by + * adding to register ra. To avoid destroying registers + */ +translate_rc_and_ret: + movi r1, 0 + bge r2, zero, 3f + sub r2, zero, r2 + movi r1, 1 +3: + stw r2, PT_R2(sp) + stw r1, PT_R7(sp) +end_translate_rc_and_ret: + +ret_from_exception: + ldw r1, PT_ESTATUS(sp) + /* if so, skip resched, signals */ + TSTBNZ r1, r1, ESTATUS_EU, Luser_return + +restore_all: + rdctl r10, status /* disable intrs */ + andi r10, r10, %lo(~STATUS_PIE) + wrctl status, r10 + RESTORE_ALL + eret + + /* If the syscall number was invalid return ENOSYS */ +ret_invsyscall: + movi r2, -ENOSYS + br translate_rc_and_ret + + /* This implements the same as above, except it calls + * do_syscall_trace_enter and do_syscall_trace_exit before and after the + * syscall in order for utilities like strace and gdb to work. + */ +traced_system_call: + SAVE_SWITCH_STACK + call do_syscall_trace_enter + RESTORE_SWITCH_STACK + + /* Create system call register arguments. The 5th and 6th + arguments on stack are already in place at the beginning + of pt_regs. */ + ldw r2, PT_R2(sp) + ldw r4, PT_R4(sp) + ldw r5, PT_R5(sp) + ldw r6, PT_R6(sp) + ldw r7, PT_R7(sp) + + /* Fetch the syscall function, we don't need to check the boundaries + * since this is already done. + */ + slli r1, r2, 2 + movhi r11,%hiadj(sys_call_table) + add r1, r1, r11 + ldw r1, %lo(sys_call_table)(r1) + + callr r1 + + /* If the syscall returns a negative result: + * Set r7 to 1 to indicate error, + * Negate r2 to get a positive error code + * If the syscall returns zero or a positive value: + * Set r7 to 0. + * The sigreturn system calls will skip the code below by + * adding to register ra. To avoid destroying registers + */ +translate_rc_and_ret2: + movi r1, 0 + bge r2, zero, 4f + sub r2, zero, r2 + movi r1, 1 +4: + stw r2, PT_R2(sp) + stw r1, PT_R7(sp) +end_translate_rc_and_ret2: + SAVE_SWITCH_STACK + call do_syscall_trace_exit + RESTORE_SWITCH_STACK + br ret_from_exception + +Luser_return: + GET_THREAD_INFO r11 /* get thread_info pointer */ + ldw r10, TI_FLAGS(r11) /* get thread_info->flags */ + ANDI32 r11, r10, _TIF_WORK_MASK + beq r11, r0, restore_all /* Nothing to do */ + BTBZ r1, r10, TIF_NEED_RESCHED, Lsignal_return + + /* Reschedule work */ + call schedule + br ret_from_exception + +Lsignal_return: + ANDI32 r1, r10, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME + beq r1, r0, restore_all + mov r4, sp /* pt_regs */ + SAVE_SWITCH_STACK + call do_notify_resume + beq r2, r0, no_work_pending + RESTORE_SWITCH_STACK + /* prepare restart syscall here without leaving kernel */ + ldw r2, PT_R2(sp) /* reload syscall number in r2 */ + ldw r4, PT_R4(sp) /* reload syscall arguments r4-r9 */ + ldw r5, PT_R5(sp) + ldw r6, PT_R6(sp) + ldw r7, PT_R7(sp) + ldw r8, PT_R8(sp) + ldw r9, PT_R9(sp) + br local_restart /* restart syscall */ + +no_work_pending: + RESTORE_SWITCH_STACK + br ret_from_exception + +/*********************************************************************** + * Handle external interrupts. + *********************************************************************** + */ +/* + * This is the generic interrupt handler (for all hardware interrupt + * sources). It figures out the vector number and calls the appropriate + * interrupt service routine directly. + */ +external_interrupt: + rdctl r12, ipending + rdctl r9, ienable + and r12, r12, r9 + /* skip if no interrupt is pending */ + beq r12, r0, ret_from_interrupt + + movi r24, -1 + stw r24, PT_ORIG_R2(sp) + + /* + * Process an external hardware interrupt. + */ + + addi ea, ea, -4 /* re-issue the interrupted instruction */ + stw ea, PT_EA(sp) +2: movi r4, %lo(-1) /* Start from bit position 0, + highest priority */ + /* This is the IRQ # for handler call */ +1: andi r10, r12, 1 /* Isolate bit we are interested in */ + srli r12, r12, 1 /* shift count is costly without hardware + multiplier */ + addi r4, r4, 1 + beq r10, r0, 1b + mov r5, sp /* Setup pt_regs pointer for handler call */ + call do_IRQ + rdctl r12, ipending /* check again if irq still pending */ + rdctl r9, ienable /* Isolate possible interrupts */ + and r12, r12, r9 + bne r12, r0, 2b + /* br ret_from_interrupt */ /* fall through to ret_from_interrupt */ + +ENTRY(ret_from_interrupt) + ldw r1, PT_ESTATUS(sp) /* check if returning to kernel */ + TSTBNZ r1, r1, ESTATUS_EU, Luser_return + +#ifdef CONFIG_PREEMPT + GET_THREAD_INFO r1 + ldw r4, TI_PREEMPT_COUNT(r1) + bne r4, r0, restore_all + +need_resched: + ldw r4, TI_FLAGS(r1) /* ? Need resched set */ + BTBZ r10, r4, TIF_NEED_RESCHED, restore_all + ldw r4, PT_ESTATUS(sp) /* ? Interrupts off */ + andi r10, r4, ESTATUS_EPIE + beq r10, r0, restore_all + movia r4, PREEMPT_ACTIVE + stw r4, TI_PREEMPT_COUNT(r1) + rdctl r10, status /* enable intrs again */ + ori r10, r10 ,STATUS_PIE + wrctl status, r10 + PUSH r1 + call schedule + POP r1 + mov r4, r0 + stw r4, TI_PREEMPT_COUNT(r1) + rdctl r10, status /* disable intrs */ + andi r10, r10, %lo(~STATUS_PIE) + wrctl status, r10 + br need_resched +#else + br restore_all +#endif + +/*********************************************************************** + * A few syscall wrappers + *********************************************************************** + */ +/* + * int clone(unsigned long clone_flags, unsigned long newsp, + * int __user * parent_tidptr, int __user * child_tidptr, + * int tls_val) + */ +ENTRY(sys_clone) + SAVE_SWITCH_STACK + addi sp, sp, -4 + stw r7, 0(sp) /* Pass 5th arg thru stack */ + mov r7, r6 /* 4th arg is 3rd of clone() */ + mov r6, zero /* 3rd arg always 0 */ + call do_fork + addi sp, sp, 4 + RESTORE_SWITCH_STACK + ret + +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + mov r4, sp + call do_rt_sigreturn + RESTORE_SWITCH_STACK + addi ra, ra, (end_translate_rc_and_ret - translate_rc_and_ret) + ret + +/*********************************************************************** + * A few other wrappers and stubs + *********************************************************************** + */ +protection_exception_pte: + rdctl r6, pteaddr + slli r6, r6, 10 + call do_page_fault + br ret_from_exception + +protection_exception_ba: + rdctl r6, badaddr + call do_page_fault + br ret_from_exception + +protection_exception_instr: + call handle_supervisor_instr + br ret_from_exception + +handle_breakpoint: + call breakpoint_c + br ret_from_exception + +#ifdef CONFIG_NIOS2_ALIGNMENT_TRAP +handle_unaligned: + SAVE_SWITCH_STACK + call handle_unaligned_c + RESTORE_SWITCH_STACK + br ret_from_exception +#else +handle_unaligned: + call handle_unaligned_c + br ret_from_exception +#endif + +handle_illegal: + call handle_illegal_c + br ret_from_exception + +handle_diverror: + call handle_diverror_c + br ret_from_exception + +/* + * Beware - when entering resume, prev (the current task) is + * in r4, next (the new task) is in r5, don't change these + * registers. + */ +ENTRY(resume) + + rdctl r7, status /* save thread status reg */ + stw r7, TASK_THREAD + THREAD_KPSR(r4) + + andi r7, r7, %lo(~STATUS_PIE) /* disable interrupts */ + wrctl status, r7 + + SAVE_SWITCH_STACK + stw sp, TASK_THREAD + THREAD_KSP(r4)/* save kernel stack pointer */ + ldw sp, TASK_THREAD + THREAD_KSP(r5)/* restore new thread stack */ + movia r24, _current_thread /* save thread */ + GET_THREAD_INFO r1 + stw r1, 0(r24) + RESTORE_SWITCH_STACK + + ldw r7, TASK_THREAD + THREAD_KPSR(r5)/* restore thread status reg */ + wrctl status, r7 + ret + +ENTRY(ret_from_fork) + call schedule_tail + br ret_from_exception + +ENTRY(ret_from_kernel_thread) + call schedule_tail + mov r4,r17 /* arg */ + callr r16 /* function */ + br ret_from_exception + +/* + * Kernel user helpers. + * + * Each segment is 64-byte aligned and will be mapped to the <User space>. + * New segments (if ever needed) must be added after the existing ones. + * This mechanism should be used only for things that are really small and + * justified, and not be abused freely. + * + */ + + /* Filling pads with undefined instructions. */ +.macro kuser_pad sym size + .if ((. - \sym) & 3) + .rept (4 - (. - \sym) & 3) + .byte 0 + .endr + .endif + .rept ((\size - (. - \sym)) / 4) + .word 0xdeadbeef + .endr +.endm + + .align 6 + .globl __kuser_helper_start +__kuser_helper_start: + +__kuser_helper_version: /* @ 0x1000 */ + .word ((__kuser_helper_end - __kuser_helper_start) >> 6) + +__kuser_cmpxchg: /* @ 0x1004 */ + /* + * r4 pointer to exchange variable + * r5 old value + * r6 new value + */ +cmpxchg_ldw: + ldw r2, 0(r4) /* load current value */ + sub r2, r2, r5 /* compare with old value */ + bne r2, zero, cmpxchg_ret + + /* We had a match, store the new value */ +cmpxchg_stw: + stw r6, 0(r4) +cmpxchg_ret: + ret + + kuser_pad __kuser_cmpxchg, 64 + + .globl __kuser_sigtramp +__kuser_sigtramp: + movi r2, __NR_rt_sigreturn + trap + + kuser_pad __kuser_sigtramp, 64 + + .globl __kuser_helper_end +__kuser_helper_end: diff --git a/arch/nios2/kernel/head.S b/arch/nios2/kernel/head.S new file mode 100644 index 000000000000..372ce4a33018 --- /dev/null +++ b/arch/nios2/kernel/head.S @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * Copyright (C) 2004 Microtronix Datacom Ltd + * Copyright (C) 2001 Vic Phillips, Microtronix Datacom Ltd. + * + * Based on head.S for Altera's Excalibur development board with nios processor + * + * Based on the following from the Excalibur sdk distribution: + * NA_MemoryMap.s, NR_JumpToStart.s, NR_Setup.s, NR_CWPManager.s + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/init.h> +#include <linux/linkage.h> +#include <asm/thread_info.h> +#include <asm/processor.h> +#include <asm/cache.h> +#include <asm/page.h> +#include <asm/asm-offsets.h> +#include <asm/asm-macros.h> + +/* + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +.data +.global empty_zero_page +.align 12 +empty_zero_page: + .space PAGE_SIZE + +/* + * This global variable is used as an extension to the nios' + * STATUS register to emulate a user/supervisor mode. + */ + .data + .align 2 + .set noat + + .global _current_thread +_current_thread: + .long 0 +/* + * Input(s): passed from u-boot + * r4 - Optional pointer to a board information structure. + * r5 - Optional pointer to the physical starting address of the init RAM + * disk. + * r6 - Optional pointer to the physical ending address of the init RAM + * disk. + * r7 - Optional pointer to the physical starting address of any kernel + * command-line parameters. + */ + +/* + * First executable code - detected and jumped to by the ROM bootstrap + * if the code resides in flash (looks for "Nios" at offset 0x0c from + * the potential executable image). + */ + __HEAD +ENTRY(_start) + wrctl status, r0 /* Disable interrupts */ + + /* Initialize all cache lines within the instruction cache */ + movia r1, NIOS2_ICACHE_SIZE + movui r2, NIOS2_ICACHE_LINE_SIZE + +icache_init: + initi r1 + sub r1, r1, r2 + bgt r1, r0, icache_init + br 1f + + /* + * This is the default location for the exception handler. Code in jump + * to our handler + */ +ENTRY(exception_handler_hook) + movia r24, inthandler + jmp r24 + +ENTRY(fast_handler) + nextpc et +helper: + stw r3, r3save - helper(et) + + rdctl r3 , pteaddr + srli r3, r3, 12 + slli r3, r3, 2 + movia et, pgd_current + + ldw et, 0(et) + add r3, et, r3 + ldw et, 0(r3) + + rdctl r3, pteaddr + andi r3, r3, 0xfff + add et, r3, et + ldw et, 0(et) + wrctl tlbacc, et + nextpc et +helper2: + ldw r3, r3save - helper2(et) + subi ea, ea, 4 + eret +r3save: + .word 0x0 +ENTRY(fast_handler_end) + +1: + /* + * After the instruction cache is initialized, the data cache must + * also be initialized. + */ + movia r1, NIOS2_DCACHE_SIZE + movui r2, NIOS2_DCACHE_LINE_SIZE + +dcache_init: + initd 0(r1) + sub r1, r1, r2 + bgt r1, r0, dcache_init + + nextpc r1 /* Find out where we are */ +chkadr: + movia r2, chkadr + beq r1, r2,finish_move /* We are running in RAM done */ + addi r1, r1,(_start - chkadr) /* Source */ + movia r2, _start /* Destination */ + movia r3, __bss_start /* End of copy */ + +loop_move: /* r1: src, r2: dest, r3: last dest */ + ldw r8, 0(r1) /* load a word from [r1] */ + stw r8, 0(r2) /* store a word to dest [r2] */ + flushd 0(r2) /* Flush cache for safety */ + addi r1, r1, 4 /* inc the src addr */ + addi r2, r2, 4 /* inc the dest addr */ + blt r2, r3, loop_move + + movia r1, finish_move /* VMA(_start)->l1 */ + jmp r1 /* jmp to _start */ + +finish_move: + + /* Mask off all possible interrupts */ + wrctl ienable, r0 + + /* Clear .bss */ + movia r2, __bss_start + movia r1, __bss_stop +1: + stb r0, 0(r2) + addi r2, r2, 1 + bne r1, r2, 1b + + movia r1, init_thread_union /* set stack at top of the task union */ + addi sp, r1, THREAD_SIZE + movia r2, _current_thread /* Remember current thread */ + stw r1, 0(r2) + + movia r1, nios2_boot_init /* save args r4-r7 passed from u-boot */ + callr r1 + + movia r1, start_kernel /* call start_kernel as a subroutine */ + callr r1 + + /* If we return from start_kernel, break to the oci debugger and + * buggered we are. + */ + break + + /* End of startup code */ +.set at diff --git a/arch/nios2/kernel/insnemu.S b/arch/nios2/kernel/insnemu.S new file mode 100644 index 000000000000..1c6b651e770d --- /dev/null +++ b/arch/nios2/kernel/insnemu.S @@ -0,0 +1,592 @@ +/* + * Copyright (C) 2003-2013 Altera Corporation + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include <linux/linkage.h> +#include <asm/entry.h> + +.set noat +.set nobreak + +/* +* Explicitly allow the use of r1 (the assembler temporary register) +* within this code. This register is normally reserved for the use of +* the compiler. +*/ + +ENTRY(instruction_trap) + ldw r1, PT_R1(sp) // Restore registers + ldw r2, PT_R2(sp) + ldw r3, PT_R3(sp) + ldw r4, PT_R4(sp) + ldw r5, PT_R5(sp) + ldw r6, PT_R6(sp) + ldw r7, PT_R7(sp) + ldw r8, PT_R8(sp) + ldw r9, PT_R9(sp) + ldw r10, PT_R10(sp) + ldw r11, PT_R11(sp) + ldw r12, PT_R12(sp) + ldw r13, PT_R13(sp) + ldw r14, PT_R14(sp) + ldw r15, PT_R15(sp) + ldw ra, PT_RA(sp) + ldw fp, PT_FP(sp) + ldw gp, PT_GP(sp) + ldw et, PT_ESTATUS(sp) + wrctl estatus, et + ldw ea, PT_EA(sp) + ldw et, PT_SP(sp) /* backup sp in et */ + + addi sp, sp, PT_REGS_SIZE + + /* INSTRUCTION EMULATION + * --------------------- + * + * Nios II processors generate exceptions for unimplemented instructions. + * The routines below emulate these instructions. Depending on the + * processor core, the only instructions that might need to be emulated + * are div, divu, mul, muli, mulxss, mulxsu, and mulxuu. + * + * The emulations match the instructions, except for the following + * limitations: + * + * 1) The emulation routines do not emulate the use of the exception + * temporary register (et) as a source operand because the exception + * handler already has modified it. + * + * 2) The routines do not emulate the use of the stack pointer (sp) or + * the exception return address register (ea) as a destination because + * modifying these registers crashes the exception handler or the + * interrupted routine. + * + * Detailed Design + * --------------- + * + * The emulation routines expect the contents of integer registers r0-r31 + * to be on the stack at addresses sp, 4(sp), 8(sp), ... 124(sp). The + * routines retrieve source operands from the stack and modify the + * destination register's value on the stack prior to the end of the + * exception handler. Then all registers except the destination register + * are restored to their previous values. + * + * The instruction that causes the exception is found at address -4(ea). + * The instruction's OP and OPX fields identify the operation to be + * performed. + * + * One instruction, muli, is an I-type instruction that is identified by + * an OP field of 0x24. + * + * muli AAAAA,BBBBB,IIIIIIIIIIIIIIII,-0x24- + * 27 22 6 0 <-- LSB of field + * + * The remaining emulated instructions are R-type and have an OP field + * of 0x3a. Their OPX fields identify them. + * + * R-type AAAAA,BBBBB,CCCCC,XXXXXX,NNNNN,-0x3a- + * 27 22 17 11 6 0 <-- LSB of field + * + * + * Opcode Encoding. muli is identified by its OP value. Then OPX & 0x02 + * is used to differentiate between the division opcodes and the + * remaining multiplication opcodes. + * + * Instruction OP OPX OPX & 0x02 + * ----------- ---- ---- ---------- + * muli 0x24 + * divu 0x3a 0x24 0 + * div 0x3a 0x25 0 + * mul 0x3a 0x27 != 0 + * mulxuu 0x3a 0x07 != 0 + * mulxsu 0x3a 0x17 != 0 + * mulxss 0x3a 0x1f != 0 + */ + + + /* + * Save everything on the stack to make it easy for the emulation + * routines to retrieve the source register operands. + */ + + addi sp, sp, -128 + stw zero, 0(sp) /* Save zero on stack to avoid special case for r0. */ + stw r1, 4(sp) + stw r2, 8(sp) + stw r3, 12(sp) + stw r4, 16(sp) + stw r5, 20(sp) + stw r6, 24(sp) + stw r7, 28(sp) + stw r8, 32(sp) + stw r9, 36(sp) + stw r10, 40(sp) + stw r11, 44(sp) + stw r12, 48(sp) + stw r13, 52(sp) + stw r14, 56(sp) + stw r15, 60(sp) + stw r16, 64(sp) + stw r17, 68(sp) + stw r18, 72(sp) + stw r19, 76(sp) + stw r20, 80(sp) + stw r21, 84(sp) + stw r22, 88(sp) + stw r23, 92(sp) + /* Don't bother to save et. It's already been changed. */ + rdctl r5, estatus + stw r5, 100(sp) + + stw gp, 104(sp) + stw et, 108(sp) /* et contains previous sp value. */ + stw fp, 112(sp) + stw ea, 116(sp) + stw ra, 120(sp) + + + /* + * Split the instruction into its fields. We need 4*A, 4*B, and 4*C as + * offsets to the stack pointer for access to the stored register values. + */ + ldw r2,-4(ea) /* r2 = AAAAA,BBBBB,IIIIIIIIIIIIIIII,PPPPPP */ + roli r3, r2, 7 /* r3 = BBB,IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BB */ + roli r4, r3, 3 /* r4 = IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB */ + roli r5, r4, 2 /* r5 = IIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB,II */ + srai r4, r4, 16 /* r4 = (sign-extended) IMM16 */ + roli r6, r5, 5 /* r6 = XXXX,NNNNN,PPPPPP,AAAAA,BBBBB,CCCCC,XX */ + andi r2, r2, 0x3f /* r2 = 00000000000000000000000000,PPPPPP */ + andi r3, r3, 0x7c /* r3 = 0000000000000000000000000,AAAAA,00 */ + andi r5, r5, 0x7c /* r5 = 0000000000000000000000000,BBBBB,00 */ + andi r6, r6, 0x7c /* r6 = 0000000000000000000000000,CCCCC,00 */ + + /* Now + * r2 = OP + * r3 = 4*A + * r4 = IMM16 (sign extended) + * r5 = 4*B + * r6 = 4*C + */ + + /* + * Get the operands. + * + * It is necessary to check for muli because it uses an I-type + * instruction format, while the other instructions are have an R-type + * format. + * + * Prepare for either multiplication or division loop. + * They both loop 32 times. + */ + movi r14, 32 + + add r3, r3, sp /* r3 = address of A-operand. */ + ldw r3, 0(r3) /* r3 = A-operand. */ + movi r7, 0x24 /* muli opcode (I-type instruction format) */ + beq r2, r7, mul_immed /* muli doesn't use the B register as a source */ + + add r5, r5, sp /* r5 = address of B-operand. */ + ldw r5, 0(r5) /* r5 = B-operand. */ + /* r4 = SSSSSSSSSSSSSSSS,-----IMM16------ */ + /* IMM16 not needed, align OPX portion */ + /* r4 = SSSSSSSSSSSSSSSS,CCCCC,-OPX--,00000 */ + srli r4, r4, 5 /* r4 = 00000,SSSSSSSSSSSSSSSS,CCCCC,-OPX-- */ + andi r4, r4, 0x3f /* r4 = 00000000000000000000000000,-OPX-- */ + + /* Now + * r2 = OP + * r3 = src1 + * r5 = src2 + * r4 = OPX (no longer can be muli) + * r6 = 4*C + */ + + + /* + * Multiply or Divide? + */ + andi r7, r4, 0x02 /* For R-type multiply instructions, + OPX & 0x02 != 0 */ + bne r7, zero, multiply + + + /* DIVISION + * + * Divide an unsigned dividend by an unsigned divisor using + * a shift-and-subtract algorithm. The example below shows + * 43 div 7 = 6 for 8-bit integers. This classic algorithm uses a + * single register to store both the dividend and the quotient, + * allowing both values to be shifted with a single instruction. + * + * remainder dividend:quotient + * --------- ----------------- + * initialize 00000000 00101011: + * shift 00000000 0101011:_ + * remainder >= divisor? no 00000000 0101011:0 + * shift 00000000 101011:0_ + * remainder >= divisor? no 00000000 101011:00 + * shift 00000001 01011:00_ + * remainder >= divisor? no 00000001 01011:000 + * shift 00000010 1011:000_ + * remainder >= divisor? no 00000010 1011:0000 + * shift 00000101 011:0000_ + * remainder >= divisor? no 00000101 011:00000 + * shift 00001010 11:00000_ + * remainder >= divisor? yes 00001010 11:000001 + * remainder -= divisor - 00000111 + * ---------- + * 00000011 11:000001 + * shift 00000111 1:000001_ + * remainder >= divisor? yes 00000111 1:0000011 + * remainder -= divisor - 00000111 + * ---------- + * 00000000 1:0000011 + * shift 00000001 :0000011_ + * remainder >= divisor? no 00000001 :00000110 + * + * The quotient is 00000110. + */ + +divide: + /* + * Prepare for division by assuming the result + * is unsigned, and storing its "sign" as 0. + */ + movi r17, 0 + + + /* Which division opcode? */ + xori r7, r4, 0x25 /* OPX of div */ + bne r7, zero, unsigned_division + + + /* + * OPX is div. Determine and store the sign of the quotient. + * Then take the absolute value of both operands. + */ + xor r17, r3, r5 /* MSB contains sign of quotient */ + bge r3,zero,dividend_is_nonnegative + sub r3, zero, r3 /* -r3 */ +dividend_is_nonnegative: + bge r5, zero, divisor_is_nonnegative + sub r5, zero, r5 /* -r5 */ +divisor_is_nonnegative: + + +unsigned_division: + /* Initialize the unsigned-division loop. */ + movi r13, 0 /* remainder = 0 */ + + /* Now + * r3 = dividend : quotient + * r4 = 0x25 for div, 0x24 for divu + * r5 = divisor + * r13 = remainder + * r14 = loop counter (already initialized to 32) + * r17 = MSB contains sign of quotient + */ + + + /* + * for (count = 32; count > 0; --count) + * { + */ +divide_loop: + + /* + * Division: + * + * (remainder:dividend:quotient) <<= 1; + */ + slli r13, r13, 1 + cmplt r7, r3, zero /* r7 = MSB of r3 */ + or r13, r13, r7 + slli r3, r3, 1 + + + /* + * if (remainder >= divisor) + * { + * set LSB of quotient + * remainder -= divisor; + * } + */ + bltu r13, r5, div_skip + ori r3, r3, 1 + sub r13, r13, r5 +div_skip: + + /* + * } + */ + subi r14, r14, 1 + bne r14, zero, divide_loop + + + /* Now + * r3 = quotient + * r4 = 0x25 for div, 0x24 for divu + * r6 = 4*C + * r17 = MSB contains sign of quotient + */ + + + /* + * Conditionally negate signed quotient. If quotient is unsigned, + * the sign already is initialized to 0. + */ + bge r17, zero, quotient_is_nonnegative + sub r3, zero, r3 /* -r3 */ + quotient_is_nonnegative: + + + /* + * Final quotient is in r3. + */ + add r6, r6, sp + stw r3, 0(r6) /* write quotient to stack */ + br restore_registers + + + + + /* MULTIPLICATION + * + * A "product" is the number that one gets by summing a "multiplicand" + * several times. The "multiplier" specifies the number of copies of the + * multiplicand that are summed. + * + * Actual multiplication algorithms don't use repeated addition, however. + * Shift-and-add algorithms get the same answer as repeated addition, and + * they are faster. To compute the lower half of a product (pppp below) + * one shifts the product left before adding in each of the partial + * products (a * mmmm) through (d * mmmm). + * + * To compute the upper half of a product (PPPP below), one adds in the + * partial products (d * mmmm) through (a * mmmm), each time following + * the add by a right shift of the product. + * + * mmmm + * * abcd + * ------ + * #### = d * mmmm + * #### = c * mmmm + * #### = b * mmmm + * #### = a * mmmm + * -------- + * PPPPpppp + * + * The example above shows 4 partial products. Computing actual Nios II + * products requires 32 partials. + * + * It is possible to compute the result of mulxsu from the result of + * mulxuu because the only difference between the results of these two + * opcodes is the value of the partial product associated with the sign + * bit of rA. + * + * mulxsu = mulxuu - (rA < 0) ? rB : 0; + * + * It is possible to compute the result of mulxss from the result of + * mulxsu because the only difference between the results of these two + * opcodes is the value of the partial product associated with the sign + * bit of rB. + * + * mulxss = mulxsu - (rB < 0) ? rA : 0; + * + */ + +mul_immed: + /* Opcode is muli. Change it into mul for remainder of algorithm. */ + mov r6, r5 /* Field B is dest register, not field C. */ + mov r5, r4 /* Field IMM16 is src2, not field B. */ + movi r4, 0x27 /* OPX of mul is 0x27 */ + +multiply: + /* Initialize the multiplication loop. */ + movi r9, 0 /* mul_product = 0 */ + movi r10, 0 /* mulxuu_product = 0 */ + mov r11, r5 /* save original multiplier for mulxsu and mulxss */ + mov r12, r5 /* mulxuu_multiplier (will be shifted) */ + movi r16, 1 /* used to create "rori B,A,1" from "ror B,A,r16" */ + + /* Now + * r3 = multiplicand + * r5 = mul_multiplier + * r6 = 4 * dest_register (used later as offset to sp) + * r7 = temp + * r9 = mul_product + * r10 = mulxuu_product + * r11 = original multiplier + * r12 = mulxuu_multiplier + * r14 = loop counter (already initialized) + * r16 = 1 + */ + + + /* + * for (count = 32; count > 0; --count) + * { + */ +multiply_loop: + + /* + * mul_product <<= 1; + * lsb = multiplier & 1; + */ + slli r9, r9, 1 + andi r7, r12, 1 + + /* + * if (lsb == 1) + * { + * mulxuu_product += multiplicand; + * } + */ + beq r7, zero, mulx_skip + add r10, r10, r3 + cmpltu r7, r10, r3 /* Save the carry from the MSB of mulxuu_product. */ + ror r7, r7, r16 /* r7 = 0x80000000 on carry, or else 0x00000000 */ +mulx_skip: + + /* + * if (MSB of mul_multiplier == 1) + * { + * mul_product += multiplicand; + * } + */ + bge r5, zero, mul_skip + add r9, r9, r3 +mul_skip: + + /* + * mulxuu_product >>= 1; logical shift + * mul_multiplier <<= 1; done with MSB + * mulx_multiplier >>= 1; done with LSB + */ + srli r10, r10, 1 + or r10, r10, r7 /* OR in the saved carry bit. */ + slli r5, r5, 1 + srli r12, r12, 1 + + + /* + * } + */ + subi r14, r14, 1 + bne r14, zero, multiply_loop + + + /* + * Multiply emulation loop done. + */ + + /* Now + * r3 = multiplicand + * r4 = OPX + * r6 = 4 * dest_register (used later as offset to sp) + * r7 = temp + * r9 = mul_product + * r10 = mulxuu_product + * r11 = original multiplier + */ + + + /* Calculate address for result from 4 * dest_register */ + add r6, r6, sp + + + /* + * Select/compute the result based on OPX. + */ + + + /* OPX == mul? Then store. */ + xori r7, r4, 0x27 + beq r7, zero, store_product + + /* It's one of the mulx.. opcodes. Move over the result. */ + mov r9, r10 + + /* OPX == mulxuu? Then store. */ + xori r7, r4, 0x07 + beq r7, zero, store_product + + /* Compute mulxsu + * + * mulxsu = mulxuu - (rA < 0) ? rB : 0; + */ + bge r3, zero, mulxsu_skip + sub r9, r9, r11 +mulxsu_skip: + + /* OPX == mulxsu? Then store. */ + xori r7, r4, 0x17 + beq r7, zero, store_product + + /* Compute mulxss + * + * mulxss = mulxsu - (rB < 0) ? rA : 0; + */ + bge r11,zero,mulxss_skip + sub r9, r9, r3 +mulxss_skip: + /* At this point, assume that OPX is mulxss, so store*/ + + +store_product: + stw r9, 0(r6) + + +restore_registers: + /* No need to restore r0. */ + ldw r5, 100(sp) + wrctl estatus, r5 + + ldw r1, 4(sp) + ldw r2, 8(sp) + ldw r3, 12(sp) + ldw r4, 16(sp) + ldw r5, 20(sp) + ldw r6, 24(sp) + ldw r7, 28(sp) + ldw r8, 32(sp) + ldw r9, 36(sp) + ldw r10, 40(sp) + ldw r11, 44(sp) + ldw r12, 48(sp) + ldw r13, 52(sp) + ldw r14, 56(sp) + ldw r15, 60(sp) + ldw r16, 64(sp) + ldw r17, 68(sp) + ldw r18, 72(sp) + ldw r19, 76(sp) + ldw r20, 80(sp) + ldw r21, 84(sp) + ldw r22, 88(sp) + ldw r23, 92(sp) + /* Does not need to restore et */ + ldw gp, 104(sp) + + ldw fp, 112(sp) + ldw ea, 116(sp) + ldw ra, 120(sp) + ldw sp, 108(sp) /* last restore sp */ + eret + +.set at +.set break diff --git a/arch/nios2/kernel/irq.c b/arch/nios2/kernel/irq.c new file mode 100644 index 000000000000..f5b74ae69b5b --- /dev/null +++ b/arch/nios2/kernel/irq.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw> + * + * based on irq.c from m68k which is: + * + * Copyright (C) 2007 Greg Ungerer <gerg@snapgear.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/of.h> + +static u32 ienable; + +asmlinkage void do_IRQ(int hwirq, struct pt_regs *regs) +{ + struct pt_regs *oldregs = set_irq_regs(regs); + int irq; + + irq_enter(); + irq = irq_find_mapping(NULL, hwirq); + generic_handle_irq(irq); + irq_exit(); + + set_irq_regs(oldregs); +} + +static void chip_unmask(struct irq_data *d) +{ + ienable |= (1 << d->hwirq); + WRCTL(CTL_IENABLE, ienable); +} + +static void chip_mask(struct irq_data *d) +{ + ienable &= ~(1 << d->hwirq); + WRCTL(CTL_IENABLE, ienable); +} + +static struct irq_chip m_irq_chip = { + .name = "NIOS2-INTC", + .irq_unmask = chip_unmask, + .irq_mask = chip_mask, +}; + +static int irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw_irq_num) +{ + irq_set_chip_and_handler(virq, &m_irq_chip, handle_level_irq); + + return 0; +} + +static struct irq_domain_ops irq_ops = { + .map = irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +void __init init_IRQ(void) +{ + struct irq_domain *domain; + struct device_node *node; + + node = of_find_compatible_node(NULL, NULL, "altr,nios2-1.0"); + if (!node) + node = of_find_compatible_node(NULL, NULL, "altr,nios2-1.1"); + + BUG_ON(!node); + + domain = irq_domain_add_linear(node, NIOS2_CPU_NR_IRQS, &irq_ops, NULL); + BUG_ON(!domain); + + irq_set_default_host(domain); + of_node_put(node); + /* Load the initial ienable value */ + ienable = RDCTL(CTL_IENABLE); +} diff --git a/arch/nios2/kernel/misaligned.c b/arch/nios2/kernel/misaligned.c new file mode 100644 index 000000000000..4e5907a0cabe --- /dev/null +++ b/arch/nios2/kernel/misaligned.c @@ -0,0 +1,256 @@ +/* + * linux/arch/nios2/kernel/misaligned.c + * + * basic emulation for mis-aligned accesses on the NIOS II cpu + * modelled after the version for arm in arm/alignment.c + * + * Brad Parker <brad@heeltoe.com> + * Copyright (C) 2010 Ambient Corporation + * Copyright (c) 2010 Altera Corporation, San Jose, California, USA. + * Copyright (c) 2010 Arrow Electronics, Inc. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of + * this archive for more details. + */ + +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/uaccess.h> +#include <linux/seq_file.h> + +#include <asm/traps.h> +#include <asm/unaligned.h> + +/* instructions we emulate */ +#define INST_LDHU 0x0b +#define INST_STH 0x0d +#define INST_LDH 0x0f +#define INST_STW 0x15 +#define INST_LDW 0x17 + +static unsigned long ma_user, ma_kern, ma_skipped, ma_half, ma_word; + +static unsigned int ma_usermode; +#define UM_WARN 0x01 +#define UM_FIXUP 0x02 +#define UM_SIGNAL 0x04 +#define KM_WARN 0x08 + +/* see arch/nios2/include/asm/ptrace.h */ +static u8 sys_stack_frame_reg_offset[] = { + /* struct pt_regs */ + 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 0, + /* struct switch_stack */ + 16, 17, 18, 19, 20, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int reg_offsets[32]; + +static inline u32 get_reg_val(struct pt_regs *fp, int reg) +{ + u8 *p = ((u8 *)fp) + reg_offsets[reg]; + + return *(u32 *)p; +} + +static inline void put_reg_val(struct pt_regs *fp, int reg, u32 val) +{ + u8 *p = ((u8 *)fp) + reg_offsets[reg]; + *(u32 *)p = val; +} + +/* + * (mis)alignment handler + */ +asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) +{ + u32 isn, addr, val; + int in_kernel; + u8 a, b, d0, d1, d2, d3; + u16 imm16; + unsigned int fault; + + /* back up one instruction */ + fp->ea -= 4; + + if (fixup_exception(fp)) { + ma_skipped++; + return; + } + + in_kernel = !user_mode(fp); + + isn = *(unsigned long *)(fp->ea); + + fault = 0; + + /* do fixup if in kernel or mode turned on */ + if (in_kernel || (ma_usermode & UM_FIXUP)) { + /* decompose instruction */ + a = (isn >> 27) & 0x1f; + b = (isn >> 22) & 0x1f; + imm16 = (isn >> 6) & 0xffff; + addr = get_reg_val(fp, a) + imm16; + + /* do fixup to saved registers */ + switch (isn & 0x3f) { + case INST_LDHU: + fault |= __get_user(d0, (u8 *)(addr+0)); + fault |= __get_user(d1, (u8 *)(addr+1)); + val = (d1 << 8) | d0; + put_reg_val(fp, b, val); + ma_half++; + break; + case INST_STH: + val = get_reg_val(fp, b); + d1 = val >> 8; + d0 = val >> 0; + + pr_debug("sth: ra=%d (%08x) rb=%d (%08x), imm16 %04x addr %08x val %08x\n", + a, get_reg_val(fp, a), + b, get_reg_val(fp, b), + imm16, addr, val); + + if (in_kernel) { + *(u8 *)(addr+0) = d0; + *(u8 *)(addr+1) = d1; + } else { + fault |= __put_user(d0, (u8 *)(addr+0)); + fault |= __put_user(d1, (u8 *)(addr+1)); + } + ma_half++; + break; + case INST_LDH: + fault |= __get_user(d0, (u8 *)(addr+0)); + fault |= __get_user(d1, (u8 *)(addr+1)); + val = (short)((d1 << 8) | d0); + put_reg_val(fp, b, val); + ma_half++; + break; + case INST_STW: + val = get_reg_val(fp, b); + d3 = val >> 24; + d2 = val >> 16; + d1 = val >> 8; + d0 = val >> 0; + if (in_kernel) { + *(u8 *)(addr+0) = d0; + *(u8 *)(addr+1) = d1; + *(u8 *)(addr+2) = d2; + *(u8 *)(addr+3) = d3; + } else { + fault |= __put_user(d0, (u8 *)(addr+0)); + fault |= __put_user(d1, (u8 *)(addr+1)); + fault |= __put_user(d2, (u8 *)(addr+2)); + fault |= __put_user(d3, (u8 *)(addr+3)); + } + ma_word++; + break; + case INST_LDW: + fault |= __get_user(d0, (u8 *)(addr+0)); + fault |= __get_user(d1, (u8 *)(addr+1)); + fault |= __get_user(d2, (u8 *)(addr+2)); + fault |= __get_user(d3, (u8 *)(addr+3)); + val = (d3 << 24) | (d2 << 16) | (d1 << 8) | d0; + put_reg_val(fp, b, val); + ma_word++; + break; + } + } + + addr = RDCTL(CTL_BADADDR); + cause >>= 2; + + if (fault) { + if (in_kernel) { + pr_err("fault during kernel misaligned fixup @ %#lx; addr 0x%08x; isn=0x%08x\n", + fp->ea, (unsigned int)addr, + (unsigned int)isn); + } else { + pr_err("fault during user misaligned fixup @ %#lx; isn=%08x addr=0x%08x sp=0x%08lx pid=%d\n", + fp->ea, + (unsigned int)isn, addr, fp->sp, + current->pid); + + _exception(SIGSEGV, fp, SEGV_MAPERR, fp->ea); + return; + } + } + + /* + * kernel mode - + * note exception and skip bad instruction (return) + */ + if (in_kernel) { + ma_kern++; + fp->ea += 4; + + if (ma_usermode & KM_WARN) { + pr_err("kernel unaligned access @ %#lx; BADADDR 0x%08x; cause=%d, isn=0x%08x\n", + fp->ea, + (unsigned int)addr, cause, + (unsigned int)isn); + /* show_regs(fp); */ + } + + return; + } + + ma_user++; + + /* + * user mode - + * possibly warn, + * possibly send SIGBUS signal to process + */ + if (ma_usermode & UM_WARN) { + pr_err("user unaligned access @ %#lx; isn=0x%08lx ea=0x%08lx ra=0x%08lx sp=0x%08lx\n", + (unsigned long)addr, (unsigned long)isn, + fp->ea, fp->ra, fp->sp); + } + + if (ma_usermode & UM_SIGNAL) + _exception(SIGBUS, fp, BUS_ADRALN, fp->ea); + else + fp->ea += 4; /* else advance */ +} + +static void __init misaligned_calc_reg_offsets(void) +{ + int i, r, offset; + + /* pre-calc offsets of registers on sys call stack frame */ + offset = 0; + + /* struct pt_regs */ + for (i = 0; i < 16; i++) { + r = sys_stack_frame_reg_offset[i]; + reg_offsets[r] = offset; + offset += 4; + } + + /* struct switch_stack */ + offset = -sizeof(struct switch_stack); + for (i = 16; i < 32; i++) { + r = sys_stack_frame_reg_offset[i]; + reg_offsets[r] = offset; + offset += 4; + } +} + + +static int __init misaligned_init(void) +{ + /* default mode - silent fix */ + ma_usermode = UM_FIXUP | KM_WARN; + + misaligned_calc_reg_offsets(); + + return 0; +} + +fs_initcall(misaligned_init); diff --git a/arch/nios2/kernel/module.c b/arch/nios2/kernel/module.c new file mode 100644 index 000000000000..cc924a38f22a --- /dev/null +++ b/arch/nios2/kernel/module.c @@ -0,0 +1,138 @@ +/* + * Kernel module support for Nios II. + * + * Copyright (C) 2004 Microtronix Datacom Ltd. + * Written by Wentao Xu <xuwentao@microtronix.com> + * Copyright (C) 2001, 2003 Rusty Russell + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#include <asm/pgtable.h> +#include <asm/cacheflush.h> + +/* + * Modules should NOT be allocated with kmalloc for (obvious) reasons. + * But we do it for now to avoid relocation issues. CALL26/PCREL26 cannot reach + * from 0x80000000 (vmalloc area) to 0xc00000000 (kernel) (kmalloc returns + * addresses in 0xc0000000) + */ +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return kmalloc(size, GFP_KERNEL); +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + kfree(module_region); +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *mod) +{ + unsigned int i; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; + + pr_debug("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) { + /* This is where to make the change */ + uint32_t word; + uint32_t *loc + = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rela[i].r_offset); + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + Elf32_Sym *sym + = ((Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rela[i].r_info)); + uint32_t v = sym->st_value + rela[i].r_addend; + + pr_debug("reltype %d 0x%x name:<%s>\n", + ELF32_R_TYPE(rela[i].r_info), + rela[i].r_offset, strtab + sym->st_name); + + switch (ELF32_R_TYPE(rela[i].r_info)) { + case R_NIOS2_NONE: + break; + case R_NIOS2_BFD_RELOC_32: + *loc += v; + break; + case R_NIOS2_PCREL16: + v -= (uint32_t)loc + 4; + if ((int32_t)v > 0x7fff || + (int32_t)v < -(int32_t)0x8000) { + pr_err("module %s: relocation overflow\n", + mod->name); + return -ENOEXEC; + } + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | + (word & 0x3f); + break; + case R_NIOS2_CALL26: + if (v & 3) { + pr_err("module %s: dangerous relocation\n", + mod->name); + return -ENOEXEC; + } + if ((v >> 28) != ((uint32_t)loc >> 28)) { + pr_err("module %s: relocation overflow\n", + mod->name); + return -ENOEXEC; + } + *loc = (*loc & 0x3f) | ((v >> 2) << 6); + break; + case R_NIOS2_HI16: + word = *loc; + *loc = ((((word >> 22) << 16) | + ((v >> 16) & 0xffff)) << 6) | (word & 0x3f); + break; + case R_NIOS2_LO16: + word = *loc; + *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | + (word & 0x3f); + break; + case R_NIOS2_HIADJ16: + { + Elf32_Addr word2; + + word = *loc; + word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff; + *loc = ((((word >> 22) << 16) | word2) << 6) | + (word & 0x3f); + } + break; + + default: + pr_err("module %s: Unknown reloc: %u\n", + mod->name, ELF32_R_TYPE(rela[i].r_info)); + return -ENOEXEC; + } + } + + return 0; +} + +int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, + struct module *me) +{ + flush_cache_all(); + return 0; +} diff --git a/arch/nios2/kernel/nios2_ksyms.c b/arch/nios2/kernel/nios2_ksyms.c new file mode 100644 index 000000000000..bf2f55d10a4d --- /dev/null +++ b/arch/nios2/kernel/nios2_ksyms.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include <linux/export.h> +#include <linux/string.h> + +/* string functions */ + +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); + +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +#define DECLARE_EXPORT(name) extern void name(void); EXPORT_SYMBOL(name) + +DECLARE_EXPORT(__gcc_bcmp); +DECLARE_EXPORT(__divsi3); +DECLARE_EXPORT(__moddi3); +DECLARE_EXPORT(__modsi3); +DECLARE_EXPORT(__udivmoddi4); +DECLARE_EXPORT(__udivsi3); +DECLARE_EXPORT(__umoddi3); +DECLARE_EXPORT(__umodsi3); +DECLARE_EXPORT(__muldi3); diff --git a/arch/nios2/kernel/process.c b/arch/nios2/kernel/process.c new file mode 100644 index 000000000000..0e075b5ad2a5 --- /dev/null +++ b/arch/nios2/kernel/process.c @@ -0,0 +1,258 @@ +/* + * Architecture-dependent parts of process handling. + * + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/export.h> +#include <linux/sched.h> +#include <linux/tick.h> +#include <linux/uaccess.h> + +#include <asm/unistd.h> +#include <asm/traps.h> +#include <asm/cpuinfo.h> + +asmlinkage void ret_from_fork(void); +asmlinkage void ret_from_kernel_thread(void); + +void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); + +void arch_cpu_idle(void) +{ + local_irq_enable(); +} + +/* + * The development boards have no way to pull a board reset. Just jump to the + * cpu reset address and let the boot loader or the code in head.S take care of + * resetting peripherals. + */ +void machine_restart(char *__unused) +{ + pr_notice("Machine restart (%08x)...\n", cpuinfo.reset_addr); + local_irq_disable(); + __asm__ __volatile__ ( + "jmp %0\n\t" + : + : "r" (cpuinfo.reset_addr) + : "r4"); +} + +void machine_halt(void) +{ + pr_notice("Machine halt...\n"); + local_irq_disable(); + for (;;) + ; +} + +/* + * There is no way to power off the development boards. So just spin for now. If + * we ever have a way of resetting a board using a GPIO we should add that here. + */ +void machine_power_off(void) +{ + pr_notice("Machine power off...\n"); + local_irq_disable(); + for (;;) + ; +} + +void show_regs(struct pt_regs *regs) +{ + pr_notice("\n"); + show_regs_print_info(KERN_DEFAULT); + + pr_notice("r1: %08lx r2: %08lx r3: %08lx r4: %08lx\n", + regs->r1, regs->r2, regs->r3, regs->r4); + + pr_notice("r5: %08lx r6: %08lx r7: %08lx r8: %08lx\n", + regs->r5, regs->r6, regs->r7, regs->r8); + + pr_notice("r9: %08lx r10: %08lx r11: %08lx r12: %08lx\n", + regs->r9, regs->r10, regs->r11, regs->r12); + + pr_notice("r13: %08lx r14: %08lx r15: %08lx\n", + regs->r13, regs->r14, regs->r15); + + pr_notice("ra: %08lx fp: %08lx sp: %08lx gp: %08lx\n", + regs->ra, regs->fp, regs->sp, regs->gp); + + pr_notice("ea: %08lx estatus: %08lx\n", + regs->ea, regs->estatus); +} + +void flush_thread(void) +{ + set_fs(USER_DS); +} + +int copy_thread(unsigned long clone_flags, + unsigned long usp, unsigned long arg, struct task_struct *p) +{ + struct pt_regs *childregs = task_pt_regs(p); + struct pt_regs *regs; + struct switch_stack *stack; + struct switch_stack *childstack = + ((struct switch_stack *)childregs) - 1; + + if (unlikely(p->flags & PF_KTHREAD)) { + memset(childstack, 0, + sizeof(struct switch_stack) + sizeof(struct pt_regs)); + + childstack->r16 = usp; /* fn */ + childstack->r17 = arg; + childstack->ra = (unsigned long) ret_from_kernel_thread; + childregs->estatus = STATUS_PIE; + childregs->sp = (unsigned long) childstack; + + p->thread.ksp = (unsigned long) childstack; + p->thread.kregs = childregs; + return 0; + } + + regs = current_pt_regs(); + *childregs = *regs; + childregs->r2 = 0; /* Set the return value for the child. */ + childregs->r7 = 0; + + stack = ((struct switch_stack *) regs) - 1; + *childstack = *stack; + childstack->ra = (unsigned long)ret_from_fork; + p->thread.kregs = childregs; + p->thread.ksp = (unsigned long) childstack; + + if (usp) + childregs->sp = usp; + + /* Initialize tls register. */ + if (clone_flags & CLONE_SETTLS) + childstack->r23 = regs->r8; + + return 0; +} + +/* + * Generic dumping code. Used for panic and debug. + */ +void dump(struct pt_regs *fp) +{ + unsigned long *sp; + unsigned char *tp; + int i; + + pr_emerg("\nCURRENT PROCESS:\n\n"); + pr_emerg("COMM=%s PID=%d\n", current->comm, current->pid); + + if (current->mm) { + pr_emerg("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", + (int) current->mm->start_code, + (int) current->mm->end_code, + (int) current->mm->start_data, + (int) current->mm->end_data, + (int) current->mm->end_data, + (int) current->mm->brk); + pr_emerg("USER-STACK=%08x KERNEL-STACK=%08x\n\n", + (int) current->mm->start_stack, + (int)(((unsigned long) current) + THREAD_SIZE)); + } + + pr_emerg("PC: %08lx\n", fp->ea); + pr_emerg("SR: %08lx SP: %08lx\n", + (long) fp->estatus, (long) fp); + + pr_emerg("r1: %08lx r2: %08lx r3: %08lx\n", + fp->r1, fp->r2, fp->r3); + + pr_emerg("r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", + fp->r4, fp->r5, fp->r6, fp->r7); + pr_emerg("r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", + fp->r8, fp->r9, fp->r10, fp->r11); + pr_emerg("r12: %08lx r13: %08lx r14: %08lx r15: %08lx\n", + fp->r12, fp->r13, fp->r14, fp->r15); + pr_emerg("or2: %08lx ra: %08lx fp: %08lx sp: %08lx\n", + fp->orig_r2, fp->ra, fp->fp, fp->sp); + pr_emerg("\nUSP: %08x TRAPFRAME: %08x\n", + (unsigned int) fp->sp, (unsigned int) fp); + + pr_emerg("\nCODE:"); + tp = ((unsigned char *) fp->ea) - 0x20; + for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { + if ((i % 0x10) == 0) + pr_emerg("\n%08x: ", (int) (tp + i)); + pr_emerg("%08x ", (int) *sp++); + } + pr_emerg("\n"); + + pr_emerg("\nKERNEL STACK:"); + tp = ((unsigned char *) fp) - 0x40; + for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { + if ((i % 0x10) == 0) + pr_emerg("\n%08x: ", (int) (tp + i)); + pr_emerg("%08x ", (int) *sp++); + } + pr_emerg("\n"); + pr_emerg("\n"); + + pr_emerg("\nUSER STACK:"); + tp = (unsigned char *) (fp->sp - 0x10); + for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { + if ((i % 0x10) == 0) + pr_emerg("\n%08x: ", (int) (tp + i)); + pr_emerg("%08x ", (int) *sp++); + } + pr_emerg("\n\n"); +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)p; + fp = ((struct switch_stack *)p->thread.ksp)->fp; /* ;dgt2 */ + do { + if (fp < stack_page+sizeof(struct task_struct) || + fp >= 8184+stack_page) /* ;dgt2;tmp */ + return 0; + pc = ((unsigned long *)fp)[1]; + if (!in_sched_functions(pc)) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); /* ;dgt2;tmp */ + return 0; +} + +/* + * Do necessary setup to start up a newly executed thread. + * Will startup in user mode (status_extension = 0). + */ +void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) +{ + memset((void *) regs, 0, sizeof(struct pt_regs)); + regs->estatus = ESTATUS_EPIE | ESTATUS_EU; + regs->ea = pc; + regs->sp = sp; +} + +#include <linux/elfcore.h> + +/* Fill in the FPU structure for a core dump. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) +{ + return 0; /* Nios2 has no FPU and thus no FPU registers */ +} diff --git a/arch/nios2/kernel/prom.c b/arch/nios2/kernel/prom.c new file mode 100644 index 000000000000..0522d3378e3f --- /dev/null +++ b/arch/nios2/kernel/prom.c @@ -0,0 +1,65 @@ +/* + * Device tree support + * + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> + * + * Based on MIPS support for CONFIG_OF device tree support + * + * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/bootmem.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/io.h> + +#include <asm/sections.h> + +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ + u64 kernel_start = (u64)virt_to_phys(_text); + + if (!memory_size && + (kernel_start >= base) && (kernel_start < (base + size))) + memory_size = size; + +} + +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return alloc_bootmem_align(size, align); +} + +void __init early_init_devtree(void *params) +{ + __be32 *dtb = (u32 *)__dtb_start; +#if defined(CONFIG_NIOS2_DTB_AT_PHYS_ADDR) + if (be32_to_cpup((__be32 *)CONFIG_NIOS2_DTB_PHYS_ADDR) == + OF_DT_HEADER) { + params = (void *)CONFIG_NIOS2_DTB_PHYS_ADDR; + early_init_dt_scan(params); + return; + } +#endif + if (be32_to_cpu((__be32) *dtb) == OF_DT_HEADER) + params = (void *)__dtb_start; + + early_init_dt_scan(params); +} diff --git a/arch/nios2/kernel/ptrace.c b/arch/nios2/kernel/ptrace.c new file mode 100644 index 000000000000..681dda92eff1 --- /dev/null +++ b/arch/nios2/kernel/ptrace.c @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2014 Altera Corporation + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include <linux/elf.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/ptrace.h> +#include <linux/regset.h> +#include <linux/sched.h> +#include <linux/tracehook.h> +#include <linux/uaccess.h> +#include <linux/user.h> + +static int genregs_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const struct pt_regs *regs = task_pt_regs(target); + const struct switch_stack *sw = (struct switch_stack *)regs - 1; + int ret = 0; + +#define REG_O_ZERO_RANGE(START, END) \ + if (!ret) \ + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \ + START * 4, (END * 4) + 4); + +#define REG_O_ONE(PTR, LOC) \ + if (!ret) \ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ + LOC * 4, (LOC * 4) + 4); + +#define REG_O_RANGE(PTR, START, END) \ + if (!ret) \ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \ + START * 4, (END * 4) + 4); + + REG_O_ZERO_RANGE(PTR_R0, PTR_R0); + REG_O_RANGE(®s->r1, PTR_R1, PTR_R7); + REG_O_RANGE(®s->r8, PTR_R8, PTR_R15); + REG_O_RANGE(sw, PTR_R16, PTR_R23); + REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */ + REG_O_ONE(®s->gp, PTR_GP); + REG_O_ONE(®s->sp, PTR_SP); + REG_O_ONE(®s->fp, PTR_FP); + REG_O_ONE(®s->ea, PTR_EA); + REG_O_ZERO_RANGE(PTR_BA, PTR_BA); + REG_O_ONE(®s->ra, PTR_RA); + REG_O_ONE(®s->ea, PTR_PC); /* use ea for PC */ + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + PTR_STATUS * 4, -1); + + return ret; +} + +/* + * Set the thread state from a regset passed in via ptrace + */ +static int genregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + const struct switch_stack *sw = (struct switch_stack *)regs - 1; + int ret = 0; + +#define REG_IGNORE_RANGE(START, END) \ + if (!ret) \ + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \ + START * 4, (END * 4) + 4); + +#define REG_IN_ONE(PTR, LOC) \ + if (!ret) \ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \ + (void *)(PTR), LOC * 4, (LOC * 4) + 4); + +#define REG_IN_RANGE(PTR, START, END) \ + if (!ret) \ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \ + (void *)(PTR), START * 4, (END * 4) + 4); + + REG_IGNORE_RANGE(PTR_R0, PTR_R0); + REG_IN_RANGE(®s->r1, PTR_R1, PTR_R7); + REG_IN_RANGE(®s->r8, PTR_R8, PTR_R15); + REG_IN_RANGE(sw, PTR_R16, PTR_R23); + REG_IGNORE_RANGE(PTR_R24, PTR_R25); /* et and bt */ + REG_IN_ONE(®s->gp, PTR_GP); + REG_IN_ONE(®s->sp, PTR_SP); + REG_IN_ONE(®s->fp, PTR_FP); + REG_IN_ONE(®s->ea, PTR_EA); + REG_IGNORE_RANGE(PTR_BA, PTR_BA); + REG_IN_ONE(®s->ra, PTR_RA); + REG_IN_ONE(®s->ea, PTR_PC); /* use ea for PC */ + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + PTR_STATUS * 4, -1); + + return ret; +} + +/* + * Define the register sets available on Nios2 under Linux + */ +enum nios2_regset { + REGSET_GENERAL, +}; + +static const struct user_regset nios2_regsets[] = { + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = NUM_PTRACE_REG, + .size = sizeof(unsigned long), + .align = sizeof(unsigned long), + .get = genregs_get, + .set = genregs_set, + } +}; + +static const struct user_regset_view nios2_user_view = { + .name = "nios2", + .e_machine = ELF_ARCH, + .ei_osabi = ELF_OSABI, + .regsets = nios2_regsets, + .n = ARRAY_SIZE(nios2_regsets) +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &nios2_user_view; +} + +void ptrace_disable(struct task_struct *child) +{ + +} + +long arch_ptrace(struct task_struct *child, long request, unsigned long addr, + unsigned long data) +{ + return ptrace_request(child, request, addr, data); +} + +asmlinkage int do_syscall_trace_enter(void) +{ + int ret = 0; + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + ret = tracehook_report_syscall_entry(task_pt_regs(current)); + + return ret; +} + +asmlinkage void do_syscall_trace_exit(void) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(task_pt_regs(current), 0); +} diff --git a/arch/nios2/kernel/setup.c b/arch/nios2/kernel/setup.c new file mode 100644 index 000000000000..cb3121f975d4 --- /dev/null +++ b/arch/nios2/kernel/setup.c @@ -0,0 +1,218 @@ +/* + * Nios2-specific parts of system setup + * + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * Copyright (C) 2001 Vic Phillips <vic@microtronix.com> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/console.h> +#include <linux/bootmem.h> +#include <linux/initrd.h> +#include <linux/of_fdt.h> + +#include <asm/mmu_context.h> +#include <asm/sections.h> +#include <asm/setup.h> +#include <asm/cpuinfo.h> + +unsigned long memory_start; +EXPORT_SYMBOL(memory_start); + +unsigned long memory_end; +EXPORT_SYMBOL(memory_end); + +unsigned long memory_size; + +static struct pt_regs fake_regs = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0}; + +/* Copy a short hook instruction sequence to the exception address */ +static inline void copy_exception_handler(unsigned int addr) +{ + unsigned int start = (unsigned int) exception_handler_hook; + volatile unsigned int tmp = 0; + + if (start == addr) { + /* The CPU exception address already points to the handler. */ + return; + } + + __asm__ __volatile__ ( + "ldw %2,0(%0)\n" + "stw %2,0(%1)\n" + "ldw %2,4(%0)\n" + "stw %2,4(%1)\n" + "ldw %2,8(%0)\n" + "stw %2,8(%1)\n" + "flushd 0(%1)\n" + "flushd 4(%1)\n" + "flushd 8(%1)\n" + "flushi %1\n" + "addi %1,%1,4\n" + "flushi %1\n" + "addi %1,%1,4\n" + "flushi %1\n" + "flushp\n" + : /* no output registers */ + : "r" (start), "r" (addr), "r" (tmp) + : "memory" + ); +} + +/* Copy the fast TLB miss handler */ +static inline void copy_fast_tlb_miss_handler(unsigned int addr) +{ + unsigned int start = (unsigned int) fast_handler; + unsigned int end = (unsigned int) fast_handler_end; + volatile unsigned int tmp = 0; + + __asm__ __volatile__ ( + "1:\n" + " ldw %3,0(%0)\n" + " stw %3,0(%1)\n" + " flushd 0(%1)\n" + " flushi %1\n" + " flushp\n" + " addi %0,%0,4\n" + " addi %1,%1,4\n" + " bne %0,%2,1b\n" + : /* no output registers */ + : "r" (start), "r" (addr), "r" (end), "r" (tmp) + : "memory" + ); +} + +/* + * save args passed from u-boot, called from head.S + * + * @r4: NIOS magic + * @r5: initrd start + * @r6: initrd end or fdt + * @r7: kernel command line + */ +asmlinkage void __init nios2_boot_init(unsigned r4, unsigned r5, unsigned r6, + unsigned r7) +{ + unsigned dtb_passed = 0; + char cmdline_passed[COMMAND_LINE_SIZE] = { 0, }; + +#if defined(CONFIG_NIOS2_PASS_CMDLINE) + if (r4 == 0x534f494e) { /* r4 is magic NIOS */ +#if defined(CONFIG_BLK_DEV_INITRD) + if (r5) { /* initramfs */ + initrd_start = r5; + initrd_end = r6; + } +#endif /* CONFIG_BLK_DEV_INITRD */ + dtb_passed = r6; + + if (r7) + strncpy(cmdline_passed, (char *)r7, COMMAND_LINE_SIZE); + } +#endif + + early_init_devtree((void *)dtb_passed); + +#ifndef CONFIG_CMDLINE_FORCE + if (cmdline_passed[0]) + strncpy(boot_command_line, cmdline_passed, COMMAND_LINE_SIZE); +#ifdef CONFIG_NIOS2_CMDLINE_IGNORE_DTB + else + strncpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); +#endif +#endif +} + +void __init setup_arch(char **cmdline_p) +{ + int bootmap_size; + + console_verbose(); + + memory_start = PAGE_ALIGN((unsigned long)__pa(_end)); + memory_end = (unsigned long) CONFIG_NIOS2_MEM_BASE + memory_size; + + init_mm.start_code = (unsigned long) _stext; + init_mm.end_code = (unsigned long) _etext; + init_mm.end_data = (unsigned long) _edata; + init_mm.brk = (unsigned long) _end; + init_task.thread.kregs = &fake_regs; + + /* Keep a copy of command line */ + *cmdline_p = boot_command_line; + + min_low_pfn = PFN_UP(memory_start); + max_low_pfn = PFN_DOWN(memory_end); + max_mapnr = max_low_pfn; + + /* + * give all the memory to the bootmap allocator, tell it to put the + * boot mem_map at the start of memory + */ + pr_debug("init_bootmem_node(?,%#lx, %#x, %#lx)\n", + min_low_pfn, PFN_DOWN(PHYS_OFFSET), max_low_pfn); + bootmap_size = init_bootmem_node(NODE_DATA(0), + min_low_pfn, PFN_DOWN(PHYS_OFFSET), + max_low_pfn); + + /* + * free the usable memory, we have to make sure we do not free + * the bootmem bitmap so we then reserve it after freeing it :-) + */ + pr_debug("free_bootmem(%#lx, %#lx)\n", + memory_start, memory_end - memory_start); + free_bootmem(memory_start, memory_end - memory_start); + + /* + * Reserve the bootmem bitmap itself as well. We do this in two + * steps (first step was init_bootmem()) because this catches + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + * + * Arguments are start, size + */ + pr_debug("reserve_bootmem(%#lx, %#x)\n", memory_start, bootmap_size); + reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) { + reserve_bootmem(virt_to_phys((void *)initrd_start), + initrd_end - initrd_start, BOOTMEM_DEFAULT); + } +#endif /* CONFIG_BLK_DEV_INITRD */ + + unflatten_and_copy_device_tree(); + + setup_cpuinfo(); + + copy_exception_handler(cpuinfo.exception_addr); + + mmu_init(); + + copy_fast_tlb_miss_handler(cpuinfo.fast_tlb_miss_exc_addr); + + /* + * Initialize MMU context handling here because data from cpuinfo is + * needed for this. + */ + mmu_context_init(); + + /* + * get kmalloc into gear + */ + paging_init(); + +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +} diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c new file mode 100644 index 000000000000..f9d27883a714 --- /dev/null +++ b/arch/nios2/kernel/signal.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2013-2014 Altera Corporation + * Copyright (C) 2011-2012 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd + * Copyright (C) 1991, 1992 Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/signal.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/uaccess.h> +#include <linux/unistd.h> +#include <linux/personality.h> +#include <linux/tracehook.h> + +#include <asm/ucontext.h> +#include <asm/cacheflush.h> + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +/* + * Do a signal return; undo the signal stack. + * + * Keep the return code on the stack quadword aligned! + * That makes the cache flush below easier. + */ + +struct rt_sigframe { + struct siginfo info; + struct ucontext uc; +}; + +static inline int rt_restore_ucontext(struct pt_regs *regs, + struct switch_stack *sw, + struct ucontext *uc, int *pr2) +{ + int temp; + greg_t *gregs = uc->uc_mcontext.gregs; + int err; + + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + + err = __get_user(temp, &uc->uc_mcontext.version); + if (temp != MCONTEXT_VERSION) + goto badframe; + /* restore passed registers */ + err |= __get_user(regs->r1, &gregs[0]); + err |= __get_user(regs->r2, &gregs[1]); + err |= __get_user(regs->r3, &gregs[2]); + err |= __get_user(regs->r4, &gregs[3]); + err |= __get_user(regs->r5, &gregs[4]); + err |= __get_user(regs->r6, &gregs[5]); + err |= __get_user(regs->r7, &gregs[6]); + err |= __get_user(regs->r8, &gregs[7]); + err |= __get_user(regs->r9, &gregs[8]); + err |= __get_user(regs->r10, &gregs[9]); + err |= __get_user(regs->r11, &gregs[10]); + err |= __get_user(regs->r12, &gregs[11]); + err |= __get_user(regs->r13, &gregs[12]); + err |= __get_user(regs->r14, &gregs[13]); + err |= __get_user(regs->r15, &gregs[14]); + err |= __get_user(sw->r16, &gregs[15]); + err |= __get_user(sw->r17, &gregs[16]); + err |= __get_user(sw->r18, &gregs[17]); + err |= __get_user(sw->r19, &gregs[18]); + err |= __get_user(sw->r20, &gregs[19]); + err |= __get_user(sw->r21, &gregs[20]); + err |= __get_user(sw->r22, &gregs[21]); + err |= __get_user(sw->r23, &gregs[22]); + /* gregs[23] is handled below */ + err |= __get_user(sw->fp, &gregs[24]); /* Verify, should this be + settable */ + err |= __get_user(sw->gp, &gregs[25]); /* Verify, should this be + settable */ + + err |= __get_user(temp, &gregs[26]); /* Not really necessary no user + settable bits */ + err |= __get_user(regs->ea, &gregs[27]); + + err |= __get_user(regs->ra, &gregs[23]); + err |= __get_user(regs->sp, &gregs[28]); + + regs->orig_r2 = -1; /* disable syscall checks */ + + err |= restore_altstack(&uc->uc_stack); + if (err) + goto badframe; + + *pr2 = regs->r2; + return err; + +badframe: + return 1; +} + +asmlinkage int do_rt_sigreturn(struct switch_stack *sw) +{ + struct pt_regs *regs = (struct pt_regs *)(sw + 1); + /* Verify, can we follow the stack back */ + struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp; + sigset_t set; + int rval; + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + set_current_blocked(&set); + + if (rt_restore_ucontext(regs, sw, &frame->uc, &rval)) + goto badframe; + + return rval; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + greg_t *gregs = uc->uc_mcontext.gregs; + int err = 0; + + err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); + err |= __put_user(regs->r1, &gregs[0]); + err |= __put_user(regs->r2, &gregs[1]); + err |= __put_user(regs->r3, &gregs[2]); + err |= __put_user(regs->r4, &gregs[3]); + err |= __put_user(regs->r5, &gregs[4]); + err |= __put_user(regs->r6, &gregs[5]); + err |= __put_user(regs->r7, &gregs[6]); + err |= __put_user(regs->r8, &gregs[7]); + err |= __put_user(regs->r9, &gregs[8]); + err |= __put_user(regs->r10, &gregs[9]); + err |= __put_user(regs->r11, &gregs[10]); + err |= __put_user(regs->r12, &gregs[11]); + err |= __put_user(regs->r13, &gregs[12]); + err |= __put_user(regs->r14, &gregs[13]); + err |= __put_user(regs->r15, &gregs[14]); + err |= __put_user(sw->r16, &gregs[15]); + err |= __put_user(sw->r17, &gregs[16]); + err |= __put_user(sw->r18, &gregs[17]); + err |= __put_user(sw->r19, &gregs[18]); + err |= __put_user(sw->r20, &gregs[19]); + err |= __put_user(sw->r21, &gregs[20]); + err |= __put_user(sw->r22, &gregs[21]); + err |= __put_user(sw->r23, &gregs[22]); + err |= __put_user(regs->ra, &gregs[23]); + err |= __put_user(sw->fp, &gregs[24]); + err |= __put_user(sw->gp, &gregs[25]); + err |= __put_user(regs->ea, &gregs[27]); + err |= __put_user(regs->sp, &gregs[28]); + return err; +} + +static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, + size_t frame_size) +{ + unsigned long usp; + + /* Default to using normal stack. */ + usp = regs->sp; + + /* This is the X/Open sanctioned signal stack switching. */ + usp = sigsp(usp, ksig); + + /* Verify, is it 32 or 64 bit aligned */ + return (void *)((usp - frame_size) & -8UL); +} + +static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, + struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ksig, regs, sizeof(*frame)); + + if (ksig->ka.sa.sa_flags & SA_SIGINFO) + err |= copy_siginfo_to_user(&frame->info, &ksig->info); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __save_altstack(&frame->uc.uc_stack, regs->sp); + err |= rt_setup_ucontext(&frame->uc, regs); + err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (err) + goto give_sigsegv; + + /* Set up to return from userspace; jump to fixed address sigreturn + trampoline on kuser page. */ + regs->ra = (unsigned long) (0x1040); + + /* Set up registers for signal handler */ + regs->sp = (unsigned long) frame; + regs->r4 = (unsigned long) ksig->sig; + regs->r5 = (unsigned long) &frame->info; + regs->r6 = (unsigned long) &frame->uc; + regs->ea = (unsigned long) ksig->ka.sa.sa_handler; + return 0; + +give_sigsegv: + force_sigsegv(ksig->sig, current); + return -EFAULT; +} + +/* + * OK, we're invoking a handler + */ +static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) +{ + int ret; + sigset_t *oldset = sigmask_to_save(); + + /* set up the stack frame */ + ret = setup_rt_frame(ksig, oldset, regs); + + signal_setup_done(ret, ksig, 0); +} + +static int do_signal(struct pt_regs *regs) +{ + unsigned int retval = 0, continue_addr = 0, restart_addr = 0; + int restart = 0; + struct ksignal ksig; + + current->thread.kregs = regs; + + /* + * If we were from a system call, check for system call restarting... + */ + if (regs->orig_r2 >= 0) { + continue_addr = regs->ea; + restart_addr = continue_addr - 4; + retval = regs->r2; + + /* + * Prepare for system call restart. We do this here so that a + * debugger will see the already changed PC. + */ + switch (retval) { + case ERESTART_RESTARTBLOCK: + restart = -2; + case ERESTARTNOHAND: + case ERESTARTSYS: + case ERESTARTNOINTR: + restart++; + regs->r2 = regs->orig_r2; + regs->r7 = regs->orig_r7; + regs->ea = restart_addr; + break; + } + } + + if (get_signal(&ksig)) { + /* handler */ + if (unlikely(restart && regs->ea == restart_addr)) { + if (retval == ERESTARTNOHAND || + retval == ERESTART_RESTARTBLOCK || + (retval == ERESTARTSYS + && !(ksig.ka.sa.sa_flags & SA_RESTART))) { + regs->r2 = EINTR; + regs->r7 = 1; + regs->ea = continue_addr; + } + } + handle_signal(&ksig, regs); + return 0; + } + + /* + * No handler present + */ + if (unlikely(restart) && regs->ea == restart_addr) { + regs->ea = continue_addr; + regs->r2 = __NR_restart_syscall; + } + + /* + * If there's no signal to deliver, we just put the saved sigmask back. + */ + restore_saved_sigmask(); + + return restart; +} + +asmlinkage int do_notify_resume(struct pt_regs *regs) +{ + /* + * We want the common case to go fast, which is why we may in certain + * cases get here from kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 0; + + if (test_thread_flag(TIF_SIGPENDING)) { + int restart = do_signal(regs); + + if (unlikely(restart)) { + /* + * Restart without handlers. + * Deal with it without leaving + * the kernel space. + */ + return restart; + } + } else if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + tracehook_notify_resume(regs); + + return 0; +} diff --git a/arch/nios2/kernel/sys_nios2.c b/arch/nios2/kernel/sys_nios2.c new file mode 100644 index 000000000000..cd390ec4f88b --- /dev/null +++ b/arch/nios2/kernel/sys_nios2.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2011-2012 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/export.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/syscalls.h> + +#include <asm/cacheflush.h> +#include <asm/traps.h> + +/* sys_cacheflush -- flush the processor cache. */ +asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, + unsigned int op) +{ + struct vm_area_struct *vma; + + if (len == 0) + return 0; + + /* We only support op 0 now, return error if op is non-zero.*/ + if (op) + return -EINVAL; + + /* Check for overflow */ + if (addr + len < addr) + return -EFAULT; + + /* + * Verify that the specified address region actually belongs + * to this process. + */ + vma = find_vma(current->mm, addr); + if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) + return -EFAULT; + + flush_cache_range(vma, addr, addr + len); + + return 0; +} + +asmlinkage int sys_getpagesize(void) +{ + return PAGE_SIZE; +} diff --git a/arch/nios2/kernel/syscall_table.c b/arch/nios2/kernel/syscall_table.c new file mode 100644 index 000000000000..06e6ac1835b2 --- /dev/null +++ b/arch/nios2/kernel/syscall_table.c @@ -0,0 +1,29 @@ +/* + * Copyright Altera Corporation (C) 2013. All rights reserved + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/syscalls.h> +#include <linux/signal.h> +#include <linux/unistd.h> + +#include <asm/syscalls.h> + +#undef __SYSCALL +#define __SYSCALL(nr, call) [nr] = (call), + +void *sys_call_table[__NR_syscalls] = { +#include <asm/unistd.h> +}; diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c new file mode 100644 index 000000000000..7f4547418ee1 --- /dev/null +++ b/arch/nios2/kernel/time.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2013-2014 Altera Corporation + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/interrupt.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/io.h> +#include <linux/slab.h> + +#define ALTERA_TIMER_STATUS_REG 0 +#define ALTERA_TIMER_CONTROL_REG 4 +#define ALTERA_TIMER_PERIODL_REG 8 +#define ALTERA_TIMER_PERIODH_REG 12 +#define ALTERA_TIMER_SNAPL_REG 16 +#define ALTERA_TIMER_SNAPH_REG 20 + +#define ALTERA_TIMER_CONTROL_ITO_MSK (0x1) +#define ALTERA_TIMER_CONTROL_CONT_MSK (0x2) +#define ALTERA_TIMER_CONTROL_START_MSK (0x4) +#define ALTERA_TIMER_CONTROL_STOP_MSK (0x8) + +struct nios2_timer { + void __iomem *base; + unsigned long freq; +}; + +struct nios2_clockevent_dev { + struct nios2_timer timer; + struct clock_event_device ced; +}; + +struct nios2_clocksource { + struct nios2_timer timer; + struct clocksource cs; +}; + +static inline struct nios2_clockevent_dev * + to_nios2_clkevent(struct clock_event_device *evt) +{ + return container_of(evt, struct nios2_clockevent_dev, ced); +} + +static inline struct nios2_clocksource * + to_nios2_clksource(struct clocksource *cs) +{ + return container_of(cs, struct nios2_clocksource, cs); +} + +static u16 timer_readw(struct nios2_timer *timer, u32 offs) +{ + return readw(timer->base + offs); +} + +static void timer_writew(struct nios2_timer *timer, u16 val, u32 offs) +{ + writew(val, timer->base + offs); +} + +static inline unsigned long read_timersnapshot(struct nios2_timer *timer) +{ + unsigned long count; + + timer_writew(timer, 0, ALTERA_TIMER_SNAPL_REG); + count = timer_readw(timer, ALTERA_TIMER_SNAPH_REG) << 16 | + timer_readw(timer, ALTERA_TIMER_SNAPL_REG); + + return count; +} + +static cycle_t nios2_timer_read(struct clocksource *cs) +{ + struct nios2_clocksource *nios2_cs = to_nios2_clksource(cs); + unsigned long flags; + u32 count; + + local_irq_save(flags); + count = read_timersnapshot(&nios2_cs->timer); + local_irq_restore(flags); + + /* Counter is counting down */ + return ~count; +} + +static struct nios2_clocksource nios2_cs = { + .cs = { + .name = "nios2-clksrc", + .rating = 250, + .read = nios2_timer_read, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }, +}; + +cycles_t get_cycles(void) +{ + return nios2_timer_read(&nios2_cs.cs); +} + +static void nios2_timer_start(struct nios2_timer *timer) +{ + u16 ctrl; + + ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG); + ctrl |= ALTERA_TIMER_CONTROL_START_MSK; + timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG); +} + +static void nios2_timer_stop(struct nios2_timer *timer) +{ + u16 ctrl; + + ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG); + ctrl |= ALTERA_TIMER_CONTROL_STOP_MSK; + timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG); +} + +static void nios2_timer_config(struct nios2_timer *timer, unsigned long period, + enum clock_event_mode mode) +{ + u16 ctrl; + + /* The timer's actual period is one cycle greater than the value + * stored in the period register. */ + period--; + + ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG); + /* stop counter */ + timer_writew(timer, ctrl | ALTERA_TIMER_CONTROL_STOP_MSK, + ALTERA_TIMER_CONTROL_REG); + + /* write new count */ + timer_writew(timer, period, ALTERA_TIMER_PERIODL_REG); + timer_writew(timer, period >> 16, ALTERA_TIMER_PERIODH_REG); + + ctrl |= ALTERA_TIMER_CONTROL_START_MSK | ALTERA_TIMER_CONTROL_ITO_MSK; + if (mode == CLOCK_EVT_MODE_PERIODIC) + ctrl |= ALTERA_TIMER_CONTROL_CONT_MSK; + else + ctrl &= ~ALTERA_TIMER_CONTROL_CONT_MSK; + timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG); +} + +static int nios2_timer_set_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); + + nios2_timer_config(&nios2_ced->timer, delta, evt->mode); + + return 0; +} + +static void nios2_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned long period; + struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); + struct nios2_timer *timer = &nios2_ced->timer; + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + period = DIV_ROUND_UP(timer->freq, HZ); + nios2_timer_config(timer, period, CLOCK_EVT_MODE_PERIODIC); + break; + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + nios2_timer_stop(timer); + break; + case CLOCK_EVT_MODE_RESUME: + nios2_timer_start(timer); + break; + } +} + +irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = (struct clock_event_device *) dev_id; + struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); + + /* Clear the interrupt condition */ + timer_writew(&nios2_ced->timer, 0, ALTERA_TIMER_STATUS_REG); + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static void __init nios2_timer_get_base_and_freq(struct device_node *np, + void __iomem **base, u32 *freq) +{ + *base = of_iomap(np, 0); + if (!*base) + panic("Unable to map reg for %s\n", np->name); + + if (of_property_read_u32(np, "clock-frequency", freq)) + panic("Unable to get %s clock frequency\n", np->name); +} + +static struct nios2_clockevent_dev nios2_ce = { + .ced = { + .name = "nios2-clkevent", + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .rating = 250, + .shift = 32, + .set_next_event = nios2_timer_set_next_event, + .set_mode = nios2_timer_set_mode, + }, +}; + +static __init void nios2_clockevent_init(struct device_node *timer) +{ + void __iomem *iobase; + u32 freq; + int irq; + + nios2_timer_get_base_and_freq(timer, &iobase, &freq); + + irq = irq_of_parse_and_map(timer, 0); + if (!irq) + panic("Unable to parse timer irq\n"); + + nios2_ce.timer.base = iobase; + nios2_ce.timer.freq = freq; + + nios2_ce.ced.cpumask = cpumask_of(0); + nios2_ce.ced.irq = irq; + + nios2_timer_stop(&nios2_ce.timer); + /* clear pending interrupt */ + timer_writew(&nios2_ce.timer, 0, ALTERA_TIMER_STATUS_REG); + + if (request_irq(irq, timer_interrupt, IRQF_TIMER, timer->name, + &nios2_ce.ced)) + panic("Unable to setup timer irq\n"); + + clockevents_config_and_register(&nios2_ce.ced, freq, 1, ULONG_MAX); +} + +static __init void nios2_clocksource_init(struct device_node *timer) +{ + unsigned int ctrl; + void __iomem *iobase; + u32 freq; + + nios2_timer_get_base_and_freq(timer, &iobase, &freq); + + nios2_cs.timer.base = iobase; + nios2_cs.timer.freq = freq; + + clocksource_register_hz(&nios2_cs.cs, freq); + + timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODL_REG); + timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODH_REG); + + /* interrupt disable + continuous + start */ + ctrl = ALTERA_TIMER_CONTROL_CONT_MSK | ALTERA_TIMER_CONTROL_START_MSK; + timer_writew(&nios2_cs.timer, ctrl, ALTERA_TIMER_CONTROL_REG); + + /* Calibrate the delay loop directly */ + lpj_fine = freq / HZ; +} + +/* + * The first timer instance will use as a clockevent. If there are two or + * more instances, the second one gets used as clocksource and all + * others are unused. +*/ +static void __init nios2_time_init(struct device_node *timer) +{ + static int num_called; + + switch (num_called) { + case 0: + nios2_clockevent_init(timer); + break; + case 1: + nios2_clocksource_init(timer); + break; + default: + break; + } + + num_called++; +} + +void read_persistent_clock(struct timespec *ts) +{ + ts->tv_sec = mktime(2007, 1, 1, 0, 0, 0); + ts->tv_nsec = 0; +} + +void __init time_init(void) +{ + clocksource_of_init(); +} + +CLOCKSOURCE_OF_DECLARE(nios2_timer, "altr,timer-1.0", nios2_time_init); diff --git a/arch/nios2/kernel/traps.c b/arch/nios2/kernel/traps.c new file mode 100644 index 000000000000..b7b97641a9a6 --- /dev/null +++ b/arch/nios2/kernel/traps.c @@ -0,0 +1,185 @@ +/* + * Hardware exception handling + * + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd. + * Copyright (C) 2001 Vic Phillips + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/export.h> +#include <linux/mm.h> +#include <linux/ptrace.h> + +#include <asm/traps.h> +#include <asm/sections.h> +#include <asm/uaccess.h> + +static DEFINE_SPINLOCK(die_lock); + +void die(const char *str, struct pt_regs *regs, long err) +{ + console_verbose(); + spin_lock_irq(&die_lock); + pr_warn("Oops: %s, sig: %ld\n", str, err); + show_regs(regs); + spin_unlock_irq(&die_lock); + /* + * do_exit() should take care of panic'ing from an interrupt + * context so we don't handle it here + */ + do_exit(err); +} + +void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr) +{ + siginfo_t info; + + if (!user_mode(regs)) + die("Exception in kernel mode", regs, signo); + + info.si_signo = signo; + info.si_errno = 0; + info.si_code = code; + info.si_addr = (void __user *) addr; + force_sig_info(signo, &info, current); +} + +/* + * The show_stack is an external API which we do not use ourselves. + */ + +int kstack_depth_to_print = 48; + +void show_stack(struct task_struct *task, unsigned long *stack) +{ + unsigned long *endstack, addr; + int i; + + if (!stack) { + if (task) + stack = (unsigned long *)task->thread.ksp; + else + stack = (unsigned long *)&stack; + } + + addr = (unsigned long) stack; + endstack = (unsigned long *) PAGE_ALIGN(addr); + + pr_emerg("Stack from %08lx:", (unsigned long)stack); + for (i = 0; i < kstack_depth_to_print; i++) { + if (stack + 1 > endstack) + break; + if (i % 8 == 0) + pr_emerg("\n "); + pr_emerg(" %08lx", *stack++); + } + + pr_emerg("\nCall Trace:"); + i = 0; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) _stext) && + (addr <= (unsigned long) _etext))) { + if (i % 4 == 0) + pr_emerg("\n "); + pr_emerg(" [<%08lx>]", addr); + i++; + } + } + pr_emerg("\n"); +} + +void __init trap_init(void) +{ + /* Nothing to do here */ +} + +/* Breakpoint handler */ +asmlinkage void breakpoint_c(struct pt_regs *fp) +{ + /* + * The breakpoint entry code has moved the PC on by 4 bytes, so we must + * move it back. This could be done on the host but we do it here + * because monitor.S of JTAG gdbserver does it too. + */ + fp->ea -= 4; + _exception(SIGTRAP, fp, TRAP_BRKPT, fp->ea); +} + +#ifndef CONFIG_NIOS2_ALIGNMENT_TRAP +/* Alignment exception handler */ +asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) +{ + unsigned long addr = RDCTL(CTL_BADADDR); + + cause >>= 2; + fp->ea -= 4; + + if (fixup_exception(fp)) + return; + + if (!user_mode(fp)) { + pr_alert("Unaligned access from kernel mode, this might be a hardware\n"); + pr_alert("problem, dump registers and restart the instruction\n"); + pr_alert(" BADADDR 0x%08lx\n", addr); + pr_alert(" cause %d\n", cause); + pr_alert(" op-code 0x%08lx\n", *(unsigned long *)(fp->ea)); + show_regs(fp); + return; + } + + _exception(SIGBUS, fp, BUS_ADRALN, addr); +} +#endif /* CONFIG_NIOS2_ALIGNMENT_TRAP */ + +/* Illegal instruction handler */ +asmlinkage void handle_illegal_c(struct pt_regs *fp) +{ + fp->ea -= 4; + _exception(SIGILL, fp, ILL_ILLOPC, fp->ea); +} + +/* Supervisor instruction handler */ +asmlinkage void handle_supervisor_instr(struct pt_regs *fp) +{ + fp->ea -= 4; + _exception(SIGILL, fp, ILL_PRVOPC, fp->ea); +} + +/* Division error handler */ +asmlinkage void handle_diverror_c(struct pt_regs *fp) +{ + fp->ea -= 4; + _exception(SIGFPE, fp, FPE_INTDIV, fp->ea); +} + +/* Unhandled exception handler */ +asmlinkage void unhandled_exception(struct pt_regs *regs, int cause) +{ + unsigned long addr = RDCTL(CTL_BADADDR); + + cause /= 4; + + pr_emerg("Unhandled exception #%d in %s mode (badaddr=0x%08lx)\n", + cause, user_mode(regs) ? "user" : "kernel", addr); + + regs->ea -= 4; + show_regs(regs); + + pr_emerg("opcode: 0x%08lx\n", *(unsigned long *)(regs->ea)); +} diff --git a/arch/nios2/kernel/vmlinux.lds.S b/arch/nios2/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..326fab40a9de --- /dev/null +++ b/arch/nios2/kernel/vmlinux.lds.S @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#include <asm/page.h> +#include <asm-generic/vmlinux.lds.h> +#include <asm/cache.h> +#include <asm/thread_info.h> + +OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2") + +OUTPUT_ARCH(nios) +ENTRY(_start) /* Defined in head.S */ + +jiffies = jiffies_64; + +SECTIONS +{ + . = CONFIG_NIOS2_MEM_BASE | CONFIG_NIOS2_KERNEL_REGION_BASE; + + _text = .; + _stext = .; + HEAD_TEXT_SECTION + .text : { + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + IRQENTRY_TEXT + KPROBES_TEXT + } =0 + _etext = .; + + .got : { + *(.got.plt) + *(.igot.plt) + *(.got) + *(.igot) + } + + EXCEPTION_TABLE(L1_CACHE_BYTES) + + . = ALIGN(PAGE_SIZE); + __init_begin = .; + INIT_TEXT_SECTION(PAGE_SIZE) + INIT_DATA_SECTION(PAGE_SIZE) + PERCPU_SECTION(L1_CACHE_BYTES) + __init_end = .; + + _sdata = .; + RO_DATA_SECTION(PAGE_SIZE) + RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) + _edata = .; + + BSS_SECTION(0, 0, 0) + _end = .; + + STABS_DEBUG + DWARF_DEBUG + NOTES + + DISCARDS +} diff --git a/arch/nios2/lib/Makefile b/arch/nios2/lib/Makefile new file mode 100644 index 000000000000..557256628ecd --- /dev/null +++ b/arch/nios2/lib/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Nios2-specific library files. +# + +lib-y += delay.o +lib-y += memcpy.o +lib-y += memmove.o +lib-y += memset.o diff --git a/arch/nios2/lib/delay.c b/arch/nios2/lib/delay.c new file mode 100644 index 000000000000..088119cd0cc5 --- /dev/null +++ b/arch/nios2/lib/delay.c @@ -0,0 +1,52 @@ +/* Copyright Altera Corporation (C) 2014. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/module.h> +#include <asm/delay.h> +#include <asm/param.h> +#include <asm/processor.h> +#include <asm/timex.h> + +void __delay(unsigned long cycles) +{ + cycles_t start = get_cycles(); + + while ((get_cycles() - start) < cycles) + cpu_relax(); +} +EXPORT_SYMBOL(__delay); + +void __const_udelay(unsigned long xloops) +{ + u64 loops; + + loops = (u64)xloops * loops_per_jiffy * HZ; + + __delay(loops >> 32); +} +EXPORT_SYMBOL(__const_udelay); + +void __udelay(unsigned long usecs) +{ + __const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */ +} +EXPORT_SYMBOL(__udelay); + +void __ndelay(unsigned long nsecs) +{ + __const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */ +} +EXPORT_SYMBOL(__ndelay); diff --git a/arch/nios2/lib/memcpy.c b/arch/nios2/lib/memcpy.c new file mode 100644 index 000000000000..1715f5d28b11 --- /dev/null +++ b/arch/nios2/lib/memcpy.c @@ -0,0 +1,202 @@ +/* Extracted from GLIBC memcpy.c and memcopy.h, which is: + Copyright (C) 1991, 1992, 1993, 1997, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Torbjorn Granlund (tege@sics.se). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <linux/types.h> + +/* Type to use for aligned memory operations. + This should normally be the biggest type supported by a single load + and store. */ +#define op_t unsigned long int +#define OPSIZ (sizeof(op_t)) + +/* Optimal type for storing bytes in registers. */ +#define reg_char char + +#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2))) + +/* Copy exactly NBYTES bytes from SRC_BP to DST_BP, + without any assumptions about alignment of the pointers. */ +#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \ +do { \ + size_t __nbytes = (nbytes); \ + while (__nbytes > 0) { \ + unsigned char __x = ((unsigned char *) src_bp)[0]; \ + src_bp += 1; \ + __nbytes -= 1; \ + ((unsigned char *) dst_bp)[0] = __x; \ + dst_bp += 1; \ + } \ +} while (0) + +/* Copy *up to* NBYTES bytes from SRC_BP to DST_BP, with + the assumption that DST_BP is aligned on an OPSIZ multiple. If + not all bytes could be easily copied, store remaining number of bytes + in NBYTES_LEFT, otherwise store 0. */ +/* extern void _wordcopy_fwd_aligned __P ((long int, long int, size_t)); */ +/* extern void _wordcopy_fwd_dest_aligned __P ((long int, long int, size_t)); */ +#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \ +do { \ + if (src_bp % OPSIZ == 0) \ + _wordcopy_fwd_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);\ + else \ + _wordcopy_fwd_dest_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);\ + src_bp += (nbytes) & -OPSIZ; \ + dst_bp += (nbytes) & -OPSIZ; \ + (nbytes_left) = (nbytes) % OPSIZ; \ +} while (0) + + +/* Threshold value for when to enter the unrolled loops. */ +#define OP_T_THRES 16 + +/* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to + block beginning at DSTP with LEN `op_t' words (not LEN bytes!). + Both SRCP and DSTP should be aligned for memory operations on `op_t's. */ +/* stream-lined (read x8 + write x8) */ +static void _wordcopy_fwd_aligned(long int dstp, long int srcp, size_t len) +{ + while (len > 7) { + register op_t a0, a1, a2, a3, a4, a5, a6, a7; + + a0 = ((op_t *) srcp)[0]; + a1 = ((op_t *) srcp)[1]; + a2 = ((op_t *) srcp)[2]; + a3 = ((op_t *) srcp)[3]; + a4 = ((op_t *) srcp)[4]; + a5 = ((op_t *) srcp)[5]; + a6 = ((op_t *) srcp)[6]; + a7 = ((op_t *) srcp)[7]; + ((op_t *) dstp)[0] = a0; + ((op_t *) dstp)[1] = a1; + ((op_t *) dstp)[2] = a2; + ((op_t *) dstp)[3] = a3; + ((op_t *) dstp)[4] = a4; + ((op_t *) dstp)[5] = a5; + ((op_t *) dstp)[6] = a6; + ((op_t *) dstp)[7] = a7; + + srcp += 8 * OPSIZ; + dstp += 8 * OPSIZ; + len -= 8; + } + while (len > 0) { + *(op_t *)dstp = *(op_t *)srcp; + + srcp += OPSIZ; + dstp += OPSIZ; + len -= 1; + } +} + +/* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to + block beginning at DSTP with LEN `op_t' words (not LEN bytes!). + DSTP should be aligned for memory operations on `op_t's, but SRCP must + *not* be aligned. */ +/* stream-lined (read x4 + write x4) */ +static void _wordcopy_fwd_dest_aligned(long int dstp, long int srcp, + size_t len) +{ + op_t ap; + int sh_1, sh_2; + + /* Calculate how to shift a word read at the memory operation + aligned srcp to make it aligned for copy. */ + + sh_1 = 8 * (srcp % OPSIZ); + sh_2 = 8 * OPSIZ - sh_1; + + /* Make SRCP aligned by rounding it down to the beginning of the `op_t' + it points in the middle of. */ + srcp &= -OPSIZ; + ap = ((op_t *) srcp)[0]; + srcp += OPSIZ; + + while (len > 3) { + op_t a0, a1, a2, a3; + + a0 = ((op_t *) srcp)[0]; + a1 = ((op_t *) srcp)[1]; + a2 = ((op_t *) srcp)[2]; + a3 = ((op_t *) srcp)[3]; + ((op_t *) dstp)[0] = MERGE(ap, sh_1, a0, sh_2); + ((op_t *) dstp)[1] = MERGE(a0, sh_1, a1, sh_2); + ((op_t *) dstp)[2] = MERGE(a1, sh_1, a2, sh_2); + ((op_t *) dstp)[3] = MERGE(a2, sh_1, a3, sh_2); + + ap = a3; + srcp += 4 * OPSIZ; + dstp += 4 * OPSIZ; + len -= 4; + } + while (len > 0) { + register op_t a0; + + a0 = ((op_t *) srcp)[0]; + ((op_t *) dstp)[0] = MERGE(ap, sh_1, a0, sh_2); + + ap = a0; + srcp += OPSIZ; + dstp += OPSIZ; + len -= 1; + } +} + +void *memcpy(void *dstpp, const void *srcpp, size_t len) +{ + unsigned long int dstp = (long int) dstpp; + unsigned long int srcp = (long int) srcpp; + + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ); + + /* Copy whole pages from SRCP to DSTP by virtual address + manipulation, as much as possible. */ + + /* PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); */ + + /* Copy from SRCP to DSTP taking advantage of the known + alignment of DSTP. Number of bytes remaining is put in the + third argument, i.e. in LEN. This number may vary from + machine to machine. */ + + WORD_COPY_FWD(dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD(dstp, srcp, len); + + return dstpp; +} + +void *memcpyb(void *dstpp, const void *srcpp, unsigned len) +{ + unsigned long int dstp = (long int) dstpp; + unsigned long int srcp = (long int) srcpp; + + BYTE_COPY_FWD(dstp, srcp, len); + + return dstpp; +} diff --git a/arch/nios2/lib/memmove.c b/arch/nios2/lib/memmove.c new file mode 100644 index 000000000000..c65ef517eb80 --- /dev/null +++ b/arch/nios2/lib/memmove.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/types.h> +#include <linux/string.h> + +#ifdef __HAVE_ARCH_MEMMOVE +void *memmove(void *d, const void *s, size_t count) +{ + unsigned long dst, src; + + if (!count) + return d; + + if (d < s) { + dst = (unsigned long) d; + src = (unsigned long) s; + + if ((count < 8) || ((dst ^ src) & 3)) + goto restup; + + if (dst & 1) { + *(char *)dst++ = *(char *)src++; + count--; + } + if (dst & 2) { + *(short *)dst = *(short *)src; + src += 2; + dst += 2; + count -= 2; + } + while (count > 3) { + *(long *)dst = *(long *)src; + src += 4; + dst += 4; + count -= 4; + } +restup: + while (count--) + *(char *)dst++ = *(char *)src++; + } else { + dst = (unsigned long) d + count; + src = (unsigned long) s + count; + + if ((count < 8) || ((dst ^ src) & 3)) + goto restdown; + + if (dst & 1) { + src--; + dst--; + count--; + *(char *)dst = *(char *)src; + } + if (dst & 2) { + src -= 2; + dst -= 2; + count -= 2; + *(short *)dst = *(short *)src; + } + while (count > 3) { + src -= 4; + dst -= 4; + count -= 4; + *(long *)dst = *(long *)src; + } +restdown: + while (count--) { + src--; + dst--; + *(char *)dst = *(char *)src; + } + } + + return d; +} +#endif /* __HAVE_ARCH_MEMMOVE */ diff --git a/arch/nios2/lib/memset.c b/arch/nios2/lib/memset.c new file mode 100644 index 000000000000..65e97802f5cc --- /dev/null +++ b/arch/nios2/lib/memset.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/types.h> +#include <linux/string.h> + +#ifdef __HAVE_ARCH_MEMSET +void *memset(void *s, int c, size_t count) +{ + int destptr, charcnt, dwordcnt, fill8reg, wrkrega; + + if (!count) + return s; + + c &= 0xFF; + + if (count <= 8) { + char *xs = (char *) s; + + while (count--) + *xs++ = c; + return s; + } + + __asm__ __volatile__ ( + /* fill8 %3, %5 (c & 0xff) */ + " slli %4, %5, 8\n" + " or %4, %4, %5\n" + " slli %3, %4, 16\n" + " or %3, %3, %4\n" + /* Word-align %0 (s) if necessary */ + " andi %4, %0, 0x01\n" + " beq %4, zero, 1f\n" + " addi %1, %1, -1\n" + " stb %3, 0(%0)\n" + " addi %0, %0, 1\n" + "1: mov %2, %1\n" + /* Dword-align %0 (s) if necessary */ + " andi %4, %0, 0x02\n" + " beq %4, zero, 2f\n" + " addi %1, %1, -2\n" + " sth %3, 0(%0)\n" + " addi %0, %0, 2\n" + " mov %2, %1\n" + /* %1 and %2 are how many more bytes to set */ + "2: srli %2, %2, 2\n" + /* %2 is how many dwords to set */ + "3: stw %3, 0(%0)\n" + " addi %0, %0, 4\n" + " addi %2, %2, -1\n" + " bne %2, zero, 3b\n" + /* store residual word and/or byte if necessary */ + " andi %4, %1, 0x02\n" + " beq %4, zero, 4f\n" + " sth %3, 0(%0)\n" + " addi %0, %0, 2\n" + /* store residual byte if necessary */ + "4: andi %4, %1, 0x01\n" + " beq %4, zero, 5f\n" + " stb %3, 0(%0)\n" + "5:\n" + : "=r" (destptr), /* %0 Output */ + "=r" (charcnt), /* %1 Output */ + "=r" (dwordcnt), /* %2 Output */ + "=r" (fill8reg), /* %3 Output */ + "=r" (wrkrega) /* %4 Output */ + : "r" (c), /* %5 Input */ + "0" (s), /* %0 Input/Output */ + "1" (count) /* %1 Input/Output */ + : "memory" /* clobbered */ + ); + + return s; +} +#endif /* __HAVE_ARCH_MEMSET */ diff --git a/arch/nios2/mm/Makefile b/arch/nios2/mm/Makefile new file mode 100644 index 000000000000..3cbd0840873c --- /dev/null +++ b/arch/nios2/mm/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Nios2-specific parts of the memory manager. +# + +obj-y += cacheflush.o +obj-y += dma-mapping.o +obj-y += extable.o +obj-y += fault.o +obj-y += init.o +obj-y += ioremap.o +obj-y += mmu_context.o +obj-y += pgtable.o +obj-y += tlb.o +obj-y += uaccess.o diff --git a/arch/nios2/mm/cacheflush.c b/arch/nios2/mm/cacheflush.c new file mode 100644 index 000000000000..2ae482b42669 --- /dev/null +++ b/arch/nios2/mm/cacheflush.c @@ -0,0 +1,271 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2009, Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + */ + +#include <linux/export.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/fs.h> + +#include <asm/cacheflush.h> +#include <asm/cpuinfo.h> + +static void __flush_dcache(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(cpuinfo.dcache_line_size - 1); + end += (cpuinfo.dcache_line_size - 1); + end &= ~(cpuinfo.dcache_line_size - 1); + + if (end > start + cpuinfo.dcache_size) + end = start + cpuinfo.dcache_size; + + for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) { + __asm__ __volatile__ (" flushda 0(%0)\n" + : /* Outputs */ + : /* Inputs */ "r"(addr) + /* : No clobber */); + } +} + +static void __flush_dcache_all(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(cpuinfo.dcache_line_size - 1); + end += (cpuinfo.dcache_line_size - 1); + end &= ~(cpuinfo.dcache_line_size - 1); + + if (end > start + cpuinfo.dcache_size) + end = start + cpuinfo.dcache_size; + + for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) { + __asm__ __volatile__ (" flushd 0(%0)\n" + : /* Outputs */ + : /* Inputs */ "r"(addr) + /* : No clobber */); + } +} + +static void __invalidate_dcache(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(cpuinfo.dcache_line_size - 1); + end += (cpuinfo.dcache_line_size - 1); + end &= ~(cpuinfo.dcache_line_size - 1); + + if (end > start + cpuinfo.dcache_size) + end = start + cpuinfo.dcache_size; + + for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) { + __asm__ __volatile__ (" initda 0(%0)\n" + : /* Outputs */ + : /* Inputs */ "r"(addr) + /* : No clobber */); + } +} + +static void __flush_icache(unsigned long start, unsigned long end) +{ + unsigned long addr; + + start &= ~(cpuinfo.icache_line_size - 1); + end += (cpuinfo.icache_line_size - 1); + end &= ~(cpuinfo.icache_line_size - 1); + + if (end > start + cpuinfo.icache_size) + end = start + cpuinfo.icache_size; + + for (addr = start; addr < end; addr += cpuinfo.icache_line_size) { + __asm__ __volatile__ (" flushi %0\n" + : /* Outputs */ + : /* Inputs */ "r"(addr) + /* : No clobber */); + } + __asm__ __volatile(" flushp\n"); +} + +static void flush_aliases(struct address_space *mapping, struct page *page) +{ + struct mm_struct *mm = current->active_mm; + struct vm_area_struct *mpnt; + pgoff_t pgoff; + + pgoff = page->index; + + flush_dcache_mmap_lock(mapping); + vma_interval_tree_foreach(mpnt, &mapping->i_mmap, pgoff, pgoff) { + unsigned long offset; + + if (mpnt->vm_mm != mm) + continue; + if (!(mpnt->vm_flags & VM_MAYSHARE)) + continue; + + offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; + flush_cache_page(mpnt, mpnt->vm_start + offset, + page_to_pfn(page)); + } + flush_dcache_mmap_unlock(mapping); +} + +void flush_cache_all(void) +{ + __flush_dcache_all(0, cpuinfo.dcache_size); + __flush_icache(0, cpuinfo.icache_size); +} + +void flush_cache_mm(struct mm_struct *mm) +{ + flush_cache_all(); +} + +void flush_cache_dup_mm(struct mm_struct *mm) +{ + flush_cache_all(); +} + +void flush_icache_range(unsigned long start, unsigned long end) +{ + __flush_icache(start, end); +} + +void flush_dcache_range(unsigned long start, unsigned long end) +{ + __flush_dcache(start, end); +} +EXPORT_SYMBOL(flush_dcache_range); + +void invalidate_dcache_range(unsigned long start, unsigned long end) +{ + __invalidate_dcache(start, end); +} +EXPORT_SYMBOL(invalidate_dcache_range); + +void flush_cache_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + __flush_dcache(start, end); + if (vma == NULL || (vma->vm_flags & VM_EXEC)) + __flush_icache(start, end); +} + +void flush_icache_page(struct vm_area_struct *vma, struct page *page) +{ + unsigned long start = (unsigned long) page_address(page); + unsigned long end = start + PAGE_SIZE; + + __flush_icache(start, end); +} + +void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, + unsigned long pfn) +{ + unsigned long start = vmaddr; + unsigned long end = start + PAGE_SIZE; + + __flush_dcache(start, end); + if (vma->vm_flags & VM_EXEC) + __flush_icache(start, end); +} + +void flush_dcache_page(struct page *page) +{ + struct address_space *mapping; + + /* + * The zero page is never written to, so never has any dirty + * cache lines, and therefore never needs to be flushed. + */ + if (page == ZERO_PAGE(0)) + return; + + mapping = page_mapping(page); + + /* Flush this page if there are aliases. */ + if (mapping && !mapping_mapped(mapping)) { + clear_bit(PG_dcache_clean, &page->flags); + } else { + unsigned long start = (unsigned long)page_address(page); + + __flush_dcache_all(start, start + PAGE_SIZE); + if (mapping) + flush_aliases(mapping, page); + set_bit(PG_dcache_clean, &page->flags); + } +} +EXPORT_SYMBOL(flush_dcache_page); + +void update_mmu_cache(struct vm_area_struct *vma, + unsigned long address, pte_t *pte) +{ + unsigned long pfn = pte_pfn(*pte); + struct page *page; + + if (!pfn_valid(pfn)) + return; + + /* + * The zero page is never written to, so never has any dirty + * cache lines, and therefore never needs to be flushed. + */ + page = pfn_to_page(pfn); + if (page == ZERO_PAGE(0)) + return; + + if (!PageReserved(page) && + !test_and_set_bit(PG_dcache_clean, &page->flags)) { + unsigned long start = page_to_virt(page); + struct address_space *mapping; + + __flush_dcache(start, start + PAGE_SIZE); + + mapping = page_mapping(page); + if (mapping) + flush_aliases(mapping, page); + } +} + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *to) +{ + __flush_dcache(vaddr, vaddr + PAGE_SIZE); + copy_page(vto, vfrom); + __flush_dcache((unsigned long)vto, (unsigned long)vto + PAGE_SIZE); +} + +void clear_user_page(void *addr, unsigned long vaddr, struct page *page) +{ + __flush_dcache(vaddr, vaddr + PAGE_SIZE); + clear_page(addr); + __flush_dcache((unsigned long)addr, (unsigned long)addr + PAGE_SIZE); +} + +void copy_from_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, + void *dst, void *src, int len) +{ + flush_cache_page(vma, user_vaddr, page_to_pfn(page)); + memcpy(dst, src, len); + __flush_dcache((unsigned long)src, (unsigned long)src + len); + if (vma->vm_flags & VM_EXEC) + __flush_icache((unsigned long)src, (unsigned long)src + len); +} + +void copy_to_user_page(struct vm_area_struct *vma, struct page *page, + unsigned long user_vaddr, + void *dst, void *src, int len) +{ + flush_cache_page(vma, user_vaddr, page_to_pfn(page)); + memcpy(dst, src, len); + __flush_dcache((unsigned long)dst, (unsigned long)dst + len); + if (vma->vm_flags & VM_EXEC) + __flush_icache((unsigned long)dst, (unsigned long)dst + len); +} diff --git a/arch/nios2/mm/dma-mapping.c b/arch/nios2/mm/dma-mapping.c new file mode 100644 index 000000000000..ac5da7594f0b --- /dev/null +++ b/arch/nios2/mm/dma-mapping.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * Based on DMA code from MIPS. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/export.h> +#include <linux/string.h> +#include <linux/scatterlist.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/cache.h> +#include <asm/cacheflush.h> + + +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + void *ret; + + /* ignore region specifiers */ + gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + + /* optimized page clearing */ + gfp |= __GFP_ZERO; + + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + gfp |= GFP_DMA; + + ret = (void *) __get_free_pages(gfp, get_order(size)); + if (ret != NULL) { + *dma_handle = virt_to_phys(ret); + flush_dcache_range((unsigned long) ret, + (unsigned long) ret + size); + ret = UNCAC_ADDR(ret); + } + + return ret; +} +EXPORT_SYMBOL(dma_alloc_coherent); + +void dma_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + unsigned long addr = (unsigned long) CAC_ADDR((unsigned long) vaddr); + + free_pages(addr, get_order(size)); +} +EXPORT_SYMBOL(dma_free_coherent); + +int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(!valid_dma_direction(direction)); + + for_each_sg(sg, sg, nents, i) { + void *addr; + + addr = sg_virt(sg); + if (addr) { + __dma_sync_for_device(addr, sg->length, direction); + sg->dma_address = sg_phys(sg); + } + } + + return nents; +} +EXPORT_SYMBOL(dma_map_sg); + +dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + void *addr; + + BUG_ON(!valid_dma_direction(direction)); + + addr = page_address(page) + offset; + __dma_sync_for_device(addr, size, direction); + + return page_to_phys(page) + offset; +} +EXPORT_SYMBOL(dma_map_page); + +void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(!valid_dma_direction(direction)); + + __dma_sync_for_cpu(phys_to_virt(dma_address), size, direction); +} +EXPORT_SYMBOL(dma_unmap_page); + +void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + void *addr; + int i; + + BUG_ON(!valid_dma_direction(direction)); + + if (direction == DMA_TO_DEVICE) + return; + + for_each_sg(sg, sg, nhwentries, i) { + addr = sg_virt(sg); + if (addr) + __dma_sync_for_cpu(addr, sg->length, direction); + } +} +EXPORT_SYMBOL(dma_unmap_sg); + +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + BUG_ON(!valid_dma_direction(direction)); + + __dma_sync_for_cpu(phys_to_virt(dma_handle), size, direction); +} +EXPORT_SYMBOL(dma_sync_single_for_cpu); + +void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ + BUG_ON(!valid_dma_direction(direction)); + + __dma_sync_for_device(phys_to_virt(dma_handle), size, direction); +} +EXPORT_SYMBOL(dma_sync_single_for_device); + +void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(!valid_dma_direction(direction)); + + __dma_sync_for_cpu(phys_to_virt(dma_handle), size, direction); +} +EXPORT_SYMBOL(dma_sync_single_range_for_cpu); + +void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(!valid_dma_direction(direction)); + + __dma_sync_for_device(phys_to_virt(dma_handle), size, direction); +} +EXPORT_SYMBOL(dma_sync_single_range_for_device); + +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(!valid_dma_direction(direction)); + + /* Make sure that gcc doesn't leave the empty loop body. */ + for_each_sg(sg, sg, nelems, i) + __dma_sync_for_cpu(sg_virt(sg), sg->length, direction); +} +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nelems, enum dma_data_direction direction) +{ + int i; + + BUG_ON(!valid_dma_direction(direction)); + + /* Make sure that gcc doesn't leave the empty loop body. */ + for_each_sg(sg, sg, nelems, i) + __dma_sync_for_device(sg_virt(sg), sg->length, direction); + +} +EXPORT_SYMBOL(dma_sync_sg_for_device); diff --git a/arch/nios2/mm/extable.c b/arch/nios2/mm/extable.c new file mode 100644 index 000000000000..4d2fc5a589d0 --- /dev/null +++ b/arch/nios2/mm/extable.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2010, Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009, Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/module.h> +#include <linux/uaccess.h> + +int fixup_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + fixup = search_exception_tables(regs->ea); + if (fixup) { + regs->ea = fixup->fixup; + return 1; + } + + return 0; +} diff --git a/arch/nios2/mm/fault.c b/arch/nios2/mm/fault.c new file mode 100644 index 000000000000..15a0bb5fc06d --- /dev/null +++ b/arch/nios2/mm/fault.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * based on arch/mips/mm/fault.c which is: + * + * Copyright (C) 1995-2000 Ralf Baechle + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/ptrace.h> + +#include <asm/mmu_context.h> +#include <asm/traps.h> + +#define EXC_SUPERV_INSN_ACCESS 9 /* Supervisor only instruction address */ +#define EXC_SUPERV_DATA_ACCESS 11 /* Supervisor only data address */ +#define EXC_X_PROTECTION_FAULT 13 /* TLB permission violation (x) */ +#define EXC_R_PROTECTION_FAULT 14 /* TLB permission violation (r) */ +#define EXC_W_PROTECTION_FAULT 15 /* TLB permission violation (w) */ + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + */ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long cause, + unsigned long address) +{ + struct vm_area_struct *vma = NULL; + struct task_struct *tsk = current; + struct mm_struct *mm = tsk->mm; + int code = SEGV_MAPERR; + int fault; + unsigned int flags = 0; + + cause >>= 2; + + /* Restart the instruction */ + regs->ea -= 4; + + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + */ + if (unlikely(address >= VMALLOC_START && address <= VMALLOC_END)) { + if (user_mode(regs)) + goto bad_area_nosemaphore; + else + goto vmalloc_fault; + } + + if (unlikely(address >= TASK_SIZE)) + goto bad_area_nosemaphore; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_atomic() || !mm) + goto bad_area_nosemaphore; + + if (user_mode(regs)) + flags |= FAULT_FLAG_USER; + + if (!down_read_trylock(&mm->mmap_sem)) { + if (!user_mode(regs) && !search_exception_tables(regs->ea)) + goto bad_area_nosemaphore; + down_read(&mm->mmap_sem); + } + + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, address)) + goto bad_area; +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + code = SEGV_ACCERR; + + switch (cause) { + case EXC_SUPERV_INSN_ACCESS: + goto bad_area; + case EXC_SUPERV_DATA_ACCESS: + goto bad_area; + case EXC_X_PROTECTION_FAULT: + if (!(vma->vm_flags & VM_EXEC)) + goto bad_area; + break; + case EXC_R_PROTECTION_FAULT: + if (!(vma->vm_flags & VM_READ)) + goto bad_area; + break; + case EXC_W_PROTECTION_FAULT: + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + flags = FAULT_FLAG_WRITE; + break; + } + +survive: + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + fault = handle_mm_fault(mm, vma, address, flags); + if (unlikely(fault & VM_FAULT_ERROR)) { + if (fault & VM_FAULT_OOM) + goto out_of_memory; + else if (fault & VM_FAULT_SIGBUS) + goto do_sigbus; + BUG(); + } + if (fault & VM_FAULT_MAJOR) + tsk->maj_flt++; + else + tsk->min_flt++; + + up_read(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up_read(&mm->mmap_sem); + +bad_area_nosemaphore: + /* User mode accesses just cause a SIGSEGV */ + if (user_mode(regs)) { + pr_alert("%s: unhandled page fault (%d) at 0x%08lx, " + "cause %ld\n", current->comm, SIGSEGV, address, cause); + show_regs(regs); + _exception(SIGSEGV, regs, code, address); + return; + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + if (fixup_exception(regs)) + return; + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + bust_spinlocks(1); + + pr_alert("Unable to handle kernel %s at virtual address %08lx", + address < PAGE_SIZE ? "NULL pointer dereference" : + "paging request", address); + pr_alert("ea = %08lx, ra = %08lx, cause = %ld\n", regs->ea, regs->ra, + cause); + panic("Oops"); + return; + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up_read(&mm->mmap_sem); + if (is_global_init(tsk)) { + yield(); + down_read(&mm->mmap_sem); + goto survive; + } + if (!user_mode(regs)) + goto no_context; + pagefault_out_of_memory(); + return; + +do_sigbus: + up_read(&mm->mmap_sem); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; + + _exception(SIGBUS, regs, BUS_ADRERR, address); + return; + +vmalloc_fault: + { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + * + * Do _not_ use "tsk" here. We might be inside + * an interrupt in the middle of a task switch.. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pud_t *pud, *pud_k; + pmd_t *pmd, *pmd_k; + pte_t *pte_k; + + pgd = pgd_current + offset; + pgd_k = init_mm.pgd + offset; + + if (!pgd_present(*pgd_k)) + goto no_context; + set_pgd(pgd, *pgd_k); + + pud = pud_offset(pgd, address); + pud_k = pud_offset(pgd_k, address); + if (!pud_present(*pud_k)) + goto no_context; + pmd = pmd_offset(pud, address); + pmd_k = pmd_offset(pud_k, address); + if (!pmd_present(*pmd_k)) + goto no_context; + set_pmd(pmd, *pmd_k); + + pte_k = pte_offset_kernel(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; + + flush_tlb_one(address); + return; + } +} diff --git a/arch/nios2/mm/init.c b/arch/nios2/mm/init.c new file mode 100644 index 000000000000..e75c75d249d6 --- /dev/null +++ b/arch/nios2/mm/init.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * Copyright (C) 2004 Microtronix Datacom Ltd + * + * based on arch/m68k/mm/init.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/pagemap.h> +#include <linux/bootmem.h> +#include <linux/slab.h> +#include <linux/binfmts.h> + +#include <asm/setup.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/sections.h> +#include <asm/tlb.h> +#include <asm/mmu_context.h> +#include <asm/cpuinfo.h> +#include <asm/processor.h> + +pgd_t *pgd_current; + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + * The parameters are pointers to where to stick the starting and ending + * addresses of available kernel virtual memory. + */ +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES]; + + memset(zones_size, 0, sizeof(zones_size)); + + pagetable_init(); + pgd_current = swapper_pg_dir; + + zones_size[ZONE_NORMAL] = max_mapnr; + + /* pass the memory from the bootmem allocator to the main allocator */ + free_area_init(zones_size); + + flush_dcache_range((unsigned long)empty_zero_page, + (unsigned long)empty_zero_page + PAGE_SIZE); +} + +void __init mem_init(void) +{ + unsigned long end_mem = memory_end; /* this must not include + kernel stack at top */ + + pr_debug("mem_init: start=%lx, end=%lx\n", memory_start, memory_end); + + end_mem &= PAGE_MASK; + high_memory = __va(end_mem); + + /* this will put all memory onto the freelists */ + free_all_bootmem(); + mem_init_print_info(NULL); +} + +void __init mmu_init(void) +{ + flush_tlb_all(); +} + +#ifdef CONFIG_BLK_DEV_INITRD +void __init free_initrd_mem(unsigned long start, unsigned long end) +{ + free_reserved_area((void *)start, (void *)end, -1, "initrd"); +} +#endif + +void __init_refok free_initmem(void) +{ + free_initmem_default(-1); +} + +#define __page_aligned(order) __aligned(PAGE_SIZE << (order)) +pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER); +pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER); +static struct page *kuser_page[1]; + +static int alloc_kuser_page(void) +{ + extern char __kuser_helper_start[], __kuser_helper_end[]; + int kuser_sz = __kuser_helper_end - __kuser_helper_start; + unsigned long vpage; + + vpage = get_zeroed_page(GFP_ATOMIC); + if (!vpage) + return -ENOMEM; + + /* Copy kuser helpers */ + memcpy((void *)vpage, __kuser_helper_start, kuser_sz); + + flush_icache_range(vpage, vpage + KUSER_SIZE); + kuser_page[0] = virt_to_page(vpage); + + return 0; +} +arch_initcall(alloc_kuser_page); + +int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) +{ + struct mm_struct *mm = current->mm; + int ret; + + down_write(&mm->mmap_sem); + + /* Map kuser helpers to user space address */ + ret = install_special_mapping(mm, KUSER_BASE, KUSER_SIZE, + VM_READ | VM_EXEC | VM_MAYREAD | + VM_MAYEXEC, kuser_page); + + up_write(&mm->mmap_sem); + + return ret; +} + +const char *arch_vma_name(struct vm_area_struct *vma) +{ + return (vma->vm_start == KUSER_BASE) ? "[kuser]" : NULL; +} diff --git a/arch/nios2/mm/ioremap.c b/arch/nios2/mm/ioremap.c new file mode 100644 index 000000000000..3a28177a01eb --- /dev/null +++ b/arch/nios2/mm/ioremap.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * Copyright (C) 2004 Microtronix Datacom Ltd. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/export.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> + +static inline void remap_area_pte(pte_t *pte, unsigned long address, + unsigned long size, unsigned long phys_addr, + unsigned long flags) +{ + unsigned long end; + unsigned long pfn; + pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ + | _PAGE_WRITE | flags); + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + if (address >= end) + BUG(); + pfn = PFN_DOWN(phys_addr); + do { + if (!pte_none(*pte)) { + pr_err("remap_area_pte: page already exists\n"); + BUG(); + } + set_pte(pte, pfn_pte(pfn, pgprot)); + address += PAGE_SIZE; + pfn++; + pte++; + } while (address && (address < end)); +} + +static inline int remap_area_pmd(pmd_t *pmd, unsigned long address, + unsigned long size, unsigned long phys_addr, + unsigned long flags) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + if (address >= end) + BUG(); + do { + pte_t *pte = pte_alloc_kernel(pmd, address); + + if (!pte) + return -ENOMEM; + remap_area_pte(pte, address, end - address, address + phys_addr, + flags); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +static int remap_area_pages(unsigned long address, unsigned long phys_addr, + unsigned long size, unsigned long flags) +{ + int error; + pgd_t *dir; + unsigned long end = address + size; + + phys_addr -= address; + dir = pgd_offset(&init_mm, address); + flush_cache_all(); + if (address >= end) + BUG(); + do { + pud_t *pud; + pmd_t *pmd; + + error = -ENOMEM; + pud = pud_alloc(&init_mm, dir, address); + if (!pud) + break; + pmd = pmd_alloc(&init_mm, pud, address); + if (!pmd) + break; + if (remap_area_pmd(pmd, address, end - address, + phys_addr + address, flags)) + break; + error = 0; + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + flush_tlb_all(); + return error; +} + +#define IS_MAPPABLE_UNCACHEABLE(addr) (addr < 0x20000000UL) + +/* + * Map some physical address range into the kernel address space. + */ +void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, + unsigned long cacheflag) +{ + struct vm_struct *area; + unsigned long offset; + unsigned long last_addr; + void *addr; + + /* Don't allow wraparound or zero size */ + last_addr = phys_addr + size - 1; + + if (!size || last_addr < phys_addr) + return NULL; + + /* Don't allow anybody to remap normal RAM that we're using */ + if (phys_addr > PHYS_OFFSET && phys_addr < virt_to_phys(high_memory)) { + char *t_addr, *t_end; + struct page *page; + + t_addr = __va(phys_addr); + t_end = t_addr + (size - 1); + for (page = virt_to_page(t_addr); + page <= virt_to_page(t_end); page++) + if (!PageReserved(page)) + return NULL; + } + + /* + * Map uncached objects in the low part of address space to + * CONFIG_NIOS2_IO_REGION_BASE + */ + if (IS_MAPPABLE_UNCACHEABLE(phys_addr) && + IS_MAPPABLE_UNCACHEABLE(last_addr) && + !(cacheflag & _PAGE_CACHED)) + return (void __iomem *)(CONFIG_NIOS2_IO_REGION_BASE + phys_addr); + + /* Mappings have to be page-aligned */ + offset = phys_addr & ~PAGE_MASK; + phys_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr + 1) - phys_addr; + + /* Ok, go for it */ + area = get_vm_area(size, VM_IOREMAP); + if (!area) + return NULL; + addr = area->addr; + if (remap_area_pages((unsigned long) addr, phys_addr, size, + cacheflag)) { + vunmap(addr); + return NULL; + } + return (void __iomem *) (offset + (char *)addr); +} +EXPORT_SYMBOL(__ioremap); + +/* + * __iounmap unmaps nearly everything, so be careful + * it doesn't free currently pointer/page tables anymore but it + * wasn't used anyway and might be added later. + */ +void __iounmap(void __iomem *addr) +{ + struct vm_struct *p; + + if ((unsigned long) addr > CONFIG_NIOS2_IO_REGION_BASE) + return; + + p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr)); + if (!p) + pr_err("iounmap: bad address %p\n", addr); + kfree(p); +} +EXPORT_SYMBOL(__iounmap); diff --git a/arch/nios2/mm/mmu_context.c b/arch/nios2/mm/mmu_context.c new file mode 100644 index 000000000000..45d6b9c58d67 --- /dev/null +++ b/arch/nios2/mm/mmu_context.c @@ -0,0 +1,116 @@ +/* + * MMU context handling. + * + * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/mm.h> + +#include <asm/cpuinfo.h> +#include <asm/mmu_context.h> +#include <asm/tlb.h> + +/* The pids position and mask in context */ +#define PID_SHIFT 0 +#define PID_BITS (cpuinfo.tlb_pid_num_bits) +#define PID_MASK ((1UL << PID_BITS) - 1) + +/* The versions position and mask in context */ +#define VERSION_BITS (32 - PID_BITS) +#define VERSION_SHIFT (PID_SHIFT + PID_BITS) +#define VERSION_MASK ((1UL << VERSION_BITS) - 1) + +/* Return the version part of a context */ +#define CTX_VERSION(c) (((c) >> VERSION_SHIFT) & VERSION_MASK) + +/* Return the pid part of a context */ +#define CTX_PID(c) (((c) >> PID_SHIFT) & PID_MASK) + +/* Value of the first context (version 1, pid 0) */ +#define FIRST_CTX ((1UL << VERSION_SHIFT) | (0 << PID_SHIFT)) + +static mm_context_t next_mmu_context; + +/* + * Initialize MMU context management stuff. + */ +void __init mmu_context_init(void) +{ + /* We need to set this here because the value depends on runtime data + * from cpuinfo */ + next_mmu_context = FIRST_CTX; +} + +/* + * Set new context (pid), keep way + */ +static void set_context(mm_context_t context) +{ + set_mmu_pid(CTX_PID(context)); +} + +static mm_context_t get_new_context(void) +{ + /* Return the next pid */ + next_mmu_context += (1UL << PID_SHIFT); + + /* If the pid field wraps around we increase the version and + * flush the tlb */ + if (unlikely(CTX_PID(next_mmu_context) == 0)) { + /* Version is incremented since the pid increment above + * overflows info version */ + flush_cache_all(); + flush_tlb_all(); + } + + /* If the version wraps we start over with the first generation, we do + * not need to flush the tlb here since it's always done above */ + if (unlikely(CTX_VERSION(next_mmu_context) == 0)) + next_mmu_context = FIRST_CTX; + + return next_mmu_context; +} + +void switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned long flags; + + local_irq_save(flags); + + /* If the process context we are swapping in has a different context + * generation then we have it should get a new generation/pid */ + if (unlikely(CTX_VERSION(next->context) != + CTX_VERSION(next_mmu_context))) + next->context = get_new_context(); + + /* Save the current pgd so the fast tlb handler can find it */ + pgd_current = next->pgd; + + /* Set the current context */ + set_context(next->context); + + local_irq_restore(flags); +} + +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +void activate_mm(struct mm_struct *prev, struct mm_struct *next) +{ + next->context = get_new_context(); + set_context(next->context); + pgd_current = next->pgd; +} + +unsigned long get_pid_from_context(mm_context_t *context) +{ + return CTX_PID((*context)); +} diff --git a/arch/nios2/mm/pgtable.c b/arch/nios2/mm/pgtable.c new file mode 100644 index 000000000000..61e24a25f71a --- /dev/null +++ b/arch/nios2/mm/pgtable.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2009 Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/mm.h> +#include <linux/sched.h> + +#include <asm/pgtable.h> +#include <asm/cpuinfo.h> + +/* pteaddr: + * ptbase | vpn* | zero + * 31-22 | 21-2 | 1-0 + * + * *vpn is preserved on double fault + * + * tlbacc: + * IG |*flags| pfn + * 31-25|24-20 | 19-0 + * + * *crwxg + * + * tlbmisc: + * resv |way |rd | we|pid |dbl|bad|perm|d + * 31-24 |23-20 |19 | 20|17-4|3 |2 |1 |0 + * + */ + +/* + * Initialize a new pgd / pmd table with invalid pointers. + */ +static void pgd_init(pgd_t *pgd) +{ + unsigned long *p = (unsigned long *) pgd; + int i; + + for (i = 0; i < USER_PTRS_PER_PGD; i += 8) { + p[i + 0] = (unsigned long) invalid_pte_table; + p[i + 1] = (unsigned long) invalid_pte_table; + p[i + 2] = (unsigned long) invalid_pte_table; + p[i + 3] = (unsigned long) invalid_pte_table; + p[i + 4] = (unsigned long) invalid_pte_table; + p[i + 5] = (unsigned long) invalid_pte_table; + p[i + 6] = (unsigned long) invalid_pte_table; + p[i + 7] = (unsigned long) invalid_pte_table; + } +} + +pgd_t *pgd_alloc(struct mm_struct *mm) +{ + pgd_t *ret, *init; + + ret = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ORDER); + if (ret) { + init = pgd_offset(&init_mm, 0UL); + pgd_init(ret); + memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + + return ret; +} + +void __init pagetable_init(void) +{ + /* Initialize the entire pgd. */ + pgd_init(swapper_pg_dir); + pgd_init(swapper_pg_dir + USER_PTRS_PER_PGD); +} diff --git a/arch/nios2/mm/tlb.c b/arch/nios2/mm/tlb.c new file mode 100644 index 000000000000..cf10326aab1c --- /dev/null +++ b/arch/nios2/mm/tlb.c @@ -0,0 +1,275 @@ +/* + * Nios2 TLB handling + * + * Copyright (C) 2009, Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/pagemap.h> + +#include <asm/tlb.h> +#include <asm/mmu_context.h> +#include <asm/pgtable.h> +#include <asm/cpuinfo.h> + +#define TLB_INDEX_MASK \ + ((((1UL << (cpuinfo.tlb_ptr_sz - cpuinfo.tlb_num_ways_log2))) - 1) \ + << PAGE_SHIFT) + +/* Used as illegal PHYS_ADDR for TLB mappings + */ +#define MAX_PHYS_ADDR 0 + +static void get_misc_and_pid(unsigned long *misc, unsigned long *pid) +{ + *misc = RDCTL(CTL_TLBMISC); + *misc &= (TLBMISC_PID | TLBMISC_WAY); + *pid = *misc & TLBMISC_PID; +} + +/* + * All entries common to a mm share an asid. To effectively flush these + * entries, we just bump the asid. + */ +void flush_tlb_mm(struct mm_struct *mm) +{ + if (current->mm == mm) + flush_tlb_all(); + else + memset(&mm->context, 0, sizeof(mm_context_t)); +} + +/* + * This one is only used for pages with the global bit set so we don't care + * much about the ASID. + */ +void flush_tlb_one_pid(unsigned long addr, unsigned long mmu_pid) +{ + unsigned int way; + unsigned long org_misc, pid_misc; + + pr_debug("Flush tlb-entry for vaddr=%#lx\n", addr); + + /* remember pid/way until we return. */ + get_misc_and_pid(&org_misc, &pid_misc); + + WRCTL(CTL_PTEADDR, (addr >> PAGE_SHIFT) << 2); + + for (way = 0; way < cpuinfo.tlb_num_ways; way++) { + unsigned long pteaddr; + unsigned long tlbmisc; + unsigned long pid; + + tlbmisc = pid_misc | TLBMISC_RD | (way << TLBMISC_WAY_SHIFT); + WRCTL(CTL_TLBMISC, tlbmisc); + pteaddr = RDCTL(CTL_PTEADDR); + tlbmisc = RDCTL(CTL_TLBMISC); + pid = (tlbmisc >> TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK; + if (((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) && + pid == mmu_pid) { + unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE + + ((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) + + (addr & TLB_INDEX_MASK); + pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n", + vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT)); + + WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2); + tlbmisc = pid_misc | TLBMISC_WE | + (way << TLBMISC_WAY_SHIFT); + WRCTL(CTL_TLBMISC, tlbmisc); + WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT)); + } + } + + WRCTL(CTL_TLBMISC, org_misc); +} + +void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end) +{ + unsigned long mmu_pid = get_pid_from_context(&vma->vm_mm->context); + + while (start < end) { + flush_tlb_one_pid(start, mmu_pid); + start += PAGE_SIZE; + } +} + +void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + while (start < end) { + flush_tlb_one(start); + start += PAGE_SIZE; + } +} + +/* + * This one is only used for pages with the global bit set so we don't care + * much about the ASID. + */ +void flush_tlb_one(unsigned long addr) +{ + unsigned int way; + unsigned long org_misc, pid_misc; + + pr_debug("Flush tlb-entry for vaddr=%#lx\n", addr); + + /* remember pid/way until we return. */ + get_misc_and_pid(&org_misc, &pid_misc); + + WRCTL(CTL_PTEADDR, (addr >> PAGE_SHIFT) << 2); + + for (way = 0; way < cpuinfo.tlb_num_ways; way++) { + unsigned long pteaddr; + unsigned long tlbmisc; + + tlbmisc = pid_misc | TLBMISC_RD | (way << TLBMISC_WAY_SHIFT); + WRCTL(CTL_TLBMISC, tlbmisc); + pteaddr = RDCTL(CTL_PTEADDR); + tlbmisc = RDCTL(CTL_TLBMISC); + + if ((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) { + unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE + + ((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) + + (addr & TLB_INDEX_MASK); + + pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n", + vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT)); + + tlbmisc = pid_misc | TLBMISC_WE | + (way << TLBMISC_WAY_SHIFT); + WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2); + WRCTL(CTL_TLBMISC, tlbmisc); + WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT)); + } + } + + WRCTL(CTL_TLBMISC, org_misc); +} + +void dump_tlb_line(unsigned long line) +{ + unsigned int way; + unsigned long org_misc; + + pr_debug("dump tlb-entries for line=%#lx (addr %08lx)\n", line, + line << (PAGE_SHIFT + cpuinfo.tlb_num_ways_log2)); + + /* remember pid/way until we return */ + org_misc = (RDCTL(CTL_TLBMISC) & (TLBMISC_PID | TLBMISC_WAY)); + + WRCTL(CTL_PTEADDR, line << 2); + + for (way = 0; way < cpuinfo.tlb_num_ways; way++) { + unsigned long pteaddr; + unsigned long tlbmisc; + unsigned long tlbacc; + + WRCTL(CTL_TLBMISC, TLBMISC_RD | (way << TLBMISC_WAY_SHIFT)); + pteaddr = RDCTL(CTL_PTEADDR); + tlbmisc = RDCTL(CTL_TLBMISC); + tlbacc = RDCTL(CTL_TLBACC); + + if ((tlbacc << PAGE_SHIFT) != (MAX_PHYS_ADDR & PAGE_MASK)) { + pr_debug("-- way:%02x vpn:0x%08lx phys:0x%08lx pid:0x%02lx flags:%c%c%c%c%c\n", + way, + (pteaddr << (PAGE_SHIFT-2)), + (tlbacc << PAGE_SHIFT), + ((tlbmisc >> TLBMISC_PID_SHIFT) & + TLBMISC_PID_MASK), + (tlbacc & _PAGE_READ ? 'r' : '-'), + (tlbacc & _PAGE_WRITE ? 'w' : '-'), + (tlbacc & _PAGE_EXEC ? 'x' : '-'), + (tlbacc & _PAGE_GLOBAL ? 'g' : '-'), + (tlbacc & _PAGE_CACHED ? 'c' : '-')); + } + } + + WRCTL(CTL_TLBMISC, org_misc); +} + +void dump_tlb(void) +{ + unsigned int i; + + for (i = 0; i < cpuinfo.tlb_num_lines; i++) + dump_tlb_line(i); +} + +void flush_tlb_pid(unsigned long pid) +{ + unsigned int line; + unsigned int way; + unsigned long org_misc, pid_misc; + + /* remember pid/way until we return */ + get_misc_and_pid(&org_misc, &pid_misc); + + for (line = 0; line < cpuinfo.tlb_num_lines; line++) { + WRCTL(CTL_PTEADDR, line << 2); + + for (way = 0; way < cpuinfo.tlb_num_ways; way++) { + unsigned long pteaddr; + unsigned long tlbmisc; + unsigned long tlbacc; + + tlbmisc = pid_misc | TLBMISC_RD | + (way << TLBMISC_WAY_SHIFT); + WRCTL(CTL_TLBMISC, tlbmisc); + pteaddr = RDCTL(CTL_PTEADDR); + tlbmisc = RDCTL(CTL_TLBMISC); + tlbacc = RDCTL(CTL_TLBACC); + + if (((tlbmisc>>TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK) + == pid) { + tlbmisc = pid_misc | TLBMISC_WE | + (way << TLBMISC_WAY_SHIFT); + WRCTL(CTL_TLBMISC, tlbmisc); + WRCTL(CTL_TLBACC, + (MAX_PHYS_ADDR >> PAGE_SHIFT)); + } + } + + WRCTL(CTL_TLBMISC, org_misc); + } +} + +void flush_tlb_all(void) +{ + int i; + unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE; + unsigned int way; + unsigned long org_misc, pid_misc, tlbmisc; + + /* remember pid/way until we return */ + get_misc_and_pid(&org_misc, &pid_misc); + pid_misc |= TLBMISC_WE; + + /* Map each TLB entry to physcal address 0 with no-access and a + bad ptbase */ + for (way = 0; way < cpuinfo.tlb_num_ways; way++) { + tlbmisc = pid_misc | (way << TLBMISC_WAY_SHIFT); + for (i = 0; i < cpuinfo.tlb_num_lines; i++) { + WRCTL(CTL_PTEADDR, ((vaddr) >> PAGE_SHIFT) << 2); + WRCTL(CTL_TLBMISC, tlbmisc); + WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT)); + vaddr += 1UL << 12; + } + } + + /* restore pid/way */ + WRCTL(CTL_TLBMISC, org_misc); +} + +void set_mmu_pid(unsigned long pid) +{ + WRCTL(CTL_TLBMISC, (RDCTL(CTL_TLBMISC) & TLBMISC_WAY) | + ((pid & TLBMISC_PID_MASK) << TLBMISC_PID_SHIFT)); +} diff --git a/arch/nios2/mm/uaccess.c b/arch/nios2/mm/uaccess.c new file mode 100644 index 000000000000..7663e156ff4f --- /dev/null +++ b/arch/nios2/mm/uaccess.c @@ -0,0 +1,163 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2009, Wind River Systems Inc + * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com + */ + +#include <linux/export.h> +#include <linux/uaccess.h> + +asm(".global __copy_from_user\n" + " .type __copy_from_user, @function\n" + "__copy_from_user:\n" + " movi r2,7\n" + " mov r3,r4\n" + " bge r2,r6,1f\n" + " xor r2,r4,r5\n" + " andi r2,r2,3\n" + " movi r7,3\n" + " beq r2,zero,4f\n" + "1: addi r6,r6,-1\n" + " movi r2,-1\n" + " beq r6,r2,3f\n" + " mov r7,r2\n" + "2: ldbu r2,0(r5)\n" + " addi r6,r6,-1\n" + " addi r5,r5,1\n" + " stb r2,0(r3)\n" + " addi r3,r3,1\n" + " bne r6,r7,2b\n" + "3:\n" + " addi r2,r6,1\n" + " ret\n" + "13:mov r2,r6\n" + " ret\n" + "4: andi r2,r4,1\n" + " cmpeq r2,r2,zero\n" + " beq r2,zero,7f\n" + "5: andi r2,r3,2\n" + " beq r2,zero,6f\n" + "9: ldhu r2,0(r5)\n" + " addi r6,r6,-2\n" + " addi r5,r5,2\n" + " sth r2,0(r3)\n" + " addi r3,r3,2\n" + "6: bge r7,r6,1b\n" + "10:ldw r2,0(r5)\n" + " addi r6,r6,-4\n" + " addi r5,r5,4\n" + " stw r2,0(r3)\n" + " addi r3,r3,4\n" + " br 6b\n" + "7: ldbu r2,0(r5)\n" + " addi r6,r6,-1\n" + " addi r5,r5,1\n" + " addi r3,r4,1\n" + " stb r2,0(r4)\n" + " br 5b\n" + ".section __ex_table,\"a\"\n" + ".word 2b,3b\n" + ".word 9b,13b\n" + ".word 10b,13b\n" + ".word 7b,13b\n" + ".previous\n" + ); +EXPORT_SYMBOL(__copy_from_user); + +asm( + " .global __copy_to_user\n" + " .type __copy_to_user, @function\n" + "__copy_to_user:\n" + " movi r2,7\n" + " mov r3,r4\n" + " bge r2,r6,1f\n" + " xor r2,r4,r5\n" + " andi r2,r2,3\n" + " movi r7,3\n" + " beq r2,zero,4f\n" + /* Bail if we try to copy zero bytes */ + "1: addi r6,r6,-1\n" + " movi r2,-1\n" + " beq r6,r2,3f\n" + /* Copy byte by byte for small copies and if src^dst != 0 */ + " mov r7,r2\n" + "2: ldbu r2,0(r5)\n" + " addi r5,r5,1\n" + "9: stb r2,0(r3)\n" + " addi r6,r6,-1\n" + " addi r3,r3,1\n" + " bne r6,r7,2b\n" + "3: addi r2,r6,1\n" + " ret\n" + "13:mov r2,r6\n" + " ret\n" + /* If 'to' is an odd address byte copy */ + "4: andi r2,r4,1\n" + " cmpeq r2,r2,zero\n" + " beq r2,zero,7f\n" + /* If 'to' is not divideable by four copy halfwords */ + "5: andi r2,r3,2\n" + " beq r2,zero,6f\n" + " ldhu r2,0(r5)\n" + " addi r5,r5,2\n" + "10:sth r2,0(r3)\n" + " addi r6,r6,-2\n" + " addi r3,r3,2\n" + /* Copy words */ + "6: bge r7,r6,1b\n" + " ldw r2,0(r5)\n" + " addi r5,r5,4\n" + "11:stw r2,0(r3)\n" + " addi r6,r6,-4\n" + " addi r3,r3,4\n" + " br 6b\n" + /* Copy remaining bytes */ + "7: ldbu r2,0(r5)\n" + " addi r5,r5,1\n" + " addi r3,r4,1\n" + "12: stb r2,0(r4)\n" + " addi r6,r6,-1\n" + " br 5b\n" + ".section __ex_table,\"a\"\n" + ".word 9b,3b\n" + ".word 10b,13b\n" + ".word 11b,13b\n" + ".word 12b,13b\n" + ".previous\n"); +EXPORT_SYMBOL(__copy_to_user); + +long strncpy_from_user(char *__to, const char __user *__from, long __len) +{ + int l = strnlen_user(__from, __len); + int is_zt = 1; + + if (l > __len) { + is_zt = 0; + l = __len; + } + + if (l == 0 || copy_from_user(__to, __from, l)) + return -EFAULT; + + if (is_zt) + l--; + return l; +} + +long strnlen_user(const char __user *s, long n) +{ + long i; + + for (i = 0; i < n; i++) { + char c; + + if (get_user(c, s + i) == -EFAULT) + return 0; + if (c == 0) + return i + 1; + } + return n + 1; +} diff --git a/arch/nios2/platform/Kconfig.platform b/arch/nios2/platform/Kconfig.platform new file mode 100644 index 000000000000..d3e5df9fb36b --- /dev/null +++ b/arch/nios2/platform/Kconfig.platform @@ -0,0 +1,129 @@ +menu "Platform options" + +comment "Memory settings" + +config NIOS2_MEM_BASE + hex "Memory base address" + default "0x00000000" + help + This is the physical address of the memory that the kernel will run + from. This address is used to link the kernel and setup initial memory + management. You should take the raw memory address without any MMU + or cache bits set. + Please not that this address is used directly so you have to manually + do address translation if it's connected to a bridge. + +comment "Device tree" + +config NIOS2_DTB_AT_PHYS_ADDR + bool "DTB at physical address" + default n + help + When enabled you can select a physical address to load the dtb from. + Normally this address is passed by a bootloader such as u-boot but + using this you can use a devicetree without a bootloader. + This way you can store a devicetree in NOR flash or an onchip rom. + Please note that this address is used directly so you have to manually + do address translation if it's connected to a bridge. Also take into + account that when using an MMU you'd have to ad 0xC0000000 to your + address + +config NIOS2_DTB_PHYS_ADDR + hex "DTB Address" + depends on NIOS2_DTB_AT_PHYS_ADDR + default "0xC0000000" + help + Physical address of a dtb blob. + +config NIOS2_DTB_SOURCE_BOOL + bool "Compile and link device tree into kernel image" + default n + help + This allows you to specify a dts (device tree source) file + which will be compiled and linked into the kernel image. + +config NIOS2_DTB_SOURCE + string "Device tree source file" + depends on NIOS2_DTB_SOURCE_BOOL + default "" + help + Absolute path to the device tree source (dts) file describing your + system. + +comment "Nios II instructions" + +config NIOS2_HW_MUL_SUPPORT + bool "Enable MUL instruction" + default n + help + Set to true if you configured the Nios II to include the MUL + instruction. This will enable the -mhw-mul compiler flag. + +config NIOS2_HW_MULX_SUPPORT + bool "Enable MULX instruction" + default n + help + Set to true if you configured the Nios II to include the MULX + instruction. Enables the -mhw-mulx compiler flag. + +config NIOS2_HW_DIV_SUPPORT + bool "Enable DIV instruction" + default n + help + Set to true if you configured the Nios II to include the DIV + instruction. Enables the -mhw-div compiler flag. + +config NIOS2_FPU_SUPPORT + bool "Custom floating point instr support" + default n + help + Enables the -mcustom-fpu-cfg=60-1 compiler flag. + +config NIOS2_CI_SWAB_SUPPORT + bool "Byteswap custom instruction" + default n + help + Use the byteswap (endian converter) Nios II custom instruction provided + by Altera and which can be enabled in QSYS builder. This accelerates + endian conversions in the kernel (e.g. ntohs). + +config NIOS2_CI_SWAB_NO + int "Byteswap custom instruction number" if NIOS2_CI_SWAB_SUPPORT + default 0 + help + Number of the instruction as configured in QSYS Builder. + +comment "Cache settings" + +config CUSTOM_CACHE_SETTINGS + bool "Custom cache settings" + help + This option allows you to tweak the cache settings used during early + boot (where the information from device tree is not yet available). + There should be no reason to change these values. Linux will work + perfectly fine, even if the Nios II is configured with smaller caches. + + Say N here unless you know what you are doing. + +config NIOS2_DCACHE_SIZE + hex "D-Cache size" if CUSTOM_CACHE_SETTINGS + range 0x200 0x10000 + default "0x800" + help + Maximum possible data cache size. + +config NIOS2_DCACHE_LINE_SIZE + hex "D-Cache line size" if CUSTOM_CACHE_SETTINGS + range 0x10 0x20 + default "0x20" + help + Minimum possible data cache line size. + +config NIOS2_ICACHE_SIZE + hex "I-Cache size" if CUSTOM_CACHE_SETTINGS + range 0x200 0x10000 + default "0x1000" + help + Maximum possible instruction cache size. + +endmenu diff --git a/arch/nios2/platform/Makefile b/arch/nios2/platform/Makefile new file mode 100644 index 000000000000..46364f1d9352 --- /dev/null +++ b/arch/nios2/platform/Makefile @@ -0,0 +1 @@ +obj-y += platform.o diff --git a/arch/nios2/platform/platform.c b/arch/nios2/platform/platform.c new file mode 100644 index 000000000000..d478773f758a --- /dev/null +++ b/arch/nios2/platform/platform.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013 Altera Corporation + * Copyright (C) 2011 Thomas Chou + * Copyright (C) 2011 Walter Goossens + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + */ + +#include <linux/init.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/of_fdt.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> +#include <linux/io.h> + +static int __init nios2_soc_device_init(void) +{ + struct soc_device *soc_dev; + struct soc_device_attribute *soc_dev_attr; + const char *machine; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (soc_dev_attr) { + machine = of_flat_dt_get_machine_name(); + if (machine) + soc_dev_attr->machine = kasprintf(GFP_KERNEL, "%s", + machine); + + soc_dev_attr->family = "Nios II"; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->machine); + kfree(soc_dev_attr); + } + } + + return of_platform_populate(NULL, of_default_bus_match_table, + NULL, NULL); +} + +device_initcall(nios2_soc_device_init); diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h index 4006964d8e12..a5cb070b54bf 100644 --- a/arch/parisc/include/asm/uaccess.h +++ b/arch/parisc/include/asm/uaccess.h @@ -9,6 +9,8 @@ #include <asm/errno.h> #include <asm-generic/uaccess-unaligned.h> +#include <linux/bug.h> + #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -28,11 +30,6 @@ * that put_user is the same as __put_user, etc. */ -extern int __get_kernel_bad(void); -extern int __get_user_bad(void); -extern int __put_kernel_bad(void); -extern int __put_user_bad(void); - static inline long access_ok(int type, const void __user * addr, unsigned long size) { @@ -43,8 +40,8 @@ static inline long access_ok(int type, const void __user * addr, #define get_user __get_user #if !defined(CONFIG_64BIT) -#define LDD_KERNEL(ptr) __get_kernel_bad(); -#define LDD_USER(ptr) __get_user_bad(); +#define LDD_KERNEL(ptr) BUILD_BUG() +#define LDD_USER(ptr) BUILD_BUG() #define STD_KERNEL(x, ptr) __put_kernel_asm64(x,ptr) #define STD_USER(x, ptr) __put_user_asm64(x,ptr) #define ASM_WORD_INSN ".word\t" @@ -94,7 +91,7 @@ struct exception_data { case 2: __get_kernel_asm("ldh",ptr); break; \ case 4: __get_kernel_asm("ldw",ptr); break; \ case 8: LDD_KERNEL(ptr); break; \ - default: __get_kernel_bad(); break; \ + default: BUILD_BUG(); break; \ } \ } \ else { \ @@ -103,7 +100,7 @@ struct exception_data { case 2: __get_user_asm("ldh",ptr); break; \ case 4: __get_user_asm("ldw",ptr); break; \ case 8: LDD_USER(ptr); break; \ - default: __get_user_bad(); break; \ + default: BUILD_BUG(); break; \ } \ } \ \ @@ -136,7 +133,7 @@ struct exception_data { case 2: __put_kernel_asm("sth",__x,ptr); break; \ case 4: __put_kernel_asm("stw",__x,ptr); break; \ case 8: STD_KERNEL(__x,ptr); break; \ - default: __put_kernel_bad(); break; \ + default: BUILD_BUG(); break; \ } \ } \ else { \ @@ -145,7 +142,7 @@ struct exception_data { case 2: __put_user_asm("sth",__x,ptr); break; \ case 4: __put_user_asm("stw",__x,ptr); break; \ case 8: STD_USER(__x,ptr); break; \ - default: __put_user_bad(); break; \ + default: BUILD_BUG(); break; \ } \ } \ \ diff --git a/arch/parisc/include/uapi/asm/bitsperlong.h b/arch/parisc/include/uapi/asm/bitsperlong.h index 75196b415d3f..e0a23c7bdd43 100644 --- a/arch/parisc/include/uapi/asm/bitsperlong.h +++ b/arch/parisc/include/uapi/asm/bitsperlong.h @@ -1,13 +1,7 @@ #ifndef __ASM_PARISC_BITSPERLONG_H #define __ASM_PARISC_BITSPERLONG_H -/* - * using CONFIG_* outside of __KERNEL__ is wrong, - * __LP64__ was also removed from headers, so what - * is the right approach on parisc? - * -arnd - */ -#if (defined(__KERNEL__) && defined(CONFIG_64BIT)) || defined (__LP64__) +#if defined(__LP64__) #define __BITS_PER_LONG 64 #define SHIFT_PER_LONG 6 #else diff --git a/arch/parisc/include/uapi/asm/msgbuf.h b/arch/parisc/include/uapi/asm/msgbuf.h index fe88f2649418..342138983914 100644 --- a/arch/parisc/include/uapi/asm/msgbuf.h +++ b/arch/parisc/include/uapi/asm/msgbuf.h @@ -1,6 +1,8 @@ #ifndef _PARISC_MSGBUF_H #define _PARISC_MSGBUF_H +#include <asm/bitsperlong.h> + /* * The msqid64_ds structure for parisc architecture, copied from sparc. * Note extra padding because this structure is passed back and forth @@ -13,15 +15,15 @@ struct msqid64_ds { struct ipc64_perm msg_perm; -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad1; #endif __kernel_time_t msg_stime; /* last msgsnd time */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad2; #endif __kernel_time_t msg_rtime; /* last msgrcv time */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad3; #endif __kernel_time_t msg_ctime; /* last change time */ diff --git a/arch/parisc/include/uapi/asm/sembuf.h b/arch/parisc/include/uapi/asm/sembuf.h index 1e59ffd3bd1e..f01d89e30d73 100644 --- a/arch/parisc/include/uapi/asm/sembuf.h +++ b/arch/parisc/include/uapi/asm/sembuf.h @@ -1,6 +1,8 @@ #ifndef _PARISC_SEMBUF_H #define _PARISC_SEMBUF_H +#include <asm/bitsperlong.h> + /* * The semid64_ds structure for parisc architecture. * Note extra padding because this structure is passed back and forth @@ -13,11 +15,11 @@ struct semid64_ds { struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad1; #endif __kernel_time_t sem_otime; /* last semop time */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad2; #endif __kernel_time_t sem_ctime; /* last change time */ diff --git a/arch/parisc/include/uapi/asm/shmbuf.h b/arch/parisc/include/uapi/asm/shmbuf.h index 0a3eada1863b..8496c38560c6 100644 --- a/arch/parisc/include/uapi/asm/shmbuf.h +++ b/arch/parisc/include/uapi/asm/shmbuf.h @@ -1,6 +1,8 @@ #ifndef _PARISC_SHMBUF_H #define _PARISC_SHMBUF_H +#include <asm/bitsperlong.h> + /* * The shmid64_ds structure for parisc architecture. * Note extra padding because this structure is passed back and forth @@ -13,19 +15,19 @@ struct shmid64_ds { struct ipc64_perm shm_perm; /* operation perms */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad1; #endif __kernel_time_t shm_atime; /* last attach time */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad2; #endif __kernel_time_t shm_dtime; /* last detach time */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad3; #endif __kernel_time_t shm_ctime; /* last change time */ -#ifndef CONFIG_64BIT +#if __BITS_PER_LONG != 64 unsigned int __pad4; #endif size_t shm_segsz; /* size of segment (bytes) */ @@ -36,23 +38,16 @@ struct shmid64_ds { unsigned int __unused2; }; -#ifdef CONFIG_64BIT -/* The 'unsigned int' (formerly 'unsigned long') data types below will - * ensure that a 32-bit app calling shmctl(*,IPC_INFO,*) will work on - * a wide kernel, but if some of these values are meant to contain pointers - * they may need to be 'long long' instead. -PB XXX FIXME - */ -#endif struct shminfo64 { - unsigned int shmmax; - unsigned int shmmin; - unsigned int shmmni; - unsigned int shmseg; - unsigned int shmall; - unsigned int __unused1; - unsigned int __unused2; - unsigned int __unused3; - unsigned int __unused4; + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; }; #endif /* _PARISC_SHMBUF_H */ diff --git a/arch/parisc/include/uapi/asm/signal.h b/arch/parisc/include/uapi/asm/signal.h index 10df7079f4cd..e26043b73f5d 100644 --- a/arch/parisc/include/uapi/asm/signal.h +++ b/arch/parisc/include/uapi/asm/signal.h @@ -85,7 +85,7 @@ struct siginfo; /* Type of a signal handler. */ -#ifdef CONFIG_64BIT +#if defined(__LP64__) /* function pointers on 64-bit parisc are pointers to little structs and the * compiler doesn't support code which changes or tests the address of * the function in the little struct. This is really ugly -PB diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h index 8667f18be238..5f5c0373de63 100644 --- a/arch/parisc/include/uapi/asm/unistd.h +++ b/arch/parisc/include/uapi/asm/unistd.h @@ -833,8 +833,9 @@ #define __NR_seccomp (__NR_Linux + 338) #define __NR_getrandom (__NR_Linux + 339) #define __NR_memfd_create (__NR_Linux + 340) +#define __NR_bpf (__NR_Linux + 341) -#define __NR_Linux_syscalls (__NR_memfd_create + 1) +#define __NR_Linux_syscalls (__NR_bpf + 1) #define __IGNORE_select /* newselect */ diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index b563d9c8268b..fe4f0b89bf8f 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -286,11 +286,11 @@ ENTRY_COMP(msgsnd) ENTRY_COMP(msgrcv) ENTRY_SAME(msgget) /* 190 */ - ENTRY_SAME(msgctl) - ENTRY_SAME(shmat) + ENTRY_COMP(msgctl) + ENTRY_COMP(shmat) ENTRY_SAME(shmdt) ENTRY_SAME(shmget) - ENTRY_SAME(shmctl) /* 195 */ + ENTRY_COMP(shmctl) /* 195 */ ENTRY_SAME(ni_syscall) /* streams1 */ ENTRY_SAME(ni_syscall) /* streams2 */ ENTRY_SAME(lstat64) @@ -323,7 +323,7 @@ ENTRY_SAME(epoll_ctl) /* 225 */ ENTRY_SAME(epoll_wait) ENTRY_SAME(remap_file_pages) - ENTRY_SAME(semtimedop) + ENTRY_COMP(semtimedop) ENTRY_COMP(mq_open) ENTRY_SAME(mq_unlink) /* 230 */ ENTRY_COMP(mq_timedsend) @@ -436,6 +436,7 @@ ENTRY_SAME(seccomp) ENTRY_SAME(getrandom) ENTRY_SAME(memfd_create) /* 340 */ + ENTRY_SAME(bpf) /* Nothing yet */ diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index a6774560afe3..493e72f64b35 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -70,39 +70,39 @@ #define CPU_UNKNOWN (~((u32)0)) /* Utility macros */ -#define SKIP_TO_NEXT_CPU(reg_entry) \ -({ \ - while (reg_entry->reg_id != REG_ID("CPUEND")) \ - reg_entry++; \ - reg_entry++; \ +#define SKIP_TO_NEXT_CPU(reg_entry) \ +({ \ + while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) \ + reg_entry++; \ + reg_entry++; \ }) /* Kernel Dump section info */ struct fadump_section { - u32 request_flag; - u16 source_data_type; - u16 error_flags; - u64 source_address; - u64 source_len; - u64 bytes_dumped; - u64 destination_address; + __be32 request_flag; + __be16 source_data_type; + __be16 error_flags; + __be64 source_address; + __be64 source_len; + __be64 bytes_dumped; + __be64 destination_address; }; /* ibm,configure-kernel-dump header. */ struct fadump_section_header { - u32 dump_format_version; - u16 dump_num_sections; - u16 dump_status_flag; - u32 offset_first_dump_section; + __be32 dump_format_version; + __be16 dump_num_sections; + __be16 dump_status_flag; + __be32 offset_first_dump_section; /* Fields for disk dump option. */ - u32 dd_block_size; - u64 dd_block_offset; - u64 dd_num_blocks; - u32 dd_offset_disk_path; + __be32 dd_block_size; + __be64 dd_block_offset; + __be64 dd_num_blocks; + __be32 dd_offset_disk_path; /* Maximum time allowed to prevent an automatic dump-reboot. */ - u32 max_time_auto; + __be32 max_time_auto; }; /* @@ -174,15 +174,15 @@ static inline u64 str_to_u64(const char *str) /* Register save area header. */ struct fadump_reg_save_area_header { - u64 magic_number; - u32 version; - u32 num_cpu_offset; + __be64 magic_number; + __be32 version; + __be32 num_cpu_offset; }; /* Register entry. */ struct fadump_reg_entry { - u64 reg_id; - u64 reg_value; + __be64 reg_id; + __be64 reg_value; }; /* fadump crash info structure */ diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 4ca90a39d6d0..725247beebec 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -159,8 +159,6 @@ struct pci_dn { int pci_ext_config_space; /* for pci devices */ - bool force_32bit_msi; - struct pci_dev *pcidev; /* back-pointer to the pci device */ #ifdef CONFIG_EEH struct eeh_dev *edev; /* eeh device */ diff --git a/arch/powerpc/include/asm/pgalloc.h b/arch/powerpc/include/asm/pgalloc.h index e9a9f60e596d..fc3ee06eab87 100644 --- a/arch/powerpc/include/asm/pgalloc.h +++ b/arch/powerpc/include/asm/pgalloc.h @@ -3,7 +3,6 @@ #ifdef __KERNEL__ #include <linux/mm.h> -#include <asm-generic/tlb.h> #ifdef CONFIG_PPC_BOOK3E extern void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address); @@ -14,6 +13,8 @@ static inline void tlb_flush_pgtable(struct mmu_gather *tlb, } #endif /* !CONFIG_PPC_BOOK3E */ +extern void tlb_remove_table(struct mmu_gather *tlb, void *table); + #ifdef CONFIG_PPC64 #include <asm/pgalloc-64.h> #else diff --git a/arch/powerpc/include/asm/tlb.h b/arch/powerpc/include/asm/tlb.h index e2b428b0f7ba..20733fa518ae 100644 --- a/arch/powerpc/include/asm/tlb.h +++ b/arch/powerpc/include/asm/tlb.h @@ -27,6 +27,7 @@ #define tlb_start_vma(tlb, vma) do { } while (0) #define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry __tlb_remove_tlb_entry extern void tlb_flush(struct mmu_gather *tlb); diff --git a/arch/powerpc/kernel/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c index f19b1e5cb060..1ceecdda810b 100644 --- a/arch/powerpc/kernel/eeh_sysfs.c +++ b/arch/powerpc/kernel/eeh_sysfs.c @@ -65,7 +65,7 @@ static ssize_t eeh_pe_state_show(struct device *dev, return -ENODEV; state = eeh_ops->get_state(edev->pe, NULL); - return sprintf(buf, "%0x08x %0x08x\n", + return sprintf(buf, "0x%08x 0x%08x\n", state, edev->pe->state); } diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 5bbd1bc8c3b0..0905c8da90f1 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -659,7 +659,13 @@ _GLOBAL(ret_from_except_lite) 3: #endif bl save_nvgprs + /* + * Use a non volatile GPR to save and restore our thread_info flags + * across the call to restore_interrupts. + */ + mr r30,r4 bl restore_interrupts + mr r4,r30 addi r3,r1,STACK_FRAME_OVERHEAD bl do_notify_resume b ret_from_except diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 742694c1d852..26d091a1a54c 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -58,7 +58,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, const __be32 *sections; int i, num_sections; int size; - const int *token; + const __be32 *token; if (depth != 1 || strcmp(uname, "rtas") != 0) return 0; @@ -72,7 +72,7 @@ int __init early_init_dt_scan_fw_dump(unsigned long node, return 1; fw_dump.fadump_supported = 1; - fw_dump.ibm_configure_kernel_dump = *token; + fw_dump.ibm_configure_kernel_dump = be32_to_cpu(*token); /* * The 'ibm,kernel-dump' rtas node is present only if there is @@ -147,11 +147,11 @@ static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm, memset(fdm, 0, sizeof(struct fadump_mem_struct)); addr = addr & PAGE_MASK; - fdm->header.dump_format_version = 0x00000001; - fdm->header.dump_num_sections = 3; + fdm->header.dump_format_version = cpu_to_be32(0x00000001); + fdm->header.dump_num_sections = cpu_to_be16(3); fdm->header.dump_status_flag = 0; fdm->header.offset_first_dump_section = - (u32)offsetof(struct fadump_mem_struct, cpu_state_data); + cpu_to_be32((u32)offsetof(struct fadump_mem_struct, cpu_state_data)); /* * Fields for disk dump option. @@ -167,27 +167,27 @@ static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm, /* Kernel dump sections */ /* cpu state data section. */ - fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG; - fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA; + fdm->cpu_state_data.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG); + fdm->cpu_state_data.source_data_type = cpu_to_be16(FADUMP_CPU_STATE_DATA); fdm->cpu_state_data.source_address = 0; - fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size; - fdm->cpu_state_data.destination_address = addr; + fdm->cpu_state_data.source_len = cpu_to_be64(fw_dump.cpu_state_data_size); + fdm->cpu_state_data.destination_address = cpu_to_be64(addr); addr += fw_dump.cpu_state_data_size; /* hpte region section */ - fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG; - fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION; + fdm->hpte_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG); + fdm->hpte_region.source_data_type = cpu_to_be16(FADUMP_HPTE_REGION); fdm->hpte_region.source_address = 0; - fdm->hpte_region.source_len = fw_dump.hpte_region_size; - fdm->hpte_region.destination_address = addr; + fdm->hpte_region.source_len = cpu_to_be64(fw_dump.hpte_region_size); + fdm->hpte_region.destination_address = cpu_to_be64(addr); addr += fw_dump.hpte_region_size; /* RMA region section */ - fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG; - fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION; - fdm->rmr_region.source_address = RMA_START; - fdm->rmr_region.source_len = fw_dump.boot_memory_size; - fdm->rmr_region.destination_address = addr; + fdm->rmr_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG); + fdm->rmr_region.source_data_type = cpu_to_be16(FADUMP_REAL_MODE_REGION); + fdm->rmr_region.source_address = cpu_to_be64(RMA_START); + fdm->rmr_region.source_len = cpu_to_be64(fw_dump.boot_memory_size); + fdm->rmr_region.destination_address = cpu_to_be64(addr); addr += fw_dump.boot_memory_size; return addr; @@ -272,7 +272,7 @@ int __init fadump_reserve_mem(void) * first kernel. */ if (fdm_active) - fw_dump.boot_memory_size = fdm_active->rmr_region.source_len; + fw_dump.boot_memory_size = be64_to_cpu(fdm_active->rmr_region.source_len); else fw_dump.boot_memory_size = fadump_calculate_reserve_size(); @@ -314,8 +314,8 @@ int __init fadump_reserve_mem(void) (unsigned long)(base >> 20)); fw_dump.fadumphdr_addr = - fdm_active->rmr_region.destination_address + - fdm_active->rmr_region.source_len; + be64_to_cpu(fdm_active->rmr_region.destination_address) + + be64_to_cpu(fdm_active->rmr_region.source_len); pr_debug("fadumphdr_addr = %p\n", (void *) fw_dump.fadumphdr_addr); } else { @@ -472,9 +472,9 @@ fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs) { memset(regs, 0, sizeof(struct pt_regs)); - while (reg_entry->reg_id != REG_ID("CPUEND")) { - fadump_set_regval(regs, reg_entry->reg_id, - reg_entry->reg_value); + while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) { + fadump_set_regval(regs, be64_to_cpu(reg_entry->reg_id), + be64_to_cpu(reg_entry->reg_value)); reg_entry++; } reg_entry++; @@ -603,20 +603,20 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm) if (!fdm->cpu_state_data.bytes_dumped) return -EINVAL; - addr = fdm->cpu_state_data.destination_address; + addr = be64_to_cpu(fdm->cpu_state_data.destination_address); vaddr = __va(addr); reg_header = vaddr; - if (reg_header->magic_number != REGSAVE_AREA_MAGIC) { + if (be64_to_cpu(reg_header->magic_number) != REGSAVE_AREA_MAGIC) { printk(KERN_ERR "Unable to read register save area.\n"); return -ENOENT; } pr_debug("--------CPU State Data------------\n"); - pr_debug("Magic Number: %llx\n", reg_header->magic_number); - pr_debug("NumCpuOffset: %x\n", reg_header->num_cpu_offset); + pr_debug("Magic Number: %llx\n", be64_to_cpu(reg_header->magic_number)); + pr_debug("NumCpuOffset: %x\n", be32_to_cpu(reg_header->num_cpu_offset)); - vaddr += reg_header->num_cpu_offset; - num_cpus = *((u32 *)(vaddr)); + vaddr += be32_to_cpu(reg_header->num_cpu_offset); + num_cpus = be32_to_cpu(*((__be32 *)(vaddr))); pr_debug("NumCpus : %u\n", num_cpus); vaddr += sizeof(u32); reg_entry = (struct fadump_reg_entry *)vaddr; @@ -639,13 +639,13 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm) fdh = __va(fw_dump.fadumphdr_addr); for (i = 0; i < num_cpus; i++) { - if (reg_entry->reg_id != REG_ID("CPUSTRT")) { + if (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUSTRT")) { printk(KERN_ERR "Unable to read CPU state data\n"); rc = -ENOENT; goto error_out; } /* Lower 4 bytes of reg_value contains logical cpu id */ - cpu = reg_entry->reg_value & FADUMP_CPU_ID_MASK; + cpu = be64_to_cpu(reg_entry->reg_value) & FADUMP_CPU_ID_MASK; if (fdh && !cpumask_test_cpu(cpu, &fdh->cpu_online_mask)) { SKIP_TO_NEXT_CPU(reg_entry); continue; @@ -692,7 +692,7 @@ static int __init process_fadump(const struct fadump_mem_struct *fdm_active) return -EINVAL; /* Check if the dump data is valid. */ - if ((fdm_active->header.dump_status_flag == FADUMP_ERROR_FLAG) || + if ((be16_to_cpu(fdm_active->header.dump_status_flag) == FADUMP_ERROR_FLAG) || (fdm_active->cpu_state_data.error_flags != 0) || (fdm_active->rmr_region.error_flags != 0)) { printk(KERN_ERR "Dump taken by platform is not valid\n"); @@ -828,7 +828,7 @@ static void fadump_setup_crash_memory_ranges(void) static inline unsigned long fadump_relocate(unsigned long paddr) { if (paddr > RMA_START && paddr < fw_dump.boot_memory_size) - return fdm.rmr_region.destination_address + paddr; + return be64_to_cpu(fdm.rmr_region.destination_address) + paddr; else return paddr; } @@ -902,7 +902,7 @@ static int fadump_create_elfcore_headers(char *bufp) * to the specified destination_address. Hence set * the correct offset. */ - phdr->p_offset = fdm.rmr_region.destination_address; + phdr->p_offset = be64_to_cpu(fdm.rmr_region.destination_address); } phdr->p_paddr = mbase; @@ -951,7 +951,7 @@ static void register_fadump(void) fadump_setup_crash_memory_ranges(); - addr = fdm.rmr_region.destination_address + fdm.rmr_region.source_len; + addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len); /* Initialize fadump crash info header. */ addr = init_fadump_header(addr); vaddr = __va(addr); @@ -1023,7 +1023,7 @@ void fadump_cleanup(void) /* Invalidate the registration only if dump is active. */ if (fw_dump.dump_active) { init_fadump_mem_struct(&fdm, - fdm_active->cpu_state_data.destination_address); + be64_to_cpu(fdm_active->cpu_state_data.destination_address)); fadump_invalidate_dump(&fdm); } } @@ -1063,7 +1063,7 @@ static void fadump_invalidate_release_mem(void) return; } - destination_address = fdm_active->cpu_state_data.destination_address; + destination_address = be64_to_cpu(fdm_active->cpu_state_data.destination_address); fadump_cleanup(); mutex_unlock(&fadump_mutex); @@ -1183,31 +1183,31 @@ static int fadump_region_show(struct seq_file *m, void *private) seq_printf(m, "CPU : [%#016llx-%#016llx] %#llx bytes, " "Dumped: %#llx\n", - fdm_ptr->cpu_state_data.destination_address, - fdm_ptr->cpu_state_data.destination_address + - fdm_ptr->cpu_state_data.source_len - 1, - fdm_ptr->cpu_state_data.source_len, - fdm_ptr->cpu_state_data.bytes_dumped); + be64_to_cpu(fdm_ptr->cpu_state_data.destination_address), + be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) + + be64_to_cpu(fdm_ptr->cpu_state_data.source_len) - 1, + be64_to_cpu(fdm_ptr->cpu_state_data.source_len), + be64_to_cpu(fdm_ptr->cpu_state_data.bytes_dumped)); seq_printf(m, "HPTE: [%#016llx-%#016llx] %#llx bytes, " "Dumped: %#llx\n", - fdm_ptr->hpte_region.destination_address, - fdm_ptr->hpte_region.destination_address + - fdm_ptr->hpte_region.source_len - 1, - fdm_ptr->hpte_region.source_len, - fdm_ptr->hpte_region.bytes_dumped); + be64_to_cpu(fdm_ptr->hpte_region.destination_address), + be64_to_cpu(fdm_ptr->hpte_region.destination_address) + + be64_to_cpu(fdm_ptr->hpte_region.source_len) - 1, + be64_to_cpu(fdm_ptr->hpte_region.source_len), + be64_to_cpu(fdm_ptr->hpte_region.bytes_dumped)); seq_printf(m, "DUMP: [%#016llx-%#016llx] %#llx bytes, " "Dumped: %#llx\n", - fdm_ptr->rmr_region.destination_address, - fdm_ptr->rmr_region.destination_address + - fdm_ptr->rmr_region.source_len - 1, - fdm_ptr->rmr_region.source_len, - fdm_ptr->rmr_region.bytes_dumped); + be64_to_cpu(fdm_ptr->rmr_region.destination_address), + be64_to_cpu(fdm_ptr->rmr_region.destination_address) + + be64_to_cpu(fdm_ptr->rmr_region.source_len) - 1, + be64_to_cpu(fdm_ptr->rmr_region.source_len), + be64_to_cpu(fdm_ptr->rmr_region.bytes_dumped)); if (!fdm_active || (fw_dump.reserve_dump_area_start == - fdm_ptr->cpu_state_data.destination_address)) + be64_to_cpu(fdm_ptr->cpu_state_data.destination_address))) goto out; /* Dump is active. Show reserved memory region. */ @@ -1215,10 +1215,10 @@ static int fadump_region_show(struct seq_file *m, void *private) " : [%#016llx-%#016llx] %#llx bytes, " "Dumped: %#llx\n", (unsigned long long)fw_dump.reserve_dump_area_start, - fdm_ptr->cpu_state_data.destination_address - 1, - fdm_ptr->cpu_state_data.destination_address - + be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) - 1, + be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) - fw_dump.reserve_dump_area_start, - fdm_ptr->cpu_state_data.destination_address - + be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) - fw_dump.reserve_dump_area_start); out: if (fdm_active) diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 155013da27e0..b15194e2c5fc 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -266,13 +266,3 @@ int pcibus_to_node(struct pci_bus *bus) } EXPORT_SYMBOL(pcibus_to_node); #endif - -static void quirk_radeon_32bit_msi(struct pci_dev *dev) -{ - struct pci_dn *pdn = pci_get_pdn(dev); - - if (pdn) - pdn->force_32bit_msi = true; -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon_32bit_msi); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon_32bit_msi); diff --git a/arch/powerpc/kernel/vdso32/getcpu.S b/arch/powerpc/kernel/vdso32/getcpu.S index 23eb9a9441bd..c62be60c7274 100644 --- a/arch/powerpc/kernel/vdso32/getcpu.S +++ b/arch/powerpc/kernel/vdso32/getcpu.S @@ -30,8 +30,8 @@ V_FUNCTION_BEGIN(__kernel_getcpu) .cfi_startproc mfspr r5,SPRN_SPRG_VDSO_READ - cmpdi cr0,r3,0 - cmpdi cr1,r4,0 + cmpwi cr0,r3,0 + cmpwi cr1,r4,0 clrlwi r6,r5,16 rlwinm r7,r5,16,31-15,31-0 beq cr0,1f diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 7e70ae968e5f..6a4a5fcb9730 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -517,8 +517,6 @@ static void free_hugepd_range(struct mmu_gather *tlb, hugepd_t *hpdp, int pdshif for (i = 0; i < num_hugepd; i++, hpdp++) hpdp->pd = 0; - tlb->need_flush = 1; - #ifdef CONFIG_PPC_FSL_BOOK3E hugepd_free(tlb, hugepte); #else diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index cad68ff8eca5..415a51b028b9 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c @@ -103,7 +103,7 @@ unsigned long __max_low_memory = MAX_LOW_MEM; /* * Check for command-line options that affect what MMU_init will do. */ -void MMU_setup(void) +void __init MMU_setup(void) { /* Check for nobats option (used in mapin_ram). */ if (strstr(boot_command_line, "nobats")) { diff --git a/arch/powerpc/platforms/powernv/opal-hmi.c b/arch/powerpc/platforms/powernv/opal-hmi.c index 5e1ed1575aab..b322bfb51343 100644 --- a/arch/powerpc/platforms/powernv/opal-hmi.c +++ b/arch/powerpc/platforms/powernv/opal-hmi.c @@ -57,7 +57,7 @@ static void print_hmi_event_info(struct OpalHMIEvent *hmi_evt) }; /* Print things out */ - if (hmi_evt->version != OpalHMIEvt_V1) { + if (hmi_evt->version < OpalHMIEvt_V1) { pr_err("HMI Interrupt, Unknown event version %d !\n", hmi_evt->version); return; diff --git a/arch/powerpc/platforms/powernv/opal-lpc.c b/arch/powerpc/platforms/powernv/opal-lpc.c index ad4b31df779a..e4169d68cb32 100644 --- a/arch/powerpc/platforms/powernv/opal-lpc.c +++ b/arch/powerpc/platforms/powernv/opal-lpc.c @@ -216,14 +216,54 @@ static ssize_t lpc_debug_read(struct file *filp, char __user *ubuf, &data, len); if (rc) return -ENXIO; + + /* + * Now there is some trickery with the data returned by OPAL + * as it's the desired data right justified in a 32-bit BE + * word. + * + * This is a very bad interface and I'm to blame for it :-( + * + * So we can't just apply a 32-bit swap to what comes from OPAL, + * because user space expects the *bytes* to be in their proper + * respective positions (ie, LPC position). + * + * So what we really want to do here is to shift data right + * appropriately on a LE kernel. + * + * IE. If the LPC transaction has bytes B0, B1, B2 and B3 in that + * order, we have in memory written to by OPAL at the "data" + * pointer: + * + * Bytes: OPAL "data" LE "data" + * 32-bit: B0 B1 B2 B3 B0B1B2B3 B3B2B1B0 + * 16-bit: B0 B1 0000B0B1 B1B00000 + * 8-bit: B0 000000B0 B0000000 + * + * So a BE kernel will have the leftmost of the above in the MSB + * and rightmost in the LSB and can just then "cast" the u32 "data" + * down to the appropriate quantity and write it. + * + * However, an LE kernel can't. It doesn't need to swap because a + * load from data followed by a store to user are going to preserve + * the byte ordering which is the wire byte order which is what the + * user wants, but in order to "crop" to the right size, we need to + * shift right first. + */ switch(len) { case 4: rc = __put_user((u32)data, (u32 __user *)ubuf); break; case 2: +#ifdef __LITTLE_ENDIAN__ + data >>= 16; +#endif rc = __put_user((u16)data, (u16 __user *)ubuf); break; default: +#ifdef __LITTLE_ENDIAN__ + data >>= 24; +#endif rc = __put_user((u8)data, (u8 __user *)ubuf); break; } @@ -263,12 +303,31 @@ static ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf, else if (todo > 1 && (pos & 1) == 0) len = 2; } + + /* + * Similarly to the read case, we have some trickery here but + * it's different to handle. We need to pass the value to OPAL in + * a register whose layout depends on the access size. We want + * to reproduce the memory layout of the user, however we aren't + * doing a load from user and a store to another memory location + * which would achieve that. Here we pass the value to OPAL via + * a register which is expected to contain the "BE" interpretation + * of the byte sequence. IE: for a 32-bit access, byte 0 should be + * in the MSB. So here we *do* need to byteswap on LE. + * + * User bytes: LE "data" OPAL "data" + * 32-bit: B0 B1 B2 B3 B3B2B1B0 B0B1B2B3 + * 16-bit: B0 B1 0000B1B0 0000B0B1 + * 8-bit: B0 000000B0 000000B0 + */ switch(len) { case 4: rc = __get_user(data, (u32 __user *)ubuf); + data = cpu_to_be32(data); break; case 2: rc = __get_user(data, (u16 __user *)ubuf); + data = cpu_to_be16(data); break; default: rc = __get_user(data, (u8 __user *)ubuf); diff --git a/arch/powerpc/platforms/powernv/opal-sensor.c b/arch/powerpc/platforms/powernv/opal-sensor.c index 10271ad1fac4..4ab67ef7abc9 100644 --- a/arch/powerpc/platforms/powernv/opal-sensor.c +++ b/arch/powerpc/platforms/powernv/opal-sensor.c @@ -20,7 +20,9 @@ #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/of_platform.h> #include <asm/opal.h> +#include <asm/machdep.h> static DEFINE_MUTEX(opal_sensor_mutex); @@ -64,3 +66,21 @@ out: return ret; } EXPORT_SYMBOL_GPL(opal_get_sensor_data); + +static __init int opal_sensor_init(void) +{ + struct platform_device *pdev; + struct device_node *sensor; + + sensor = of_find_node_by_path("/ibm,opal/sensors"); + if (!sensor) { + pr_err("Opal node 'sensors' not found\n"); + return -ENODEV; + } + + pdev = of_platform_device_create(sensor, "opal-sensor", NULL); + of_node_put(sensor); + + return PTR_ERR_OR_ZERO(pdev); +} +machine_subsys_initcall(powernv, opal_sensor_init); diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 468a0f23c7f2..3ba435ec3dcd 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1509,7 +1509,6 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, unsigned int is_64, struct msi_msg *msg) { struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev); - struct pci_dn *pdn = pci_get_pdn(dev); unsigned int xive_num = hwirq - phb->msi_base; __be32 data; int rc; @@ -1523,7 +1522,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, return -ENXIO; /* Force 32-bit MSI on some broken devices */ - if (pdn && pdn->force_32bit_msi) + if (dev->no_64bit_msi) is_64 = 0; /* Assign XIVE to PE */ @@ -1997,7 +1996,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np, if (is_kdump_kernel()) { pr_info(" Issue PHB reset ...\n"); ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL); - ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET); + ioda_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE); } /* Configure M64 window */ diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index b2187d0068b8..4b20f2c6b3b2 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -50,7 +50,6 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) { struct pci_controller *hose = pci_bus_to_host(pdev->bus); struct pnv_phb *phb = hose->private_data; - struct pci_dn *pdn = pci_get_pdn(pdev); struct msi_desc *entry; struct msi_msg msg; int hwirq; @@ -60,7 +59,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (WARN_ON(!phb) || !phb->msi_bmp.bitmap) return -ENODEV; - if (pdn && pdn->force_32bit_msi && !phb->msi32_support) + if (pdev->no_64bit_msi && !phb->msi32_support) return -ENODEV; list_for_each_entry(entry, &pdev->msi_list, list) { diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 6ad83bd11fe2..c22bb1b4beb8 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -382,7 +382,7 @@ static int dlpar_online_cpu(struct device_node *dn) BUG_ON(get_cpu_current_state(cpu) != CPU_STATE_OFFLINE); cpu_maps_update_done(); - rc = cpu_up(cpu); + rc = device_online(get_cpu_device(cpu)); if (rc) goto out; cpu_maps_update_begin(); @@ -467,7 +467,7 @@ static int dlpar_offline_cpu(struct device_node *dn) if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); cpu_maps_update_done(); - rc = cpu_down(cpu); + rc = device_offline(get_cpu_device(cpu)); if (rc) goto out; cpu_maps_update_begin(); diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 8c509d5397c6..f6880d2a40fb 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -43,6 +43,7 @@ #include <asm/trace.h> #include <asm/firmware.h> #include <asm/plpar_wrappers.h> +#include <asm/fadump.h> #include "pseries.h" @@ -247,8 +248,17 @@ static void pSeries_lpar_hptab_clear(void) } #ifdef __LITTLE_ENDIAN__ - /* Reset exceptions to big endian */ - if (firmware_has_feature(FW_FEATURE_SET_MODE)) { + /* + * Reset exceptions to big endian. + * + * FIXME this is a hack for kexec, we need to reset the exception + * endian before starting the new kernel and this is a convenient place + * to do it. + * + * This is also called on boot when a fadump happens. In that case we + * must not change the exception endian mode. + */ + if (firmware_has_feature(FW_FEATURE_SET_MODE) && !is_fadump_active()) { long rc; rc = pseries_big_endian_exceptions(); diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 8ab5add4ac82..8b909e94fd9a 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -420,7 +420,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) */ again: if (type == PCI_CAP_ID_MSI) { - if (pdn->force_32bit_msi) { + if (pdev->no_64bit_msi) { rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); if (rc < 0) { /* diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index de40b48b460e..da08ed088157 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -361,7 +361,7 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev, cascade_data->virq = virt_msir; msi->cascade_array[irq_index] = cascade_data; - ret = request_irq(virt_msir, fsl_msi_cascade, 0, + ret = request_irq(virt_msir, fsl_msi_cascade, IRQF_NO_THREAD, "fsl-msi-cascade", cascade_data); if (ret) { dev_err(&dev->dev, "failed to request_irq(%d), ret = %d\n", diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index b988b5addf86..c8efbb37d6e0 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -293,10 +293,10 @@ static inline void disable_surveillance(void) args.token = rtas_token("set-indicator"); if (args.token == RTAS_UNKNOWN_SERVICE) return; - args.nargs = 3; - args.nret = 1; + args.nargs = cpu_to_be32(3); + args.nret = cpu_to_be32(1); args.rets = &args.args[3]; - args.args[0] = SURVEILLANCE_TOKEN; + args.args[0] = cpu_to_be32(SURVEILLANCE_TOKEN); args.args[1] = 0; args.args[2] = 0; enter_rtas(__pa(&args)); diff --git a/arch/s390/configs/default_defconfig b/arch/s390/configs/default_defconfig index 9d94fdd9f525..9432d0f202ef 100644 --- a/arch/s390/configs/default_defconfig +++ b/arch/s390/configs/default_defconfig @@ -35,7 +35,6 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_THROTTLING=y CONFIG_PARTITION_ADVANCED=y CONFIG_IBM_PARTITION=y @@ -245,6 +244,7 @@ CONFIG_NF_TABLES_IPV4=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NF_NAT_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -252,11 +252,6 @@ CONFIG_IP_NF_MATCH_RPFILTER=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_ECN=m @@ -270,6 +265,7 @@ CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NF_TABLES_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NF_NAT_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -286,9 +282,6 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_SECURITY=m -CONFIG_NF_NAT_IPV6=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m -CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m CONFIG_NET_SCTPPROBE=m CONFIG_RDS=m @@ -374,14 +367,13 @@ CONFIG_BLK_DEV_SR=m CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_ENCLOSURE=m -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_SAS_LIBSAS=m CONFIG_SCSI_SRP_ATTRS=m CONFIG_ISCSI_TCP=m -CONFIG_LIBFCOE=m CONFIG_SCSI_DEBUG=m CONFIG_ZFCP=y CONFIG_SCSI_VIRTIO=m @@ -427,7 +419,6 @@ CONFIG_VIRTIO_NET=m CONFIG_NLMON=m CONFIG_VHOST_NET=m # CONFIG_NET_VENDOR_ARC is not set -# CONFIG_NET_CADENCE is not set # CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set @@ -481,14 +472,14 @@ CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y CONFIG_JFS_SECURITY=y CONFIG_JFS_STATISTICS=y -CONFIG_XFS_FS=m +CONFIG_XFS_FS=y CONFIG_XFS_QUOTA=y CONFIG_XFS_POSIX_ACL=y CONFIG_XFS_RT=y CONFIG_XFS_DEBUG=y CONFIG_GFS2_FS=m CONFIG_OCFS2_FS=m -CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_FANOTIFY=y @@ -574,7 +565,6 @@ CONFIG_DEBUG_SHIRQ=y CONFIG_DETECT_HUNG_TASK=y CONFIG_TIMER_STATS=y CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_RT_MUTEX_TESTER=y CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y CONFIG_PROVE_LOCKING=y CONFIG_LOCK_STAT=y @@ -600,8 +590,13 @@ CONFIG_FAULT_INJECTION_DEBUG_FS=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_LATENCYTOP=y CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_SCHED_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_STACK_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y -# CONFIG_KPROBE_EVENT is not set +CONFIG_UPROBE_EVENT=y CONFIG_LKDTM=m CONFIG_TEST_LIST_SORT=y CONFIG_KPROBES_SANITY_TEST=y @@ -609,7 +604,10 @@ CONFIG_RBTREE_TEST=y CONFIG_INTERVAL_TREE_TEST=m CONFIG_PERCPU_TEST=m CONFIG_ATOMIC64_SELFTEST=y +CONFIG_TEST_STRING_HELPERS=y +CONFIG_TEST_KSTRTOX=y CONFIG_DMA_API_DEBUG=y +CONFIG_TEST_BPF=m # CONFIG_STRICT_DEVMEM is not set CONFIG_S390_PTDUMP=y CONFIG_ENCRYPTED_KEYS=m @@ -673,12 +671,6 @@ CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m CONFIG_X509_CERTIFICATE_PARSER=m CONFIG_CRC7=m CONFIG_CRC8=m -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_CORDIC=m CONFIG_CMM=m CONFIG_APPLDATA_BASE=y diff --git a/arch/s390/configs/gcov_defconfig b/arch/s390/configs/gcov_defconfig index 90f514baa37d..219dca6ea926 100644 --- a/arch/s390/configs/gcov_defconfig +++ b/arch/s390/configs/gcov_defconfig @@ -35,7 +35,6 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_THROTTLING=y CONFIG_PARTITION_ADVANCED=y CONFIG_IBM_PARTITION=y @@ -243,6 +242,7 @@ CONFIG_NF_TABLES_IPV4=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NF_NAT_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -250,11 +250,6 @@ CONFIG_IP_NF_MATCH_RPFILTER=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_ECN=m @@ -268,6 +263,7 @@ CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NF_TABLES_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NF_NAT_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -284,9 +280,6 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_SECURITY=m -CONFIG_NF_NAT_IPV6=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m -CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m CONFIG_NET_SCTPPROBE=m CONFIG_RDS=m @@ -371,14 +364,13 @@ CONFIG_BLK_DEV_SR=m CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_ENCLOSURE=m -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_SAS_LIBSAS=m CONFIG_SCSI_SRP_ATTRS=m CONFIG_ISCSI_TCP=m -CONFIG_LIBFCOE=m CONFIG_SCSI_DEBUG=m CONFIG_ZFCP=y CONFIG_SCSI_VIRTIO=m @@ -424,7 +416,6 @@ CONFIG_VIRTIO_NET=m CONFIG_NLMON=m CONFIG_VHOST_NET=m # CONFIG_NET_VENDOR_ARC is not set -# CONFIG_NET_CADENCE is not set # CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set @@ -478,13 +469,13 @@ CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y CONFIG_JFS_SECURITY=y CONFIG_JFS_STATISTICS=y -CONFIG_XFS_FS=m +CONFIG_XFS_FS=y CONFIG_XFS_QUOTA=y CONFIG_XFS_POSIX_ACL=y CONFIG_XFS_RT=y CONFIG_GFS2_FS=m CONFIG_OCFS2_FS=m -CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_FANOTIFY=y @@ -626,12 +617,6 @@ CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m CONFIG_X509_CERTIFICATE_PARSER=m CONFIG_CRC7=m CONFIG_CRC8=m -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_CORDIC=m CONFIG_CMM=m CONFIG_APPLDATA_BASE=y diff --git a/arch/s390/configs/performance_defconfig b/arch/s390/configs/performance_defconfig index 13559d32af69..822c2f2e0c25 100644 --- a/arch/s390/configs/performance_defconfig +++ b/arch/s390/configs/performance_defconfig @@ -33,7 +33,6 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_BLK_DEV_INTEGRITY=y CONFIG_BLK_DEV_THROTTLING=y CONFIG_PARTITION_ADVANCED=y CONFIG_IBM_PARTITION=y @@ -241,6 +240,7 @@ CONFIG_NF_TABLES_IPV4=m CONFIG_NFT_CHAIN_ROUTE_IPV4=m CONFIG_NFT_CHAIN_NAT_IPV4=m CONFIG_NF_TABLES_ARP=m +CONFIG_NF_NAT_IPV4=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_AH=m CONFIG_IP_NF_MATCH_ECN=m @@ -248,11 +248,6 @@ CONFIG_IP_NF_MATCH_RPFILTER=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_NF_NAT_IPV4=m -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_CLUSTERIP=m CONFIG_IP_NF_TARGET_ECN=m @@ -266,6 +261,7 @@ CONFIG_NF_CONNTRACK_IPV6=m CONFIG_NF_TABLES_IPV6=m CONFIG_NFT_CHAIN_ROUTE_IPV6=m CONFIG_NFT_CHAIN_NAT_IPV6=m +CONFIG_NF_NAT_IPV6=m CONFIG_IP6_NF_IPTABLES=m CONFIG_IP6_NF_MATCH_AH=m CONFIG_IP6_NF_MATCH_EUI64=m @@ -282,9 +278,6 @@ CONFIG_IP6_NF_TARGET_REJECT=m CONFIG_IP6_NF_MANGLE=m CONFIG_IP6_NF_RAW=m CONFIG_IP6_NF_SECURITY=m -CONFIG_NF_NAT_IPV6=m -CONFIG_IP6_NF_TARGET_MASQUERADE=m -CONFIG_IP6_NF_TARGET_NPT=m CONFIG_NF_TABLES_BRIDGE=m CONFIG_NET_SCTPPROBE=m CONFIG_RDS=m @@ -369,14 +362,13 @@ CONFIG_BLK_DEV_SR=m CONFIG_CHR_DEV_SG=y CONFIG_CHR_DEV_SCH=m CONFIG_SCSI_ENCLOSURE=m -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SPI_ATTRS=m +CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_SAS_LIBSAS=m CONFIG_SCSI_SRP_ATTRS=m CONFIG_ISCSI_TCP=m -CONFIG_LIBFCOE=m CONFIG_SCSI_DEBUG=m CONFIG_ZFCP=y CONFIG_SCSI_VIRTIO=m @@ -422,7 +414,6 @@ CONFIG_VIRTIO_NET=m CONFIG_NLMON=m CONFIG_VHOST_NET=m # CONFIG_NET_VENDOR_ARC is not set -# CONFIG_NET_CADENCE is not set # CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set @@ -476,13 +467,13 @@ CONFIG_JFS_FS=m CONFIG_JFS_POSIX_ACL=y CONFIG_JFS_SECURITY=y CONFIG_JFS_STATISTICS=y -CONFIG_XFS_FS=m +CONFIG_XFS_FS=y CONFIG_XFS_QUOTA=y CONFIG_XFS_POSIX_ACL=y CONFIG_XFS_RT=y CONFIG_GFS2_FS=m CONFIG_OCFS2_FS=m -CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_FANOTIFY=y @@ -550,8 +541,11 @@ CONFIG_TIMER_STATS=y CONFIG_RCU_TORTURE_TEST=m CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_LATENCYTOP=y +CONFIG_SCHED_TRACER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_STACK_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y -# CONFIG_KPROBE_EVENT is not set +CONFIG_UPROBE_EVENT=y CONFIG_LKDTM=m CONFIG_PERCPU_TEST=m CONFIG_ATOMIC64_SELFTEST=y @@ -618,12 +612,6 @@ CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m CONFIG_X509_CERTIFICATE_PARSER=m CONFIG_CRC7=m CONFIG_CRC8=m -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y CONFIG_CORDIC=m CONFIG_CMM=m CONFIG_APPLDATA_BASE=y diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index e376789f2d8d..9d63051ebec4 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -22,8 +22,8 @@ CONFIG_HZ_100=y CONFIG_CRASH_DUMP=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set # CONFIG_SECCOMP is not set -# CONFIG_IUCV is not set CONFIG_NET=y +# CONFIG_IUCV is not set CONFIG_ATM=y CONFIG_ATM_LANE=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" @@ -36,9 +36,9 @@ CONFIG_ENCLOSURE_SERVICES=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SCSI_ENCLOSURE=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_FC_ATTRS=y CONFIG_SCSI_SRP_ATTRS=y CONFIG_ZFCP=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set @@ -75,12 +75,6 @@ CONFIG_DEBUG_KERNEL=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 # CONFIG_FTRACE is not set # CONFIG_STRICT_DEVMEM is not set -CONFIG_XZ_DEC_X86=y -CONFIG_XZ_DEC_POWERPC=y -CONFIG_XZ_DEC_IA64=y -CONFIG_XZ_DEC_ARM=y -CONFIG_XZ_DEC_ARMTHUMB=y -CONFIG_XZ_DEC_SPARC=y # CONFIG_PFAULT is not set # CONFIG_S390_HYPFS_FS is not set # CONFIG_VIRTUALIZATION is not set diff --git a/arch/s390/defconfig b/arch/s390/defconfig index fab35a8efa4f..785c5f24d6f9 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -92,10 +92,10 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_MULTI_LUN=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_LOGGING=y CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_FC_ATTRS=y CONFIG_ZFCP=y CONFIG_SCSI_VIRTIO=y CONFIG_NETDEVICES=y @@ -164,14 +164,13 @@ CONFIG_CRYPTO_CMAC=m CONFIG_CRYPTO_XCBC=m CONFIG_CRYPTO_VMAC=m CONFIG_CRYPTO_CRC32=m -CONFIG_CRYPTO_CRCT10DIF=m CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_RMD128=m CONFIG_CRYPTO_RMD160=m CONFIG_CRYPTO_RMD256=m CONFIG_CRYPTO_RMD320=m -CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_TGR192=m CONFIG_CRYPTO_WP512=m diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 51d14fe5eb9a..ca1cabb3a96c 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -121,6 +121,8 @@ unsigned long __kprobes prepare_ftrace_return(unsigned long parent, { struct ftrace_graph_ent trace; + if (unlikely(ftrace_graph_is_dead())) + goto out; if (unlikely(atomic_read(¤t->tracing_graph_pause))) goto out; ip = (ip & PSW_ADDR_INSN) - MCOUNT_INSN_SIZE; diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index dd1c24ceda50..3f51cf4e8f02 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -54,12 +54,8 @@ void s390_handle_mcck(void) */ local_irq_save(flags); local_mcck_disable(); - /* - * Ummm... Does this make sense at all? Copying the percpu struct - * and then zapping it one statement later? - */ - memcpy(&mcck, this_cpu_ptr(&cpu_mcck), sizeof(mcck)); - memset(&mcck, 0, sizeof(struct mcck_struct)); + mcck = *this_cpu_ptr(&cpu_mcck); + memset(this_cpu_ptr(&cpu_mcck), 0, sizeof(mcck)); clear_cpu_flag(CIF_MCCK_PENDING); local_mcck_enable(); local_irq_restore(flags); diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S index 48c2206a3956..5eec9afbb5b5 100644 --- a/arch/s390/kernel/vdso32/clock_gettime.S +++ b/arch/s390/kernel/vdso32/clock_gettime.S @@ -19,6 +19,7 @@ .type __kernel_clock_gettime,@function __kernel_clock_gettime: .cfi_startproc + ahi %r15,-16 basr %r5,0 0: al %r5,21f-0b(%r5) /* get &_vdso_data */ chi %r2,__CLOCK_REALTIME_COARSE @@ -34,8 +35,8 @@ __kernel_clock_gettime: 1: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */ tml %r4,0x0001 /* pending update ? loop */ jnz 1b - stcke 24(%r15) /* Store TOD clock */ - lm %r0,%r1,25(%r15) + stcke 0(%r15) /* Store TOD clock */ + lm %r0,%r1,1(%r15) s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,2f @@ -70,6 +71,7 @@ __kernel_clock_gettime: 8: st %r2,0(%r3) /* store tp->tv_sec */ st %r1,4(%r3) /* store tp->tv_nsec */ lhi %r2,0 + ahi %r15,16 br %r14 /* CLOCK_MONOTONIC_COARSE */ @@ -96,8 +98,8 @@ __kernel_clock_gettime: 11: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */ tml %r4,0x0001 /* pending update ? loop */ jnz 11b - stcke 24(%r15) /* Store TOD clock */ - lm %r0,%r1,25(%r15) + stcke 0(%r15) /* Store TOD clock */ + lm %r0,%r1,1(%r15) s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,12f @@ -132,11 +134,13 @@ __kernel_clock_gettime: 17: st %r2,0(%r3) /* store tp->tv_sec */ st %r1,4(%r3) /* store tp->tv_nsec */ lhi %r2,0 + ahi %r15,16 br %r14 /* Fallback to system call */ 19: lhi %r1,__NR_clock_gettime svc 0 + ahi %r15,16 br %r14 20: .long 1000000000 diff --git a/arch/s390/kernel/vdso32/gettimeofday.S b/arch/s390/kernel/vdso32/gettimeofday.S index 60def5f562db..719de6186b20 100644 --- a/arch/s390/kernel/vdso32/gettimeofday.S +++ b/arch/s390/kernel/vdso32/gettimeofday.S @@ -19,6 +19,7 @@ .type __kernel_gettimeofday,@function __kernel_gettimeofday: .cfi_startproc + ahi %r15,-16 basr %r5,0 0: al %r5,13f-0b(%r5) /* get &_vdso_data */ 1: ltr %r3,%r3 /* check if tz is NULL */ @@ -29,30 +30,30 @@ __kernel_gettimeofday: l %r4,__VDSO_UPD_COUNT+4(%r5) /* load update counter */ tml %r4,0x0001 /* pending update ? loop */ jnz 1b - stcke 24(%r15) /* Store TOD clock */ - lm %r0,%r1,25(%r15) + stcke 0(%r15) /* Store TOD clock */ + lm %r0,%r1,1(%r15) s %r0,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,3f ahi %r0,-1 3: ms %r0,__VDSO_TK_MULT(%r5) /* * tk->mult */ - st %r0,24(%r15) + st %r0,0(%r15) l %r0,__VDSO_TK_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 4f a %r0,__VDSO_TK_MULT(%r5) -4: al %r0,24(%r15) +4: al %r0,0(%r15) al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ al %r1,__VDSO_XTIME_NSEC+4(%r5) brc 12,5f ahi %r0,1 -5: mvc 24(4,%r15),__VDSO_XTIME_SEC+4(%r5) +5: mvc 0(4,%r15),__VDSO_XTIME_SEC+4(%r5) cl %r4,__VDSO_UPD_COUNT+4(%r5) /* check update counter */ jne 1b l %r4,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ srdl %r0,0(%r4) /* >> tk->shift */ - l %r4,24(%r15) /* get tv_sec from stack */ + l %r4,0(%r15) /* get tv_sec from stack */ basr %r5,0 6: ltr %r0,%r0 jnz 7f @@ -71,6 +72,7 @@ __kernel_gettimeofday: 9: srl %r0,6 st %r0,4(%r2) /* store tv->tv_usec */ 10: slr %r2,%r2 + ahi %r15,16 br %r14 11: .long 1000000000 12: .long 274877907 diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S index 9d9761f8e110..7699e735ae28 100644 --- a/arch/s390/kernel/vdso64/clock_gettime.S +++ b/arch/s390/kernel/vdso64/clock_gettime.S @@ -19,6 +19,7 @@ .type __kernel_clock_gettime,@function __kernel_clock_gettime: .cfi_startproc + aghi %r15,-16 larl %r5,_vdso_data cghi %r2,__CLOCK_REALTIME_COARSE je 4f @@ -37,10 +38,10 @@ __kernel_clock_gettime: 0: lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */ tmll %r4,0x0001 /* pending update ? loop */ jnz 0b - stcke 48(%r15) /* Store TOD clock */ + stcke 0(%r15) /* Store TOD clock */ lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ lg %r0,__VDSO_WTOM_SEC(%r5) - lg %r1,49(%r15) + lg %r1,1(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ alg %r1,__VDSO_WTOM_NSEC(%r5) @@ -56,6 +57,7 @@ __kernel_clock_gettime: 2: stg %r0,0(%r3) /* store tp->tv_sec */ stg %r1,8(%r3) /* store tp->tv_nsec */ lghi %r2,0 + aghi %r15,16 br %r14 /* CLOCK_MONOTONIC_COARSE */ @@ -82,9 +84,9 @@ __kernel_clock_gettime: 5: lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */ tmll %r4,0x0001 /* pending update ? loop */ jnz 5b - stcke 48(%r15) /* Store TOD clock */ + stcke 0(%r15) /* Store TOD clock */ lgf %r2,__VDSO_TK_SHIFT(%r5) /* Timekeeper shift */ - lg %r1,49(%r15) + lg %r1,1(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ @@ -101,6 +103,7 @@ __kernel_clock_gettime: 7: stg %r0,0(%r3) /* store tp->tv_sec */ stg %r1,8(%r3) /* store tp->tv_nsec */ lghi %r2,0 + aghi %r15,16 br %r14 /* CLOCK_THREAD_CPUTIME_ID for this thread */ @@ -134,11 +137,13 @@ __kernel_clock_gettime: slgr %r4,%r0 /* r4 = tv_nsec */ stg %r4,8(%r3) lghi %r2,0 + aghi %r15,16 br %r14 /* Fallback to system call */ 12: lghi %r1,__NR_clock_gettime svc 0 + aghi %r15,16 br %r14 13: .quad 1000000000 diff --git a/arch/s390/kernel/vdso64/gettimeofday.S b/arch/s390/kernel/vdso64/gettimeofday.S index 7a344995a97f..6ce46707663c 100644 --- a/arch/s390/kernel/vdso64/gettimeofday.S +++ b/arch/s390/kernel/vdso64/gettimeofday.S @@ -19,6 +19,7 @@ .type __kernel_gettimeofday,@function __kernel_gettimeofday: .cfi_startproc + aghi %r15,-16 larl %r5,_vdso_data 0: ltgr %r3,%r3 /* check if tz is NULL */ je 1f @@ -28,8 +29,8 @@ __kernel_gettimeofday: lg %r4,__VDSO_UPD_COUNT(%r5) /* load update counter */ tmll %r4,0x0001 /* pending update ? loop */ jnz 0b - stcke 48(%r15) /* Store TOD clock */ - lg %r1,49(%r15) + stcke 0(%r15) /* Store TOD clock */ + lg %r1,1(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ msgf %r1,__VDSO_TK_MULT(%r5) /* * tk->mult */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + tk->xtime_nsec */ @@ -50,6 +51,7 @@ __kernel_gettimeofday: srlg %r0,%r0,6 stg %r0,8(%r2) /* store tv->tv_usec */ 4: lghi %r2,0 + aghi %r15,16 br %r14 5: .quad 1000000000 .long 274877907 diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 416f2a323ba5..7f0089d9a4aa 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -66,7 +66,11 @@ static int do_account_vtime(struct task_struct *tsk, int hardirq_offset) clock = S390_lowcore.last_update_clock; asm volatile( " stpt %0\n" /* Store current cpu timer value */ +#ifdef CONFIG_HAVE_MARCH_Z9_109_FEATURES + " stckf %1" /* Store current tod clock value */ +#else " stck %1" /* Store current tod clock value */ +#endif : "=m" (S390_lowcore.last_update_timer), "=m" (S390_lowcore.last_update_clock)); S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 765c1776ec9f..0e69b7e7a439 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -22,7 +22,7 @@ int atomic_add_return(int, atomic_t *); int atomic_cmpxchg(atomic_t *, int, int); -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +int atomic_xchg(atomic_t *, int); int __atomic_add_unless(atomic_t *, int, int); void atomic_set(atomic_t *, int); diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h index 32c29a133f9d..d38b52dca216 100644 --- a/arch/sparc/include/asm/cmpxchg_32.h +++ b/arch/sparc/include/asm/cmpxchg_32.h @@ -11,22 +11,14 @@ #ifndef __ARCH_SPARC_CMPXCHG__ #define __ARCH_SPARC_CMPXCHG__ -static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) -{ - __asm__ __volatile__("swap [%2], %0" - : "=&r" (val) - : "0" (val), "r" (m) - : "memory"); - return val; -} - +unsigned long __xchg_u32(volatile u32 *m, u32 new); void __xchg_called_with_bad_pointer(void); static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) { switch (size) { case 4: - return xchg_u32(ptr, x); + return __xchg_u32(ptr, x); } __xchg_called_with_bad_pointer(); return x; diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 5b1b52a04ad6..7e064c68c5ec 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -12,6 +12,14 @@ int dma_supported(struct device *dev, u64 mask); #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) +static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction dir) +{ + /* Since dma_{alloc,free}_noncoherent() allocated coherent memory, this + * routine can be a nop. + */ +} + extern struct dma_map_ops *dma_ops; extern struct dma_map_ops *leon_dma_ops; extern struct dma_map_ops pci32_dma_ops; diff --git a/arch/sparc/include/uapi/asm/swab.h b/arch/sparc/include/uapi/asm/swab.h index a34ad079487e..4c7c12d69bea 100644 --- a/arch/sparc/include/uapi/asm/swab.h +++ b/arch/sparc/include/uapi/asm/swab.h @@ -9,9 +9,9 @@ static inline __u16 __arch_swab16p(const __u16 *addr) { __u16 ret; - __asm__ __volatile__ ("lduha [%1] %2, %0" + __asm__ __volatile__ ("lduha [%2] %3, %0" : "=r" (ret) - : "r" (addr), "i" (ASI_PL)); + : "m" (*addr), "r" (addr), "i" (ASI_PL)); return ret; } #define __arch_swab16p __arch_swab16p @@ -20,9 +20,9 @@ static inline __u32 __arch_swab32p(const __u32 *addr) { __u32 ret; - __asm__ __volatile__ ("lduwa [%1] %2, %0" + __asm__ __volatile__ ("lduwa [%2] %3, %0" : "=r" (ret) - : "r" (addr), "i" (ASI_PL)); + : "m" (*addr), "r" (addr), "i" (ASI_PL)); return ret; } #define __arch_swab32p __arch_swab32p @@ -31,9 +31,9 @@ static inline __u64 __arch_swab64p(const __u64 *addr) { __u64 ret; - __asm__ __volatile__ ("ldxa [%1] %2, %0" + __asm__ __volatile__ ("ldxa [%2] %3, %0" : "=r" (ret) - : "r" (addr), "i" (ASI_PL)); + : "m" (*addr), "r" (addr), "i" (ASI_PL)); return ret; } #define __arch_swab64p __arch_swab64p diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index 8f76f23dac38..f9c6813c132d 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -581,7 +581,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) { unsigned long csr_reg, csr, csr_error_bits; irqreturn_t ret = IRQ_NONE; - u16 stat; + u32 stat; csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL; csr = upa_readq(csr_reg); @@ -617,7 +617,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) pbm->name); ret = IRQ_HANDLED; } - pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat); + pbm->pci_ops->read(pbm->pci_bus, 0, PCI_STATUS, 2, &stat); if (stat & (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_TARGET_ABORT | @@ -625,7 +625,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) PCI_STATUS_SIG_SYSTEM_ERROR)) { printk("%s: PCI bus error, PCI_STATUS[%04x]\n", pbm->name, stat); - pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff); + pbm->pci_ops->write(pbm->pci_bus, 0, PCI_STATUS, 2, 0xffff); ret = IRQ_HANDLED; } return ret; diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 302c476413d5..da6f1a7fc4db 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -816,13 +816,17 @@ void arch_send_call_function_single_ipi(int cpu) void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs) { clear_softint(1 << irq); + irq_enter(); generic_smp_call_function_interrupt(); + irq_exit(); } void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs) { clear_softint(1 << irq); + irq_enter(); generic_smp_call_function_single_interrupt(); + irq_exit(); } static void tsb_sync(void *info) diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index a7c418ac26af..71cd65ab200c 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -45,6 +45,19 @@ ATOMIC_OP(add, +=) #undef ATOMIC_OP +int atomic_xchg(atomic_t *v, int new) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(ATOMIC_HASH(v), flags); + ret = v->counter; + v->counter = new; + spin_unlock_irqrestore(ATOMIC_HASH(v), flags); + return ret; +} +EXPORT_SYMBOL(atomic_xchg); + int atomic_cmpxchg(atomic_t *v, int old, int new) { int ret; @@ -137,3 +150,17 @@ unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new) return (unsigned long)prev; } EXPORT_SYMBOL(__cmpxchg_u32); + +unsigned long __xchg_u32(volatile u32 *ptr, u32 new) +{ + unsigned long flags; + u32 prev; + + spin_lock_irqsave(ATOMIC_HASH(ptr), flags); + prev = *ptr; + *ptr = new; + spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags); + + return (unsigned long)prev; +} +EXPORT_SYMBOL(__xchg_u32); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ded8a6774ac9..41a503c15862 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -144,7 +144,7 @@ config INSTRUCTION_DECODER config PERF_EVENTS_INTEL_UNCORE def_bool y - depends on PERF_EVENTS && SUP_SUP_INTEL && PCI + depends on PERF_EVENTS && CPU_SUP_INTEL && PCI config OUTPUT_FORMAT string diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 704f58aa79cd..45abc363dd3e 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -76,8 +76,10 @@ suffix-$(CONFIG_KERNEL_XZ) := xz suffix-$(CONFIG_KERNEL_LZO) := lzo suffix-$(CONFIG_KERNEL_LZ4) := lz4 +RUN_SIZE = $(shell $(OBJDUMP) -h vmlinux | \ + perl $(srctree)/arch/x86/tools/calc_run_size.pl) quiet_cmd_mkpiggy = MKPIGGY $@ - cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false ) + cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false ) targets += piggy.S $(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S index cbed1407a5cd..1d7fbbcc196d 100644 --- a/arch/x86/boot/compressed/head_32.S +++ b/arch/x86/boot/compressed/head_32.S @@ -207,7 +207,8 @@ relocated: * Do the decompression, and jump to the new kernel.. */ /* push arguments for decompress_kernel: */ - pushl $z_output_len /* decompressed length */ + pushl $z_run_size /* size of kernel with .bss and .brk */ + pushl $z_output_len /* decompressed length, end of relocs */ leal z_extract_offset_negative(%ebx), %ebp pushl %ebp /* output address */ pushl $z_input_len /* input_len */ @@ -217,7 +218,7 @@ relocated: pushl %eax /* heap area */ pushl %esi /* real mode pointer */ call decompress_kernel /* returns kernel location in %eax */ - addl $24, %esp + addl $28, %esp /* * Jump to the decompressed kernel. diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 2884e0c3e8a5..6b1766c6c082 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -402,13 +402,16 @@ relocated: * Do the decompression, and jump to the new kernel.. */ pushq %rsi /* Save the real mode argument */ + movq $z_run_size, %r9 /* size of kernel with .bss and .brk */ + pushq %r9 movq %rsi, %rdi /* real mode address */ leaq boot_heap(%rip), %rsi /* malloc area for uncompression */ leaq input_data(%rip), %rdx /* input_data */ movl $z_input_len, %ecx /* input_len */ movq %rbp, %r8 /* output target address */ - movq $z_output_len, %r9 /* decompressed length */ + movq $z_output_len, %r9 /* decompressed length, end of relocs */ call decompress_kernel /* returns kernel location in %rax */ + popq %r9 popq %rsi /* diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 57ab74df7eea..30dd59a9f0b4 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -358,7 +358,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, unsigned char *input_data, unsigned long input_len, unsigned char *output, - unsigned long output_len) + unsigned long output_len, + unsigned long run_size) { real_mode = rmode; @@ -381,8 +382,14 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, free_mem_ptr = heap; /* Heap */ free_mem_end_ptr = heap + BOOT_HEAP_SIZE; - output = choose_kernel_location(input_data, input_len, - output, output_len); + /* + * The memory hole needed for the kernel is the larger of either + * the entire decompressed kernel plus relocation table, or the + * entire decompressed kernel plus .bss and .brk sections. + */ + output = choose_kernel_location(input_data, input_len, output, + output_len > run_size ? output_len + : run_size); /* Validate memory location choices. */ if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c index b669ab65bf6c..d8222f213182 100644 --- a/arch/x86/boot/compressed/mkpiggy.c +++ b/arch/x86/boot/compressed/mkpiggy.c @@ -36,11 +36,13 @@ int main(int argc, char *argv[]) uint32_t olen; long ilen; unsigned long offs; + unsigned long run_size; FILE *f = NULL; int retval = 1; - if (argc < 2) { - fprintf(stderr, "Usage: %s compressed_file\n", argv[0]); + if (argc < 3) { + fprintf(stderr, "Usage: %s compressed_file run_size\n", + argv[0]); goto bail; } @@ -74,6 +76,7 @@ int main(int argc, char *argv[]) offs += olen >> 12; /* Add 8 bytes for each 32K block */ offs += 64*1024 + 128; /* Add 64K + 128 bytes slack */ offs = (offs+4095) & ~4095; /* Round to a 4K boundary */ + run_size = atoi(argv[2]); printf(".section \".rodata..compressed\",\"a\",@progbits\n"); printf(".globl z_input_len\n"); @@ -85,6 +88,8 @@ int main(int argc, char *argv[]) /* z_extract_offset_negative allows simplification of head_32.S */ printf(".globl z_extract_offset_negative\n"); printf("z_extract_offset_negative = -0x%lx\n", offs); + printf(".globl z_run_size\n"); + printf("z_run_size = %lu\n", run_size); printf(".globl input_data, input_data_end\n"); printf("input_data:\n"); diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h index f48b17df4224..3a52ee0e726d 100644 --- a/arch/x86/include/asm/page_32_types.h +++ b/arch/x86/include/asm/page_32_types.h @@ -20,7 +20,6 @@ #define THREAD_SIZE_ORDER 1 #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) -#define STACKFAULT_STACK 0 #define DOUBLEFAULT_STACK 1 #define NMI_STACK 0 #define DEBUG_STACK 0 diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h index 678205195ae1..75450b2c7be4 100644 --- a/arch/x86/include/asm/page_64_types.h +++ b/arch/x86/include/asm/page_64_types.h @@ -14,12 +14,11 @@ #define IRQ_STACK_ORDER 2 #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER) -#define STACKFAULT_STACK 1 -#define DOUBLEFAULT_STACK 2 -#define NMI_STACK 3 -#define DEBUG_STACK 4 -#define MCE_STACK 5 -#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ +#define DOUBLEFAULT_STACK 1 +#define NMI_STACK 2 +#define DEBUG_STACK 3 +#define MCE_STACK 4 +#define N_EXCEPTION_STACKS 4 /* hw limit: 7 */ #define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) #define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index 8cd27e08e23c..8cd1cc3bc835 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -150,6 +150,7 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask) } void cpu_disable_common(void); +void cpu_die_common(unsigned int cpu); void native_smp_prepare_boot_cpu(void); void native_smp_prepare_cpus(unsigned int max_cpus); void native_smp_cpus_done(unsigned int max_cpus); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 854053889d4d..547e344a6dc6 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -141,7 +141,7 @@ struct thread_info { /* Only used for 64 bit */ #define _TIF_DO_NOTIFY_MASK \ (_TIF_SIGPENDING | _TIF_MCE_NOTIFY | _TIF_NOTIFY_RESUME | \ - _TIF_USER_RETURN_NOTIFY) + _TIF_USER_RETURN_NOTIFY | _TIF_UPROBE) /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW \ diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index bc8352e7010a..707adc6549d8 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -39,6 +39,7 @@ asmlinkage void simd_coprocessor_error(void); #ifdef CONFIG_TRACING asmlinkage void trace_page_fault(void); +#define trace_stack_segment stack_segment #define trace_divide_error divide_error #define trace_bounds bounds #define trace_invalid_op invalid_op diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index f04dbb3069b8..5caed1dd7ccf 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -21,6 +21,7 @@ const struct pci_device_id amd_nb_misc_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, {} @@ -30,6 +31,7 @@ EXPORT_SYMBOL(amd_nb_misc_ids); static const struct pci_device_id amd_nb_link_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) }, {} diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 4b4f78c9ba19..cfa9b5b2c27a 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -146,6 +146,8 @@ EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); static int __init x86_xsave_setup(char *s) { + if (strlen(s)) + return 0; setup_clear_cpu_cap(X86_FEATURE_XSAVE); setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); setup_clear_cpu_cap(X86_FEATURE_XSAVES); diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index 7aa1acc79789..06674473b0e6 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c @@ -108,12 +108,13 @@ static size_t compute_container_size(u8 *data, u32 total_size) * load_microcode_amd() to save equivalent cpu table and microcode patches in * kernel heap memory. */ -static void apply_ucode_in_initrd(void *ucode, size_t size) +static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch) { struct equiv_cpu_entry *eq; size_t *cont_sz; u32 *header; u8 *data, **cont; + u8 (*patch)[PATCH_MAX_SIZE]; u16 eq_id = 0; int offset, left; u32 rev, eax, ebx, ecx, edx; @@ -123,10 +124,12 @@ static void apply_ucode_in_initrd(void *ucode, size_t size) new_rev = (u32 *)__pa_nodebug(&ucode_new_rev); cont_sz = (size_t *)__pa_nodebug(&container_size); cont = (u8 **)__pa_nodebug(&container); + patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); #else new_rev = &ucode_new_rev; cont_sz = &container_size; cont = &container; + patch = &amd_ucode_patch; #endif data = ucode; @@ -213,9 +216,9 @@ static void apply_ucode_in_initrd(void *ucode, size_t size) rev = mc->hdr.patch_id; *new_rev = rev; - /* save ucode patch */ - memcpy(amd_ucode_patch, mc, - min_t(u32, header[1], PATCH_MAX_SIZE)); + if (save_patch) + memcpy(patch, mc, + min_t(u32, header[1], PATCH_MAX_SIZE)); } } @@ -246,7 +249,7 @@ void __init load_ucode_amd_bsp(void) *data = cp.data; *size = cp.size; - apply_ucode_in_initrd(cp.data, cp.size); + apply_ucode_in_initrd(cp.data, cp.size, true); } #ifdef CONFIG_X86_32 @@ -263,7 +266,7 @@ void load_ucode_amd_ap(void) size_t *usize; void **ucode; - mc = (struct microcode_amd *)__pa(amd_ucode_patch); + mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch); if (mc->hdr.patch_id && mc->hdr.processor_rev_id) { __apply_microcode_amd(mc); return; @@ -275,7 +278,7 @@ void load_ucode_amd_ap(void) if (!*ucode || !*usize) return; - apply_ucode_in_initrd(*ucode, *usize); + apply_ucode_in_initrd(*ucode, *usize, false); } static void __init collect_cpu_sig_on_bsp(void *arg) @@ -339,7 +342,7 @@ void load_ucode_amd_ap(void) * AP has a different equivalence ID than BSP, looks like * mixed-steppings silicon so go through the ucode blob anew. */ - apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size); + apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size, false); } } #endif @@ -347,7 +350,9 @@ void load_ucode_amd_ap(void) int __init save_microcode_in_initrd_amd(void) { unsigned long cont; + int retval = 0; enum ucode_state ret; + u8 *cont_va; u32 eax; if (!container) @@ -355,13 +360,15 @@ int __init save_microcode_in_initrd_amd(void) #ifdef CONFIG_X86_32 get_bsp_sig(); - cont = (unsigned long)container; + cont = (unsigned long)container; + cont_va = __va(container); #else /* * We need the physical address of the container for both bitness since * boot_params.hdr.ramdisk_image is a physical address. */ - cont = __pa(container); + cont = __pa(container); + cont_va = container; #endif /* @@ -372,6 +379,8 @@ int __init save_microcode_in_initrd_amd(void) if (relocated_ramdisk) container = (u8 *)(__va(relocated_ramdisk) + (cont - boot_params.hdr.ramdisk_image)); + else + container = cont_va; if (ucode_new_rev) pr_info("microcode: updated early to new patch_level=0x%08x\n", @@ -382,7 +391,7 @@ int __init save_microcode_in_initrd_amd(void) ret = load_microcode_amd(eax, container, container_size); if (ret != UCODE_OK) - return -EINVAL; + retval = -EINVAL; /* * This will be freed any msec now, stash patches for the current @@ -391,5 +400,5 @@ int __init save_microcode_in_initrd_amd(void) container = NULL; container_size = 0; - return 0; + return retval; } diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index dd9d6190b08d..08fe6e8a726e 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -465,6 +465,16 @@ static void mc_bp_resume(void) if (uci->valid && uci->mc) microcode_ops->apply_microcode(cpu); +#ifdef CONFIG_X86_64 + else if (!uci->mc) + /* + * We might resume and not have applied late microcode but still + * have a newer patch stashed from the early loader. We don't + * have it in uci->mc so we have to load it the same way we're + * applying patches early on the APs. + */ + load_ucode_ap(); +#endif } static struct syscore_ops mc_syscore_ops = { diff --git a/arch/x86/kernel/cpu/microcode/core_early.c b/arch/x86/kernel/cpu/microcode/core_early.c index 5f28a64e71ea..2c017f242a78 100644 --- a/arch/x86/kernel/cpu/microcode/core_early.c +++ b/arch/x86/kernel/cpu/microcode/core_early.c @@ -124,7 +124,7 @@ void __init load_ucode_bsp(void) static bool check_loader_disabled_ap(void) { #ifdef CONFIG_X86_32 - return __pa_nodebug(dis_ucode_ldr); + return *((bool *)__pa_nodebug(&dis_ucode_ldr)); #else return dis_ucode_ldr; #endif diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index adf138eac85c..f9ed429d6e4f 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -486,14 +486,17 @@ static struct attribute_group snbep_uncore_qpi_format_group = { .attrs = snbep_uncore_qpi_formats_attr, }; -#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ - .init_box = snbep_uncore_msr_init_box, \ +#define __SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ .disable_box = snbep_uncore_msr_disable_box, \ .enable_box = snbep_uncore_msr_enable_box, \ .disable_event = snbep_uncore_msr_disable_event, \ .enable_event = snbep_uncore_msr_enable_event, \ .read_counter = uncore_msr_read_counter +#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ + __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), \ + .init_box = snbep_uncore_msr_init_box \ + static struct intel_uncore_ops snbep_uncore_msr_ops = { SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), }; @@ -1919,6 +1922,30 @@ static struct intel_uncore_type hswep_uncore_cbox = { .format_group = &hswep_uncore_cbox_format_group, }; +/* + * Write SBOX Initialization register bit by bit to avoid spurious #GPs + */ +static void hswep_uncore_sbox_msr_init_box(struct intel_uncore_box *box) +{ + unsigned msr = uncore_msr_box_ctl(box); + + if (msr) { + u64 init = SNBEP_PMON_BOX_CTL_INT; + u64 flags = 0; + int i; + + for_each_set_bit(i, (unsigned long *)&init, 64) { + flags |= (1ULL << i); + wrmsrl(msr, flags); + } + } +} + +static struct intel_uncore_ops hswep_uncore_sbox_msr_ops = { + __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), + .init_box = hswep_uncore_sbox_msr_init_box +}; + static struct attribute *hswep_uncore_sbox_formats_attr[] = { &format_attr_event.attr, &format_attr_umask.attr, @@ -1944,7 +1971,7 @@ static struct intel_uncore_type hswep_uncore_sbox = { .event_mask = HSWEP_S_MSR_PMON_RAW_EVENT_MASK, .box_ctl = HSWEP_S0_MSR_PMON_BOX_CTL, .msr_offset = HSWEP_SBOX_MSR_OFFSET, - .ops = &snbep_uncore_msr_ops, + .ops = &hswep_uncore_sbox_msr_ops, .format_group = &hswep_uncore_sbox_format_group, }; @@ -2025,13 +2052,27 @@ static struct intel_uncore_type hswep_uncore_imc = { SNBEP_UNCORE_PCI_COMMON_INIT(), }; +static unsigned hswep_uncore_irp_ctrs[] = {0xa0, 0xa8, 0xb0, 0xb8}; + +static u64 hswep_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + u64 count = 0; + + pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx], (u32 *)&count); + pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1); + + return count; +} + static struct intel_uncore_ops hswep_uncore_irp_ops = { .init_box = snbep_uncore_pci_init_box, .disable_box = snbep_uncore_pci_disable_box, .enable_box = snbep_uncore_pci_enable_box, .disable_event = ivbep_uncore_irp_disable_event, .enable_event = ivbep_uncore_irp_enable_event, - .read_counter = ivbep_uncore_irp_read_counter, + .read_counter = hswep_uncore_irp_read_counter, }; static struct intel_uncore_type hswep_uncore_irp = { diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 1abcb50b48ae..ff86f19b5758 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c @@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = { [ DEBUG_STACK-1 ] = "#DB", [ NMI_STACK-1 ] = "NMI", [ DOUBLEFAULT_STACK-1 ] = "#DF", - [ STACKFAULT_STACK-1 ] = "#SS", [ MCE_STACK-1 ] = "#MC", #if DEBUG_STKSZ > EXCEPTION_STKSZ [ N_EXCEPTION_STACKS ... diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index df088bb03fb3..c0226ab54106 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S @@ -828,9 +828,15 @@ ENTRY(native_iret) jnz native_irq_return_ldt #endif +.global native_irq_return_iret native_irq_return_iret: + /* + * This may fault. Non-paranoid faults on return to userspace are + * handled by fixup_bad_iret. These include #SS, #GP, and #NP. + * Double-faults due to espfix64 are handled in do_double_fault. + * Other faults here are fatal. + */ iretq - _ASM_EXTABLE(native_irq_return_iret, bad_iret) #ifdef CONFIG_X86_ESPFIX64 native_irq_return_ldt: @@ -858,25 +864,6 @@ native_irq_return_ldt: jmp native_irq_return_iret #endif - .section .fixup,"ax" -bad_iret: - /* - * The iret traps when the %cs or %ss being restored is bogus. - * We've lost the original trap vector and error code. - * #GPF is the most likely one to get for an invalid selector. - * So pretend we completed the iret and took the #GPF in user mode. - * - * We are now running with the kernel GS after exception recovery. - * But error_entry expects us to have user GS to match the user %cs, - * so swap back. - */ - pushq $0 - - SWAPGS - jmp general_protection - - .previous - /* edi: workmask, edx: work */ retint_careful: CFI_RESTORE_STATE @@ -922,37 +909,6 @@ ENTRY(retint_kernel) CFI_ENDPROC END(common_interrupt) - /* - * If IRET takes a fault on the espfix stack, then we - * end up promoting it to a doublefault. In that case, - * modify the stack to make it look like we just entered - * the #GP handler from user space, similar to bad_iret. - */ -#ifdef CONFIG_X86_ESPFIX64 - ALIGN -__do_double_fault: - XCPT_FRAME 1 RDI+8 - movq RSP(%rdi),%rax /* Trap on the espfix stack? */ - sarq $PGDIR_SHIFT,%rax - cmpl $ESPFIX_PGD_ENTRY,%eax - jne do_double_fault /* No, just deliver the fault */ - cmpl $__KERNEL_CS,CS(%rdi) - jne do_double_fault - movq RIP(%rdi),%rax - cmpq $native_irq_return_iret,%rax - jne do_double_fault /* This shouldn't happen... */ - movq PER_CPU_VAR(kernel_stack),%rax - subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */ - movq %rax,RSP(%rdi) - movq $0,(%rax) /* Missing (lost) #GP error code */ - movq $general_protection,RIP(%rdi) - retq - CFI_ENDPROC -END(__do_double_fault) -#else -# define __do_double_fault do_double_fault -#endif - /* * APIC interrupts. */ @@ -1124,7 +1080,7 @@ idtentry overflow do_overflow has_error_code=0 idtentry bounds do_bounds has_error_code=0 idtentry invalid_op do_invalid_op has_error_code=0 idtentry device_not_available do_device_not_available has_error_code=0 -idtentry double_fault __do_double_fault has_error_code=1 paranoid=1 +idtentry double_fault do_double_fault has_error_code=1 paranoid=1 idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0 idtentry invalid_TSS do_invalid_TSS has_error_code=1 idtentry segment_not_present do_segment_not_present has_error_code=1 @@ -1289,7 +1245,7 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK -idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1 +idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN idtentry xen_debug do_debug has_error_code=0 idtentry xen_int3 do_int3 has_error_code=0 @@ -1399,17 +1355,16 @@ error_sti: /* * There are two places in the kernel that can potentially fault with - * usergs. Handle them here. The exception handlers after iret run with - * kernel gs again, so don't set the user space flag. B stepping K8s - * sometimes report an truncated RIP for IRET exceptions returning to - * compat mode. Check for these here too. + * usergs. Handle them here. B stepping K8s sometimes report a + * truncated RIP for IRET exceptions returning to compat mode. Check + * for these here too. */ error_kernelspace: CFI_REL_OFFSET rcx, RCX+8 incl %ebx leaq native_irq_return_iret(%rip),%rcx cmpq %rcx,RIP+8(%rsp) - je error_swapgs + je error_bad_iret movl %ecx,%eax /* zero extend */ cmpq %rax,RIP+8(%rsp) je bstep_iret @@ -1420,7 +1375,15 @@ error_kernelspace: bstep_iret: /* Fix truncated RIP */ movq %rcx,RIP+8(%rsp) - jmp error_swapgs + /* fall through */ + +error_bad_iret: + SWAPGS + mov %rsp,%rdi + call fixup_bad_iret + mov %rax,%rsp + decl %ebx /* Return to usergs */ + jmp error_sti CFI_ENDPROC END(error_entry) diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 749b0e423419..e510618b2e91 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -1484,7 +1484,7 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch) */ if (work & _TIF_NOHZ) { user_exit(); - work &= ~TIF_NOHZ; + work &= ~_TIF_NOHZ; } #ifdef CONFIG_SECCOMP diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 4d2128ac70bd..668d8f2a8781 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1303,10 +1303,14 @@ static void __ref remove_cpu_from_maps(int cpu) numa_remove_cpu(cpu); } +static DEFINE_PER_CPU(struct completion, die_complete); + void cpu_disable_common(void) { int cpu = smp_processor_id(); + init_completion(&per_cpu(die_complete, smp_processor_id())); + remove_siblinginfo(cpu); /* It's now safe to remove this processor from the online map */ @@ -1316,8 +1320,6 @@ void cpu_disable_common(void) fixup_irqs(); } -static DEFINE_PER_CPU(struct completion, die_complete); - int native_cpu_disable(void) { int ret; @@ -1327,16 +1329,21 @@ int native_cpu_disable(void) return ret; clear_local_APIC(); - init_completion(&per_cpu(die_complete, smp_processor_id())); cpu_disable_common(); return 0; } +void cpu_die_common(unsigned int cpu) +{ + wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ); +} + void native_cpu_die(unsigned int cpu) { /* We don't do anything here: idle task is faking death itself. */ - wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ); + + cpu_die_common(cpu); /* They ack this in play_dead() by setting CPU_DEAD */ if (per_cpu(cpu_state, cpu) == CPU_DEAD) { diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 0d0e922fafc1..de801f22128a 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -233,32 +233,40 @@ DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op) DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) -#ifdef CONFIG_X86_32 DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) -#endif DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check) #ifdef CONFIG_X86_64 /* Runs on IST stack */ -dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) -{ - enum ctx_state prev_state; - - prev_state = exception_enter(); - if (notify_die(DIE_TRAP, "stack segment", regs, error_code, - X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { - preempt_conditional_sti(regs); - do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); - preempt_conditional_cli(regs); - } - exception_exit(prev_state); -} - dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) { static const char str[] = "double fault"; struct task_struct *tsk = current; +#ifdef CONFIG_X86_ESPFIX64 + extern unsigned char native_irq_return_iret[]; + + /* + * If IRET takes a non-IST fault on the espfix64 stack, then we + * end up promoting it to a doublefault. In that case, modify + * the stack to make it look like we just entered the #GP + * handler from user space, similar to bad_iret. + */ + if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY && + regs->cs == __KERNEL_CS && + regs->ip == (unsigned long)native_irq_return_iret) + { + struct pt_regs *normal_regs = task_pt_regs(current); + + /* Fake a #GP(0) from userspace. */ + memmove(&normal_regs->ip, (void *)regs->sp, 5*8); + normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */ + regs->ip = (unsigned long)general_protection; + regs->sp = (unsigned long)&normal_regs->orig_ax; + return; + } +#endif + exception_enter(); /* Return not checked because double check cannot be ignored */ notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); @@ -399,6 +407,35 @@ asmlinkage __visible struct pt_regs *sync_regs(struct pt_regs *eregs) return regs; } NOKPROBE_SYMBOL(sync_regs); + +struct bad_iret_stack { + void *error_entry_ret; + struct pt_regs regs; +}; + +asmlinkage __visible +struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s) +{ + /* + * This is called from entry_64.S early in handling a fault + * caused by a bad iret to user mode. To handle the fault + * correctly, we want move our stack frame to task_pt_regs + * and we want to pretend that the exception came from the + * iret target. + */ + struct bad_iret_stack *new_stack = + container_of(task_pt_regs(current), + struct bad_iret_stack, regs); + + /* Copy the IRET target to the new stack. */ + memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8); + + /* Copy the remainder of the stack from the current stack. */ + memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip)); + + BUG_ON(!user_mode_vm(&new_stack->regs)); + return new_stack; +} #endif /* @@ -778,7 +815,7 @@ void __init trap_init(void) set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun); set_intr_gate(X86_TRAP_TS, invalid_TSS); set_intr_gate(X86_TRAP_NP, segment_not_present); - set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); + set_intr_gate(X86_TRAP_SS, stack_segment); set_intr_gate(X86_TRAP_GP, general_protection); set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug); set_intr_gate(X86_TRAP_MF, coprocessor_error); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5edf088ca51e..9f8a2faf5040 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -4287,6 +4287,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, fetch_register_operand(op); break; case OpCL: + op->type = OP_IMM; op->bytes = 1; op->val = reg_read(ctxt, VCPU_REGS_RCX) & 0xff; break; @@ -4294,6 +4295,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, rc = decode_imm(ctxt, op, 1, true); break; case OpOne: + op->type = OP_IMM; op->bytes = 1; op->val = 1; break; @@ -4352,21 +4354,27 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, ctxt->memop.bytes = ctxt->op_bytes + 2; goto mem_common; case OpES: + op->type = OP_IMM; op->val = VCPU_SREG_ES; break; case OpCS: + op->type = OP_IMM; op->val = VCPU_SREG_CS; break; case OpSS: + op->type = OP_IMM; op->val = VCPU_SREG_SS; break; case OpDS: + op->type = OP_IMM; op->val = VCPU_SREG_DS; break; case OpFS: + op->type = OP_IMM; op->val = VCPU_SREG_FS; break; case OpGS: + op->type = OP_IMM; op->val = VCPU_SREG_GS; break; case OpImplicit: diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index ac1c4de3a484..978f402006ee 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -630,7 +630,7 @@ static int mmu_spte_clear_track_bits(u64 *sptep) * kvm mmu, before reclaiming the page, we should * unmap it from mmu first. */ - WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn))); + WARN_ON(!kvm_is_reserved_pfn(pfn) && !page_count(pfn_to_page(pfn))); if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) kvm_set_pfn_accessed(pfn); @@ -2461,7 +2461,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, spte |= PT_PAGE_SIZE_MASK; if (tdp_enabled) spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, - kvm_is_mmio_pfn(pfn)); + kvm_is_reserved_pfn(pfn)); if (host_writable) spte |= SPTE_HOST_WRITEABLE; @@ -2737,7 +2737,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, * PT_PAGE_TABLE_LEVEL and there would be no adjustment done * here. */ - if (!is_error_noslot_pfn(pfn) && !kvm_is_mmio_pfn(pfn) && + if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) && level == PT_PAGE_TABLE_LEVEL && PageTransCompound(pfn_to_page(pfn)) && !has_wrprotected_page(vcpu->kvm, gfn, PT_DIRECTORY_LEVEL)) { diff --git a/arch/x86/lib/csum-wrappers_64.c b/arch/x86/lib/csum-wrappers_64.c index 7609e0e421ec..1318f75d56e4 100644 --- a/arch/x86/lib/csum-wrappers_64.c +++ b/arch/x86/lib/csum-wrappers_64.c @@ -41,9 +41,8 @@ csum_partial_copy_from_user(const void __user *src, void *dst, while (((unsigned long)src & 6) && len >= 2) { __u16 val16; - *errp = __get_user(val16, (const __u16 __user *)src); - if (*errp) - return isum; + if (__get_user(val16, (const __u16 __user *)src)) + goto out_err; *(__u16 *)dst = val16; isum = (__force __wsum)add32_with_carry( diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 4cb8763868fc..4e5dfec750fc 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1123,7 +1123,7 @@ void mark_rodata_ro(void) unsigned long end = (unsigned long) &__end_rodata_hpage_align; unsigned long text_end = PFN_ALIGN(&__stop___ex_table); unsigned long rodata_end = PFN_ALIGN(&__end_rodata); - unsigned long all_end = PFN_ALIGN(&_end); + unsigned long all_end; printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", (end - start) >> 10); @@ -1134,7 +1134,16 @@ void mark_rodata_ro(void) /* * The rodata/data/bss/brk section (but not the kernel text!) * should also be not-executable. + * + * We align all_end to PMD_SIZE because the existing mapping + * is a full PMD. If we would align _brk_end to PAGE_SIZE we + * split the PMD and the reminder between _brk_end and the end + * of the PMD will remain mapped executable. + * + * Any PMD which was setup after the one which covers _brk_end + * has been zapped already via cleanup_highmem(). */ + all_end = roundup((unsigned long)_brk_end, PMD_SIZE); set_memory_nx(rodata_start, (all_end - rodata_start) >> PAGE_SHIFT); rodata_test(); diff --git a/arch/x86/tools/calc_run_size.pl b/arch/x86/tools/calc_run_size.pl new file mode 100644 index 000000000000..23210baade2d --- /dev/null +++ b/arch/x86/tools/calc_run_size.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl +# +# Calculate the amount of space needed to run the kernel, including room for +# the .bss and .brk sections. +# +# Usage: +# objdump -h a.out | perl calc_run_size.pl +use strict; + +my $mem_size = 0; +my $file_offset = 0; + +my $sections=" *[0-9]+ \.(?:bss|brk) +"; +while (<>) { + if (/^$sections([0-9a-f]+) +(?:[0-9a-f]+ +){2}([0-9a-f]+)/) { + my $size = hex($1); + my $offset = hex($2); + $mem_size += $size; + if ($file_offset == 0) { + $file_offset = $offset; + } elsif ($file_offset != $offset) { + # BFD linker shows the same file offset in ELF. + # Gold linker shows them as consecutive. + next if ($file_offset + $mem_size == $offset + $size); + + printf STDERR "file_offset: 0x%lx\n", $file_offset; + printf STDERR "mem_size: 0x%lx\n", $mem_size; + printf STDERR "offset: 0x%lx\n", $offset; + printf STDERR "size: 0x%lx\n", $size; + + die ".bss and .brk are non-contiguous\n"; + } + } +} + +if ($file_offset == 0) { + die "Never found .bss or .brk file offset\n"; +} +printf("%d\n", $mem_size + $file_offset); diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 8650cdb53209..4c071aeb8417 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -510,6 +510,9 @@ static void xen_cpu_die(unsigned int cpu) current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ/10); } + + cpu_die_common(cpu); + xen_smp_intr_free(cpu); xen_uninit_lock_cpu(cpu); xen_teardown_timer(cpu); diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 49c6c3d94449..81f57e8c8f1b 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -319,8 +319,8 @@ config XTENSA_PLATFORM_S6105 config XTENSA_PLATFORM_XTFPGA bool "XTFPGA" + select ETHOC if ETHERNET select SERIAL_CONSOLE - select ETHOC select XTENSA_CALIBRATE_CCOUNT help XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605). @@ -367,7 +367,7 @@ config BUILTIN_DTB config BLK_DEV_SIMDISK tristate "Host file-based simulated block device support" default n - depends on XTENSA_PLATFORM_ISS + depends on XTENSA_PLATFORM_ISS && BLOCK help Create block devices that map to files in the host file system. Device binding to host file may be changed at runtime via proc diff --git a/arch/xtensa/boot/dts/lx200mx.dts b/arch/xtensa/boot/dts/lx200mx.dts new file mode 100644 index 000000000000..249822b99bd6 --- /dev/null +++ b/arch/xtensa/boot/dts/lx200mx.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/include/ "xtfpga.dtsi" +/include/ "xtfpga-flash-16m.dtsi" + +/ { + compatible = "cdns,xtensa-lx200"; + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x06000000>; + }; + pic: pic { + compatible = "cdns,xtensa-mx"; + #interrupt-cells = <2>; + interrupt-controller; + }; +}; diff --git a/arch/xtensa/configs/generic_kc705_defconfig b/arch/xtensa/configs/generic_kc705_defconfig new file mode 100644 index 000000000000..f4b7b3888da8 --- /dev/null +++ b/arch/xtensa/configs/generic_kc705_defconfig @@ -0,0 +1,131 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_FHANDLE=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_MEMCG=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_XTENSA_VARIANT_DC233C=y +CONFIG_XTENSA_UNALIGNED_USER=y +CONFIG_PREEMPT=y +CONFIG_HIGHMEM=y +# CONFIG_PCI is not set +CONFIG_XTENSA_PLATFORM_XTFPGA=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug" +CONFIG_USE_OF=y +CONFIG_BUILTIN_DTB="kc705" +# CONFIG_COMPACTION is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_MTD=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_MARVELL_PHY=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_HW_RANDOM=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_SOFT_WATCHDOG=y +# CONFIG_VGA_CONSOLE is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_FANOTIFY=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_NFS_SWAP=y +CONFIG_ROOT_NFS=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_STACKTRACE=y +CONFIG_RCU_TRACE=y +# CONFIG_FTRACE is not set +CONFIG_LD_NO_RELAX=y +# CONFIG_S32C1I_SELFTEST is not set +CONFIG_CRYPTO_ANSI_CPRNG=y diff --git a/arch/xtensa/configs/smp_lx200_defconfig b/arch/xtensa/configs/smp_lx200_defconfig new file mode 100644 index 000000000000..22eeacba37cc --- /dev/null +++ b/arch/xtensa/configs/smp_lx200_defconfig @@ -0,0 +1,135 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_FHANDLE=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +CONFIG_MEMCG=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_XTENSA_VARIANT_CUSTOM=y +CONFIG_XTENSA_VARIANT_CUSTOM_NAME="test_mmuhifi_c3" +CONFIG_XTENSA_UNALIGNED_USER=y +CONFIG_PREEMPT=y +CONFIG_HAVE_SMP=y +CONFIG_SMP=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX is not set +# CONFIG_PCI is not set +CONFIG_XTENSA_PLATFORM_XTFPGA=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug" +CONFIG_USE_OF=y +CONFIG_BUILTIN_DTB="lx200mx" +# CONFIG_COMPACTION is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +CONFIG_MTD=y +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_UBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_MARVELL_PHY=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_HW_RANDOM=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_SOFT_WATCHDOG=y +# CONFIG_VGA_CONSOLE is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_FANOTIFY=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_NFS_SWAP=y +CONFIG_ROOT_NFS=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_VM=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_STACKTRACE=y +CONFIG_RCU_TRACE=y +# CONFIG_FTRACE is not set +CONFIG_LD_NO_RELAX=y +# CONFIG_S32C1I_SELFTEST is not set +CONFIG_CRYPTO_ANSI_CPRNG=y diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h index b2173e5da601..0383aed59121 100644 --- a/arch/xtensa/include/asm/pgtable.h +++ b/arch/xtensa/include/asm/pgtable.h @@ -277,6 +277,8 @@ static inline pte_t pte_mkwrite(pte_t pte) static inline pte_t pte_mkspecial(pte_t pte) { return pte; } +#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) & ~_PAGE_CA_MASK)) + /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h index 8883fc877c5c..db5bb72e2f4e 100644 --- a/arch/xtensa/include/uapi/asm/unistd.h +++ b/arch/xtensa/include/uapi/asm/unistd.h @@ -384,7 +384,8 @@ __SYSCALL(174, sys_chroot, 1) #define __NR_pivot_root 175 __SYSCALL(175, sys_pivot_root, 2) #define __NR_umount 176 -__SYSCALL(176, sys_umount, 2) +__SYSCALL(176, sys_oldumount, 1) +#define __ARCH_WANT_SYS_OLDUMOUNT #define __NR_swapoff 177 __SYSCALL(177, sys_swapoff, 1) #define __NR_sync 178 @@ -742,7 +743,14 @@ __SYSCALL(335, sys_sched_getattr, 3) #define __NR_renameat2 336 __SYSCALL(336, sys_renameat2, 5) -#define __NR_syscall_count 337 +#define __NR_seccomp 337 +__SYSCALL(337, sys_seccomp, 3) +#define __NR_getrandom 338 +__SYSCALL(338, sys_getrandom, 3) +#define __NR_memfd_create 339 +__SYSCALL(339, sys_memfd_create, 2) + +#define __NR_syscall_count 340 /* * sysxtensa syscall handler |