diff options
Diffstat (limited to 'arch/arm')
77 files changed, 4781 insertions, 486 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9a9b1ca0886..00f04f64cbb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -56,6 +56,7 @@ config ARM select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND select MODULES_USE_ELF_REL select CLONE_BACKWARDS + select HAVE_MEMBLOCK_NODE_MAP help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and @@ -67,6 +68,9 @@ config ARM config ARM_HAS_SG_CHAIN bool +config ARM_RUNTIME_PATCH + bool + config NEED_SG_DMA_LENGTH bool @@ -197,6 +201,7 @@ config ARM_PATCH_PHYS_VIRT default y depends on !XIP_KERNEL && MMU depends on !ARCH_REALVIEW || !SPARSEMEM + select ARM_RUNTIME_PATCH help Patch phys-to-virt and virt-to-phys translation functions at boot and module load time according to the position of the @@ -216,6 +221,18 @@ config NEED_MACH_GPIO_H definitions for this platform. The need for mach/gpio.h should be avoided when possible. +config ARM_RUNTIME_PATCH_TEST + bool "Self test runtime patching mechanism" if ARM_RUNTIME_PATCH + default y + help + Select this to enable init time self checking for the runtime kernel + patching mechanism. This enables an ISA specific set of tests that + ensure that the instructions generated by the patch process are + consistent with those generated by the assembler at compile time. + + Only disable this option if you need to shrink the kernel to the + minimal size. + config NEED_MACH_IO_H bool help @@ -1163,8 +1180,48 @@ config ARM_TIMER_SP804 select CLKSRC_MMIO select HAVE_SCHED_CLOCK +config ARCH_FLATMEM_ENABLE + bool + depends on MMU + default y + +config ARCH_DISCONTIGMEM_ENABLE + bool + depends on MMU + default y + source arch/arm/mm/Kconfig +config NUMA + bool "NUMA Support (EXPERIMENTAL)" + depends on MMU && !FLATMEM && EXPERIMENTAL + help + Say Y to compile the kernel to support NUMA (Non-Uniform Memory + Access). At the moment, one has to specify the number of nodes using + the commandline: + numa=fake=x,[size0],[size1],...,[sizeN-1],[usetopology] + where x is the number of nodes, and sizeY is the size of node Y in + bytes (one can suffix m or g for megabytes or gigabytes). If no sizes + are specified, the memory is distributed roughly evenly between nodes. + If "usetopology" is specified, the "topology_physical_package_id" is + used to assign CPUs to nodes (so for instance on the TC2, the A7s are + grouped together in one node and the A15s are grouped together in + another node). + +config NODES_SHIFT + int "Maximum NUMA Nodes (as a power of 2)" if NUMA + range 1 10 + default "1" + depends on NEED_MULTIPLE_NODES + ---help--- + Specify the maximum number of NUMA Nodes available on the target + system. Increases memory reserved to accommodate various tables. + +config NUMA_ALLOC_NODES + bool + depends on DISCONTIGMEM || NUMA + default y + config ARM_NR_BANKS int default 16 if ARCH_EP93XX @@ -1869,6 +1926,14 @@ config HW_PERF_EVENTS Enable hardware performance counter support for perf events. If disabled, perf events will use software events only. +config SYS_SUPPORTS_HUGETLBFS + def_bool y + depends on ARM_LPAE || (!CPU_USE_DOMAINS && !MEMORY_FAILURE) + +config HAVE_ARCH_TRANSPARENT_HUGEPAGE + def_bool y + depends on SYS_SUPPORTS_HUGETLBFS + source "mm/Kconfig" config FORCE_MAX_ZONEORDER diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 6dbebeeb820..c043aea9340 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -44,6 +44,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \ exynos4210-trats.dtb \ exynos4412-smdk4412.dtb \ exynos5250-smdk5250.dtb \ + exynos5250-arndale.dtb \ exynos5250-snow.dtb \ exynos5440-ssdk5440.dtb dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \ diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts index f2710018e84..14bc7359e74 100644 --- a/arch/arm/boot/dts/exynos4210-origen.dts +++ b/arch/arm/boot/dts/exynos4210-origen.dts @@ -73,6 +73,209 @@ status = "okay"; }; + lcd_fimd0: lcd_panel0 { + compatible = "lcd-powercontrol"; + vcc-lcd-supply = <&buck7_reg>; + lcd-reset-gpio = <&gpe3 4 0>; + lcd-htiming = <64 16 48 1024>; + lcd-vtiming = <64 16 3 600>; + }; + + fimd@11C00000 { + samsung,fimd-display = <&lcd_fimd0>; + samsung,fimd-vidout-rgb; + samsung,fimd-inv-hsync; + samsung,fimd-inv-vsync; + samsung,fimd-inv-vclk; + samsung,fimd-frame-rate = <60>; + + samsung,power-domain = <&pd_lcd0>; + + pinctrl-0 = <&lcd0_sync &lcd0_clk &lcd0_en &lcd0_data &pwm0_out>; + pinctrl-names = "default"; + + window0 { + samsung,fimd-win-id = <0>; + samsung,fimd-win-bpp = <32 24>; + samsung,fimd-win-res = <1024 600>; + samsung,fimd-win-vres = <1024 600>; + }; + + window1 { + samsung,fimd-win-id = <1>; + samsung,fimd-win-bpp = <32 24>; + samsung,fimd-win-res = <1024 600>; + samsung,fimd-win-vres = <1024 600>; + }; + }; + + i2c@13860000 { + status = "okay"; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <20000>; + pinctrl-0 = <&i2c0_bus>; + pinctrl-names = "default"; + + max8997_pmic@66 { + compatible = "maxim,max8997-pmic"; + reg = <0x66>; + interrupt-parent = <&gpx0>; + interrupts = <4 0>, <3 0>; + + max8997,pmic-buck1-dvs-voltage = <1350000>; + max8997,pmic-buck2-dvs-voltage = <1100000>; + max8997,pmic-buck5-dvs-voltage = <1200000>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ABB_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo2_reg: LDO2 { + regulator-name = "VDD_ALIVE_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + ldo3_reg: LDO3 { + regulator-name = "VMIPI_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + ldo4_reg: LDO4 { + regulator-name = "VDD_RTC_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo6_reg: LDO6 { + regulator-name = "VMIPI_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo7_reg: LDO7 { + regulator-name = "VDD_AUD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo8_reg: LDO8 { + regulator-name = "VADC_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + ldo9_reg: LDO9 { + regulator-name = "DVDD_SWB_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + + ldo10_reg: LDO10 { + regulator-name = "VDD_PLL_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + ldo11_reg: LDO11 { + regulator-name = "VDD_AUD_3V"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + ldo14_reg: LDO14 { + regulator-name = "AVDD18_SWB_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo17_reg: LDO17 { + regulator-name = "VDD_SWB_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + ldo21_reg: LDO21 { + regulator-name = "VDD_MIF_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "VDD_ARM_1.2V"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "VDD_INT_1.1V"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + }; + + buck3_reg: BUCK3 { + regulator-name = "VDD_G3D_1.1V"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1100000>; + }; + + buck5_reg: BUCK5 { + regulator-name = "VDDQ_M1M2_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + buck7_reg: BUCK7 { + regulator-name = "VDD_LCD_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + }; + }; + + unidisplay_ts@41 { + compatible = "pixcir,unidisplay-ts"; + reg = <0x41>; + interrupt-parent = <&gpx3>; + interrupts = <1 0>; + }; + }; + + i2c@13870000 { + status = "okay"; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <20000>; + pinctrl-0 = <&i2c1_bus>; + pinctrl-names = "default"; + + codec: alc5625@1e { + compatible = "realtek,alc5625"; + reg = <0x1e>; + }; + }; + gpio_keys { compatible = "gpio-keys"; #address-cells = <1>; @@ -121,4 +324,62 @@ linux,default-trigger = "heartbeat"; }; }; + + usb@12480000 { + vusb_a-supply = <&ldo3_reg>; + vusb_d-supply = <&ldo8_reg>; + }; + + i2c@138e0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-hdmiphy-i2c"; + samsung,i2c-quirk-hdmiphy; + samsung,i2c-no-gpio; + reg = <0x138e0000 0x1000>; + interrupts = <0 93 0>; + status = "okay"; + + hdmiphy: phy@38 { + compatible = "samsung,hdmiphy-exynos4210"; + reg = <0x38>; + }; + }; + + tvmixer: tvmixer@12c10000 { + compatible = "samsung,s5pv210-tvmixer"; + reg = <0x12c10000 0x10000>, <0x12c00000 0x10000>; + reg-names = "mxr", "vp"; + interrupts = <0 91 0>; + interrupt-names = "irq"; + samsung,power-domain = <&pd_tv>; + }; + + hdmi: hdmi@12d00000 { + compatible = "samsung,s5pv210-hdmi"; + reg = <0x12d00000 0x100000>; + interrupts = <0 92 0>; + phy = <&hdmiphy>; + samsung,power-domain = <&pd_tv>; + + vdd_osc-supply = <&ldo8_reg>; + vdd_pll-supply = <&ldo3_reg>; + vdd-supply = <&ldo3_reg>; + }; + + reg_hdmi_en: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "hdmi-en"; + }; + + i2s_0: i2s@03830000 { + pinctrl-0 = <&i2s0_bus>; + pinctrl-names = "default"; + idma-addr = <0x03000000>; + }; + + asoc_dma { + compatible = "samsung,audio-dma"; + }; + }; diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi index 55a2efb763d..8e1bb58212f 100644 --- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi +++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi @@ -330,6 +330,53 @@ samsung,pin-pud = <3>; samsung,pin-drv = <0>; }; + + pwm0_out: pwm0-out { + samsung,pins = "gpd0-0"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + lcd0_sync: lcd0-sync { + samsung,pins = "gpf0-0", "gpf0-1"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + lcd0_clk: lcd0-clk { + samsung,pins = "gpf0-2"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + lcd0_en: lcd0-en { + samsung,pins = "gpf0-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + lcd0_data: lcd0-data { + samsung,pins = "gpf0-4", "gpf0-5", "gpf0-6", "gpf0-7", + "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3", + "gpf1-4", "gpf1-5", "gpf1-6", "gpf1-7", + "gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3", + "gpf2-4", "gpf2-5", "gpf2-6", "gpf2-7", + "gpf3-0", "gpf3-1", "gpf3-2", "gpf3-3"; + samsung,pin-function = <2>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + + lcdpanel_en: lcdpanel-en { + samsung,pins = "gpe3-4"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; }; pinctrl@11000000 { diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index e31bfc4a6f0..a9a8cc4de04 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi @@ -29,6 +29,7 @@ pinctrl0 = &pinctrl_0; pinctrl1 = &pinctrl_1; pinctrl2 = &pinctrl_2; + i2s0 = &i2s_0; }; pd_lcd1: lcd1-power-domain@10023CA0 { @@ -47,6 +48,12 @@ <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; }; + pmu { + compatible = "arm,cortex-a9-pmu"; + interrupt-parent = <&combiner>; + interrupts = <2 2>, <3 2>; + }; + pinctrl_0: pinctrl@11400000 { compatible = "samsung,pinctrl-exynos4210"; reg = <0x11400000 0x1000>; @@ -57,8 +64,8 @@ compatible = "samsung,pinctrl-exynos4210"; reg = <0x11000000 0x1000>; interrupts = <0 46 0>; - wakup_eint: wakeup-interrupt-controller { + compatible = "samsung,exynos4210-wakeup-eint"; interrupt-parent = <&gic>; interrupts = <0 32 0>; @@ -76,4 +83,40 @@ reg = <0x100C0000 0x100>; interrupts = <2 4>; }; + + fimd@11C00000 { + compatible = "samsung,exynos4210-fimd"; + interrupt-parent = <&combiner>; + reg = <0x11C00000 0x8000>; + interrupts = <11 1>, <11 0>, <11 2>; + }; + + usb@12580000 { + compatible = "samsung,exynos-ehci", "usb-ehci"; + reg = <0x12580000 0x100>; + interrupts = <0 70 0>; + }; + + usb@12590000 { + compatible = "samsung,exynos-ohci", "usb-ohci"; + reg = <0x12590000 0x100>; + interrupts = <0 70 0>; + }; + + usb@12480000 { + compatible = "samsung,exynos-hsotg"; + reg = <0x12480000 0x20000>; + interrupts = <0 71 0>; + }; + + i2s_0: i2s@03830000 { + compatible = "samsung,samsung-i2s"; + reg = <0x03830000 0x100>; + tx-dma-channel-secondary = <&pdma0 10>; + tx-dma-channel = <&pdma0 12>; + rx-dma-channel = <&pdma0 11>; + supports-6ch; + supports-rstclr; + supports-secdai; + }; }; diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts new file mode 100644 index 00000000000..92a6955eeb1 --- /dev/null +++ b/arch/arm/boot/dts/exynos5250-arndale.dts @@ -0,0 +1,357 @@ +/* + * SAMSUNG ARNDALE5250 board device tree source + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +/dts-v1/; +/include/ "exynos5250.dtsi" + +/ { + model = "SAMSUNG ARNDALE board based on EXYNOS5250"; + compatible = "samsung,arndale", "samsung,exynos5250"; + + aliases { + mshc0 = &dwmmc_0; + mshc1 = &dwmmc_1; + mshc2 = &dwmmc_2; + mshc3 = &dwmmc_3; + }; + + memory { + reg = <0x40000000 0x80000000>; + }; + + chosen { + bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc"; + }; + + i2c@12C60000 { + status = "okay"; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <20000>; + samsung,i2c-slave-addr = <0x66>; + gpios = <&gpb3 0 2 3 0>, + <&gpb3 1 2 3 0>; + + s5m8767_pmic@66 { + compatible = "samsung,s5m8767-pmic"; + reg = <0x66>; + + s5m8767,pmic-buck2-dvs-voltage = <1300000>; + s5m8767,pmic-buck3-dvs-voltage = <1100000>; + s5m8767,pmic-buck4-dvs-voltage = <1200000>; + s5m8767,pmic-buck-dvs-gpios = <&gpd1 0 1 0 0>, /* DVS1 */ + <&gpd1 1 1 0 0>, /* DVS2 */ + <&gpd1 2 1 0 0>; /* DVS3 */ + s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */ + <&gpx2 4 1 0 0>, /* SET2 */ + <&gpx2 5 1 0 0>; /* SET3 */ + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ALIVE_1.0V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo2_reg: LDO2 { + regulator-name = "VDD_28IO_DP_1.35V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo3_reg: LDO3 { + regulator-name = "VDD_COMMON1_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo4_reg: LDO4 { + regulator-name = "VDD_IOPERI_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo5_reg: LDO5 { + regulator-name = "VDD_EXT_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo6_reg: LDO6 { + regulator-name = "VDD_MPLL_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo7_reg: LDO7 { + regulator-name = "VDD_XPLL_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo8_reg: LDO8 { + regulator-name = "VDD_COMMON2_1.0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo9_reg: LDO9 { + regulator-name = "VDD_33ON_3.0V"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo10_reg: LDO10 { + regulator-name = "VDD_COMMON3_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo11_reg: LDO11 { + regulator-name = "VDD_ABB2_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo12_reg: LDO12 { + regulator-name = "VDD_USB_3.0V"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo13_reg: LDO13 { + regulator-name = "VDDQ_C2C_W_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo14_reg: LDO14 { + regulator-name = "VDD18_ABB0/3_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo15_reg: LDO15 { + regulator-name = "VDD10_COMMON4_1.0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo16_reg: LDO16 { + regulator-name = "VDD18_HSIC_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo17_reg: LDO17 { + regulator-name = "VDDQ_MMC2/3_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + ldo18_reg: LDO18 { + regulator-name = "VDD_33ON_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck1_reg: BUCK1 { + regulator-name = "VDD_MIF_1.2V"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck3_reg: BUCK3 { + regulator-name = "VDD_INT_1.0V"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck4_reg: BUCK4 { + regulator-name = "VDD_G3D_1.0V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + op_mode = <1>; /* Normal Mode */ + }; + + buck5_reg: BUCK5 { + regulator-name = "VDD_MEM_1.35V"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1355000>; + regulator-always-on; + regulator-boot-on; + op_mode = <1>; /* Normal Mode */ + }; + + }; + }; + }; + + i2c@12C70000 { + status = "disabled"; + }; + + i2c@12C80000 { + status = "disabled"; + }; + + i2c@12C90000 { + status = "disabled"; + }; + + i2c@12CA0000 { + status = "disabled"; + }; + + i2c@12CB0000 { + status = "disabled"; + }; + + i2c@12CC0000 { + status = "disabled"; + }; + + i2c@12CD0000 { + status = "disabled"; + }; + + i2c@121D0000 { + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <40000>; + samsung,i2c-slave-addr = <0x38>; + + sata-phy { + compatible = "samsung,sata-phy"; + reg = <0x38>; + }; + }; + + sata@122F0000 { + samsung,sata-freq = <66>; + }; + + dwmmc_0: dwmmc0@12200000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + fifo-depth = <0x80>; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + + slot@0 { + reg = <0>; + bus-width = <8>; + gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>, + <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>, + <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>, + <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>, + <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>; + }; + }; + + dwmmc_1: dwmmc1@12210000 { + status = "disabled"; + }; + dwmmc_2: dwmmc2@12220000 { + num-slots = <1>; + supports-highspeed; + fifo-depth = <0x80>; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + + slot@0 { + reg = <0>; + bus-width = <4>; + samsung,cd-pinmux-gpio = <&gpc3 2 2 3 3>; + gpios = <&gpc3 0 2 0 3>, <&gpc3 1 2 0 3>, + <&gpc3 3 2 3 3>, <&gpc3 4 2 3 3>, + <&gpc3 5 2 3 3>, <&gpc3 6 2 3 3>, + <&gpc4 3 3 3 3>, <&gpc4 3 3 3 3>, + <&gpc4 5 3 3 3>, <&gpc4 6 3 3 3>; + }; + }; + + dwmmc_3: dwmmc3@12230000 { + status = "disabled"; + }; + + spi_0: spi@12d20000 { + status = "disabled"; + }; + + spi_1: spi@12d30000 { + status = "disabled"; + }; + + spi_2: spi@12d40000 { + status = "disabled"; + }; + + ehci { + samsung,hub-reset = <&gpx3 5 1 0 3>; + samsung,hub-connect = <&gpd1 7 1 0 3>; + }; +}; diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts index 942d5761ca9..c5115c88941 100644 --- a/arch/arm/boot/dts/exynos5250-smdk5250.dts +++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts @@ -204,4 +204,8 @@ samsung,mfc-r = <0x43000000 0x800000>; samsung,mfc-l = <0x51000000 0x800000>; }; + + ehci { + samsung,vbus-gpio = <&gpx2 6 1 3 3>; + }; }; diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 3acf594ea60..d166e61c754 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -69,6 +69,12 @@ <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; }; + pmu { + compatible = "arm,cortex-a15-pmu"; + interrupt-parent = <&combiner>; + interrupts = <1 2>, <22 4>; + }; + watchdog { compatible = "samsung,s3c2410-wdt"; reg = <0x101D0000 0x100>; @@ -81,6 +87,29 @@ interrupts = <0 96 0>; }; + usbphy { + compatible = "samsung,exynos5250-usbphy"; + reg = <0x12130000 0x100>, <0x12100000 0x100>; + }; + + usb@12000000 { + compatible = "samsung,exynos-dwc3"; + reg = <0x12000000 0x10000>; + interrupts = <0 72 0>; + }; + + ohci { + compatible = "samsung,exynos-ohci"; + reg = <0x12120000 0x100>; + interrupts = <0 71 0>; + }; + + ehci { + compatible = "samsung,exynos-ehci"; + reg = <0x12110000 0x100>; + interrupts = <0 71 0>; + }; + rtc { compatible = "samsung,s3c6410-rtc"; reg = <0x101E0000 0x100>; @@ -200,11 +229,11 @@ #size-cells = <0>; }; - i2c@121D0000 { - compatible = "samsung,exynos5-sata-phy-i2c"; - reg = <0x121D0000 0x100>; - #address-cells = <1>; - #size-cells = <0>; + i2c_sataphy: i2c@121D0000 { + compatible = "samsung,exynos5-sata-phy-i2c"; + reg = <0x121D0000 0x100>; + #address-cells = <1>; + #size-cells = <0>; }; spi_0: spi@12d20000 { @@ -269,6 +298,7 @@ #size-cells = <0>; }; + amba { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/configs/android_origen_defconfig b/arch/arm/configs/android_origen_defconfig new file mode 100644 index 00000000000..eab7b5a5293 --- /dev/null +++ b/arch/arm/configs/android_origen_defconfig @@ -0,0 +1,210 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_PERF_COUNTERS=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_GCOV_KERNEL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_BSD_DISKLABEL=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_ARCH_EXYNOS=y +CONFIG_S3C_LOWLEVEL_UART_PORT=2 +CONFIG_S3C24XX_PWM=y +CONFIG_MACH_SMDKC210=y +CONFIG_MACH_ARMLEX4210=y +CONFIG_MACH_UNIVERSAL_C210=y +CONFIG_MACH_NURI=y +CONFIG_MACH_ORIGEN=y +CONFIG_MACH_SMDK4412=y +CONFIG_MACH_EXYNOS4_DT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_NR_CPUS=2 +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc mem=256M" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_PM_RUNTIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IPV6=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_ACCT=y +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_BT=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +CONFIG_BT_HCIUART_BCSP=y +CONFIG_CFG80211=y +CONFIG_RFKILL=y +CONFIG_RFKILL_GPIO=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_NETDEVICES=y +CONFIG_USB_PEGASUS=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_DM9601=y +CONFIG_USB_NET_MCS7830=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_ATH_COMMON=y +CONFIG_ATH_DEBUG=y +CONFIG_ATH6KL=m +CONFIG_ATH6KL_PLATFORM_DATA=y +CONFIG_ATH6KL_POLL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_UNIDISPLAY_TS=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_S3C2410=y +CONFIG_POWER_SUPPLY=y +CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_SENSORS_EXYNOS4_TMU=y +CONFIG_MFD_MAX8997=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MAX8997=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_V4L_USB_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_FIMC=y +CONFIG_VIDEO_S5P_FIMC=y +CONFIG_VIDEO_SAMSUNG_S5P_TV=y +CONFIG_VIDEO_SAMSUNG_S5P_HDMI=y +CONFIG_VIDEO_SAMSUNG_S5P_SDO=y +CONFIG_VIDEO_SAMSUNG_S5P_MIXER=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_G2D=y +CONFIG_VIDEO_SAMSUNG_S5P_JPEG=y +CONFIG_VIDEO_SAMSUNG_S5P_MFC=y +CONFIG_DRM=y +CONFIG_ION=y +CONFIG_MALI400MP=y +CONFIG_USING_PMM=y +CONFIG_UMP=y +CONFIG_FB=y +CONFIG_FB_S3C=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_PLATFORM=y +CONFIG_LCD_PWRCTRL=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_HID_KYE=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_S5P=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_EXYNOS=y +CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_S3C_HSOTG=y +CONFIG_USB_G_ANDROID=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_S3C=y +CONFIG_MMC_SDHCI_S3C_DMA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_S3C=y +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_PERSISTENT_TRACER=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_SWITCH=y +CONFIG_SND_SOC_ORIGEN_ALC5625=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CRAMFS=y +CONFIG_ROMFS_FS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_RAM=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_INFO=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_DEBUG_USER=y +CONFIG_CRC_CCITT=y diff --git a/arch/arm/configs/arndale_ubuntu_defconfig b/arch/arm/configs/arndale_ubuntu_defconfig new file mode 100644 index 00000000000..230ca41d786 --- /dev/null +++ b/arch/arm/configs/arndale_ubuntu_defconfig @@ -0,0 +1,129 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_BSD_DISKLABEL=y +CONFIG_SOLARIS_X86_PARTITION=y +# CONFIG_EFI_PARTITION is not set +CONFIG_ARCH_EXYNOS=y +CONFIG_S3C_LOWLEVEL_UART_PORT=2 +# CONFIG_ARCH_EXYNOS4 is not set +CONFIG_ARCH_EXYNOS5=y +CONFIG_ARM_LPAE=y +CONFIG_NUMA=y +CONFIG_NODES_SHIFT=2 +CONFIG_SMP=y +CONFIG_NR_CPUS=2 +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init= mem=256M" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IPV6=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=m +CONFIG_INET6_XFRM_MODE_TUNNEL=m +CONFIG_INET6_XFRM_MODE_BEET=m +CONFIG_IPV6_SIT=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_ATA=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_SATA_EXYNOS=y +CONFIG_NETDEVICES=y +CONFIG_AX88796=y +CONFIG_AX88796_93CX6=y +CONFIG_SMC91X=y +CONFIG_SMC911X=y +CONFIG_SMSC911X=y +CONFIG_USB_USBNET=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C_GPIO=y +# CONFIG_HWMON is not set +CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_EXYNOS_THERMAL=y +CONFIG_MFD_SEC_CORE=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_HID_LOGITECH_DJ=m +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_DWC3=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_S5P=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_EXYNOS=y +CONFIG_USB_STORAGE=y +CONFIG_SAMSUNG_USBPHY=y +CONFIG_USB_GADGET=y +CONFIG_MMC=y +CONFIG_MMC_DW=y +CONFIG_MMC_DW_IDMAC=y +CONFIG_MMC_DW_EXYNOS=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XIP=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_DEBUG=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_CRAMFS=y +CONFIG_ROMFS_FS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_S3C_UART2=y +CONFIG_EARLY_PRINTK=y +CONFIG_CRC_CCITT=y diff --git a/arch/arm/configs/exynos4_defconfig b/arch/arm/configs/exynos4_defconfig index bffe68e190a..62dd948ecac 100644 --- a/arch/arm/configs/exynos4_defconfig +++ b/arch/arm/configs/exynos4_defconfig @@ -5,43 +5,154 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_EXYNOS=y -CONFIG_S3C_LOWLEVEL_UART_PORT=1 +CONFIG_S3C_LOWLEVEL_UART_PORT=2 +CONFIG_S3C24XX_PWM=y CONFIG_MACH_SMDKC210=y CONFIG_MACH_ARMLEX4210=y CONFIG_MACH_UNIVERSAL_C210=y CONFIG_MACH_NURI=y CONFIG_MACH_ORIGEN=y CONFIG_MACH_SMDK4412=y +CONFIG_MACH_EXYNOS4_DT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y CONFIG_NR_CPUS=2 CONFIG_PREEMPT=y CONFIG_AEABI=y -CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc mem=256M" +CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc mem=256M" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y +CONFIG_PM_RUNTIME=y +CONFIG_NET=y +CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IPV6=y +CONFIG_CFG80211=y +CONFIG_RFKILL=y +CONFIG_RFKILL_GPIO=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y +CONFIG_NETDEVICES=y +CONFIG_USB_PEGASUS=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_DM9601=y +CONFIG_USB_NET_MCS7830=y +CONFIG_ATH_COMMON=y +CONFIG_ATH_DEBUG=y +CONFIG_ATH6KL=m +CONFIG_ATH6KL_PLATFORM_DATA=y +CONFIG_ATH6KL_POLL=y CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_KEYBOARD is not set +CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_UNIDISPLAY_TS=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_SAMSUNG=y CONFIG_SERIAL_SAMSUNG_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_I2C=y +CONFIG_I2C_S3C2410=y +CONFIG_POWER_SUPPLY=y # CONFIG_HWMON is not set -# CONFIG_MFD_SUPPORT is not set -# CONFIG_HID_SUPPORT is not set -# CONFIG_USB_SUPPORT is not set +CONFIG_MFD_MAX8997=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MAX8997=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_FIMC=y +CONFIG_VIDEO_S5P_FIMC=y +CONFIG_VIDEO_SAMSUNG_S5P_TV=y +CONFIG_VIDEO_SAMSUNG_S5P_HDMI=y +CONFIG_VIDEO_SAMSUNG_S5P_SDO=y +CONFIG_VIDEO_SAMSUNG_S5P_MIXER=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_G2D=y +CONFIG_VIDEO_SAMSUNG_S5P_JPEG=y +CONFIG_VIDEO_SAMSUNG_S5P_MFC=y +CONFIG_FB=y +CONFIG_FB_S3C=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_PLATFORM=y +CONFIG_LCD_PWRCTRL=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_S5P=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_EXYNOS=y +CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_S3C_HSOTG=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_EEM=y +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_FUNCTIONFS=m +CONFIG_USB_FUNCTIONFS_ETH=y +CONFIG_USB_FUNCTIONFS_RNDIS=y +CONFIG_USB_FUNCTIONFS_GENERIC=y +CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_FILE_STORAGE_TEST=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_USB_G_PRINTER=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_G_ACM_MS=m +CONFIG_USB_G_MULTI=m +CONFIG_USB_G_MULTI_CDC=y +CONFIG_USB_G_HID=m +CONFIG_USB_G_DBGP=m +CONFIG_USB_G_DBGP_PRINTK=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_S3C=y +CONFIG_MMC_SDHCI_S3C_DMA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_S3C=y +CONFIG_STAGING=y +CONFIG_SND_SOC_ORIGEN_ALC5625=y CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y @@ -54,7 +165,9 @@ CONFIG_SOLARIS_X86_PARTITION=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SECTION_MISMATCH=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_RT_MUTEXES=y @@ -63,6 +176,4 @@ CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_INFO=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y -CONFIG_EARLY_PRINTK=y CONFIG_CRC_CCITT=y diff --git a/arch/arm/configs/ubuntu_origen_defconfig b/arch/arm/configs/ubuntu_origen_defconfig new file mode 100644 index 00000000000..6bcf64c06db --- /dev/null +++ b/arch/arm/configs/ubuntu_origen_defconfig @@ -0,0 +1,241 @@ +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_BLK_DEV_INITRD=y +CONFIG_EMBEDDED=y +CONFIG_PERF_COUNTERS=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_ARCH_EXYNOS=y +CONFIG_S3C_LOWLEVEL_UART_PORT=2 +CONFIG_S3C24XX_PWM=y +CONFIG_MACH_SMDKC210=y +CONFIG_MACH_ARMLEX4210=y +CONFIG_MACH_UNIVERSAL_C210=y +CONFIG_MACH_NURI=y +CONFIG_MACH_ORIGEN=y +CONFIG_MACH_SMDK4412=y +CONFIG_MACH_EXYNOS4_DT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_NR_CPUS=2 +CONFIG_THUMB2_KERNEL=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_SECCOMP=y +CONFIG_CC_STACKPROTECTOR=y +CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc mem=256M" +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_BINFMT_MISC=y +CONFIG_PM_RUNTIME=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=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_SYN_COOKIES=y +# CONFIG_INET_LRO is not set +CONFIG_IPV6=y +CONFIG_NETLABEL=y +CONFIG_NETFILTER=y +CONFIG_CFG80211=y +CONFIG_RFKILL=y +CONFIG_RFKILL_GPIO=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CMA=y +CONFIG_CMA_SIZE_MBYTES=32 +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_OOPS=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_NAND=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_NETDEVICES=y +CONFIG_USB_PEGASUS=y +CONFIG_USB_USBNET=y +CONFIG_USB_NET_DM9601=y +CONFIG_USB_NET_MCS7830=y +CONFIG_ATH_COMMON=y +CONFIG_ATH_DEBUG=y +CONFIG_ATH6KL=m +CONFIG_ATH6KL_PLATFORM_DATA=y +CONFIG_ATH6KL_POLL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_UNIDISPLAY_TS=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C=y +CONFIG_I2C_S3C2410=y +CONFIG_POWER_SUPPLY=y +CONFIG_THERMAL=y +CONFIG_CPU_THERMAL=y +CONFIG_SENSORS_EXYNOS4_TMU=y +CONFIG_MFD_MAX8997=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_MAX8997=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_FIMC=y +CONFIG_VIDEO_S5P_FIMC=y +CONFIG_VIDEO_SAMSUNG_S5P_TV=y +CONFIG_VIDEO_SAMSUNG_S5P_HDMI=y +CONFIG_VIDEO_SAMSUNG_S5P_SDO=y +CONFIG_VIDEO_SAMSUNG_S5P_MIXER=y +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_SAMSUNG_S5P_G2D=y +CONFIG_VIDEO_SAMSUNG_S5P_JPEG=y +CONFIG_VIDEO_SAMSUNG_S5P_MFC=y +CONFIG_FB=y +CONFIG_FB_S3C=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_PLATFORM=y +CONFIG_LCD_PWRCTRL=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_S5P=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_EXYNOS=y +CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_USB_S3C_HSOTG=y +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +CONFIG_USB_ETH_EEM=y +CONFIG_USB_G_NCM=m +CONFIG_USB_GADGETFS=m +CONFIG_USB_FUNCTIONFS=m +CONFIG_USB_FUNCTIONFS_ETH=y +CONFIG_USB_FUNCTIONFS_RNDIS=y +CONFIG_USB_FUNCTIONFS_GENERIC=y +CONFIG_USB_FILE_STORAGE=m +CONFIG_USB_FILE_STORAGE_TEST=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_USB_G_PRINTER=m +CONFIG_USB_CDC_COMPOSITE=m +CONFIG_USB_G_ACM_MS=m +CONFIG_USB_G_MULTI=m +CONFIG_USB_G_MULTI_CDC=y +CONFIG_USB_G_HID=m +CONFIG_USB_G_DBGP=m +CONFIG_USB_G_DBGP_PRINTK=y +CONFIG_MMC=y +CONFIG_MMC_UNSAFE_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_S3C=y +CONFIG_MMC_SDHCI_S3C_DMA=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_S3C=y +CONFIG_STAGING=y +CONFIG_SND_SOC_ORIGEN_ALC5625=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y +CONFIG_BTRFS_FS=y +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_SUMMARY=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_LZO=y +CONFIG_JFFS2_RUBIN=y +CONFIG_CRAMFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SECTION_MISMATCH=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEBUG_RT_MUTEXES=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_INFO=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DEBUG_USER=y +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_PROVE_LOCKING=y +CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_STRICT_DEVMEM=y +CONFIG_KEYS=y +CONFIG_SECURITY=y +CONFIG_LSM_MMAP_MIN_ADDR=0 +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_DEFAULT_SECURITY_APPARMOR=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_CRC_CCITT=y +CONFIG_CRC_T10DIF=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC7=y diff --git a/arch/arm/include/asm/hugetlb-2level.h b/arch/arm/include/asm/hugetlb-2level.h new file mode 100644 index 00000000000..3532b54bcfd --- /dev/null +++ b/arch/arm/include/asm/hugetlb-2level.h @@ -0,0 +1,71 @@ +/* + * arch/arm/include/asm/hugetlb-2level.h + * + * Copyright (C) 2012 ARM Ltd. + * + * Based on arch/x86/include/asm/hugetlb.h and Bill Carson's patches + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASM_ARM_HUGETLB_2LEVEL_H +#define _ASM_ARM_HUGETLB_2LEVEL_H + + +pte_t huge_ptep_get(pte_t *ptep); + +void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte); + +static inline pte_t pte_mkhuge(pte_t pte) { return pte; } + +static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ + flush_tlb_range(vma, addr, addr + HPAGE_SIZE); +} + +static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + pmd_t *pmdp = (pmd_t *) ptep; + set_pmd_at(mm, addr, pmdp, pmd_wrprotect(*pmdp)); +} + + +static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + pmd_t *pmdp = (pmd_t *)ptep; + pte_t pte = huge_ptep_get(ptep); + pmd_clear(pmdp); + + return pte; +} + +static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty) +{ + int changed = !pte_same(huge_ptep_get(ptep), pte); + + if (changed) { + set_huge_pte_at(vma->vm_mm, addr, ptep, pte); + huge_ptep_clear_flush(vma, addr, &pte); + } + + return changed; +} + +#endif /* _ASM_ARM_HUGETLB_2LEVEL_H */ diff --git a/arch/arm/include/asm/hugetlb-3level.h b/arch/arm/include/asm/hugetlb-3level.h new file mode 100644 index 00000000000..486806445c3 --- /dev/null +++ b/arch/arm/include/asm/hugetlb-3level.h @@ -0,0 +1,61 @@ +/* + * arch/arm/include/asm/hugetlb-3level.h + * + * Copyright (C) 2012 ARM Ltd. + * + * Based on arch/x86/include/asm/hugetlb.h. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASM_ARM_HUGETLB_3LEVEL_H +#define _ASM_ARM_HUGETLB_3LEVEL_H + +static inline pte_t huge_ptep_get(pte_t *ptep) +{ + return *ptep; +} + +static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) +{ + set_pte_at(mm, addr, ptep, pte); +} + +static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ + ptep_clear_flush(vma, addr, ptep); +} + +static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + ptep_set_wrprotect(mm, addr, ptep); +} + +static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + return ptep_get_and_clear(mm, addr, ptep); +} + +static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty) +{ + return ptep_set_access_flags(vma, addr, ptep, pte, dirty); +} + +#endif /* _ASM_ARM_HUGETLB_3LEVEL_H */ diff --git a/arch/arm/include/asm/hugetlb.h b/arch/arm/include/asm/hugetlb.h new file mode 100644 index 00000000000..1e92975f6c1 --- /dev/null +++ b/arch/arm/include/asm/hugetlb.h @@ -0,0 +1,87 @@ +/* + * arch/arm/include/asm/hugetlb.h + * + * Copyright (C) 2012 ARM Ltd. + * + * Based on arch/x86/include/asm/hugetlb.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASM_ARM_HUGETLB_H +#define _ASM_ARM_HUGETLB_H + +#include <asm/page.h> + +#ifdef CONFIG_ARM_LPAE +#include <asm/hugetlb-3level.h> +#else +#include <asm/hugetlb-2level.h> +#endif + +static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb, + unsigned long addr, unsigned long end, + unsigned long floor, + unsigned long ceiling) +{ + free_pgd_range(tlb, addr, end, floor, ceiling); +} + + +static inline int is_hugepage_only_range(struct mm_struct *mm, + unsigned long addr, unsigned long len) +{ + return 0; +} + +static inline int prepare_hugepage_range(struct file *file, + unsigned long addr, unsigned long len) +{ + struct hstate *h = hstate_file(file); + if (len & ~huge_page_mask(h)) + return -EINVAL; + if (addr & ~huge_page_mask(h)) + return -EINVAL; + return 0; +} + +static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) +{ +} + +static inline int huge_pte_none(pte_t pte) +{ + return pte_none(pte); +} + +static inline pte_t huge_pte_wrprotect(pte_t pte) +{ + return pte_wrprotect(pte); +} + +static inline int arch_prepare_hugepage(struct page *page) +{ + return 0; +} + +static inline void arch_release_hugepage(struct page *page) +{ +} + +static inline void arch_clear_hugepage_flags(struct page *page) +{ + clear_bit(PG_dcache_clean, &page->flags); +} + +#endif /* _ASM_ARM_HUGETLB_H */ diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 73cf03aa981..485c3154ba8 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -18,6 +18,9 @@ #include <linux/types.h> #include <linux/sizes.h> +#include <asm/cache.h> +#include <asm/runtime-patch.h> + #ifdef CONFIG_NEED_MACH_MEMORY_H #include <mach/memory.h> #endif @@ -99,11 +102,11 @@ #endif #ifndef PHYS_OFFSET -#define PHYS_OFFSET UL(CONFIG_DRAM_BASE) +#define PHYS_OFFSET UL(CONFIG_DRAM_BASE) #endif #ifndef END_MEM -#define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE) +#define END_MEM (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE) #endif #ifndef PAGE_OFFSET @@ -141,6 +144,20 @@ #define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) #define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) +/* + * Minimum guaranted alignment in pgd_alloc(). The page table pointers passed + * around in head.S and proc-*.S are shifted by this amount, in order to + * leave spare high bits for systems with physical address extension. This + * does not fully accomodate the 40-bit addressing capability of ARM LPAE, but + * gives us about 38-bits or so. + */ +#ifdef CONFIG_ARM_LPAE +#define ARCH_PGD_SHIFT L1_CACHE_SHIFT +#else +#define ARCH_PGD_SHIFT 0 +#endif +#define ARCH_PGD_MASK ((1 << ARCH_PGD_SHIFT) - 1) + #ifndef __ASSEMBLY__ /* @@ -151,40 +168,70 @@ #ifndef __virt_to_phys #ifdef CONFIG_ARM_PATCH_PHYS_VIRT -/* - * Constants used to force the right instruction encodings and shifts - * so that all we need to do is modify the 8-bit constant field. - */ -#define __PV_BITS_31_24 0x81000000 +extern unsigned long __pv_offset; +extern phys_addr_t __pv_phys_offset; +#define PHYS_OFFSET __virt_to_phys(PAGE_OFFSET) -extern unsigned long __pv_phys_offset; -#define PHYS_OFFSET __pv_phys_offset +static inline phys_addr_t __virt_to_phys(unsigned long x) +{ + phys_addr_t t; -#define __pv_stub(from,to,instr,type) \ - __asm__("@ __pv_stub\n" \ - "1: " instr " %0, %1, %2\n" \ - " .pushsection .pv_table,\"a\"\n" \ - " .long 1b\n" \ - " .popsection\n" \ - : "=r" (to) \ - : "r" (from), "I" (type)) +#ifndef CONFIG_ARM_LPAE + early_patch_imm8("add", t, x, __pv_offset, 0); +#else + unsigned long __tmp; -static inline unsigned long __virt_to_phys(unsigned long x) -{ - unsigned long t; - __pv_stub(x, t, "add", __PV_BITS_31_24); +#ifndef __ARMEB__ +#define PV_PHYS_HIGH "(__pv_phys_offset + 4)" +#else +#define PV_PHYS_HIGH "__pv_phys_offset" +#endif + + early_patch_stub( + /* type */ PATCH_IMM8, + /* code */ + "ldr %[tmp], =__pv_offset\n" + "ldr %[tmp], [%[tmp]]\n" + "add %Q[to], %[from], %[tmp]\n" + "ldr %[tmp], =" PV_PHYS_HIGH "\n" + "ldr %[tmp], [%[tmp]]\n" + "mov %R[to], %[tmp]\n", + /* pad */ 4, + /* patch_data */ + ".long __pv_offset\n" + "add %Q[to], %[from], %[imm]\n" + ".long " PV_PHYS_HIGH "\n" + "mov %R[to], %[imm]\n", + /* operands */ + : [to] "=r" (t), + [tmp] "=&r" (__tmp) + : [from]"r" (x), + [imm] "I" (__IMM8), + "i" (&__pv_offset), + "i" (&__pv_phys_offset)); +#endif return t; } -static inline unsigned long __phys_to_virt(unsigned long x) +static inline unsigned long __phys_to_virt(phys_addr_t x) { - unsigned long t; - __pv_stub(x, t, "sub", __PV_BITS_31_24); + unsigned long t, xlo = x; + early_patch_imm8("sub", t, xlo, __pv_offset, 0); return t; } + #else -#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) -#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) + +static inline phys_addr_t __virt_to_phys(unsigned long x) +{ + return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET; +} + +static inline unsigned long __phys_to_virt(phys_addr_t x) +{ + return x - PHYS_OFFSET + PAGE_OFFSET; +} + #endif #endif #endif /* __ASSEMBLY__ */ @@ -222,14 +269,14 @@ static inline phys_addr_t virt_to_phys(const volatile void *x) static inline void *phys_to_virt(phys_addr_t x) { - return (void *)(__phys_to_virt((unsigned long)(x))); + return (void *)__phys_to_virt(x); } /* * Drivers should NOT use these either. */ #define __pa(x) __virt_to_phys((unsigned long)(x)) -#define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) +#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) /* @@ -279,4 +326,6 @@ static inline __deprecated void *bus_to_virt(unsigned long x) #include <asm-generic/memory_model.h> +#define ARCH_LOW_ADDRESS_LIMIT PHYS_MASK + #endif diff --git a/arch/arm/include/asm/mmzone.h b/arch/arm/include/asm/mmzone.h new file mode 100644 index 00000000000..628e5035659 --- /dev/null +++ b/arch/arm/include/asm/mmzone.h @@ -0,0 +1,49 @@ +/* + * Discontiguous memory and NUMA support, based on the PowerPC implementation. + * + * Copyright (C) 2012 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. + * + * 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_ARM_MMZONE_H_ +#define __ASM_ARM_MMZONE_H_ +#ifdef __KERNEL__ + +#include <linux/cpumask.h> + +#ifdef CONFIG_NUMA_ALLOC_NODES +#define NODE_DATA(nid) (node_data[nid]) +extern void __init arm_numa_alloc_nodes(unsigned long max_low); +extern struct pglist_data *node_data[]; +#else +#define arm_numa_alloc_nodes(_mlow) do {} while (0) +#endif + +#ifdef CONFIG_NUMA +extern cpumask_var_t *node_to_cpumask_map; +extern int numa_cpu_lookup_table[]; +extern int pfn_to_nid(unsigned long pfn); +extern void __init arm_setup_nodes(unsigned long min, unsigned long max_high); +extern void __init arm_numa_alloc_cpumask(unsigned long max_low); +#else +#define pfn_to_nid(pfn) (0) +#define arm_setup_nodes(min, max_high) memblock_set_node( \ + __pfn_to_phys(min), \ + __pfn_to_phys(max_high - min), 0) +#define arm_numa_alloc_cpumask(max_low) do {} while (0) +#endif /* CONFIG_NUMA */ + +#endif /* __KERNEL__ */ +#endif /* __ASM_ARM_MMZONE_H_ */ diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h index 0d3a28dbc8e..c4ebe522ca4 100644 --- a/arch/arm/include/asm/module.h +++ b/arch/arm/include/asm/module.h @@ -39,9 +39,16 @@ struct mod_arch_specific { #define MODULE_ARCH_VERMAGIC_ARMTHUMB "" #endif +#ifdef CONFIG_ARM_RUNTIME_PATCH +#define MODULE_ARCH_VERMAGIC_RT_PATCH "rt-patch " +#else +#define MODULE_ARCH_VERMAGIC_RT_PATCH "" +#endif + #define MODULE_ARCH_VERMAGIC \ MODULE_ARCH_VERMAGIC_ARMVSN \ MODULE_ARCH_VERMAGIC_ARMTHUMB \ + MODULE_ARCH_VERMAGIC_RT_PATCH \ MODULE_ARCH_VERMAGIC_P2V #endif /* _ASM_ARM_MODULE_H */ diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 812a4944e78..6363f3d1d50 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -13,7 +13,7 @@ /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) #ifndef __ASSEMBLY__ diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h index f97ee02386e..eb1640ed2a5 100644 --- a/arch/arm/include/asm/pgtable-2level.h +++ b/arch/arm/include/asm/pgtable-2level.h @@ -127,6 +127,11 @@ #define L_PTE_NONE (_AT(pteval_t, 1) << 11) /* + * for 2 levels of paging we don't mask off any bits when comparing present ptes + */ +#define L_PTE_CMP_MASKOFF 0 + +/* * These are the memory types, defined to be compatible with * pre-ARMv6 CPUs cacheable and bufferable bits: XXCB */ @@ -160,7 +165,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) return (pmd_t *)pud; } -#define pmd_bad(pmd) (pmd_val(pmd) & 2) +#define pmd_bad(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_FAULT) #define copy_pmd(pmdpd,pmdps) \ do { \ @@ -176,11 +181,156 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) clean_pmd_entry(pmdp); \ } while (0) + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define _PMD_HUGE(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) +#else +#define _PMD_HUGE(pmd) (0) +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + /* we don't need complex calculations here as the pmd is folded into the pgd */ #define pmd_addr_end(addr,end) (end) +#define pmd_present(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) != PMD_TYPE_FAULT) + #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext) + +#ifdef CONFIG_SYS_SUPPORTS_HUGETLBFS + +/* + * now follows some of the definitions to allow huge page support, we can't put + * these in the hugetlb source files as they are also required for transparent + * hugepage support. + */ + +#define HPAGE_SHIFT PMD_SHIFT +#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) + +#define HUGE_LINUX_PTE_COUNT (PAGE_OFFSET >> HPAGE_SHIFT) +#define HUGE_LINUX_PTE_SIZE (HUGE_LINUX_PTE_COUNT * sizeof(pte_t *)) +#define HUGE_LINUX_PTE_INDEX(addr) (addr >> HPAGE_SHIFT) + +/* + * We re-purpose the following domain bits in the section descriptor + */ +#define PMD_DSECT_DIRTY (_AT(pmdval_t, 1) << 5) +#define PMD_DSECT_AF (_AT(pmdval_t, 1) << 6) +#define PMD_DSECT_SPLITTING (_AT(pmdval_t, 1) << 7) + +#define PMD_BIT_FUNC(fn,op) \ +static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; } + +PMD_BIT_FUNC(wrprotect, &= ~PMD_SECT_AP_WRITE); + +static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp, pmd_t pmd) +{ + /* + * we can sometimes be passed a pmd pointing to a level 2 descriptor + * from collapse_huge_page. + */ + if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE) { + pmdp[0] = __pmd(pmd_val(pmd)); + pmdp[1] = __pmd(pmd_val(pmd) + 256 * sizeof(pte_t)); + } else { + pmdp[0] = __pmd(pmd_val(pmd)); /* first 1M section */ + pmdp[1] = __pmd(pmd_val(pmd) + SECTION_SIZE); /* second 1M section */ + } + + flush_pmd_entry(pmdp); +} + +#define HPMD_XLATE(res, cmp, from, to) do { if (cmp & from) res |= to; \ + else res &= ~to; \ + } while (0) + +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +{ + pmdval_t pmdval = pmd_val(pmd); + pteval_t newprotval = pgprot_val(newprot); + + HPMD_XLATE(pmdval, newprotval, L_PTE_XN, PMD_SECT_XN); + HPMD_XLATE(pmdval, newprotval, L_PTE_SHARED, PMD_SECT_S); + HPMD_XLATE(pmdval, newprotval, L_PTE_YOUNG, PMD_DSECT_AF); + HPMD_XLATE(pmdval, newprotval, L_PTE_DIRTY, PMD_DSECT_DIRTY); + + /* preserve bits C & B */ + pmdval |= (newprotval & (3 << 2)); + + /* Linux PTE bit 4 corresponds to PMD TEX bit 0 */ + HPMD_XLATE(pmdval, newprotval, 1 << 4, PMD_SECT_TEX(1)); + + if (newprotval & L_PTE_RDONLY) + pmdval &= ~PMD_SECT_AP_WRITE; + else + pmdval |= PMD_SECT_AP_WRITE; + + return __pmd(pmdval); +} + +#else +#define HPAGE_SIZE 0 +#endif /* CONFIG_SYS_SUPPORTS_HUGETLBFS */ + +#define HPAGE_MASK (~(HPAGE_SIZE - 1)) + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define pmd_mkhuge(pmd) (__pmd((pmd_val(pmd) & ~PMD_TYPE_MASK) | PMD_TYPE_SECT)) + +PMD_BIT_FUNC(mkold, &= ~PMD_DSECT_AF); +PMD_BIT_FUNC(mksplitting, |= PMD_DSECT_SPLITTING); +PMD_BIT_FUNC(mkdirty, |= PMD_DSECT_DIRTY); +PMD_BIT_FUNC(mkyoung, |= PMD_DSECT_AF); +PMD_BIT_FUNC(mkwrite, |= PMD_SECT_AP_WRITE); +PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK); + +#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_DSECT_SPLITTING) +#define pmd_young(pmd) (pmd_val(pmd) & PMD_DSECT_AF) +#define pmd_write(pmd) (pmd_val(pmd) & PMD_SECT_AP_WRITE) +#define pmd_trans_huge(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) + +static inline unsigned long pmd_pfn(pmd_t pmd) +{ + /* + * for a section, we need to mask off more of the pmd + * before looking up the pfn + */ + if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) + return __phys_to_pfn(pmd_val(pmd) & HPAGE_MASK); + else + return __phys_to_pfn(pmd_val(pmd) & PHYS_MASK); +} + +static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t prot) +{ + pmd_t pmd = __pmd(__pfn_to_phys(pfn) | PMD_SECT_AP_READ | PMD_SECT_nG); + + return pmd_modify(pmd, prot); +} + +#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot); + +static inline int has_transparent_hugepage(void) +{ + return 1; +} + +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +static inline struct page *pmd_page(pmd_t pmd) +{ + /* + * for a section, we need to mask off more of the pmd + * before looking up the page as it is a section descriptor. + */ + if (_PMD_HUGE(pmd)) + return phys_to_page(pmd_val(pmd) & HPAGE_MASK); + + return phys_to_page(pmd_val(pmd) & PHYS_MASK); +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_PGTABLE_2LEVEL_H */ diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h index d7952824c5c..bf1707f0239 100644 --- a/arch/arm/include/asm/pgtable-3level-hwdef.h +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h @@ -38,6 +38,8 @@ */ #define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2) #define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3) +#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */ +#define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */ #define PMD_SECT_S (_AT(pmdval_t, 3) << 8) #define PMD_SECT_AF (_AT(pmdval_t, 1) << 10) #define PMD_SECT_nG (_AT(pmdval_t, 1) << 11) @@ -74,4 +76,14 @@ #define PHYS_MASK_SHIFT (40) #define PHYS_MASK ((1ULL << PHYS_MASK_SHIFT) - 1) +#if defined CONFIG_VMSPLIT_2G +#define TTBR1_OFFSET (1 << 4) /* skip two L1 entries */ +#elif defined CONFIG_VMSPLIT_3G +#define TTBR1_OFFSET (4096 * (1 + 3)) /* only L2, skip pgd + 3*pmd */ +#else +#define TTBR1_OFFSET 0 +#endif + +#define TTBR1_SIZE (((PAGE_OFFSET >> 30) - 1) << 16) + #endif diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index a3f37929940..3c2432fe5e6 100644 --- a/arch/arm/include/asm/pgtable-3level.h +++ b/arch/arm/include/asm/pgtable-3level.h @@ -48,20 +48,28 @@ #define PMD_SHIFT 21 #define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) +#define PMD_MASK (~((1 << PMD_SHIFT) - 1)) #define PGDIR_SIZE (1UL << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) +#define PGDIR_MASK (~((1 << PGDIR_SHIFT) - 1)) /* * section address mask and size definitions. */ #define SECTION_SHIFT 21 #define SECTION_SIZE (1UL << SECTION_SHIFT) -#define SECTION_MASK (~(SECTION_SIZE-1)) +#define SECTION_MASK (~((1 << SECTION_SHIFT) - 1)) #define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE) /* + * Hugetlb definitions. + */ +#define HPAGE_SHIFT PMD_SHIFT +#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE - 1)) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) + +/* * "Linux" PTE definitions for LPAE. * * These bits overlap with the hardware bits but the naming is preserved for @@ -79,6 +87,9 @@ #define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) /* unused */ #define L_PTE_NONE (_AT(pteval_t, 1) << 57) /* PROT_NONE */ +#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55) +#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 57) + /* * To be used in assembly code with the upper page attributes. */ @@ -86,6 +97,11 @@ #define L_PTE_DIRTY_HIGH (1 << (55 - 32)) /* + * we need to mask off PTE_EXT_NG when comparing present ptes. + */ +#define L_PTE_CMP_MASKOFF PTE_EXT_NG + +/* * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). */ #define L_PTE_MT_UNCACHED (_AT(pteval_t, 0) << 2) /* strongly ordered */ @@ -150,6 +166,67 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,__pte(pte_val(pte)|(ext))) +#define pte_huge(pte) ((pte_val(pte) & PMD_TYPE_MASK) == PMD_TYPE_SECT) + +#define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PMD_TYPE_MASK) | PMD_TYPE_SECT)) + + +#define pmd_present(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) != PMD_TYPE_FAULT) +#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF) + +#define __HAVE_ARCH_PMD_WRITE +#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY)) + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define pmd_trans_huge(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) +#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING) +#endif + +#define PMD_BIT_FUNC(fn,op) \ +static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; } + +PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY); +PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF); +PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING); +PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY); +PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY); +PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF); +PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK); + +#define pmd_mkhuge(pmd) (__pmd((pmd_val(pmd) & ~PMD_TYPE_MASK) | PMD_TYPE_SECT)) + +#define pmd_pfn(pmd) ((pmd_val(pmd) & PHYS_MASK) >> PAGE_SHIFT) +#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) +#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot) + +#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) + +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +{ + const pmdval_t mask = PMD_SECT_USER | PMD_SECT_XN | PMD_SECT_RDONLY; + pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask); + return pmd; +} + +static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) +{ + *pmdp = pmd; +} + +static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp, pmd_t pmd) +{ + BUG_ON(addr >= TASK_SIZE); + pmd = __pmd(pmd_val(pmd) | PMD_SECT_nG); + set_pmd(pmdp, pmd); + flush_pmd_entry(pmdp); +} + +static inline int has_transparent_hugepage(void) +{ + return 1; +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_PGTABLE_3LEVEL_H */ diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 9c82f988c0e..529ceae8d98 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -24,6 +24,9 @@ #include <asm/memory.h> #include <asm/pgtable-hwdef.h> + +#include <asm/tlbflush.h> + #ifdef CONFIG_ARM_LPAE #include <asm/pgtable-3level.h> #else @@ -163,15 +166,17 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) #define pmd_none(pmd) (!pmd_val(pmd)) -#define pmd_present(pmd) (pmd_val(pmd)) static inline pte_t *pmd_page_vaddr(pmd_t pmd) { +#ifdef SYS_SUPPORTS_HUGETLBFS + if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT) + return __va(pmd_val(pmd) & HPAGE_MASK); +#endif + return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); } -#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) - #ifndef CONFIG_HIGHPTE #define __pte_map(pmd) pmd_page_vaddr(*(pmd)) #define __pte_unmap(pte) do { } while (0) @@ -246,6 +251,29 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) } /* + * For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes + * that are written to a page table but not for ptes created with mk_pte. + * + * This can cause some comparison tests made by pte_same to fail spuriously and + * lead to other problems. + * + * To correct this behaviour, we mask off PTE_EXT_NG for any pte that is + * present before running the comparison. + */ +#define __HAVE_ARCH_PTE_SAME +static inline int pte_same(pte_t pte_a, pte_t pte_b) +{ + pteval_t vala = pte_val(pte_a), valb = pte_val(pte_b); + if (pte_present(pte_a)) + vala &= ~L_PTE_CMP_MASKOFF; + + if (pte_present(pte_b)) + valb &= ~L_PTE_CMP_MASKOFF; + + return vala == valb; +} + +/* * Encode and decode a swap entry. Swap entries are stored in the Linux * page tables as follows: * diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h index f3628fb3d2b..2d270b8c6e1 100644 --- a/arch/arm/include/asm/proc-fns.h +++ b/arch/arm/include/asm/proc-fns.h @@ -60,7 +60,7 @@ extern struct processor { /* * Set the page table */ - void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm); + void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm); /* * Set a possibly extended PTE. Non-extended PTEs should * ignore 'ext'. @@ -82,7 +82,7 @@ extern void cpu_proc_init(void); extern void cpu_proc_fin(void); extern int cpu_do_idle(void); extern void cpu_dcache_clean_area(void *, int); -extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); +extern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm); #ifdef CONFIG_ARM_LPAE extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte); #else @@ -116,13 +116,27 @@ extern void cpu_resume(void); #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm) #ifdef CONFIG_ARM_LPAE + +#define cpu_get_ttbr(nr) \ + ({ \ + u64 ttbr; \ + __asm__("mrrc p15, " #nr ", %Q0, %R0, c2" \ + : "=r" (ttbr) \ + : : ); \ + ttbr; \ + }) + +#define cpu_set_ttbr(nr, val) \ + do { \ + u64 ttbr = val; \ + __asm__("mcrr p15, " #nr ", %Q0, %R0, c2" \ + : : "r" (ttbr) \ + : "cc"); \ + } while (0) + #define cpu_get_pgd() \ ({ \ - unsigned long pg, pg2; \ - __asm__("mrrc p15, 0, %0, %1, c2" \ - : "=r" (pg), "=r" (pg2) \ - : \ - : "cc"); \ + u64 pg = cpu_get_ttbr(0); \ pg &= ~(PTRS_PER_PGD*sizeof(pgd_t)-1); \ (pgd_t *)phys_to_virt(pg); \ }) diff --git a/arch/arm/include/asm/runtime-patch.h b/arch/arm/include/asm/runtime-patch.h new file mode 100644 index 00000000000..366444d7eef --- /dev/null +++ b/arch/arm/include/asm/runtime-patch.h @@ -0,0 +1,208 @@ +/* + * arch/arm/include/asm/runtime-patch.h + * Note: this file should not be included by non-asm/.h files + * + * Copyright 2012 Texas Instruments, Inc. + * + * 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_ARM_RUNTIME_PATCH_H +#define __ASM_ARM_RUNTIME_PATCH_H + +#include <linux/stringify.h> + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_ARM_RUNTIME_PATCH + +struct patch_info { + void *insn; + u16 type; + u8 insn_size; + u8 data_size; + u32 data[0]; +}; + +#define PATCH_IMM8 0x0001 +struct patch_info_imm8 { + u32 *imm; + u32 insn; +}; + +#define patch_next(p) ((void *)(p) + sizeof(*(p)) + (p)->data_size) +#define patch_data(p) ((void *)&(p)->data[0]) + +#define patch_stub(type, code, patch_data, ...) \ + __asm__("@ patch stub\n" \ + "1:\n" \ + code \ + "2:\n" \ + " .pushsection .runtime.patch.table, \"a\"\n" \ + "3:\n" \ + " .word 1b\n" \ + " .hword (" __stringify(type) ")\n" \ + " .byte (2b-1b)\n" \ + " .byte (5f-4f)\n" \ + "4:\n" \ + patch_data \ + " .align\n" \ + "5:\n" \ + " .popsection\n" \ + __VA_ARGS__) + +#define early_patch_stub(type, code, pad, patch_data, ...) \ + __asm__("@ patch stub\n" \ + "1:\n" \ + " b 6f\n" \ + " .fill " __stringify(pad) ", 1, 0\n" \ + "2:\n" \ + " .pushsection .runtime.patch.table, \"a\"\n" \ + "3:\n" \ + " .word 1b\n" \ + " .hword (" __stringify(type) ")\n" \ + " .byte (2b-1b)\n" \ + " .byte (5f-4f)\n" \ + "4:\n" \ + patch_data \ + " .align\n" \ + "5:\n" \ + " .popsection\n" \ + " .pushsection .runtime.patch.code, \"ax\"\n" \ + "6:\n" \ + code \ + " b 2b\n" \ + " .popsection\n" \ + __VA_ARGS__) + +/* constant used to force encoding */ +#define __IMM8 (0x81 << 24) + +/* + * patch_imm8() - init-time specialized binary operation (imm8 operand) + * This effectively does: to = from "insn" sym, + * where the value of sym is fixed at init-time, and is patched + * in as an immediate operand. This value must be + * representible as an 8-bit quantity with an optional + * rotation. + * + * The stub code produced by this variant is non-functional + * prior to patching. Use early_patch_imm8() if you need the + * code to be functional early on in the init sequence. + */ +#define patch_imm8(_insn, _to, _from, _sym, _ofs) \ + patch_stub( \ + /* type */ \ + PATCH_IMM8, \ + /* code */ \ + _insn " %[to], %[from], %[imm]\n", \ + /* patch_data */ \ + ".long " __stringify(_sym + _ofs) "\n" \ + _insn " %[to], %[from], %[imm]\n", \ + /* operands */ \ + : [to] "=r" (_to) \ + : [from] "r" (_from), \ + [imm] "I" (__IMM8), \ + "i" (&(_sym)) \ + : "cc") + +/* + * patch_imm8_mov() - same as patch_imm8(), but for mov/mvn instructions + */ +#define patch_imm8_mov(_insn, _to, _sym, _ofs) \ + patch_stub( \ + /* type */ \ + PATCH_IMM8, \ + /* code */ \ + _insn " %[to], %[imm]\n", \ + /* patch_data */ \ + ".long " __stringify(_sym + _ofs) "\n" \ + _insn " %[to], %[imm]\n", \ + /* operands */ \ + : [to] "=r" (_to) \ + : [imm] "I" (__IMM8), \ + "i" (&(_sym)) \ + : "cc") + +/* + * early_patch_imm8() - early functional variant of patch_imm8() above. The + * same restrictions on the constant apply here. This + * version emits workable (albeit inefficient) code at + * compile-time, and therefore functions even prior to + * patch application. + */ +#define early_patch_imm8(_insn, _to, _from, _sym, _ofs) \ +do { \ + unsigned long __tmp; \ + early_patch_stub( \ + /* type */ \ + PATCH_IMM8, \ + /* code */ \ + "ldr %[tmp], =" __stringify(_sym + _ofs) "\n"\ + "ldr %[tmp], [%[tmp]]\n" \ + _insn " %[to], %[from], %[tmp]\n", \ + /* pad */ \ + 0, \ + /* patch_data */ \ + ".long " __stringify(_sym + _ofs) "\n" \ + _insn " %[to], %[from], %[imm]\n", \ + /* operands */ \ + : [to] "=r" (_to), \ + [tmp] "=&r" (__tmp) \ + : [from] "r" (_from), \ + [imm] "I" (__IMM8), \ + "i" (&(_sym)) \ + : "cc"); \ +} while (0) + +#define early_patch_imm8_mov(_insn, _to, _sym, _ofs) \ +do { \ + unsigned long __tmp; \ + early_patch_stub( \ + /* type */ \ + PATCH_IMM8 \ + /* code */ \ + "ldr %[tmp], =" __stringify(_sym + _ofs) "\n"\ + "ldr %[tmp], [%[tmp]]\n" \ + _insn " %[to], %[tmp]\n", \ + /* pad */ \ + 0, \ + /* patch_data */ \ + ".long " __stringify(_sym + _ofs) "\n" \ + _insn " %[to], %[imm]\n", \ + /* operands */ \ + : [to] "=r" (_to), \ + [tmp] "=&r" (__tmp) \ + : [imm] "I" (__IMM8), \ + "i" (&(_sym)) \ + : "cc"); \ +} while (0) + +int runtime_patch(const void *table, unsigned size); +void runtime_patch_kernel(void); + +#else + +static inline int runtime_patch(const void *table, unsigned size) +{ + return 0; +} + +static inline void runtime_patch_kernel(void) +{ +} + +#endif /* CONFIG_ARM_RUNTIME_PATCH */ + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_ARM_RUNTIME_PATCH_H */ diff --git a/arch/arm/include/asm/tlb.h b/arch/arm/include/asm/tlb.h index 99a19512ee2..0fc2d9d3503 100644 --- a/arch/arm/include/asm/tlb.h +++ b/arch/arm/include/asm/tlb.h @@ -92,10 +92,16 @@ static inline void tlb_flush(struct mmu_gather *tlb) static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr) { if (!tlb->fullmm) { + unsigned long size = PAGE_SIZE; + if (addr < tlb->range_start) tlb->range_start = addr; - if (addr + PAGE_SIZE > tlb->range_end) - tlb->range_end = addr + PAGE_SIZE; + + if (tlb->vma && is_vm_hugetlb_page(tlb->vma)) + size = HPAGE_SIZE; + + if (addr + size > tlb->range_end) + tlb->range_end = addr + size; } } @@ -223,6 +229,12 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, #endif } +static inline void +tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr) +{ + tlb_add_flush(tlb, addr); +} + #define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr) #define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr) #define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp) diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h index 6e924d3a77e..907cede92e8 100644 --- a/arch/arm/include/asm/tlbflush.h +++ b/arch/arm/include/asm/tlbflush.h @@ -505,6 +505,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, } #endif +#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) + #endif #endif /* CONFIG_MMU */ diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index 983fa7c153a..5357eb195d1 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -68,6 +68,21 @@ static inline int cluster_to_logical_mask(unsigned int socket_id, #endif +#ifdef CONFIG_NUMA + +static inline int cpu_to_node(int cpu) +{ + return numa_cpu_lookup_table[cpu]; +} + +#define cpumask_of_node(node) ((node) == -1 ? \ + cpu_all_mask : \ + node_to_cpumask_map[node]) + +#define parent_node(node) (node) + +#endif /* CONFIG_NUMA */ + #include <asm-generic/topology.h> #endif /* _ASM_ARM_TOPOLOGY_H */ diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h index 21a2700d295..16f45f673f6 100644 --- a/arch/arm/include/asm/unistd.h +++ b/arch/arm/include/asm/unistd.h @@ -15,7 +15,7 @@ #include <uapi/asm/unistd.h> -#define __NR_syscalls (380) +#define __NR_syscalls (384) #define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0) #define __ARCH_WANT_STAT64 diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h index 4da7cde70b5..3d97a64aede 100644 --- a/arch/arm/include/uapi/asm/unistd.h +++ b/arch/arm/include/uapi/asm/unistd.h @@ -406,6 +406,7 @@ #define __NR_process_vm_writev (__NR_SYSCALL_BASE+377) /* 378 for kcmp */ #define __NR_finit_module (__NR_SYSCALL_BASE+379) +#define __NR_migrate_pages (__NR_SYSCALL_BASE+380) /* * This may need to be greater than __NR_last_syscall+1 in order to diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5bbec7b8183..47868ae4e48 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -80,6 +80,7 @@ endif head-y := head$(MMUEXT).o obj-$(CONFIG_DEBUG_LL) += debug.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_ARM_RUNTIME_PATCH) += runtime-patch.o patch.o obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 60d3b738d42..6b388f88116 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -152,7 +152,3 @@ EXPORT_SYMBOL(mcount); #endif EXPORT_SYMBOL(__gnu_mcount_nc); #endif - -#ifdef CONFIG_ARM_PATCH_PHYS_VIRT -EXPORT_SYMBOL(__pv_phys_offset); -#endif diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index a4fda4e7a37..d2fd9d4e5d2 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -389,6 +389,7 @@ CALL(sys_process_vm_writev) CALL(sys_ni_syscall) /* reserved for sys_kcmp */ CALL(sys_finit_module) + CALL(sys_migrate_pages) #ifndef syscalls_counted .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls #define syscalls_counted diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 4eee351f466..fefa44070a5 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -121,7 +121,7 @@ ENTRY(stext) bl __fixup_smp #endif #ifdef CONFIG_ARM_PATCH_PHYS_VIRT - bl __fixup_pv_table + bl __fixup_pv_offsets #endif bl __create_page_tables @@ -156,7 +156,7 @@ ENDPROC(stext) * * Returns: * r0, r3, r5-r7 corrupted - * r4 = physical page table address + * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) */ __create_page_tables: pgtbl r4, r8 @ page table address @@ -310,6 +310,7 @@ __create_page_tables: #endif #ifdef CONFIG_ARM_LPAE sub r4, r4, #0x1000 @ point to the PGD table + mov r4, r4, lsr #ARCH_PGD_SHIFT #endif mov pc, lr ENDPROC(__create_page_tables) @@ -387,7 +388,7 @@ __secondary_data: * r0 = cp#15 control register * r1 = machine ID * r2 = atags or dtb pointer - * r4 = page table pointer + * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h) * r9 = processor ID * r13 = *virtual* address to jump to upon completion */ @@ -406,17 +407,22 @@ __enable_mmu: #ifdef CONFIG_CPU_ICACHE_DISABLE bic r0, r0, #CR_I #endif -#ifdef CONFIG_ARM_LPAE - mov r5, #0 - mcrr p15, 0, r4, r5, c2 @ load TTBR0 -#else +#ifndef CONFIG_ARM_LPAE +#ifndef CONFIG_SYS_SUPPORTS_HUGETLBFS mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT)) +#else + @ set ourselves as the client in all domains + @ this allows us to then use the 4 domain bits in the + @ section descriptors in our transparent huge pages + ldr r5, =0x55555555 +#endif /* CONFIG_SYS_SUPPORTS_HUGETLBFS */ + mcr p15, 0, r5, c3, c0, 0 @ load domain access register mcr p15, 0, r4, c2, c0, 0 @ load page table pointer -#endif +#endif /* CONFIG_ARM_LPAE */ b __turn_mmu_on ENDPROC(__enable_mmu) @@ -519,92 +525,33 @@ ENDPROC(fixup_smp) #ifdef CONFIG_ARM_PATCH_PHYS_VIRT -/* __fixup_pv_table - patch the stub instructions with the delta between - * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and - * can be expressed by an immediate shifter operand. The stub instruction - * has a form of '(add|sub) rd, rn, #imm'. +/* + * __fixup_pv_offsets - update __pv_offset and __pv_phys_offset based on the + * runtime location of the kernel. */ __HEAD -__fixup_pv_table: +__fixup_pv_offsets: adr r0, 1f - ldmia r0, {r3-r5, r7} + ldmia r0, {r3-r6} sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET - add r4, r4, r3 @ adjust table start address - add r5, r5, r3 @ adjust table end address - add r7, r7, r3 @ adjust __pv_phys_offset address - str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset - mov r6, r3, lsr #24 @ constant for add/sub instructions - teq r3, r6, lsl #24 @ must be 16MiB aligned -THUMB( it ne @ cross section branch ) - bne __error - str r6, [r7, #4] @ save to __pv_offset - b __fixup_a_pv_table -ENDPROC(__fixup_pv_table) + add r4, r4, r3 @ virt_to_phys(__pv_phys_offset) + add r5, r5, r3 @ virt_to_phys(__pv_offset) + add r6, r6, r3 @ virt_to_phys(PAGE_OFFSET) = PHYS_OFFSET + str r6, [r4] @ save __pv_phys_offset + str r3, [r5] @ save __pv_offset + mov pc, lr +ENDPROC(__fixup_pv_offsets) .align 1: .long . - .long __pv_table_begin - .long __pv_table_end -2: .long __pv_phys_offset - - .text -__fixup_a_pv_table: -#ifdef CONFIG_THUMB2_KERNEL - lsls r6, #24 - beq 2f - clz r7, r6 - lsr r6, #24 - lsl r6, r7 - bic r6, #0x0080 - lsrs r7, #1 - orrcs r6, #0x0080 - orr r6, r6, r7, lsl #12 - orr r6, #0x4000 - b 2f -1: add r7, r3 - ldrh ip, [r7, #2] - and ip, 0x8f00 - orr ip, r6 @ mask in offset bits 31-24 - strh ip, [r7, #2] -2: cmp r4, r5 - ldrcc r7, [r4], #4 @ use branch for delay slot - bcc 1b - bx lr +#if defined(CONFIG_ARM_LPAE) && defined(__ARMEB__) + .long __pv_phys_offset + 4 #else - b 2f -1: ldr ip, [r7, r3] - bic ip, ip, #0x000000ff - orr ip, ip, r6 @ mask in offset bits 31-24 - str ip, [r7, r3] -2: cmp r4, r5 - ldrcc r7, [r4], #4 @ use branch for delay slot - bcc 1b - mov pc, lr + .long __pv_phys_offset #endif -ENDPROC(__fixup_a_pv_table) - -ENTRY(fixup_pv_table) - stmfd sp!, {r4 - r7, lr} - ldr r2, 2f @ get address of __pv_phys_offset - mov r3, #0 @ no offset - mov r4, r0 @ r0 = table start - add r5, r0, r1 @ r1 = table size - ldr r6, [r2, #4] @ get __pv_offset - bl __fixup_a_pv_table - ldmfd sp!, {r4 - r7, pc} -ENDPROC(fixup_pv_table) - - .align -2: .long __pv_phys_offset - - .data - .globl __pv_phys_offset - .type __pv_phys_offset, %object -__pv_phys_offset: - .long 0 - .size __pv_phys_offset, . - __pv_phys_offset -__pv_offset: - .long 0 + .long __pv_offset + .long PAGE_OFFSET #endif + #include "head-common.S" diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 1e9be5d25e5..bd8a860422a 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -24,6 +24,7 @@ #include <asm/sections.h> #include <asm/smp_plat.h> #include <asm/unwind.h> +#include <asm/runtime-patch.h> #ifdef CONFIG_XIP_KERNEL /* @@ -272,6 +273,7 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod) { const Elf_Shdr *s = NULL; + int err; #ifdef CONFIG_ARM_UNWIND const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; @@ -316,11 +318,12 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, maps[i].txt_sec->sh_addr, maps[i].txt_sec->sh_size); #endif -#ifdef CONFIG_ARM_PATCH_PHYS_VIRT - s = find_mod_section(hdr, sechdrs, ".pv_table"); - if (s) - fixup_pv_table((void *)s->sh_addr, s->sh_size); -#endif + s = find_mod_section(hdr, sechdrs, ".runtime.patch.table"); + if (s) { + err = runtime_patch((void *)s->sh_addr, s->sh_size); + if (err) + return err; + } s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); if (s && !is_smp()) #ifdef CONFIG_SMP_ON_UP diff --git a/arch/arm/kernel/runtime-patch.c b/arch/arm/kernel/runtime-patch.c new file mode 100644 index 00000000000..0be9ef314a3 --- /dev/null +++ b/arch/arm/kernel/runtime-patch.c @@ -0,0 +1,268 @@ +/* + * arch/arm/kernel/runtime-patch.c + * + * Copyright 2012 Texas Instruments, Inc. + * + * 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/kernel.h> +#include <linux/sched.h> + +#include <asm/opcodes.h> +#include <asm/cacheflush.h> +#include <asm/runtime-patch.h> + +#include "patch.h" + +static inline void flush_icache_insn(void *insn_ptr, int bytes) +{ + unsigned long insn_addr = (unsigned long)insn_ptr; + flush_icache_range(insn_addr, insn_addr + bytes - 1); +} + +#ifdef CONFIG_THUMB2_KERNEL + +static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn) +{ + u32 op, rot, val; + const u32 supported_ops = (BIT(0) | /* and */ + BIT(1) | /* bic */ + BIT(2) | /* orr/mov */ + BIT(3) | /* orn/mvn */ + BIT(4) | /* eor */ + BIT(8) | /* add */ + BIT(10) | /* adc */ + BIT(11) | /* sbc */ + BIT(12) | /* sub */ + BIT(13)); /* rsb */ + + insn = __mem_to_opcode_thumb32(insn); + + if (!__opcode_is_thumb32(insn)) { + pr_err("patch: invalid thumb2 insn %08x\n", insn); + return -EINVAL; + } + + /* allow only data processing (immediate) + * 1111 0x0x xxx0 xxxx 0xxx xxxx xxxx xxxx */ + if ((insn & 0xfa008000) != 0xf0000000) { + pr_err("patch: unknown insn %08x\n", insn); + return -EINVAL; + } + + /* extract op code */ + op = (insn >> 21) & 0xf; + + /* disallow unsupported opcodes */ + if ((supported_ops & BIT(op)) == 0) { + pr_err("patch: unsupported opcode %x\n", op); + return -EINVAL; + } + + if (imm <= 0xff) { + rot = 0; + val = imm; + } else { + rot = 32 - fls(imm); /* clz */ + if (imm & ~(0xff000000 >> rot)) { + pr_err("patch: constant overflow %08x\n", imm); + return -EINVAL; + } + val = (imm >> (24 - rot)) & 0x7f; + rot += 8; /* encoded i:imm3:a */ + + /* pack least-sig rot bit into most-sig val bit */ + val |= (rot & 1) << 7; + rot >>= 1; + } + + *ninsn = insn & ~(BIT(26) | 0x7 << 12 | 0xff); + *ninsn |= (rot >> 3) << 26; /* field "i" */ + *ninsn |= (rot & 0x7) << 12; /* field "imm3" */ + *ninsn |= val; + + return 0; +} + +#else + +static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn) +{ + u32 rot, val, op; + + insn = __mem_to_opcode_arm(insn); + + /* disallow special unconditional instructions + * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx */ + if ((insn >> 24) == 0xf) { + pr_err("patch: unconditional insn %08x\n", insn); + return -EINVAL; + } + + /* allow only data processing (immediate) + * xxxx 001x xxxx xxxx xxxx xxxx xxxx xxxx */ + if (((insn >> 25) & 0x3) != 1) { + pr_err("patch: unknown insn %08x\n", insn); + return -EINVAL; + } + + /* extract op code */ + op = (insn >> 20) & 0x1f; + + /* disallow unsupported 10xxx op codes */ + if (((op >> 3) & 0x3) == 2) { + pr_err("patch: unsupported opcode %08x\n", insn); + return -EINVAL; + } + + rot = imm ? __ffs(imm) / 2 : 0; + val = imm >> (rot * 2); + rot = (-rot) & 0xf; + + /* does this fit in 8-bit? */ + if (val > 0xff) { + pr_err("patch: constant overflow %08x\n", imm); + return -EINVAL; + } + + /* patch in new immediate and rotation */ + *ninsn = (insn & ~0xfff) | (rot << 8) | val; + + return 0; +} + +#endif /* CONFIG_THUMB2_KERNEL */ + +static int apply_patch_imm8(const struct patch_info *p) +{ + u32 *insn_ptr = p->insn, ninsn; + int count = p->insn_size / sizeof(u32); + const struct patch_info_imm8 *info; + int err; + + + if (count <= 0 || p->data_size != count * sizeof(*info)) { + pr_err("patch: bad patch, insn size %d, data size %d\n", + p->insn_size, p->data_size); + return -EINVAL; + } + + for (info = patch_data(p); count; count--, info++, insn_ptr++) { + err = do_patch_imm8(info->insn, *info->imm, &ninsn); + if (err) + return err; + __patch_text(insn_ptr, ninsn); + } + + + return 0; +} + +#ifdef CONFIG_ARM_RUNTIME_PATCH_TEST + +struct patch_test_imm8 { + u16 imm; + u16 shift; + u32 insn; +}; + +static void __init __used __naked __patch_test_code_imm8(void) +{ + __asm__ __volatile__ ( + + /* a single test case */ + " .macro test_one, imm, sft\n" + " .hword \\imm\n" + " .hword \\sft\n" + " add r1, r2, #(\\imm << \\sft)\n" + " .endm\n" + + /* a sequence of tests at 'inc' increments of shift */ + " .macro test_seq, imm, sft, max, inc\n" + " test_one \\imm, \\sft\n" + " .if \\sft < \\max\n" + " test_seq \\imm, (\\sft + \\inc), \\max, \\inc\n" + " .endif\n" + " .endm\n" + + /* an empty record to mark the end */ + " .macro test_end\n" + " .hword 0, 0\n" + " .word 0\n" + " .endm\n" + + /* finally generate the test sequences */ + " test_seq 0x41, 0, 24, 1\n" + " test_seq 0x81, 0, 24, 2\n" + " test_end\n" + : : : "r1", "r2", "cc"); +} + +static void __init test_patch_imm8(void) +{ + u32 test_code_addr = (u32)(&__patch_test_code_imm8); + struct patch_test_imm8 *test = (void *)(test_code_addr & ~1); + u32 ninsn, insn, patched_insn; + int i, err; + + insn = test[0].insn; + for (i = 0; test[i].insn; i++) { + err = do_patch_imm8(insn, test[i].imm << test[i].shift, &ninsn); + __patch_text(&patched_insn, ninsn); + + if (err) { + pr_err("rtpatch imm8: failed at imm %x, shift %d\n", + test[i].imm, test[i].shift); + } else if (patched_insn != test[i].insn) { + pr_err("rtpatch imm8: failed, need %x got %x\n", + test[i].insn, patched_insn); + } else { + pr_debug("rtpatch imm8: imm %x, shift %d, %x -> %x\n", + test[i].imm, test[i].shift, insn, + patched_insn); + } + } +} + +static void __init runtime_patch_test(void) +{ + test_patch_imm8(); +} +#endif + +int runtime_patch(const void *table, unsigned size) +{ + const struct patch_info *p = table, *end = (table + size); + + for (p = table; p < end; p = patch_next(p)) { + int err = -EINVAL; + + if (p->type == PATCH_IMM8) + err = apply_patch_imm8(p); + if (err) + return err; + } + return 0; +} + +void __init runtime_patch_kernel(void) +{ + extern unsigned __runtime_patch_table_begin, __runtime_patch_table_end; + const void *start = &__runtime_patch_table_begin; + const void *end = &__runtime_patch_table_end; + +#ifdef CONFIG_ARM_RUNTIME_PATCH_TEST + runtime_patch_test(); +#endif + BUG_ON(runtime_patch(start, end - start)); +} diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 452a6124c4f..a47e3680b11 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -54,6 +54,7 @@ #include <asm/unwind.h> #include <asm/memblock.h> #include <asm/virt.h> +#include <asm/runtime-patch.h> #include "atags.h" #include "tcm.h" @@ -143,6 +144,19 @@ static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', ' DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data); +#ifdef CONFIG_ARM_PATCH_PHYS_VIRT + +/* + * These are initialized in head.S code prior to BSS getting cleared out. + * The initializers here prevent these from landing in the BSS section. + */ +unsigned long __pv_offset = 0xdeadbeef; +EXPORT_SYMBOL(__pv_offset); +phys_addr_t __pv_phys_offset = 0xdeadbeef; +EXPORT_SYMBOL(__pv_phys_offset); + +#endif + /* * Standard memory resources */ @@ -810,6 +824,8 @@ void __init setup_arch(char **cmdline_p) if (mdesc->init_early) mdesc->init_early(); + + runtime_patch_kernel(); } @@ -817,6 +833,12 @@ static int __init topology_init(void) { int cpu; +#ifdef CONFIG_NUMA + int node; + for_each_online_node(node) + register_one_node(node); +#endif + for_each_possible_cpu(cpu) { struct cpuinfo_arm *cpuinfo = &per_cpu(cpu_data, cpu); cpuinfo->cpu.hotpluggable = 1; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index c115ab3c27f..2477225c33c 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -71,6 +71,13 @@ enum ipi_msg_type { static DECLARE_COMPLETION(cpu_running); +static unsigned long get_arch_pgd(pgd_t *pgd) +{ + phys_addr_t pgdir = virt_to_phys(pgd); + BUG_ON(pgdir & ARCH_PGD_MASK); + return pgdir >> ARCH_PGD_SHIFT; +} + static struct smp_operations smp_ops; void __init smp_set_ops(struct smp_operations *ops) @@ -88,8 +95,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) * its stack and the page tables. */ secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; - secondary_data.pgdir = virt_to_phys(idmap_pgd); - secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir); + secondary_data.pgdir = get_arch_pgd(idmap_pgd); + secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir); __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data)); outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1)); diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 11c1785bf63..88c7f2f5100 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -173,10 +173,15 @@ SECTIONS __smpalt_end = .; } #endif - .init.pv_table : { - __pv_table_begin = .; - *(.pv_table) - __pv_table_end = .; + .init.runtime_patch_table : { + __runtime_patch_table_begin = .; + *(.runtime.patch.table) + __runtime_patch_table_end = .; + } + .init.runtime_patch_code : { + __runtime_patch_code_begin = .; + *(.runtime.patch.code) + __runtime_patch_code_end = .; } .init.data : { #ifndef CONFIG_XIP_KERNEL diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index e103c290bc9..46600332be1 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -332,6 +332,7 @@ config MACH_ORIGEN select CPU_EXYNOS4210 select EXYNOS4_DEV_USB_OHCI select EXYNOS4_SETUP_FIMD0 + select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_SDHCI select EXYNOS4_SETUP_USB_PHY select EXYNOS_DEV_DMA @@ -340,7 +341,9 @@ config MACH_ORIGEN select S3C24XX_PWM select S3C_DEV_HSMMC select S3C_DEV_HSMMC2 + select S3C_DEV_HSMMC3 select S3C_DEV_RTC + select S3C_DEV_I2C1 select S3C_DEV_USB_HSOTG select S3C_DEV_WDT select S5P_DEV_FIMC0 @@ -349,6 +352,7 @@ config MACH_ORIGEN select S5P_DEV_FIMC3 select S5P_DEV_FIMD0 select S5P_DEV_G2D + select S5P_DEV_G3D select S5P_DEV_I2C_HDMIPHY select S5P_DEV_JPEG select S5P_DEV_MFC @@ -416,6 +420,8 @@ config MACH_EXYNOS4_DT select PINCTRL select PINCTRL_EXYNOS4 select USE_OF + select SAMSUNG_DEV_BACKLIGHT + select SAMSUNG_DEV_PWM help Machine support for Samsung Exynos4 machine with device tree enabled. Select this if a fdt blob is available for the Exynos4 SoC based board. @@ -428,6 +434,8 @@ config MACH_EXYNOS5_DT depends on ARCH_EXYNOS5 select ARM_AMBA select USE_OF + select EXYNOS4_SETUP_USB_PHY + select USB_ARCH_HAS_XHCI help Machine support for Samsung EXYNOS5 machine with device tree enabled. Select this if a fdt blob is available for the EXYNOS5 SoC based board. diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c index bbcb3dea0d4..c125dd73978 100644 --- a/arch/arm/mach-exynos/clock-exynos4.c +++ b/arch/arm/mach-exynos/clock-exynos4.c @@ -23,14 +23,28 @@ #include <plat/pm.h> #include <mach/map.h> +#include <mach/regs-audss.h> #include <mach/regs-clock.h> #include <mach/sysmmu.h> #include "common.h" #include "clock-exynos4.h" +/* For vpll */ +struct vpll_div_data { + u32 rate; + u32 pdiv; + u32 mdiv; + u32 sdiv; + u32 k; + u32 mfr; + u32 mrr; + u32 vsel; +}; + #ifdef CONFIG_PM_SLEEP static struct sleep_save exynos4_clock_save[] = { + SAVE_ITEM(EXYNOS4_CLKSRC_AUDSS), SAVE_ITEM(EXYNOS4_CLKDIV_LEFTBUS), SAVE_ITEM(EXYNOS4_CLKGATE_IP_LEFTBUS), SAVE_ITEM(EXYNOS4_CLKDIV_RIGHTBUS), @@ -118,6 +132,15 @@ static struct clk dummy_apb_pclk = { .id = -1, }; +static struct clk exynos4_clk_xxti = { + .name = "xxti", +}; + +static int exynos4_clk_ip_g3d_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS4_CLKGATE_IP_G3D, clk, enable); +} + static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(EXYNOS4_CLKSRC_MASK_TOP, clk, enable); @@ -617,6 +640,11 @@ static struct clk exynos4_init_clocks_off[] = { .ctrlbit = (1 << 18), }, { .name = "iis", + .devname = "samsung-i2s.0", + .enable = exynos4_clk_ip_peril_ctrl, + .ctrlbit = (1 << 19), + }, { + .name = "iis", .devname = "samsung-i2s.1", .enable = exynos4_clk_ip_peril_ctrl, .ctrlbit = (1 << 20), @@ -823,6 +851,24 @@ static struct clk exynos4_clk_fimd0 = { .ctrlbit = (1 << 0), }; +static struct clk *exynos4_clkset_mout_audss_list[] = { + &exynos4_clk_xxti, + &clk_fout_epll, +}; + +static struct clksrc_sources exynos4_clkset_mout_audss = { + .sources = exynos4_clkset_mout_audss_list, + .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_audss_list), +}; + +static struct clksrc_clk exynos4_clk_mout_audss = { + .clk = { + .name = "busclk", + }, + .sources = &exynos4_clkset_mout_audss, + .reg_src = { .reg = EXYNOS4_CLKSRC_AUDSS, .shift = 0, .size = 1 }, +}; + struct clk *exynos4_clkset_group_list[] = { [0] = &clk_ext_xtal_mux, [1] = &clk_xusbxti, @@ -906,6 +952,52 @@ static struct clksrc_sources exynos4_clkset_mout_mfc = { .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_mfc_list), }; +static struct clk *exynos4_clkset_mout_g3d0_list[] = { + [0] = &exynos4_clk_mout_mpll.clk, + [1] = &exynos4_clk_sclk_apll.clk, +}; + +static struct clksrc_sources exynos4_clkset_mout_g3d0 = { + .sources = exynos4_clkset_mout_g3d0_list, + .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g3d0_list), +}; + +static struct clksrc_clk exynos4_clk_mout_g3d0 = { + .clk = { + .name = "mout_g3d0", + }, + .sources = &exynos4_clkset_mout_g3d0, + .reg_src = { .reg = EXYNOS4_CLKSRC_G3D, .shift = 0, .size = 1 }, +}; + +static struct clk *exynos4_clkset_mout_g3d1_list[] = { + [0] = &exynos4_clk_mout_epll.clk, + [1] = &exynos4_clk_sclk_vpll.clk, +}; + +static struct clksrc_sources exynos4_clkset_mout_g3d1 = { + .sources = exynos4_clkset_mout_g3d1_list, + .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g3d1_list), +}; + +static struct clksrc_clk exynos4_clk_mout_g3d1 = { + .clk = { + .name = "mout_g3d1", + }, + .sources = &exynos4_clkset_mout_g3d1, + .reg_src = { .reg = EXYNOS4_CLKSRC_G3D, .shift = 4, .size = 1 }, +}; + +static struct clk *exynos4_clkset_mout_g3d_list[] = { + [0] = &exynos4_clk_mout_g3d0.clk, + [1] = &exynos4_clk_mout_g3d1.clk, +}; + +static struct clksrc_sources exynos4_clkset_mout_g3d = { + .sources = exynos4_clkset_mout_g3d_list, + .nr_sources = ARRAY_SIZE(exynos4_clkset_mout_g3d_list), +}; + static struct clk *exynos4_clkset_sclk_dac_list[] = { [0] = &exynos4_clk_sclk_vpll.clk, [1] = &exynos4_clk_sclk_hdmiphy, @@ -1134,6 +1226,15 @@ static struct clksrc_clk exynos4_clksrcs[] = { .reg_div = { .reg = EXYNOS4_CLKDIV_MFC, .shift = 0, .size = 4 }, }, { .clk = { + .name = "sclk_g3d", + .enable = exynos4_clk_ip_g3d_ctrl, + .ctrlbit = (1 << 0), + }, + .sources = &exynos4_clkset_mout_g3d, + .reg_src = { .reg = EXYNOS4_CLKSRC_G3D, .shift = 8, .size = 1 }, + .reg_div = { .reg = EXYNOS4_CLKDIV_G3D, .shift = 0, .size = 4 }, + }, { + .clk = { .name = "ciu", .parent = &exynos4_clk_dout_mmc4.clk, .enable = exynos4_clksrc_mask_fsys_ctrl, @@ -1323,6 +1424,7 @@ static struct clksrc_clk *exynos4_sysclks[] = { &exynos4_clk_aclk_100, &exynos4_clk_aclk_160, &exynos4_clk_aclk_133, + &exynos4_clk_mout_audss, &exynos4_clk_dout_mmc0, &exynos4_clk_dout_mmc1, &exynos4_clk_dout_mmc2, @@ -1330,6 +1432,8 @@ static struct clksrc_clk *exynos4_sysclks[] = { &exynos4_clk_dout_mmc4, &exynos4_clk_mout_mfc0, &exynos4_clk_mout_mfc1, + &exynos4_clk_mout_g3d0, + &exynos4_clk_mout_g3d1, }; static struct clk *exynos4_clk_cdev[] = { @@ -1372,6 +1476,7 @@ static struct clk_lookup exynos4_clk_lookup[] = { CLKDEV_INIT("exynos4210-spi.0", "spi_busclk0", &exynos4_clk_sclk_spi0.clk), CLKDEV_INIT("exynos4210-spi.1", "spi_busclk0", &exynos4_clk_sclk_spi1.clk), CLKDEV_INIT("exynos4210-spi.2", "spi_busclk0", &exynos4_clk_sclk_spi2.clk), + CLKDEV_INIT("samsung-i2s.0", "i2s_opclk0", &exynos4_clk_mout_audss.clk), }; static int xtal_rate; @@ -1387,13 +1492,92 @@ static unsigned long exynos4_fout_apll_get_rate(struct clk *clk) return 0; } +static u32 exynos4_epll_div[][6] = { + { 48000000, 0, 48, 3, 3, 0 }, + { 96000000, 0, 48, 3, 2, 0 }, + { 144000000, 1, 72, 3, 2, 0 }, + { 192000000, 0, 48, 3, 1, 0 }, + { 288000000, 1, 72, 3, 1, 0 }, + { 84000000, 0, 42, 3, 2, 0 }, + { 50000000, 0, 50, 3, 3, 0 }, + { 80000000, 1, 80, 3, 3, 0 }, + { 32750000, 1, 65, 3, 4, 35127 }, + { 32768000, 1, 65, 3, 4, 35127 }, + { 49152000, 0, 49, 3, 3, 9961 }, + { 67737600, 1, 67, 3, 3, 48366 }, + { 73728000, 1, 73, 3, 3, 47710 }, + { 45158400, 0, 45, 3, 3, 10381 }, + { 45000000, 0, 45, 3, 3, 10355 }, + { 45158000, 0, 45, 3, 3, 10355 }, + { 49125000, 0, 49, 3, 3, 9961 }, + { 67738000, 1, 67, 3, 3, 48366 }, + { 73800000, 1, 73, 3, 3, 47710 }, + { 36000000, 1, 32, 3, 4, 0 }, + { 60000000, 1, 60, 3, 3, 0 }, + { 72000000, 1, 72, 3, 3, 0 }, + { 191923200, 0, 47, 3, 1, 64278 }, + { 180633600, 0, 45, 3, 1, 10381 }, +}; + +static int exynos4_epll_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int epll_con, epll_con_k; + unsigned int i; + + /* Return if nothing changed */ + if (clk->rate == rate) + return 0; + + epll_con = __raw_readl(EXYNOS4_EPLL_CON0); + epll_con &= ~(0x1 << 27 | \ + PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT | \ + PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | \ + PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); + + for (i = 0; i < ARRAY_SIZE(exynos4_epll_div); i++) { + if (exynos4_epll_div[i][0] == rate) { + epll_con_k = exynos4_epll_div[i][5] << 0; + epll_con |= exynos4_epll_div[i][1] << 27; + epll_con |= exynos4_epll_div[i][2] << PLL46XX_MDIV_SHIFT; + epll_con |= exynos4_epll_div[i][3] << PLL46XX_PDIV_SHIFT; + epll_con |= exynos4_epll_div[i][4] << PLL46XX_SDIV_SHIFT; + break; + } + } + + if (i == ARRAY_SIZE(exynos4_epll_div)) { + printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", + __func__); + return -EINVAL; + } + + __raw_writel(epll_con, EXYNOS4_EPLL_CON0); + __raw_writel(epll_con_k, EXYNOS4_EPLL_CON1); + + clk->rate = rate; + + return 0; +} + +static struct clk_ops exynos4_epll_ops = { + .get_rate = s5p_epll_get_rate, + .set_rate = exynos4_epll_set_rate, +}; + static struct clk_ops exynos4_fout_apll_ops = { .get_rate = exynos4_fout_apll_get_rate, }; -static u32 exynos4_vpll_div[][8] = { - { 54000000, 3, 53, 3, 1024, 0, 17, 0 }, - { 108000000, 3, 53, 2, 1024, 0, 17, 0 }, +static struct vpll_div_data exynos4_vpll_div[] = { + {54000000, 2, 72, 4, 0, 0, 0, 0}, + {108000000, 2, 72, 3, 0, 0, 0, 0}, + {160000000, 3, 160, 3, 0, 0, 0, 0}, + {266000000, 3, 133, 2, 0, 0, 0, 0}, + {275000000, 2, 92, 2, 43692, 0, 0, 0}, + {300000000, 2, 100, 2, 0, 0, 0, 0}, + {333000000, 2, 111, 2, 0, 0, 0, 0}, + {350000000, 3, 175, 2, 0, 0, 0, 0}, + {440000000, 3, 110, 1, 0, 0, 0, 0}, }; static unsigned long exynos4_vpll_get_rate(struct clk *clk) @@ -1403,7 +1587,7 @@ static unsigned long exynos4_vpll_get_rate(struct clk *clk) static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate) { - unsigned int vpll_con0, vpll_con1 = 0; + unsigned int vpll_con0, vpll_con1; unsigned int i; /* Return if nothing changed */ @@ -1411,25 +1595,22 @@ static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate) return 0; vpll_con0 = __raw_readl(EXYNOS4_VPLL_CON0); - vpll_con0 &= ~(0x1 << 27 | \ - PLL90XX_MDIV_MASK << PLL46XX_MDIV_SHIFT | \ - PLL90XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | \ - PLL90XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); + vpll_con0 &= ~(PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT | \ + PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT | \ + PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT); vpll_con1 = __raw_readl(EXYNOS4_VPLL_CON1); - vpll_con1 &= ~(PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT | \ - PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT | \ - PLL4650C_KDIV_MASK << PLL46XX_KDIV_SHIFT); + vpll_con1 &= ~(0xffff << 0); for (i = 0; i < ARRAY_SIZE(exynos4_vpll_div); i++) { - if (exynos4_vpll_div[i][0] == rate) { - vpll_con0 |= exynos4_vpll_div[i][1] << PLL46XX_PDIV_SHIFT; - vpll_con0 |= exynos4_vpll_div[i][2] << PLL46XX_MDIV_SHIFT; - vpll_con0 |= exynos4_vpll_div[i][3] << PLL46XX_SDIV_SHIFT; - vpll_con1 |= exynos4_vpll_div[i][4] << PLL46XX_KDIV_SHIFT; - vpll_con1 |= exynos4_vpll_div[i][5] << PLL46XX_MFR_SHIFT; - vpll_con1 |= exynos4_vpll_div[i][6] << PLL46XX_MRR_SHIFT; - vpll_con0 |= exynos4_vpll_div[i][7] << 27; + if (exynos4_vpll_div[i].rate == rate) { + vpll_con0 |= exynos4_vpll_div[i].pdiv << + PLL36XX_PDIV_SHIFT; + vpll_con0 |= exynos4_vpll_div[i].mdiv << + PLL36XX_MDIV_SHIFT; + vpll_con0 |= exynos4_vpll_div[i].sdiv << + PLL36XX_SDIV_SHIFT; + vpll_con1 |= exynos4_vpll_div[i].k << 0; break; } } @@ -1443,11 +1624,8 @@ static int exynos4_vpll_set_rate(struct clk *clk, unsigned long rate) __raw_writel(vpll_con0, EXYNOS4_VPLL_CON0); __raw_writel(vpll_con1, EXYNOS4_VPLL_CON1); - /* Wait for VPLL lock */ - while (!(__raw_readl(EXYNOS4_VPLL_CON0) & (1 << PLL46XX_LOCKED_SHIFT))) - continue; - clk->rate = rate; + return 0; } @@ -1516,6 +1694,10 @@ void __init_or_cpufreq exynos4_setup_clocks(void) clk_fout_vpll.ops = &exynos4_vpll_ops; clk_fout_vpll.rate = vpll; + clk_fout_epll.enable = s5p_epll_enable; + clk_fout_epll.ops = &exynos4_epll_ops; + clk_set_parent(&exynos4_clk_mout_audss.clk, &clk_fout_epll); + printk(KERN_INFO "EXYNOS4: PLL settings, A=%ld, M=%ld, E=%ld V=%ld", apll, mpll, epll, vpll); diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c index e9d7b80bae4..49a20d2c05d 100644 --- a/arch/arm/mach-exynos/clock-exynos5.c +++ b/arch/arm/mach-exynos/clock-exynos5.c @@ -747,6 +747,11 @@ static struct clk exynos5_init_clocks_off[] = { .enable = exynos5_clk_ip_fsys_ctrl , .ctrlbit = (1 << 18), }, { + .name = "usbdrd30", + .parent = &exynos5_clk_aclk_200.clk, + .enable = exynos5_clk_ip_fsys_ctrl, + .ctrlbit = (1 << 19), + }, { .name = "usbotg", .enable = exynos5_clk_ip_fsys_ctrl, .ctrlbit = (1 << 7), @@ -1011,6 +1016,16 @@ static struct clksrc_sources exynos5_clkset_group = { .nr_sources = ARRAY_SIZE(exynos5_clkset_group_list), }; +struct clk *exynos5_clkset_usbdrd30_list[] = { + [0] = &exynos5_clk_mout_mpll.clk, + [1] = &exynos5_clk_mout_cpll.clk, +}; + +struct clksrc_sources exynos5_clkset_usbdrd30 = { + .sources = exynos5_clkset_usbdrd30_list, + .nr_sources = ARRAY_SIZE(exynos5_clkset_usbdrd30_list), +}; + /* Possible clock sources for aclk_266_gscl_sub Mux */ static struct clk *clk_src_gscl_266_list[] = { [0] = &clk_ext_xtal_mux, @@ -1305,7 +1320,17 @@ static struct clksrc_clk exynos5_clksrcs[] = { .parent = &exynos5_clk_mout_cpll.clk, }, .reg_div = { .reg = EXYNOS5_CLKDIV_GEN, .shift = 4, .size = 3 }, - }, + }, { + + .clk = { + .name = "sclk_usbdrd30", + .enable = exynos5_clksrc_mask_fsys_ctrl, + .ctrlbit = (1 << 28), + }, + .sources = &exynos5_clkset_usbdrd30, + .reg_src = {.reg = EXYNOS5_CLKSRC_FSYS, .shift = 28, .size = 1}, + .reg_div = {.reg = EXYNOS5_CLKDIV_FSYS0, .shift = 24, .size = 4}, + } }; /* Clock initialization code */ diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 1a89824a5f7..9f90e30134b 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -36,6 +36,7 @@ #include <mach/regs-pmu.h> #include <mach/regs-gpio.h> #include <mach/pmu.h> +#include <mach/irqs.h> #include <plat/cpu.h> #include <plat/clock.h> @@ -209,6 +210,11 @@ static struct map_desc exynos4_iodesc[] __initdata = { .length = SZ_64K, .type = MT_DEVICE, }, { + .virtual = (unsigned long)S5P_VA_AUDSS, + .pfn = __phys_to_pfn(EXYNOS4_PA_AUDSS), + .length = SZ_4K, + .type = MT_DEVICE, + }, { .virtual = (unsigned long)S3C_VA_USB_HSPHY, .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY), .length = SZ_4K, @@ -289,6 +295,11 @@ static struct map_desc exynos5440_iodesc0[] __initdata = { .pfn = __phys_to_pfn(EXYNOS5440_PA_UART0), .length = SZ_512K, .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_USB_HSPHY, + .pfn = __phys_to_pfn(EXYNOS5_PA_USB_PHY), + .length = SZ_4K, + .type = MT_DEVICE, }, }; @@ -448,6 +459,7 @@ struct combiner_chip_data { unsigned int irq_offset; unsigned int irq_mask; void __iomem *base; + unsigned int parent_irq; }; static struct irq_domain *combiner_irq_domain; @@ -504,22 +516,46 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } +#ifdef CONFIG_SMP +static int combiner_set_affinity(struct irq_data *d, + const struct cpumask *mask_val, bool force) +{ + struct combiner_chip_data *chip_data = irq_data_get_irq_chip_data(d); + struct irq_chip *chip = irq_get_chip(chip_data->parent_irq); + struct irq_data *data = irq_get_irq_data(chip_data->parent_irq); + + if (chip && chip->irq_set_affinity) + return chip->irq_set_affinity(data, mask_val, force); + else + return -EINVAL; +} +#endif + static struct irq_chip combiner_chip = { - .name = "COMBINER", - .irq_mask = combiner_mask_irq, - .irq_unmask = combiner_unmask_irq, + .name = "COMBINER", + .irq_mask = combiner_mask_irq, + .irq_unmask = combiner_unmask_irq, +#ifdef CONFIG_SMP + .irq_set_affinity = combiner_set_affinity, +#endif }; -static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq) +static unsigned int max_combiner_nr(void) { - unsigned int max_nr; - if (soc_is_exynos5250()) - max_nr = EXYNOS5_MAX_COMBINER_NR; + return EXYNOS5_MAX_COMBINER_NR; + else if (soc_is_exynos4412()) + return EXYNOS4412_MAX_COMBINER_NR; + else if (soc_is_exynos4212()) + return EXYNOS4212_MAX_COMBINER_NR; else - max_nr = EXYNOS4_MAX_COMBINER_NR; + return EXYNOS4210_MAX_COMBINER_NR; +} - if (combiner_nr >= max_nr) +static void __init combiner_cascade_irq(unsigned int combiner_nr, + unsigned int irq) +{ + if (combiner_nr >= max_combiner_nr()) BUG(); if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0) BUG(); @@ -527,12 +563,13 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i } static void __init combiner_init_one(unsigned int combiner_nr, - void __iomem *base) + void __iomem *base, unsigned int irq) { combiner_data[combiner_nr].base = base; combiner_data[combiner_nr].irq_offset = irq_find_mapping( combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER); combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); + combiner_data[combiner_nr].parent_irq = irq; /* Disable all interrupts */ __raw_writel(combiner_data[combiner_nr].irq_mask, @@ -583,23 +620,38 @@ static struct irq_domain_ops combiner_irq_domain_ops = { .map = combiner_irq_domain_map, }; +static unsigned int exynos4x12_combiner_extra_irq(int group) +{ + switch (group) { + case 16: + return IRQ_SPI(107); + case 17: + return IRQ_SPI(108); + case 18: + return IRQ_SPI(48); + case 19: + return IRQ_SPI(42); + default: + return 0; + } +} + static void __init combiner_init(void __iomem *combiner_base, struct device_node *np) { int i, irq, irq_base; unsigned int max_nr, nr_irq; + max_nr = max_combiner_nr(); + if (np) { if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { - pr_warning("%s: number of combiners not specified, " + pr_info("%s: number of combiners not specified, " "setting default as %d.\n", - __func__, EXYNOS4_MAX_COMBINER_NR); - max_nr = EXYNOS4_MAX_COMBINER_NR; + __func__, max_nr); } - } else { - max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR : - EXYNOS4_MAX_COMBINER_NR; } + nr_irq = max_nr * MAX_IRQ_IN_COMBINER; irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); @@ -616,12 +668,15 @@ static void __init combiner_init(void __iomem *combiner_base, } for (i = 0; i < max_nr; i++) { - combiner_init_one(i, combiner_base + (i >> 2) * 0x10); - irq = IRQ_SPI(i); + if (i < EXYNOS4210_MAX_COMBINER_NR || soc_is_exynos5250()) + irq = IRQ_SPI(i); + else + irq = exynos4x12_combiner_extra_irq(i); #ifdef CONFIG_OF if (np) irq = irq_of_parse_and_map(np, i); #endif + combiner_init_one(i, combiner_base + (i >> 2) * 0x10, irq); combiner_cascade_irq(i, irq); } } @@ -674,6 +729,8 @@ void __init exynos4_init_irq(void) * uses GIC instead of VIC. */ s5p_init_irq(NULL, 0); + + gic_arch_extn.irq_set_wake = s3c_irq_wake; } void __init exynos5_init_irq(void) @@ -1086,3 +1143,30 @@ static int __init exynos_init_irq_eint(void) return 0; } arch_initcall(exynos_init_irq_eint); + +static struct resource exynos4_pmu_resource[] = { + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU), + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU1), +#if defined(CONFIG_SOC_EXYNOS4412) + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU2), + DEFINE_RES_IRQ(EXYNOS4_IRQ_PMU_CPU3), +#endif +}; + +static struct platform_device exynos4_device_pmu = { + .name = "arm-pmu", + .num_resources = ARRAY_SIZE(exynos4_pmu_resource), + .resource = exynos4_pmu_resource, +}; + +static int __init exynos_armpmu_init(void) +{ + if (!of_have_populated_dt()) { + if (soc_is_exynos4210() || soc_is_exynos4212()) + exynos4_device_pmu.num_resources = 2; + platform_device_register(&exynos4_device_pmu); + } + + return 0; +} +arch_initcall(exynos_armpmu_init); diff --git a/arch/arm/mach-exynos/dev-ahci.c b/arch/arm/mach-exynos/dev-ahci.c index ce1aad3eeeb..7f3811da389 100644 --- a/arch/arm/mach-exynos/dev-ahci.c +++ b/arch/arm/mach-exynos/dev-ahci.c @@ -240,7 +240,7 @@ static struct resource exynos4_ahci_resource[] = { [1] = DEFINE_RES_IRQ(EXYNOS4_IRQ_SATA), }; -static u64 exynos4_ahci_dmamask = DMA_BIT_MASK(32); +static u64 exynos4_ahci_dmamask = DMA_BIT_MASK(64); struct platform_device exynos4_device_ahci = { .name = "ahci", @@ -250,6 +250,6 @@ struct platform_device exynos4_device_ahci = { .dev = { .platform_data = &exynos4_ahci_pdata, .dma_mask = &exynos4_ahci_dmamask, - .coherent_dma_mask = DMA_BIT_MASK(32), + .coherent_dma_mask = DMA_BIT_MASK(64), }, }; diff --git a/arch/arm/mach-exynos/dev-ohci.c b/arch/arm/mach-exynos/dev-ohci.c index 4244d02dafb..3a9c6719e80 100644 --- a/arch/arm/mach-exynos/dev-ohci.c +++ b/arch/arm/mach-exynos/dev-ohci.c @@ -25,7 +25,7 @@ static struct resource exynos4_ohci_resource[] = { [1] = DEFINE_RES_IRQ(IRQ_USB_HOST), }; -static u64 exynos4_ohci_dma_mask = DMA_BIT_MASK(32); +static u64 exynos4_ohci_dma_mask = DMA_BIT_MASK(64); struct platform_device exynos4_device_ohci = { .name = "exynos-ohci", @@ -34,7 +34,7 @@ struct platform_device exynos4_device_ohci = { .resource = exynos4_ohci_resource, .dev = { .dma_mask = &exynos4_ohci_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), + .coherent_dma_mask = DMA_BIT_MASK(64), } }; diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h index 1f4dc35cd4b..626245a38e1 100644 --- a/arch/arm/mach-exynos/include/mach/irqs.h +++ b/arch/arm/mach-exynos/include/mach/irqs.h @@ -128,7 +128,7 @@ #define EXYNOS4_IRQ_ADC1 IRQ_SPI(107) #define EXYNOS4_IRQ_PEN1 IRQ_SPI(108) #define EXYNOS4_IRQ_KEYPAD IRQ_SPI(109) -#define EXYNOS4_IRQ_PMU IRQ_SPI(110) +#define EXYNOS4_IRQ_POWER_PMU IRQ_SPI(110) #define EXYNOS4_IRQ_GPS IRQ_SPI(111) #define EXYNOS4_IRQ_INTFEEDCTRL_SSS IRQ_SPI(112) #define EXYNOS4_IRQ_SLIMBUS IRQ_SPI(113) @@ -139,6 +139,11 @@ #define EXYNOS4_IRQ_TMU_TRIG0 COMBINER_IRQ(2, 4) #define EXYNOS4_IRQ_TMU_TRIG1 COMBINER_IRQ(3, 4) +#define EXYNOS4_IRQ_PMU COMBINER_IRQ(2, 2) +#define EXYNOS4_IRQ_PMU_CPU1 COMBINER_IRQ(3, 2) +#define EXYNOS4_IRQ_PMU_CPU2 COMBINER_IRQ(18, 2) +#define EXYNOS4_IRQ_PMU_CPU3 COMBINER_IRQ(19, 2) + #define EXYNOS4_IRQ_SYSMMU_MDMA0_0 COMBINER_IRQ(4, 0) #define EXYNOS4_IRQ_SYSMMU_SSS_0 COMBINER_IRQ(4, 1) #define EXYNOS4_IRQ_SYSMMU_FIMC0_0 COMBINER_IRQ(4, 2) @@ -168,7 +173,10 @@ #define EXYNOS4_IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1) #define EXYNOS4_IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2) -#define EXYNOS4_MAX_COMBINER_NR 16 +#define EXYNOS4210_MAX_COMBINER_NR 16 +#define EXYNOS4212_MAX_COMBINER_NR 18 +#define EXYNOS4412_MAX_COMBINER_NR 20 +#define EXYNOS4_MAX_COMBINER_NR EXYNOS4412_MAX_COMBINER_NR #define EXYNOS4_IRQ_GPIO1_NR_GROUPS 16 #define EXYNOS4_IRQ_GPIO2_NR_GROUPS 9 @@ -233,7 +241,6 @@ #define IRQ_TC EXYNOS4_IRQ_PEN0 #define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD -#define IRQ_PMU EXYNOS4_IRQ_PMU #define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO #define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC @@ -464,6 +471,7 @@ #define S5P_GPIOINT_BASE (S5P_EINT_BASE1 + 32) #define IRQ_GPIO_END (S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT) #define IRQ_TIMER_BASE (IRQ_GPIO_END + 64) +#define IRQ_TS (S5P_EINT_BASE1 + 25) /* Set the default NR_IRQS */ diff --git a/arch/arm/mach-exynos/include/mach/mali/config.h b/arch/arm/mach-exynos/include/mach/mali/config.h new file mode 100644 index 00000000000..ccd3cf7d245 --- /dev/null +++ b/arch/arm/mach-exynos/include/mach/mali/config.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2010 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the EB platform with ZBT memory enabled */ +/*zepplin added 2010.08.17 for orion configuration*/ +#define MALI_BASE_ADDR 0x13000000 +#define GP_ADDR MALI_BASE_ADDR +#define L2_ADDR MALI_BASE_ADDR+0x1000 +#define PMU_ADDR MALI_BASE_ADDR+0x2000 +#define GP_MMU_ADDR MALI_BASE_ADDR+0x3000 +#define PP0_MMU_ADDR MALI_BASE_ADDR+0x4000 +#define PP1_MMU_ADDR MALI_BASE_ADDR+0x5000 +#define PP2_MMU_ADDR MALI_BASE_ADDR+0x6000 +#define PP3_MMU_ADDR MALI_BASE_ADDR+0x7000 +#define PP0_ADDR MALI_BASE_ADDR+0x8000 +#define PP1_ADDR MALI_BASE_ADDR+0xA000 +#define PP2_ADDR MALI_BASE_ADDR+0xC000 +#define PP3_ADDR MALI_BASE_ADDR+0xE000 + +/*for mmu and os memory*/ +#define MEM_BASE_ADDR 0x40000000 +#define MEM_TOTAL_SIZE 0x40000000 +#define MEM_MALI_OS_SIZE 0x18000000 + +/*for dedicated memory*/ +//#define MEM_MALI_BASE 0x58000000 +//#define MEM_MALI_SIZE 0x08000000 +#define MEM_MALI_SIZE CONFIG_MALI_MEM_SIZE*1024*1024 +#define MEM_MALI_BASE 0x60000000 - MEM_MALI_SIZE + +//#define S5P_IRQ(x) (x+32) +//#define IRQ_SPI(x) S5P_IRQ(x+32) +#define MAX_IRQ_IN_COMBINER 8 +//#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64)) +#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y) + +#define IRQ_PPMMU0_3D COMBINER_IRQ(13, 0) +#define IRQ_PPMMU1_3D COMBINER_IRQ(13, 1) +#define IRQ_PPMMU2_3D COMBINER_IRQ(13, 2) +#define IRQ_PPMMU3_3D COMBINER_IRQ(13, 3) +#define IRQ_GPMMU_3D COMBINER_IRQ(13, 4) + +#define IRQ_PP0_3D COMBINER_IRQ(14, 0) +#define IRQ_PP1_3D COMBINER_IRQ(14, 1) +#define IRQ_PP2_3D COMBINER_IRQ(14, 2) +#define IRQ_PP3_3D COMBINER_IRQ(14, 3) +#define IRQ_GP_3D COMBINER_IRQ(14, 4) +#define IRQ_PMU_3D COMBINER_IRQ(14, 5) + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = GP_ADDR, + .irq = IRQ_GP_3D, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = PP0_ADDR, + .irq = IRQ_PP0_3D, + .description = "Mali-400 PP 0", + .mmu_id = 2 + }, + { + .type = MALI400PP, + .base = PP1_ADDR, + .irq = IRQ_PP1_3D, + .description = "Mali-400 PP 1", + .mmu_id = 3 + }, + { + .type = MALI400PP, + .base = PP2_ADDR, + .irq = IRQ_PP2_3D, + .description = "Mali-400 PP 2", + .mmu_id = 4 + }, + { + .type = MALI400PP, + .base = PP3_ADDR, + .irq = IRQ_PP3_3D, + .description = "Mali-400 PP 3", + .mmu_id = 5 + }, +#if USING_MMU + { + .type = MMU, + .base = GP_MMU_ADDR, + .irq = IRQ_GPMMU_3D, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = PP0_MMU_ADDR, + .irq = IRQ_PPMMU0_3D, + .description = "Mali-400 MMU for PP 0", + .mmu_id = 2 + }, + { + .type = MMU, + .base = PP1_MMU_ADDR, + .irq = IRQ_PPMMU1_3D, + .description = "Mali-400 MMU for PP 1", + .mmu_id = 3 + }, + { + .type = MMU, + .base = PP2_MMU_ADDR, + .irq = IRQ_PPMMU2_3D, + .description = "Mali-400 MMU for PP 2", + .mmu_id = 4 + }, + { + .type = MMU, + .base = PP3_MMU_ADDR, + .irq = IRQ_PPMMU3_3D, + .description = "Mali-400 MMU for PP 3", + .mmu_id = 5 + }, +#if USING_OS_MEMORY + { + .type = OS_MEMORY, + .description = "System Memory", + .size = MEM_MALI_OS_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, +#endif +#if USING_DED /* Dedicated Memory */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif/* if USING_OS_MEMORY*/ + { + .type = MEM_VALIDATION, + .description = "memory validation", + .base = MEM_BASE_ADDR, + .size = MEM_TOTAL_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#else /* Not using MMU */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif + { + .type = MALI400L2, + .base = L2_ADDR, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 1df6abbf53b..6421632733c 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -39,6 +39,8 @@ #define EXYNOS4_PA_G2D 0x12800000 +#define EXYNOS4_PA_G3D 0x13000000 + #define EXYNOS4_PA_I2S0 0x03830000 #define EXYNOS4_PA_I2S1 0xE3100000 #define EXYNOS4_PA_I2S2 0xE2A00000 @@ -188,10 +190,13 @@ #define EXYNOS4_PA_HSOTG 0x12480000 #define EXYNOS4_PA_USB_HSPHY 0x125B0000 - +#define EXYNOS5_PA_HSPHY 0x12130000 #define EXYNOS4_PA_SATA 0x12560000 #define EXYNOS4_PA_SATAPHY 0x125D0000 #define EXYNOS4_PA_SATAPHY_CTRL 0x126B0000 +#define EXYNOS5_PA_SATA_PHY_CTRL 0x12170000 +#define EXYNOS5_PA_SATA_PHY_I2C 0x121D0000 +#define EXYNOS5_PA_SATA_BASE 0x122F0000 #define EXYNOS4_PA_SROMC 0x12570000 #define EXYNOS5_PA_SROMC 0x12250000 @@ -199,11 +204,16 @@ #define EXYNOS4_PA_EHCI 0x12580000 #define EXYNOS4_PA_OHCI 0x12590000 #define EXYNOS4_PA_HSPHY 0x125B0000 +#define EXYNOS5_PA_DRD 0x12000000 +#define EXYNOS5_PA_EHCI 0x12110000 +#define EXYNOS5_PA_OHCI 0x12120000 #define EXYNOS4_PA_MFC 0x13400000 #define EXYNOS4_PA_UART 0x13800000 #define EXYNOS5_PA_UART 0x12C00000 +#define EXYNOS5_PA_USB_PHY 0x12130000 + #define EXYNOS4_PA_VP 0x12C00000 #define EXYNOS4_PA_MIXER 0x12C10000 #define EXYNOS4_PA_SDO 0x12C20000 @@ -216,6 +226,8 @@ #define EXYNOS4_PA_ADC 0x13910000 #define EXYNOS4_PA_ADC1 0x13911000 +#define EXYNOS4_PA_AUDSS 0x03810000 + #define EXYNOS4_PA_AC97 0x139A0000 #define EXYNOS4_PA_SPDIF 0x139B0000 @@ -246,7 +258,7 @@ #define S3C_PA_SPI1 EXYNOS4_PA_SPI1 #define S3C_PA_SPI2 EXYNOS4_PA_SPI2 #define S3C_PA_USB_HSOTG EXYNOS4_PA_HSOTG - +#define S3C_PA_USB_PHY EXYNOS4_PA_HSPHY #define S5P_PA_EHCI EXYNOS4_PA_EHCI #define S5P_PA_FIMC0 EXYNOS4_PA_FIMC0 #define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1 @@ -254,6 +266,7 @@ #define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3 #define S5P_PA_JPEG EXYNOS4_PA_JPEG #define S5P_PA_G2D EXYNOS4_PA_G2D +#define S5P_PA_G3D EXYNOS4_PA_G3D #define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0 #define S5P_PA_HDMI EXYNOS4_PA_HDMI #define S5P_PA_IIC_HDMIPHY EXYNOS4_PA_IIC_HDMIPHY diff --git a/arch/arm/mach-exynos/include/mach/regs-audss.h b/arch/arm/mach-exynos/include/mach/regs-audss.h index ca5a8b64218..71ceb08ae63 100644 --- a/arch/arm/mach-exynos/include/mach/regs-audss.h +++ b/arch/arm/mach-exynos/include/mach/regs-audss.h @@ -1,5 +1,4 @@ -/* arch/arm/mach-exynos4/include/mach/regs-audss.h - * +/* * Copyright (c) 2011 Samsung Electronics * http://www.samsung.com * @@ -15,4 +14,12 @@ #define EXYNOS4_AUDSS_INT_MEM (0x03000000) +#define EXYNOS_AUDSSREG(x) (S5P_VA_AUDSS + (x)) + +#define EXYNOS4_CLKSRC_AUDSS EXYNOS_AUDSSREG(0x0) +#define EXYNOS4_CLKDIV_AUDSS EXYNOS_AUDSSREG(0x4) +#define EXYNOS4_CLKGATE_AUDSS EXYNOS_AUDSSREG(0x8) + +#define EXYNOS4_AUDSS_CLKGATE_I2SBUS (1<<2) + #endif /* _PLAT_REGS_AUDSS_H */ diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h index 3f30aa1ae35..d2bee973ecc 100644 --- a/arch/arm/mach-exynos/include/mach/regs-pmu.h +++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h @@ -41,6 +41,10 @@ #define S5P_HDMI_PHY_CONTROL S5P_PMUREG(0x0700) #define S5P_HDMI_PHY_ENABLE (1 << 0) +/* only for EXYNOS5250*/ +#define S5P_USBDRD_PHY_CONTROL S5P_PMUREG(0x0704) +#define S5P_USBDRD_PHY_ENABLE (1 << 0) + #define S5P_DAC_PHY_CONTROL S5P_PMUREG(0x070C) #define S5P_DAC_PHY_ENABLE (1 << 0) @@ -369,4 +373,7 @@ #define EXYNOS5_OPTION_USE_RETENTION (1 << 4) +/* Only for EXYNOS5250 */ +#define EXYNOS5_SATA_PHY_CONTROL S5P_PMUREG(0x0724) + #endif /* __ASM_ARCH_REGS_PMU_H */ diff --git a/arch/arm/mach-exynos/include/mach/regs-sata.h b/arch/arm/mach-exynos/include/mach/regs-sata.h new file mode 100644 index 00000000000..80dd564eb32 --- /dev/null +++ b/arch/arm/mach-exynos/include/mach/regs-sata.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * EXYNOS - SATA PHY controller definition + * + * 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 EXYNOS5_SATA_RESET 0x4 +#define RESET_CMN_RST_N (1 << 1) +#define LINK_RESET 0xF0000 + +#define EXYNOS5_SATA_MODE0 0x10 + +#define EXYNOS5_SATA_CTRL0 0x14 +#define CTRL0_P0_PHY_CALIBRATED_SEL (1 << 9) +#define CTRL0_P0_PHY_CALIBRATED (1 << 8) + +#define EXYNOS5_SATA_PHSATA_CTRLM 0xE0 +#define PHCTRLM_REF_RATE (1 << 1) +#define PHCTRLM_HIGH_SPEED (1 << 0) + +#define EXYNOS5_SATA_PHSATA_STATM 0xF0 +#define PHSTATM_PLL_LOCKED (1 << 0) + +#define SATA_PHY_CON_RESET 0xF003F diff --git a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h index 07277735252..2df4bd7e540 100644 --- a/arch/arm/mach-exynos/include/mach/regs-usb-phy.h +++ b/arch/arm/mach-exynos/include/mach/regs-usb-phy.h @@ -13,6 +13,7 @@ #define EXYNOS4_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY) +/* Exynos 4 */ #define EXYNOS4_PHYPWR EXYNOS4_HSOTG_PHYREG(0x00) #define PHY1_HSIC_NORMAL_MASK (0xf << 9) #define PHY1_HSIC1_SLEEP (1 << 12) @@ -71,4 +72,89 @@ #define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34) #define FPENABLEN (1 << 0) +/* Exynos 5 */ +#define EXYNOS5_PHY_HOST_CTRL0 EXYNOS4_HSOTG_PHYREG(0x00) +#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31) + +#define HOST_CTRL0_REFCLKSEL_XTAL (0x0) +#define HOST_CTRL0_REFCLKSEL_EXTL (0x1) +#define HOST_CTRL0_REFCLKSEL_CLK_CORE (0x2) +#define HOST_CTRL0_REFCLKSEL_MASK (0x3) +#define HOST_CTRL0_REFCLKSEL_SHIFT (19) + +#define EXYNOS5_CLKSEL_50M (0x7) +#define EXYNOS5_CLKSEL_24M (0x5) +#define EXYNOS5_CLKSEL_20M (0x4) +#define EXYNOS5_CLKSEL_19200K (0x3) +#define EXYNOS5_CLKSEL_12M (0x2) +#define EXYNOS5_CLKSEL_10M (0x1) +#define EXYNOS5_CLKSEL_9600K (0x0) +#define HOST_CTRL0_FSEL_MASK (0x7 << 16) +#define HOST_CTRL0_CLKSEL_SHIFT (16) + +#define HOST_CTRL0_COMMONON_N (0x1 << 9) +#define HOST_CTRL0_SIDDQ (0x1 << 6) +#define HOST_CTRL0_FORCESLEEP (0x1 << 5) +#define HOST_CTRL0_FORCESUSPEND (0x1 << 4) +#define HOST_CTRL0_WORDINTERFACE (0x1 << 3) +#define HOST_CTRL0_UTMISWRST (0x1 << 2) +#define HOST_CTRL0_LINKSWRST (0x1 << 1) +#define HOST_CTRL0_PHYSWRST (0x1 << 0) + +#define EXYNOS5_PHY_HOST_TUNE0 EXYNOS4_HSOTG_PHYREG(0x04) +#define EXYNOS5_PHY_HOST_TEST0 EXYNOS4_HSOTG_PHYREG(0x08) + +#define EXYNOS5_PHY_HSIC_CTRL1 EXYNOS4_HSOTG_PHYREG(0x10) +#define EXYNOS5_PHY_HSIC_CTRL2 EXYNOS4_HSOTG_PHYREG(0x20) +#define HSIC_CTRL_REFCLKSEL (0x2) +#define HSIC_CTRL_REFCLKSEL_MASK (0x3) +#define HSIC_CTRL_REFCLKSEL_SHIFT (23) + +#define HSIC_CTRL_REFCLKDIV_12 (0x24) +#define HSIC_CTRL_REFCLKDIV_15 (0x1C) +#define HSIC_CTRL_REFCLKDIV_16 (0x1A) +#define HSIC_CTRL_REFCLKDIV_19_2 (0x15) +#define HSIC_CTRL_REFCLKDIV_20 (0x14) +#define HSIC_CTRL_REFCLKDIV_MASK (0x7f) +#define HSIC_CTRL_REFCLKDIV_SHIFT (16) + +#define HSIC_CTRL_SIDDQ (0x1 << 6) +#define HSIC_CTRL_FORCESLEEP (0x1 << 5) +#define HSIC_CTRL_FORCESUSPEND (0x1 << 4) +#define HSIC_CTRL_WORDINTERFACE (0x1 << 3) +#define HSIC_CTRL_UTMISWRST (0x1 << 2) +#define HSIC_CTRL_PHYSWRST (0x1 << 0) + +#define EXYNOS5_PHY_HOST_EHCICTRL EXYNOS4_HSOTG_PHYREG(0x30) +#define EHCICTRL_ENAINCRXALIGN (0x1 << 29) +#define EHCICTRL_ENAINCR4 (0x1 << 28) +#define EHCICTRL_ENAINCR8 (0x1 << 27) +#define EHCICTRL_ENAINCR16 (0x1 << 26) + +#define EXYNOS5_PHY_HOST_OHCICTRL EXYNOS4_HSOTG_PHYREG(0x34) +#define OHCICTRL_SUSPLGCY (0x1 << 3) +#define OHCICTRL_APPSTARTCLK (0x1 << 2) +#define OHCICTRL_CNTSEL (0x1 << 1) +#define OHCICTRL_CLKCKTRST (0x1 << 0) + +#define EXYNOS5_PHY_OTG_SYS EXYNOS4_HSOTG_PHYREG(0x38) +#define OTG_SYS_PHYLINK_SW_RESET (0x1 << 14) +#define OTG_SYS_LINK_SW_RST_UOTG (0x1 << 13) +#define OTG_SYS_PHY0_SW_RST (0x1 << 12) + +#define OTG_SYS_REF_CLK_SEL_XTAL (0x0) +#define OTG_SYS_REF_CLK_SEL_EXTL (0x1) +#define OTG_SYS_REF_CLK_SEL_CLKCORE (0x2) +#define OTG_SYS_REF_CLK_SEL_MASK (0x3) +#define OTG_SYS_REF_CLK_SEL_SHIFT (9) + +#define OTG_SYS_IP_PULLUP_UOTG (0x1 << 8) +#define OTG_SYS_COMMON_ON (0x1 << 7) +#define OTG_SYS_CLKSEL_SHIFT (4) +#define OTG_SYS_CTRL0_FSEL_MASK (0x7 << 4) +#define OTG_SYS_FORCE_SLEEP (0x1 << 3) +#define OTG_SYS_OTGDISABLE (0x1 << 2) +#define OTG_SYS_SIDDQ_UOTG (0x1 << 1) +#define OTG_SYS_FORCE_SUSPEND (0x1 << 0) + #endif /* __PLAT_S5P_REGS_USB_PHY_H */ diff --git a/arch/arm/mach-exynos/include/mach/ump/config.h b/arch/arm/mach-exynos/include/mach/ump/config.h new file mode 100644 index 00000000000..a82934f2799 --- /dev/null +++ b/arch/arm/mach-exynos/include/mach/ump/config.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2010 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +#define ARCH_UMP_BACKEND_DEFAULT UMP_MEMORY_TYPE +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0 +#define ARCH_UMP_MEMORY_SIZE_DEFAULT CONFIG_UMP_MEM_SIZE * 1024UL * 1024UL + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c index 92757ff817a..26babfa032a 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c @@ -14,15 +14,58 @@ #include <linux/of_platform.h> #include <linux/serial_core.h> +#include <linux/platform_data/usb-ehci-s5p.h> +#include <linux/platform_data/usb-exynos.h> + +#include <linux/platform_data/s3c-hsotg.h> +#include <linux/pwm_backlight.h> +#include <linux/gpio.h> +#include <linux/fb.h> +#include <linux/lcd.h> + +#include <video/samsung_fimd.h> + +#include <plat/backlight.h> +#include <plat/gpio-cfg.h> +#include <plat/fb.h> +#include <plat/devs.h> + #include <asm/mach/arch.h> #include <asm/hardware/gic.h> #include <mach/map.h> #include <plat/cpu.h> #include <plat/regs-serial.h> +#include <plat/usb-phy.h> #include "common.h" +static struct s5p_ehci_platdata origen_ehci_pdata = { + .phy_init = s5p_usb_phy_init, + .phy_exit = s5p_usb_phy_exit, +}; + +static struct exynos4_ohci_platdata origen_ohci_pdata = { + .phy_init = s5p_usb_phy_init, + .phy_exit = s5p_usb_phy_exit, +}; + +static struct s3c_hsotg_plat origen_hsotg_pdata = { + .phy_init = s5p_usb_phy_init, + .phy_exit = s5p_usb_phy_exit, +}; + +/* LCD Backlight data */ +static struct samsung_bl_gpio_info origen_bl_gpio_info = { + .no = EXYNOS4_GPD0(0), + .func = S3C_GPIO_SFN(2), +}; + +static struct platform_pwm_backlight_data origen_bl_data = { + .pwm_id = 0, + .pwm_period_ns = 1000, +}; + /* * The following lookup table is used to override device names when devices * are registered from device tree. This is temporarily added to enable @@ -69,6 +112,12 @@ static const struct of_dev_auxdata exynos4_auxdata_lookup[] __initconst = { "s3c2440-i2c.6", NULL), OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS4_PA_IIC(7), "s3c2440-i2c.7", NULL), + OF_DEV_AUXDATA("samsung,s3c2440-hdmiphy-i2c", EXYNOS4_PA_IIC_HDMIPHY, + "s3c2440-hdmiphy-i2c", NULL), + OF_DEV_AUXDATA("samsung,s5pv210-tvmixer", EXYNOS4_PA_MIXER, + "s5p-mixer", NULL), + OF_DEV_AUXDATA("samsung,s5pv210-hdmi", EXYNOS4_PA_HDMI, + "exynos4-hdmi", NULL), OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI0, "exynos4210-spi.0", NULL), OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS4_PA_SPI1, @@ -80,6 +129,16 @@ static const struct of_dev_auxdata exynos4_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("arm,pl330", EXYNOS4_PA_MDMA1, "dma-pl330.2", NULL), OF_DEV_AUXDATA("samsung,exynos4210-tmu", EXYNOS4_PA_TMU, "exynos-tmu", NULL), + OF_DEV_AUXDATA("samsung,exynos-ehci", EXYNOS4_PA_EHCI, "s5p-ehci", + &origen_ehci_pdata), + OF_DEV_AUXDATA("samsung,exynos-ohci", EXYNOS4_PA_OHCI, "exynos-ohci", + &origen_ohci_pdata), + OF_DEV_AUXDATA("samsung,exynos-hsotg", EXYNOS4_PA_HSOTG, "s3c-hsotg", + &origen_hsotg_pdata), + OF_DEV_AUXDATA("samsung,exynos4210-fimd", EXYNOS4_PA_FIMD0, + "exynos4-fb.0", NULL), + OF_DEV_AUXDATA("samsung,samsung-i2s", EXYNOS4_PA_I2S0, + "samsung-i2s.0", NULL), {}, }; @@ -89,10 +148,21 @@ static void __init exynos4_dt_map_io(void) s3c24xx_init_clocks(24000000); } +static void __init exynos4_setup_fimd(void) +{ + unsigned int reg; + + reg = __raw_readl(S3C_VA_SYS + 0x0210); + reg |= (1 << 1); + __raw_writel(reg, S3C_VA_SYS + 0x0210); +} + static void __init exynos4_dt_machine_init(void) { of_platform_populate(NULL, of_default_bus_match_table, exynos4_auxdata_lookup, NULL); + samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); + exynos4_setup_fimd(); } static char const *exynos4_dt_compat[] __initdata = { diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index e99d3d8f2bc..f479b5b03f5 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -17,15 +17,40 @@ #include <asm/mach/arch.h> #include <asm/hardware/gic.h> + #include <mach/map.h> #include <mach/regs-pmu.h> #include <plat/cpu.h> #include <plat/regs-serial.h> #include <plat/mfc.h> +#include <linux/platform_data/samsung-usbphy.h> +#include <linux/platform_data/usb-exynos.h> + +#include <plat/regs-srom.h> +#include <plat/devs.h> +#include <plat/usb-phy.h> +#include <linux/platform_data/usb-ehci-s5p.h> #include "common.h" + + +static struct samsung_usbphy_data exynos5_usbphy_pdata = { + .pmu_isolation = s5p_usb_phy_pmu_isolation, + .phy_cfg_sel = s5p_usb_phy_cfg_sel, +}; + +static struct exynos4_ohci_platdata smdk5250_ohci_pdata = { + .phy_init = s5p_usb_phy_init, + .phy_exit = s5p_usb_phy_exit, +}; + +static struct s5p_ehci_platdata smdk5250_ehci_pdata = { + .phy_init = s5p_usb_phy_init, + .phy_exit = s5p_usb_phy_exit, +}; + /* * The following lookup table is used to override device names when devices * are registered from device tree. This is temporarily added to enable @@ -80,11 +105,11 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { "exynos4210-spi.1", NULL), OF_DEV_AUXDATA("samsung,exynos4210-spi", EXYNOS5_PA_SPI2, "exynos4210-spi.2", NULL), - OF_DEV_AUXDATA("samsung,exynos5-sata-ahci", 0x122F0000, + OF_DEV_AUXDATA("samsung,exynos5-sata-ahci", EXYNOS5_PA_SATA_BASE, "exynos5-sata", NULL), - OF_DEV_AUXDATA("samsung,exynos5-sata-phy", 0x12170000, + OF_DEV_AUXDATA("samsung,exynos5-sata-phy", EXYNOS5_PA_SATA_PHY_CTRL, "exynos5-sata-phy", NULL), - OF_DEV_AUXDATA("samsung,exynos5-sata-phy-i2c", 0x121D0000, + OF_DEV_AUXDATA("samsung,exynos5-sata-phy-i2c", EXYNOS5_PA_SATA_PHY_I2C, "exynos5-sata-phy-i2c", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL), @@ -104,6 +129,14 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("samsung,mfc-v6", 0x11000000, "s5p-mfc-v6", NULL), OF_DEV_AUXDATA("samsung,exynos5250-tmu", 0x10060000, "exynos-tmu", NULL), + OF_DEV_AUXDATA("samsung,exynos5250-usbphy", EXYNOS5_PA_HSPHY, + "s3c-usbphy", &exynos5_usbphy_pdata), + OF_DEV_AUXDATA("samsung,exynos-dwc3", EXYNOS5_PA_DRD, + "exynos-dwc3", NULL), + OF_DEV_AUXDATA("samsung,exynos-ohci", 0x12120000, + "exynos-ohci", &smdk5250_ohci_pdata), + OF_DEV_AUXDATA("samsung,exynos-ehci", 0x12110000, + "s5p-ehci", &smdk5250_ehci_pdata), {}, }; @@ -123,6 +156,11 @@ static void __init exynos5_dt_map_io(void) s3c24xx_init_clocks(24000000); } +static void exynos5_i2c_setup(void) +{ /* Setup the low-speed i2c controller interrupts */ + writel(0x0, EXYNOS5_SYS_I2C_CFG); +} + static void __init exynos5_dt_machine_init(void) { struct device_node *i2c_np; @@ -147,6 +185,8 @@ static void __init exynos5_dt_machine_init(void) } } + exynos5_i2c_setup(); + if (of_machine_is_compatible("samsung,exynos5250")) of_platform_populate(NULL, of_default_bus_match_table, exynos5250_auxdata_lookup, NULL); diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 5e34b9c1619..85f984dff9e 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -20,6 +20,7 @@ #include <linux/gpio_keys.h> #include <linux/i2c.h> #include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> #include <linux/mfd/max8997.h> #include <linux/lcd.h> #include <linux/rfkill-gpio.h> @@ -27,6 +28,8 @@ #include <linux/platform_data/s3c-hsotg.h> #include <linux/platform_data/usb-ehci-s5p.h> #include <linux/platform_data/usb-exynos.h> +#include <linux/ath6kl.h> +#include <linux/delay.h> #include <asm/mach/arch.h> #include <asm/hardware/gic.h> @@ -34,6 +37,7 @@ #include <video/platform_lcd.h> #include <video/samsung_fimd.h> +#include <video/lcd_pwrctrl.h> #include <plat/regs-serial.h> #include <plat/cpu.h> @@ -65,6 +69,11 @@ S5PV210_UFCON_TXTRIG4 | \ S5PV210_UFCON_RXTRIG4) +enum fixed_regulator_id { + FIXED_REG_ID_MMC = 0, + FIXED_REG_ID_5V, +}; + static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { [0] = { .hwport = 0, @@ -96,6 +105,10 @@ static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { }, }; +static struct regulator_consumer_supply __initdata fixed_5v_supply[] = { + REGULATOR_SUPPLY("hdmi-en", "exynos4-hdmi"), /* HDMI */ +}; + static struct regulator_consumer_supply __initdata ldo3_consumer[] = { REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), /* MIPI */ REGULATOR_SUPPLY("vdd", "exynos4-hdmi"), /* HDMI */ @@ -135,7 +148,7 @@ static struct regulator_consumer_supply __initdata buck3_consumer[] = { REGULATOR_SUPPLY("vdd_g3d", "mali_drm"), /* G3D */ }; static struct regulator_consumer_supply __initdata buck7_consumer[] = { - REGULATOR_SUPPLY("vcc", "platform-lcd"), /* LCD */ + REGULATOR_SUPPLY("vcc-lcd", "lcd-pwrctrl.0"), /* LCD */ }; static struct regulator_init_data __initdata max8997_ldo1_data = { @@ -169,6 +182,7 @@ static struct regulator_init_data __initdata max8997_ldo3_data = { .min_uV = 1100000, .max_uV = 1100000, .apply_uV = 1, + .always_on = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { .disabled = 1, @@ -197,6 +211,7 @@ static struct regulator_init_data __initdata max8997_ldo6_data = { .min_uV = 1800000, .max_uV = 1800000, .apply_uV = 1, + .always_on = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { .disabled = 1, @@ -227,6 +242,7 @@ static struct regulator_init_data __initdata max8997_ldo8_data = { .min_uV = 3300000, .max_uV = 3300000, .apply_uV = 1, + .always_on = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { .disabled = 1, @@ -271,6 +287,7 @@ static struct regulator_init_data __initdata max8997_ldo11_data = { .min_uV = 3000000, .max_uV = 3000000, .apply_uV = 1, + .always_on = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { .disabled = 1, @@ -361,7 +378,9 @@ static struct regulator_init_data __initdata max8997_buck3_data = { .constraints = { .name = "VDD_G3D_1.1V", .min_uV = 900000, - .max_uV = 1100000, + .max_uV = 1200000, + .always_on = 1, + .boot_on = 1, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, .state_mem = { @@ -390,7 +409,7 @@ static struct regulator_init_data __initdata max8997_buck7_data = { .name = "VDD_LCD_3.3V", .min_uV = 3300000, .max_uV = 3300000, - .boot_on = 1, + .boot_on = 0, .apply_uV = 1, .valid_ops_mask = REGULATOR_CHANGE_STATUS, .state_mem = { @@ -473,6 +492,49 @@ static struct i2c_board_info i2c0_devs[] __initdata = { .platform_data = &origen_max8997_pdata, .irq = IRQ_EINT(4), }, +#ifdef CONFIG_TOUCHSCREEN_UNIDISPLAY_TS + { + I2C_BOARD_INFO("unidisplay_ts", 0x41), + .irq = IRQ_TS, + }, +#endif +}; + +static struct regulator_consumer_supply mmc_supplies[] = { + REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.0"), + REGULATOR_SUPPLY("vmmc", "exynos4-sdhci.2"), +}; + +static struct regulator_init_data mmc_fixed_voltage_init_data = { + .constraints = { + .name = "VMEM_VDD_2.8V", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(mmc_supplies), + .consumer_supplies = mmc_supplies, +}; + +static struct fixed_voltage_config mmc_fixed_voltage_config = { + .supply_name = "MMC_POWER_EN", + .microvolts = 2800000, + .gpio = EXYNOS4_GPX1(1), + .enable_high = true, + .init_data = &mmc_fixed_voltage_init_data, +}; + +static struct platform_device mmc_fixed_voltage = { + .name = "reg-fixed-voltage", + .id = FIXED_REG_ID_MMC, + .dev = { + .platform_data = &mmc_fixed_voltage_config, + }, +}; + +/* I2C1 */ +static struct i2c_board_info i2c1_devs[] __initdata = { + { + I2C_BOARD_INFO("alc5625", 0x1E), + }, }; static struct s3c_sdhci_platdata origen_hsmmc0_pdata __initdata = { @@ -483,6 +545,100 @@ static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = { .cd_type = S3C_SDHCI_CD_INTERNAL, }; + +/* + * WLAN: SDIO Host will call this func at booting time + */ +static int origen_wifi_status_register(void (*notify_func) + (struct platform_device *, int state)); + +/* WLAN: MMC3-SDIO */ +static struct s3c_sdhci_platdata origen_hsmmc3_pdata __initdata = { + .max_width = 4, + .host_caps = MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED, + .pm_caps = MMC_PM_KEEP_POWER, + .cd_type = S3C_SDHCI_CD_EXTERNAL, + .ext_cd_init = origen_wifi_status_register, +}; + +/* + * WLAN: Save SDIO Card detect func into this pointer + */ +static void (*wifi_status_cb)(struct platform_device *, int state); + +static int origen_wifi_status_register(void (*notify_func) + (struct platform_device *, int state)) +{ + /* Assign sdhci_s3c_notify_change to wifi_status_cb */ + if (!notify_func) + return -EAGAIN; + else + wifi_status_cb = notify_func; + + return 0; +} + +#define ORIGEN_WLAN_WOW EXYNOS4_GPX2(3) +#define ORIGEN_WLAN_RESET EXYNOS4_GPX2(4) + + +static void origen_wlan_setup_power(bool val) +{ + int err; + + if (val) { + err = gpio_request_one(ORIGEN_WLAN_RESET, + GPIOF_OUT_INIT_LOW, "GPX2_4"); + if (err) { + pr_warning("ORIGEN: Not obtain WIFI gpios\n"); + return; + } + s3c_gpio_cfgpin(ORIGEN_WLAN_RESET, S3C_GPIO_OUTPUT); + s3c_gpio_setpull(ORIGEN_WLAN_RESET, + S3C_GPIO_PULL_NONE); + /* VDD33,I/O Supply must be done */ + gpio_set_value(ORIGEN_WLAN_RESET, 0); + udelay(30); /*Tb */ + gpio_direction_output(ORIGEN_WLAN_RESET, 1); + } else { + gpio_direction_output(ORIGEN_WLAN_RESET, 0); + gpio_free(ORIGEN_WLAN_RESET); + } + + mdelay(100); + + return; +} + +/* + * This will be called at init time of WLAN driver + */ +static int origen_wifi_set_detect(bool val) +{ + + if (!wifi_status_cb) { + pr_warning("ORIGEN: WLAN: No callback \n" + "ORIGEN: WLAN: MMC should boot earlier than net \n"); + + return -EAGAIN; + } + if (true == val) { + origen_wlan_setup_power(true); + wifi_status_cb(&s3c_device_hsmmc3, 1); + } else { + origen_wlan_setup_power(false); + wifi_status_cb(&s3c_device_hsmmc3, 0); + } + + return 0; +} + +struct ath6kl_platform_data origen_wlan_data __initdata = { + .setup_power = origen_wifi_set_detect, +}; + + /* USB EHCI */ static struct s5p_ehci_platdata origen_ehci_pdata; @@ -590,29 +746,12 @@ static struct platform_device origen_device_gpiokeys = { }, }; -static void lcd_hv070wsa_set_power(struct plat_lcd_data *pd, unsigned int power) -{ - int ret; - - if (power) - ret = gpio_request_one(EXYNOS4_GPE3(4), - GPIOF_OUT_INIT_HIGH, "GPE3_4"); - else - ret = gpio_request_one(EXYNOS4_GPE3(4), - GPIOF_OUT_INIT_LOW, "GPE3_4"); - - gpio_free(EXYNOS4_GPE3(4)); - - if (ret) - pr_err("failed to request gpio for LCD power: %d\n", ret); -} - -static struct plat_lcd_data origen_lcd_hv070wsa_data = { - .set_power = lcd_hv070wsa_set_power, +static struct lcd_pwrctrl_data origen_lcd_hv070wsa_data = { + .gpio = EXYNOS4_GPE3(4), }; static struct platform_device origen_lcd_hv070wsa = { - .name = "platform-lcd", + .name = "lcd-pwrctrl", .dev.parent = &s5p_device_fimd0.dev, .dev.platform_data = &origen_lcd_hv070wsa_data, }; @@ -646,7 +785,25 @@ static struct s3c_fb_pd_win origen_fb_win0 = { .xres = 1024, .yres = 600, .max_bpp = 32, - .default_bpp = 24, + .default_bpp = 32, + .virtual_x = 1024, + .virtual_y = 2 * 600, +}; + +static struct s3c_fb_pd_win origen_fb_win1 = { + .xres = 1024, + .yres = 600, + .max_bpp = 32, + .default_bpp = 32, + .virtual_x = 1024, + .virtual_y = 2 * 600, +}; + +static struct s3c_fb_pd_win origen_fb_win2 = { + .xres = 1024, + .yres = 600, + .max_bpp = 32, + .default_bpp = 32, .virtual_x = 1024, .virtual_y = 2 * 600, }; @@ -664,6 +821,8 @@ static struct fb_videomode origen_lcd_timing = { static struct s3c_fb_platdata origen_lcd_pdata __initdata = { .win[0] = &origen_fb_win0, + .win[1] = &origen_fb_win1, + .win[2] = &origen_fb_win2, .vtiming = &origen_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | @@ -690,9 +849,12 @@ static struct platform_device origen_device_bluetooth = { }; static struct platform_device *origen_devices[] __initdata = { + &mmc_fixed_voltage, &s3c_device_hsmmc2, &s3c_device_hsmmc0, + &s3c_device_hsmmc3, &s3c_device_i2c0, + &s3c_device_i2c1, &s3c_device_rtc, &s3c_device_usb_hsotg, &s3c_device_wdt, @@ -704,6 +866,7 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_fimc_md, &s5p_device_fimd0, &s5p_device_g2d, + &s5p_device_g3d, &s5p_device_hdmi, &s5p_device_i2c_hdmiphy, &s5p_device_jpeg, @@ -711,6 +874,7 @@ static struct platform_device *origen_devices[] __initdata = { &s5p_device_mfc_l, &s5p_device_mfc_r, &s5p_device_mixer, + &exynos4_device_i2s0, &exynos4_device_ohci, &origen_device_gpiokeys, &origen_lcd_hv070wsa, @@ -768,7 +932,7 @@ static void __init origen_power_init(void) static void __init origen_reserve(void) { - s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20); + s5p_mfc_reserve_mem(0x43000000, 32 << 20, 0x51000000, 32 << 20); } static void __init origen_machine_init(void) @@ -778,12 +942,16 @@ static void __init origen_machine_init(void) s3c_i2c0_set_platdata(NULL); i2c_register_board_info(0, i2c0_devs, ARRAY_SIZE(i2c0_devs)); + s3c_i2c1_set_platdata(NULL); + i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs)); + /* * Since sdhci instance 2 can contain a bootable media, * sdhci instance 0 is registered after instance 2. */ s3c_sdhci2_set_platdata(&origen_hsmmc2_pdata); s3c_sdhci0_set_platdata(&origen_hsmmc0_pdata); + s3c_sdhci3_set_platdata(&origen_hsmmc3_pdata); origen_ehci_init(); origen_ohci_init(); @@ -800,12 +968,17 @@ static void __init origen_machine_init(void) s5p_fimd0_set_platdata(&origen_lcd_pdata); #endif + regulator_register_always_on(FIXED_REG_ID_5V, "Fixed 5V", + fixed_5v_supply, ARRAY_SIZE(fixed_5v_supply), 5000000); + platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); pwm_add_table(origen_pwm_lookup, ARRAY_SIZE(origen_pwm_lookup)); samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data); origen_bt_setup(); + + ath6kl_set_platform_data(&origen_wlan_data); } MACHINE_START(ORIGEN, "ORIGEN") diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c index 9f1351de52f..b9bfc3b9643 100644 --- a/arch/arm/mach-exynos/pm_domains.c +++ b/arch/arm/mach-exynos/pm_domains.c @@ -276,6 +276,11 @@ static __init int exynos4_pm_init_power_domain(void) #ifdef CONFIG_S5P_DEV_G2D exynos_pm_add_dev_to_genpd(&s5p_device_g2d, &exynos4_pd_lcd0); #endif +#ifdef CONFIG_S5P_DEV_G3D + /* MALI requires the PD to be always on. */ + exynos4_pd_g3d.pd.power_off = NULL; + exynos_pm_add_dev_to_genpd(&s5p_device_g3d, &exynos4_pd_g3d); +#endif #ifdef CONFIG_S5P_DEV_JPEG exynos_pm_add_dev_to_genpd(&s5p_device_jpeg, &exynos4_pd_cam); #endif diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c index b81cc569a8d..78100981b0b 100644 --- a/arch/arm/mach-exynos/setup-usb-phy.c +++ b/arch/arm/mach-exynos/setup-usb-phy.c @@ -14,24 +14,75 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/usb/samsung_usb_phy.h> +#include <linux/platform_data/samsung-usbphy.h> #include <mach/regs-pmu.h> #include <mach/regs-usb-phy.h> #include <plat/cpu.h> +#include <plat/map-base.h> #include <plat/usb-phy.h> +#define PHY_ENABLE 1 +#define PHY_DISABLE 0 +#define EXYNOS5_USB_CFG (S3C_VA_SYS + 0x230) + static atomic_t host_usage; static int exynos4_usb_host_phy_is_on(void) { - return (readl(EXYNOS4_PHYPWR) & PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1; + if (soc_is_exynos5250()) { + return (readl(EXYNOS5_PHY_HOST_CTRL0) & + HOST_CTRL0_PHYSWRSTALL) ? 0 : 1; + } else { + return (readl(EXYNOS4_PHYPWR) & + PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1; + } +} + +static void exynos_usb_mux_change(struct platform_device *pdev, int val) +{ + u32 is_host; + if (soc_is_exynos5250()) { + is_host = readl(EXYNOS5_USB_CFG); + writel(val, EXYNOS5_USB_CFG); + } + if (is_host != val) + dev_dbg(&pdev->dev, "Change USB MUX from %s to %s", + is_host ? "Host" : "Device", val ? "Host" : "Device"); } -static void exynos4210_usb_phy_clkset(struct platform_device *pdev) +static struct clk *exynos_usb_clock_enable(struct platform_device *pdev) +{ + struct clk *usb_clk = NULL; + int err = 0; + + if (soc_is_exynos5250()) + usb_clk = clk_get(&pdev->dev, "usbhost"); + else + usb_clk = clk_get(&pdev->dev, "otg"); + if (IS_ERR(usb_clk)) { + dev_err(&pdev->dev, "Failed to get otg clock\n"); + return NULL; + } + + err = clk_enable(usb_clk); + if (err) { + clk_put(usb_clk); + return NULL; + } + return usb_clk; +} + +static int exynos4210_usb_phy_clkset(struct platform_device *pdev) { struct clk *xusbxti_clk; - u32 phyclk; + u32 phyclk = 0; + + if (soc_is_exynos5250()) + xusbxti_clk = clk_get(&pdev->dev, "ext_xtal"); + else + xusbxti_clk = clk_get(&pdev->dev, "xusbxti"); - xusbxti_clk = clk_get(&pdev->dev, "xusbxti"); if (xusbxti_clk && !IS_ERR(xusbxti_clk)) { if (soc_is_exynos4210()) { /* set clock frequency for PLL */ @@ -77,11 +128,47 @@ static void exynos4210_usb_phy_clkset(struct platform_device *pdev) break; } writel(phyclk, EXYNOS4_PHYCLK); + } else if (soc_is_exynos5250()) { + /* set clock frequency for PLL */ + switch (clk_get_rate(xusbxti_clk)) { + case 96 * 100000: + phyclk |= EXYNOS5_CLKSEL_9600K; + break; + case 10 * MHZ: + phyclk |= EXYNOS5_CLKSEL_10M; + break; + case 12 * MHZ: + phyclk |= EXYNOS5_CLKSEL_12M; + break; + case 192 * 100000: + phyclk |= EXYNOS5_CLKSEL_19200K; + break; + case 20 * MHZ: + phyclk |= EXYNOS5_CLKSEL_20M; + break; + case 50 * MHZ: + phyclk |= EXYNOS5_CLKSEL_50M; + break; + case 24 * MHZ: + default: + /* default reference clock */ + phyclk |= EXYNOS5_CLKSEL_24M; + break; + } } clk_put(xusbxti_clk); } + return phyclk; } - +#if 0 +static void exynos_usb_phy_control(enum usb_phy_type phy_type , int on) +{ + if (soc_is_exynos5250()) { + if (phy_type & USB_PHY) + writel(on, S5P_USBHOST_PHY_CONTROL); + } +} +#endif static int exynos4210_usb_phy0_init(struct platform_device *pdev) { u32 rstcon; @@ -120,21 +207,12 @@ static int exynos4210_usb_phy1_init(struct platform_device *pdev) { struct clk *otg_clk; u32 rstcon; - int err; atomic_inc(&host_usage); - otg_clk = clk_get(&pdev->dev, "otg"); - if (IS_ERR(otg_clk)) { - dev_err(&pdev->dev, "Failed to get otg clock\n"); - return PTR_ERR(otg_clk); - } - - err = clk_enable(otg_clk); - if (err) { - clk_put(otg_clk); - return err; - } + otg_clk = exynos_usb_clock_enable(pdev); + if (otg_clk == NULL) + dev_err(&pdev->dev, "Failed to enable otg clock\n"); if (exynos4_usb_host_phy_is_on()) return 0; @@ -173,22 +251,13 @@ static int exynos4210_usb_phy1_init(struct platform_device *pdev) static int exynos4210_usb_phy1_exit(struct platform_device *pdev) { struct clk *otg_clk; - int err; if (atomic_dec_return(&host_usage) > 0) return 0; - otg_clk = clk_get(&pdev->dev, "otg"); - if (IS_ERR(otg_clk)) { - dev_err(&pdev->dev, "Failed to get otg clock\n"); - return PTR_ERR(otg_clk); - } - - err = clk_enable(otg_clk); - if (err) { - clk_put(otg_clk); - return err; - } + otg_clk = exynos_usb_clock_enable(pdev); + if (otg_clk == NULL) + dev_err(&pdev->dev, "Failed to enable otg clock\n"); writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN), EXYNOS4_PHYPWR); @@ -202,22 +271,70 @@ static int exynos4210_usb_phy1_exit(struct platform_device *pdev) return 0; } + int s5p_usb_phy_init(struct platform_device *pdev, int type) { - if (type == S5P_USB_PHY_DEVICE) + if (type == USB_PHY_TYPE_DEVICE) return exynos4210_usb_phy0_init(pdev); - else if (type == S5P_USB_PHY_HOST) - return exynos4210_usb_phy1_init(pdev); + else if (type == USB_PHY_TYPE_HOST) { + return exynos4210_usb_phy1_init(pdev); + } return -EINVAL; } int s5p_usb_phy_exit(struct platform_device *pdev, int type) { - if (type == S5P_USB_PHY_DEVICE) - return exynos4210_usb_phy0_exit(pdev); - else if (type == S5P_USB_PHY_HOST) - return exynos4210_usb_phy1_exit(pdev); + if (type == USB_PHY_TYPE_DEVICE) + return exynos4210_usb_phy0_exit(pdev); + else if (type == USB_PHY_TYPE_HOST) { + return exynos4210_usb_phy1_exit(pdev); + } return -EINVAL; } + + void s5p_usb_phy_pmu_isolation(int on, int type) + { + if (type == USB_PHY_TYPE_HOST) { + if (on) + writel(readl(S5P_USBHOST_PHY_CONTROL) + & ~S5P_USBHOST_PHY_ENABLE, + S5P_USBHOST_PHY_CONTROL); + else + writel(readl(S5P_USBHOST_PHY_CONTROL) + | S5P_USBHOST_PHY_ENABLE, + S5P_USBHOST_PHY_CONTROL); + }else if(type == USB_PHY_TYPE_DRD) { + if (on) + writel(readl(S5P_USBDRD_PHY_CONTROL) + & ~S5P_USBDRD_PHY_ENABLE, + S5P_USBDRD_PHY_CONTROL); + else + writel(readl(S5P_USBDRD_PHY_CONTROL) + | S5P_USBDRD_PHY_ENABLE, + S5P_USBDRD_PHY_CONTROL); + } else { + if (on) + writel(readl(S5P_USBDEVICE_PHY_CONTROL) + & ~S5P_USBDEVICE_PHY_ENABLE, + S5P_USBDEVICE_PHY_CONTROL); + else + writel(readl(S5P_USBDEVICE_PHY_CONTROL) + | S5P_USBDEVICE_PHY_ENABLE, + S5P_USBDEVICE_PHY_CONTROL); + } + } + +/* Switch between HOST and OTG link from PHY_CFG */ +void s5p_usb_phy_cfg_sel(struct device *dev, int type) +{ + u32 is_host; + + is_host = readl(EXYNOS5_USB_CFG); + writel(type, EXYNOS5_USB_CFG); + + if (is_host != type) + dev_dbg(dev, "Changed USB MUX from %s to %s", + is_host ? "Host" : "Device", type ? "Host" : "Device"); +} diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 9d32a253aac..684a5fe84ea 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -17,6 +17,12 @@ obj-$(CONFIG_MODULES) += proc-syms.o obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o +ifeq ($(CONFIG_ARM_LPAE),y) +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage-3level.o +else +obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage-2level.o +endif obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o @@ -97,3 +103,5 @@ obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o + +obj-$(CONFIG_NUMA_ALLOC_NODES) += numa.o diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index bc4a5e9ebb7..7c17ff80882 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -20,6 +20,7 @@ #include <asm/smp_plat.h> #include <asm/thread_notify.h> #include <asm/tlbflush.h> +#include <asm/proc-fns.h> /* * On ARMv6, we have the following structure in the Context ID: @@ -52,17 +53,11 @@ static cpumask_t tlb_flush_pending; #ifdef CONFIG_ARM_LPAE static void cpu_set_reserved_ttbr0(void) { - unsigned long ttbl = __pa(swapper_pg_dir); - unsigned long ttbh = 0; - /* * Set TTBR0 to swapper_pg_dir which contains only global entries. The * ASID is set to 0. */ - asm volatile( - " mcrr p15, 0, %0, %1, c2 @ set TTBR0\n" - : - : "r" (ttbl), "r" (ttbh)); + cpu_set_ttbr(0, __pa(swapper_pg_dir)); isb(); } #else diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 6b2fb87c869..d2c7c3acf51 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -239,7 +239,7 @@ static void __dma_free_buffer(struct page *page, size_t size) #ifdef CONFIG_MMU #ifdef CONFIG_HUGETLB_PAGE -#error ARM Coherent DMA allocator does not (yet) support huge TLB +#warning ARM Coherent DMA allocator does not (yet) support huge TLB #endif static void *__alloc_from_contiguous(struct device *dev, size_t size, diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index e207aa5f846..b55bec0f1f0 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -497,13 +497,13 @@ do_translation_fault(unsigned long addr, unsigned int fsr, #endif /* CONFIG_MMU */ /* - * Some section permission faults need to be handled gracefully. - * They can happen due to a __{get,put}_user during an oops. + * A fault in a section will likely be due to a huge page, treat it + * as a page fault. */ static int do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { - do_bad_area(addr, fsr, regs); + do_page_fault(addr, fsr, regs); return 0; } diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 1c8f7f56417..0a69cb83a22 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -17,6 +17,7 @@ #include <asm/highmem.h> #include <asm/smp_plat.h> #include <asm/tlbflush.h> +#include <linux/hugetlb.h> #include "mm.h" @@ -168,17 +169,21 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page) * coherent with the kernels mapping. */ if (!PageHighMem(page)) { - __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE); + __cpuc_flush_dcache_area(page_address(page), (PAGE_SIZE << compound_order(page))); } else { - void *addr = kmap_high_get(page); - if (addr) { - __cpuc_flush_dcache_area(addr, PAGE_SIZE); - kunmap_high(page); - } else if (cache_is_vipt()) { - /* unmapped pages might still be cached */ - addr = kmap_atomic(page); - __cpuc_flush_dcache_area(addr, PAGE_SIZE); - kunmap_atomic(addr); + unsigned long i; + for(i = 0; i < (1 << compound_order(page)); i++) { + struct page *cpage = page + i; + void *addr = kmap_high_get(cpage); + if (addr) { + __cpuc_flush_dcache_area(addr, PAGE_SIZE); + kunmap_high(cpage); + } else if (cache_is_vipt()) { + /* unmapped pages might still be cached */ + addr = kmap_atomic(cpage); + __cpuc_flush_dcache_area(addr, PAGE_SIZE); + kunmap_atomic(addr); + } } } diff --git a/arch/arm/mm/fsr-3level.c b/arch/arm/mm/fsr-3level.c index 05a4e943183..47f4c6fb25b 100644 --- a/arch/arm/mm/fsr-3level.c +++ b/arch/arm/mm/fsr-3level.c @@ -9,7 +9,7 @@ static struct fsr_info fsr_info[] = { { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, { do_bad, SIGBUS, 0, "reserved access flag fault" }, { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, - { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, + { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, { do_bad, SIGBUS, 0, "reserved permission fault" }, { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, diff --git a/arch/arm/mm/hugetlbpage-2level.c b/arch/arm/mm/hugetlbpage-2level.c new file mode 100644 index 00000000000..4b2b38ca0f4 --- /dev/null +++ b/arch/arm/mm/hugetlbpage-2level.c @@ -0,0 +1,115 @@ +/* + * arch/arm/mm/hugetlbpage-2level.c + * + * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com> + * Copyright (C) 2012 ARM Ltd + * Copyright (C) 2012 Bill Carson. + * + * Based on arch/x86/include/asm/hugetlb.h and Bill Carson's patches + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/hugetlb.h> +#include <linux/pagemap.h> +#include <linux/err.h> +#include <linux/sysctl.h> +#include <asm/mman.h> +#include <asm/tlb.h> +#include <asm/tlbflush.h> +#include <asm/pgalloc.h> + +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + return 0; +} + +pte_t *huge_pte_alloc(struct mm_struct *mm, + unsigned long addr, unsigned long sz) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + pgd = pgd_offset(mm, addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + + return (pte_t *)pmd; /* our huge pte is actually a pmd */ +} + +struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, + pmd_t *pmd, int write) +{ + struct page *page; + unsigned long pfn; + + BUG_ON((pmd_val(*pmd) & PMD_TYPE_MASK) != PMD_TYPE_SECT); + pfn = ((pmd_val(*pmd) & HPAGE_MASK) >> PAGE_SHIFT); + page = pfn_to_page(pfn); + return page; +} + +pte_t huge_ptep_get(pte_t *ptep) +{ + pmd_t *pmdp = (pmd_t*)ptep; + pmdval_t pmdval = pmd_val(*pmdp); + pteval_t retval; + + if (!pmdval) + return __pte(0); + + retval = (pteval_t) (pmdval & HPAGE_MASK); + HPMD_XLATE(retval, pmdval, PMD_SECT_XN, L_PTE_XN); + HPMD_XLATE(retval, pmdval, PMD_SECT_S, L_PTE_SHARED); + HPMD_XLATE(retval, pmdval, PMD_DSECT_AF, L_PTE_YOUNG); + HPMD_XLATE(retval, pmdval, PMD_DSECT_DIRTY, L_PTE_DIRTY); + + /* preserve bits C & B */ + retval |= (pmdval & (3 << 2)); + + /* PMD TEX bit 0 corresponds to Linux PTE bit 4 */ + HPMD_XLATE(retval, pmdval, PMD_SECT_TEX(1), 1 << 4); + + if (pmdval & PMD_SECT_AP_WRITE) + retval &= ~L_PTE_RDONLY; + else + retval |= L_PTE_RDONLY; + + if ((pmdval & PMD_TYPE_MASK) == PMD_TYPE_SECT) + retval |= L_PTE_VALID; + + /* we assume all hugetlb pages are user */ + retval |= L_PTE_USER; + + return __pte(retval); +} + +void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) +{ + pmdval_t pmdval = (pmdval_t) pte_val(pte); + pmd_t *pmdp = (pmd_t*) ptep; + + pmdval &= HPAGE_MASK; + pmdval |= PMD_SECT_AP_READ | PMD_SECT_nG | PMD_TYPE_SECT; + pmdval = pmd_val(pmd_modify(__pmd(pmdval), __pgprot(pte_val(pte)))); + + __sync_icache_dcache(pte); + + set_pmd_at(mm, addr, pmdp, __pmd(pmdval)); +} diff --git a/arch/arm/mm/hugetlbpage-3level.c b/arch/arm/mm/hugetlbpage-3level.c new file mode 100644 index 00000000000..86474f01104 --- /dev/null +++ b/arch/arm/mm/hugetlbpage-3level.c @@ -0,0 +1,190 @@ +/* + * arch/arm/mm/hugetlbpage-3level.c + * + * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com> + * Copyright (C) 2012 ARM Ltd. + * + * Based on arch/x86/mm/hugetlbpage.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/hugetlb.h> +#include <linux/pagemap.h> +#include <linux/err.h> +#include <linux/sysctl.h> +#include <asm/mman.h> +#include <asm/tlb.h> +#include <asm/tlbflush.h> +#include <asm/pgalloc.h> + +static unsigned long page_table_shareable(struct vm_area_struct *svma, + struct vm_area_struct *vma, + unsigned long addr, pgoff_t idx) +{ + unsigned long saddr = ((idx - svma->vm_pgoff) << PAGE_SHIFT) + + svma->vm_start; + unsigned long sbase = saddr & PUD_MASK; + unsigned long s_end = sbase + PUD_SIZE; + + /* Allow segments to share if only one is marked locked */ + unsigned long vm_flags = vma->vm_flags & ~VM_LOCKED; + unsigned long svm_flags = svma->vm_flags & ~VM_LOCKED; + + /* + * match the virtual addresses, permission and the alignment of the + * page table page. + */ + if (pmd_index(addr) != pmd_index(saddr) || + vm_flags != svm_flags || + sbase < svma->vm_start || svma->vm_end < s_end) + return 0; + + return saddr; +} + +static int vma_shareable(struct vm_area_struct *vma, unsigned long addr) +{ + unsigned long base = addr & PUD_MASK; + unsigned long end = base + PUD_SIZE; + + /* + * check on proper vm_flags and page table alignment + */ + if (vma->vm_flags & VM_MAYSHARE && + vma->vm_start <= base && end <= vma->vm_end) + return 1; + return 0; +} + +/* + * search for a shareable pmd page for hugetlb. + */ +static pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, + pud_t *pud) +{ + struct vm_area_struct *vma = find_vma(mm, addr); + struct address_space *mapping = vma->vm_file->f_mapping; + pgoff_t idx = ((addr - vma->vm_start) >> PAGE_SHIFT) + + vma->vm_pgoff; + struct vm_area_struct *svma; + unsigned long saddr; + pte_t *spte = NULL; + pte_t *pte; + + if (!vma_shareable(vma, addr)) + return (pte_t *)pmd_alloc(mm, pud, addr); + + mutex_lock(&mapping->i_mmap_mutex); + vma_interval_tree_foreach(svma, &mapping->i_mmap, idx, idx) { + if (svma == vma) + continue; + + saddr = page_table_shareable(svma, vma, addr, idx); + if (saddr) { + spte = huge_pte_offset(svma->vm_mm, saddr); + if (spte) { + get_page(virt_to_page(spte)); + break; + } + } + } + + if (!spte) + goto out; + + spin_lock(&mm->page_table_lock); + if (pud_none(*pud)) + pud_populate(mm, pud, (pmd_t *)((unsigned long)spte & PAGE_MASK)); + else + put_page(virt_to_page(spte)); + spin_unlock(&mm->page_table_lock); +out: + pte = (pte_t *)pmd_alloc(mm, pud, addr); + mutex_unlock(&mapping->i_mmap_mutex); + return pte; +} + +/* + * unmap huge page backed by shared pte. + * + * Hugetlb pte page is ref counted at the time of mapping. If pte is shared + * indicated by page_count > 1, unmap is achieved by clearing pud and + * decrementing the ref count. If count == 1, the pte page is not shared. + * + * called with vma->vm_mm->page_table_lock held. + * + * returns: 1 successfully unmapped a shared pte page + * 0 the underlying pte page is not shared, or it is the last user + */ +int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) +{ + pgd_t *pgd = pgd_offset(mm, *addr); + pud_t *pud = pud_offset(pgd, *addr); + + BUG_ON(page_count(virt_to_page(ptep)) == 0); + if (page_count(virt_to_page(ptep)) == 1) + return 0; + + pud_clear(pud); + put_page(virt_to_page(ptep)); + *addr = ALIGN(*addr, HPAGE_SIZE * PTRS_PER_PTE) - HPAGE_SIZE; + return 1; +} + +pte_t *huge_pte_alloc(struct mm_struct *mm, + unsigned long addr, unsigned long sz) +{ + pgd_t *pgd; + pud_t *pud; + pte_t *pte = NULL; + + pgd = pgd_offset(mm, addr); + pud = pud_alloc(mm, pgd, addr); + if (pud) { + BUG_ON(sz != PMD_SIZE); + if (pud_none(*pud)) + pte = huge_pmd_share(mm, addr, pud); + else + pte = (pte_t *)pmd_alloc(mm, pud, addr); + } + BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte)); + + return pte; +} + +struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, + pmd_t *pmd, int write) +{ + struct page *page; + + page = pte_page(*(pte_t *)pmd); + if (page) + page += ((address & ~PMD_MASK) >> PAGE_SHIFT); + return page; +} + +struct page *follow_huge_pud(struct mm_struct *mm, unsigned long address, + pud_t *pud, int write) +{ + struct page *page; + + page = pte_page(*(pte_t *)pud); + if (page) + page += ((address & ~PUD_MASK) >> PAGE_SHIFT); + return page; +} diff --git a/arch/arm/mm/hugetlbpage.c b/arch/arm/mm/hugetlbpage.c new file mode 100644 index 00000000000..32fe7fdae0a --- /dev/null +++ b/arch/arm/mm/hugetlbpage.c @@ -0,0 +1,65 @@ +/* + * arch/arm/mm/hugetlbpage.c + * + * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com> + * Copyright (C) 2012 ARM Ltd. + * + * Based on arch/x86/mm/hugetlbpage.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/hugetlb.h> +#include <linux/pagemap.h> +#include <linux/err.h> +#include <linux/sysctl.h> +#include <asm/mman.h> +#include <asm/tlb.h> +#include <asm/tlbflush.h> +#include <asm/pgalloc.h> + +pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd = NULL; + + pgd = pgd_offset(mm, addr); + if (pgd_present(*pgd)) { + pud = pud_offset(pgd, addr); + if (pud_present(*pud)) + pmd = pmd_offset(pud, addr); + } + + return (pte_t *)pmd; +} + +struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, + int write) +{ + return ERR_PTR(-EINVAL); +} + +int pmd_huge(pmd_t pmd) +{ + return (pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_SECT; +} + +int pud_huge(pud_t pud) +{ + return 0; +} diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index ad722f1208a..e5c80b6a4c8 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -33,15 +33,17 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> +#include <asm/mmzone.h> #include "mm.h" -static unsigned long phys_initrd_start __initdata = 0; +static phys_addr_t phys_initrd_start __initdata = 0; static unsigned long phys_initrd_size __initdata = 0; static int __init early_initrd(char *p) { - unsigned long start, size; + phys_addr_t start; + unsigned long size; char *endp; start = memparse(p, &endp); @@ -94,36 +96,56 @@ void show_mem(unsigned int filter) { int free = 0, total = 0, reserved = 0; int shared = 0, cached = 0, slab = 0, i; - struct meminfo * mi = &meminfo; + struct meminfo *mi = &meminfo; + struct memblock_region *reg; printk("Mem-info:\n"); show_free_areas(filter); for_each_bank (i, mi) { struct membank *bank = &mi->bank[i]; - unsigned int pfn1, pfn2; - struct page *page, *end; - - pfn1 = bank_pfn_start(bank); - pfn2 = bank_pfn_end(bank); - - page = pfn_to_page(pfn1); - end = pfn_to_page(pfn2 - 1) + 1; - - do { - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (PageSlab(page)) - slab++; - else if (!page_count(page)) - free++; - else - shared += page_count(page) - 1; - page++; - } while (page < end); + unsigned int sbank, ebank; + + sbank = bank_pfn_start(bank); + ebank = bank_pfn_end(bank); + + /* consider every memory block that intersects our memory bank */ + for_each_memblock(memory, reg) { + struct page *page, *end; + unsigned int pfn1, pfn2; + unsigned int sblock = memblock_region_memory_base_pfn(reg); + unsigned int eblock = memblock_region_memory_end_pfn(reg); + + /* we're beyond the membank */ + if (sblock >= ebank) + break; + + /* we're not yet at the membank */ + if (eblock <= sbank) + continue; + + /* take the intersection between bank and block */ + pfn1 = max(sblock, sbank); + pfn2 = min(eblock, ebank); + + page = pfn_to_page(pfn1); + end = pfn_to_page(pfn2 - 1) + 1; + + do { + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (PageSlab(page)) + slab++; + else if (!page_count(page)) + free++; + else + shared += page_count(page) - 1; + page++; + } while (page < end); + } } printk("%d pages of RAM\n", total); @@ -158,6 +180,12 @@ static void __init arm_bootmem_init(unsigned long start_pfn, pg_data_t *pgdat; /* + * If we have NUMA or discontiguous memory, allocate the required + * nodes by reserving memblocks. + */ + arm_numa_alloc_nodes(end_pfn); + + /* * Allocate the bootmem bitmap page. This must be in a region * of memory which has already been mapped. */ @@ -241,56 +269,31 @@ void __init setup_dma_zone(struct machine_desc *mdesc) static void __init arm_bootmem_free(unsigned long min, unsigned long max_low, unsigned long max_high) { - unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; - struct memblock_region *reg; + unsigned long max_zone_pfns[MAX_NR_ZONES]; /* - * initialise the zones. - */ - memset(zone_size, 0, sizeof(zone_size)); - - /* - * The memory size has already been determined. If we need - * to do anything fancy with the allocation of this memory - * to the zones, now is the time to do it. + * On NUMA systems we register a CPU notifier, split the memory between + * the nodes and bring them online before free_area_init_nodes). + * + * Otherwise, we put all memory into node 0. */ - zone_size[0] = max_low - min; -#ifdef CONFIG_HIGHMEM - zone_size[ZONE_HIGHMEM] = max_high - max_low; -#endif - + arm_setup_nodes(min, max_high); + /* - * Calculate the size of the holes. - * holes = node_size - sum(bank_sizes) + * initialise the zones. */ - memcpy(zhole_size, zone_size, sizeof(zhole_size)); - for_each_memblock(memory, reg) { - unsigned long start = memblock_region_memory_base_pfn(reg); - unsigned long end = memblock_region_memory_end_pfn(reg); + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_NORMAL] = max_low; - if (start < max_low) { - unsigned long low_end = min(end, max_low); - zhole_size[0] -= low_end - start; - } #ifdef CONFIG_HIGHMEM - if (end > max_low) { - unsigned long high_start = max(start, max_low); - zhole_size[ZONE_HIGHMEM] -= end - high_start; - } + max_zone_pfns[ZONE_HIGHMEM] = max_high; #endif - } -#ifdef CONFIG_ZONE_DMA - /* - * Adjust the sizes according to any special requirements for - * this machine type. - */ - if (arm_dma_zone_size) - arm_adjust_dma_zone(zone_size, zhole_size, - arm_dma_zone_size >> PAGE_SHIFT); +#ifdef CONFIG_DMA + max_zone_pfns[ZONE_DMA] = __phys_to_pfn(arm_dma_limit); #endif - free_area_init_node(0, zone_size, min, zhole_size); + free_area_init_nodes(max_zone_pfns); } #ifdef CONFIG_HAVE_ARCH_PFN_VALID @@ -347,14 +350,14 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) #ifdef CONFIG_BLK_DEV_INITRD if (phys_initrd_size && !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) { - pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n", - phys_initrd_start, phys_initrd_size); + pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n", + (u64)phys_initrd_start, phys_initrd_size); phys_initrd_start = phys_initrd_size = 0; } if (phys_initrd_size && memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) { - pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n", - phys_initrd_start, phys_initrd_size); + pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n", + (u64)phys_initrd_start, phys_initrd_size); phys_initrd_start = phys_initrd_size = 0; } if (phys_initrd_size) { @@ -457,7 +460,7 @@ static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn) { struct page *start_pg, *end_pg; - unsigned long pg, pgend; + phys_addr_t pg, pgend; /* * Convert start_pfn/end_pfn to a struct page pointer. @@ -469,8 +472,8 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn) * Convert to physical addresses, and * round start upwards and end downwards. */ - pg = (unsigned long)PAGE_ALIGN(__pa(start_pg)); - pgend = (unsigned long)__pa(end_pg) & PAGE_MASK; + pg = PAGE_ALIGN(__pa(start_pg)); + pgend = __pa(end_pg) & PAGE_MASK; /* * If there are free pages between these, @@ -600,7 +603,9 @@ void __init mem_init(void) extern u32 itcm_end; #endif +#ifdef CONFIG_FLATMEM max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; +#endif /* this will put all unused low memory onto the freelists */ free_unused_memmap(&meminfo); @@ -619,22 +624,41 @@ void __init mem_init(void) for_each_bank(i, &meminfo) { struct membank *bank = &meminfo.bank[i]; - unsigned int pfn1, pfn2; - struct page *page, *end; - - pfn1 = bank_pfn_start(bank); - pfn2 = bank_pfn_end(bank); - - page = pfn_to_page(pfn1); - end = pfn_to_page(pfn2 - 1) + 1; - - do { - if (PageReserved(page)) - reserved_pages++; - else if (!page_count(page)) - free_pages++; - page++; - } while (page < end); + unsigned int sbank, ebank; + + sbank = bank_pfn_start(bank); + ebank = bank_pfn_end(bank); + + /* consider every memory block that intersects our memory bank */ + for_each_memblock(memory, reg) { + struct page *page, *end; + unsigned int pfn1, pfn2; + unsigned int sblock = memblock_region_memory_base_pfn(reg); + unsigned int eblock = memblock_region_memory_end_pfn(reg); + + /* we're beyond the membank */ + if (sblock >= ebank) + break; + + /* we're not yet at the membank */ + if (eblock <= sbank) + continue; + + /* take the intersection between bank and block */ + pfn1 = max(sblock, sbank); + pfn2 = min(eblock, ebank); + + page = pfn_to_page(pfn1); + end = pfn_to_page(pfn2 - 1) + 1; + + do { + if (PageReserved(page)) + reserved_pages++; + else if (!page_count(page)) + free_pages++; + page++; + } while (page < end); + } } /* diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 59eeb5c20bd..aa677868334 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -950,27 +950,28 @@ phys_addr_t arm_lowmem_limit __initdata = 0; void __init sanity_check_meminfo(void) { int i, j, highmem = 0; + phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1; for (i = 0, j = 0; i < meminfo.nr_banks; i++) { struct membank *bank = &meminfo.bank[j]; - *bank = meminfo.bank[i]; + phys_addr_t size_limit; - if (bank->start > ULONG_MAX) - highmem = 1; + *bank = meminfo.bank[i]; + size_limit = bank->size; -#ifdef CONFIG_HIGHMEM - if (__va(bank->start) >= vmalloc_min || - __va(bank->start) < (void *)PAGE_OFFSET) + if (bank->start >= vmalloc_limit) highmem = 1; + else + size_limit = vmalloc_limit - bank->start; bank->highmem = highmem; +#ifdef CONFIG_HIGHMEM /* * Split those memory banks which are partially overlapping * the vmalloc area greatly simplifying things later. */ - if (!highmem && __va(bank->start) < vmalloc_min && - bank->size > vmalloc_min - __va(bank->start)) { + if (!highmem && bank->size > size_limit) { if (meminfo.nr_banks >= NR_BANKS) { printk(KERN_CRIT "NR_BANKS too low, " "ignoring high memory\n"); @@ -979,16 +980,14 @@ void __init sanity_check_meminfo(void) (meminfo.nr_banks - i) * sizeof(*bank)); meminfo.nr_banks++; i++; - bank[1].size -= vmalloc_min - __va(bank->start); - bank[1].start = __pa(vmalloc_min - 1) + 1; + bank[1].size -= size_limit; + bank[1].start = vmalloc_limit; bank[1].highmem = highmem = 1; j++; } - bank->size = vmalloc_min - __va(bank->start); + bank->size = size_limit; } #else - bank->highmem = highmem; - /* * Highmem banks not allowed with !CONFIG_HIGHMEM. */ @@ -1001,31 +1000,16 @@ void __init sanity_check_meminfo(void) } /* - * Check whether this memory bank would entirely overlap - * the vmalloc area. - */ - if (__va(bank->start) >= vmalloc_min || - __va(bank->start) < (void *)PAGE_OFFSET) { - printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx " - "(vmalloc region overlap).\n", - (unsigned long long)bank->start, - (unsigned long long)bank->start + bank->size - 1); - continue; - } - - /* * Check whether this memory bank would partially overlap * the vmalloc area. */ - if (__va(bank->start + bank->size - 1) >= vmalloc_min || - __va(bank->start + bank->size - 1) <= __va(bank->start)) { - unsigned long newsize = vmalloc_min - __va(bank->start); + if (bank->size > size_limit) { printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx " "to -%.8llx (vmalloc region overlap).\n", (unsigned long long)bank->start, (unsigned long long)bank->start + bank->size - 1, - (unsigned long long)bank->start + newsize - 1); - bank->size = newsize; + (unsigned long long)bank->start + size_limit - 1); + bank->size = size_limit; } #endif if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit) diff --git a/arch/arm/mm/numa.c b/arch/arm/mm/numa.c new file mode 100644 index 00000000000..5933e2caf2d --- /dev/null +++ b/arch/arm/mm/numa.c @@ -0,0 +1,278 @@ +/* + * Discontiguous memory and NUMA support, based on the PowerPC implementation. + * + * Copyright (C) 2012 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. + * + * 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/export.h> +#include <linux/nodemask.h> +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <linux/mmzone.h> +#include <linux/node.h> +#include <linux/cpu.h> +#include <linux/memblock.h> + +#include <asm/string.h> +#include <asm/mmzone.h> +#include <asm/setup.h> + +struct pglist_data *node_data[MAX_NUMNODES]; +EXPORT_SYMBOL(node_data); + +static unsigned int numa_node_count = 1; + +cpumask_var_t *node_to_cpumask_map; +EXPORT_SYMBOL(node_to_cpumask_map); + +void __init arm_numa_alloc_nodes(unsigned long max_low) +{ + int node; + + arm_numa_alloc_cpumask(max_low); + + for (node = 0; node < numa_node_count; node++) { + phys_addr_t pa = memblock_alloc_base(sizeof(pg_data_t), + L1_CACHE_BYTES, __pfn_to_phys(max_low)); + + NODE_DATA(node) = __va(pa); + memset(NODE_DATA(node), 0, sizeof(pg_data_t)); + NODE_DATA(node)->bdata = &bootmem_node_data[node]; + } +} + +#ifdef CONFIG_NUMA + +static unsigned int numa_use_topology; + +static char *memcmdline __initdata; + +int numa_cpu_lookup_table[NR_CPUS]; +EXPORT_SYMBOL(numa_cpu_lookup_table); + +static unsigned long pfn_starts[MAX_NUMNODES]; + +#ifdef CONFIG_DISCONTIGMEM +int pfn_to_nid(unsigned long pfn) +{ + int node; + + for (node = numa_node_count - 1; node >= 0; node--) + if (pfn >= pfn_starts[node]) + return node; + + panic("NUMA: Unable to locate nid for %lX\n", pfn); + return 0; +} +#endif + +void __init arm_numa_alloc_cpumask(unsigned long max_low) +{ + size_t size = sizeof(cpumask_var_t) * numa_node_count; + node_to_cpumask_map = __va(memblock_alloc_base(size, + L1_CACHE_BYTES, __pfn_to_phys(max_low))); + memset(node_to_cpumask_map, 0, size); +} + +/* + * Add a CPU to a NUMA node. + * Default assignment policy is the cpu number modulo the number of nodes. + * + * We can also group CPUs via the topology_physical_package_id. + * (if the user adds "usetopology" to the command line). + * When we add CPU 0 (the boot CPU), it is always to node 0, as we don't have + * the topology information at that time. + * Subsequent CPUs get added based on the topology_physical_package_id. + * To stop CPU0 being added to the same node as CPUs on a different cluster, + * we subtract the topology_physical_package_id of node 0. + * + * This ensures that the TC2 has equivalent node configurations when booted + * off the A15s or the A7s. + */ +static void add_cpu_to_node(int cpu) +{ + unsigned int node; + unsigned int n0 = topology_physical_package_id(0); + unsigned int nc = topology_physical_package_id(cpu); + + if (numa_use_topology) + node = cpu ? (numa_node_count + nc - n0) % numa_node_count : 0; + else + node = cpu % numa_node_count; + + cpumask_set_cpu(cpu, node_to_cpumask_map[node]); + numa_cpu_lookup_table[cpu] = node; + pr_info("NUMA: Adding CPU %d to node %d\n", cpu, node); +} + +static int __cpuinit numa_add_cpu(struct notifier_block *self, + unsigned long action, void *cpu) +{ + if (action == CPU_ONLINE) + add_cpu_to_node((int)cpu); + + return NOTIFY_OK; + +} + +static struct notifier_block __cpuinitdata numa_node_nb = { + .notifier_call = numa_add_cpu, + .priority = 1, /* Must run before sched domains notifier. */ +}; + +/* + * Split the available memory between the NUMA nodes. + * We want all the pages mapped by a pmd to belong to the same node; as code, + * such as the THP splitting code, assumes pmds are backed by contiguous + * struct page *s. So we mask off the sizes with "rmask". + * + * By default, the memory is distributed roughly evenly between nodes. + * + * One can also specify requested node sizes on the command line, if + * "memcmdline" is not NULL, we try to parse it as a size. + * + * We traverse memory blocks rather than the pfn addressable range to allow for + * sparse memory configurations and memory holes. + */ +static void __init arm_numa_split_memblocks(void) +{ + const unsigned long rmask = ~((1UL << (PMD_SHIFT - PAGE_SHIFT)) - 1); + unsigned int node; + unsigned long pfnsrem = 0, pfnsblock, pfncurr, pfnend = 0; + struct memblock_region *reg; + + for_each_memblock(memory, reg) { + pfnend = memblock_region_memory_end_pfn(reg); + pfnsrem += pfnend - memblock_region_memory_base_pfn(reg); + } + + reg = memblock.memory.regions; + pfnsblock = memblock_region_memory_end_pfn(reg) + - memblock_region_memory_base_pfn(reg); + + pfncurr = memblock_region_memory_base_pfn(reg); + pfn_starts[0] = pfncurr; + + for (node = 0; node < numa_node_count - 1; node++) { + unsigned long pfnsnode = pfnsrem / (numa_node_count - node) + & rmask; + + if (memcmdline) { + unsigned long nsize = __phys_to_pfn( + memparse(memcmdline, &memcmdline)) + & rmask; + if (*memcmdline == ',') + ++memcmdline; + + if ((nsize > 0) && (nsize < pfnsrem)) + pfnsnode = nsize; + else + memcmdline = NULL; + } + + while (pfnsnode > 0) { + unsigned long pfnsset = min(pfnsnode, pfnsblock); + + pfncurr += pfnsset; + + pfnsblock -= pfnsset; + pfnsrem -= pfnsset; + pfnsnode -= pfnsset; + + if (pfnsblock == 0) { + reg++; + pfnsblock = memblock_region_memory_end_pfn(reg) + - memblock_region_memory_base_pfn(reg); + pfncurr = memblock_region_memory_base_pfn(reg); + } + } + + pfn_starts[node + 1] = pfncurr; + } + + for (node = 0; node < numa_node_count - 1; node++) + memblock_set_node(__pfn_to_phys(pfn_starts[node]), + __pfn_to_phys(pfn_starts[node + 1] - pfn_starts[node]), + node); + + memblock_set_node(__pfn_to_phys(pfn_starts[node]), + __pfn_to_phys(pfnend - pfn_starts[node]), node); + +} + +void __init arm_setup_nodes(unsigned long min, unsigned long max_high) +{ + int node; + + register_cpu_notifier(&numa_node_nb); + arm_numa_split_memblocks(); + + + for (node = 0; node < numa_node_count; node++) { + alloc_bootmem_cpumask_var(&node_to_cpumask_map[node]); + node_set_online(node); + } + + add_cpu_to_node(0); + +} + +static int __init early_numa(char *p) +{ + if (!p) + return 0; + + p = strstr(p, "fake="); + if (p) { + int num_nodes = 0; + int optres; + + p += strlen("fake="); + optres = get_option(&p, &num_nodes); + if ((optres == 0) || (optres == 3)) + return -EINVAL; + + if ((num_nodes > 0) && (num_nodes <= MAX_NUMNODES)) { + pr_info("NUMA: setting up fake NUMA with %d nodes.\n", + num_nodes); + + numa_node_count = num_nodes; + } else { + pr_info("NUMA: can't set up %d nodes for NUMA (MAX_NUMNODES = %d)\n", + num_nodes, MAX_NUMNODES); + return -EINVAL; + } + + /* + * If a comma was specified after the number of nodes then subsequent + * numbers should be regarded as memory sizes for each node for as + * many nodes as are supplied. + */ + if (optres == 2) + memcmdline = p; + + if (strstr(p, "usetopology")) { + numa_use_topology = 1; + pr_info("NUMA: using CPU topology to assign nodes.\n"); + } else + pr_info("NUMA: NOT using CPU topology.\n"); + } + + return 0; +} +early_param("numa", early_numa); + +#endif /* CONFIG_NUMA */ diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S index cdadc2fff92..4b6c527fa25 100644 --- a/arch/arm/mm/proc-v7-3level.S +++ b/arch/arm/mm/proc-v7-3level.S @@ -39,6 +39,14 @@ #define TTB_FLAGS_SMP (TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA) #define PMD_FLAGS_SMP (PMD_SECT_WBWA|PMD_SECT_S) +#ifndef __ARMEB__ +# define rpgdl r0 +# define rpgdh r1 +#else +# define rpgdl r1 +# define rpgdh r0 +#endif + /* * cpu_v7_switch_mm(pgd_phys, tsk) * @@ -47,10 +55,11 @@ */ ENTRY(cpu_v7_switch_mm) #ifdef CONFIG_MMU - ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id - and r3, r1, #0xff - mov r3, r3, lsl #(48 - 32) @ ASID - mcrr p15, 0, r0, r3, c2 @ set TTB 0 + ldr r2, [r2, #MM_CONTEXT_ID] @ get mm->context.id + and r2, r2, #0xff + mov r2, r2, lsl #(48 - 32) @ ASID + orr rpgdh, rpgdh, r2 @ upper 32-bits of pgd phys + mcrr p15, 0, rpgdl, rpgdh, c2 @ set TTB 0 isb #endif mov pc, lr @@ -107,6 +116,7 @@ ENDPROC(cpu_v7_set_pte_ext) */ .macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address + mov \tmp, \tmp, lsr #ARCH_PGD_SHIFT cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET? (branch below) mrc p15, 0, \tmp, c2, c0, 2 @ TTB control register orr \tmp, \tmp, #TTB_EAE @@ -124,18 +134,17 @@ ENDPROC(cpu_v7_set_pte_ext) * booting secondary CPUs would end up using TTBR1 for the identity * mapping set up in TTBR0. */ - bhi 9001f @ PHYS_OFFSET > PAGE_OFFSET? - orr \tmp, \tmp, #(((PAGE_OFFSET >> 30) - 1) << 16) @ TTBCR.T1SZ -#if defined CONFIG_VMSPLIT_2G - /* PAGE_OFFSET == 0x80000000, T1SZ == 1 */ - add \ttbr1, \ttbr1, #1 << 4 @ skip two L1 entries -#elif defined CONFIG_VMSPLIT_3G - /* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */ - add \ttbr1, \ttbr1, #4096 * (1 + 3) @ only L2 used, skip pgd+3*pmd -#endif - /* CONFIG_VMSPLIT_1G does not need TTBR1 adjustment */ -9001: mcr p15, 0, \tmp, c2, c0, 2 @ TTB control register - mcrr p15, 1, \ttbr1, \zero, c2 @ load TTBR1 + orrls \tmp, \tmp, #TTBR1_SIZE @ TTBCR.T1SZ + mcr p15, 0, \tmp, c2, c0, 2 @ TTBCR + mov \tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits + mov \ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT @ lower bits + addls \ttbr1, \ttbr1, #TTBR1_OFFSET + mcrr p15, 1, \ttbr1, \zero, c2 @ load TTBR1 + mov \tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT) @ upper bits + mov \ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT @ lower bits + mcrr p15, 0, \ttbr0, \zero, c2 @ load TTBR0 + mcrr p15, 1, \ttbr1, \zero, c2 @ load TTBR1 + mcrr p15, 0, \ttbr0, \zero, c2 @ load TTBR0 .endm __CPUINIT diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index a9d52167e16..c67ff56c2e6 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -371,6 +371,11 @@ config S5P_DEV_G2D help Compile in platform device definitions for G2D device +config S5P_DEV_G3D + bool + help + Compile in platform device definitions for G3D device + config S5P_DEV_I2C_HDMIPHY bool help diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 51afedda9ab..9e21d3f6bc5 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -282,6 +282,25 @@ struct platform_device s5p_device_g2d = { }; #endif /* CONFIG_S5P_DEV_G2D */ +/* G3D */ + +#ifdef CONFIG_S5P_DEV_G3D +static struct resource s5p_g3d_resource[] = { + [0] = DEFINE_RES_MEM(S5P_PA_G3D, SZ_256K), +}; + +struct platform_device s5p_device_g3d = { + .name = "s5p-g3d", + .id = 0, + .num_resources = ARRAY_SIZE(s5p_g3d_resource), + .resource = s5p_g3d_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +#endif /* CONFIG_S5P_DEV_G3D */ + #ifdef CONFIG_S5P_DEV_JPEG static struct resource s5p_jpeg_resource[] = { [0] = DEFINE_RES_MEM(S5P_PA_JPEG, SZ_4K), @@ -1113,7 +1132,7 @@ struct platform_device s5p_device_onenand = { /* PMU */ -#ifdef CONFIG_PLAT_S5P +#if defined(CONFIG_PLAT_S5P) && !defined(CONFIG_ARCH_EXYNOS) static struct resource s5p_pmu_resource[] = { DEFINE_RES_IRQ(IRQ_PMU) }; diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index 87d501ff332..e4bbd7d0ccd 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -83,6 +83,7 @@ extern struct platform_device s5p_device_fimc3; extern struct platform_device s5p_device_fimc_md; extern struct platform_device s5p_device_jpeg; extern struct platform_device s5p_device_g2d; +extern struct platform_device s5p_device_g3d; extern struct platform_device s5p_device_fimd0; extern struct platform_device s5p_device_hdmi; extern struct platform_device s5p_device_i2c_hdmiphy; @@ -134,7 +135,6 @@ extern struct platform_device exynos4_device_spdif; extern struct platform_device samsung_asoc_idma; extern struct platform_device samsung_device_keypad; - /* s3c2440 specific devices */ #ifdef CONFIG_CPU_S3C2440 diff --git a/arch/arm/plat-samsung/include/plat/map-s5p.h b/arch/arm/plat-samsung/include/plat/map-s5p.h index c2d7bdae589..b98be492ee0 100644 --- a/arch/arm/plat-samsung/include/plat/map-s5p.h +++ b/arch/arm/plat-samsung/include/plat/map-s5p.h @@ -40,6 +40,8 @@ #define S5P_VA_GIC_CPU S3C_ADDR(0x02810000) #define S5P_VA_GIC_DIST S3C_ADDR(0x02820000) +#define S5P_VA_AUDSS S3C_ADDR(0X02A00000) + #define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000)) #define VA_VIC0 VA_VIC(0) #define VA_VIC1 VA_VIC(1) diff --git a/arch/arm/plat-samsung/include/plat/usb-phy.h b/arch/arm/plat-samsung/include/plat/usb-phy.h index 959bcdb03a2..72fb3122912 100644 --- a/arch/arm/plat-samsung/include/plat/usb-phy.h +++ b/arch/arm/plat-samsung/include/plat/usb-phy.h @@ -11,12 +11,8 @@ #ifndef __PLAT_SAMSUNG_USB_PHY_H #define __PLAT_SAMSUNG_USB_PHY_H __FILE__ -enum s5p_usb_phy_type { - S5P_USB_PHY_DEVICE, - S5P_USB_PHY_HOST, -}; - extern int s5p_usb_phy_init(struct platform_device *pdev, int type); extern int s5p_usb_phy_exit(struct platform_device *pdev, int type); - +extern void s5p_usb_phy_pmu_isolation(int on, int type); +extern void s5p_usb_phy_cfg_sel(struct device *dev, int type); #endif /* __PLAT_SAMSUNG_USB_PHY_H */ diff --git a/arch/arm/plat-samsung/s5p-dev-mfc.c b/arch/arm/plat-samsung/s5p-dev-mfc.c index 5ec104b5408..d7c679b7588 100644 --- a/arch/arm/plat-samsung/s5p-dev-mfc.c +++ b/arch/arm/plat-samsung/s5p-dev-mfc.c @@ -12,6 +12,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/dma-contiguous.h> #include <linux/memblock.h> #include <linux/ioport.h> #include <linux/of_fdt.h> @@ -22,55 +23,17 @@ #include <plat/irqs.h> #include <plat/mfc.h> -struct s5p_mfc_reserved_mem { - phys_addr_t base; - unsigned long size; - struct device *dev; -}; - -static struct s5p_mfc_reserved_mem s5p_mfc_mem[2] __initdata; - void __init s5p_mfc_reserve_mem(phys_addr_t rbase, unsigned int rsize, phys_addr_t lbase, unsigned int lsize) { - int i; - - s5p_mfc_mem[0].dev = &s5p_device_mfc_r.dev; - s5p_mfc_mem[0].base = rbase; - s5p_mfc_mem[0].size = rsize; - - s5p_mfc_mem[1].dev = &s5p_device_mfc_l.dev; - s5p_mfc_mem[1].base = lbase; - s5p_mfc_mem[1].size = lsize; - - for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) { - struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i]; - if (memblock_remove(area->base, area->size)) { - printk(KERN_ERR "Failed to reserve memory for MFC device (%ld bytes at 0x%08lx)\n", - area->size, (unsigned long) area->base); - area->base = 0; - } - } -} - -static int __init s5p_mfc_memory_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(s5p_mfc_mem); i++) { - struct s5p_mfc_reserved_mem *area = &s5p_mfc_mem[i]; - if (!area->base) - continue; + if (dma_declare_contiguous(&s5p_device_mfc_r.dev, rsize, rbase, 0)) + printk(KERN_ERR "Failed to reserve memory for MFC device (%u bytes at 0x%08lx)\n", + rsize, (unsigned long) rbase); - if (dma_declare_coherent_memory(area->dev, area->base, - area->base, area->size, - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) - printk(KERN_ERR "Failed to declare coherent memory for MFC device (%ld bytes at 0x%08lx)\n", - area->size, (unsigned long) area->base); - } - return 0; + if (dma_declare_contiguous(&s5p_device_mfc_l.dev, lsize, lbase, 0)) + printk(KERN_ERR "Failed to reserve memory for MFC device (%u bytes at 0x%08lx)\n", + rsize, (unsigned long) rbase); } -device_initcall(s5p_mfc_memory_init); #ifdef CONFIG_OF int __init s5p_fdt_find_mfc_mem(unsigned long node, const char *uname, |