diff options
270 files changed, 6505 insertions, 3950 deletions
diff --git a/Documentation/block/00-INDEX b/Documentation/block/00-INDEX index d111e3b23db0..d18ecd827c40 100644 --- a/Documentation/block/00-INDEX +++ b/Documentation/block/00-INDEX @@ -3,15 +3,21 @@ biodoc.txt - Notes on the Generic Block Layer Rewrite in Linux 2.5 capability.txt - - Generic Block Device Capability (/sys/block/<disk>/capability) + - Generic Block Device Capability (/sys/block/<device>/capability) +cfq-iosched.txt + - CFQ IO scheduler tunables +data-integrity.txt + - Block data integrity deadline-iosched.txt - Deadline IO scheduler tunables ioprio.txt - Block io priorities (in CFQ scheduler) +queue-sysfs.txt + - Queue's sysfs entries request.txt - The members of struct request (in include/linux/blkdev.h) stat.txt - - Block layer statistics in /sys/block/<dev>/stat + - Block layer statistics in /sys/block/<device>/stat switching-sched.txt - Switching I/O schedulers at runtime writeback_cache_control.txt diff --git a/Documentation/block/cfq-iosched.txt b/Documentation/block/cfq-iosched.txt index 6d670f570451..d89b4fe724d7 100644 --- a/Documentation/block/cfq-iosched.txt +++ b/Documentation/block/cfq-iosched.txt @@ -1,3 +1,14 @@ +CFQ (Complete Fairness Queueing) +=============================== + +The main aim of CFQ scheduler is to provide a fair allocation of the disk +I/O bandwidth for all the processes which requests an I/O operation. + +CFQ maintains the per process queue for the processes which request I/O +operation(syncronous requests). In case of asynchronous requests, all the +requests from all the processes are batched together according to their +process's I/O priority. + CFQ ioscheduler tunables ======================== @@ -25,6 +36,72 @@ there are multiple spindles behind single LUN (Host based hardware RAID controller or for storage arrays), setting slice_idle=0 might end up in better throughput and acceptable latencies. +back_seek_max +------------- +This specifies, given in Kbytes, the maximum "distance" for backward seeking. +The distance is the amount of space from the current head location to the +sectors that are backward in terms of distance. + +This parameter allows the scheduler to anticipate requests in the "backward" +direction and consider them as being the "next" if they are within this +distance from the current head location. + +back_seek_penalty +----------------- +This parameter is used to compute the cost of backward seeking. If the +backward distance of request is just 1/back_seek_penalty from a "front" +request, then the seeking cost of two requests is considered equivalent. + +So scheduler will not bias toward one or the other request (otherwise scheduler +will bias toward front request). Default value of back_seek_penalty is 2. + +fifo_expire_async +----------------- +This parameter is used to set the timeout of asynchronous requests. Default +value of this is 248ms. + +fifo_expire_sync +---------------- +This parameter is used to set the timeout of synchronous requests. Default +value of this is 124ms. In case to favor synchronous requests over asynchronous +one, this value should be decreased relative to fifo_expire_async. + +slice_async +----------- +This parameter is same as of slice_sync but for asynchronous queue. The +default value is 40ms. + +slice_async_rq +-------------- +This parameter is used to limit the dispatching of asynchronous request to +device request queue in queue's slice time. The maximum number of request that +are allowed to be dispatched also depends upon the io priority. Default value +for this is 2. + +slice_sync +---------- +When a queue is selected for execution, the queues IO requests are only +executed for a certain amount of time(time_slice) before switching to another +queue. This parameter is used to calculate the time slice of synchronous +queue. + +time_slice is computed using the below equation:- +time_slice = slice_sync + (slice_sync/5 * (4 - prio)). To increase the +time_slice of synchronous queue, increase the value of slice_sync. Default +value is 100ms. + +quantum +------- +This specifies the number of request dispatched to the device queue. In a +queue's time slice, a request will not be dispatched if the number of request +in the device exceeds this parameter. This parameter is used for synchronous +request. + +In case of storage with several disk, this setting can limit the parallel +processing of request. Therefore, increasing the value can imporve the +performace although this can cause the latency of some I/O to increase due +to more number of requests. + CFQ IOPS Mode for group scheduling =================================== Basic CFQ design is to provide priority based time slices. Higher priority diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt index 6518a55273e7..e54ac1d53403 100644 --- a/Documentation/block/queue-sysfs.txt +++ b/Documentation/block/queue-sysfs.txt @@ -9,20 +9,71 @@ These files are the ones found in the /sys/block/xxx/queue/ directory. Files denoted with a RO postfix are readonly and the RW postfix means read-write. +add_random (RW) +---------------- +This file allows to trun off the disk entropy contribution. Default +value of this file is '1'(on). + +discard_granularity (RO) +----------------------- +This shows the size of internal allocation of the device in bytes, if +reported by the device. A value of '0' means device does not support +the discard functionality. + +discard_max_bytes (RO) +---------------------- +Devices that support discard functionality may have internal limits on +the number of bytes that can be trimmed or unmapped in a single operation. +The discard_max_bytes parameter is set by the device driver to the maximum +number of bytes that can be discarded in a single operation. Discard +requests issued to the device must not exceed this limit. A discard_max_bytes +value of 0 means that the device does not support discard functionality. + +discard_zeroes_data (RO) +------------------------ +When read, this file will show if the discarded block are zeroed by the +device or not. If its value is '1' the blocks are zeroed otherwise not. + hw_sector_size (RO) ------------------- This is the hardware sector size of the device, in bytes. +iostats (RW) +------------- +This file is used to control (on/off) the iostats accounting of the +disk. + +logical_block_size (RO) +----------------------- +This is the logcal block size of the device, in bytes. + max_hw_sectors_kb (RO) ---------------------- This is the maximum number of kilobytes supported in a single data transfer. +max_integrity_segments (RO) +--------------------------- +When read, this file shows the max limit of integrity segments as +set by block layer which a hardware controller can handle. + max_sectors_kb (RW) ------------------- This is the maximum number of kilobytes that the block layer will allow for a filesystem request. Must be smaller than or equal to the maximum size allowed by the hardware. +max_segments (RO) +----------------- +Maximum number of segments of the device. + +max_segment_size (RO) +--------------------- +Maximum segment size of the device. + +minimum_io_size (RO) +-------------------- +This is the smallest preferred io size reported by the device. + nomerges (RW) ------------- This enables the user to disable the lookup logic involved with IO @@ -45,11 +96,24 @@ per-block-cgroup request pool. IOW, if there are N block cgroups, each request queue may have upto N request pools, each independently regulated by nr_requests. +optimal_io_size (RO) +-------------------- +This is the optimal io size reported by the device. + +physical_block_size (RO) +------------------------ +This is the physical block size of device, in bytes. + read_ahead_kb (RW) ------------------ Maximum number of kilobytes to read-ahead for filesystems on this block device. +rotational (RW) +--------------- +This file is used to stat if the device is of rotational type or +non-rotational type. + rq_affinity (RW) ---------------- If this option is '1', the block layer will migrate request completions to the diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt index 70cd49b1caa8..1dd622546d06 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt @@ -10,8 +10,8 @@ Required properties: - compatible : Should be "fsl,<chip>-esdhc" Optional properties: -- fsl,cd-internal : Indicate to use controller internal card detection -- fsl,wp-internal : Indicate to use controller internal write protection +- fsl,cd-controller : Indicate to use controller internal card detection +- fsl,wp-controller : Indicate to use controller internal write protection Examples: @@ -19,8 +19,8 @@ esdhc@70004000 { compatible = "fsl,imx51-esdhc"; reg = <0x70004000 0x4000>; interrupts = <1>; - fsl,cd-internal; - fsl,wp-internal; + fsl,cd-controller; + fsl,wp-controller; }; esdhc@70008000 { diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c index 73ff5cc93e05..3da822967ee0 100644 --- a/Documentation/watchdog/src/watchdog-test.c +++ b/Documentation/watchdog/src/watchdog-test.c @@ -31,7 +31,7 @@ static void keep_alive(void) * or "-e" to enable the card. */ -void term(int sig) +static void term(int sig) { close(fd); fprintf(stderr, "Stopping watchdog ticks...\n"); @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 6 SUBLEVEL = 0 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc4 NAME = Saber-toothed Squirrel # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6d6e18fee9fe..c5f9ae5dbd1a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2144,6 +2144,7 @@ source "drivers/cpufreq/Kconfig" config CPU_FREQ_IMX tristate "CPUfreq driver for i.MX CPUs" depends on ARCH_MXC && CPU_FREQ + select CPU_FREQ_TABLE help This enables the CPUfreq driver for i.MX CPUs. diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 59509c48d7e5..bd0cff3f808c 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -154,5 +154,10 @@ #size-cells = <0>; ti,hwmods = "i2c3"; }; + + wdt2: wdt@44e35000 { + compatible = "ti,omap3-wdt"; + ti,hwmods = "wd_timer2"; + }; }; }; diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index cd86177a3ea2..59d9789e5508 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -25,8 +25,8 @@ aips@70000000 { /* aips-1 */ spba@70000000 { esdhc@70004000 { /* ESDHC1 */ - fsl,cd-internal; - fsl,wp-internal; + fsl,cd-controller; + fsl,wp-controller; status = "okay"; }; diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts index 52d947045106..f8ca6fa88192 100644 --- a/arch/arm/boot/dts/kirkwood-iconnect.dts +++ b/arch/arm/boot/dts/kirkwood-iconnect.dts @@ -41,9 +41,13 @@ }; power-blue { label = "power:blue"; - gpios = <&gpio1 11 0>; + gpios = <&gpio1 10 0>; linux,default-trigger = "timer"; }; + power-red { + label = "power:red"; + gpios = <&gpio1 11 0>; + }; usb1 { label = "usb1:blue"; gpios = <&gpio1 12 0>; diff --git a/arch/arm/boot/dts/twl6030.dtsi b/arch/arm/boot/dts/twl6030.dtsi index 3b2f3510d7eb..d351b27d7213 100644 --- a/arch/arm/boot/dts/twl6030.dtsi +++ b/arch/arm/boot/dts/twl6030.dtsi @@ -66,6 +66,7 @@ vcxio: regulator@8 { compatible = "ti,twl6030-vcxio"; + regulator-always-on; }; vusb: regulator@9 { @@ -74,10 +75,12 @@ v1v8: regulator@10 { compatible = "ti,twl6030-v1v8"; + regulator-always-on; }; v2v1: regulator@11 { compatible = "ti,twl6030-v2v1"; + regulator-always-on; }; clk32kg: regulator@12 { diff --git a/arch/arm/configs/u8500_defconfig b/arch/arm/configs/u8500_defconfig index 2d4f661d1cf6..da6845493caa 100644 --- a/arch/arm/configs/u8500_defconfig +++ b/arch/arm/configs/u8500_defconfig @@ -86,6 +86,7 @@ CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_LM3530=y CONFIG_LEDS_LP5521=y +CONFIG_LEDS_GPIO=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_AB8500=y CONFIG_RTC_DRV_PL031=y diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index 4db5de54b6a7..6321567d8eaa 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -102,7 +102,8 @@ void __init dove_ehci1_init(void) void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, DOVE_GE00_PHYS_BASE, - IRQ_DOVE_GE00_SUM, IRQ_DOVE_GE00_ERR); + IRQ_DOVE_GE00_SUM, IRQ_DOVE_GE00_ERR, + 1600); } /***************************************************************************** diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 4e245f1b29a2..5ec563be6c65 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -42,6 +42,7 @@ #include <plat/backlight.h> #include <plat/fb.h> #include <plat/mfc.h> +#include <plat/hdmi.h> #include <mach/ohci.h> #include <mach/map.h> @@ -734,6 +735,11 @@ static void __init origen_bt_setup(void) s3c_gpio_setpull(EXYNOS4_GPX2(2), S3C_GPIO_PULL_NONE); } +/* I2C module and id for HDMIPHY */ +static struct i2c_board_info hdmiphy_info = { + I2C_BOARD_INFO("hdmiphy-exynos4210", 0x38), +}; + static void s5p_tv_setup(void) { /* Direct HPD to HDMI chip */ @@ -781,6 +787,7 @@ static void __init origen_machine_init(void) s5p_tv_setup(); s5p_i2c_hdmiphy_set_platdata(NULL); + s5p_hdmi_set_platdata(&hdmiphy_info, NULL, 0); #ifdef CONFIG_DRM_EXYNOS s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata; diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index b1c50dabd862..208aa6236af3 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -40,6 +40,7 @@ #include <plat/mfc.h> #include <plat/ehci.h> #include <plat/clock.h> +#include <plat/hdmi.h> #include <mach/map.h> #include <mach/ohci.h> @@ -354,6 +355,11 @@ static struct platform_pwm_backlight_data smdkv310_bl_data = { .pwm_period_ns = 1000, }; +/* I2C module and id for HDMIPHY */ +static struct i2c_board_info hdmiphy_info = { + I2C_BOARD_INFO("hdmiphy-exynos4210", 0x38), +}; + static void s5p_tv_setup(void) { /* direct HPD to HDMI chip */ @@ -388,6 +394,7 @@ static void __init smdkv310_machine_init(void) s5p_tv_setup(); s5p_i2c_hdmiphy_set_platdata(NULL); + s5p_hdmi_set_platdata(&hdmiphy_info, NULL, 0); samsung_keypad_set_platdata(&smdkv310_keypad_data); diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 07f7c226e4cf..d004d37ad9d8 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -9,7 +9,8 @@ obj-$(CONFIG_SOC_IMX27) += clk-imx27.o mm-imx27.o ehci-imx27.o obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o -obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o +imx5-pm-$(CONFIG_PM) += pm-imx5.o +obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o $(imx5-pm-y) cpu_op-mx51.o obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ clk-pfd.o clk-busy.o @@ -70,14 +71,13 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o obj-$(CONFIG_HAVE_IMX_SRC) += src.o -obj-$(CONFIG_CPU_V7) += head-v7.o -AFLAGS_head-v7.o :=-Wa,-march=armv7-a -obj-$(CONFIG_SMP) += platsmp.o +AFLAGS_headsmp.o :=-Wa,-march=armv7-a +obj-$(CONFIG_SMP) += headsmp.o platsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o ifeq ($(CONFIG_PM),y) -obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o +obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o endif # i.MX5 based machines diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index ea89520b6e22..4233d9e3531d 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -152,7 +152,7 @@ enum mx6q_clks { ssi2, ssi3, uart_ipg, uart_serial, usboh3, usdhc1, usdhc2, usdhc3, usdhc4, vdo_axi, vpu_axi, cko1, pll1_sys, pll2_bus, pll3_usb_otg, pll4_audio, pll5_video, pll6_mlb, pll7_usb_host, pll8_enet, ssi1_ipg, - ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, + ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5, clk_max }; @@ -288,8 +288,10 @@ int __init mx6q_clocks_init(void) clk[gpu3d_shader] = imx_clk_divider("gpu3d_shader", "gpu3d_shader_sel", base + 0x18, 29, 3); clk[ipu1_podf] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3); clk[ipu2_podf] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3); - clk[ldb_di0_podf] = imx_clk_divider("ldb_di0_podf", "ldb_di0_sel", base + 0x20, 10, 1); - clk[ldb_di1_podf] = imx_clk_divider("ldb_di1_podf", "ldb_di1_sel", base + 0x20, 11, 1); + clk[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clk[ldb_di0_podf] = imx_clk_divider("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1); + clk[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); + clk[ldb_di1_podf] = imx_clk_divider("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1); clk[ipu1_di0_pre] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3); clk[ipu1_di1_pre] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3); clk[ipu2_di0_pre] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3); diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/headsmp.S index 7e49deb128a4..7e49deb128a4 100644 --- a/arch/arm/mach-imx/head-v7.S +++ b/arch/arm/mach-imx/headsmp.S diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c index 20ed2d56c1af..f8f7437c83b8 100644 --- a/arch/arm/mach-imx/hotplug.c +++ b/arch/arm/mach-imx/hotplug.c @@ -42,22 +42,6 @@ static inline void cpu_enter_lowpower(void) : "cc"); } -static inline void cpu_leave_lowpower(void) -{ - unsigned int v; - - asm volatile( - "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, %1\n" - " mcr p15, 0, %0, c1, c0, 0\n" - " mrc p15, 0, %0, c1, c0, 1\n" - " orr %0, %0, %2\n" - " mcr p15, 0, %0, c1, c0, 1\n" - : "=&r" (v) - : "Ir" (CR_C), "Ir" (0x40) - : "cc"); -} - /* * platform-specific code to shutdown a CPU * @@ -67,11 +51,10 @@ void platform_cpu_die(unsigned int cpu) { cpu_enter_lowpower(); imx_enable_cpu(cpu, false); - cpu_do_idle(); - cpu_leave_lowpower(); - /* We should never return from idle */ - panic("cpu %d unexpectedly exit from shutdown\n", cpu); + /* spin here until hardware takes it down */ + while (1) + ; } int platform_cpu_disable(unsigned int cpu) diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 5ec0608f2a76..045b3f6a387d 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c @@ -71,7 +71,7 @@ soft: /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ static int ksz9021rn_phy_fixup(struct phy_device *phydev) { - if (IS_ENABLED(CONFIG_PHYLIB)) { + if (IS_BUILTIN(CONFIG_PHYLIB)) { /* min rx data delay */ phy_write(phydev, 0x0b, 0x8105); phy_write(phydev, 0x0c, 0x0000); @@ -112,7 +112,7 @@ put_clk: static void __init imx6q_sabrelite_init(void) { - if (IS_ENABLED(CONFIG_PHYLIB)) + if (IS_BUILTIN(CONFIG_PHYLIB)) phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, ksz9021rn_phy_fixup); imx6q_sabrelite_cko1_setup(); diff --git a/arch/arm/mach-kirkwood/Makefile.boot b/arch/arm/mach-kirkwood/Makefile.boot index a5717558ee89..a13299d758e1 100644 --- a/arch/arm/mach-kirkwood/Makefile.boot +++ b/arch/arm/mach-kirkwood/Makefile.boot @@ -7,7 +7,8 @@ dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns320.dtb dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns325.dtb dtb-$(CONFIG_MACH_ICONNECT_DT) += kirkwood-iconnect.dtb dtb-$(CONFIG_MACH_IB62X0_DT) += kirkwood-ib62x0.dtb -dtb-$(CONFIG_MACH_TS219_DT) += kirkwood-qnap-ts219.dtb +dtb-$(CONFIG_MACH_TS219_DT) += kirkwood-ts219-6281.dtb +dtb-$(CONFIG_MACH_TS219_DT) += kirkwood-ts219-6282.dtb dtb-$(CONFIG_MACH_GOFLEXNET_DT) += kirkwood-goflexnet.dtb dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lschlv2.dtb dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lsxhl.dtb diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index c4b64adcbfce..3226077735b1 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -301,7 +301,7 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM, - IRQ_KIRKWOOD_GE00_ERR); + IRQ_KIRKWOOD_GE00_ERR, 1600); /* The interface forgets the MAC address assigned by u-boot if the clock is turned off, so claim the clk now. */ clk_prepare_enable(ge0); @@ -315,7 +315,7 @@ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM, - IRQ_KIRKWOOD_GE01_ERR); + IRQ_KIRKWOOD_GE01_ERR, 1600); clk_prepare_enable(ge1); } diff --git a/arch/arm/mach-mmp/sram.c b/arch/arm/mach-mmp/sram.c index 4304f9519372..7e8a5a2e1ec7 100644 --- a/arch/arm/mach-mmp/sram.c +++ b/arch/arm/mach-mmp/sram.c @@ -68,7 +68,7 @@ static int __devinit sram_probe(struct platform_device *pdev) struct resource *res; int ret = 0; - if (!pdata && !pdata->pool_name) + if (!pdata || !pdata->pool_name) return -ENODEV; info = kzalloc(sizeof(*info), GFP_KERNEL); diff --git a/arch/arm/mach-mv78xx0/addr-map.c b/arch/arm/mach-mv78xx0/addr-map.c index 62b53d710efd..a9bc84180d21 100644 --- a/arch/arm/mach-mv78xx0/addr-map.c +++ b/arch/arm/mach-mv78xx0/addr-map.c @@ -37,7 +37,7 @@ #define WIN0_OFF(n) (BRIDGE_VIRT_BASE + 0x0000 + ((n) << 4)) #define WIN8_OFF(n) (BRIDGE_VIRT_BASE + 0x0900 + (((n) - 8) << 4)) -static void __init __iomem *win_cfg_base(int win) +static void __init __iomem *win_cfg_base(const struct orion_addr_map_cfg *cfg, int win) { /* * Find the control register base address for this window. diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index b4c53b846c9c..3057f7d4329a 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -213,7 +213,8 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM, - IRQ_MV78XX0_GE_ERR); + IRQ_MV78XX0_GE_ERR, + MV643XX_TX_CSUM_DEFAULT_LIMIT); } @@ -224,7 +225,8 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge01_init(eth_data, GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM, - NO_IRQ); + NO_IRQ, + MV643XX_TX_CSUM_DEFAULT_LIMIT); } diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index dd2db025f778..fcd4e85c4ddc 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -62,13 +62,14 @@ config ARCH_OMAP4 select PM_OPP if PM select USB_ARCH_HAS_EHCI if USB_SUPPORT select ARM_CPU_SUSPEND if PM - select ARCH_NEEDS_CPU_IDLE_COUPLED + select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP config SOC_OMAP5 bool "TI OMAP5" select CPU_V7 select ARM_GIC select HAVE_SMP + select ARM_CPU_SUSPEND if PM comment "OMAP Core Type" depends on ARCH_OMAP2 diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index ad8a7d94afcd..c165e20506c9 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -601,29 +601,6 @@ static void __init omap_sfh7741prox_init(void) __func__, OMAP4_SFH7741_ENABLE_GPIO, error); } -static struct gpio sdp4430_hdmi_gpios[] = { - { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, - { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, - { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, -}; - -static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev) -{ - int status; - - status = gpio_request_array(sdp4430_hdmi_gpios, - ARRAY_SIZE(sdp4430_hdmi_gpios)); - if (status) - pr_err("%s: Cannot request HDMI GPIOs\n", __func__); - - return status; -} - -static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) -{ - gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios)); -} - static struct nokia_dsi_panel_data dsi1_panel = { .name = "taal", .reset_gpio = 102, @@ -644,29 +621,6 @@ static struct omap_dss_device sdp4430_lcd_device = { .phy.dsi = { .module = 0, }, - - .clocks = { - .dispc = { - .channel = { - /* Logic Clock = 172.8 MHz */ - .lck_div = 1, - /* Pixel Clock = 34.56 MHz */ - .pck_div = 5, - .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, - }, - .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, - }, - - .dsi = { - .regn = 16, /* Fint = 2.4 MHz */ - .regm = 180, /* DDR Clock = 216 MHz */ - .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ - .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ - - .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ - .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, - }, - }, .channel = OMAP_DSS_CHANNEL_LCD, }; @@ -691,33 +645,12 @@ static struct omap_dss_device sdp4430_lcd2_device = { .module = 1, }, - - .clocks = { - .dispc = { - .channel = { - /* Logic Clock = 172.8 MHz */ - .lck_div = 1, - /* Pixel Clock = 34.56 MHz */ - .pck_div = 5, - .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC, - }, - .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, - }, - - .dsi = { - .regn = 16, /* Fint = 2.4 MHz */ - .regm = 180, /* DDR Clock = 216 MHz */ - .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ - .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ - - .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ - .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, - }, - }, .channel = OMAP_DSS_CHANNEL_LCD2, }; static struct omap_dss_hdmi_data sdp4430_hdmi_data = { + .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD, + .ls_oe_gpio = HDMI_GPIO_LS_OE, .hpd_gpio = HDMI_GPIO_HPD, }; @@ -725,8 +658,6 @@ static struct omap_dss_device sdp4430_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", .type = OMAP_DISPLAY_TYPE_HDMI, - .platform_enable = sdp4430_panel_enable_hdmi, - .platform_disable = sdp4430_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, .data = &sdp4430_hdmi_data, }; diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index 74915295482e..28214483aaba 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -554,6 +554,8 @@ static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = { #ifdef CONFIG_OMAP_MUX static struct omap_board_mux board_mux[] __initdata = { + /* SMSC9221 LAN Controller ETH IRQ (GPIO_176) */ + OMAP3_MUX(MCSPI1_CS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), { .reg_offset = OMAP_MUX_TERMINATOR }, }; #endif diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index ef230a0eb5eb..0d362e9f9cb9 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -58,6 +58,7 @@ #include "hsmmc.h" #include "common-board-devices.h" +#define OMAP3_EVM_TS_GPIO 175 #define OMAP3_EVM_EHCI_VBUS 22 #define OMAP3_EVM_EHCI_SELECT 61 diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 70f6d1d25463..cd4852e5ca57 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -408,30 +408,9 @@ static struct omap_dss_device omap4_panda_dvi_device = { .channel = OMAP_DSS_CHANNEL_LCD2, }; -static struct gpio panda_hdmi_gpios[] = { - { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, - { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, - { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, -}; - -static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev) -{ - int status; - - status = gpio_request_array(panda_hdmi_gpios, - ARRAY_SIZE(panda_hdmi_gpios)); - if (status) - pr_err("Cannot request HDMI GPIOs\n"); - - return status; -} - -static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev) -{ - gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios)); -} - static struct omap_dss_hdmi_data omap4_panda_hdmi_data = { + .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD, + .ls_oe_gpio = HDMI_GPIO_LS_OE, .hpd_gpio = HDMI_GPIO_HPD, }; @@ -439,8 +418,6 @@ static struct omap_dss_device omap4_panda_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", .type = OMAP_DISPLAY_TYPE_HDMI, - .platform_enable = omap4_panda_panel_enable_hdmi, - .platform_disable = omap4_panda_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, .data = &omap4_panda_hdmi_data, }; diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c index 14734746457c..c1875862679f 100644 --- a/arch/arm/mach-omap2/common-board-devices.c +++ b/arch/arm/mach-omap2/common-board-devices.c @@ -35,16 +35,6 @@ static struct omap2_mcspi_device_config ads7846_mcspi_config = { .turbo_mode = 0, }; -/* - * ADS7846 driver maybe request a gpio according to the value - * of pdata->get_pendown_state, but we have done this. So set - * get_pendown_state to avoid twice gpio requesting. - */ -static int omap3_get_pendown_state(void) -{ - return !gpio_get_value(OMAP3_EVM_TS_GPIO); -} - static struct ads7846_platform_data ads7846_config = { .x_max = 0x0fff, .y_max = 0x0fff, @@ -55,7 +45,6 @@ static struct ads7846_platform_data ads7846_config = { .debounce_rep = 1, .gpio_pendown = -EINVAL, .keep_vref_on = 1, - .get_pendown_state = &omap3_get_pendown_state, }; static struct spi_board_info ads7846_spi_board_info __initdata = { diff --git a/arch/arm/mach-omap2/common-board-devices.h b/arch/arm/mach-omap2/common-board-devices.h index 4c4ef6a6166b..a0b4a42836ab 100644 --- a/arch/arm/mach-omap2/common-board-devices.h +++ b/arch/arm/mach-omap2/common-board-devices.h @@ -4,7 +4,6 @@ #include "twl-common.h" #define NAND_BLOCK_SIZE SZ_128K -#define OMAP3_EVM_TS_GPIO 175 struct mtd_partition; struct ads7846_platform_data; diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index ee05e193fc61..288bee6cbb76 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -238,8 +238,9 @@ int __init omap4_idle_init(void) for_each_cpu(cpu_id, cpu_online_mask) { dev = &per_cpu(omap4_idle_dev, cpu_id); dev->cpu = cpu_id; +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED dev->coupled_cpus = *cpu_online_mask; - +#endif cpuidle_register_driver(&omap4_idle_driver); if (cpuidle_register_device(dev)) { diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index af1ed7d24a1f..ee40739b55c0 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -95,7 +95,6 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = { { "dss_core", "omapdss_dss", -1 }, { "dss_dispc", "omapdss_dispc", -1 }, { "dss_rfbi", "omapdss_rfbi", -1 }, - { "dss_venc", "omapdss_venc", -1 }, { "dss_dsi1", "omapdss_dsi", 0 }, { "dss_dsi2", "omapdss_dsi", 1 }, { "dss_hdmi", "omapdss_hdmi", -1 }, diff --git a/arch/arm/mach-omap2/mux.h b/arch/arm/mach-omap2/mux.h index 471e62a74a16..76f9b3c2f586 100644 --- a/arch/arm/mach-omap2/mux.h +++ b/arch/arm/mach-omap2/mux.h @@ -127,7 +127,6 @@ struct omap_mux_partition { * @gpio: GPIO number * @muxnames: available signal modes for a ball * @balls: available balls on the package - * @partition: mux partition */ struct omap_mux { u16 reg_offset; diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c index 2293ba27101b..c95415da23c2 100644 --- a/arch/arm/mach-omap2/opp4xxx_data.c +++ b/arch/arm/mach-omap2/opp4xxx_data.c @@ -94,7 +94,7 @@ int __init omap4_opp_init(void) { int r = -ENODEV; - if (!cpu_is_omap44xx()) + if (!cpu_is_omap443x()) return r; r = omap_init_opp_table(omap44xx_opp_def_list, diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index e4fc88c65dbd..05bd8f02723f 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c @@ -272,21 +272,16 @@ void omap_sram_idle(void) per_next_state = pwrdm_read_next_pwrst(per_pwrdm); core_next_state = pwrdm_read_next_pwrst(core_pwrdm); - if (mpu_next_state < PWRDM_POWER_ON) { - pwrdm_pre_transition(mpu_pwrdm); - pwrdm_pre_transition(neon_pwrdm); - } + pwrdm_pre_transition(NULL); /* PER */ if (per_next_state < PWRDM_POWER_ON) { - pwrdm_pre_transition(per_pwrdm); per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; omap2_gpio_prepare_for_idle(per_going_off); } /* CORE */ if (core_next_state < PWRDM_POWER_ON) { - pwrdm_pre_transition(core_pwrdm); if (core_next_state == PWRDM_POWER_OFF) { omap3_core_save_context(); omap3_cm_save_context(); @@ -339,20 +334,14 @@ void omap_sram_idle(void) omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK, OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET); - pwrdm_post_transition(core_pwrdm); } omap3_intc_resume_idle(); + pwrdm_post_transition(NULL); + /* PER */ - if (per_next_state < PWRDM_POWER_ON) { + if (per_next_state < PWRDM_POWER_ON) omap2_gpio_resume_after_idle(); - pwrdm_post_transition(per_pwrdm); - } - - if (mpu_next_state < PWRDM_POWER_ON) { - pwrdm_post_transition(mpu_pwrdm); - pwrdm_post_transition(neon_pwrdm); - } } static void omap3_pm_idle(void) diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S index 9f6b83d1b193..91e71d8f46f0 100644 --- a/arch/arm/mach-omap2/sleep44xx.S +++ b/arch/arm/mach-omap2/sleep44xx.S @@ -56,9 +56,13 @@ ppa_por_params: * The restore function pointer is stored at CPUx_WAKEUP_NS_PA_ADDR_OFFSET. * It returns to the caller for CPU INACTIVE and ON power states or in case * CPU failed to transition to targeted OFF/DORMANT state. + * + * omap4_finish_suspend() calls v7_flush_dcache_all() which doesn't save + * stack frame and it expects the caller to take care of it. Hence the entire + * stack frame is saved to avoid possible stack corruption. */ ENTRY(omap4_finish_suspend) - stmfd sp!, {lr} + stmfd sp!, {r4-r12, lr} cmp r0, #0x0 beq do_WFI @ No lowpower state, jump to WFI @@ -226,7 +230,7 @@ scu_gp_clear: skip_scu_gp_clear: isb dsb - ldmfd sp!, {pc} + ldmfd sp!, {r4-r12, pc} ENDPROC(omap4_finish_suspend) /* diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c index de47f170ba50..9bf8a89e78c6 100644 --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@ -67,6 +67,7 @@ void __init omap_pmic_init(int bus, u32 clkrate, const char *pmic_type, int pmic_irq, struct twl4030_platform_data *pmic_data) { + omap_mux_init_signal("sys_nirq", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE); strncpy(pmic_i2c_board_info.type, pmic_type, sizeof(pmic_i2c_board_info.type)); pmic_i2c_board_info.irq = pmic_irq; @@ -257,6 +258,10 @@ static struct twl4030_usb_data omap4_usb_pdata = { .phy_suspend = omap4430_phy_suspend, }; +static struct regulator_consumer_supply omap4_vdda_hdmi_dac_supplies[] = { + REGULATOR_SUPPLY("vdda_hdmi_dac", "omapdss_hdmi"), +}; + static struct regulator_init_data omap4_vdac_idata = { .constraints = { .min_uV = 1800000, @@ -266,6 +271,8 @@ static struct regulator_init_data omap4_vdac_idata = { .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, }, + .num_consumer_supplies = ARRAY_SIZE(omap4_vdda_hdmi_dac_supplies), + .consumer_supplies = omap4_vdda_hdmi_dac_supplies, .supply_regulator = "V2V1", }; diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index 9148b229d0de..410291c67666 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -109,7 +109,8 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) { orion_ge00_init(eth_data, ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM, - IRQ_ORION5X_ETH_ERR); + IRQ_ORION5X_ETH_ERR, + MV643XX_TX_CSUM_DEFAULT_LIMIT); } diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h index 454831b66037..ee99fd56c043 100644 --- a/arch/arm/mach-s3c24xx/include/mach/dma.h +++ b/arch/arm/mach-s3c24xx/include/mach/dma.h @@ -24,7 +24,8 @@ */ enum dma_ch { - DMACH_XD0, + DMACH_DT_PROP = -1, /* not yet supported, do not use */ + DMACH_XD0 = 0, DMACH_XD1, DMACH_SDI, DMACH_SPI0, diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index c013bbf79cac..53d3d46dec12 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -41,7 +41,6 @@ config MACH_HREFV60 config MACH_SNOWBALL bool "U8500 Snowball platform" select MACH_MOP500 - select LEDS_GPIO help Include support for the snowball development platform. diff --git a/arch/arm/mach-ux500/board-mop500-msp.c b/arch/arm/mach-ux500/board-mop500-msp.c index 996048038743..df15646036aa 100644 --- a/arch/arm/mach-ux500/board-mop500-msp.c +++ b/arch/arm/mach-ux500/board-mop500-msp.c @@ -191,9 +191,9 @@ static struct platform_device *db8500_add_msp_i2s(struct device *parent, return pdev; } -/* Platform device for ASoC U8500 machine */ -static struct platform_device snd_soc_u8500 = { - .name = "snd-soc-u8500", +/* Platform device for ASoC MOP500 machine */ +static struct platform_device snd_soc_mop500 = { + .name = "snd-soc-mop500", .id = 0, .dev = { .platform_data = NULL, @@ -227,8 +227,8 @@ int mop500_msp_init(struct device *parent) { struct platform_device *msp1; - pr_info("%s: Register platform-device 'snd-soc-u8500'.\n", __func__); - platform_device_register(&snd_soc_u8500); + pr_info("%s: Register platform-device 'snd-soc-mop500'.\n", __func__); + platform_device_register(&snd_soc_mop500); pr_info("Initialize MSP I2S-devices.\n"); db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 8674a890fd1c..a534d8880de1 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -797,6 +797,7 @@ static void __init u8500_init_machine(void) ARRAY_SIZE(mop500_platform_devs)); mop500_sdi_init(parent); + mop500_msp_init(parent); i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs); i2c_register_board_info(2, mop500_i2c2_devices, @@ -804,6 +805,8 @@ static void __init u8500_init_machine(void) mop500_uib_init(); + } else if (of_machine_is_compatible("calaosystems,snowball-a9500")) { + mop500_msp_init(parent); } else if (of_machine_is_compatible("st-ericsson,hrefv60+")) { /* * The HREFv60 board removed a GPIO expander and routed @@ -815,6 +818,7 @@ static void __init u8500_init_machine(void) ARRAY_SIZE(mop500_platform_devs)); hrefv60_sdi_init(parent); + mop500_msp_init(parent); i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES; diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 626ad8cad7a9..938b50a33439 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -189,6 +189,7 @@ struct omap_dm_timer *omap_dm_timer_request(void) timer->reserved = 1; break; } + spin_unlock_irqrestore(&dm_timer_lock, flags); if (timer) { ret = omap_dm_timer_prepare(timer); @@ -197,7 +198,6 @@ struct omap_dm_timer *omap_dm_timer_request(void) timer = NULL; } } - spin_unlock_irqrestore(&dm_timer_lock, flags); if (!timer) pr_debug("%s: timer request failed!\n", __func__); @@ -220,6 +220,7 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) break; } } + spin_unlock_irqrestore(&dm_timer_lock, flags); if (timer) { ret = omap_dm_timer_prepare(timer); @@ -228,7 +229,6 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) timer = NULL; } } - spin_unlock_irqrestore(&dm_timer_lock, flags); if (!timer) pr_debug("%s: timer%d request failed!\n", __func__, id); @@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_enable); void omap_dm_timer_disable(struct omap_dm_timer *timer) { - pm_runtime_put(&timer->pdev->dev); + pm_runtime_put_sync(&timer->pdev->dev); } EXPORT_SYMBOL_GPL(omap_dm_timer_disable); diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index 68b180edcfff..bb5d08a70dbc 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -372,7 +372,8 @@ IS_OMAP_TYPE(3430, 0x3430) #define cpu_class_is_omap1() (cpu_is_omap7xx() || cpu_is_omap15xx() || \ cpu_is_omap16xx()) #define cpu_class_is_omap2() (cpu_is_omap24xx() || cpu_is_omap34xx() || \ - cpu_is_omap44xx() || soc_is_omap54xx()) + cpu_is_omap44xx() || soc_is_omap54xx() || \ + soc_is_am33xx()) /* Various silicon revisions for omap2 */ #define OMAP242X_CLASS 0x24200024 diff --git a/arch/arm/plat-omap/include/plat/multi.h b/arch/arm/plat-omap/include/plat/multi.h index 045e320f1067..324d31b14852 100644 --- a/arch/arm/plat-omap/include/plat/multi.h +++ b/arch/arm/plat-omap/include/plat/multi.h @@ -108,4 +108,13 @@ # endif #endif +#ifdef CONFIG_SOC_AM33XX +# ifdef OMAP_NAME +# undef MULTI_OMAP2 +# define MULTI_OMAP2 +# else +# define OMAP_NAME am33xx +# endif +#endif + #endif /* __PLAT_OMAP_MULTI_H */ diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h index b8d19a136781..7f7b112acccb 100644 --- a/arch/arm/plat-omap/include/plat/uncompress.h +++ b/arch/arm/plat-omap/include/plat/uncompress.h @@ -110,7 +110,7 @@ static inline void flush(void) _DEBUG_LL_ENTRY(mach, AM33XX_UART##p##_BASE, OMAP_PORT_SHIFT, \ AM33XXUART##p) -static inline void __arch_decomp_setup(unsigned long arch_id) +static inline void arch_decomp_setup(void) { int port = 0; @@ -198,8 +198,6 @@ static inline void __arch_decomp_setup(unsigned long arch_id) } while (0); } -#define arch_decomp_setup() __arch_decomp_setup(arch_id) - /* * nothing to do */ diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index d245a87dc014..b8b747a9d360 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -291,10 +291,12 @@ static struct platform_device orion_ge00 = { void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err) + unsigned long irq_err, + unsigned int tx_csum_limit) { fill_resources(&orion_ge00_shared, orion_ge00_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); + orion_ge00_shared_data.tx_csum_limit = tx_csum_limit; ge_complete(&orion_ge00_shared_data, orion_ge00_resources, irq, &orion_ge00_shared, eth_data, &orion_ge00); @@ -343,10 +345,12 @@ static struct platform_device orion_ge01 = { void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err) + unsigned long irq_err, + unsigned int tx_csum_limit) { fill_resources(&orion_ge01_shared, orion_ge01_shared_resources, mapbase + 0x2000, SZ_16K - 1, irq_err); + orion_ge01_shared_data.tx_csum_limit = tx_csum_limit; ge_complete(&orion_ge01_shared_data, orion_ge01_resources, irq, &orion_ge01_shared, eth_data, &orion_ge01); diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h index e00fdb213609..ae2377ef63e5 100644 --- a/arch/arm/plat-orion/include/plat/common.h +++ b/arch/arm/plat-orion/include/plat/common.h @@ -39,12 +39,14 @@ void __init orion_rtc_init(unsigned long mapbase, void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err); + unsigned long irq_err, + unsigned int tx_csum_limit); void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, unsigned long irq, - unsigned long irq_err); + unsigned long irq_err, + unsigned int tx_csum_limit); void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, unsigned long mapbase, diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 28f898f75380..db98e7021f0d 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -430,7 +430,7 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan) * when necessary. */ -int s3c2410_dma_enqueue(unsigned int channel, void *id, +int s3c2410_dma_enqueue(enum dma_ch channel, void *id, dma_addr_t data, int size) { struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 74e31ce35538..fc49f3dabd76 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -32,6 +32,8 @@ #include <linux/platform_data/s3c-hsudc.h> #include <linux/platform_data/s3c-hsotg.h> +#include <media/s5p_hdmi.h> + #include <asm/irq.h> #include <asm/pmu.h> #include <asm/mach/arch.h> @@ -748,7 +750,8 @@ void __init s5p_i2c_hdmiphy_set_platdata(struct s3c2410_platform_i2c *pd) if (!pd) { pd = &default_i2c_data; - if (soc_is_exynos4210()) + if (soc_is_exynos4210() || + soc_is_exynos4212() || soc_is_exynos4412()) pd->bus_num = 8; else if (soc_is_s5pv210()) pd->bus_num = 3; @@ -759,6 +762,30 @@ void __init s5p_i2c_hdmiphy_set_platdata(struct s3c2410_platform_i2c *pd) npd = s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c), &s5p_device_i2c_hdmiphy); } + +struct s5p_hdmi_platform_data s5p_hdmi_def_platdata; + +void __init s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info, + struct i2c_board_info *mhl_info, int mhl_bus) +{ + struct s5p_hdmi_platform_data *pd = &s5p_hdmi_def_platdata; + + if (soc_is_exynos4210() || + soc_is_exynos4212() || soc_is_exynos4412()) + pd->hdmiphy_bus = 8; + else if (soc_is_s5pv210()) + pd->hdmiphy_bus = 3; + else + pd->hdmiphy_bus = 0; + + pd->hdmiphy_info = hdmiphy_info; + pd->mhl_info = mhl_info; + pd->mhl_bus = mhl_bus; + + s3c_set_platdata(pd, sizeof(struct s5p_hdmi_platform_data), + &s5p_device_hdmi); +} + #endif /* CONFIG_S5P_DEV_I2C_HDMIPHY */ /* I2S */ diff --git a/arch/arm/plat-samsung/include/plat/hdmi.h b/arch/arm/plat-samsung/include/plat/hdmi.h new file mode 100644 index 000000000000..331d046ac2c5 --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/hdmi.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PLAT_SAMSUNG_HDMI_H +#define __PLAT_SAMSUNG_HDMI_H __FILE__ + +extern void s5p_hdmi_set_platdata(struct i2c_board_info *hdmiphy_info, + struct i2c_board_info *mhl_info, int mhl_bus); + +#endif /* __PLAT_SAMSUNG_HDMI_H */ diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 64ab65f0fdbc..15070284343e 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -74,7 +74,7 @@ unsigned char pm_uart_udivslot; #ifdef CONFIG_SAMSUNG_PM_DEBUG -struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS]; +static struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS]; static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) { diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 331d574df99c..faf65286574e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -89,6 +89,7 @@ config ATH79 select CEVT_R4K select CSRC_R4K select DMA_NONCOHERENT + select HAVE_CLK select IRQ_CPU select MIPS_MACHINE select SYS_HAS_CPU_MIPS32_R2 diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c index 99969484c475..a124c251c0c9 100644 --- a/arch/mips/alchemy/board-mtx1.c +++ b/arch/mips/alchemy/board-mtx1.c @@ -228,6 +228,8 @@ static int mtx1_pci_idsel(unsigned int devsel, int assert) * adapter on the mtx-1 "singleboard" variant. It triggers a custom * logic chip connected to EXT_IO3 (GPIO1) to suppress IDSEL signals. */ + udelay(1); + if (assert && devsel != 0) /* Suppress signal to Cardbus */ alchemy_gpio_set_value(1, 0); /* set EXT_IO3 OFF */ diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c index 36e9570e7bc4..b2a2311ec85b 100644 --- a/arch/mips/ath79/dev-usb.c +++ b/arch/mips/ath79/dev-usb.c @@ -145,6 +145,8 @@ static void __init ar7240_usb_setup(void) ath79_ohci_resources[0].start = AR7240_OHCI_BASE; ath79_ohci_resources[0].end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1; + ath79_ohci_resources[1].start = ATH79_CPU_IRQ_USB; + ath79_ohci_resources[1].end = ATH79_CPU_IRQ_USB; platform_device_register(&ath79_ohci_device); } diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index 29054f211832..48fe762d2526 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -188,8 +188,10 @@ void __init ath79_gpio_init(void) if (soc_is_ar71xx()) ath79_gpio_count = AR71XX_GPIO_COUNT; - else if (soc_is_ar724x()) - ath79_gpio_count = AR724X_GPIO_COUNT; + else if (soc_is_ar7240()) + ath79_gpio_count = AR7240_GPIO_COUNT; + else if (soc_is_ar7241() || soc_is_ar7242()) + ath79_gpio_count = AR7241_GPIO_COUNT; else if (soc_is_ar913x()) ath79_gpio_count = AR913X_GPIO_COUNT; else if (soc_is_ar933x()) diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c index e39f73048d4f..f1c9c3e2f678 100644 --- a/arch/mips/bcm63xx/dev-spi.c +++ b/arch/mips/bcm63xx/dev-spi.c @@ -106,11 +106,15 @@ int __init bcm63xx_spi_register(void) if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) { spi_resources[0].end += BCM_6338_RSET_SPI_SIZE - 1; spi_pdata.fifo_size = SPI_6338_MSG_DATA_SIZE; + spi_pdata.msg_type_shift = SPI_6338_MSG_TYPE_SHIFT; + spi_pdata.msg_ctl_width = SPI_6338_MSG_CTL_WIDTH; } if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) { spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1; spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE; + spi_pdata.msg_type_shift = SPI_6358_MSG_TYPE_SHIFT; + spi_pdata.msg_ctl_width = SPI_6358_MSG_CTL_WIDTH; } bcm63xx_spi_regs_init(); diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 7fb1f222b8a5..274cd4fad30c 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -61,6 +61,12 @@ static void octeon_irq_set_ciu_mapping(int irq, int line, int bit, octeon_irq_ciu_to_irq[line][bit] = irq; } +static void octeon_irq_force_ciu_mapping(struct irq_domain *domain, + int irq, int line, int bit) +{ + irq_domain_associate(domain, irq, line << 6 | bit); +} + static int octeon_coreid_for_cpu(int cpu) { #ifdef CONFIG_SMP @@ -183,19 +189,9 @@ static void __init octeon_irq_init_core(void) mutex_init(&cd->core_irq_mutex); irq = OCTEON_IRQ_SW0 + i; - switch (irq) { - case OCTEON_IRQ_TIMER: - case OCTEON_IRQ_SW0: - case OCTEON_IRQ_SW1: - case OCTEON_IRQ_5: - case OCTEON_IRQ_PERF: - irq_set_chip_data(irq, cd); - irq_set_chip_and_handler(irq, &octeon_irq_chip_core, - handle_percpu_irq); - break; - default: - break; - } + irq_set_chip_data(irq, cd); + irq_set_chip_and_handler(irq, &octeon_irq_chip_core, + handle_percpu_irq); } } @@ -890,7 +886,6 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d, unsigned int type; unsigned int pin; unsigned int trigger; - struct octeon_irq_gpio_domain_data *gpiod; if (d->of_node != node) return -EINVAL; @@ -925,8 +920,7 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d, break; } *out_type = type; - gpiod = d->host_data; - *out_hwirq = gpiod->base_hwirq + pin; + *out_hwirq = pin; return 0; } @@ -996,19 +990,21 @@ static int octeon_irq_ciu_map(struct irq_domain *d, static int octeon_irq_gpio_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { - unsigned int line = hw >> 6; - unsigned int bit = hw & 63; + struct octeon_irq_gpio_domain_data *gpiod = d->host_data; + unsigned int line, bit; if (!octeon_irq_virq_in_range(virq)) return -EINVAL; + hw += gpiod->base_hwirq; + line = hw >> 6; + bit = hw & 63; if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0) return -EINVAL; octeon_irq_set_ciu_mapping(virq, line, bit, octeon_irq_gpio_chip, octeon_irq_handle_gpio); - return 0; } @@ -1149,6 +1145,7 @@ static void __init octeon_irq_init_ciu(void) struct irq_chip *chip_wd; struct device_node *gpio_node; struct device_node *ciu_node; + struct irq_domain *ciu_domain = NULL; octeon_irq_init_ciu_percpu(); octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu; @@ -1177,31 +1174,6 @@ static void __init octeon_irq_init_ciu(void) /* Mips internal */ octeon_irq_init_core(); - /* CIU_0 */ - for (i = 0; i < 16; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq); - - for (i = 0; i < 4; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_INT0, 0, i + 36, chip, handle_level_irq); - for (i = 0; i < 4; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_MSI0, 0, i + 40, chip, handle_level_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq); - for (i = 0; i < 4; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq); - octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq); - - /* CIU_1 */ - for (i = 0; i < 16; i++) - octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq); - - octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq); - gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio"); if (gpio_node) { struct octeon_irq_gpio_domain_data *gpiod; @@ -1219,10 +1191,35 @@ static void __init octeon_irq_init_ciu(void) ciu_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu"); if (ciu_node) { - irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL); + ciu_domain = irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL); of_node_put(ciu_node); } else - pr_warn("Cannot find device node for cavium,octeon-3860-ciu.\n"); + panic("Cannot find device node for cavium,octeon-3860-ciu."); + + /* CIU_0 */ + for (i = 0; i < 16; i++) + octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_WORKQ0, 0, i + 0); + + octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq); + octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq); + + for (i = 0; i < 4; i++) + octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_INT0, 0, i + 36); + for (i = 0; i < 4; i++) + octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 0, i + 40); + + octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46); + for (i = 0; i < 4; i++) + octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52); + + octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56); + octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_BOOTDMA, 0, 63); + + /* CIU_1 */ + for (i = 0; i < 16; i++) + octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq); + + octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB1, 1, 17); /* Enable the CIU lines */ set_c0_status(STATUSF_IP3 | STATUSF_IP2); diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 1caa78ad06d5..dde504477fac 100644 --- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -393,7 +393,8 @@ #define AR71XX_GPIO_REG_FUNC 0x28 #define AR71XX_GPIO_COUNT 16 -#define AR724X_GPIO_COUNT 18 +#define AR7240_GPIO_COUNT 18 +#define AR7241_GPIO_COUNT 20 #define AR913X_GPIO_COUNT 22 #define AR933X_GPIO_COUNT 30 #define AR934X_GPIO_COUNT 23 diff --git a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h index 4476fa03bf36..6ddae926bf79 100644 --- a/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h +++ b/arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h @@ -42,7 +42,6 @@ #define cpu_has_mips64r1 0 #define cpu_has_mips64r2 0 -#define cpu_has_dsp 0 #define cpu_has_mipsmt 0 #define cpu_has_64bits 0 diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h index 7d98dbe5d4b5..c9bae1362606 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h @@ -9,6 +9,8 @@ int __init bcm63xx_spi_register(void); struct bcm63xx_spi_pdata { unsigned int fifo_size; + unsigned int msg_type_shift; + unsigned int msg_ctl_width; int bus_num; int num_chipselect; u32 speed_hz; diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h index 4ccc2a748aff..61f2a2a5099d 100644 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h +++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h @@ -1054,7 +1054,8 @@ #define SPI_6338_FILL_BYTE 0x07 #define SPI_6338_MSG_TAIL 0x09 #define SPI_6338_RX_TAIL 0x0b -#define SPI_6338_MSG_CTL 0x40 +#define SPI_6338_MSG_CTL 0x40 /* 8-bits register */ +#define SPI_6338_MSG_CTL_WIDTH 8 #define SPI_6338_MSG_DATA 0x41 #define SPI_6338_MSG_DATA_SIZE 0x3f #define SPI_6338_RX_DATA 0x80 @@ -1070,7 +1071,8 @@ #define SPI_6348_FILL_BYTE 0x07 #define SPI_6348_MSG_TAIL 0x09 #define SPI_6348_RX_TAIL 0x0b -#define SPI_6348_MSG_CTL 0x40 +#define SPI_6348_MSG_CTL 0x40 /* 8-bits register */ +#define SPI_6348_MSG_CTL_WIDTH 8 #define SPI_6348_MSG_DATA 0x41 #define SPI_6348_MSG_DATA_SIZE 0x3f #define SPI_6348_RX_DATA 0x80 @@ -1078,6 +1080,7 @@ /* BCM 6358 SPI core */ #define SPI_6358_MSG_CTL 0x00 /* 16-bits register */ +#define SPI_6358_MSG_CTL_WIDTH 16 #define SPI_6358_MSG_DATA 0x02 #define SPI_6358_MSG_DATA_SIZE 0x21e #define SPI_6358_RX_DATA 0x400 @@ -1094,6 +1097,7 @@ /* BCM 6358 SPI core */ #define SPI_6368_MSG_CTL 0x00 /* 16-bits register */ +#define SPI_6368_MSG_CTL_WIDTH 16 #define SPI_6368_MSG_DATA 0x02 #define SPI_6368_MSG_DATA_SIZE 0x21e #define SPI_6368_RX_DATA 0x400 @@ -1115,7 +1119,10 @@ #define SPI_HD_W 0x01 #define SPI_HD_R 0x02 #define SPI_BYTE_CNT_SHIFT 0 -#define SPI_MSG_TYPE_SHIFT 14 +#define SPI_6338_MSG_TYPE_SHIFT 6 +#define SPI_6348_MSG_TYPE_SHIFT 6 +#define SPI_6358_MSG_TYPE_SHIFT 14 +#define SPI_6368_MSG_TYPE_SHIFT 14 /* Command */ #define SPI_CMD_NOOP 0x00 diff --git a/arch/mips/include/asm/mach-cavium-octeon/irq.h b/arch/mips/include/asm/mach-cavium-octeon/irq.h index 418992042f6f..c22a3078bf11 100644 --- a/arch/mips/include/asm/mach-cavium-octeon/irq.h +++ b/arch/mips/include/asm/mach-cavium-octeon/irq.h @@ -21,14 +21,10 @@ enum octeon_irq { OCTEON_IRQ_TIMER, /* sources in CIU_INTX_EN0 */ OCTEON_IRQ_WORKQ0, - OCTEON_IRQ_GPIO0 = OCTEON_IRQ_WORKQ0 + 16, - OCTEON_IRQ_WDOG0 = OCTEON_IRQ_GPIO0 + 16, + OCTEON_IRQ_WDOG0 = OCTEON_IRQ_WORKQ0 + 16, OCTEON_IRQ_WDOG15 = OCTEON_IRQ_WDOG0 + 15, OCTEON_IRQ_MBOX0 = OCTEON_IRQ_WDOG0 + 16, OCTEON_IRQ_MBOX1, - OCTEON_IRQ_UART0, - OCTEON_IRQ_UART1, - OCTEON_IRQ_UART2, OCTEON_IRQ_PCI_INT0, OCTEON_IRQ_PCI_INT1, OCTEON_IRQ_PCI_INT2, @@ -38,8 +34,6 @@ enum octeon_irq { OCTEON_IRQ_PCI_MSI2, OCTEON_IRQ_PCI_MSI3, - OCTEON_IRQ_TWSI, - OCTEON_IRQ_TWSI2, OCTEON_IRQ_RML, OCTEON_IRQ_TIMER0, OCTEON_IRQ_TIMER1, @@ -47,8 +41,6 @@ enum octeon_irq { OCTEON_IRQ_TIMER3, OCTEON_IRQ_USB0, OCTEON_IRQ_USB1, - OCTEON_IRQ_MII0, - OCTEON_IRQ_MII1, OCTEON_IRQ_BOOTDMA, #ifndef CONFIG_PCI_MSI OCTEON_IRQ_LAST = 127 diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h index 7531ecd654d6..dca8bce8c7ab 100644 --- a/arch/mips/include/asm/module.h +++ b/arch/mips/include/asm/module.h @@ -10,6 +10,7 @@ struct mod_arch_specific { struct list_head dbe_list; const struct exception_table_entry *dbe_start; const struct exception_table_entry *dbe_end; + struct mips_hi16 *r_mips_hi16_list; }; typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ diff --git a/arch/mips/include/asm/r4k-timer.h b/arch/mips/include/asm/r4k-timer.h index a37d12b3b61c..afe9e0e03fe9 100644 --- a/arch/mips/include/asm/r4k-timer.h +++ b/arch/mips/include/asm/r4k-timer.h @@ -12,16 +12,16 @@ #ifdef CONFIG_SYNC_R4K -extern void synchronise_count_master(void); -extern void synchronise_count_slave(void); +extern void synchronise_count_master(int cpu); +extern void synchronise_count_slave(int cpu); #else -static inline void synchronise_count_master(void) +static inline void synchronise_count_master(int cpu) { } -static inline void synchronise_count_slave(void) +static inline void synchronise_count_slave(int cpu) { } diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index a5066b1c3de3..4f8c3cba8c0c 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -39,8 +39,6 @@ struct mips_hi16 { Elf_Addr value; }; -static struct mips_hi16 *mips_hi16_list; - static LIST_HEAD(dbe_list); static DEFINE_SPINLOCK(dbe_lock); @@ -128,8 +126,8 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) n->addr = (Elf_Addr *)location; n->value = v; - n->next = mips_hi16_list; - mips_hi16_list = n; + n->next = me->arch.r_mips_hi16_list; + me->arch.r_mips_hi16_list = n; return 0; } @@ -142,18 +140,28 @@ static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v) return 0; } +static void free_relocation_chain(struct mips_hi16 *l) +{ + struct mips_hi16 *next; + + while (l) { + next = l->next; + kfree(l); + l = next; + } +} + static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) { unsigned long insnlo = *location; + struct mips_hi16 *l; Elf_Addr val, vallo; /* Sign extend the addend we extract from the lo insn. */ vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; - if (mips_hi16_list != NULL) { - struct mips_hi16 *l; - - l = mips_hi16_list; + if (me->arch.r_mips_hi16_list != NULL) { + l = me->arch.r_mips_hi16_list; while (l != NULL) { struct mips_hi16 *next; unsigned long insn; @@ -188,7 +196,7 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) l = next; } - mips_hi16_list = NULL; + me->arch.r_mips_hi16_list = NULL; } /* @@ -201,6 +209,9 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) return 0; out_danger: + free_relocation_chain(l); + me->arch.r_mips_hi16_list = NULL; + pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name); return -ENOEXEC; @@ -273,6 +284,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, pr_debug("Applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); + me->arch.r_mips_hi16_list = NULL; for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr @@ -296,6 +308,19 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, return res; } + /* + * Normally the hi16 list should be deallocated at this point. A + * malformed binary however could contain a series of R_MIPS_HI16 + * relocations not followed by a R_MIPS_LO16 relocation. In that + * case, free up the list and return an error. + */ + if (me->arch.r_mips_hi16_list) { + free_relocation_chain(me->arch.r_mips_hi16_list); + me->arch.r_mips_hi16_list = NULL; + + return -ENOEXEC; + } + return 0; } diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 31637d8c8738..9005bf9fb859 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -130,7 +130,7 @@ asmlinkage __cpuinit void start_secondary(void) cpu_set(cpu, cpu_callin_map); - synchronise_count_slave(); + synchronise_count_slave(cpu); /* * irq will be enabled in ->smp_finish(), enabling it too early @@ -173,7 +173,6 @@ void smp_send_stop(void) void __init smp_cpus_done(unsigned int max_cpus) { mp_ops->cpus_done(); - synchronise_count_master(); } /* called from main before smp_init() */ @@ -206,6 +205,7 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) while (!cpu_isset(cpu, cpu_callin_map)) udelay(100); + synchronise_count_master(cpu); return 0; } diff --git a/arch/mips/kernel/sync-r4k.c b/arch/mips/kernel/sync-r4k.c index 842d55e411fd..7f1eca3858de 100644 --- a/arch/mips/kernel/sync-r4k.c +++ b/arch/mips/kernel/sync-r4k.c @@ -28,12 +28,11 @@ static atomic_t __cpuinitdata count_reference = ATOMIC_INIT(0); #define COUNTON 100 #define NR_LOOPS 5 -void __cpuinit synchronise_count_master(void) +void __cpuinit synchronise_count_master(int cpu) { int i; unsigned long flags; unsigned int initcount; - int nslaves; #ifdef CONFIG_MIPS_MT_SMTC /* @@ -43,8 +42,7 @@ void __cpuinit synchronise_count_master(void) return; #endif - printk(KERN_INFO "Synchronize counters across %u CPUs: ", - num_online_cpus()); + printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu); local_irq_save(flags); @@ -52,7 +50,7 @@ void __cpuinit synchronise_count_master(void) * Notify the slaves that it's time to start */ atomic_set(&count_reference, read_c0_count()); - atomic_set(&count_start_flag, 1); + atomic_set(&count_start_flag, cpu); smp_wmb(); /* Count will be initialised to current timer for all CPU's */ @@ -69,10 +67,9 @@ void __cpuinit synchronise_count_master(void) * two CPUs. */ - nslaves = num_online_cpus()-1; for (i = 0; i < NR_LOOPS; i++) { - /* slaves loop on '!= ncpus' */ - while (atomic_read(&count_count_start) != nslaves) + /* slaves loop on '!= 2' */ + while (atomic_read(&count_count_start) != 1) mb(); atomic_set(&count_count_stop, 0); smp_wmb(); @@ -89,7 +86,7 @@ void __cpuinit synchronise_count_master(void) /* * Wait for all slaves to leave the synchronization point: */ - while (atomic_read(&count_count_stop) != nslaves) + while (atomic_read(&count_count_stop) != 1) mb(); atomic_set(&count_count_start, 0); smp_wmb(); @@ -97,6 +94,7 @@ void __cpuinit synchronise_count_master(void) } /* Arrange for an interrupt in a short while */ write_c0_compare(read_c0_count() + COUNTON); + atomic_set(&count_start_flag, 0); local_irq_restore(flags); @@ -108,11 +106,10 @@ void __cpuinit synchronise_count_master(void) printk("done.\n"); } -void __cpuinit synchronise_count_slave(void) +void __cpuinit synchronise_count_slave(int cpu) { int i; unsigned int initcount; - int ncpus; #ifdef CONFIG_MIPS_MT_SMTC /* @@ -127,16 +124,15 @@ void __cpuinit synchronise_count_slave(void) * so we first wait for the master to say everyone is ready */ - while (!atomic_read(&count_start_flag)) + while (atomic_read(&count_start_flag) != cpu) mb(); /* Count will be initialised to next expire for all CPU's */ initcount = atomic_read(&count_reference); - ncpus = num_online_cpus(); for (i = 0; i < NR_LOOPS; i++) { atomic_inc(&count_count_start); - while (atomic_read(&count_count_start) != ncpus) + while (atomic_read(&count_count_start) != 2) mb(); /* @@ -146,7 +142,7 @@ void __cpuinit synchronise_count_slave(void) write_c0_count(initcount); atomic_inc(&count_count_stop); - while (atomic_read(&count_count_stop) != ncpus) + while (atomic_read(&count_count_stop) != 2) mb(); } /* Arrange for an interrupt in a short while */ diff --git a/arch/mips/mti-malta/malta-pci.c b/arch/mips/mti-malta/malta-pci.c index 284dea54faf5..2147cb34e705 100644 --- a/arch/mips/mti-malta/malta-pci.c +++ b/arch/mips/mti-malta/malta-pci.c @@ -252,16 +252,3 @@ void __init mips_pcibios_init(void) register_pci_controller(controller); } - -/* Enable PCI 2.1 compatibility in PIIX4 */ -static void __devinit quirk_dlcsetup(struct pci_dev *dev) -{ - u8 odlc, ndlc; - (void) pci_read_config_byte(dev, 0x82, &odlc); - /* Enable passive releases and delayed transaction */ - ndlc = odlc | 7; - (void) pci_write_config_byte(dev, 0x82, ndlc); -} - -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, - quirk_dlcsetup); diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 414a7459858d..86d77a666458 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -23,9 +23,12 @@ #define AR724X_PCI_MEM_BASE 0x10000000 #define AR724X_PCI_MEM_SIZE 0x08000000 +#define AR724X_PCI_REG_RESET 0x18 #define AR724X_PCI_REG_INT_STATUS 0x4c #define AR724X_PCI_REG_INT_MASK 0x50 +#define AR724X_PCI_RESET_LINK_UP BIT(0) + #define AR724X_PCI_INT_DEV0 BIT(14) #define AR724X_PCI_IRQ_COUNT 1 @@ -38,6 +41,15 @@ static void __iomem *ar724x_pci_ctrl_base; static u32 ar724x_pci_bar0_value; static bool ar724x_pci_bar0_is_cached; +static bool ar724x_pci_link_up; + +static inline bool ar724x_pci_check_link(void) +{ + u32 reset; + + reset = __raw_readl(ar724x_pci_ctrl_base + AR724X_PCI_REG_RESET); + return reset & AR724X_PCI_RESET_LINK_UP; +} static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, uint32_t *value) @@ -46,6 +58,9 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, void __iomem *base; u32 data; + if (!ar724x_pci_link_up) + return PCIBIOS_DEVICE_NOT_FOUND; + if (devfn) return PCIBIOS_DEVICE_NOT_FOUND; @@ -96,6 +111,9 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, u32 data; int s; + if (!ar724x_pci_link_up) + return PCIBIOS_DEVICE_NOT_FOUND; + if (devfn) return PCIBIOS_DEVICE_NOT_FOUND; @@ -280,6 +298,10 @@ int __init ar724x_pcibios_init(int irq) if (ar724x_pci_ctrl_base == NULL) goto err_unmap_devcfg; + ar724x_pci_link_up = ar724x_pci_check_link(); + if (!ar724x_pci_link_up) + pr_warn("ar724x: PCIe link is down\n"); + ar724x_pci_irq_init(irq); register_pci_controller(&ar724x_pci_controller); diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 6c6defc24619..af9cf30ed474 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -141,7 +141,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) -#define ATOMIC_INIT(i) ((atomic_t) { (i) }) +#define ATOMIC_INIT(i) { (i) } #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() @@ -150,7 +150,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) #ifdef CONFIG_64BIT -#define ATOMIC64_INIT(i) ((atomic64_t) { (i) }) +#define ATOMIC64_INIT(i) { (i) } static __inline__ s64 __atomic64_add_return(s64 i, atomic64_t *v) diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index d4b94b395c16..2c05a9292a81 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -309,7 +309,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, cregs->ksp = (unsigned long)stack + (pregs->gr[21] & (THREAD_SIZE - 1)); cregs->gr[30] = usp; - if (p->personality == PER_HPUX) { + if (personality(p->personality) == PER_HPUX) { #ifdef CONFIG_HPUX cregs->kpc = (unsigned long) &hpux_child_return; #else diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index c9b932260f47..7426e40699bd 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -225,12 +225,12 @@ long parisc_personality(unsigned long personality) long err; if (personality(current->personality) == PER_LINUX32 - && personality == PER_LINUX) - personality = PER_LINUX32; + && personality(personality) == PER_LINUX) + personality = (personality & ~PER_MASK) | PER_LINUX32; err = sys_personality(personality); - if (err == PER_LINUX32) - err = PER_LINUX; + if (personality(err) == PER_LINUX32) + err = (err & ~PER_MASK) | PER_LINUX; return err; } diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi index 8d35d2c1f694..4f9c9f682ecf 100644 --- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi @@ -345,6 +345,13 @@ /include/ "qoriq-duart-1.dtsi" /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" + usb@210000 { + compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; + port0; + }; /include/ "qoriq-usb2-dr-0.dtsi" + usb@211000 { + compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; + }; /include/ "qoriq-sec4.0-0.dtsi" }; diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig index f4337bacd0e7..26e541c4662b 100644 --- a/arch/powerpc/configs/85xx/p1023rds_defconfig +++ b/arch/powerpc/configs/85xx/p1023rds_defconfig @@ -6,28 +6,27 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y -CONFIG_SPARSE_IRQ=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_KALLSYMS_ALL=y -CONFIG_KALLSYMS_EXTRA_PASS=y CONFIG_EMBEDDED=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y CONFIG_P1023_RDS=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_CPM2=y -CONFIG_GPIO_MPC8XXX=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_MISC=m CONFIG_MATH_EMULATION=y @@ -63,11 +62,11 @@ CONFIG_INET_ESP=y CONFIG_IPV6=y CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -80,15 +79,14 @@ CONFIG_SATA_FSL=y CONFIG_SATA_SIL24=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y +CONFIG_FS_ENET=y +CONFIG_FSL_PQ_MDIO=y +CONFIG_E1000E=y CONFIG_MARVELL_PHY=y CONFIG_DAVICOM_PHY=y CONFIG_CICADA_PHY=y CONFIG_VITESSE_PHY=y CONFIG_FIXED_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_FS_ENET=y -CONFIG_E1000E=y -CONFIG_FSL_PQ_MDIO=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -98,16 +96,15 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y CONFIG_SERIAL_QE=m -CONFIG_HW_RANDOM=y CONFIG_NVRAM=y CONFIG_I2C=y CONFIG_I2C_CPM=m CONFIG_I2C_MPC=y +CONFIG_GPIO_MPC8XXX=y # CONFIG_HWMON is not set CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_SOUND=y @@ -123,7 +120,6 @@ CONFIG_DMADEVICES=y CONFIG_FSL_DMA=y # CONFIG_NET_DMA is not set CONFIG_STAGING=y -# CONFIG_STAGING_EXCLUDE_BUILD is not set CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set @@ -150,22 +146,15 @@ CONFIG_QNX4FS_FS=m CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y CONFIG_FRAME_WARN=8092 CONFIG_DEBUG_FS=y -CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y # CONFIG_DEBUG_BUGVERBOSE is not set CONFIG_DEBUG_INFO=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig index cbb98c1234fd..8b3d57c1ebe8 100644 --- a/arch/powerpc/configs/corenet32_smp_defconfig +++ b/arch/powerpc/configs/corenet32_smp_defconfig @@ -6,8 +6,8 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y -CONFIG_SPARSE_IRQ=y -CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -21,23 +21,22 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y CONFIG_P2041_RDB=y CONFIG_P3041_DS=y CONFIG_P4080_DS=y CONFIG_P5020_DS=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_BINFMT_MISC=m CONFIG_KEXEC=y CONFIG_IRQ_ALL_CPUS=y CONFIG_FORCE_MAX_ZONEORDER=13 -CONFIG_FSL_LBC=y CONFIG_PCI=y CONFIG_PCIEPORTBUS=y -CONFIG_PCI_MSI=y # CONFIG_PCIEASPM is not set +CONFIG_PCI_MSI=y CONFIG_RAPIDIO=y CONFIG_FSL_RIO=y CONFIG_NET=y @@ -70,6 +69,7 @@ CONFIG_INET_IPCOMP=y CONFIG_IPV6=y CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y @@ -77,17 +77,14 @@ CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_ECC=y -CONFIG_MTD_NAND_IDS=y -CONFIG_MTD_NAND_FSL_IFC=y CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND_FSL_IFC=y CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y @@ -115,11 +112,9 @@ CONFIG_SERIO_LIBPS2=y CONFIG_PPC_EPAPR_HV_BYTECHAN=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y -CONFIG_HW_RANDOM=y CONFIG_NVRAM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y @@ -132,7 +127,6 @@ CONFIG_SPI_FSL_ESPI=y CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_USB_HID=m CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_FSL=y @@ -142,8 +136,6 @@ CONFIG_USB_OHCI_HCD_PPC_OF_LE=y CONFIG_USB_STORAGE=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_OF=y -CONFIG_MMC_SDHCI_OF_ESDHC=y CONFIG_EDAC=y CONFIG_EDAC_MM_EDAC=y CONFIG_EDAC_MPC85XX=y @@ -170,19 +162,16 @@ CONFIG_HUGETLBFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=m -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_UTF8=m CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_SHIRQ=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_RCU_TRACE=y CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_MD4=y diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig index dd89de8b0b7f..0516e22ca3de 100644 --- a/arch/powerpc/configs/corenet64_smp_defconfig +++ b/arch/powerpc/configs/corenet64_smp_defconfig @@ -56,6 +56,7 @@ CONFIG_INET_ESP=y CONFIG_IPV6=y CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig index 15130066e5e2..07b7f2af2dca 100644 --- a/arch/powerpc/configs/g5_defconfig +++ b/arch/powerpc/configs/g5_defconfig @@ -1,8 +1,10 @@ +CONFIG_PPC64=y +CONFIG_ALTIVEC=y +CONFIG_SMP=y +CONFIG_NR_CPUS=4 CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_BLK_DEV_INITRD=y @@ -13,15 +15,16 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y -CONFIG_SMP=y -CONFIG_NR_CPUS=4 -CONFIG_KEXEC=y -# CONFIG_RELOCATABLE is not set +# CONFIG_PPC_PSERIES is not set CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_PMAC64=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_KEXEC=y +CONFIG_IRQ_ALL_CPUS=y +# CONFIG_MIGRATION is not set CONFIG_PCI_MSI=y CONFIG_NET=y CONFIG_PACKET=y @@ -49,6 +52,7 @@ CONFIG_NF_CT_NETLINK=m CONFIG_NF_CONNTRACK_IPV4=m CONFIG_IP_NF_QUEUE=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y @@ -56,6 +60,8 @@ CONFIG_BLK_DEV_RAM_SIZE=65536 CONFIG_CDROM_PKTCDVD=m CONFIG_IDE=y CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y @@ -79,24 +85,33 @@ CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m CONFIG_DM_MIRROR=m CONFIG_DM_ZERO=m -CONFIG_MACINTOSH_DRIVERS=y +CONFIG_IEEE1394=y +CONFIG_IEEE1394_OHCI1394=y +CONFIG_IEEE1394_SBP2=m +CONFIG_IEEE1394_ETH1394=m +CONFIG_IEEE1394_RAWIO=y +CONFIG_IEEE1394_VIDEO1394=m +CONFIG_IEEE1394_DV1394=m +CONFIG_ADB_PMU=y +CONFIG_PMAC_SMU=y CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_THERM_PM72=y +CONFIG_WINDFARM=y +CONFIG_WINDFARM_PM81=y +CONFIG_WINDFARM_PM91=y +CONFIG_WINDFARM_PM112=y +CONFIG_WINDFARM_PM121=y CONFIG_NETDEVICES=y -CONFIG_BONDING=m CONFIG_DUMMY=m -CONFIG_MII=y +CONFIG_BONDING=m CONFIG_TUN=m +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SUNGEM=y CONFIG_ACENIC=m CONFIG_ACENIC_OMIT_TIGON_I=y -CONFIG_TIGON3=y CONFIG_E1000=y -CONFIG_SUNGEM=y -CONFIG_PPP=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPPOE=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m +CONFIG_TIGON3=y CONFIG_USB_CATC=m CONFIG_USB_KAWETH=m CONFIG_USB_PEGASUS=m @@ -106,24 +121,36 @@ CONFIG_USB_USBNET=m # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_CDC_SUBSET is not set # CONFIG_USB_NET_ZAURUS is not set +CONFIG_PPP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set # CONFIG_MOUSE_PS2 is not set +# CONFIG_SERIO_I8042 is not set # CONFIG_SERIO_SERPORT is not set -CONFIG_VT_HW_CONSOLE_BINDING=y # CONFIG_HW_RANDOM is not set CONFIG_GEN_RTC=y CONFIG_RAW_DRIVER=y CONFIG_I2C_CHARDEV=y # CONFIG_HWMON is not set -CONFIG_AGP=y -CONFIG_DRM=y -CONFIG_DRM_NOUVEAU=y +CONFIG_AGP=m +CONFIG_AGP_UNINORTH=m CONFIG_VIDEO_OUTPUT_CONTROL=m +CONFIG_FB=y CONFIG_FIRMWARE_EDID=y CONFIG_FB_TILEBLITTING=y +CONFIG_FB_OF=y +CONFIG_FB_NVIDIA=y +CONFIG_FB_NVIDIA_I2C=y CONFIG_FB_RADEON=y +# CONFIG_VGA_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y CONFIG_SOUND=m CONFIG_SND=m @@ -131,7 +158,15 @@ CONFIG_SND_SEQUENCER=m CONFIG_SND_MIXER_OSS=m CONFIG_SND_PCM_OSS=m CONFIG_SND_SEQUENCER_OSS=y +CONFIG_SND_POWERMAC=m +CONFIG_SND_AOA=m +CONFIG_SND_AOA_FABRIC_LAYOUT=m +CONFIG_SND_AOA_ONYX=m +CONFIG_SND_AOA_TAS=m +CONFIG_SND_AOA_TOONIE=m CONFIG_SND_USB_AUDIO=m +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y CONFIG_HID_GYRATION=y CONFIG_LOGITECH_FF=y CONFIG_HID_PANTHERLORD=y @@ -139,12 +174,13 @@ CONFIG_HID_PETALYNX=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y -CONFIG_HID_PID=y -CONFIG_USB_HIDDEV=y CONFIG_USB=y +CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_HCD_PPC_OF is not set CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PPC_OF_BE=y CONFIG_USB_ACM=m CONFIG_USB_PRINTER=y CONFIG_USB_STORAGE=y @@ -208,6 +244,8 @@ CONFIG_REISERFS_FS_POSIX_ACL=y CONFIG_REISERFS_FS_SECURITY=y CONFIG_XFS_FS=m CONFIG_XFS_POSIX_ACL=y +CONFIG_INOTIFY=y +CONFIG_AUTOFS_FS=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y @@ -221,12 +259,14 @@ CONFIG_HFS_FS=m CONFIG_HFSPLUS_FS=m CONFIG_CRAMFS=y CONFIG_NFS_FS=y +CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFSD=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y CONFIG_CIFS=m +CONFIG_PARTITION_ADVANCED=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_1250=y CONFIG_NLS_CODEPAGE_1251=y @@ -234,23 +274,29 @@ CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_15=y CONFIG_NLS_UTF8=y +CONFIG_CRC_T10DIF=y +CONFIG_LIBCRC32C=m CONFIG_MAGIC_SYSRQ=y -# CONFIG_UNUSED_SYMBOLS is not set CONFIG_DEBUG_FS=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_MUTEXES=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set CONFIG_LATENCYTOP=y -CONFIG_STRICT_DEVMEM=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_BOOTX_TEXT=y CONFIG_CRYPTO_NULL=m CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_SHA256=m CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m @@ -260,6 +306,3 @@ CONFIG_CRYPTO_TEA=m CONFIG_CRYPTO_TWOFISH=m # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_HW is not set -# CONFIG_VIRTUALIZATION is not set -CONFIG_CRC_T10DIF=y -CONFIG_LIBCRC32C=m diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig index 5aac9a8bc53b..9352e4430c3b 100644 --- a/arch/powerpc/configs/mpc83xx_defconfig +++ b/arch/powerpc/configs/mpc83xx_defconfig @@ -2,12 +2,12 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_SLAB=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y # CONFIG_PPC_CHRP is not set # CONFIG_PPC_PMAC is not set CONFIG_PPC_83xx=y @@ -25,7 +25,6 @@ CONFIG_ASP834x=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_MATH_EMULATION=y -CONFIG_SPARSE_IRQ=y CONFIG_PCI=y CONFIG_NET=y CONFIG_PACKET=y @@ -42,10 +41,9 @@ CONFIG_INET_ESP=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y # CONFIG_FW_LOADER is not set CONFIG_MTD=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_OF_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y @@ -64,15 +62,14 @@ CONFIG_ATA=y CONFIG_SATA_FSL=y CONFIG_SATA_SIL=y CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_UCC_GETH=y +CONFIG_GIANFAR=y CONFIG_MARVELL_PHY=y CONFIG_DAVICOM_PHY=y CONFIG_VITESSE_PHY=y CONFIG_ICPLUS_PHY=y CONFIG_FIXED_PHY=y -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_GIANFAR=y -CONFIG_UCC_GETH=y CONFIG_INPUT_FF_MEMLESS=m # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_KEYBOARD is not set @@ -112,17 +109,12 @@ CONFIG_RTC_DRV_DS1374=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_INOTIFY=y CONFIG_PROC_KCORE=y CONFIG_TMPFS=y CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y -CONFIG_PARTITION_ADVANCED=y CONFIG_CRC_T10DIF=y -# CONFIG_RCU_CPU_STALL_DETECTOR is not set -CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_CRYPTO_ECB=m CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index 03ee911c4577..8b5bda27d248 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -5,7 +5,9 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y -CONFIG_SPARSE_IRQ=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -17,6 +19,8 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y CONFIG_MPC8540_ADS=y CONFIG_MPC8560_ADS=y CONFIG_MPC85xx_CDS=y @@ -40,8 +44,6 @@ CONFIG_SBC8548=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=m CONFIG_MATH_EMULATION=y CONFIG_FORCE_MAX_ZONEORDER=12 @@ -74,36 +76,25 @@ CONFIG_INET_ESP=y CONFIG_IPV6=y CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y CONFIG_FTL=y -CONFIG_MTD_GEN_PROBE=y -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y +CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_CFI_UTIL=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_IFC=y -CONFIG_MTD_NAND_IDS=y -CONFIG_MTD_NAND_ECC=y -CONFIG_MTD_M25P80=y CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -115,6 +106,7 @@ CONFIG_ATA=y CONFIG_SATA_AHCI=y CONFIG_SATA_FSL=y CONFIG_PATA_ALI=y +CONFIG_PATA_VIA=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_FS_ENET=y @@ -134,7 +126,6 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y @@ -183,7 +174,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_FSL=y @@ -229,18 +219,13 @@ CONFIG_QNX4FS_FS=m CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y CONFIG_DEBUG_FS=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index fdfa84dc908f..b0974e7e98ae 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -7,7 +7,9 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_AUDIT=y -CONFIG_SPARSE_IRQ=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=14 @@ -19,6 +21,8 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y # CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +CONFIG_MAC_PARTITION=y CONFIG_MPC8540_ADS=y CONFIG_MPC8560_ADS=y CONFIG_MPC85xx_CDS=y @@ -42,8 +46,6 @@ CONFIG_SBC8548=y CONFIG_QUICC_ENGINE=y CONFIG_QE_GPIO=y CONFIG_HIGHMEM=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y CONFIG_BINFMT_MISC=m CONFIG_MATH_EMULATION=y CONFIG_IRQ_ALL_CPUS=y @@ -77,36 +79,25 @@ CONFIG_INET_ESP=y CONFIG_IPV6=y CONFIG_IP_SCTP=m CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y CONFIG_FTL=y -CONFIG_MTD_GEN_PROBE=y -CONFIG_MTD_MAP_BANK_WIDTH_1=y -CONFIG_MTD_MAP_BANK_WIDTH_2=y -CONFIG_MTD_MAP_BANK_WIDTH_4=y -CONFIG_MTD_CFI_I1=y -CONFIG_MTD_CFI_I2=y +CONFIG_MTD_CFI=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_CFI_UTIL=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_PARTITIONS=y -CONFIG_MTD_OF_PARTS=y +CONFIG_MTD_M25P80=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_FSL_ELBC=y CONFIG_MTD_NAND_FSL_IFC=y -CONFIG_MTD_NAND_IDS=y -CONFIG_MTD_NAND_ECC=y -CONFIG_MTD_M25P80=y CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y CONFIG_EEPROM_LEGACY=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y @@ -137,7 +128,6 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y @@ -186,7 +176,6 @@ CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SUNPLUS=y CONFIG_USB=y -CONFIG_USB_DEVICEFS=y CONFIG_USB_MON=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_FSL=y @@ -232,18 +221,13 @@ CONFIG_QNX4FS_FS=m CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_NFS_FS=y -CONFIG_NFS_V3=y CONFIG_NFS_V4=y CONFIG_ROOT_NFS=y CONFIG_NFSD=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y CONFIG_CRC_T10DIF=y CONFIG_DEBUG_FS=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_IRQ_DOMAIN_DEBUG=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 50d82c8a037f..b3c083de17ad 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -553,9 +553,7 @@ static inline int cpu_has_feature(unsigned long feature) & feature); } -#ifdef CONFIG_HAVE_HW_BREAKPOINT #define HBP_NUM 1 -#endif /* CONFIG_HAVE_HW_BREAKPOINT */ #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 50ea12fd7bf5..a8bf5c673a3c 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -33,6 +33,7 @@ #include <asm/kvm_asm.h> #include <asm/processor.h> #include <asm/page.h> +#include <asm/cacheflush.h> #define KVM_MAX_VCPUS NR_CPUS #define KVM_MAX_VCORES NR_CPUS diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 0124937a23b9..e006f0bdea95 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h @@ -219,4 +219,16 @@ void kvmppc_claim_lpid(long lpid); void kvmppc_free_lpid(long lpid); void kvmppc_init_lpid(unsigned long nr_lpids); +static inline void kvmppc_mmu_flush_icache(pfn_t pfn) +{ + /* Clear i-cache for new pages */ + struct page *page; + page = pfn_to_page(pfn); + if (!test_bit(PG_arch_1, &page->flags)) { + flush_dcache_icache_page(page); + set_bit(PG_arch_1, &page->flags); + } +} + + #endif /* __POWERPC_KVM_PPC_H__ */ diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h index 326d33ca55cd..d4f471fb1031 100644 --- a/arch/powerpc/include/asm/mpic_msgr.h +++ b/arch/powerpc/include/asm/mpic_msgr.h @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/spinlock.h> #include <asm/smp.h> +#include <asm/io.h> struct mpic_msgr { u32 __iomem *base; diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index 2d7bb8ced136..e4897523de41 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -83,11 +83,10 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask) return 0; } - if ((tbl->it_offset + tbl->it_size) > (mask >> IOMMU_PAGE_SHIFT)) { - dev_info(dev, "Warning: IOMMU window too big for device mask\n"); - dev_info(dev, "mask: 0x%08llx, table end: 0x%08lx\n", - mask, (tbl->it_offset + tbl->it_size) << - IOMMU_PAGE_SHIFT); + if (tbl->it_offset > (mask >> IOMMU_PAGE_SHIFT)) { + dev_info(dev, "Warning: IOMMU offset too big for device mask\n"); + dev_info(dev, "mask: 0x%08llx, table offset: 0x%08lx\n", + mask, tbl->it_offset << IOMMU_PAGE_SHIFT); return 0; } else return 1; diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index f3a82dde61db..956a4c496de9 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -253,7 +253,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) /* Do not emulate user-space instructions, instead single-step them */ if (user_mode(regs)) { - bp->ctx->task->thread.last_hit_ubp = bp; + current->thread.last_hit_ubp = bp; regs->msr |= MSR_SE; goto out; } diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 782bd0a3c2f0..c470a40b29f5 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -25,6 +25,7 @@ #include <asm/processor.h> #include <asm/machdep.h> #include <asm/debug.h> +#include <linux/slab.h> /* * This table contains the mapping between PowerPC hardware trap types, and @@ -101,6 +102,21 @@ static int computeSignal(unsigned int tt) return SIGHUP; /* default for things we don't know about */ } +/** + * + * kgdb_skipexception - Bail out of KGDB when we've been triggered. + * @exception: Exception vector number + * @regs: Current &struct pt_regs. + * + * On some architectures we need to skip a breakpoint exception when + * it occurs after a breakpoint has been removed. + * + */ +int kgdb_skipexception(int exception, struct pt_regs *regs) +{ + return kgdb_isremovedbreak(regs->nip); +} + static int kgdb_call_nmi_hook(struct pt_regs *regs) { kgdb_nmicallback(raw_smp_processor_id(), regs); @@ -138,6 +154,8 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs) static int kgdb_singlestep(struct pt_regs *regs) { struct thread_info *thread_info, *exception_thread_info; + struct thread_info *backup_current_thread_info = \ + (struct thread_info *)kmalloc(sizeof(struct thread_info), GFP_KERNEL); if (user_mode(regs)) return 0; @@ -155,13 +173,17 @@ static int kgdb_singlestep(struct pt_regs *regs) thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1)); exception_thread_info = current_thread_info(); - if (thread_info != exception_thread_info) + if (thread_info != exception_thread_info) { + /* Save the original current_thread_info. */ + memcpy(backup_current_thread_info, exception_thread_info, sizeof *thread_info); memcpy(exception_thread_info, thread_info, sizeof *thread_info); + } kgdb_handle_exception(0, SIGTRAP, 0, regs); if (thread_info != exception_thread_info) - memcpy(thread_info, exception_thread_info, sizeof *thread_info); + /* Restore current_thread_info lastly. */ + memcpy(exception_thread_info, backup_current_thread_info, sizeof *thread_info); return 1; } @@ -410,7 +432,6 @@ int kgdb_arch_handle_exception(int vector, int signo, int err_code, #else linux_regs->msr |= MSR_SE; #endif - kgdb_single_step = 1; atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id()); } diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index f2496f2faecc..4e3cc47f26b9 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -107,11 +107,11 @@ long ppc64_personality(unsigned long personality) long ret; if (personality(current->personality) == PER_LINUX32 - && personality == PER_LINUX) - personality = PER_LINUX32; + && personality(personality) == PER_LINUX) + personality = (personality & ~PER_MASK) | PER_LINUX32; ret = sys_personality(personality); - if (ret == PER_LINUX32) - ret = PER_LINUX; + if (personality(ret) == PER_LINUX32) + ret = (ret & ~PER_MASK) | PER_LINUX; return ret; } #endif diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c index f922c29bb234..837f13e7b6bf 100644 --- a/arch/powerpc/kvm/book3s_32_mmu_host.c +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c @@ -211,6 +211,9 @@ next_pteg: pteg1 |= PP_RWRX; } + if (orig_pte->may_execute) + kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT); + local_irq_disable(); if (pteg[rr]) { diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c index 10fc8ec9d2a8..0688b6b39585 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -126,6 +126,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) if (!orig_pte->may_execute) rflags |= HPTE_R_N; + else + kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT); hash = hpt_hash(va, PTE_SIZE, MMU_SEGSIZE_256M); diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 5a84c8d3d040..44b72feaff7d 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1421,13 +1421,13 @@ _GLOBAL(kvmppc_h_cede) sync /* order setting ceded vs. testing prodded */ lbz r5,VCPU_PRODDED(r3) cmpwi r5,0 - bne 1f + bne kvm_cede_prodded li r0,0 /* set trap to 0 to say hcall is handled */ stw r0,VCPU_TRAP(r3) li r0,H_SUCCESS std r0,VCPU_GPR(R3)(r3) BEGIN_FTR_SECTION - b 2f /* just send it up to host on 970 */ + b kvm_cede_exit /* just send it up to host on 970 */ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) /* @@ -1446,7 +1446,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206) or r4,r4,r0 PPC_POPCNTW(R7,R4) cmpw r7,r8 - bge 2f + bge kvm_cede_exit stwcx. r4,0,r6 bne 31b li r0,1 @@ -1555,7 +1555,8 @@ kvm_end_cede: b hcall_real_fallback /* cede when already previously prodded case */ -1: li r0,0 +kvm_cede_prodded: + li r0,0 stb r0,VCPU_PRODDED(r3) sync /* order testing prodded vs. clearing ceded */ stb r0,VCPU_CEDED(r3) @@ -1563,7 +1564,8 @@ kvm_end_cede: blr /* we've ceded but we want to give control to the host */ -2: li r3,H_TOO_HARD +kvm_cede_exit: + li r3,H_TOO_HARD blr secondary_too_late: diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index c510fc961302..a2b66717813d 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c @@ -322,11 +322,11 @@ static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref) static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500) { if (vcpu_e500->g2h_tlb1_map) - memset(vcpu_e500->g2h_tlb1_map, - sizeof(u64) * vcpu_e500->gtlb_params[1].entries, 0); + memset(vcpu_e500->g2h_tlb1_map, 0, + sizeof(u64) * vcpu_e500->gtlb_params[1].entries); if (vcpu_e500->h2g_tlb1_rmap) - memset(vcpu_e500->h2g_tlb1_rmap, - sizeof(unsigned int) * host_tlb_params[1].entries, 0); + memset(vcpu_e500->h2g_tlb1_rmap, 0, + sizeof(unsigned int) * host_tlb_params[1].entries); } static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500) @@ -539,6 +539,9 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize, ref, gvaddr, stlbe); + + /* Clear i-cache for new pages */ + kvmppc_mmu_flush_icache(pfn); } /* XXX only map the one-one case, for now use TLB0 */ diff --git a/arch/powerpc/lib/copyuser_power7.S b/arch/powerpc/lib/copyuser_power7.S index f9ede7c6606e..0d24ff15f5f6 100644 --- a/arch/powerpc/lib/copyuser_power7.S +++ b/arch/powerpc/lib/copyuser_power7.S @@ -288,7 +288,7 @@ err1; stb r0,0(r3) std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) bl .enter_vmx_usercopy - cmpwi r3,0 + cmpwi cr1,r3,0 ld r0,STACKFRAMESIZE+16(r1) ld r3,STACKFRAMESIZE+48(r1) ld r4,STACKFRAMESIZE+56(r1) @@ -326,38 +326,7 @@ err1; stb r0,0(r3) dcbt r0,r8,0b01010 /* GO */ .machine pop - /* - * We prefetch both the source and destination using enhanced touch - * instructions. We use a stream ID of 0 for the load side and - * 1 for the store side. - */ - clrrdi r6,r4,7 - clrrdi r9,r3,7 - ori r9,r9,1 /* stream=1 */ - - srdi r7,r5,7 /* length in cachelines, capped at 0x3FF */ - cmpldi cr1,r7,0x3FF - ble cr1,1f - li r7,0x3FF -1: lis r0,0x0E00 /* depth=7 */ - sldi r7,r7,7 - or r7,r7,r0 - ori r10,r7,1 /* stream=1 */ - - lis r8,0x8000 /* GO=1 */ - clrldi r8,r8,32 - -.machine push -.machine "power4" - dcbt r0,r6,0b01000 - dcbt r0,r7,0b01010 - dcbtst r0,r9,0b01000 - dcbtst r0,r10,0b01010 - eieio - dcbt r0,r8,0b01010 /* GO */ -.machine pop - - beq .Lunwind_stack_nonvmx_copy + beq cr1,.Lunwind_stack_nonvmx_copy /* * If source and destination are not relatively aligned we use a diff --git a/arch/powerpc/lib/memcpy_power7.S b/arch/powerpc/lib/memcpy_power7.S index 0efdc51bc716..7ba6c96de778 100644 --- a/arch/powerpc/lib/memcpy_power7.S +++ b/arch/powerpc/lib/memcpy_power7.S @@ -222,7 +222,7 @@ _GLOBAL(memcpy_power7) std r0,16(r1) stdu r1,-STACKFRAMESIZE(r1) bl .enter_vmx_copy - cmpwi r3,0 + cmpwi cr1,r3,0 ld r0,STACKFRAMESIZE+16(r1) ld r3,STACKFRAMESIZE+48(r1) ld r4,STACKFRAMESIZE+56(r1) @@ -260,7 +260,7 @@ _GLOBAL(memcpy_power7) dcbt r0,r8,0b01010 /* GO */ .machine pop - beq .Lunwind_stack_nonvmx_copy + beq cr1,.Lunwind_stack_nonvmx_copy /* * If source and destination are not relatively aligned we use a diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index baaafde7d135..fbdad0e3929a 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -469,6 +469,7 @@ void flush_dcache_icache_page(struct page *page) __flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT); #endif } +EXPORT_SYMBOL(flush_dcache_icache_page); void clear_user_page(void *page, unsigned long vaddr, struct page *pg) { diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 77b49ddda9d3..7cd2dbd6e4c4 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -1431,7 +1431,7 @@ static void perf_event_interrupt(struct pt_regs *regs) if (!event->hw.idx || is_limited_pmc(event->hw.idx)) continue; val = read_pmc(event->hw.idx); - if ((int)val < 0) { + if (pmc_overflow(val)) { /* event has overflowed */ found = 1; record_and_restart(event, val, regs); diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index a7b2a600d0a4..c37f46136321 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -465,7 +465,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) iounmap(hose->cfg_data); iounmap(hose->cfg_addr); pcibios_free_controller(hose); - return 0; + return -ENODEV; } setup_pci_cmd(hose); @@ -827,6 +827,7 @@ struct device_node *fsl_pci_primary; void __devinit fsl_pci_init(void) { + int ret; struct device_node *node; struct pci_controller *hose; dma_addr_t max = 0xffffffff; @@ -855,10 +856,12 @@ void __devinit fsl_pci_init(void) if (!fsl_pci_primary) fsl_pci_primary = node; - fsl_add_bridge(node, fsl_pci_primary == node); - hose = pci_find_hose_for_OF_device(node); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); + ret = fsl_add_bridge(node, fsl_pci_primary == node); + if (ret == 0) { + hose = pci_find_hose_for_OF_device(node); + max = min(max, hose->dma_window_base_cur + + hose->dma_window_size); + } } } diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c index 483d8fa72e8b..e961f8c4a8f0 100644 --- a/arch/powerpc/sysdev/mpic_msgr.c +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -14,6 +14,9 @@ #include <linux/list.h> #include <linux/of_platform.h> #include <linux/errno.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/slab.h> #include <asm/prom.h> #include <asm/hw_irq.h> #include <asm/ppc-pci.h> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index eab3492a45c5..9b49c65ee7a4 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -17,6 +17,7 @@ #include <linux/reboot.h> #include <linux/delay.h> #include <linux/kallsyms.h> +#include <linux/kmsg_dump.h> #include <linux/cpumask.h> #include <linux/export.h> #include <linux/sysrq.h> @@ -894,13 +895,13 @@ cmds(struct pt_regs *excp) #endif default: printf("Unrecognized command: "); - do { + do { if (' ' < cmd && cmd <= '~') putchar(cmd); else printf("\\x%x", cmd); cmd = inchar(); - } while (cmd != '\n'); + } while (cmd != '\n'); printf(" (type ? for help)\n"); break; } @@ -1097,7 +1098,7 @@ static long check_bp_loc(unsigned long addr) return 1; } -static char *breakpoint_help_string = +static char *breakpoint_help_string = "Breakpoint command usage:\n" "b show breakpoints\n" "b <addr> [cnt] set breakpoint at given instr addr\n" @@ -1193,7 +1194,7 @@ bpt_cmds(void) default: termch = cmd; - cmd = skipbl(); + cmd = skipbl(); if (cmd == '?') { printf(breakpoint_help_string); break; @@ -1359,7 +1360,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr, sp + REGS_OFFSET); break; } - printf("--- Exception: %lx %s at ", regs.trap, + printf("--- Exception: %lx %s at ", regs.trap, getvecname(TRAP(®s))); pc = regs.nip; lr = regs.link; @@ -1623,14 +1624,14 @@ static void super_regs(void) cmd = skipbl(); if (cmd == '\n') { - unsigned long sp, toc; + unsigned long sp, toc; asm("mr %0,1" : "=r" (sp) :); asm("mr %0,2" : "=r" (toc) :); printf("msr = "REG" sprg0= "REG"\n", mfmsr(), mfspr(SPRN_SPRG0)); printf("pvr = "REG" sprg1= "REG"\n", - mfspr(SPRN_PVR), mfspr(SPRN_SPRG1)); + mfspr(SPRN_PVR), mfspr(SPRN_SPRG1)); printf("dec = "REG" sprg2= "REG"\n", mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); @@ -1783,7 +1784,7 @@ byterev(unsigned char *val, int size) static int brev; static int mnoread; -static char *memex_help_string = +static char *memex_help_string = "Memory examine command usage:\n" "m [addr] [flags] examine/change memory\n" " addr is optional. will start where left off.\n" @@ -1798,7 +1799,7 @@ static char *memex_help_string = "NOTE: flags are saved as defaults\n" ""; -static char *memex_subcmd_help_string = +static char *memex_subcmd_help_string = "Memory examine subcommands:\n" " hexval write this val to current location\n" " 'string' write chars from string to this location\n" @@ -2064,7 +2065,7 @@ prdump(unsigned long adrs, long ndump) nr = mread(adrs, temp, r); adrs += nr; for (m = 0; m < r; ++m) { - if ((m & (sizeof(long) - 1)) == 0 && m > 0) + if ((m & (sizeof(long) - 1)) == 0 && m > 0) putchar(' '); if (m < nr) printf("%.2x", temp[m]); @@ -2072,7 +2073,7 @@ prdump(unsigned long adrs, long ndump) printf("%s", fault_chars[fault_type]); } for (; m < 16; ++m) { - if ((m & (sizeof(long) - 1)) == 0) + if ((m & (sizeof(long) - 1)) == 0) putchar(' '); printf(" "); } @@ -2148,45 +2149,28 @@ print_address(unsigned long addr) void dump_log_buf(void) { - const unsigned long size = 128; - unsigned long end, addr; - unsigned char buf[size + 1]; - - addr = 0; - buf[size] = '\0'; - - if (setjmp(bus_error_jmp) != 0) { - printf("Unable to lookup symbol __log_buf!\n"); - return; - } - - catch_memory_errors = 1; - sync(); - addr = kallsyms_lookup_name("__log_buf"); - - if (! addr) - printf("Symbol __log_buf not found!\n"); - else { - end = addr + (1 << CONFIG_LOG_BUF_SHIFT); - while (addr < end) { - if (! mread(addr, buf, size)) { - printf("Can't read memory at address 0x%lx\n", addr); - break; - } - - printf("%s", buf); - - if (strlen(buf) < size) - break; - - addr += size; - } - } - - sync(); - /* wait a little while to see if we get a machine check */ - __delay(200); - catch_memory_errors = 0; + struct kmsg_dumper dumper = { .active = 1 }; + unsigned char buf[128]; + size_t len; + + if (setjmp(bus_error_jmp) != 0) { + printf("Error dumping printk buffer!\n"); + return; + } + + catch_memory_errors = 1; + sync(); + + kmsg_dump_rewind_nolock(&dumper); + while (kmsg_dump_get_line_nolock(&dumper, false, buf, sizeof(buf), &len)) { + buf[len] = '\0'; + printf("%s", buf); + } + + sync(); + /* wait a little while to see if we get a machine check */ + __delay(200); + catch_memory_errors = 0; } /* diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 32e8449640fa..9b94a160fe7f 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h @@ -180,7 +180,8 @@ extern char elf_platform[]; #define ELF_PLATFORM (elf_platform) #ifndef CONFIG_64BIT -#define SET_PERSONALITY(ex) set_personality(PER_LINUX) +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX | (current->personality & (~PER_MASK))) #else /* CONFIG_64BIT */ #define SET_PERSONALITY(ex) \ do { \ diff --git a/arch/s390/include/asm/posix_types.h b/arch/s390/include/asm/posix_types.h index 7bcc14e395f0..bf2a2ad2f800 100644 --- a/arch/s390/include/asm/posix_types.h +++ b/arch/s390/include/asm/posix_types.h @@ -13,6 +13,7 @@ */ typedef unsigned long __kernel_size_t; +typedef long __kernel_ssize_t; #define __kernel_size_t __kernel_size_t typedef unsigned short __kernel_old_dev_t; @@ -25,7 +26,6 @@ typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_gid_t; -typedef int __kernel_ssize_t; typedef int __kernel_ptrdiff_t; #else /* __s390x__ */ @@ -35,7 +35,6 @@ typedef unsigned int __kernel_mode_t; typedef int __kernel_ipc_pid_t; typedef unsigned int __kernel_uid_t; typedef unsigned int __kernel_gid_t; -typedef long __kernel_ssize_t; typedef long __kernel_ptrdiff_t; typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index a0a8340daafa..ce26ac3cb162 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -44,6 +44,7 @@ static inline void smp_call_online_cpu(void (*func)(void *), void *data) } static inline int smp_find_processor_id(int address) { return 0; } +static inline int smp_store_status(int cpu) { return 0; } static inline int smp_vcpu_scheduled(int cpu) { return 1; } static inline void smp_yield_cpu(int cpu) { } static inline void smp_yield(void) { } diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h index b315a33867f2..33692eaabab5 100644 --- a/arch/x86/include/asm/spinlock.h +++ b/arch/x86/include/asm/spinlock.h @@ -12,8 +12,7 @@ * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. * - * These are fair FIFO ticket locks, which are currently limited to 256 - * CPUs. + * These are fair FIFO ticket locks, which support up to 2^16 CPUs. * * (the type definitions are in asm/spinlock_types.h) */ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index afb7ff79a29f..ced4534baed5 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -165,7 +165,7 @@ static const unsigned char * const k7_nops[ASM_NOP_MAX+2] = #endif #ifdef P6_NOP1 -static const unsigned char __initconst_or_module p6nops[] = +static const unsigned char p6nops[] = { P6_NOP1, P6_NOP2, diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 7ad683d78645..d44f7829968e 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -270,7 +270,7 @@ void fixup_irqs(void) if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { break_affinity = 1; - affinity = cpu_all_mask; + affinity = cpu_online_mask; } chip = irq_data_get_irq_chip(data); diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 8a2ce8fd41c0..82746f942cd8 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -143,11 +143,12 @@ static int get_matching_microcode(int cpu, const u8 *ucode_ptr, unsigned int *current_size) { struct microcode_header_amd *mc_hdr; - unsigned int actual_size; + unsigned int actual_size, patch_size; u16 equiv_cpu_id; /* size of the current patch we're staring at */ - *current_size = *(u32 *)(ucode_ptr + 4) + SECTION_HDR_SIZE; + patch_size = *(u32 *)(ucode_ptr + 4); + *current_size = patch_size + SECTION_HDR_SIZE; equiv_cpu_id = find_equiv_id(); if (!equiv_cpu_id) @@ -174,7 +175,7 @@ static int get_matching_microcode(int cpu, const u8 *ucode_ptr, /* * now that the header looks sane, verify its size */ - actual_size = verify_ucode_size(cpu, *current_size, leftover_size); + actual_size = verify_ucode_size(cpu, patch_size, leftover_size); if (!actual_size) return 0; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 97d9a9914ba8..a3b57a27be88 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -475,13 +475,26 @@ register_address(struct x86_emulate_ctxt *ctxt, unsigned long reg) return address_mask(ctxt, reg); } +static void masked_increment(ulong *reg, ulong mask, int inc) +{ + assign_masked(reg, *reg + inc, mask); +} + static inline void register_address_increment(struct x86_emulate_ctxt *ctxt, unsigned long *reg, int inc) { + ulong mask; + if (ctxt->ad_bytes == sizeof(unsigned long)) - *reg += inc; + mask = ~0UL; else - *reg = (*reg & ~ad_mask(ctxt)) | ((*reg + inc) & ad_mask(ctxt)); + mask = ad_mask(ctxt); + masked_increment(reg, mask, inc); +} + +static void rsp_increment(struct x86_emulate_ctxt *ctxt, int inc) +{ + masked_increment(&ctxt->regs[VCPU_REGS_RSP], stack_mask(ctxt), inc); } static inline void jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) @@ -1522,8 +1535,8 @@ static int push(struct x86_emulate_ctxt *ctxt, void *data, int bytes) { struct segmented_address addr; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], -bytes); - addr.ea = register_address(ctxt, ctxt->regs[VCPU_REGS_RSP]); + rsp_increment(ctxt, -bytes); + addr.ea = ctxt->regs[VCPU_REGS_RSP] & stack_mask(ctxt); addr.seg = VCPU_SREG_SS; return segmented_write(ctxt, addr, data, bytes); @@ -1542,13 +1555,13 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt, int rc; struct segmented_address addr; - addr.ea = register_address(ctxt, ctxt->regs[VCPU_REGS_RSP]); + addr.ea = ctxt->regs[VCPU_REGS_RSP] & stack_mask(ctxt); addr.seg = VCPU_SREG_SS; rc = segmented_read(ctxt, addr, dest, len); if (rc != X86EMUL_CONTINUE) return rc; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], len); + rsp_increment(ctxt, len); return rc; } @@ -1688,8 +1701,7 @@ static int em_popa(struct x86_emulate_ctxt *ctxt) while (reg >= VCPU_REGS_RAX) { if (reg == VCPU_REGS_RSP) { - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], - ctxt->op_bytes); + rsp_increment(ctxt, ctxt->op_bytes); --reg; } @@ -2825,7 +2837,7 @@ static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) rc = emulate_pop(ctxt, &ctxt->dst.val, ctxt->op_bytes); if (rc != X86EMUL_CONTINUE) return rc; - register_address_increment(ctxt, &ctxt->regs[VCPU_REGS_RSP], ctxt->src.val); + rsp_increment(ctxt, ctxt->src.val); return X86EMUL_CONTINUE; } diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 01ca00423938..7fbd0d273ea8 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -4113,16 +4113,21 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc) LIST_HEAD(invalid_list); /* + * Never scan more than sc->nr_to_scan VM instances. + * Will not hit this condition practically since we do not try + * to shrink more than one VM and it is very unlikely to see + * !n_used_mmu_pages so many times. + */ + if (!nr_to_scan--) + break; + /* * n_used_mmu_pages is accessed without holding kvm->mmu_lock * here. We may skip a VM instance errorneosly, but we do not * want to shrink a VM that only started to populate its MMU * anyway. */ - if (kvm->arch.n_used_mmu_pages > 0) { - if (!nr_to_scan--) - break; + if (!kvm->arch.n_used_mmu_pages) continue; - } idx = srcu_read_lock(&kvm->srcu); spin_lock(&kvm->mmu_lock); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 42bce48f6928..148ed666e311 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -806,7 +806,7 @@ EXPORT_SYMBOL_GPL(kvm_rdpmc); * kvm-specific. Those are put in the beginning of the list. */ -#define KVM_SAVE_MSRS_BEGIN 9 +#define KVM_SAVE_MSRS_BEGIN 10 static u32 msrs_to_save[] = { MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW, @@ -2000,6 +2000,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) case MSR_KVM_STEAL_TIME: data = vcpu->arch.st.msr_val; break; + case MSR_KVM_PV_EOI_EN: + data = vcpu->arch.pv_eoi.msr_val; + break; case MSR_IA32_P5_MC_ADDR: case MSR_IA32_P5_MC_TYPE: case MSR_IA32_MCG_CAP: diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bf4bda6d3e9a..9642d4a38602 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -31,7 +31,6 @@ #include <linux/pci.h> #include <linux/gfp.h> #include <linux/memblock.h> -#include <linux/syscore_ops.h> #include <xen/xen.h> #include <xen/interface/xen.h> @@ -1470,130 +1469,38 @@ asmlinkage void __init xen_start_kernel(void) #endif } -#ifdef CONFIG_XEN_PVHVM -/* - * The pfn containing the shared_info is located somewhere in RAM. This - * will cause trouble if the current kernel is doing a kexec boot into a - * new kernel. The new kernel (and its startup code) can not know where - * the pfn is, so it can not reserve the page. The hypervisor will - * continue to update the pfn, and as a result memory corruption occours - * in the new kernel. - * - * One way to work around this issue is to allocate a page in the - * xen-platform pci device's BAR memory range. But pci init is done very - * late and the shared_info page is already in use very early to read - * the pvclock. So moving the pfn from RAM to MMIO is racy because some - * code paths on other vcpus could access the pfn during the small - * window when the old pfn is moved to the new pfn. There is even a - * small window were the old pfn is not backed by a mfn, and during that - * time all reads return -1. - * - * Because it is not known upfront where the MMIO region is located it - * can not be used right from the start in xen_hvm_init_shared_info. - * - * To minimise trouble the move of the pfn is done shortly before kexec. - * This does not eliminate the race because all vcpus are still online - * when the syscore_ops will be called. But hopefully there is no work - * pending at this point in time. Also the syscore_op is run last which - * reduces the risk further. - */ - -static struct shared_info *xen_hvm_shared_info; - -static void xen_hvm_connect_shared_info(unsigned long pfn) +void __ref xen_hvm_init_shared_info(void) { + int cpu; struct xen_add_to_physmap xatp; + static struct shared_info *shared_info_page = 0; + if (!shared_info_page) + shared_info_page = (struct shared_info *) + extend_brk(PAGE_SIZE, PAGE_SIZE); xatp.domid = DOMID_SELF; xatp.idx = 0; xatp.space = XENMAPSPACE_shared_info; - xatp.gpfn = pfn; + xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT; if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) BUG(); -} -static void xen_hvm_set_shared_info(struct shared_info *sip) -{ - int cpu; - - HYPERVISOR_shared_info = sip; + HYPERVISOR_shared_info = (struct shared_info *)shared_info_page; /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info * page, we use it in the event channel upcall and in some pvclock * related functions. We don't need the vcpu_info placement * optimizations because we don't use any pv_mmu or pv_irq op on * HVM. - * When xen_hvm_set_shared_info is run at boot time only vcpu 0 is - * online but xen_hvm_set_shared_info is run at resume time too and + * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is + * online but xen_hvm_init_shared_info is run at resume time too and * in that case multiple vcpus might be online. */ for_each_online_cpu(cpu) { per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; } } -/* Reconnect the shared_info pfn to a mfn */ -void xen_hvm_resume_shared_info(void) -{ - xen_hvm_connect_shared_info(__pa(xen_hvm_shared_info) >> PAGE_SHIFT); -} - -#ifdef CONFIG_KEXEC -static struct shared_info *xen_hvm_shared_info_kexec; -static unsigned long xen_hvm_shared_info_pfn_kexec; - -/* Remember a pfn in MMIO space for kexec reboot */ -void __devinit xen_hvm_prepare_kexec(struct shared_info *sip, unsigned long pfn) -{ - xen_hvm_shared_info_kexec = sip; - xen_hvm_shared_info_pfn_kexec = pfn; -} - -static void xen_hvm_syscore_shutdown(void) -{ - struct xen_memory_reservation reservation = { - .domid = DOMID_SELF, - .nr_extents = 1, - }; - unsigned long prev_pfn; - int rc; - - if (!xen_hvm_shared_info_kexec) - return; - - prev_pfn = __pa(xen_hvm_shared_info) >> PAGE_SHIFT; - set_xen_guest_handle(reservation.extent_start, &prev_pfn); - - /* Move pfn to MMIO, disconnects previous pfn from mfn */ - xen_hvm_connect_shared_info(xen_hvm_shared_info_pfn_kexec); - - /* Update pointers, following hypercall is also a memory barrier */ - xen_hvm_set_shared_info(xen_hvm_shared_info_kexec); - - /* Allocate new mfn for previous pfn */ - do { - rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation); - if (rc == 0) - msleep(123); - } while (rc == 0); - - /* Make sure the previous pfn is really connected to a (new) mfn */ - BUG_ON(rc != 1); -} - -static struct syscore_ops xen_hvm_syscore_ops = { - .shutdown = xen_hvm_syscore_shutdown, -}; -#endif - -/* Use a pfn in RAM, may move to MMIO before kexec. */ -static void __init xen_hvm_init_shared_info(void) -{ - /* Remember pointer for resume */ - xen_hvm_shared_info = extend_brk(PAGE_SIZE, PAGE_SIZE); - xen_hvm_connect_shared_info(__pa(xen_hvm_shared_info) >> PAGE_SHIFT); - xen_hvm_set_shared_info(xen_hvm_shared_info); -} - +#ifdef CONFIG_XEN_PVHVM static void __init init_hvm_pv_info(void) { int major, minor; @@ -1644,9 +1551,6 @@ static void __init xen_hvm_guest_init(void) init_hvm_pv_info(); xen_hvm_init_shared_info(); -#ifdef CONFIG_KEXEC - register_syscore_ops(&xen_hvm_syscore_ops); -#endif if (xen_feature(XENFEAT_hvm_callback_vector)) xen_have_vector_callback = 1; diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index b2e91d40a4cb..d4b255463253 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -196,9 +196,11 @@ RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3); /* When we populate back during bootup, the amount of pages can vary. The * max we have is seen is 395979, but that does not mean it can't be more. - * But some machines can have 3GB I/O holes even. So lets reserve enough - * for 4GB of I/O and E820 holes. */ -RESERVE_BRK(p2m_populated, PMD_SIZE * 4); + * Some machines can have 3GB I/O holes even. With early_can_reuse_p2m_middle + * it can re-use Xen provided mfn_list array, so we only need to allocate at + * most three P2M top nodes. */ +RESERVE_BRK(p2m_populated, PAGE_SIZE * 3); + static inline unsigned p2m_top_index(unsigned long pfn) { BUG_ON(pfn >= MAX_P2M_PFN); @@ -575,12 +577,99 @@ static bool __init early_alloc_p2m(unsigned long pfn) } return true; } + +/* + * Skim over the P2M tree looking at pages that are either filled with + * INVALID_P2M_ENTRY or with 1:1 PFNs. If found, re-use that page and + * replace the P2M leaf with a p2m_missing or p2m_identity. + * Stick the old page in the new P2M tree location. + */ +bool __init early_can_reuse_p2m_middle(unsigned long set_pfn, unsigned long set_mfn) +{ + unsigned topidx; + unsigned mididx; + unsigned ident_pfns; + unsigned inv_pfns; + unsigned long *p2m; + unsigned long *mid_mfn_p; + unsigned idx; + unsigned long pfn; + + /* We only look when this entails a P2M middle layer */ + if (p2m_index(set_pfn)) + return false; + + for (pfn = 0; pfn <= MAX_DOMAIN_PAGES; pfn += P2M_PER_PAGE) { + topidx = p2m_top_index(pfn); + + if (!p2m_top[topidx]) + continue; + + if (p2m_top[topidx] == p2m_mid_missing) + continue; + + mididx = p2m_mid_index(pfn); + p2m = p2m_top[topidx][mididx]; + if (!p2m) + continue; + + if ((p2m == p2m_missing) || (p2m == p2m_identity)) + continue; + + if ((unsigned long)p2m == INVALID_P2M_ENTRY) + continue; + + ident_pfns = 0; + inv_pfns = 0; + for (idx = 0; idx < P2M_PER_PAGE; idx++) { + /* IDENTITY_PFNs are 1:1 */ + if (p2m[idx] == IDENTITY_FRAME(pfn + idx)) + ident_pfns++; + else if (p2m[idx] == INVALID_P2M_ENTRY) + inv_pfns++; + else + break; + } + if ((ident_pfns == P2M_PER_PAGE) || (inv_pfns == P2M_PER_PAGE)) + goto found; + } + return false; +found: + /* Found one, replace old with p2m_identity or p2m_missing */ + p2m_top[topidx][mididx] = (ident_pfns ? p2m_identity : p2m_missing); + /* And the other for save/restore.. */ + mid_mfn_p = p2m_top_mfn_p[topidx]; + /* NOTE: Even if it is a p2m_identity it should still be point to + * a page filled with INVALID_P2M_ENTRY entries. */ + mid_mfn_p[mididx] = virt_to_mfn(p2m_missing); + + /* Reset where we want to stick the old page in. */ + topidx = p2m_top_index(set_pfn); + mididx = p2m_mid_index(set_pfn); + + /* This shouldn't happen */ + if (WARN_ON(p2m_top[topidx] == p2m_mid_missing)) + early_alloc_p2m(set_pfn); + + if (WARN_ON(p2m_top[topidx][mididx] != p2m_missing)) + return false; + + p2m_init(p2m); + p2m_top[topidx][mididx] = p2m; + mid_mfn_p = p2m_top_mfn_p[topidx]; + mid_mfn_p[mididx] = virt_to_mfn(p2m); + + return true; +} bool __init early_set_phys_to_machine(unsigned long pfn, unsigned long mfn) { if (unlikely(!__set_phys_to_machine(pfn, mfn))) { if (!early_alloc_p2m(pfn)) return false; + if (early_can_reuse_p2m_middle(pfn, mfn)) + return __set_phys_to_machine(pfn, mfn); + if (!early_alloc_p2m_middle(pfn, false /* boundary crossover OK!*/)) return false; diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index ead85576d54a..d11ca11d14fc 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -78,9 +78,16 @@ static void __init xen_add_extra_mem(u64 start, u64 size) memblock_reserve(start, size); xen_max_p2m_pfn = PFN_DOWN(start + size); + for (pfn = PFN_DOWN(start); pfn < xen_max_p2m_pfn; pfn++) { + unsigned long mfn = pfn_to_mfn(pfn); + + if (WARN(mfn == pfn, "Trying to over-write 1-1 mapping (pfn: %lx)\n", pfn)) + continue; + WARN(mfn != INVALID_P2M_ENTRY, "Trying to remove %lx which has %lx mfn!\n", + pfn, mfn); - for (pfn = PFN_DOWN(start); pfn <= xen_max_p2m_pfn; pfn++) __set_phys_to_machine(pfn, INVALID_P2M_ENTRY); + } } static unsigned long __init xen_do_chunk(unsigned long start, diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index ae8a00c39de4..45329c8c226e 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -30,7 +30,7 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled) { #ifdef CONFIG_XEN_PVHVM int cpu; - xen_hvm_resume_shared_info(); + xen_hvm_init_shared_info(); xen_callback_vector(); xen_unplug_emulated_devices(); if (xen_feature(XENFEAT_hvm_safe_pvclock)) { diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index 1e4329e04e0f..202d4c150154 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -41,7 +41,7 @@ void xen_enable_syscall(void); void xen_vcpu_restore(void); void xen_callback_vector(void); -void xen_hvm_resume_shared_info(void); +void xen_hvm_init_shared_info(void); void xen_unplug_emulated_devices(void); void __init xen_build_dynamic_phys_to_machine(void); diff --git a/block/blk-lib.c b/block/blk-lib.c index 2b461b496a78..19cc761cacb2 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -44,6 +44,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, struct request_queue *q = bdev_get_queue(bdev); int type = REQ_WRITE | REQ_DISCARD; unsigned int max_discard_sectors; + unsigned int granularity, alignment, mask; struct bio_batch bb; struct bio *bio; int ret = 0; @@ -54,18 +55,20 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, if (!blk_queue_discard(q)) return -EOPNOTSUPP; + /* Zero-sector (unknown) and one-sector granularities are the same. */ + granularity = max(q->limits.discard_granularity >> 9, 1U); + mask = granularity - 1; + alignment = (bdev_discard_alignment(bdev) >> 9) & mask; + /* * Ensure that max_discard_sectors is of the proper - * granularity + * granularity, so that requests stay aligned after a split. */ max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9); + max_discard_sectors = round_down(max_discard_sectors, granularity); if (unlikely(!max_discard_sectors)) { /* Avoid infinite loop below. Being cautious never hurts. */ return -EOPNOTSUPP; - } else if (q->limits.discard_granularity) { - unsigned int disc_sects = q->limits.discard_granularity >> 9; - - max_discard_sectors &= ~(disc_sects - 1); } if (flags & BLKDEV_DISCARD_SECURE) { @@ -79,25 +82,37 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, bb.wait = &wait; while (nr_sects) { + unsigned int req_sects; + sector_t end_sect; + bio = bio_alloc(gfp_mask, 1); if (!bio) { ret = -ENOMEM; break; } + req_sects = min_t(sector_t, nr_sects, max_discard_sectors); + + /* + * If splitting a request, and the next starting sector would be + * misaligned, stop the discard at the previous aligned sector. + */ + end_sect = sector + req_sects; + if (req_sects < nr_sects && (end_sect & mask) != alignment) { + end_sect = + round_down(end_sect - alignment, granularity) + + alignment; + req_sects = end_sect - sector; + } + bio->bi_sector = sector; bio->bi_end_io = bio_batch_end_io; bio->bi_bdev = bdev; bio->bi_private = &bb; - if (nr_sects > max_discard_sectors) { - bio->bi_size = max_discard_sectors << 9; - nr_sects -= max_discard_sectors; - sector += max_discard_sectors; - } else { - bio->bi_size = nr_sects << 9; - nr_sects = 0; - } + bio->bi_size = req_sects << 9; + nr_sects -= req_sects; + sector = end_sect; atomic_inc(&bb.done); submit_bio(type, bio); diff --git a/block/blk-merge.c b/block/blk-merge.c index 160035f54882..e76279e41162 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -110,6 +110,49 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, return 0; } +static void +__blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec, + struct scatterlist *sglist, struct bio_vec **bvprv, + struct scatterlist **sg, int *nsegs, int *cluster) +{ + + int nbytes = bvec->bv_len; + + if (*bvprv && *cluster) { + if ((*sg)->length + nbytes > queue_max_segment_size(q)) + goto new_segment; + + if (!BIOVEC_PHYS_MERGEABLE(*bvprv, bvec)) + goto new_segment; + if (!BIOVEC_SEG_BOUNDARY(q, *bvprv, bvec)) + goto new_segment; + + (*sg)->length += nbytes; + } else { +new_segment: + if (!*sg) + *sg = sglist; + else { + /* + * If the driver previously mapped a shorter + * list, we could see a termination bit + * prematurely unless it fully inits the sg + * table on each mapping. We KNOW that there + * must be more entries here or the driver + * would be buggy, so force clear the + * termination bit to avoid doing a full + * sg_init_table() in drivers for each command. + */ + (*sg)->page_link &= ~0x02; + *sg = sg_next(*sg); + } + + sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset); + (*nsegs)++; + } + *bvprv = bvec; +} + /* * map a request to scatterlist, return number of sg entries setup. Caller * must make sure sg can hold rq->nr_phys_segments entries @@ -131,41 +174,8 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, bvprv = NULL; sg = NULL; rq_for_each_segment(bvec, rq, iter) { - int nbytes = bvec->bv_len; - - if (bvprv && cluster) { - if (sg->length + nbytes > queue_max_segment_size(q)) - goto new_segment; - - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) - goto new_segment; - - sg->length += nbytes; - } else { -new_segment: - if (!sg) - sg = sglist; - else { - /* - * If the driver previously mapped a shorter - * list, we could see a termination bit - * prematurely unless it fully inits the sg - * table on each mapping. We KNOW that there - * must be more entries here or the driver - * would be buggy, so force clear the - * termination bit to avoid doing a full - * sg_init_table() in drivers for each command. - */ - sg->page_link &= ~0x02; - sg = sg_next(sg); - } - - sg_set_page(sg, bvec->bv_page, nbytes, bvec->bv_offset); - nsegs++; - } - bvprv = bvec; + __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg, + &nsegs, &cluster); } /* segments in rq */ @@ -199,6 +209,43 @@ new_segment: } EXPORT_SYMBOL(blk_rq_map_sg); +/** + * blk_bio_map_sg - map a bio to a scatterlist + * @q: request_queue in question + * @bio: bio being mapped + * @sglist: scatterlist being mapped + * + * Note: + * Caller must make sure sg can hold bio->bi_phys_segments entries + * + * Will return the number of sg entries setup + */ +int blk_bio_map_sg(struct request_queue *q, struct bio *bio, + struct scatterlist *sglist) +{ + struct bio_vec *bvec, *bvprv; + struct scatterlist *sg; + int nsegs, cluster; + unsigned long i; + + nsegs = 0; + cluster = blk_queue_cluster(q); + + bvprv = NULL; + sg = NULL; + bio_for_each_segment(bvec, bio, i) { + __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg, + &nsegs, &cluster); + } /* segments in bio */ + + if (sg) + sg_mark_end(sg); + + BUG_ON(bio->bi_phys_segments && nsegs > bio->bi_phys_segments); + return nsegs; +} +EXPORT_SYMBOL(blk_bio_map_sg); + static inline int ll_new_hw_segment(struct request_queue *q, struct request *req, struct bio *bio) diff --git a/block/genhd.c b/block/genhd.c index cac7366957c3..d839723303c8 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -835,7 +835,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v) static void *show_partition_start(struct seq_file *seqf, loff_t *pos) { - static void *p; + void *p; p = disk_seqf_start(seqf, pos); if (!IS_ERR_OR_NULL(p) && !*pos) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2be8ef1d3093..27cecd313e75 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -115,7 +115,7 @@ config SATA_SIL24 If unsure, say N. config ATA_SFF - bool "ATA SFF support" + bool "ATA SFF support (for legacy IDE and PATA)" default y help This option adds support for ATA controllers with SFF diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 062e6a1a248f..50d5dea0ff59 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -256,6 +256,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x8c07), board_ahci }, /* Lynx Point RAID */ { PCI_VDEVICE(INTEL, 0x8c0e), board_ahci }, /* Lynx Point RAID */ { PCI_VDEVICE(INTEL, 0x8c0f), board_ahci }, /* Lynx Point RAID */ + { PCI_VDEVICE(INTEL, 0x9c02), board_ahci }, /* Lynx Point-LP AHCI */ + { PCI_VDEVICE(INTEL, 0x9c03), board_ahci }, /* Lynx Point-LP AHCI */ + { PCI_VDEVICE(INTEL, 0x9c04), board_ahci }, /* Lynx Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c05), board_ahci }, /* Lynx Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c06), board_ahci }, /* Lynx Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c07), board_ahci }, /* Lynx Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c0e), board_ahci }, /* Lynx Point-LP RAID */ + { PCI_VDEVICE(INTEL, 0x9c0f), board_ahci }, /* Lynx Point-LP RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index c2594ddf25b0..57eb1c212a4c 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -320,6 +320,7 @@ extern struct device_attribute *ahci_sdev_attrs[]; extern struct ata_port_operations ahci_ops; extern struct ata_port_operations ahci_pmp_retry_srst_ops; +unsigned int ahci_dev_classify(struct ata_port *ap); void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, u32 opts); void ahci_save_initial_config(struct device *dev, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 3c809bfbccf5..ef773e12af79 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -329,6 +329,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (Lynx Point) */ { 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Lynx Point-LP) */ + { 0x8086, 0x9c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Lynx Point-LP) */ + { 0x8086, 0x9c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Lynx Point-LP) */ + { 0x8086, 0x9c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Lynx Point-LP) */ + { 0x8086, 0x9c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (DH89xxCC) */ { 0x8086, 0x2326, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index f9eaa82311a9..555c07afa05b 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1139,7 +1139,7 @@ static void ahci_dev_config(struct ata_device *dev) } } -static unsigned int ahci_dev_classify(struct ata_port *ap) +unsigned int ahci_dev_classify(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); struct ata_taskfile tf; @@ -1153,6 +1153,7 @@ static unsigned int ahci_dev_classify(struct ata_port *ap) return ata_dev_classify(&tf); } +EXPORT_SYMBOL_GPL(ahci_dev_classify); void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, u32 opts) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 902b5a457170..fd9ecf74e631 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -60,17 +60,7 @@ acpi_handle ata_ap_acpi_handle(struct ata_port *ap) if (ap->flags & ATA_FLAG_ACPI_SATA) return NULL; - /* - * If acpi bind operation has already happened, we can get the handle - * for the port by checking the corresponding scsi_host device's - * firmware node, otherwise we will need to find out the handle from - * its parent's acpi node. - */ - if (ap->scsi_host) - return DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev); - else - return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), - ap->port_no); + return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), ap->port_no); } EXPORT_SYMBOL(ata_ap_acpi_handle); @@ -1101,6 +1091,9 @@ static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle) if (!*handle) return -ENODEV; + if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) + ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; + return 0; } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fadd5866d40f..8e1039c8e159 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4062,7 +4062,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA }, { "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA }, { "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA }, - { "2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA }, + { " 2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA }, /* Odd clown on sil3726/4726 PMPs */ { "Config Disk", NULL, ATA_HORKAGE_DISABLE }, @@ -4128,6 +4128,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices that do not need bridging limits applied */ { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, }, + { "BUFFALO HD-QSU2/R5", NULL, ATA_HORKAGE_BRIDGE_OK, }, /* Devices which aren't very happy with higher link speeds */ { "WD My Book", NULL, ATA_HORKAGE_1_5_GBPS, }, diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 361c75cea57b..24e51056ac26 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -20,6 +20,7 @@ #include <linux/delay.h> #include <scsi/scsi_host.h> #include <linux/libata.h> +#include <linux/dmi.h> #define DRV_NAME "pata_atiixp" #define DRV_VERSION "0.4.6" @@ -33,11 +34,26 @@ enum { ATIIXP_IDE_UDMA_MODE = 0x56 }; +static const struct dmi_system_id attixp_cable_override_dmi_table[] = { + { + /* Board has onboard PATA<->SATA converters */ + .ident = "MSI E350DM-E33", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), + DMI_MATCH(DMI_BOARD_NAME, "E350DM-E33(MS-7720)"), + }, + }, + { } +}; + static int atiixp_cable_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); u8 udma; + if (dmi_check_system(attixp_cable_override_dmi_table)) + return ATA_CBL_PATA40_SHORT; + /* Hack from drivers/ide/pci. Really we want to know how to do the raw detection not play follow the bios mode guess */ pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma); diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index ba91b408abad..d84566496746 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -889,6 +889,7 @@ struct bm_aio_ctx { unsigned int done; unsigned flags; #define BM_AIO_COPY_PAGES 1 +#define BM_WRITE_ALL_PAGES 2 int error; struct kref kref; }; @@ -1059,7 +1060,8 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx) break; if (rw & WRITE) { - if (bm_test_page_unchanged(b->bm_pages[i])) { + if (!(flags & BM_WRITE_ALL_PAGES) && + bm_test_page_unchanged(b->bm_pages[i])) { dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i); continue; } @@ -1141,6 +1143,17 @@ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) } /** + * drbd_bm_write_all() - Write the whole bitmap to its on disk location. + * @mdev: DRBD device. + * + * Will write all pages. + */ +int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local) +{ + return bm_rw(mdev, WRITE, BM_WRITE_ALL_PAGES, 0); +} + +/** * drbd_bm_lazy_write_out() - Write bitmap pages 0 to @upper_idx-1, if they have changed. * @mdev: DRBD device. * @upper_idx: 0: write all changed pages; +ve: page index to stop scanning for changed pages diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index b2ca143d0053..b953cc7c9c00 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1469,6 +1469,7 @@ extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr); extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local); extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local); extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local); +extern int drbd_bm_write_all(struct drbd_conf *mdev) __must_hold(local); extern int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local); extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index dbe6135a2abe..f93a0320e952 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -79,6 +79,7 @@ static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused); static void md_sync_timer_fn(unsigned long data); static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused); static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused); +static void _tl_clear(struct drbd_conf *mdev); MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, " "Lars Ellenberg <lars@linbit.com>"); @@ -432,19 +433,10 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) /* Actions operating on the disk state, also want to work on requests that got barrier acked. */ - switch (what) { - case fail_frozen_disk_io: - case restart_frozen_disk_io: - list_for_each_safe(le, tle, &mdev->barrier_acked_requests) { - req = list_entry(le, struct drbd_request, tl_requests); - _req_mod(req, what); - } - case connection_lost_while_pending: - case resend: - break; - default: - dev_err(DEV, "what = %d in _tl_restart()\n", what); + list_for_each_safe(le, tle, &mdev->barrier_acked_requests) { + req = list_entry(le, struct drbd_request, tl_requests); + _req_mod(req, what); } } @@ -459,11 +451,16 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) */ void tl_clear(struct drbd_conf *mdev) { + spin_lock_irq(&mdev->req_lock); + _tl_clear(mdev); + spin_unlock_irq(&mdev->req_lock); +} + +static void _tl_clear(struct drbd_conf *mdev) +{ struct list_head *le, *tle; struct drbd_request *r; - spin_lock_irq(&mdev->req_lock); - _tl_restart(mdev, connection_lost_while_pending); /* we expect this list to be empty. */ @@ -482,7 +479,6 @@ void tl_clear(struct drbd_conf *mdev) memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *)); - spin_unlock_irq(&mdev->req_lock); } void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) @@ -1476,12 +1472,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (ns.susp_fen) { /* case1: The outdate peer handler is successful: */ if (os.pdsk > D_OUTDATED && ns.pdsk <= D_OUTDATED) { - tl_clear(mdev); if (test_bit(NEW_CUR_UUID, &mdev->flags)) { drbd_uuid_new_current(mdev); clear_bit(NEW_CUR_UUID, &mdev->flags); } spin_lock_irq(&mdev->req_lock); + _tl_clear(mdev); _drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL); spin_unlock_irq(&mdev->req_lock); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index fb9dce8daa24..edb490aad8b4 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -674,8 +674,8 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds la_size_changed && md_moved ? "size changed and md moved" : la_size_changed ? "size changed" : "md moved"); /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */ - err = drbd_bitmap_io(mdev, &drbd_bm_write, - "size changed", BM_LOCKED_MASK); + err = drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write, + "size changed", BM_LOCKED_MASK); if (err) { rv = dev_size_error; goto out; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 910335c30927..01b2ac641c7b 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -695,6 +695,12 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, break; case resend: + /* Simply complete (local only) READs. */ + if (!(req->rq_state & RQ_WRITE) && !req->w.cb) { + _req_may_be_done(req, m); + break; + } + /* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK before the connection loss (B&C only); only P_BARRIER_ACK was missing. Trowing them out of the TL here by pretending we got a BARRIER_ACK @@ -834,7 +840,15 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns req->private_bio = NULL; } if (rw == WRITE) { - remote = 1; + /* Need to replicate writes. Unless it is an empty flush, + * which is better mapped to a DRBD P_BARRIER packet, + * also for drbd wire protocol compatibility reasons. */ + if (unlikely(size == 0)) { + /* The only size==0 bios we expect are empty flushes. */ + D_ASSERT(bio->bi_rw & REQ_FLUSH); + remote = 0; + } else + remote = 1; } else { /* READ || READA */ if (local) { @@ -870,8 +884,11 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns * extent. This waits for any resync activity in the corresponding * resync extent to finish, and, if necessary, pulls in the target * extent into the activity log, which involves further disk io because - * of transactional on-disk meta data updates. */ - if (rw == WRITE && local && !test_bit(AL_SUSPENDED, &mdev->flags)) { + * of transactional on-disk meta data updates. + * Empty flushes don't need to go into the activity log, they can only + * flush data for pending writes which are already in there. */ + if (rw == WRITE && local && size + && !test_bit(AL_SUSPENDED, &mdev->flags)) { req->rq_state |= RQ_IN_ACT_LOG; drbd_al_begin_io(mdev, sector); } @@ -994,7 +1011,10 @@ allocate_barrier: if (rw == WRITE && _req_conflicts(req)) goto fail_conflicting; - list_add_tail(&req->tl_requests, &mdev->newest_tle->requests); + /* no point in adding empty flushes to the transfer log, + * they are mapped to drbd barriers already. */ + if (likely(size!=0)) + list_add_tail(&req->tl_requests, &mdev->newest_tle->requests); /* NOTE remote first: to get the concurrent write detection right, * we must register the request before start of local IO. */ @@ -1014,6 +1034,14 @@ allocate_barrier: mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) maybe_pull_ahead(mdev); + /* If this was a flush, queue a drbd barrier/start a new epoch. + * Unless the current epoch was empty anyways, or we are not currently + * replicating, in which case there is no point. */ + if (unlikely(bio->bi_rw & REQ_FLUSH) + && mdev->newest_tle->n_writes + && drbd_should_do_remote(mdev->state)) + queue_barrier(mdev); + spin_unlock_irq(&mdev->req_lock); kfree(b); /* if someone else has beaten us to it... */ diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 17fa04d08be9..b47034e650a5 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -218,7 +218,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); - if (atomic_inc_return(&freq_table_users) == 1) + if (!freq_table) result = opp_init_cpufreq_table(mpu_dev, &freq_table); if (result) { @@ -227,6 +227,8 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) goto fail_ck; } + atomic_inc_return(&freq_table_users); + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); if (result) goto fail_table; diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 53c8c51d5881..93d14070141a 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -63,7 +63,7 @@ static void caam_jr_dequeue(unsigned long devarg) head = ACCESS_ONCE(jrp->head); - spin_lock_bh(&jrp->outlock); + spin_lock(&jrp->outlock); sw_idx = tail = jrp->tail; hw_idx = jrp->out_ring_read_index; @@ -115,7 +115,7 @@ static void caam_jr_dequeue(unsigned long devarg) jrp->tail = tail; } - spin_unlock_bh(&jrp->outlock); + spin_unlock(&jrp->outlock); /* Finally, execute user's callback */ usercall(dev, userdesc, userstatus, userarg); @@ -236,14 +236,14 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, return -EIO; } - spin_lock(&jrp->inplock); + spin_lock_bh(&jrp->inplock); head = jrp->head; tail = ACCESS_ONCE(jrp->tail); if (!rd_reg32(&jrp->rregs->inpring_avail) || CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) { - spin_unlock(&jrp->inplock); + spin_unlock_bh(&jrp->inplock); dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE); return -EBUSY; } @@ -265,7 +265,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, wr_reg32(&jrp->rregs->inpring_jobadd, 1); - spin_unlock(&jrp->inplock); + spin_unlock_bh(&jrp->inplock); return 0; } diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index c9c4befb5a8d..df14358d7fa1 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -821,8 +821,8 @@ static int hifn_register_rng(struct hifn_device *dev) /* * We must wait at least 256 Pk_clk cycles between two reads of the rng. */ - dev->rng_wait_time = DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) * - 256; + dev->rng_wait_time = DIV_ROUND_UP_ULL(NSEC_PER_SEC, + dev->pk_clk_freq) * 256; dev->rng.name = dev->name; dev->rng.data_present = hifn_rng_data_present, diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 08a7aa722d6b..6fbfc244748f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1981,7 +1981,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; - if (!req->flags) + if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) return -EINVAL; mutex_lock(&dev->mode_config.mutex); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a8743c399e83..b7ee230572b7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -87,6 +87,9 @@ static struct edid_quirk { int product_id; u32 quirks; } edid_quirk_list[] = { + /* ASUS VW222S */ + { "ACI", 0x22a2, EDID_QUIRK_FORCE_REDUCED_BLANKING }, + /* Acer AL1706 */ { "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 }, /* Acer F51 */ diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index 30dc22a7156c..8033526bb53b 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -1362,6 +1362,9 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe, (struct drm_connector **) (psb_intel_crtc + 1); psb_intel_crtc->mode_set.num_connectors = 0; psb_intel_cursor_init(dev, psb_intel_crtc); + + /* Set to true so that the pipe is forced off on initial config. */ + psb_intel_crtc->active = true; } int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d9a5372ec56f..60815b861ec2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -72,7 +72,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 * entries. For aliasing ppgtt support we just steal them at the end for * now. */ - first_pd_entry_in_global_pt = 512*1024 - I915_PPGTT_PD_ENTRIES; + first_pd_entry_in_global_pt = dev_priv->mm.gtt->gtt_total_entries - I915_PPGTT_PD_ENTRIES; ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); if (!ppgtt) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a69a3d0d3acf..2dfa6cf4886b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1384,7 +1384,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - WARN(hdmi_pipe_enabled(dev_priv, val, pipe), + WARN(hdmi_pipe_enabled(dev_priv, pipe, val), "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); @@ -1404,13 +1404,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, reg = PCH_ADPA; val = I915_READ(reg); - WARN(adpa_pipe_enabled(dev_priv, val, pipe), + WARN(adpa_pipe_enabled(dev_priv, pipe, val), "PCH VGA enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); reg = PCH_LVDS; val = I915_READ(reg); - WARN(lvds_pipe_enabled(dev_priv, val, pipe), + WARN(lvds_pipe_enabled(dev_priv, pipe, val), "PCH LVDS enabled on transcoder %c, should be disabled\n", pipe_name(pipe)); @@ -1872,7 +1872,7 @@ static void disable_pch_hdmi(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - if (hdmi_pipe_enabled(dev_priv, val, pipe)) { + if (hdmi_pipe_enabled(dev_priv, pipe, val)) { DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n", reg, pipe); I915_WRITE(reg, val & ~PORT_ENABLE); @@ -1894,12 +1894,12 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, reg = PCH_ADPA; val = I915_READ(reg); - if (adpa_pipe_enabled(dev_priv, val, pipe)) + if (adpa_pipe_enabled(dev_priv, pipe, val)) I915_WRITE(reg, val & ~ADPA_DAC_ENABLE); reg = PCH_LVDS; val = I915_READ(reg); - if (lvds_pipe_enabled(dev_priv, val, pipe)) { + if (lvds_pipe_enabled(dev_priv, pipe, val)) { DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val); I915_WRITE(reg, val & ~LVDS_PORT_EN); POSTING_READ(reg); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index e05c0d3e3440..e9a6f6aaed85 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -780,6 +780,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Gigabyte GA-D525TUD", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "D525TUD"), + }, + }, { } /* terminating entry */ }; diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index cc8df4de2d92..7644f31a3778 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -60,11 +60,11 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, switch (fb->pixel_format) { case DRM_FORMAT_XBGR8888: - sprctl |= SPRITE_FORMAT_RGBX888; + sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; pixel_size = 4; break; case DRM_FORMAT_XRGB8888: - sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX; + sprctl |= SPRITE_FORMAT_RGBX888; pixel_size = 4; break; case DRM_FORMAT_YUYV: diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 1866dbb49979..c61014442aa9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -736,9 +736,11 @@ nouveau_card_init(struct drm_device *dev) } break; case NV_C0: - nvc0_copy_create(dev, 1); + if (!(nv_rd32(dev, 0x022500) & 0x00000200)) + nvc0_copy_create(dev, 1); case NV_D0: - nvc0_copy_create(dev, 0); + if (!(nv_rd32(dev, 0x022500) & 0x00000100)) + nvc0_copy_create(dev, 0); break; default: break; diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index f4d4505fe831..2817101fb167 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -258,7 +258,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) radeon_crtc->enabled = true; /* adjust pm to dpms changes BEFORE enabling crtcs */ radeon_pm_compute_clocks(rdev); - /* disable crtc pair power gating before programming */ if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) atombios_powergate_crtc(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_ENABLE); @@ -278,25 +277,8 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); radeon_crtc->enabled = false; - /* power gating is per-pair */ - if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) { - struct drm_crtc *other_crtc; - struct radeon_crtc *other_radeon_crtc; - list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) { - other_radeon_crtc = to_radeon_crtc(other_crtc); - if (((radeon_crtc->crtc_id == 0) && (other_radeon_crtc->crtc_id == 1)) || - ((radeon_crtc->crtc_id == 1) && (other_radeon_crtc->crtc_id == 0)) || - ((radeon_crtc->crtc_id == 2) && (other_radeon_crtc->crtc_id == 3)) || - ((radeon_crtc->crtc_id == 3) && (other_radeon_crtc->crtc_id == 2)) || - ((radeon_crtc->crtc_id == 4) && (other_radeon_crtc->crtc_id == 5)) || - ((radeon_crtc->crtc_id == 5) && (other_radeon_crtc->crtc_id == 4))) { - /* if both crtcs in the pair are off, enable power gating */ - if (other_radeon_crtc->enabled == false) - atombios_powergate_crtc(crtc, ATOM_ENABLE); - break; - } - } - } + if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) + atombios_powergate_crtc(crtc, ATOM_ENABLE); /* adjust pm to dpms changes AFTER disabling crtcs */ radeon_pm_compute_clocks(rdev); break; @@ -1682,9 +1664,22 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_atom_ss ss; + int i; atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + for (i = 0; i < rdev->num_crtc; i++) { + if (rdev->mode_info.crtcs[i] && + rdev->mode_info.crtcs[i]->enabled && + i != radeon_crtc->crtc_id && + radeon_crtc->pll_id == rdev->mode_info.crtcs[i]->pll_id) { + /* one other crtc is using this pll don't turn + * off the pll + */ + goto done; + } + } + switch (radeon_crtc->pll_id) { case ATOM_PPLL1: case ATOM_PPLL2: @@ -1701,6 +1696,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) default: break; } +done: radeon_crtc->pll_id = -1; } diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 7712cf5ab33b..3623b98ed3fe 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -577,30 +577,25 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; + u16 dp_bridge = radeon_connector_encoder_get_dp_bridge_encoder_id(connector); + u8 tmp; if (!ASIC_IS_DCE4(rdev)) return panel_mode; - if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == - ENCODER_OBJECT_ID_NUTMEG) - panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; - else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == - ENCODER_OBJECT_ID_TRAVIS) { - u8 id[6]; - int i; - for (i = 0; i < 6; i++) - id[i] = radeon_read_dpcd_reg(radeon_connector, 0x503 + i); - if (id[0] == 0x73 && - id[1] == 0x69 && - id[2] == 0x76 && - id[3] == 0x61 && - id[4] == 0x72 && - id[5] == 0x54) + if (dp_bridge != ENCODER_OBJECT_ID_NONE) { + /* DP bridge chips */ + tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + if (tmp & 1) + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || + (dp_bridge == ENCODER_OBJECT_ID_TRAVIS)) panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; else - panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { - u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + /* eDP */ + tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; } diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index f9bc27fe269a..6e8803a1170c 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1379,6 +1379,8 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); struct radeon_connector *radeon_connector = NULL; struct radeon_connector_atom_dig *radeon_dig_connector = NULL; @@ -1390,19 +1392,37 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) switch (mode) { case DRM_MODE_DPMS_ON: - /* some early dce3.2 boards have a bug in their transmitter control table */ - if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730) || - ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { - if (ASIC_IS_DCE6(rdev)) { - /* It seems we need to call ATOM_ENCODER_CMD_SETUP again - * before reenabling encoder on DPMS ON, otherwise we never - * get picture - */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { + if (!connector) + dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; + else + dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); + + /* setup and enable the encoder */ + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + atombios_dig_encoder_setup(encoder, + ATOM_ENCODER_CMD_SETUP_PANEL_MODE, + dig->panel_mode); + if (ext_encoder) { + if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); } atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } else { + } else if (ASIC_IS_DCE4(rdev)) { + /* setup and enable the encoder */ + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + /* enable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + } else { + /* setup and enable the encoder and transmitter */ + atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + /* some early dce3.2 boards have a bug in their transmitter control table */ + if ((rdev->family != CHIP_RV710) || (rdev->family != CHIP_RV730)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { @@ -1420,10 +1440,19 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) + if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { + /* disable the transmitter */ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - else + } else if (ASIC_IS_DCE4(rdev)) { + /* disable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + } else { + /* disable the encoder and transmitter */ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); + } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); @@ -1740,13 +1769,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct drm_encoder *test_encoder; - struct radeon_encoder_atom_dig *dig; + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; uint32_t dig_enc_in_use = 0; - /* DCE4/5 */ - if (ASIC_IS_DCE4(rdev)) { - dig = radeon_encoder->enc_priv; - if (ASIC_IS_DCE41(rdev)) { + if (ASIC_IS_DCE6(rdev)) { + /* DCE6 */ + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (dig->linkb) + return 1; + else + return 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + if (dig->linkb) + return 3; + else + return 2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (dig->linkb) + return 5; + else + return 4; + break; + } + } else if (ASIC_IS_DCE4(rdev)) { + /* DCE4/5 */ + if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { /* ontario follows DCE4 */ if (rdev->family == CHIP_PALM) { if (dig->linkb) @@ -1848,10 +1898,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); radeon_encoder->pixel_clock = adjusted_mode->clock; + /* need to call this here rather than in prepare() since we need some crtc info */ + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) atombios_yuv_setup(encoder, true); @@ -1870,38 +1922,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - - if (!connector) - dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; - else - dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector); - - /* setup and enable the encoder */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - atombios_dig_encoder_setup(encoder, - ATOM_ENCODER_CMD_SETUP_PANEL_MODE, - dig->panel_mode); - } else if (ASIC_IS_DCE4(rdev)) { - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - /* setup and enable the encoder */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - - /* enable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - - /* setup and enable the encoder and transmitter */ - atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } + /* handled in dpms */ break; case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DVO1: @@ -1922,14 +1943,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder, break; } - if (ext_encoder) { - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); - else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - } - atombios_apply_encoder_quirks(encoder, adjusted_mode); if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { @@ -2116,7 +2129,6 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) } radeon_atom_output_lock(encoder, true); - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); if (connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -2137,6 +2149,7 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) static void radeon_atom_encoder_commit(struct drm_encoder *encoder) { + /* need to call this here as we need the crtc set up */ radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); radeon_atom_output_lock(encoder, false); } @@ -2177,14 +2190,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE4(rdev)) - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - } + /* handled in dpms */ break; case ENCODER_OBJECT_ID_INTERNAL_DDI: case ENCODER_OBJECT_ID_INTERNAL_DVO1: diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index ab74e6b149e7..f37676d7f217 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -63,6 +63,7 @@ struct r600_cs_track { u32 cb_color_size_idx[8]; /* unused */ u32 cb_target_mask; u32 cb_shader_mask; /* unused */ + bool is_resolve; u32 cb_color_size[8]; u32 vgt_strmout_en; u32 vgt_strmout_buffer_en; @@ -315,7 +316,15 @@ static void r600_cs_track_init(struct r600_cs_track *track) track->cb_color_bo[i] = NULL; track->cb_color_bo_offset[i] = 0xFFFFFFFF; track->cb_color_bo_mc[i] = 0xFFFFFFFF; - } + track->cb_color_frag_bo[i] = NULL; + track->cb_color_frag_offset[i] = 0xFFFFFFFF; + track->cb_color_tile_bo[i] = NULL; + track->cb_color_tile_offset[i] = 0xFFFFFFFF; + track->cb_color_mask[i] = 0xFFFFFFFF; + } + track->is_resolve = false; + track->nsamples = 16; + track->log_nsamples = 4; track->cb_target_mask = 0xFFFFFFFF; track->cb_shader_mask = 0xFFFFFFFF; track->cb_dirty = true; @@ -352,6 +361,8 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) volatile u32 *ib = p->ib.ptr; unsigned array_mode; u32 format; + /* When resolve is used, the second colorbuffer has always 1 sample. */ + unsigned nsamples = track->is_resolve && i == 1 ? 1 : track->nsamples; size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i]; format = G_0280A0_FORMAT(track->cb_color_info[i]); @@ -375,7 +386,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) array_check.group_size = track->group_size; array_check.nbanks = track->nbanks; array_check.npipes = track->npipes; - array_check.nsamples = track->nsamples; + array_check.nsamples = nsamples; array_check.blocksize = r600_fmt_get_blocksize(format); if (r600_get_array_mode_alignment(&array_check, &pitch_align, &height_align, &depth_align, &base_align)) { @@ -421,7 +432,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) /* check offset */ tmp = r600_fmt_get_nblocksy(format, height) * r600_fmt_get_nblocksx(format, pitch) * - r600_fmt_get_blocksize(format) * track->nsamples; + r600_fmt_get_blocksize(format) * nsamples; switch (array_mode) { default: case V_0280A0_ARRAY_LINEAR_GENERAL: @@ -792,6 +803,12 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) */ if (track->cb_dirty) { tmp = track->cb_target_mask; + + /* We must check both colorbuffers for RESOLVE. */ + if (track->is_resolve) { + tmp |= 0xff; + } + for (i = 0; i < 8; i++) { if ((tmp >> (i * 4)) & 0xF) { /* at least one component is enabled */ @@ -1281,6 +1298,11 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) track->nsamples = 1 << tmp; track->cb_dirty = true; break; + case R_028808_CB_COLOR_CONTROL: + tmp = G_028808_SPECIAL_OP(radeon_get_ib_value(p, idx)); + track->is_resolve = tmp == V_028808_SPECIAL_RESOLVE_BOX; + track->cb_dirty = true; + break; case R_0280A0_CB_COLOR0_INFO: case R_0280A4_CB_COLOR1_INFO: case R_0280A8_CB_COLOR2_INFO: @@ -1416,7 +1438,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) case R_028118_CB_COLOR6_MASK: case R_02811C_CB_COLOR7_MASK: tmp = (reg - R_028100_CB_COLOR0_MASK) / 4; - track->cb_color_mask[tmp] = ib[idx]; + track->cb_color_mask[tmp] = radeon_get_ib_value(p, idx); if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) { track->cb_dirty = true; } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index bdb69a63062f..fa6f37099ba9 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -66,6 +66,14 @@ #define CC_RB_BACKEND_DISABLE 0x98F4 #define BACKEND_DISABLE(x) ((x) << 16) +#define R_028808_CB_COLOR_CONTROL 0x28808 +#define S_028808_SPECIAL_OP(x) (((x) & 0x7) << 4) +#define G_028808_SPECIAL_OP(x) (((x) >> 4) & 0x7) +#define C_028808_SPECIAL_OP 0xFFFFFF8F +#define V_028808_SPECIAL_NORMAL 0x00 +#define V_028808_SPECIAL_DISABLE 0x01 +#define V_028808_SPECIAL_RESOLVE_BOX 0x07 + #define CB_COLOR0_BASE 0x28040 #define CB_COLOR1_BASE 0x28044 #define CB_COLOR2_BASE 0x28048 diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index d2e243867ac6..7a3daebd732d 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1051,7 +1051,7 @@ int radeon_device_init(struct radeon_device *rdev, if (rdev->flags & RADEON_IS_AGP) rdev->need_dma32 = true; if ((rdev->flags & RADEON_IS_PCI) && - (rdev->family < CHIP_RS400)) + (rdev->family <= CHIP_RS740)) rdev->need_dma32 = true; dma_bits = rdev->need_dma32 ? 32 : 40; @@ -1346,12 +1346,15 @@ retry: for (i = 0; i < RADEON_NUM_RINGS; ++i) { radeon_ring_restore(rdev, &rdev->ring[i], ring_sizes[i], ring_data[i]); + ring_sizes[i] = 0; + ring_data[i] = NULL; } r = radeon_ib_ring_tests(rdev); if (r) { dev_err(rdev->dev, "ib ring test failed (%d).\n", r); if (saved) { + saved = false; radeon_suspend(rdev); goto retry; } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 27d22d709c90..8c593ea82c41 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -63,9 +63,10 @@ * 2.19.0 - r600-eg: MSAA textures * 2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query * 2.21.0 - r600-r700: FMASK and CMASK + * 2.22.0 - r600 only: RESOLVE_BOX allowed */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 21 +#define KMS_DRIVER_MINOR 22 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index f93e45d869f4..20bfbda7b3f1 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -744,7 +744,6 @@ r600 0x9400 0x00028C38 CB_CLRCMP_DST 0x00028C3C CB_CLRCMP_MSK 0x00028C34 CB_CLRCMP_SRC -0x00028808 CB_COLOR_CONTROL 0x0002842C CB_FOG_BLUE 0x00028428 CB_FOG_GREEN 0x00028424 CB_FOG_RED diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 60ea284407ce..8bf8a64e5115 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1624,7 +1624,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 351d1f4593e7..4ee578948723 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -34,6 +34,12 @@ static const struct dmi_system_id __initconst atk_force_new_if[] = { .matches = { DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58") } + }, { + /* Old interface reads the same sensor for fan0 and fan1 */ + .ident = "Asus M5A78L", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "M5A78L") + } }, { } }; diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c index 92406097efeb..8d1e32d7cd97 100644 --- a/drivers/ide/ide-pm.c +++ b/drivers/ide/ide-pm.c @@ -4,7 +4,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) { - ide_drive_t *drive = dev_get_drvdata(dev); + ide_drive_t *drive = to_ide_device(dev); ide_drive_t *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = drive->hwif; struct request *rq; @@ -40,7 +40,7 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) int generic_ide_resume(struct device *dev) { - ide_drive_t *drive = dev_get_drvdata(dev); + ide_drive_t *drive = to_ide_device(dev); ide_drive_t *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = drive->hwif; struct request *rq; diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 88cf9d952631..f721fd2155f7 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -454,11 +454,15 @@ static int omapvid_init(struct omap_vout_device *vout, u32 addr) win = &vout->win; for (i = 0; i < ovid->num_overlays; i++) { + struct omap_dss_device *dssdev; + ovl = ovid->overlays[i]; - if (!ovl->manager || !ovl->manager->device) + dssdev = ovl->get_device(ovl); + + if (!dssdev) return -EINVAL; - timing = &ovl->manager->device->panel.timings; + timing = &dssdev->panel.timings; outw = win->w.width; outh = win->w.height; @@ -515,8 +519,11 @@ static int omapvid_apply_changes(struct omap_vout_device *vout) struct omapvideo_info *ovid = &vout->vid_info; for (i = 0; i < ovid->num_overlays; i++) { + struct omap_dss_device *dssdev; + ovl = ovid->overlays[i]; - if (!ovl->manager || !ovl->manager->device) + dssdev = ovl->get_device(ovl); + if (!dssdev) return -EINVAL; ovl->manager->apply(ovl->manager); } @@ -579,12 +586,14 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) ovid = &vout->vid_info; ovl = ovid->overlays[0]; - /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) - return; mgr_id = ovl->manager->id; - cur_display = ovl->manager->device; + + /* get the display device attached to the overlay */ + cur_display = ovl->get_device(ovl); + + if (!cur_display) + return; spin_lock(&vout->vbq_lock); do_gettimeofday(&timevalue); @@ -948,7 +957,9 @@ static int omap_vout_release(struct file *file) /* Disable all the overlay managers connected with this interface */ for (i = 0; i < ovid->num_overlays; i++) { struct omap_overlay *ovl = ovid->overlays[i]; - if (ovl->manager && ovl->manager->device) + struct omap_dss_device *dssdev = ovl->get_device(ovl); + + if (dssdev) ovl->disable(ovl); } /* Turn off the pipeline */ @@ -1081,14 +1092,17 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *fh, struct omapvideo_info *ovid; struct omap_video_timings *timing; struct omap_vout_device *vout = fh; + struct omap_dss_device *dssdev; ovid = &vout->vid_info; ovl = ovid->overlays[0]; + /* get the display device attached to the overlay */ + dssdev = ovl->get_device(ovl); - if (!ovl->manager || !ovl->manager->device) + if (!dssdev) return -EINVAL; - /* get the display device attached to the overlay */ - timing = &ovl->manager->device->panel.timings; + + timing = &dssdev->panel.timings; vout->fbuf.fmt.height = timing->y_res; vout->fbuf.fmt.width = timing->x_res; @@ -1105,6 +1119,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, struct omapvideo_info *ovid; struct omap_video_timings *timing; struct omap_vout_device *vout = fh; + struct omap_dss_device *dssdev; if (vout->streaming) return -EBUSY; @@ -1113,13 +1128,14 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, ovid = &vout->vid_info; ovl = ovid->overlays[0]; + dssdev = ovl->get_device(ovl); /* get the display device attached to the overlay */ - if (!ovl->manager || !ovl->manager->device) { + if (!dssdev) { ret = -EINVAL; goto s_fmt_vid_out_exit; } - timing = &ovl->manager->device->panel.timings; + timing = &dssdev->panel.timings; /* We dont support RGB24-packed mode if vrfb rotation * is enabled*/ @@ -1298,6 +1314,7 @@ static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) struct omapvideo_info *ovid; struct omap_overlay *ovl; struct omap_video_timings *timing; + struct omap_dss_device *dssdev; if (vout->streaming) return -EBUSY; @@ -1305,13 +1322,15 @@ static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) mutex_lock(&vout->lock); ovid = &vout->vid_info; ovl = ovid->overlays[0]; + /* get the display device attached to the overlay */ + dssdev = ovl->get_device(ovl); - if (!ovl->manager || !ovl->manager->device) { + if (!dssdev) { ret = -EINVAL; goto s_crop_err; } - /* get the display device attached to the overlay */ - timing = &ovl->manager->device->panel.timings; + + timing = &dssdev->panel.timings; if (is_rotation_90_or_270(vout)) { vout->fbuf.fmt.height = timing->x_res; @@ -1667,7 +1686,7 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) for (j = 0; j < ovid->num_overlays; j++) { struct omap_overlay *ovl = ovid->overlays[j]; - if (ovl->manager && ovl->manager->device) { + if (ovl->get_device(ovl)) { struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); info.paddr = addr; @@ -1690,8 +1709,9 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) for (j = 0; j < ovid->num_overlays; j++) { struct omap_overlay *ovl = ovid->overlays[j]; + struct omap_dss_device *dssdev = ovl->get_device(ovl); - if (ovl->manager && ovl->manager->device) { + if (dssdev) { ret = ovl->enable(ovl); if (ret) goto streamon_err1; @@ -1726,8 +1746,9 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) for (j = 0; j < ovid->num_overlays; j++) { struct omap_overlay *ovl = ovid->overlays[j]; + struct omap_dss_device *dssdev = ovl->get_device(ovl); - if (ovl->manager && ovl->manager->device) + if (dssdev) ovl->disable(ovl); } @@ -1890,8 +1911,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) struct video_device *vfd; struct v4l2_pix_format *pix; struct v4l2_control *control; - struct omap_dss_device *display = - vout->vid_info.overlays[0]->manager->device; + struct omap_overlay *ovl = vout->vid_info.overlays[0]; + struct omap_dss_device *display = ovl->get_device(ovl); /* set the default pix */ pix = &vout->pix; @@ -2205,8 +2226,10 @@ static int __init omap_vout_probe(struct platform_device *pdev) */ for (i = 1; i < vid_dev->num_overlays; i++) { ovl = omap_dss_get_overlay(i); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; + dssdev = ovl->get_device(ovl); + + if (dssdev) { + def_display = dssdev; } else { dev_warn(&pdev->dev, "cannot find display\n"); def_display = NULL; @@ -2253,8 +2276,10 @@ probe_err1: for (i = 1; i < vid_dev->num_overlays; i++) { def_display = NULL; ovl = omap_dss_get_overlay(i); - if (ovl->manager && ovl->manager->device) - def_display = ovl->manager->device; + dssdev = ovl->get_device(ovl); + + if (dssdev) + def_display = dssdev; if (def_display && def_display->driver) def_display->driver->disable(def_display); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 40a826a7295f..2fb2b9ea97ec 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3804,7 +3804,7 @@ dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) case BIODASDSYMMIO: return dasd_symm_io(device, argp); default: - return -ENOIOCTLCMD; + return -ENOTTY; } } diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index cceae70279f6..654c6921a6d4 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -498,12 +498,9 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode, break; default: /* if the discipline has an ioctl method try it. */ - if (base->discipline->ioctl) { + rc = -ENOTTY; + if (base->discipline->ioctl) rc = base->discipline->ioctl(block, cmd, argp); - if (rc == -ENOIOCTLCMD) - rc = -EINVAL; - } else - rc = -EINVAL; } dasd_put_device(base); return rc; diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index ea0aaa3f13d0..a9f4049c6769 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -47,6 +47,8 @@ struct bcm63xx_spi { /* Platform data */ u32 speed_hz; unsigned fifo_size; + unsigned int msg_type_shift; + unsigned int msg_ctl_width; /* Data buffers */ const unsigned char *tx_ptr; @@ -221,13 +223,20 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi, msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT); if (t->rx_buf && t->tx_buf) - msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT); + msg_ctl |= (SPI_FD_RW << bs->msg_type_shift); else if (t->rx_buf) - msg_ctl |= (SPI_HD_R << SPI_MSG_TYPE_SHIFT); + msg_ctl |= (SPI_HD_R << bs->msg_type_shift); else if (t->tx_buf) - msg_ctl |= (SPI_HD_W << SPI_MSG_TYPE_SHIFT); - - bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL); + msg_ctl |= (SPI_HD_W << bs->msg_type_shift); + + switch (bs->msg_ctl_width) { + case 8: + bcm_spi_writeb(bs, msg_ctl, SPI_MSG_CTL); + break; + case 16: + bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL); + break; + } /* Issue the transfer */ cmd = SPI_CMD_START_IMMEDIATE; @@ -406,9 +415,21 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev) master->transfer_one_message = bcm63xx_spi_transfer_one; master->mode_bits = MODEBITS; bs->speed_hz = pdata->speed_hz; + bs->msg_type_shift = pdata->msg_type_shift; + bs->msg_ctl_width = pdata->msg_ctl_width; bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA)); bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA)); + switch (bs->msg_ctl_width) { + case 8: + case 16: + break; + default: + dev_err(dev, "unsupported MSG_CTL width: %d\n", + bs->msg_ctl_width); + goto out_clk_disable; + } + /* Initialize hardware */ clk_enable(bs->clk); bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 4beab9447ceb..64a354a54737 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -106,7 +106,8 @@ static void dump_video_chains(void) for (i = 0; i < omap_dss_get_num_overlays(); i++) { struct omap_overlay *ovl = omap_dss_get_overlay(i); struct omap_overlay_manager *mgr = ovl->manager; - struct omap_dss_device *dssdev = mgr ? mgr->device : NULL; + struct omap_dss_device *dssdev = mgr ? + mgr->get_device(mgr) : NULL; if (dssdev) { DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name, dssdev->name); @@ -185,7 +186,7 @@ static int create_connector(struct drm_device *dev, for (j = 0; j < priv->num_encoders; j++) { struct omap_overlay_manager *mgr = omap_encoder_get_manager(priv->encoders[j]); - if (mgr->device == dssdev) { + if (mgr->get_device(mgr) == dssdev) { drm_mode_connector_attach_encoder(connector, priv->encoders[j]); } diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 9f1d23c319cb..f349ee6f0cea 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -27,7 +27,6 @@ #include <linux/clk.h> #include <linux/interrupt.h> -#include <plat/dma.h> #include "omapfb.h" #define HWA742_REV_CODE_REG 0x0 diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c index d3a311327227..5cca6b373af7 100644 --- a/drivers/video/omap/lcd_ams_delta.c +++ b/drivers/video/omap/lcd_ams_delta.c @@ -28,7 +28,6 @@ #include <linux/gpio.h> #include <plat/board-ams-delta.h> -#include <mach/hardware.h> #include "omapfb.h" diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c index 88c31eb0cd6c..ff4fb624b904 100644 --- a/drivers/video/omap/lcd_palmte.c +++ b/drivers/video/omap/lcd_palmte.c @@ -23,7 +23,6 @@ #include <linux/platform_device.h> #include <linux/io.h> -#include <plat/fpga.h> #include "omapfb.h" static int palmte_panel_init(struct lcd_panel *panel, diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index f54b463709e9..4351c438b76f 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -131,15 +131,6 @@ static void omapfb_rqueue_unlock(struct omapfb_device *fbdev) * LCD controller and LCD DMA * --------------------------------------------------------------------------- */ -/* Lookup table to map elem size to elem type. */ -static const int dma_elem_type[] = { - 0, - OMAP_DMA_DATA_TYPE_S8, - OMAP_DMA_DATA_TYPE_S16, - 0, - OMAP_DMA_DATA_TYPE_S32, -}; - /* * Allocate resources needed for LCD controller and LCD DMA operations. Video * memory is allocated from system memory according to the virtual display diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index eaeed4340e04..c835aa70f96f 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -600,6 +600,9 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) mutex_lock(&md->mutex); + omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs); + r = omapdss_sdi_display_enable(dssdev); if (r) { pr_err("%s sdi enable failed\n", __func__); @@ -731,18 +734,9 @@ static int acx_panel_resume(struct omap_dss_device *dssdev) static void acx_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - int r; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - omapdss_sdi_display_disable(dssdev); + omapdss_sdi_set_timings(dssdev, timings); dssdev->panel.timings = *timings; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - r = omapdss_sdi_display_enable(dssdev); - if (r) - dev_err(&dssdev->dev, "%s enable failed\n", __func__); - } } static int acx_panel_check_timings(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index bc5af2500eb9..88295c526815 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -545,6 +545,8 @@ struct panel_drv_data { struct omap_dss_device *dssdev; struct panel_config *panel_config; + + struct mutex lock; }; static inline struct panel_generic_dpi_data @@ -563,6 +565,9 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -634,6 +639,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) drv_data->dssdev = dssdev; drv_data->panel_config = panel_config; + mutex_init(&drv_data->lock); + dev_set_drvdata(&dssdev->dev, drv_data); return 0; @@ -652,56 +659,108 @@ static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) { - int r = 0; + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); r = generic_dpi_panel_power_on(dssdev); if (r) - return r; + goto err; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; +err: + mutex_unlock(&drv_data->lock); - return 0; + return r; } static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) { + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + generic_dpi_panel_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&drv_data->lock); } static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) { + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + generic_dpi_panel_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + mutex_unlock(&drv_data->lock); + return 0; } static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) { - int r = 0; + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); r = generic_dpi_panel_power_on(dssdev); if (r) - return r; + goto err; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - return 0; +err: + mutex_unlock(&drv_data->lock); + + return r; } static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dpi_set_timings(dssdev, timings); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + + omapdss_dpi_set_timings(dssdev, timings); + + dssdev->panel.timings = *timings; + + mutex_unlock(&drv_data->lock); +} + +static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + + *timings = dssdev->panel.timings; + + mutex_unlock(&drv_data->lock); } static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - return dpi_check_timings(dssdev, timings); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); + + r = dpi_check_timings(dssdev, timings); + + mutex_unlock(&drv_data->lock); + + return r; } static struct omap_dss_driver dpi_driver = { @@ -714,6 +773,7 @@ static struct omap_dss_driver dpi_driver = { .resume = generic_dpi_panel_resume, .set_timings = generic_dpi_panel_set_timings, + .get_timings = generic_dpi_panel_get_timings, .check_timings = generic_dpi_panel_check_timings, .driver = { diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 802807798846..90c1cabf244e 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c @@ -55,6 +55,9 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index e6c115373c00..3fc5ad081a21 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -150,11 +150,17 @@ static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev, BLIZZARD_SRC_WRITE_LCD : BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; - omap_rfbi_configure(dssdev, 16, 8); + omapdss_rfbi_set_pixel_size(dssdev, 16); + omapdss_rfbi_set_data_lines(dssdev, 8); + + omap_rfbi_configure(dssdev); blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18); - omap_rfbi_configure(dssdev, 16, 16); + omapdss_rfbi_set_pixel_size(dssdev, 16); + omapdss_rfbi_set_data_lines(dssdev, 16); + + omap_rfbi_configure(dssdev); } static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf, @@ -297,6 +303,12 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev) goto err_plat_en; } + omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); + omapdss_rfbi_set_data_lines(dssdev, dssdev->phy.rfbi.data_lines); + omapdss_rfbi_set_interface_timings(dssdev, &dssdev->ctrl.rfbi_timings); + r = omapdss_rfbi_display_enable(dssdev); if (r) goto err_rfbi_en; @@ -477,6 +489,7 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) dssdev->panel.timings.y_res = 480; dssdev->ctrl.pixel_size = 16; dssdev->ctrl.rfbi_timings = n8x0_panel_timings; + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; memset(&props, 0, sizeof(props)); props.max_brightness = 127; @@ -625,17 +638,25 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct panel_drv_data *ddata = get_drv_data(dssdev); + u16 dw, dh; dev_dbg(&dssdev->dev, "update\n"); + dw = dssdev->panel.timings.x_res; + dh = dssdev->panel.timings.y_res; + + if (x != 0 || y != 0 || w != dw || h != dh) { + dev_err(&dssdev->dev, "invaid update region %d, %d, %d, %d\n", + x, y, w, h); + return -EINVAL; + } + mutex_lock(&ddata->lock); rfbi_bus_lock(); - omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h); - blizzard_ctrl_setup_update(dssdev, x, y, w, h); - omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL); + omap_rfbi_update(dssdev, update_done, NULL); mutex_unlock(&ddata->lock); diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index b122b0f31c43..908fd268f3dc 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -175,6 +175,9 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 2d35bd388860..9df87640ddd2 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -377,6 +377,10 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) * then only i2c commands can be successfully sent to dpp2600 */ msleep(1000); + + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DPI\n"); diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index bd86ba9ccf76..1ec3b277ff15 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -142,6 +142,9 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 3f5acc7771da..4cf94161ff51 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -121,6 +121,18 @@ struct taal_data { struct omap_dss_device *dssdev; + /* panel specific HW info */ + struct panel_config *panel_config; + + /* panel HW configuration from DT or platform data */ + int reset_gpio; + int ext_te_gpio; + + bool use_dsi_backlight; + + struct omap_dsi_pin_config pin_config; + + /* runtime variables */ bool enabled; u8 rotate; bool mirror; @@ -145,16 +157,8 @@ struct taal_data { bool ulps_enabled; unsigned ulps_timeout; struct delayed_work ulps_work; - - struct panel_config *panel_config; }; -static inline struct nokia_dsi_panel_data -*get_panel_data(const struct omap_dss_device *dssdev) -{ - return (struct nokia_dsi_panel_data *) dssdev->data; -} - static void taal_esd_work(struct work_struct *work); static void taal_ulps_work(struct work_struct *work); @@ -371,7 +375,6 @@ static void taal_cancel_ulps_work(struct omap_dss_device *dssdev) static int taal_enter_ulps(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (td->ulps_enabled) @@ -383,7 +386,8 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev) if (r) goto err; - disable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + disable_irq(gpio_to_irq(td->ext_te_gpio)); omapdss_dsi_display_disable(dssdev, false, true); @@ -405,7 +409,6 @@ err: static int taal_exit_ulps(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (!td->ulps_enabled) @@ -425,7 +428,8 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) goto err2; } - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + enable_irq(gpio_to_irq(td->ext_te_gpio)); taal_queue_ulps_work(dssdev); @@ -438,7 +442,8 @@ err2: r = taal_panel_reset(dssdev); if (!r) { - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + enable_irq(gpio_to_irq(td->ext_te_gpio)); td->ulps_enabled = false; } err1: @@ -835,94 +840,135 @@ static struct attribute_group taal_attr_group = { static void taal_hw_reset(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); - if (panel_data->reset_gpio == -1) + if (!gpio_is_valid(td->reset_gpio)) return; - gpio_set_value(panel_data->reset_gpio, 1); + gpio_set_value(td->reset_gpio, 1); if (td->panel_config->reset_sequence.high) udelay(td->panel_config->reset_sequence.high); /* reset the panel */ - gpio_set_value(panel_data->reset_gpio, 0); + gpio_set_value(td->reset_gpio, 0); /* assert reset */ if (td->panel_config->reset_sequence.low) udelay(td->panel_config->reset_sequence.low); - gpio_set_value(panel_data->reset_gpio, 1); + gpio_set_value(td->reset_gpio, 1); /* wait after releasing reset */ if (td->panel_config->sleep.hw_reset) msleep(td->panel_config->sleep.hw_reset); } +static void taal_probe_pdata(struct taal_data *td, + const struct nokia_dsi_panel_data *pdata) +{ + td->reset_gpio = pdata->reset_gpio; + + if (pdata->use_ext_te) + td->ext_te_gpio = pdata->ext_te_gpio; + else + td->ext_te_gpio = -1; + + td->esd_interval = pdata->esd_interval; + td->ulps_timeout = pdata->ulps_timeout; + + td->use_dsi_backlight = pdata->use_dsi_backlight; + + td->pin_config = pdata->pin_config; +} + static int taal_probe(struct omap_dss_device *dssdev) { struct backlight_properties props; struct taal_data *td; struct backlight_device *bldev = NULL; - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); - struct panel_config *panel_config = NULL; int r, i; + const char *panel_name; dev_dbg(&dssdev->dev, "probe\n"); - if (!panel_data || !panel_data->name) { - r = -EINVAL; - goto err; + td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL); + if (!td) + return -ENOMEM; + + dev_set_drvdata(&dssdev->dev, td); + td->dssdev = dssdev; + + if (dssdev->data) { + const struct nokia_dsi_panel_data *pdata = dssdev->data; + + taal_probe_pdata(td, pdata); + + panel_name = pdata->name; + } else { + return -ENODEV; } + if (panel_name == NULL) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { - if (strcmp(panel_data->name, panel_configs[i].name) == 0) { - panel_config = &panel_configs[i]; + if (strcmp(panel_name, panel_configs[i].name) == 0) { + td->panel_config = &panel_configs[i]; break; } } - if (!panel_config) { - r = -EINVAL; - goto err; - } + if (!td->panel_config) + return -EINVAL; - dssdev->panel.timings = panel_config->timings; + dssdev->panel.timings = td->panel_config->timings; dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; - - td = kzalloc(sizeof(*td), GFP_KERNEL); - if (!td) { - r = -ENOMEM; - goto err; - } - td->dssdev = dssdev; - td->panel_config = panel_config; - td->esd_interval = panel_data->esd_interval; - td->ulps_enabled = false; - td->ulps_timeout = panel_data->ulps_timeout; + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | + OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; mutex_init(&td->lock); atomic_set(&td->do_update, 0); - td->workqueue = create_singlethread_workqueue("taal_esd"); - if (td->workqueue == NULL) { - dev_err(&dssdev->dev, "can't create ESD workqueue\n"); - r = -ENOMEM; - goto err_wq; + if (gpio_is_valid(td->reset_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio, + GPIOF_OUT_INIT_LOW, "taal rst"); + if (r) { + dev_err(&dssdev->dev, "failed to request reset gpio\n"); + return r; + } } - INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); - INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); - dev_set_drvdata(&dssdev->dev, td); + if (gpio_is_valid(td->ext_te_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio, + GPIOF_IN, "taal irq"); + if (r) { + dev_err(&dssdev->dev, "GPIO request failed\n"); + return r; + } + + r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio), + taal_te_isr, + IRQF_TRIGGER_RISING, + "taal vsync", dssdev); - if (gpio_is_valid(panel_data->reset_gpio)) { - r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW, - "taal rst"); if (r) { - dev_err(&dssdev->dev, "failed to request reset gpio\n"); - goto err_rst_gpio; + dev_err(&dssdev->dev, "IRQ request failed\n"); + return r; } + + INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, + taal_te_timeout_work_callback); + + dev_dbg(&dssdev->dev, "Using GPIO TE\n"); } + td->workqueue = create_singlethread_workqueue("taal_esd"); + if (td->workqueue == NULL) { + dev_err(&dssdev->dev, "can't create ESD workqueue\n"); + return -ENOMEM; + } + INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); + INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); + taal_hw_reset(dssdev); - if (panel_data->use_dsi_backlight) { + if (td->use_dsi_backlight) { memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 255; @@ -943,31 +989,6 @@ static int taal_probe(struct omap_dss_device *dssdev) taal_bl_update_status(bldev); } - if (panel_data->use_ext_te) { - int gpio = panel_data->ext_te_gpio; - - r = gpio_request_one(gpio, GPIOF_IN, "taal irq"); - if (r) { - dev_err(&dssdev->dev, "GPIO request failed\n"); - goto err_gpio; - } - - r = request_irq(gpio_to_irq(gpio), taal_te_isr, - IRQF_TRIGGER_RISING, - "taal vsync", dssdev); - - if (r) { - dev_err(&dssdev->dev, "IRQ request failed\n"); - gpio_free(gpio); - goto err_irq; - } - - INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, - taal_te_timeout_work_callback); - - dev_dbg(&dssdev->dev, "Using GPIO TE\n"); - } - r = omap_dsi_request_vc(dssdev, &td->channel); if (r) { dev_err(&dssdev->dev, "failed to get virtual channel\n"); @@ -991,29 +1012,16 @@ static int taal_probe(struct omap_dss_device *dssdev) err_vc_id: omap_dsi_release_vc(dssdev, td->channel); err_req_vc: - if (panel_data->use_ext_te) - free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); -err_irq: - if (panel_data->use_ext_te) - gpio_free(panel_data->ext_te_gpio); -err_gpio: if (bldev != NULL) backlight_device_unregister(bldev); err_bl: - if (gpio_is_valid(panel_data->reset_gpio)) - gpio_free(panel_data->reset_gpio); -err_rst_gpio: destroy_workqueue(td->workqueue); -err_wq: - kfree(td); -err: return r; } static void __exit taal_remove(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); struct backlight_device *bldev; dev_dbg(&dssdev->dev, "remove\n"); @@ -1021,12 +1029,6 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); omap_dsi_release_vc(dssdev, td->channel); - if (panel_data->use_ext_te) { - int gpio = panel_data->ext_te_gpio; - free_irq(gpio_to_irq(gpio), dssdev); - gpio_free(gpio); - } - bldev = td->bldev; if (bldev != NULL) { bldev->props.power = FB_BLANK_POWERDOWN; @@ -1040,26 +1042,31 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) /* reset, to be sure that the panel is in a valid state */ taal_hw_reset(dssdev); - - if (gpio_is_valid(panel_data->reset_gpio)) - gpio_free(panel_data->reset_gpio); - - kfree(td); } static int taal_power_on(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 id1, id2, id3; int r; - r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config); + r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); if (r) { dev_err(&dssdev->dev, "failed to configure DSI pins\n"); goto err0; }; + omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888); + omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE); + + r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000); + if (r) { + dev_err(&dssdev->dev, "failed to set HS and LP clocks\n"); + goto err0; + } + r = omapdss_dsi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DSI\n"); @@ -1356,7 +1363,6 @@ static int taal_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); @@ -1380,7 +1386,7 @@ static int taal_update(struct omap_dss_device *dssdev, if (r) goto err; - if (td->te_enabled && panel_data->use_ext_te) { + if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { schedule_delayed_work(&td->te_timeout_work, msecs_to_jiffies(250)); atomic_set(&td->do_update, 1); @@ -1419,7 +1425,6 @@ static int taal_sync(struct omap_dss_device *dssdev) static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (enable) @@ -1427,7 +1432,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) else r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF); - if (!panel_data->use_ext_te) + if (!gpio_is_valid(td->ext_te_gpio)) omapdss_dsi_enable_te(dssdev, enable); if (td->panel_config->sleep.enable_te) @@ -1487,6 +1492,7 @@ static int taal_get_te(struct omap_dss_device *dssdev) static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + u16 dw, dh; int r; dev_dbg(&dssdev->dev, "rotate %d\n", rotate); @@ -1508,6 +1514,16 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) goto err; } + if (rotate == 0 || rotate == 2) { + dw = dssdev->panel.timings.x_res; + dh = dssdev->panel.timings.y_res; + } else { + dw = dssdev->panel.timings.y_res; + dh = dssdev->panel.timings.x_res; + } + + omapdss_dsi_set_size(dssdev, dw, dh); + td->rotate = rotate; dsi_bus_unlock(dssdev); @@ -1726,7 +1742,6 @@ static void taal_esd_work(struct work_struct *work) struct taal_data *td = container_of(work, struct taal_data, esd_work.work); struct omap_dss_device *dssdev = td->dssdev; - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 state1, state2; int r; @@ -1773,7 +1788,7 @@ static void taal_esd_work(struct work_struct *work) } /* Self-diagnostics result is also shown on TE GPIO line. We need * to re-enable TE after self diagnostics */ - if (td->te_enabled && panel_data->use_ext_te) { + if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); if (r) goto err; diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 40cc0cfa5d17..383811cf8648 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c @@ -65,6 +65,9 @@ static int tfp410_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -116,8 +119,8 @@ static int tfp410_probe(struct omap_dss_device *dssdev) } if (gpio_is_valid(ddata->pd_gpio)) { - r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW, - "tfp410 pd"); + r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio, + GPIOF_OUT_INIT_LOW, "tfp410 pd"); if (r) { dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", ddata->pd_gpio); @@ -132,8 +135,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev) if (!adapter) { dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", i2c_bus_num); - r = -EINVAL; - goto err_i2c; + return -EINVAL; } ddata->i2c_adapter = adapter; @@ -142,10 +144,6 @@ static int tfp410_probe(struct omap_dss_device *dssdev) dev_set_drvdata(&dssdev->dev, ddata); return 0; -err_i2c: - if (gpio_is_valid(ddata->pd_gpio)) - gpio_free(ddata->pd_gpio); - return r; } static void __exit tfp410_remove(struct omap_dss_device *dssdev) @@ -157,9 +155,6 @@ static void __exit tfp410_remove(struct omap_dss_device *dssdev) if (ddata->i2c_adapter) i2c_put_adapter(ddata->i2c_adapter); - if (gpio_is_valid(ddata->pd_gpio)) - gpio_free(ddata->pd_gpio); - dev_set_drvdata(&dssdev->dev, NULL); mutex_unlock(&ddata->lock); @@ -231,7 +226,8 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev, struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); mutex_lock(&ddata->lock); - dpi_set_timings(dssdev, timings); + omapdss_dpi_set_timings(dssdev, timings); + dssdev->panel.timings = *timings; mutex_unlock(&ddata->lock); } diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index fa7baa650ae0..b5e6dbc59f0a 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -337,6 +337,9 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -480,7 +483,9 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev) static void tpo_td043_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dpi_set_timings(dssdev, timings); + omapdss_dpi_set_timings(dssdev, timings); + + dssdev->panel.timings = *timings; } static int tpo_td043_check_timings(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index b337a8469fd8..80f5390aa136 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -84,7 +84,7 @@ config OMAP2_DSS_SDI config OMAP2_DSS_DSI bool "DSI support" - depends on ARCH_OMAP3 || ARCH_OMAP4 + depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5 default n help MIPI DSI (Display Serial Interface) support. diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 5c450b0f94d0..4549869bfe1a 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,9 +1,9 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - manager.o overlay.o apply.o + manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o -omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o +omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 0fefc68372b9..19d66f471b4b 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -111,9 +111,6 @@ static struct { struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; - bool fifo_merge_dirty; - bool fifo_merge; - bool irq_enabled; } dss_data; @@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void) int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); - struct mgr_priv_data *mp; + struct mgr_priv_data *mp = get_mgr_priv(mgr); u32 irq; + unsigned long flags; int r; int i; - struct omap_dss_device *dssdev = mgr->device; - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + spin_lock_irqsave(&data_lock, flags); + + if (mgr_manual_update(mgr)) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } - if (mgr_manual_update(mgr)) + if (!mp->enabled) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } + + spin_unlock_irqrestore(&data_lock, flags); r = dispc_runtime_get(); if (r) @@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) irq = dispc_mgr_get_vsync_irq(mgr->id); - mp = get_mgr_priv(mgr); i = 0; while (1) { - unsigned long flags; bool shadow_dirty, dirty; spin_lock_irqsave(&data_lock, flags); @@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) { unsigned long timeout = msecs_to_jiffies(500); struct ovl_priv_data *op; - struct omap_dss_device *dssdev; + struct mgr_priv_data *mp; u32 irq; + unsigned long flags; int r; int i; if (!ovl->manager) return 0; - dssdev = ovl->manager->device; + mp = get_mgr_priv(ovl->manager); + + spin_lock_irqsave(&data_lock, flags); - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + if (ovl_manual_update(ovl)) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } - if (ovl_manual_update(ovl)) + if (!mp->enabled) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } + + spin_unlock_irqrestore(&data_lock, flags); r = dispc_runtime_get(); if (r) @@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) op = get_ovl_priv(ovl); i = 0; while (1) { - unsigned long flags; bool shadow_dirty, dirty; spin_lock_irqsave(&data_lock, flags); @@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); - r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings); + r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false); if (r) { /* * We can't do much here, as this function can be called from @@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) mp->shadow_extra_info_dirty = true; } -static void dss_write_regs_common(void) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - int i; - - if (!dss_data.fifo_merge_dirty) - return; - - for (i = 0; i < num_mgrs; ++i) { - struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; - - mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (mp->enabled) { - if (dss_data.fifo_merge_dirty) { - dispc_enable_fifomerge(dss_data.fifo_merge); - dss_data.fifo_merge_dirty = false; - } - - if (mp->updating) - mp->shadow_info_dirty = true; - } - } -} - static void dss_write_regs(void) { const int num_mgrs = omap_dss_get_num_overlay_managers(); int i; - dss_write_regs_common(); - for (i = 0; i < num_mgrs; ++i) { struct omap_overlay_manager *mgr; struct mgr_priv_data *mp; @@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) dss_mgr_write_regs(mgr); dss_mgr_write_regs_extra(mgr); - dss_write_regs_common(); - mp->updating = true; if (!dss_data.irq_enabled && need_isr()) @@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, op->extra_info_dirty = true; } -static void dss_apply_fifo_merge(bool use_fifo_merge) -{ - if (dss_data.fifo_merge == use_fifo_merge) - return; - - dss_data.fifo_merge = use_fifo_merge; - dss_data.fifo_merge_dirty = true; -} - -static void dss_ovl_setup_fifo(struct omap_overlay *ovl, - bool use_fifo_merge) +static void dss_ovl_setup_fifo(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); u32 fifo_low, fifo_high; + bool use_fifo_merge = false; if (!op->enabled && !op->enabling) return; @@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl, dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); } -static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, - bool use_fifo_merge) +static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) { struct omap_overlay *ovl; struct mgr_priv_data *mp; @@ -1020,94 +990,19 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, return; list_for_each_entry(ovl, &mgr->overlays, list) - dss_ovl_setup_fifo(ovl, use_fifo_merge); -} - -static void dss_setup_fifos(bool use_fifo_merge) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - struct omap_overlay_manager *mgr; - int i; - - for (i = 0; i < num_mgrs; ++i) { - mgr = omap_dss_get_overlay_manager(i); - dss_mgr_setup_fifos(mgr, use_fifo_merge); - } + dss_ovl_setup_fifo(ovl); } -static int get_num_used_managers(void) +static void dss_setup_fifos(void) { const int num_mgrs = omap_dss_get_num_overlay_managers(); struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; int i; - int enabled_mgrs; - - enabled_mgrs = 0; for (i = 0; i < num_mgrs; ++i) { mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (!mp->enabled) - continue; - - enabled_mgrs++; + dss_mgr_setup_fifos(mgr); } - - return enabled_mgrs; -} - -static int get_num_used_overlays(void) -{ - const int num_ovls = omap_dss_get_num_overlays(); - struct omap_overlay *ovl; - struct ovl_priv_data *op; - struct mgr_priv_data *mp; - int i; - int enabled_ovls; - - enabled_ovls = 0; - - for (i = 0; i < num_ovls; ++i) { - ovl = omap_dss_get_overlay(i); - op = get_ovl_priv(ovl); - - if (!op->enabled && !op->enabling) - continue; - - mp = get_mgr_priv(ovl->manager); - - if (!mp->enabled) - continue; - - enabled_ovls++; - } - - return enabled_ovls; -} - -static bool get_use_fifo_merge(void) -{ - int enabled_mgrs = get_num_used_managers(); - int enabled_ovls = get_num_used_overlays(); - - if (!dss_has_feature(FEAT_FIFO_MERGE)) - return false; - - /* - * In theory the only requirement for fifomerge is enabled_ovls <= 1. - * However, if we have two managers enabled and set/unset the fifomerge, - * we need to set the GO bits in particular sequence for the managers, - * and wait in between. - * - * This is rather difficult as new apply calls can happen at any time, - * so we simplify the problem by requiring also that enabled_mgrs <= 1. - * In practice this shouldn't matter, because when only one overlay is - * enabled, most likely only one output is enabled. - */ - - return enabled_mgrs <= 1 && enabled_ovls <= 1; } int dss_mgr_enable(struct omap_overlay_manager *mgr) @@ -1115,7 +1010,6 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; int r; - bool fifo_merge; mutex_lock(&apply_lock); @@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) goto err; } - /* step 1: setup fifos/fifomerge before enabling the manager */ - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); + dss_setup_fifos(); dss_write_regs(); dss_set_go_bits(); - spin_unlock_irqrestore(&data_lock, flags); - - /* wait until fifo config is in */ - wait_pending_extra_info_updates(); - - /* step 2: enable the manager */ - spin_lock_irqsave(&data_lock, flags); - if (!mgr_manual_update(mgr)) mp->updating = true; @@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; - bool fifo_merge; mutex_lock(&apply_lock); @@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) mp->updating = false; mp->enabled = false; - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - spin_unlock_irqrestore(&data_lock, flags); - wait_pending_extra_info_updates(); out: mutex_unlock(&apply_lock); } @@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, spin_unlock_irqrestore(&data_lock, flags); } -int dss_mgr_set_device(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev) +int dss_mgr_set_output(struct omap_overlay_manager *mgr, + struct omap_dss_output *output) { int r; mutex_lock(&apply_lock); - if (dssdev->manager) { - DSSERR("display '%s' already has a manager '%s'\n", - dssdev->name, dssdev->manager->name); + if (mgr->output) { + DSSERR("manager %s is already connected to an output\n", + mgr->name); r = -EINVAL; goto err; } - if ((mgr->supported_displays & dssdev->type) == 0) { - DSSERR("display '%s' does not support manager '%s'\n", - dssdev->name, mgr->name); + if ((mgr->supported_outputs & output->id) == 0) { + DSSERR("output does not support manager %s\n", + mgr->name); r = -EINVAL; goto err; } - dssdev->manager = mgr; - mgr->device = dssdev; + output->manager = mgr; + mgr->output = output; mutex_unlock(&apply_lock); @@ -1269,40 +1142,46 @@ err: return r; } -int dss_mgr_unset_device(struct omap_overlay_manager *mgr) +int dss_mgr_unset_output(struct omap_overlay_manager *mgr) { int r; + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; mutex_lock(&apply_lock); - if (!mgr->device) { - DSSERR("failed to unset display, display not set.\n"); + if (!mgr->output) { + DSSERR("failed to unset output, output not set\n"); r = -EINVAL; goto err; } - /* - * Don't allow currently enabled displays to have the overlay manager - * pulled out from underneath them - */ - if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) { + spin_lock_irqsave(&data_lock, flags); + + if (mp->enabled) { + DSSERR("output can't be unset when manager is enabled\n"); r = -EINVAL; - goto err; + goto err1; } - mgr->device->manager = NULL; - mgr->device = NULL; + spin_unlock_irqrestore(&data_lock, flags); + + mgr->output->manager = NULL; + mgr->output = NULL; mutex_unlock(&apply_lock); return 0; +err1: + spin_unlock_irqrestore(&data_lock, flags); err: mutex_unlock(&apply_lock); + return r; } static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings) + const struct omap_video_timings *timings) { struct mgr_priv_data *mp = get_mgr_priv(mgr); @@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, } void dss_mgr_set_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings) + const struct omap_video_timings *timings) { unsigned long flags; - - mutex_lock(&apply_lock); + struct mgr_priv_data *mp = get_mgr_priv(mgr); spin_lock_irqsave(&data_lock, flags); - dss_apply_mgr_timings(mgr, timings); - - dss_write_regs(); - dss_set_go_bits(); + if (mp->updating) { + DSSERR("cannot set timings for %s: manager needs to be disabled\n", + mgr->name); + goto out; + } + dss_apply_mgr_timings(mgr, timings); +out: spin_unlock_irqrestore(&data_lock, flags); - - wait_pending_extra_info_updates(); - - mutex_unlock(&apply_lock); } static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, @@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, unsigned long flags; struct mgr_priv_data *mp = get_mgr_priv(mgr); - mutex_lock(&apply_lock); + spin_lock_irqsave(&data_lock, flags); if (mp->enabled) { DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", @@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, goto out; } - spin_lock_irqsave(&data_lock, flags); - dss_apply_mgr_lcd_config(mgr, config); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - wait_pending_extra_info_updates(); - out: - mutex_unlock(&apply_lock); + spin_unlock_irqrestore(&data_lock, flags); } int dss_ovl_set_info(struct omap_overlay *ovl, @@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) goto err; } + spin_unlock_irqrestore(&data_lock, flags); + + /* wait for pending extra_info updates to ensure the ovl is disabled */ + wait_pending_extra_info_updates(); + + spin_lock_irqsave(&data_lock, flags); + op->channel = -1; ovl->manager = NULL; @@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; - bool fifo_merge; int r; mutex_lock(&apply_lock); @@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) goto err1; } - if (ovl->manager == NULL || ovl->manager->device == NULL) { + if (ovl->manager == NULL || ovl->manager->output == NULL) { r = -EINVAL; goto err1; } @@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) goto err2; } - /* step 1: configure fifos/fifomerge for currently enabled ovls */ - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - /* wait for fifo configs to go in */ - wait_pending_extra_info_updates(); - - /* step 2: enable the overlay */ - spin_lock_irqsave(&data_lock, flags); + dss_setup_fifos(); op->enabling = false; dss_apply_ovl_enable(ovl, true); @@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) spin_unlock_irqrestore(&data_lock, flags); - /* wait for overlay to be enabled */ - wait_pending_extra_info_updates(); - mutex_unlock(&apply_lock); return 0; @@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; - bool fifo_merge; int r; mutex_lock(&apply_lock); @@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl) goto err; } - if (ovl->manager == NULL || ovl->manager->device == NULL) { + if (ovl->manager == NULL || ovl->manager->output == NULL) { r = -EINVAL; goto err; } - /* step 1: disable the overlay */ spin_lock_irqsave(&data_lock, flags); dss_apply_ovl_enable(ovl, false); - dss_write_regs(); dss_set_go_bits(); spin_unlock_irqrestore(&data_lock, flags); - /* wait for the overlay to be disabled */ - wait_pending_extra_info_updates(); - - /* step 2: configure fifos/fifomerge */ - spin_lock_irqsave(&data_lock, flags); - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - /* wait for fifo config to go in */ - wait_pending_extra_info_updates(); - mutex_unlock(&apply_lock); return 0; diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 58bd9c27369d..b2af72dc20bd 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -33,6 +33,7 @@ #include <linux/device.h> #include <linux/regulator/consumer.h> #include <linux/suspend.h> +#include <linux/slab.h> #include <video/omapdss.h> @@ -57,6 +58,11 @@ bool dss_debug; module_param_named(debug, dss_debug, bool, 0644); #endif +const char *dss_get_default_display_name(void) +{ + return core.default_display_name; +} + /* REGULATORS */ struct regulator *dss_get_vdds_dsi(void) @@ -347,17 +353,14 @@ static int dss_driver_probe(struct device *dev) int r; struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); struct omap_dss_device *dssdev = to_dss_device(dev); - bool force; DSSDBG("driver_probe: dev %s/%s, drv %s\n", dev_name(dev), dssdev->driver_name, dssdrv->driver.name); - dss_init_device(core.pdev, dssdev); - - force = core.default_display_name && - strcmp(core.default_display_name, dssdev->name) == 0; - dss_recheck_connections(dssdev, force); + r = dss_init_device(core.pdev, dssdev); + if (r) + return r; r = dssdrv->probe(dssdev); @@ -416,54 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver) EXPORT_SYMBOL(omap_dss_unregister_driver); /* DEVICE */ -static void reset_device(struct device *dev, int check) -{ - u8 *dev_p = (u8 *)dev; - u8 *dev_end = dev_p + sizeof(*dev); - void *saved_pdata; - - saved_pdata = dev->platform_data; - if (check) { - /* - * Check if there is any other setting than platform_data - * in struct device; warn that these will be reset by our - * init. - */ - dev->platform_data = NULL; - while (dev_p < dev_end) { - if (*dev_p) { - WARN("%s: struct device fields will be " - "discarded\n", - __func__); - break; - } - dev_p++; - } - } - memset(dev, 0, sizeof(*dev)); - dev->platform_data = saved_pdata; -} - static void omap_dss_dev_release(struct device *dev) { - reset_device(dev, 0); + struct omap_dss_device *dssdev = to_dss_device(dev); + kfree(dssdev); } -int omap_dss_register_device(struct omap_dss_device *dssdev, - struct device *parent, int disp_num) +static int disp_num_counter; + +struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) { - WARN_ON(!dssdev->driver_name); + struct omap_dss_device *dssdev; + + dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL); + if (!dssdev) + return NULL; - reset_device(&dssdev->dev, 1); dssdev->dev.bus = &dss_bus_type; dssdev->dev.parent = parent; dssdev->dev.release = omap_dss_dev_release; - dev_set_name(&dssdev->dev, "display%d", disp_num); - return device_register(&dssdev->dev); + dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); + + device_initialize(&dssdev->dev); + + return dssdev; +} + +int dss_add_device(struct omap_dss_device *dssdev) +{ + return device_add(&dssdev->dev); +} + +void dss_put_device(struct omap_dss_device *dssdev) +{ + put_device(&dssdev->dev); } -void omap_dss_unregister_device(struct omap_dss_device *dssdev) +void dss_unregister_device(struct omap_dss_device *dssdev) { device_unregister(&dssdev->dev); } @@ -471,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev) static int dss_unregister_dss_dev(struct device *dev, void *data) { struct omap_dss_device *dssdev = to_dss_device(dev); - omap_dss_unregister_device(dssdev); + dss_unregister_device(dssdev); return 0; } -void omap_dss_unregister_child_devices(struct device *parent) +void dss_unregister_child_devices(struct device *parent) { device_for_each_child(parent, NULL, dss_unregister_dss_dev); } +void dss_copy_device_pdata(struct omap_dss_device *dst, + const struct omap_dss_device *src) +{ + u8 *d = (u8 *)dst; + u8 *s = (u8 *)src; + size_t dsize = sizeof(struct device); + + memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize); +} + /* BUS */ static int __init omap_dss_bus_register(void) { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 5b289c5f695b..a173a9481a23 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -37,8 +37,6 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <plat/clock.h> - #include <video/omapdss.h> #include "dss.h" @@ -81,6 +79,30 @@ struct dispc_irq_stats { unsigned irqs[32]; }; +struct dispc_features { + u8 sw_start; + u8 fp_start; + u8 bp_start; + u16 sw_max; + u16 vp_max; + u16 hp_max; + int (*calc_scaling) (enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem); + unsigned long (*calc_core_clk) (enum omap_plane plane, + u16 width, u16 height, u16 out_width, u16 out_height, + bool mem_to_mem); + u8 num_fifos; + + /* swap GFX & WB fifos */ + bool gfx_fifo_workaround:1; +}; + +#define DISPC_MAX_NR_FIFOS 5 + static struct { struct platform_device *pdev; void __iomem *base; @@ -90,7 +112,9 @@ static struct { int irq; struct clk *dss_clk; - u32 fifo_size[MAX_DSS_OVERLAYS]; + u32 fifo_size[DISPC_MAX_NR_FIFOS]; + /* maps which plane is using a fifo. fifo-id -> plane-id */ + int fifo_assignment[DISPC_MAX_NR_FIFOS]; spinlock_t irq_lock; u32 irq_error_mask; @@ -101,6 +125,8 @@ static struct { bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + const struct dispc_features *feat; + #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spinlock_t irq_stats_lock; struct dispc_irq_stats irq_stats; @@ -210,7 +236,14 @@ static const struct { }, }; +struct color_conv_coef { + int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; + int full_range; +}; + static void _omap_dispc_set_irqs(void); +static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); +static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); static inline void dispc_write_reg(const u16 idx, u32 val) { @@ -508,6 +541,11 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) return mgr_desc[channel].framedone_irq; } +u32 dispc_wb_get_framedone_irq(void) +{ + return DISPC_IRQ_FRAMEDONEWB; +} + bool dispc_mgr_go_busy(enum omap_channel channel) { return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; @@ -535,6 +573,30 @@ void dispc_mgr_go(enum omap_channel channel) mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); } +bool dispc_wb_go_busy(void) +{ + return REG_GET(DISPC_CONTROL2, 6, 6) == 1; +} + +void dispc_wb_go(void) +{ + enum omap_plane plane = OMAP_DSS_WB; + bool enable, go; + + enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; + + if (!enable) + return; + + go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; + if (go) { + DSSERR("GO bit not down for WB\n"); + return; + } + + REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); +} + static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) { dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); @@ -617,41 +679,41 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, } } -static void _dispc_setup_color_conv_coef(void) -{ - int i; - const struct color_conv_coef { - int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; - int full_range; - } ctbl_bt601_5 = { - 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, - }; - - const struct color_conv_coef *ct; +static void dispc_ovl_write_color_conv_coef(enum omap_plane plane, + const struct color_conv_coef *ct) +{ #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) - ct = &ctbl_bt601_5; + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); - for (i = 1; i < dss_feat_get_num_ovls(); i++) { - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0), - CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1), - CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2), - CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3), - CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4), - CVAL(0, ct->bcb)); - - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range, - 11, 11); - } + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); #undef CVAL } +static void dispc_setup_color_conv_coef(void) +{ + int i; + int num_ovl = dss_feat_get_num_ovls(); + int num_wb = dss_feat_get_num_wbs(); + const struct color_conv_coef ctbl_bt601_5_ovl = { + 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, + }; + const struct color_conv_coef ctbl_bt601_5_wb = { + 66, 112, -38, 129, -94, -74, 25, -18, 112, 0, + }; + + for (i = 1; i < num_ovl; i++) + dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); + + for (; i < num_wb; i++) + dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb); +} static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) { @@ -673,24 +735,32 @@ static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); } -static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) +static void dispc_ovl_set_pos(enum omap_plane plane, + enum omap_overlay_caps caps, int x, int y) { - u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); + u32 val; + + if ((caps & OMAP_DSS_OVL_CAP_POS) == 0) + return; + + val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); dispc_write_reg(DISPC_OVL_POSITION(plane), val); } -static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_input_size(enum omap_plane plane, int width, + int height) { u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - if (plane == OMAP_DSS_GFX) + if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) dispc_write_reg(DISPC_OVL_SIZE(plane), val); else dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); } -static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_output_size(enum omap_plane plane, int width, + int height) { u32 val; @@ -698,14 +768,16 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - dispc_write_reg(DISPC_OVL_SIZE(plane), val); + if (plane == OMAP_DSS_WB) + dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); + else + dispc_write_reg(DISPC_OVL_SIZE(plane), val); } -static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) +static void dispc_ovl_set_zorder(enum omap_plane plane, + enum omap_overlay_caps caps, u8 zorder) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) return; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); @@ -722,23 +794,22 @@ static void dispc_ovl_enable_zorder_planes(void) REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); } -static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) +static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, + enum omap_overlay_caps caps, bool enable) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) + if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) return; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); } -static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) +static void dispc_ovl_setup_global_alpha(enum omap_plane plane, + enum omap_overlay_caps caps, u8 global_alpha) { static const unsigned shifts[] = { 0, 8, 16, 24, }; int shift; - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) + if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) return; shift = shifts[plane]; @@ -946,10 +1017,17 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) return channel; } +void dispc_wb_set_channel_in(enum dss_writeback_channel channel) +{ + enum omap_plane plane = OMAP_DSS_WB; + + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); +} + static void dispc_ovl_set_burst_size(enum omap_plane plane, enum omap_burst_size burst_size) { - static const unsigned shifts[] = { 6, 14, 14, 14, }; + static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; int shift; shift = shifts[plane]; @@ -1026,11 +1104,15 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } -static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) +static void dispc_ovl_enable_replication(enum omap_plane plane, + enum omap_overlay_caps caps, bool enable) { static const unsigned shifts[] = { 5, 10, 10, 10 }; int shift; + if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) + return; + shift = shifts[plane]; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); } @@ -1044,10 +1126,10 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width, dispc_write_reg(DISPC_SIZE_MGR(channel), val); } -static void dispc_read_plane_fifo_sizes(void) +static void dispc_init_fifos(void) { u32 size; - int plane; + int fifo; u8 start, end; u32 unit; @@ -1055,16 +1137,53 @@ static void dispc_read_plane_fifo_sizes(void) dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); - for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) { - size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); + for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { + size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); size *= unit; - dispc.fifo_size[plane] = size; + dispc.fifo_size[fifo] = size; + + /* + * By default fifos are mapped directly to overlays, fifo 0 to + * ovl 0, fifo 1 to ovl 1, etc. + */ + dispc.fifo_assignment[fifo] = fifo; + } + + /* + * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo + * causes problems with certain use cases, like using the tiler in 2D + * mode. The below hack swaps the fifos of GFX and WB planes, thus + * giving GFX plane a larger fifo. WB but should work fine with a + * smaller fifo. + */ + if (dispc.feat->gfx_fifo_workaround) { + u32 v; + + v = dispc_read_reg(DISPC_GLOBAL_BUFFER); + + v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ + v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ + v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ + v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ + + dispc_write_reg(DISPC_GLOBAL_BUFFER, v); + + dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; + dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; } } static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) { - return dispc.fifo_size[plane]; + int fifo; + u32 size = 0; + + for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { + if (dispc.fifo_assignment[fifo] == plane) + size += dispc.fifo_size[fifo]; + } + + return size; } void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) @@ -1140,6 +1259,14 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { *fifo_low = ovl_fifo_size - burst_size * 2; *fifo_high = total_fifo_size - burst_size; + } else if (plane == OMAP_DSS_WB) { + /* + * Most optimal configuration for writeback is to push out data + * to the interconnect the moment writeback pushes enough pixels + * in the FIFO to form a burst + */ + *fifo_low = 0; + *fifo_high = burst_size; } else { *fifo_low = ovl_fifo_size - burst_size; *fifo_high = total_fifo_size - buf_unit; @@ -1382,6 +1509,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, { int scale_x = out_width != orig_width; int scale_y = out_height != orig_height; + bool chroma_upscale = plane != OMAP_DSS_WB ? true : false; if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) return; @@ -1389,7 +1517,8 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, color_mode != OMAP_DSS_COLOR_UYVY && color_mode != OMAP_DSS_COLOR_NV12)) { /* reset chroma resampling for RGB formats */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); + if (plane != OMAP_DSS_WB) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); return; } @@ -1398,23 +1527,34 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, switch (color_mode) { case OMAP_DSS_COLOR_NV12: - /* UV is subsampled by 2 vertically*/ - orig_height >>= 1; - /* UV is subsampled by 2 horz.*/ - orig_width >>= 1; + if (chroma_upscale) { + /* UV is subsampled by 2 horizontally and vertically */ + orig_height >>= 1; + orig_width >>= 1; + } else { + /* UV is downsampled by 2 horizontally and vertically */ + orig_height <<= 1; + orig_width <<= 1; + } + break; case OMAP_DSS_COLOR_YUV2: case OMAP_DSS_COLOR_UYVY: - /*For YUV422 with 90/270 rotation, - *we don't upsample chroma - */ + /* For YUV422 with 90/270 rotation, we don't upsample chroma */ if (rotation == OMAP_DSS_ROT_0 || - rotation == OMAP_DSS_ROT_180) - /* UV is subsampled by 2 hrz*/ - orig_width >>= 1; + rotation == OMAP_DSS_ROT_180) { + if (chroma_upscale) + /* UV is subsampled by 2 horizontally */ + orig_width >>= 1; + else + /* UV is downsampled by 2 horizontally */ + orig_width <<= 1; + } + /* must use FIR for YUV422 if rotated */ if (rotation != OMAP_DSS_ROT_0) scale_x = scale_y = true; + break; default: BUG(); @@ -1430,8 +1570,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, out_width, out_height, five_taps, rotation, DISPC_COLOR_COMPONENT_UV); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), - (scale_x || scale_y) ? 1 : 0, 8, 8); + if (plane != OMAP_DSS_WB) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), + (scale_x || scale_y) ? 1 : 0, 8, 8); + /* set H scaling */ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); /* set V scaling */ @@ -1847,22 +1989,19 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width, * This function is used to avoid synclosts in OMAP3, because of some * undocumented horizontal position and timing related limitations. */ -static int check_horiz_timing_omap3(enum omap_channel channel, +static int check_horiz_timing_omap3(enum omap_plane plane, const struct omap_video_timings *t, u16 pos_x, u16 width, u16 height, u16 out_width, u16 out_height) { int DS = DIV_ROUND_UP(height, out_height); - unsigned long nonactive, lclk, pclk; + unsigned long nonactive; static const u8 limits[3] = { 8, 10, 20 }; u64 val, blank; + unsigned long pclk = dispc_plane_pclk_rate(plane); + unsigned long lclk = dispc_plane_lclk_rate(plane); int i; nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; - pclk = dispc_mgr_pclk_rate(channel); - if (dss_mgr_is_lcd(channel)) - lclk = dispc_mgr_lclk_rate(channel); - else - lclk = dispc_fclk_rate(); i = 0; if (out_height < height) @@ -1899,13 +2038,14 @@ static int check_horiz_timing_omap3(enum omap_channel channel, return 0; } -static unsigned long calc_core_clk_five_taps(enum omap_channel channel, +static unsigned long calc_core_clk_five_taps(enum omap_plane plane, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode) { u32 core_clk = 0; - u64 tmp, pclk = dispc_mgr_pclk_rate(channel); + u64 tmp; + unsigned long pclk = dispc_plane_pclk_rate(plane); if (height <= out_height && width <= out_width) return (unsigned long) pclk; @@ -1939,11 +2079,22 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel, return core_clk; } -static unsigned long calc_core_clk(enum omap_channel channel, u16 width, - u16 height, u16 out_width, u16 out_height) +static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) +{ + unsigned long pclk = dispc_plane_pclk_rate(plane); + + if (height > out_height && width > out_width) + return pclk * 4; + else + return pclk * 2; +} + +static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) { unsigned int hf, vf; - unsigned long pclk = dispc_mgr_pclk_rate(channel); + unsigned long pclk = dispc_plane_pclk_rate(plane); /* * FIXME how to determine the 'A' factor @@ -1958,51 +2109,207 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width, hf = 2; else hf = 1; - if (height > out_height) vf = 2; else vf = 1; - if (cpu_is_omap24xx()) { - if (vf > 1 && hf > 1) - return pclk * 4; - else - return pclk * 2; - } else if (cpu_is_omap34xx()) { - return pclk * vf * hf; - } else { - if (hf > 1) - return DIV_ROUND_UP(pclk, out_width) * width; - else - return pclk; + return pclk * vf * hf; +} + +static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) +{ + unsigned long pclk; + + /* + * If the overlay/writeback is in mem to mem mode, there are no + * downscaling limitations with respect to pixel clock, return 1 as + * required core clock to represent that we have sufficient enough + * core clock to do maximum downscaling + */ + if (mem_to_mem) + return 1; + + pclk = dispc_plane_pclk_rate(plane); + + if (width > out_width) + return DIV_ROUND_UP(pclk, out_width) * width; + else + return pclk; +} + +static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +{ + int error; + u16 in_width, in_height; + int min_factor = min(*decim_x, *decim_y); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + + *five_taps = false; + + do { + in_height = DIV_ROUND_UP(height, *decim_y); + in_width = DIV_ROUND_UP(width, *decim_x); + *core_clk = dispc.feat->calc_core_clk(plane, in_width, + in_height, out_width, out_height, mem_to_mem); + error = (in_width > maxsinglelinewidth || !*core_clk || + *core_clk > dispc_core_clk_rate()); + if (error) { + if (*decim_x == *decim_y) { + *decim_x = min_factor; + ++*decim_y; + } else { + swap(*decim_x, *decim_y); + if (*decim_x < *decim_y) + ++*decim_x; + } + } + } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); + + if (in_width > maxsinglelinewidth) { + DSSERR("Cannot scale max input width exceeded"); + return -EINVAL; } + return 0; } -static int dispc_ovl_calc_scaling(enum omap_plane plane, - enum omap_channel channel, +static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool *five_taps, - int *x_predecim, int *y_predecim, u16 pos_x) + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + int error; + u16 in_width, in_height; + int min_factor = min(*decim_x, *decim_y); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + + do { + in_height = DIV_ROUND_UP(height, *decim_y); + in_width = DIV_ROUND_UP(width, *decim_x); + *core_clk = calc_core_clk_five_taps(plane, mgr_timings, + in_width, in_height, out_width, out_height, color_mode); + + error = check_horiz_timing_omap3(plane, mgr_timings, + pos_x, in_width, in_height, out_width, + out_height); + + if (in_width > maxsinglelinewidth) + if (in_height > out_height && + in_height < out_height * 2) + *five_taps = false; + if (!*five_taps) + *core_clk = dispc.feat->calc_core_clk(plane, in_width, + in_height, out_width, out_height, + mem_to_mem); + + error = (error || in_width > maxsinglelinewidth * 2 || + (in_width > maxsinglelinewidth && *five_taps) || + !*core_clk || *core_clk > dispc_core_clk_rate()); + if (error) { + if (*decim_x == *decim_y) { + *decim_x = min_factor; + ++*decim_y; + } else { + swap(*decim_x, *decim_y); + if (*decim_x < *decim_y) + ++*decim_x; + } + } + } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); + + if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height, + out_width, out_height)){ + DSSERR("horizontal timing too tight\n"); + return -EINVAL; + } + + if (in_width > (maxsinglelinewidth * 2)) { + DSSERR("Cannot setup scaling"); + DSSERR("width exceeds maximum width possible"); + return -EINVAL; + } + + if (in_width > maxsinglelinewidth && *five_taps) { + DSSERR("cannot setup scaling with five taps"); + return -EINVAL; + } + return 0; +} + +static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +{ + u16 in_width, in_width_max; + int decim_x_min = *decim_x; + u16 in_height = DIV_ROUND_UP(height, *decim_y); const int maxsinglelinewidth = dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + unsigned long pclk = dispc_plane_pclk_rate(plane); + const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + + if (mem_to_mem) + in_width_max = DIV_ROUND_UP(out_width, maxdownscale); + else + in_width_max = dispc_core_clk_rate() / + DIV_ROUND_UP(pclk, out_width); + + *decim_x = DIV_ROUND_UP(width, in_width_max); + + *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; + if (*decim_x > *x_predecim) + return -EINVAL; + + do { + in_width = DIV_ROUND_UP(width, *decim_x); + } while (*decim_x <= *x_predecim && + in_width > maxsinglelinewidth && ++*decim_x); + + if (in_width > maxsinglelinewidth) { + DSSERR("Cannot scale width exceeds max line width"); + return -EINVAL; + } + + *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height, + out_width, out_height, mem_to_mem); + return 0; +} + +static int dispc_ovl_calc_scaling(enum omap_plane plane, + enum omap_overlay_caps caps, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, u16 pos_x, + enum omap_dss_rotation_type rotation_type, bool mem_to_mem) +{ + const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); const int max_decim_limit = 16; unsigned long core_clk = 0; - int decim_x, decim_y, error, min_factor; - u16 in_width, in_height, in_width_max = 0; + int decim_x, decim_y, ret; if (width == out_width && height == out_height) return 0; - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) + if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) return -EINVAL; *x_predecim = max_decim_limit; - *y_predecim = max_decim_limit; + *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && + dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit; if (color_mode == OMAP_DSS_COLOR_CLUT1 || color_mode == OMAP_DSS_COLOR_CLUT2 || @@ -2017,118 +2324,18 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); - min_factor = min(decim_x, decim_y); - if (decim_x > *x_predecim || out_width > width * 8) return -EINVAL; if (decim_y > *y_predecim || out_height > height * 8) return -EINVAL; - if (cpu_is_omap24xx()) { - *five_taps = false; - - do { - in_height = DIV_ROUND_UP(height, decim_y); - in_width = DIV_ROUND_UP(width, decim_x); - core_clk = calc_core_clk(channel, in_width, in_height, - out_width, out_height); - error = (in_width > maxsinglelinewidth || !core_clk || - core_clk > dispc_core_clk_rate()); - if (error) { - if (decim_x == decim_y) { - decim_x = min_factor; - decim_y++; - } else { - swap(decim_x, decim_y); - if (decim_x < decim_y) - decim_x++; - } - } - } while (decim_x <= *x_predecim && decim_y <= *y_predecim && - error); - - if (in_width > maxsinglelinewidth) { - DSSERR("Cannot scale max input width exceeded"); - return -EINVAL; - } - } else if (cpu_is_omap34xx()) { - - do { - in_height = DIV_ROUND_UP(height, decim_y); - in_width = DIV_ROUND_UP(width, decim_x); - core_clk = calc_core_clk_five_taps(channel, mgr_timings, - in_width, in_height, out_width, out_height, - color_mode); - - error = check_horiz_timing_omap3(channel, mgr_timings, - pos_x, in_width, in_height, out_width, - out_height); - - if (in_width > maxsinglelinewidth) - if (in_height > out_height && - in_height < out_height * 2) - *five_taps = false; - if (!*five_taps) - core_clk = calc_core_clk(channel, in_width, - in_height, out_width, out_height); - error = (error || in_width > maxsinglelinewidth * 2 || - (in_width > maxsinglelinewidth && *five_taps) || - !core_clk || core_clk > dispc_core_clk_rate()); - if (error) { - if (decim_x == decim_y) { - decim_x = min_factor; - decim_y++; - } else { - swap(decim_x, decim_y); - if (decim_x < decim_y) - decim_x++; - } - } - } while (decim_x <= *x_predecim && decim_y <= *y_predecim - && error); - - if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, - height, out_width, out_height)){ - DSSERR("horizontal timing too tight\n"); - return -EINVAL; - } - - if (in_width > (maxsinglelinewidth * 2)) { - DSSERR("Cannot setup scaling"); - DSSERR("width exceeds maximum width possible"); - return -EINVAL; - } - - if (in_width > maxsinglelinewidth && *five_taps) { - DSSERR("cannot setup scaling with five taps"); - return -EINVAL; - } - } else { - int decim_x_min = decim_x; - in_height = DIV_ROUND_UP(height, decim_y); - in_width_max = dispc_core_clk_rate() / - DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), - out_width); - decim_x = DIV_ROUND_UP(width, in_width_max); - - decim_x = decim_x > decim_x_min ? decim_x : decim_x_min; - if (decim_x > *x_predecim) - return -EINVAL; - - do { - in_width = DIV_ROUND_UP(width, decim_x); - } while (decim_x <= *x_predecim && - in_width > maxsinglelinewidth && decim_x++); - - if (in_width > maxsinglelinewidth) { - DSSERR("Cannot scale width exceeds max line width"); - return -EINVAL; - } - - core_clk = calc_core_clk(channel, in_width, in_height, - out_width, out_height); - } + ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height, + out_width, out_height, color_mode, five_taps, + x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, + mem_to_mem); + if (ret) + return ret; DSSDBG("required core clk rate = %lu Hz\n", core_clk); DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); @@ -2146,69 +2353,64 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, return 0; } -int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool replication, const struct omap_video_timings *mgr_timings) +static int dispc_ovl_setup_common(enum omap_plane plane, + enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, + u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, + u16 out_width, u16 out_height, enum omap_color_mode color_mode, + u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha, + u8 global_alpha, enum omap_dss_rotation_type rotation_type, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); bool five_taps = true; bool fieldmode = 0; int r, cconv = 0; unsigned offset0, offset1; s32 row_inc; s32 pix_inc; - u16 frame_height = oi->height; + u16 frame_height = height; unsigned int field_offset = 0; - u16 in_height = oi->height; - u16 in_width = oi->width; - u16 out_width, out_height; - enum omap_channel channel; + u16 in_height = height; + u16 in_width = width; int x_predecim = 1, y_predecim = 1; bool ilace = mgr_timings->interlace; - channel = dispc_ovl_get_channel_out(plane); - - DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", - plane, oi->paddr, oi->p_uv_addr, - oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, - oi->out_width, oi->out_height, oi->color_mode, oi->rotation, - oi->mirror, ilace, channel, replication); - - if (oi->paddr == 0) + if (paddr == 0) return -EINVAL; - out_width = oi->out_width == 0 ? oi->width : oi->out_width; - out_height = oi->out_height == 0 ? oi->height : oi->out_height; + out_width = out_width == 0 ? width : out_width; + out_height = out_height == 0 ? height : out_height; - if (ilace && oi->height == out_height) + if (ilace && height == out_height) fieldmode = 1; if (ilace) { if (fieldmode) in_height /= 2; - oi->pos_y /= 2; + pos_y /= 2; out_height /= 2; DSSDBG("adjusting for ilace: height %d, pos_y %d, " - "out_height %d\n", - in_height, oi->pos_y, out_height); + "out_height %d\n", in_height, pos_y, + out_height); } - if (!dss_feat_color_mode_supported(plane, oi->color_mode)) + if (!dss_feat_color_mode_supported(plane, color_mode)) return -EINVAL; - r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width, - in_height, out_width, out_height, oi->color_mode, - &five_taps, &x_predecim, &y_predecim, oi->pos_x); + r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width, + in_height, out_width, out_height, color_mode, + &five_taps, &x_predecim, &y_predecim, pos_x, + rotation_type, mem_to_mem); if (r) return r; in_width = DIV_ROUND_UP(in_width, x_predecim); in_height = DIV_ROUND_UP(in_height, y_predecim); - if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || - oi->color_mode == OMAP_DSS_COLOR_UYVY || - oi->color_mode == OMAP_DSS_COLOR_NV12) + if (color_mode == OMAP_DSS_COLOR_YUV2 || + color_mode == OMAP_DSS_COLOR_UYVY || + color_mode == OMAP_DSS_COLOR_NV12) cconv = 1; if (ilace && !fieldmode) { @@ -2234,70 +2436,144 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, row_inc = 0; pix_inc = 0; - if (oi->rotation_type == OMAP_DSS_ROT_TILER) - calc_tiler_rotation_offset(oi->screen_width, in_width, - oi->color_mode, fieldmode, field_offset, + if (rotation_type == OMAP_DSS_ROT_TILER) + calc_tiler_rotation_offset(screen_width, in_width, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); - else if (oi->rotation_type == OMAP_DSS_ROT_DMA) - calc_dma_rotation_offset(oi->rotation, oi->mirror, - oi->screen_width, in_width, frame_height, - oi->color_mode, fieldmode, field_offset, + else if (rotation_type == OMAP_DSS_ROT_DMA) + calc_dma_rotation_offset(rotation, mirror, + screen_width, in_width, frame_height, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); else - calc_vrfb_rotation_offset(oi->rotation, oi->mirror, - oi->screen_width, in_width, frame_height, - oi->color_mode, fieldmode, field_offset, + calc_vrfb_rotation_offset(rotation, mirror, + screen_width, in_width, frame_height, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", offset0, offset1, row_inc, pix_inc); - dispc_ovl_set_color_mode(plane, oi->color_mode); + dispc_ovl_set_color_mode(plane, color_mode); - dispc_ovl_configure_burst_type(plane, oi->rotation_type); + dispc_ovl_configure_burst_type(plane, rotation_type); - dispc_ovl_set_ba0(plane, oi->paddr + offset0); - dispc_ovl_set_ba1(plane, oi->paddr + offset1); + dispc_ovl_set_ba0(plane, paddr + offset0); + dispc_ovl_set_ba1(plane, paddr + offset1); - if (OMAP_DSS_COLOR_NV12 == oi->color_mode) { - dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0); - dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1); + if (OMAP_DSS_COLOR_NV12 == color_mode) { + dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); + dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); } - dispc_ovl_set_row_inc(plane, row_inc); dispc_ovl_set_pix_inc(plane, pix_inc); - DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width, + DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, in_height, out_width, out_height); - dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); + dispc_ovl_set_pos(plane, caps, pos_x, pos_y); - dispc_ovl_set_pic_size(plane, in_width, in_height); + dispc_ovl_set_input_size(plane, in_width, in_height); - if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { + if (caps & OMAP_DSS_OVL_CAP_SCALE) { dispc_ovl_set_scaling(plane, in_width, in_height, out_width, out_height, ilace, five_taps, fieldmode, - oi->color_mode, oi->rotation); - dispc_ovl_set_vid_size(plane, out_width, out_height); + color_mode, rotation); + dispc_ovl_set_output_size(plane, out_width, out_height); dispc_ovl_set_vid_color_conv(plane, cconv); } - dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror, - oi->color_mode); + dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); - dispc_ovl_set_zorder(plane, oi->zorder); - dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); - dispc_ovl_setup_global_alpha(plane, oi->global_alpha); + dispc_ovl_set_zorder(plane, caps, zorder); + dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); + dispc_ovl_setup_global_alpha(plane, caps, global_alpha); - dispc_ovl_enable_replication(plane, replication); + dispc_ovl_enable_replication(plane, caps, replication); return 0; } +int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem) +{ + int r; + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + enum omap_channel channel; + + channel = dispc_ovl_get_channel_out(plane); + + DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " + "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", + plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, + oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, + oi->color_mode, oi->rotation, oi->mirror, channel, replication); + + r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr, + oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, + oi->out_width, oi->out_height, oi->color_mode, oi->rotation, + oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, + oi->rotation_type, replication, mgr_timings, mem_to_mem); + + return r; +} + +int dispc_wb_setup(const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct omap_video_timings *mgr_timings) +{ + int r; + u32 l; + enum omap_plane plane = OMAP_DSS_WB; + const int pos_x = 0, pos_y = 0; + const u8 zorder = 0, global_alpha = 0; + const bool replication = false; + bool truncation; + int in_width = mgr_timings->x_res; + int in_height = mgr_timings->y_res; + enum omap_overlay_caps caps = + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; + + DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " + "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width, + in_height, wi->width, wi->height, wi->color_mode, wi->rotation, + wi->mirror); + + r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, + wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, + wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder, + wi->pre_mult_alpha, global_alpha, wi->rotation_type, + replication, mgr_timings, mem_to_mem); + + switch (wi->color_mode) { + case OMAP_DSS_COLOR_RGB16: + case OMAP_DSS_COLOR_RGB24P: + case OMAP_DSS_COLOR_ARGB16: + case OMAP_DSS_COLOR_RGBA16: + case OMAP_DSS_COLOR_RGB12U: + case OMAP_DSS_COLOR_ARGB16_1555: + case OMAP_DSS_COLOR_XRGB16_1555: + case OMAP_DSS_COLOR_RGBX16: + truncation = true; + break; + default: + truncation = false; + break; + } + + /* setup extra DISPC_WB_ATTRIBUTES */ + l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ + l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ + dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); + + return r; +} + int dispc_ovl_enable(enum omap_plane plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); @@ -2450,6 +2726,47 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable) BUG(); } +void dispc_wb_enable(bool enable) +{ + enum omap_plane plane = OMAP_DSS_WB; + struct completion frame_done_completion; + bool is_on; + int r; + u32 irq; + + is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); + irq = DISPC_IRQ_FRAMEDONEWB; + + if (!enable && is_on) { + init_completion(&frame_done_completion); + + r = omap_dispc_register_isr(dispc_disable_isr, + &frame_done_completion, irq); + if (r) + DSSERR("failed to register FRAMEDONEWB isr\n"); + } + + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); + + if (!enable && is_on) { + if (!wait_for_completion_timeout(&frame_done_completion, + msecs_to_jiffies(100))) + DSSERR("timeout waiting for FRAMEDONEWB\n"); + + r = omap_dispc_unregister_isr(dispc_disable_isr, + &frame_done_completion, irq); + if (r) + DSSERR("failed to unregister FRAMEDONEWB isr\n"); + } +} + +bool dispc_wb_is_enabled(void) +{ + enum omap_plane plane = OMAP_DSS_WB; + + return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); +} + void dispc_lcd_enable_signal_polarity(bool act_high) { if (!dss_has_feature(FEAT_LCDENABLEPOL)) @@ -2604,24 +2921,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height) static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, int vsw, int vfp, int vbp) { - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { - if (hsw < 1 || hsw > 64 || - hfp < 1 || hfp > 256 || - hbp < 1 || hbp > 256 || - vsw < 1 || vsw > 64 || - vfp < 0 || vfp > 255 || - vbp < 0 || vbp > 255) - return false; - } else { - if (hsw < 1 || hsw > 256 || - hfp < 1 || hfp > 4096 || - hbp < 1 || hbp > 4096 || - vsw < 1 || vsw > 256 || - vfp < 0 || vfp > 4095 || - vbp < 0 || vbp > 4095) - return false; - } - + if (hsw < 1 || hsw > dispc.feat->sw_max || + hfp < 1 || hfp > dispc.feat->hp_max || + hbp < 1 || hbp > dispc.feat->hp_max || + vsw < 1 || vsw > dispc.feat->sw_max || + vfp < 0 || vfp > dispc.feat->vp_max || + vbp < 0 || vbp > dispc.feat->vp_max) + return false; return true; } @@ -2653,19 +2959,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, u32 timing_h, timing_v, l; bool onoff, rf, ipc; - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { - timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | - FLD_VAL(hbp-1, 27, 20); - - timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | - FLD_VAL(vbp, 27, 20); - } else { - timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) | - FLD_VAL(hbp-1, 31, 20); - - timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) | - FLD_VAL(vbp, 31, 20); - } + timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) | + FLD_VAL(hfp-1, dispc.feat->fp_start, 8) | + FLD_VAL(hbp-1, dispc.feat->bp_start, 20); + timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) | + FLD_VAL(vfp, dispc.feat->fp_start, 8) | + FLD_VAL(vbp, dispc.feat->bp_start, 20); dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_V(channel), timing_v); @@ -2871,6 +3170,23 @@ unsigned long dispc_core_clk_rate(void) return fclk / lcd; } +static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) +{ + enum omap_channel channel = dispc_ovl_get_channel_out(plane); + + return dispc_mgr_pclk_rate(channel); +} + +static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) +{ + enum omap_channel channel = dispc_ovl_get_channel_out(plane); + + if (dss_mgr_is_lcd(channel)) + return dispc_mgr_lclk_rate(channel); + else + return dispc_fclk_rate(); + +} static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) { int lcd, pcd; @@ -3491,7 +3807,7 @@ static void dispc_error_worker(struct work_struct *work) ovl->name); dispc_ovl_enable(ovl->id, false); dispc_mgr_go(ovl->manager->id); - mdelay(50); + msleep(50); } } @@ -3503,7 +3819,7 @@ static void dispc_error_worker(struct work_struct *work) bit = mgr_desc[i].sync_lost_irq; if (bit & errors) { - struct omap_dss_device *dssdev = mgr->device; + struct omap_dss_device *dssdev = mgr->get_device(mgr); bool enable; DSSERR("SYNC_LOST on channel %s, restarting the output " @@ -3523,7 +3839,7 @@ static void dispc_error_worker(struct work_struct *work) } dispc_mgr_go(mgr->id); - mdelay(50); + msleep(50); if (enable) dssdev->driver->enable(dssdev); @@ -3534,9 +3850,13 @@ static void dispc_error_worker(struct work_struct *work) DSSERR("OCP_ERR\n"); for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { struct omap_overlay_manager *mgr; + struct omap_dss_device *dssdev; + mgr = omap_dss_get_overlay_manager(i); - if (mgr->device && mgr->device->driver) - mgr->device->driver->disable(mgr->device); + dssdev = mgr->get_device(mgr); + + if (dssdev && dssdev->driver) + dssdev->driver->disable(dssdev); } } @@ -3660,17 +3980,98 @@ static void _omap_dispc_initial_config(void) if (dss_has_feature(FEAT_FUNCGATED)) REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); - _dispc_setup_color_conv_coef(); + dispc_setup_color_conv_coef(); dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); - dispc_read_plane_fifo_sizes(); + dispc_init_fifos(); dispc_configure_burst_sizes(); dispc_ovl_enable_zorder_planes(); } +static const struct dispc_features omap24xx_dispc_feats __initconst = { + .sw_start = 5, + .fp_start = 15, + .bp_start = 27, + .sw_max = 64, + .vp_max = 255, + .hp_max = 256, + .calc_scaling = dispc_ovl_calc_scaling_24xx, + .calc_core_clk = calc_core_clk_24xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { + .sw_start = 5, + .fp_start = 15, + .bp_start = 27, + .sw_max = 64, + .vp_max = 255, + .hp_max = 256, + .calc_scaling = dispc_ovl_calc_scaling_34xx, + .calc_core_clk = calc_core_clk_34xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { + .sw_start = 7, + .fp_start = 19, + .bp_start = 31, + .sw_max = 256, + .vp_max = 4095, + .hp_max = 4096, + .calc_scaling = dispc_ovl_calc_scaling_34xx, + .calc_core_clk = calc_core_clk_34xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap44xx_dispc_feats __initconst = { + .sw_start = 7, + .fp_start = 19, + .bp_start = 31, + .sw_max = 256, + .vp_max = 4095, + .hp_max = 4096, + .calc_scaling = dispc_ovl_calc_scaling_44xx, + .calc_core_clk = calc_core_clk_44xx, + .num_fifos = 5, + .gfx_fifo_workaround = true, +}; + +static int __init dispc_init_features(struct device *dev) +{ + const struct dispc_features *src; + struct dispc_features *dst; + + dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + if (!dst) { + dev_err(dev, "Failed to allocate DISPC Features\n"); + return -ENOMEM; + } + + if (cpu_is_omap24xx()) { + src = &omap24xx_dispc_feats; + } else if (cpu_is_omap34xx()) { + if (omap_rev() < OMAP3430_REV_ES3_0) + src = &omap34xx_rev1_0_dispc_feats; + else + src = &omap34xx_rev3_0_dispc_feats; + } else if (cpu_is_omap44xx()) { + src = &omap44xx_dispc_feats; + } else if (soc_is_omap54xx()) { + src = &omap44xx_dispc_feats; + } else { + return -ENODEV; + } + + memcpy(dst, src, sizeof(*dst)); + dispc.feat = dst; + + return 0; +} + /* DISPC HW IP initialisation */ static int __init omap_dispchw_probe(struct platform_device *pdev) { @@ -3681,6 +4082,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) dispc.pdev = pdev; + r = dispc_init_features(&dispc.pdev->dev); + if (r) + return r; + spin_lock_init(&dispc.irq_lock); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 92d8a9be86fc..222363c6e623 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -36,6 +36,7 @@ #define DISPC_CONTROL2 0x0238 #define DISPC_CONFIG2 0x0620 #define DISPC_DIVISOR 0x0804 +#define DISPC_GLOBAL_BUFFER 0x0800 #define DISPC_CONTROL3 0x0848 #define DISPC_CONFIG3 0x084C @@ -355,6 +356,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane) return 0x014C; case OMAP_DSS_VIDEO3: return 0x0300; + case OMAP_DSS_WB: + return 0x0500; default: BUG(); return 0; @@ -370,6 +373,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0000; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0008; default: BUG(); @@ -385,6 +389,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0004; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x000C; default: BUG(); @@ -404,6 +409,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) return 0x04BC; case OMAP_DSS_VIDEO3: return 0x0310; + case OMAP_DSS_WB: + return 0x0118; default: BUG(); return 0; @@ -422,6 +429,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) return 0x04C0; case OMAP_DSS_VIDEO3: return 0x0314; + case OMAP_DSS_WB: + return 0x011C; default: BUG(); return 0; @@ -451,6 +460,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x000C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x00A8; default: BUG(); @@ -467,6 +477,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0010; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0070; default: BUG(); @@ -486,6 +497,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) return 0x04DC; case OMAP_DSS_VIDEO3: return 0x032C; + case OMAP_DSS_WB: + return 0x0310; default: BUG(); return 0; @@ -501,6 +514,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0014; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x008C; default: BUG(); @@ -517,6 +531,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0018; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0088; default: BUG(); @@ -533,6 +548,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x001C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x00A4; default: BUG(); @@ -549,6 +565,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0020; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0098; default: BUG(); @@ -598,6 +615,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0024; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0090; default: BUG(); @@ -617,6 +635,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) return 0x055C; case OMAP_DSS_VIDEO3: return 0x0424; + case OMAP_DSS_WB: + return 0x290; default: BUG(); return 0; @@ -633,6 +653,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0028; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0094; default: BUG(); @@ -651,6 +672,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x002C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0000; default: BUG(); @@ -670,6 +692,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) return 0x0560; case OMAP_DSS_VIDEO3: return 0x0428; + case OMAP_DSS_WB: + return 0x0294; default: BUG(); return 0; @@ -686,6 +710,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0030; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0004; default: BUG(); @@ -705,6 +730,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) return 0x0564; case OMAP_DSS_VIDEO3: return 0x042C; + case OMAP_DSS_WB: + return 0x0298; default: BUG(); return 0; @@ -722,6 +749,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x0034 + i * 0x8; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0010 + i * 0x8; default: BUG(); @@ -742,6 +770,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) return 0x0568 + i * 0x8; case OMAP_DSS_VIDEO3: return 0x0430 + i * 0x8; + case OMAP_DSS_WB: + return 0x02A0 + i * 0x8; default: BUG(); return 0; @@ -759,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x0038 + i * 0x8; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0014 + i * 0x8; default: BUG(); @@ -779,6 +810,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) return 0x056C + i * 0x8; case OMAP_DSS_VIDEO3: return 0x0434 + i * 0x8; + case OMAP_DSS_WB: + return 0x02A4 + i * 0x8; default: BUG(); return 0; @@ -795,6 +828,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0074 + i * 0x4; default: BUG(); @@ -814,6 +848,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x00B4 + i * 0x4; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0050 + i * 0x4; default: BUG(); @@ -834,6 +869,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) return 0x05A8 + i * 0x4; case OMAP_DSS_VIDEO3: return 0x0470 + i * 0x4; + case OMAP_DSS_WB: + return 0x02E0 + i * 0x4; default: BUG(); return 0; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 5bd957e85505..ccf8550fafde 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -142,7 +142,11 @@ static ssize_t display_timings_store(struct device *dev, if (r) return r; + dssdev->driver->disable(dssdev); dssdev->driver->set_timings(dssdev, &t); + r = dssdev->driver->enable(dssdev); + if (r) + return r; return size; } @@ -316,26 +320,117 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_default_get_timings); -void dss_init_device(struct platform_device *pdev, +/* + * Connect dssdev to a manager if the manager is free or if force is specified. + * Connect all overlays to that manager if they are free or if force is + * specified. + */ +static int dss_init_connections(struct omap_dss_device *dssdev, bool force) +{ + struct omap_dss_output *out; + struct omap_overlay_manager *mgr; + int i, r; + + out = omapdss_get_output_from_dssdev(dssdev); + + WARN_ON(dssdev->output); + WARN_ON(out->device); + + r = omapdss_output_set_device(out, dssdev); + if (r) { + DSSERR("failed to connect output to new device\n"); + return r; + } + + mgr = omap_dss_get_overlay_manager(dssdev->channel); + + if (mgr->output && !force) + return 0; + + if (mgr->output) + mgr->unset_output(mgr); + + r = mgr->set_output(mgr, out); + if (r) { + DSSERR("failed to connect manager to output of new device\n"); + + /* remove the output-device connection we just made */ + omapdss_output_unset_device(out); + return r; + } + + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl = omap_dss_get_overlay(i); + + if (!ovl->manager || force) { + if (ovl->manager) + ovl->unset_manager(ovl); + + r = ovl->set_manager(ovl, mgr); + if (r) { + DSSERR("failed to set initial overlay\n"); + return r; + } + } + } + + return 0; +} + +static void dss_uninit_connections(struct omap_dss_device *dssdev) +{ + if (dssdev->output) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + + if (mgr) + mgr->unset_output(mgr); + + omapdss_output_unset_device(dssdev->output); + } +} + +int dss_init_device(struct platform_device *pdev, struct omap_dss_device *dssdev) { struct device_attribute *attr; - int i; - int r; + int i, r; + const char *def_disp_name = dss_get_default_display_name(); + bool force; + + force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0; + dss_init_connections(dssdev, force); /* create device sysfs files */ i = 0; while ((attr = display_sysfs_attrs[i++]) != NULL) { r = device_create_file(&dssdev->dev, attr); - if (r) + if (r) { + for (i = i - 2; i >= 0; i--) { + attr = display_sysfs_attrs[i]; + device_remove_file(&dssdev->dev, attr); + } + + dss_uninit_connections(dssdev); + DSSERR("failed to create sysfs file\n"); + return r; + } } /* create display? sysfs links */ r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, dev_name(&dssdev->dev)); - if (r) + if (r) { + while ((attr = display_sysfs_attrs[i++]) != NULL) + device_remove_file(&dssdev->dev, attr); + + dss_uninit_connections(dssdev); + DSSERR("failed to create sysfs display link\n"); + return r; + } + + return 0; } void dss_uninit_device(struct platform_device *pdev, @@ -349,8 +444,7 @@ void dss_uninit_device(struct platform_device *pdev, while ((attr = display_sysfs_attrs[i++]) != NULL) device_remove_file(&dssdev->dev, attr); - if (dssdev->manager) - dssdev->manager->unset_device(dssdev->manager); + dss_uninit_connections(dssdev); } static int dss_suspend_device(struct device *dev, void *data) diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 3266be23fc0d..56748cf8760e 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -29,17 +29,24 @@ #include <linux/errno.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/string.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" +#include "dss_features.h" static struct { struct regulator *vdds_dsi_reg; struct platform_device *dsidev; + struct mutex lock; + + struct omap_video_timings timings; struct dss_lcd_mgr_config mgr_config; + int data_lines; + + struct omap_dss_output output; } dpi; static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) @@ -121,7 +128,8 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, static int dpi_set_mode(struct omap_dss_device *dssdev) { - struct omap_video_timings *t = &dssdev->panel.timings; + struct omap_video_timings *t = &dpi.timings; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div = 0, pck_div = 0; unsigned long fck = 0; unsigned long pck; @@ -146,37 +154,44 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) t->pixel_clock = pck; } - dss_mgr_set_timings(dssdev->manager, t); + dss_mgr_set_timings(mgr, t); return 0; } static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dpi.mgr_config.stallmode = false; dpi.mgr_config.fifohandcheck = false; - dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines; + dpi.mgr_config.video_port_width = dpi.data_lines; dpi.mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config); + dss_mgr_set_lcd_config(mgr, &dpi.mgr_config); } int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_output *out = dssdev->output; int r; - if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) { + mutex_lock(&dpi.lock); + + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) { DSSERR("no VDSS_DSI regulator\n"); - return -ENODEV; + r = -ENODEV; + goto err_no_reg; } - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); - return -ENODEV; + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); + r = -ENODEV; + goto err_no_out_mgr; } r = omap_dss_start_device(dssdev); @@ -185,7 +200,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) goto err_start_dev; } - if (cpu_is_omap34xx()) { + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { r = regulator_enable(dpi.vdds_dsi_reg); if (r) goto err_reg_enable; @@ -195,6 +210,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; + r = dss_dpi_select_source(dssdev->channel); + if (r) + goto err_src_sel; + if (dpi_use_dsi_pll(dssdev)) { r = dsi_runtime_get(dpi.dsidev); if (r) @@ -213,10 +232,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(out->manager); if (r) goto err_mgr_enable; + mutex_unlock(&dpi.lock); + return 0; err_mgr_enable: @@ -227,20 +248,28 @@ err_dsi_pll_init: if (dpi_use_dsi_pll(dssdev)) dsi_runtime_put(dpi.dsidev); err_get_dsi: +err_src_sel: dispc_runtime_put(); err_get_dispc: - if (cpu_is_omap34xx()) + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); err_reg_enable: omap_dss_stop_device(dssdev); err_start_dev: +err_no_out_mgr: +err_no_reg: + mutex_unlock(&dpi.lock); return r; } EXPORT_SYMBOL(omapdss_dpi_display_enable); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + mutex_lock(&dpi.lock); + + dss_mgr_disable(mgr); if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); @@ -250,44 +279,39 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) dispc_runtime_put(); - if (cpu_is_omap34xx()) + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); omap_dss_stop_device(dssdev); + + mutex_unlock(&dpi.lock); } EXPORT_SYMBOL(omapdss_dpi_display_disable); -void dpi_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { - int r; - DSSDBG("dpi_set_timings\n"); - dssdev->panel.timings = *timings; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - r = dispc_runtime_get(); - if (r) - return; - dpi_set_mode(dssdev); + mutex_lock(&dpi.lock); - dispc_runtime_put(); - } else { - dss_mgr_set_timings(dssdev->manager, timings); - } + dpi.timings = *timings; + + mutex_unlock(&dpi.lock); } -EXPORT_SYMBOL(dpi_set_timings); +EXPORT_SYMBOL(omapdss_dpi_set_timings); int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { int r; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div, pck_div; unsigned long fck; unsigned long pck; struct dispc_clock_info dispc_cinfo; - if (dss_mgr_check_timings(dssdev->manager, timings)) + if (dss_mgr_check_timings(mgr, timings)) return -EINVAL; if (timings->pixel_clock == 0) @@ -325,11 +349,22 @@ int dpi_check_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(dpi_check_timings); +void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) +{ + mutex_lock(&dpi.lock); + + dpi.data_lines = data_lines; + + mutex_unlock(&dpi.lock); +} +EXPORT_SYMBOL(omapdss_dpi_set_data_lines); + static int __init dpi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); - if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) { + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && + dpi.vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; vdds_dsi = dss_get_vdds_dsi(); @@ -351,10 +386,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __init dpi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -362,21 +401,75 @@ static void __init dpi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_DPI) continue; - r = dpi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init dpi_probe_pdata(struct platform_device *dpidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = dpi_find_dssdev(dpidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&dpidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = dpi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } } +static void __init dpi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &dpi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_DPI; + out->type = OMAP_DISPLAY_TYPE_DPI; + + dss_register_output(out); +} + +static void __exit dpi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &dpi.output; + + dss_unregister_output(out); +} + static int __init omap_dpi_probe(struct platform_device *pdev) { + mutex_init(&dpi.lock); + + dpi_init_output(pdev); + dpi_probe_pdata(pdev); return 0; @@ -384,7 +477,9 @@ static int __init omap_dpi_probe(struct platform_device *pdev) static int __exit omap_dpi_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + dpi_uninit_output(pdev); return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b07e8864f82f..e37e6d868acd 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -41,7 +41,6 @@ #include <video/omapdss.h> #include <video/mipi_display.h> -#include <plat/clock.h> #include "dss.h" #include "dss_features.h" @@ -333,6 +332,12 @@ struct dsi_data { unsigned scp_clk_refcount; struct dss_lcd_mgr_config mgr_config; + struct omap_video_timings timings; + enum omap_dss_dsi_pixel_format pix_fmt; + enum omap_dss_dsi_mode mode; + struct omap_dss_dsi_videomode_timings vm_timings; + + struct omap_dss_output output; }; struct dsi_packet_sent_handler_data { @@ -340,8 +345,6 @@ struct dsi_packet_sent_handler_data { struct completion *completion; }; -static struct platform_device *dsi_pdev_map[MAX_NUM_DSI]; - #ifdef DEBUG static bool dsi_perf; module_param(dsi_perf, bool, 0644); @@ -354,12 +357,19 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) { - return dsi_pdev_map[dssdev->phy.dsi.module]; + return dssdev->output->pdev; } struct platform_device *dsi_get_dsidev_from_id(int module) { - return dsi_pdev_map[module]; + struct omap_dss_output *out; + enum omap_dss_output_id id; + + id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + + out = omap_dss_get_output(id); + + return out->pdev; } static inline void dsi_write_reg(struct platform_device *dsidev, @@ -1450,6 +1460,148 @@ found: return 0; } +static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, + unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cur, best; + + DSSDBG("dsi_pll_calc_ddrfreq\n"); + + memset(&best, 0, sizeof(best)); + memset(&cur, 0, sizeof(cur)); + + cur.clkin = clk_get_rate(dsi->sys_clk); + + for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { + cur.fint = cur.clkin / cur.regn; + + if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) + continue; + + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ + for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { + unsigned long a, b; + + a = 2 * cur.regm * (cur.clkin/1000); + b = cur.regn; + cur.clkin4ddr = a / b * 1000; + + if (cur.clkin4ddr > 1800 * 1000 * 1000) + break; + + if (abs(cur.clkin4ddr - req_clkin4ddr) < + abs(best.clkin4ddr - req_clkin4ddr)) { + best = cur; + DSSDBG("best %ld\n", best.clkin4ddr); + } + + if (cur.clkin4ddr == req_clkin4ddr) + goto found; + } + } +found: + if (cinfo) + *cinfo = best; + + return 0; +} + +static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, + struct dsi_clock_info *cinfo) +{ + unsigned long max_dsi_fck; + + max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); + + cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck); + cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; +} + +static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev, + unsigned long req_pck, struct dsi_clock_info *cinfo, + struct dispc_clock_info *dispc_cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + unsigned regm_dispc, best_regm_dispc; + unsigned long dispc_clk, best_dispc_clk; + int min_fck_per_pck; + unsigned long max_dss_fck; + struct dispc_clock_info best_dispc; + bool match; + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; + + if (min_fck_per_pck && + req_pck * min_fck_per_pck > max_dss_fck) { + DSSERR("Requested pixel clock not possible with the current " + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " + "the constraint off.\n"); + min_fck_per_pck = 0; + } + +retry: + best_regm_dispc = 0; + best_dispc_clk = 0; + memset(&best_dispc, 0, sizeof(best_dispc)); + match = false; + + for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) { + struct dispc_clock_info cur_dispc; + + dispc_clk = cinfo->clkin4ddr / regm_dispc; + + /* this will narrow down the search a bit, + * but still give pixclocks below what was + * requested */ + if (dispc_clk < req_pck) + break; + + if (dispc_clk > max_dss_fck) + continue; + + if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck) + continue; + + match = true; + + dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc); + + if (abs(cur_dispc.pck - req_pck) < + abs(best_dispc.pck - req_pck)) { + best_regm_dispc = regm_dispc; + best_dispc_clk = dispc_clk; + best_dispc = cur_dispc; + + if (cur_dispc.pck == req_pck) + goto found; + } + } + + if (!match) { + if (min_fck_per_pck) { + DSSERR("Could not find suitable clock settings.\n" + "Turning FCK/PCK constraint off and" + "trying again.\n"); + min_fck_per_pck = 0; + goto retry; + } + + DSSERR("Could not find suitable clock settings.\n"); + + return -EINVAL; + } +found: + cinfo->regm_dispc = best_regm_dispc; + cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk; + + *dispc_cinfo = best_dispc; + + return 0; +} + int dsi_pll_set_clock_div(struct platform_device *dsidev, struct dsi_clock_info *cinfo) { @@ -1526,21 +1678,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); + l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); + if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { f = cinfo->fint < 1000000 ? 0x3 : cinfo->fint < 1250000 ? 0x4 : cinfo->fint < 1500000 ? 0x5 : cinfo->fint < 1750000 ? 0x6 : 0x7; - } - l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); - - if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ + } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) { + f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4; + + l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */ + } + l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ + if (dss_has_feature(FEAT_DSI_PLL_REFSEL)) + l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */ dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ @@ -2004,15 +2162,16 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) return 1194 * 3; /* 1194x24 bits */ case 6: return 1365 * 3; /* 1365x24 bits */ + case 7: + return 1920 * 3; /* 1920x24 bits */ default: BUG(); return 0; } } -static int dsi_set_lane_config(struct omap_dss_device *dssdev) +static int dsi_set_lane_config(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); static const u8 offsets[] = { 0, 4, 8, 12, 16 }; static const enum dsi_lane_function functions[] = { @@ -2136,9 +2295,16 @@ static void dsi_cio_timings(struct platform_device *dsidev) dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); - r = FLD_MOD(r, tlpx_half, 22, 16); + r = FLD_MOD(r, tlpx_half, 20, 16); r = FLD_MOD(r, tclk_trail, 15, 8); r = FLD_MOD(r, tclk_zero, 7, 0); + + if (dss_has_feature(FEAT_DSI_PHY_DCC)) { + r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */ + r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */ + r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ + } + dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); @@ -2147,10 +2313,9 @@ static void dsi_cio_timings(struct platform_device *dsidev) } /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ -static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, +static void dsi_cio_enable_lane_override(struct platform_device *dsidev, unsigned mask_p, unsigned mask_n) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; u32 l; @@ -2197,9 +2362,8 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); } -static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) +static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int t, i; bool in_use[DSI_MAX_NR_LANES]; @@ -2247,9 +2411,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) } /* return bitmask of enabled lanes, lane0 being the lsb */ -static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) +static unsigned dsi_get_lane_mask(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned mask = 0; int i; @@ -2262,16 +2425,15 @@ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) return mask; } -static int dsi_cio_init(struct omap_dss_device *dssdev) +static int dsi_cio_init(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; u32 l; DSSDBGF(); - r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); if (r) return r; @@ -2288,7 +2450,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) goto err_scp_clk_dom; } - r = dsi_set_lane_config(dssdev); + r = dsi_set_lane_config(dsidev); if (r) goto err_scp_clk_dom; @@ -2323,7 +2485,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) mask_p |= 1 << i; } - dsi_cio_enable_lane_override(dssdev, mask_p, 0); + dsi_cio_enable_lane_override(dsidev, mask_p, 0); } r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); @@ -2340,7 +2502,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_if_enable(dsidev, false); REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ - r = dsi_cio_wait_tx_clk_esc_reset(dssdev); + r = dsi_cio_wait_tx_clk_esc_reset(dsidev); if (r) goto err_tx_clk_esc_rst; @@ -2360,10 +2522,10 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_cio_timings(dsidev); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* DDR_CLK_ALWAYS_ON */ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, - dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13); + dsi->vm_timings.ddr_clk_always_on, 13, 13); } dsi->ulps_enabled = false; @@ -2381,13 +2543,12 @@ err_cio_pwr: dsi_cio_disable_lane_override(dsidev); err_scp_clk_dom: dsi_disable_scp_clk(dsidev); - dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); return r; } -static void dsi_cio_uninit(struct omap_dss_device *dssdev) +static void dsi_cio_uninit(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); /* DDR_CLK_ALWAYS_ON */ @@ -2395,7 +2556,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev) dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); dsi_disable_scp_clk(dsidev); - dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); } static void dsi_config_tx_fifo(struct platform_device *dsidev, @@ -2685,6 +2846,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); @@ -2701,7 +2863,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, dsi_force_tx_stop_mode_io(dsidev); /* start the DDR clock by sending a NULL packet */ - if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable) + if (dsi->vm_timings.ddr_clk_always_on && enable) dsi_vc_send_null(dssdev, channel); } EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); @@ -2987,10 +3149,9 @@ int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) } EXPORT_SYMBOL(dsi_vc_send_null); -static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, +static int dsi_vc_write_nosync_common(struct platform_device *dsidev, int channel, u8 *data, int len, enum dss_dsi_content_type type) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; if (len == 0) { @@ -3021,7 +3182,9 @@ static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - return dsi_vc_write_nosync_common(dssdev, channel, data, len, + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + + return dsi_vc_write_nosync_common(dsidev, channel, data, len, DSS_DSI_CONTENT_DCS); } EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); @@ -3029,7 +3192,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - return dsi_vc_write_nosync_common(dssdev, channel, data, len, + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + + return dsi_vc_write_nosync_common(dsidev, channel, data, len, DSS_DSI_CONTENT_GENERIC); } EXPORT_SYMBOL(dsi_vc_generic_write_nosync); @@ -3040,7 +3205,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type); + r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type); if (r) goto err; @@ -3118,10 +3283,9 @@ int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel, } EXPORT_SYMBOL(dsi_vc_generic_write_2); -static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, +static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, int channel, u8 dcs_cmd) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; @@ -3139,10 +3303,9 @@ static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, return 0; } -static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev, +static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, int channel, u8 *reqdata, int reqlen) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 data; u8 data_type; @@ -3291,7 +3454,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd); + r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd); if (r) goto err; @@ -3322,7 +3485,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen); + r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen); if (r) return r; @@ -3604,15 +3767,15 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) +static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int num_line_buffers; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + int bpp = dsi_get_pixel_size(dsi->pix_fmt); unsigned line_buf_size = dsi_get_line_buf_size(dsidev); - struct omap_video_timings *timings = &dssdev->panel.timings; + struct omap_video_timings *timings = &dsi->timings; /* * Don't use line buffers if width is greater than the video * port's line buffer size @@ -3630,11 +3793,11 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); } -static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) +static void dsi_config_vp_sync_events(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end; - bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + bool vsync_end = dsi->vm_timings.vp_vsync_end; + bool hsync_end = dsi->vm_timings.vp_hsync_end; u32 r; r = dsi_read_reg(dsidev, DSI_CTRL); @@ -3648,13 +3811,13 @@ static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); } -static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) +static void dsi_config_blanking_modes(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode; - int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode; - int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode; - int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int blanking_mode = dsi->vm_timings.blanking_mode; + int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode; + int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode; + int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode; u32 r; /* @@ -3741,8 +3904,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; int tclk_trail, ths_exit, exiths_clk; bool ddr_alwon; - struct omap_video_timings *timings = &dssdev->panel.timings; - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + struct omap_video_timings *timings = &dsi->timings; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); int ndl = dsi->num_lanes_used - 1; int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; int hsa_interleave_hs = 0, hsa_interleave_lp = 0; @@ -3852,6 +4015,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) static int dsi_proto_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; int buswidth = 0; @@ -3871,7 +4035,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); - switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) { + switch (dsi_get_pixel_size(dsi->pix_fmt)) { case 16: buswidth = 0; break; @@ -3903,11 +4067,11 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); - dsi_config_vp_num_line_buffers(dssdev); + dsi_config_vp_num_line_buffers(dsidev); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_config_vp_sync_events(dssdev); - dsi_config_blanking_modes(dssdev); + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_config_vp_sync_events(dsidev); + dsi_config_blanking_modes(dsidev); dsi_config_cmd_mode_interleaving(dssdev); } @@ -3919,9 +4083,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) return 0; } -static void dsi_proto_timings(struct omap_dss_device *dssdev) +static void dsi_proto_timings(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; unsigned tclk_pre, tclk_post; @@ -3941,7 +4104,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) ths_exit = FLD_GET(r, 7, 0); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); - tlpx = FLD_GET(r, 22, 16) * 2; + tlpx = FLD_GET(r, 20, 16) * 2; tclk_trail = FLD_GET(r, 15, 8); tclk_zero = FLD_GET(r, 7, 0); @@ -3984,18 +4147,18 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", enter_hs_mode_lat, exit_hs_mode_lat); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* TODO: Implement a video mode check_timings function */ - int hsa = dssdev->panel.dsi_vm_data.hsa; - int hfp = dssdev->panel.dsi_vm_data.hfp; - int hbp = dssdev->panel.dsi_vm_data.hbp; - int vsa = dssdev->panel.dsi_vm_data.vsa; - int vfp = dssdev->panel.dsi_vm_data.vfp; - int vbp = dssdev->panel.dsi_vm_data.vbp; - int window_sync = dssdev->panel.dsi_vm_data.window_sync; - bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; - struct omap_video_timings *timings = &dssdev->panel.timings; - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + int hsa = dsi->vm_timings.hsa; + int hfp = dsi->vm_timings.hfp; + int hbp = dsi->vm_timings.hbp; + int vsa = dsi->vm_timings.vsa; + int vfp = dsi->vm_timings.vfp; + int vbp = dsi->vm_timings.vbp; + int window_sync = dsi->vm_timings.window_sync; + bool hsync_end = dsi->vm_timings.vp_hsync_end; + struct omap_video_timings *timings = &dsi->timings; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); int tl, t_he, width_bytes; t_he = hsync_end ? @@ -4100,16 +4263,84 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_dsi_configure_pins); -int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, + unsigned long ddr_clk, unsigned long lp_clk) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cinfo; + struct dispc_clock_info dispc_cinfo; + unsigned lp_clk_div; + unsigned long dsi_fclk; int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + unsigned long pck; + int r; + + DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); + + mutex_lock(&dsi->lock); + + /* Calculate PLL output clock */ + r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); + if (r) + goto err; + + /* Calculate PLL's DSI clock */ + dsi_pll_calc_dsi_fck(dsidev, &cinfo); + + /* Calculate PLL's DISPC clock and pck & lck divs */ + pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; + DSSDBG("finding dispc dividers for pck %lu\n", pck); + r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); + if (r) + goto err; + + /* Calculate LP clock */ + dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; + lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); + + dssdev->clocks.dsi.regn = cinfo.regn; + dssdev->clocks.dsi.regm = cinfo.regm; + dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; + dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi; + + dssdev->clocks.dsi.lp_clk_div = lp_clk_div; + + dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; + dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; + + dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; + + dssdev->clocks.dispc.channel.lcd_clk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; + + dssdev->clocks.dsi.dsi_fclk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI; + + mutex_unlock(&dsi->lock); + return 0; +err: + mutex_unlock(&dsi->lock); + return r; +} +EXPORT_SYMBOL(omapdss_dsi_set_clocks); + +int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); u8 data_type; u16 word_count; int r; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - switch (dssdev->panel.dsi_pix_fmt) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + switch (dsi->pix_fmt) { case OMAP_DSS_DSI_FMT_RGB888: data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; break; @@ -4133,7 +4364,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) /* MODE, 1 = video mode */ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); - word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); + word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8); dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); @@ -4142,9 +4373,9 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsidev, true); } - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) { - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); dsi_vc_enable(dsidev, channel, false); } @@ -4159,8 +4390,10 @@ EXPORT_SYMBOL(dsi_enable_video_output); void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); dsi_vc_enable(dsidev, channel, false); @@ -4171,15 +4404,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsidev, true); } - dss_mgr_disable(dssdev->manager); + dss_mgr_disable(mgr); } EXPORT_SYMBOL(dsi_disable_video_output); -static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, - u16 w, u16 h) +static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned bytespp; unsigned bytespl; unsigned bytespf; @@ -4190,12 +4423,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, int r; const unsigned channel = dsi->update_channel; const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); + u16 w = dsi->timings.x_res; + u16 h = dsi->timings.y_res; DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); - bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8; bytespl = w * bytespp; bytespf = bytespl * h; @@ -4239,7 +4474,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_mgr_start_update(dssdev->manager); + dss_mgr_set_timings(mgr, &dsi->timings); + + dss_mgr_start_update(mgr); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait @@ -4297,8 +4534,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) static void dsi_framedone_irq_callback(void *data, u32 mask) { - struct omap_dss_device *dssdev = (struct omap_dss_device *) data; - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct platform_device *dsidev = (struct platform_device *) data; struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); /* Note: We get FRAMEDONE when DISPC has finished sending pixels and @@ -4325,13 +4561,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel, dsi->framedone_callback = callback; dsi->framedone_data = data; - dssdev->driver->get_resolution(dssdev, &dw, &dh); + dw = dsi->timings.x_res; + dh = dsi->timings.y_res; #ifdef DEBUG dsi->update_bytes = dw * dh * - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + dsi_get_pixel_size(dsi->pix_fmt) / 8; #endif - dsi_update_screen_dispc(dssdev, dw, dh); + dsi_update_screen_dispc(dssdev); return 0; } @@ -4367,28 +4604,22 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_video_timings timings; + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; u32 irq = 0; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { - u16 dw, dh; - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - timings.x_res = dw; - timings.y_res = dh; - timings.hsw = 1; - timings.hfp = 1; - timings.hbp = 1; - timings.vsw = 1; - timings.vfp = 0; - timings.vbp = 0; + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { + dsi->timings.hsw = 1; + dsi->timings.hfp = 1; + dsi->timings.hbp = 1; + dsi->timings.vsw = 1; + dsi->timings.vfp = 0; + dsi->timings.vbp = 0; - irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); + irq = dispc_mgr_get_framedone_irq(mgr->id); r = omap_dispc_register_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); if (r) { DSSERR("can't get FRAMEDONE irq\n"); goto err; @@ -4397,8 +4628,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dsi->mgr_config.stallmode = true; dsi->mgr_config.fifohandcheck = true; } else { - timings = dssdev->panel.timings; - dsi->mgr_config.stallmode = false; dsi->mgr_config.fifohandcheck = false; } @@ -4407,14 +4636,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) * override interlace, logic level and edge related parameters in * omap_video_timings with default values */ - timings.interlace = false; - timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + dsi->timings.interlace = false; + dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; - dss_mgr_set_timings(dssdev->manager, &timings); + dss_mgr_set_timings(mgr, &dsi->timings); r = dsi_configure_dispc_clocks(dssdev); if (r) @@ -4422,29 +4651,33 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dsi->mgr_config.video_port_width = - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + dsi_get_pixel_size(dsi->pix_fmt); dsi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config); + dss_mgr_set_lcd_config(mgr, &dsi->mgr_config); return 0; err1: - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); err: return r; } static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) { - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { u32 irq; - irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); + irq = dispc_mgr_get_framedone_irq(mgr->id); omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); } } @@ -4477,6 +4710,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; r = dsi_pll_init(dsidev, true, true); @@ -4489,18 +4723,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); - dss_select_lcd_clk_source(dssdev->manager->id, + dss_select_lcd_clk_source(mgr->id, dssdev->clocks.dispc.channel.lcd_clk_src); DSSDBG("PLL OK\n"); - r = dsi_cio_init(dssdev); + r = dsi_cio_init(dsidev); if (r) goto err2; _dsi_print_reset_status(dsidev); - dsi_proto_timings(dssdev); + dsi_proto_timings(dsidev); dsi_set_lp_clk_divisor(dssdev); if (1) @@ -4520,11 +4754,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) return 0; err3: - dsi_cio_uninit(dssdev); + dsi_cio_uninit(dsidev); err2: dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); - dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); err1: dsi_pll_uninit(dsidev, true); @@ -4537,6 +4771,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; if (enter_ulps && !dsi->ulps_enabled) dsi_enter_ulps(dsidev); @@ -4550,8 +4785,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); - dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); - dsi_cio_uninit(dssdev); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); + dsi_cio_uninit(dsidev); dsi_pll_uninit(dsidev, disconnect_lanes); } @@ -4559,6 +4794,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = dssdev->output; int r = 0; DSSDBG("dsi_display_enable\n"); @@ -4567,8 +4803,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dsi->lock); - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err_start_dev; } @@ -4653,17 +4889,83 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) } EXPORT_SYMBOL(omapdss_dsi_enable_te); -static int __init dsi_init_display(struct omap_dss_device *dssdev) +void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - DSSDBG("DSI init\n"); + mutex_lock(&dsi->lock); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | - OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; - } + dsi->timings = *timings; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_timings); + +void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->timings.x_res = w; + dsi->timings.y_res = h; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_size); + +void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, + enum omap_dss_dsi_pixel_format fmt) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->pix_fmt = fmt; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); + +void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, + enum omap_dss_dsi_mode mode) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->mode = mode; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); + +void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, + struct omap_dss_dsi_videomode_timings *timings) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->vm_timings = *timings; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings); + +static int __init dsi_init_display(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = + dsi_get_dsidev_from_id(dssdev->phy.dsi.module); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + DSSDBG("DSI init\n"); if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; @@ -4806,11 +5108,15 @@ static void dsi_put_clocks(struct platform_device *dsidev) clk_put(dsi->sys_clk); } -static void __init dsi_probe_pdata(struct platform_device *dsidev) +static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_dss_board_info *pdata = dsidev->dev.platform_data; - int i, r; + struct omap_dss_board_info *pdata = pdev->dev.platform_data; + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -4821,19 +5127,73 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) if (dssdev->phy.dsi.module != dsi->module_id) continue; - r = dsi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &dsidev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init dsi_probe_pdata(struct platform_device *dsidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = dsi_find_dssdev(dsidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&dsidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = dsi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } } +static void __init dsi_init_output(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = &dsi->output; + + out->pdev = dsidev; + out->id = dsi->module_id == 0 ? + OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + + out->type = OMAP_DISPLAY_TYPE_DSI; + + dss_register_output(out); +} + +static void __exit dsi_uninit_output(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = &dsi->output; + + dss_unregister_output(out); +} + /* DSI1 HW IP initialisation */ static int __init omap_dsihw_probe(struct platform_device *dsidev) { @@ -4848,7 +5208,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) dsi->module_id = dsidev->id; dsi->pdev = dsidev; - dsi_pdev_map[dsi->module_id] = dsidev; dev_set_drvdata(&dsidev->dev, dsi); spin_lock_init(&dsi->irq_lock); @@ -4928,6 +5287,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) else dsi->num_lanes_supported = 3; + dsi_init_output(dsidev); + dsi_probe_pdata(dsidev); dsi_runtime_put(dsidev); @@ -4957,7 +5318,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) WARN_ON(dsi->scp_clk_refcount > 0); - omap_dss_unregister_child_devices(&dsidev->dev); + dss_unregister_child_devices(&dsidev->dev); + + dsi_uninit_output(dsidev); pm_runtime_disable(&dsidev->dev); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 04b4586113e3..2ab1c3e96553 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -31,11 +31,11 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/gfp.h> #include <video/omapdss.h> #include <plat/cpu.h> -#include <plat/clock.h> #include "dss.h" #include "dss_features.h" @@ -65,6 +65,13 @@ struct dss_reg { static int dss_runtime_get(void); static void dss_runtime_put(void); +struct dss_features { + u8 fck_div_max; + u8 dss_fck_multiplier; + const char *clk_name; + int (*dpi_select_source)(enum omap_channel channel); +}; + static struct { struct platform_device *pdev; void __iomem *base; @@ -83,6 +90,8 @@ static struct { bool ctx_valid; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; + + const struct dss_features *feat; } dss; static const char * const dss_generic_clk_source_names[] = { @@ -144,7 +153,7 @@ static void dss_restore_context(void) #undef SR #undef RR -void dss_sdi_init(u8 datapairs) +void dss_sdi_init(int datapairs) { u32 l; @@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) return dss_generic_clk_source_names[clk_src]; } - void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; @@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); - if (cpu_is_omap3630() || cpu_is_omap44xx()) - seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); - else - seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); + seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n", + fclk_name, fclk_real_name, dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + dss.feat->dss_fck_multiplier, fclk_rate); } else { seq_printf(s, "%s (%s) = %lu\n", fclk_name, fclk_real_name, @@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) } } -/* calculate clock rates using dividers in cinfo */ -int dss_calc_clock_rates(struct dss_clock_info *cinfo) -{ - if (dss.dpll4_m4_ck) { - unsigned long prate; - u16 fck_div_max = 16; - - if (cpu_is_omap3630() || cpu_is_omap44xx()) - fck_div_max = 32; - - if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) - return -EINVAL; - - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - - cinfo->fck = prate / cinfo->fck_div; - } else { - if (cinfo->fck_div != 0) - return -EINVAL; - cinfo->fck = clk_get_rate(dss.dss_clk); - } - - return 0; -} - int dss_set_clock_div(struct dss_clock_info *cinfo) { if (dss.dpll4_m4_ck) { @@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) return 0; } -int dss_get_clock_div(struct dss_clock_info *cinfo) -{ - cinfo->fck = clk_get_rate(dss.dss_clk); - - if (dss.dpll4_m4_ck) { - unsigned long prate; - - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - - if (cpu_is_omap3630() || cpu_is_omap44xx()) - cinfo->fck_div = prate / (cinfo->fck); - else - cinfo->fck_div = prate / (cinfo->fck / 2); - } else { - cinfo->fck_div = 0; - } - - return 0; -} - unsigned long dss_get_dpll4_rate(void) { if (dss.dpll4_m4_ck) @@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, unsigned long fck, max_dss_fck; - u16 fck_div, fck_div_max = 16; + u16 fck_div; int match = 0; int min_fck_per_pck; @@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); fck = clk_get_rate(dss.dss_clk); - if (req_pck == dss.cache_req_pck && - ((cpu_is_omap34xx() && prate == dss.cache_prate) || - dss.cache_dss_cinfo.fck == fck)) { + if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && + dss.cache_dss_cinfo.fck == fck) { DSSDBG("dispc clock info found from cache.\n"); *dss_cinfo = dss.cache_dss_cinfo; *dispc_cinfo = dss.cache_dispc_cinfo; @@ -564,16 +518,10 @@ retry: goto found; } else { - if (cpu_is_omap3630() || cpu_is_omap44xx()) - fck_div_max = 32; - - for (fck_div = fck_div_max; fck_div > 0; --fck_div) { + for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { struct dispc_clock_info cur_dispc; - if (fck_div_max == 32) - fck = prate / fck_div; - else - fck = prate / fck_div * 2; + fck = prate / fck_div * dss.feat->dss_fck_multiplier; if (fck > max_dss_fck) continue; @@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable) REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } -void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) +void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) { - REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ + enum omap_display_type dp; + dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); + + /* Complain about invalid selections */ + WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC)); + WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI)); + + /* Select only if we have options */ + if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI)) + REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ } enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) @@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) return DSS_VENC_TV_CLK; + if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0) + return DSS_HDMI_M_PCLK; + return REG_GET(DSS_CONTROL, 15, 15); } +static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) +{ + if (channel != OMAP_DSS_CHANNEL_LCD) + return -EINVAL; + + return 0; +} + +static int dss_dpi_select_source_omap4(enum omap_channel channel) +{ + int val; + + switch (channel) { + case OMAP_DSS_CHANNEL_LCD2: + val = 0; + break; + case OMAP_DSS_CHANNEL_DIGIT: + val = 1; + break; + default: + return -EINVAL; + } + + REG_FLD_MOD(DSS_CONTROL, val, 17, 17); + + return 0; +} + +static int dss_dpi_select_source_omap5(enum omap_channel channel) +{ + int val; + + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + val = 1; + break; + case OMAP_DSS_CHANNEL_LCD2: + val = 2; + break; + case OMAP_DSS_CHANNEL_LCD3: + val = 3; + break; + case OMAP_DSS_CHANNEL_DIGIT: + val = 0; + break; + default: + return -EINVAL; + } + + REG_FLD_MOD(DSS_CONTROL, val, 17, 16); + + return 0; +} + +int dss_dpi_select_source(enum omap_channel channel) +{ + return dss.feat->dpi_select_source(channel); +} + static int dss_get_clocks(void) { struct clk *clk; @@ -678,22 +697,11 @@ static int dss_get_clocks(void) dss.dss_clk = clk; - if (cpu_is_omap34xx()) { - clk = clk_get(NULL, "dpll4_m4_ck"); - if (IS_ERR(clk)) { - DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(clk); - goto err; - } - } else if (cpu_is_omap44xx()) { - clk = clk_get(NULL, "dpll_per_m5x2_ck"); - if (IS_ERR(clk)) { - DSSERR("Failed to get dpll_per_m5x2_ck\n"); - r = PTR_ERR(clk); - goto err; - } - } else { /* omap24xx */ - clk = NULL; + clk = clk_get(NULL, dss.feat->clk_name); + if (IS_ERR(clk)) { + DSSERR("Failed to get %s\n", dss.feat->clk_name); + r = PTR_ERR(clk); + goto err; } dss.dpll4_m4_ck = clk; @@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s) } #endif +static const struct dss_features omap24xx_dss_feats __initconst = { + .fck_div_max = 16, + .dss_fck_multiplier = 2, + .clk_name = NULL, + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap34xx_dss_feats __initconst = { + .fck_div_max = 16, + .dss_fck_multiplier = 2, + .clk_name = "dpll4_m4_ck", + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap3630_dss_feats __initconst = { + .fck_div_max = 32, + .dss_fck_multiplier = 1, + .clk_name = "dpll4_m4_ck", + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap44xx_dss_feats __initconst = { + .fck_div_max = 32, + .dss_fck_multiplier = 1, + .clk_name = "dpll_per_m5x2_ck", + .dpi_select_source = &dss_dpi_select_source_omap4, +}; + +static const struct dss_features omap54xx_dss_feats __initconst = { + .fck_div_max = 64, + .dss_fck_multiplier = 1, + .clk_name = "dpll_per_h12x2_ck", + .dpi_select_source = &dss_dpi_select_source_omap5, +}; + +static int __init dss_init_features(struct device *dev) +{ + const struct dss_features *src; + struct dss_features *dst; + + dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + if (!dst) { + dev_err(dev, "Failed to allocate local DSS Features\n"); + return -ENOMEM; + } + + if (cpu_is_omap24xx()) + src = &omap24xx_dss_feats; + else if (cpu_is_omap34xx()) + src = &omap34xx_dss_feats; + else if (cpu_is_omap3630()) + src = &omap3630_dss_feats; + else if (cpu_is_omap44xx()) + src = &omap44xx_dss_feats; + else if (soc_is_omap54xx()) + src = &omap54xx_dss_feats; + else + return -ENODEV; + + memcpy(dst, src, sizeof(*dst)); + dss.feat = dst; + + return 0; +} + /* DSS HW IP initialisation */ static int __init omap_dsshw_probe(struct platform_device *pdev) { @@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.pdev = pdev; + r = dss_init_features(&dss.pdev->dev); + if (r) + return r; + dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); if (!dss_mem) { DSSERR("can't get IORESOURCE_MEM DSS\n"); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index f67afe76f217..6728892f9dad 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -113,6 +113,17 @@ enum dss_dsi_content_type { DSS_DSI_CONTENT_GENERIC, }; +enum dss_writeback_channel { + DSS_WB_LCD1_MGR = 0, + DSS_WB_LCD2_MGR = 1, + DSS_WB_TV_MGR = 2, + DSS_WB_OVL0 = 3, + DSS_WB_OVL1 = 4, + DSS_WB_OVL2 = 5, + DSS_WB_OVL3 = 6, + DSS_WB_LCD3_MGR = 7, +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -175,6 +186,7 @@ struct seq_file; struct platform_device; /* core */ +const char *dss_get_default_display_name(void); struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); @@ -184,10 +196,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); int dss_set_min_bus_tput(struct device *dev, unsigned long tput); int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); -int omap_dss_register_device(struct omap_dss_device *dssdev, - struct device *parent, int disp_num); -void omap_dss_unregister_device(struct omap_dss_device *dssdev); -void omap_dss_unregister_child_devices(struct device *parent); +struct omap_dss_device *dss_alloc_and_init_device(struct device *parent); +int dss_add_device(struct omap_dss_device *dssdev); +void dss_unregister_device(struct omap_dss_device *dssdev); +void dss_unregister_child_devices(struct device *parent); +void dss_put_device(struct omap_dss_device *dssdev); +void dss_copy_device_pdata(struct omap_dss_device *dst, + const struct omap_dss_device *src); /* apply */ void dss_apply_init(void); @@ -205,8 +220,11 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, int dss_mgr_set_device(struct omap_overlay_manager *mgr, struct omap_dss_device *dssdev); int dss_mgr_unset_device(struct omap_overlay_manager *mgr); +int dss_mgr_set_output(struct omap_overlay_manager *mgr, + struct omap_dss_output *output); +int dss_mgr_unset_output(struct omap_overlay_manager *mgr); void dss_mgr_set_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings); + const struct omap_video_timings *timings); void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, const struct dss_lcd_mgr_config *config); const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); @@ -222,12 +240,17 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, struct omap_overlay_manager *mgr); int dss_ovl_unset_manager(struct omap_overlay *ovl); +/* output */ +void dss_register_output(struct omap_dss_output *out); +void dss_unregister_output(struct omap_dss_output *out); +struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev); + /* display */ int dss_suspend_all_devices(void); int dss_resume_all_devices(void); void dss_disable_all_devices(void); -void dss_init_device(struct platform_device *pdev, +int dss_init_device(struct platform_device *pdev, struct omap_dss_device *dssdev); void dss_uninit_device(struct platform_device *pdev, struct omap_dss_device *dssdev); @@ -254,22 +277,29 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) return false; } +int dss_manager_kobj_init(struct omap_overlay_manager *mgr, + struct platform_device *pdev); +void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr); + /* overlay */ void dss_init_overlays(struct platform_device *pdev); void dss_uninit_overlays(struct platform_device *pdev); void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); -void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); int dss_ovl_simple_check(struct omap_overlay *ovl, const struct omap_overlay_info *info); int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, const struct omap_video_timings *mgr_timings); bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, enum omap_color_mode mode); +int dss_overlay_kobj_init(struct omap_overlay *ovl, + struct platform_device *pdev); +void dss_overlay_kobj_uninit(struct omap_overlay *ovl); /* DSS */ int dss_init_platform_driver(void) __init; void dss_uninit_platform_driver(void); +int dss_dpi_select_source(enum omap_channel channel); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); @@ -279,7 +309,7 @@ void dss_dump_clocks(struct seq_file *s); void dss_debug_dump_clocks(struct seq_file *s); #endif -void dss_sdi_init(u8 datapairs); +void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); @@ -296,9 +326,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); unsigned long dss_get_dpll4_rate(void); -int dss_calc_clock_rates(struct dss_clock_info *cinfo); int dss_set_clock_div(struct dss_clock_info *cinfo); -int dss_get_clock_div(struct dss_clock_info *cinfo); int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, struct dispc_clock_info *dispc_cinfo); @@ -427,8 +455,9 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, bool manual_update); -int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool replication, const struct omap_video_timings *mgr_timings); +int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem); int dispc_ovl_enable(enum omap_plane plane, bool enable); void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel); @@ -457,6 +486,15 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, void dispc_mgr_setup(enum omap_channel channel, struct omap_overlay_manager_info *info); +u32 dispc_wb_get_framedone_irq(void); +bool dispc_wb_go_busy(void); +void dispc_wb_go(void); +void dispc_wb_enable(bool enable); +bool dispc_wb_is_enabled(void); +void dispc_wb_set_channel_in(enum dss_writeback_channel channel); +int dispc_wb_setup(const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct omap_video_timings *timings); + /* VENC */ #ifdef CONFIG_OMAP2_DSS_VENC int venc_init_platform_driver(void) __init; @@ -469,6 +507,20 @@ static inline unsigned long venc_get_pixel_clock(void) return 0; } #endif +int omapdss_venc_display_enable(struct omap_dss_device *dssdev); +void omapdss_venc_display_disable(struct omap_dss_device *dssdev); +void omapdss_venc_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +int omapdss_venc_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev); +int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss); +void omapdss_venc_set_type(struct omap_dss_device *dssdev, + enum omap_dss_venc_type type); +void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, + bool invert_polarity); +int venc_panel_init(void); +void venc_panel_exit(void); /* HDMI */ #ifdef CONFIG_OMAP4_DSS_HDMI @@ -484,7 +536,8 @@ static inline unsigned long hdmi_get_pixel_clock(void) #endif int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); -void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings); int omapdss_hdmi_read_edid(u8 *buf, int len); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 938709724f0c..acbc1e1efba3 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -46,7 +46,9 @@ struct omap_dss_features { const int num_mgrs; const int num_ovls; + const int num_wbs; const enum omap_display_type *supported_displays; + const enum omap_dss_output_id *supported_outputs; const enum omap_color_mode *supported_color_modes; const enum omap_overlay_caps *overlay_caps; const char * const *clksrc_names; @@ -106,6 +108,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, }; +static const struct dss_reg_field omap5_dss_reg_fields[] = { + [FEAT_REG_FIRHINC] = { 12, 0 }, + [FEAT_REG_FIRVINC] = { 28, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, + [FEAT_REG_FIFOSIZE] = { 15, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, + [FEAT_REG_VERTICALACCU] = { 26, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, + [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, + [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, + [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, + [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, +}; + static const enum omap_display_type omap2_dss_supported_displays[] = { /* OMAP_DSS_CHANNEL_LCD */ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, @@ -144,6 +161,76 @@ static const enum omap_display_type omap4_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_DSI, }; +static const enum omap_display_type omap5_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, +}; + +static const enum omap_dss_output_id omap2_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI | + OMAP_DSS_OUTPUT_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI2, +}; + +static const enum omap_dss_output_id omap5_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_LCD3 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI2, +}; + static const enum omap_color_mode omap2_dss_supported_color_modes[] = { /* OMAP_DSS_GFX */ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | @@ -224,58 +311,80 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | OMAP_DSS_COLOR_RGBX32, + + /* OMAP_DSS_WB */ + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | + OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 | + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 | + OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY | + OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | + OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | + OMAP_DSS_COLOR_RGBX32, }; static const enum omap_overlay_caps omap2_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - 0, + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ - OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | - OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO3 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, }; static const char * const omap2_dss_clk_source_names[] = { @@ -298,6 +407,14 @@ static const char * const omap4_dss_clk_source_names[] = { [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", }; +static const char * const omap5_dss_clk_source_names[] = { + [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1", + [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2", + [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2", +}; + static const struct dss_param_range omap2_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, [FEAT_PARAM_DSS_PCD] = { 2, 255 }, @@ -326,6 +443,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, + [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, @@ -341,6 +459,23 @@ static const struct dss_param_range omap4_dss_param_range[] = { [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, + [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, + [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, + [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, + [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, + [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, +}; + +static const struct dss_param_range omap5_dss_param_range[] = { + [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, + [FEAT_PARAM_DSS_PCD] = { 1, 255 }, + [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, + [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, + [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, + [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, @@ -373,6 +508,26 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = { FEAT_ALPHA_FIXED_ZORDER, FEAT_FIFO_MERGE, FEAT_OMAP3_DSI_FIFO_BUG, + FEAT_DPI_USES_VDDS_DSI, +}; + +static const enum dss_feat_id am35xx_dss_feat_list[] = { + FEAT_LCDENABLEPOL, + FEAT_LCDENABLESIGNAL, + FEAT_PCKFREEENABLE, + FEAT_FUNCGATED, + FEAT_LINEBUFFERSPLIT, + FEAT_ROWREPEATENABLE, + FEAT_RESIZECONF, + FEAT_DSI_PLL_FREQSEL, + FEAT_DSI_REVERSE_TXCLKESC, + FEAT_VENC_REQUIRES_TV_DAC_CLK, + FEAT_CPR, + FEAT_PRELOAD, + FEAT_FIR_COEF_V, + FEAT_ALPHA_FIXED_ZORDER, + FEAT_FIFO_MERGE, + FEAT_OMAP3_DSI_FIFO_BUG, }; static const enum dss_feat_id omap3630_dss_feat_list[] = { @@ -447,6 +602,28 @@ static const enum dss_feat_id omap4_dss_feat_list[] = { FEAT_BURST_2D, }; +static const enum dss_feat_id omap5_dss_feat_list[] = { + FEAT_MGR_LCD2, + FEAT_CORE_CLK_DIV, + FEAT_LCD_CLK_SRC, + FEAT_DSI_DCS_CMD_CONFIG_VC, + FEAT_DSI_VC_OCP_WIDTH, + FEAT_DSI_GNQ, + FEAT_HDMI_CTS_SWMODE, + FEAT_HDMI_AUDIO_USE_MCLK, + FEAT_HANDLE_UV_SEPARATE, + FEAT_ATTR2, + FEAT_CPR, + FEAT_PRELOAD, + FEAT_FIR_COEF_V, + FEAT_ALPHA_FREE_ZORDER, + FEAT_FIFO_MERGE, + FEAT_BURST_2D, + FEAT_DSI_PLL_SELFREQDCO, + FEAT_DSI_PLL_REFSEL, + FEAT_DSI_PHY_DCC, +}; + /* OMAP2 DSS Features */ static const struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, @@ -458,6 +635,7 @@ static const struct omap_dss_features omap2_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap2_dss_supported_displays, + .supported_outputs = omap2_dss_supported_outputs, .supported_color_modes = omap2_dss_supported_color_modes, .overlay_caps = omap2_dss_overlay_caps, .clksrc_names = omap2_dss_clk_source_names, @@ -478,6 +656,31 @@ static const struct omap_dss_features omap3430_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3430_dss_supported_displays, + .supported_outputs = omap3430_dss_supported_outputs, + .supported_color_modes = omap3_dss_supported_color_modes, + .overlay_caps = omap3430_dss_overlay_caps, + .clksrc_names = omap3_dss_clk_source_names, + .dss_params = omap3_dss_param_range, + .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, + .buffer_size_unit = 1, + .burst_size_unit = 8, +}; + +/* + * AM35xx DSS Features. This is basically OMAP3 DSS Features without the + * vdds_dsi regulator. + */ +static const struct omap_dss_features am35xx_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .features = am35xx_dss_feat_list, + .num_features = ARRAY_SIZE(am35xx_dss_feat_list), + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap3430_dss_supported_displays, + .supported_outputs = omap3430_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3430_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, @@ -497,6 +700,7 @@ static const struct omap_dss_features omap3630_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3630_dss_supported_displays, + .supported_outputs = omap3630_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3630_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, @@ -517,7 +721,9 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -537,7 +743,9 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -557,7 +765,9 @@ static const struct omap_dss_features omap4_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -567,6 +777,27 @@ static const struct omap_dss_features omap4_dss_features = { .burst_size_unit = 16, }; +/* OMAP5 DSS Features */ +static const struct omap_dss_features omap5_dss_features = { + .reg_fields = omap5_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields), + + .features = omap5_dss_feat_list, + .num_features = ARRAY_SIZE(omap5_dss_feat_list), + + .num_mgrs = 3, + .num_ovls = 4, + .supported_displays = omap5_dss_supported_displays, + .supported_outputs = omap5_dss_supported_outputs, + .supported_color_modes = omap4_dss_supported_color_modes, + .overlay_caps = omap4_dss_overlay_caps, + .clksrc_names = omap5_dss_clk_source_names, + .dss_params = omap5_dss_param_range, + .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, + .buffer_size_unit = 16, + .burst_size_unit = 16, +}; + #if defined(CONFIG_OMAP4_DSS_HDMI) /* HDMI OMAP4 Functions*/ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { @@ -612,6 +843,11 @@ int dss_feat_get_num_ovls(void) return omap_current_dss_features->num_ovls; } +int dss_feat_get_num_wbs(void) +{ + return omap_current_dss_features->num_wbs; +} + unsigned long dss_feat_get_param_min(enum dss_range_param param) { return omap_current_dss_features->dss_params[param].min; @@ -627,6 +863,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel return omap_current_dss_features->supported_displays[channel]; } +enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) +{ + return omap_current_dss_features->supported_outputs[channel]; +} + enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) { return omap_current_dss_features->supported_color_modes[plane]; @@ -694,8 +935,13 @@ void dss_features_init(void) omap_current_dss_features = &omap2_dss_features; else if (cpu_is_omap3630()) omap_current_dss_features = &omap3630_dss_features; - else if (cpu_is_omap34xx()) - omap_current_dss_features = &omap3430_dss_features; + else if (cpu_is_omap34xx()) { + if (soc_is_am35xx()) { + omap_current_dss_features = &am35xx_dss_features; + } else { + omap_current_dss_features = &omap3430_dss_features; + } + } else if (omap_rev() == OMAP4430_REV_ES1_0) omap_current_dss_features = &omap4430_es1_0_dss_features; else if (omap_rev() == OMAP4430_REV_ES2_0 || @@ -704,6 +950,8 @@ void dss_features_init(void) omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; else if (cpu_is_omap44xx()) omap_current_dss_features = &omap4_dss_features; + else if (soc_is_omap54xx()) + omap_current_dss_features = &omap5_dss_features; else DSSWARN("Unsupported OMAP version"); } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 996ffcbfed58..9218113b5e88 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -50,6 +50,7 @@ enum dss_feat_id { FEAT_DSI_VC_OCP_WIDTH, FEAT_DSI_REVERSE_TXCLKESC, FEAT_DSI_GNQ, + FEAT_DPI_USES_VDDS_DSI, FEAT_HDMI_CTS_SWMODE, FEAT_HDMI_AUDIO_USE_MCLK, FEAT_HANDLE_UV_SEPARATE, @@ -64,6 +65,9 @@ enum dss_feat_id { /* An unknown HW bug causing the normal FIFO thresholds not to work */ FEAT_OMAP3_DSI_FIFO_BUG, FEAT_BURST_2D, + FEAT_DSI_PLL_SELFREQDCO, + FEAT_DSI_PLL_REFSEL, + FEAT_DSI_PHY_DCC, }; /* DSS register field id */ @@ -91,6 +95,7 @@ enum dss_range_param { FEAT_PARAM_DSIPLL_REGM_DSI, FEAT_PARAM_DSIPLL_FINT, FEAT_PARAM_DSIPLL_LPDIV, + FEAT_PARAM_DSI_FCK, FEAT_PARAM_DOWNSCALE, FEAT_PARAM_LINEWIDTH, FEAT_PARAM_MGR_WIDTH, @@ -100,9 +105,11 @@ enum dss_range_param { /* DSS Feature Functions */ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); +int dss_feat_get_num_wbs(void); unsigned long dss_feat_get_param_min(enum dss_range_param param); unsigned long dss_feat_get_param_max(enum dss_range_param param); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); +enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 060216fdc578..a48a7dd75b33 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -32,6 +32,8 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> #include <video/omapdss.h> #include "ti_hdmi.h" @@ -61,6 +63,13 @@ static struct { struct hdmi_ip_data ip_data; struct clk *sys_clk; + struct regulator *vdda_hdmi_dac_reg; + + int ct_cp_hpd_gpio; + int ls_oe_gpio; + int hpd_gpio; + + struct omap_dss_output output; } hdmi; /* @@ -314,12 +323,47 @@ static void hdmi_runtime_put(void) static int __init hdmi_init_display(struct omap_dss_device *dssdev) { + int r; + + struct gpio gpios[] = { + { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" }, + { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" }, + { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" }, + }; + DSSDBG("init_display\n"); dss_init_hdmi_ip_ops(&hdmi.ip_data); + + if (hdmi.vdda_hdmi_dac_reg == NULL) { + struct regulator *reg; + + reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); + + if (IS_ERR(reg)) { + DSSERR("can't get VDDA_HDMI_DAC regulator\n"); + return PTR_ERR(reg); + } + + hdmi.vdda_hdmi_dac_reg = reg; + } + + r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (r) + return r; + return 0; } +static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) +{ + DSSDBG("uninit_display\n"); + + gpio_free(hdmi.ct_cp_hpd_gpio); + gpio_free(hdmi.ls_oe_gpio); + gpio_free(hdmi.hpd_gpio); +} + static const struct hdmi_config *hdmi_find_timing( const struct hdmi_config *timings_arr, int len) @@ -459,32 +503,30 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, static int hdmi_power_on(struct omap_dss_device *dssdev) { int r; - const struct hdmi_config *timing; struct omap_video_timings *p; + struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned long phy; + gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); + gpio_set_value(hdmi.ls_oe_gpio, 1); + + /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ + udelay(300); + + r = regulator_enable(hdmi.vdda_hdmi_dac_reg); + if (r) + goto err_vdac_enable; + r = hdmi_runtime_get(); if (r) - return r; + goto err_runtime_get; - dss_mgr_disable(dssdev->manager); + dss_mgr_disable(mgr); - p = &dssdev->panel.timings; + p = &hdmi.ip_data.cfg.timings; - DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", - dssdev->panel.timings.x_res, - dssdev->panel.timings.y_res); + DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); - timing = hdmi_get_timings(); - if (timing == NULL) { - /* HDMI code 4 corresponds to 640 * 480 VGA */ - hdmi.ip_data.cfg.cm.code = 4; - /* DVI mode 1 corresponds to HDMI 0 to DVI */ - hdmi.ip_data.cfg.cm.mode = HDMI_DVI; - hdmi.ip_data.cfg = vesa_timings[0]; - } else { - hdmi.ip_data.cfg = *timing; - } phy = p->pixel_clock; hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); @@ -495,13 +537,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to lock PLL\n"); - goto err; + goto err_pll_enable; } r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to start PHY\n"); - goto err; + goto err_phy_enable; } hdmi.ip_data.ops->video_configure(&hdmi.ip_data); @@ -521,13 +563,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dispc_enable_gamma_table(0); /* tv size */ - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); + dss_mgr_set_timings(mgr, p); r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); if (r) goto err_vid_enable; - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) goto err_mgr_enable; @@ -537,20 +579,33 @@ err_mgr_enable: hdmi.ip_data.ops->video_disable(&hdmi.ip_data); err_vid_enable: hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); +err_phy_enable: hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); -err: +err_pll_enable: hdmi_runtime_put(); +err_runtime_get: + regulator_disable(hdmi.vdda_hdmi_dac_reg); +err_vdac_enable: + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); return -EIO; } static void hdmi_power_off(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + dss_mgr_disable(mgr); hdmi.ip_data.ops->video_disable(&hdmi.ip_data); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); hdmi_runtime_put(); + + regulator_disable(hdmi.vdda_hdmi_dac_reg); + + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); } int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, @@ -567,25 +622,22 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, } -void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { struct hdmi_cm cm; + const struct hdmi_config *t; - cm = hdmi_get_code(&dssdev->panel.timings); - hdmi.ip_data.cfg.cm.code = cm.code; - hdmi.ip_data.cfg.cm.mode = cm.mode; + mutex_lock(&hdmi.lock); - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - int r; + cm = hdmi_get_code(timings); + hdmi.ip_data.cfg.cm = cm; - hdmi_power_off(dssdev); + t = hdmi_get_timings(); + if (t != NULL) + hdmi.ip_data.cfg = *t; - r = hdmi_power_on(dssdev); - if (r) - DSSERR("failed to power on device\n"); - } else { - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); - } + mutex_unlock(&hdmi.lock); } static void hdmi_dump_regs(struct seq_file *s) @@ -640,20 +692,20 @@ bool omapdss_hdmi_detect(void) int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_hdmi_data *priv = dssdev->data; + struct omap_dss_output *out = dssdev->output; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi.lock); - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - hdmi.ip_data.hpd_gpio = priv->hpd_gpio; + hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; r = omap_dss_start_device(dssdev); if (r) { @@ -661,26 +713,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) { - DSSERR("failed to enable GPIO's\n"); - goto err1; - } - } - r = hdmi_power_on(dssdev); if (r) { DSSERR("failed to power on device\n"); - goto err2; + goto err1; } mutex_unlock(&hdmi.lock); return 0; -err2: - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); err1: omap_dss_stop_device(dssdev); err0: @@ -696,9 +737,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) hdmi_power_off(dssdev); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - omap_dss_stop_device(dssdev); mutex_unlock(&hdmi.lock); @@ -869,10 +907,14 @@ int hdmi_audio_config(struct omap_dss_audio *audio) #endif -static void __init hdmi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int r, i; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -880,17 +922,76 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI) continue; - r = hdmi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init hdmi_probe_pdata(struct platform_device *pdev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + struct omap_dss_hdmi_data *priv; + int r; + + plat_dssdev = hdmi_find_dssdev(pdev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&pdev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + priv = dssdev->data; + + hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio; + hdmi.ls_oe_gpio = priv->ls_oe_gpio; + hdmi.hpd_gpio = priv->hpd_gpio; + + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + + r = hdmi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init hdmi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &hdmi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_HDMI; + out->type = OMAP_DISPLAY_TYPE_HDMI; + + dss_register_output(out); +} + +static void __exit hdmi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &hdmi.output; + + dss_unregister_output(out); } /* HDMI HW IP initialisation */ @@ -929,23 +1030,37 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi.ip_data.core_av_offset = HDMI_CORE_AV; hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.phy_offset = HDMI_PHY; + mutex_init(&hdmi.ip_data.lock); hdmi_panel_init(); dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi_init_output(pdev); + hdmi_probe_pdata(pdev); return 0; } +static int __exit hdmi_remove_child(struct device *dev, void *data) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + hdmi_uninit_display(dssdev); + return 0; +} + static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + device_for_each_child(&pdev->dev, NULL, hdmi_remove_child); + + dss_unregister_child_devices(&pdev->dev); hdmi_panel_exit(); + hdmi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); hdmi_put_clocks(); diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index e10844faadf9..69fb115bab32 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c @@ -41,17 +41,34 @@ static struct { static int hdmi_panel_probe(struct omap_dss_device *dssdev) { + /* Initialize default timings to VGA in DVI mode */ + const struct omap_video_timings default_timings = { + .x_res = 640, + .y_res = 480, + .pixel_clock = 25175, + .hsw = 96, + .hfp = 16, + .hbp = 48, + .vsw = 2, + .vfp = 11, + .vbp = 31, + + .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, + .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, + + .interlace = false, + }; + DSSDBG("ENTER hdmi_panel_probe\n"); - dssdev->panel.timings = (struct omap_video_timings) - { 640, 480, 25175, 96, 16, 48, 2, 11, 31, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, - }; + dssdev->panel.timings = default_timings; DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); + + omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); + return 0; } @@ -228,6 +245,8 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev) goto err; } + omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); + r = omapdss_hdmi_display_enable(dssdev); if (r) { DSSERR("failed to power on\n"); @@ -336,8 +355,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, */ hdmi_panel_audio_disable(dssdev); + omapdss_hdmi_display_set_timing(dssdev, timings); dssdev->panel.timings = *timings; - omapdss_hdmi_display_set_timing(dssdev); mutex_unlock(&hdmi.lock); } diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c new file mode 100644 index 000000000000..9a2fb59b6f89 --- /dev/null +++ b/drivers/video/omap2/dss/manager-sysfs.c @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "MANAGER" + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/jiffies.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); +} + +static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) +{ + struct omap_dss_device *dssdev = mgr->get_device(mgr); + + return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ? + dssdev->name : "<none>"); +} + +static ssize_t manager_display_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + int r = 0; + size_t len = size; + struct omap_dss_device *dssdev = NULL; + + int match(struct omap_dss_device *dssdev, void *data) + { + const char *str = data; + return sysfs_streq(dssdev->name, str); + } + + if (buf[size-1] == '\n') + --len; + + if (len > 0) + dssdev = omap_dss_find_device((void *)buf, match); + + if (len > 0 && dssdev == NULL) + return -EINVAL; + + if (dssdev) + DSSDBG("display %s found\n", dssdev->name); + + if (mgr->output) { + r = mgr->unset_output(mgr); + if (r) { + DSSERR("failed to unset current output\n"); + goto put_device; + } + } + + if (dssdev) { + struct omap_dss_output *out = dssdev->output; + + /* + * a registered device should have an output connected to it + * already + */ + if (!out) { + DSSERR("device has no output connected to it\n"); + goto put_device; + } + + r = mgr->set_output(mgr, out); + if (r) { + DSSERR("failed to set manager output\n"); + goto put_device; + } + + r = mgr->apply(mgr); + if (r) { + DSSERR("failed to apply dispc config\n"); + goto put_device; + } + } + +put_device: + if (dssdev) + omap_dss_put_device(dssdev); + + return r ? r : size; +} + +static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); +} + +static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + u32 color; + int r; + + r = kstrtouint(buf, 0, &color); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.default_color = color; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static const char *trans_key_type_str[] = { + "gfx-destination", + "video-source", +}; + +static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, + char *buf) +{ + enum omap_dss_trans_key_type key_type; + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + key_type = info.trans_key_type; + BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); + + return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); +} + +static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + enum omap_dss_trans_key_type key_type; + struct omap_overlay_manager_info info; + int r; + + for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; + key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { + if (sysfs_streq(buf, trans_key_type_str[key_type])) + break; + } + + if (key_type == ARRAY_SIZE(trans_key_type_str)) + return -EINVAL; + + mgr->get_manager_info(mgr, &info); + + info.trans_key_type = key_type; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); +} + +static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + u32 key_value; + int r; + + r = kstrtouint(buf, 0, &key_value); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.trans_key = key_value; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); +} + +static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + bool enable; + int r; + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.trans_enabled = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_alpha_blending_enabled_show( + struct omap_overlay_manager *mgr, char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.partial_alpha_enabled); +} + +static ssize_t manager_alpha_blending_enabled_store( + struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + bool enable; + int r; + + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.partial_alpha_enabled = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); +} + +static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + int r; + bool enable; + + if (!dss_has_feature(FEAT_CPR)) + return -ENODEV; + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + if (info.cpr_enable == enable) + return size; + + info.cpr_enable = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, + "%d %d %d %d %d %d %d %d %d\n", + info.cpr_coefs.rr, + info.cpr_coefs.rg, + info.cpr_coefs.rb, + info.cpr_coefs.gr, + info.cpr_coefs.gg, + info.cpr_coefs.gb, + info.cpr_coefs.br, + info.cpr_coefs.bg, + info.cpr_coefs.bb); +} + +static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + struct omap_dss_cpr_coefs coefs; + int r, i; + s16 *arr; + + if (!dss_has_feature(FEAT_CPR)) + return -ENODEV; + + if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", + &coefs.rr, &coefs.rg, &coefs.rb, + &coefs.gr, &coefs.gg, &coefs.gb, + &coefs.br, &coefs.bg, &coefs.bb) != 9) + return -EINVAL; + + arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, + coefs.gr, coefs.gg, coefs.gb, + coefs.br, coefs.bg, coefs.bb }; + + for (i = 0; i < 9; ++i) { + if (arr[i] < -512 || arr[i] > 511) + return -EINVAL; + } + + mgr->get_manager_info(mgr, &info); + + info.cpr_coefs = coefs; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +struct manager_attribute { + struct attribute attr; + ssize_t (*show)(struct omap_overlay_manager *, char *); + ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); +}; + +#define MANAGER_ATTR(_name, _mode, _show, _store) \ + struct manager_attribute manager_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); +static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, + manager_display_show, manager_display_store); +static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, + manager_default_color_show, manager_default_color_store); +static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, + manager_trans_key_type_show, manager_trans_key_type_store); +static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, + manager_trans_key_value_show, manager_trans_key_value_store); +static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, + manager_trans_key_enabled_show, + manager_trans_key_enabled_store); +static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, + manager_alpha_blending_enabled_show, + manager_alpha_blending_enabled_store); +static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, + manager_cpr_enable_show, + manager_cpr_enable_store); +static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, + manager_cpr_coef_show, + manager_cpr_coef_store); + + +static struct attribute *manager_sysfs_attrs[] = { + &manager_attr_name.attr, + &manager_attr_display.attr, + &manager_attr_default_color.attr, + &manager_attr_trans_key_type.attr, + &manager_attr_trans_key_value.attr, + &manager_attr_trans_key_enabled.attr, + &manager_attr_alpha_blending_enabled.attr, + &manager_attr_cpr_enable.attr, + &manager_attr_cpr_coef.attr, + NULL +}; + +static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct omap_overlay_manager *manager; + struct manager_attribute *manager_attr; + + manager = container_of(kobj, struct omap_overlay_manager, kobj); + manager_attr = container_of(attr, struct manager_attribute, attr); + + if (!manager_attr->show) + return -ENOENT; + + return manager_attr->show(manager, buf); +} + +static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + struct omap_overlay_manager *manager; + struct manager_attribute *manager_attr; + + manager = container_of(kobj, struct omap_overlay_manager, kobj); + manager_attr = container_of(attr, struct manager_attribute, attr); + + if (!manager_attr->store) + return -ENOENT; + + return manager_attr->store(manager, buf, size); +} + +static const struct sysfs_ops manager_sysfs_ops = { + .show = manager_attr_show, + .store = manager_attr_store, +}; + +static struct kobj_type manager_ktype = { + .sysfs_ops = &manager_sysfs_ops, + .default_attrs = manager_sysfs_attrs, +}; + +int dss_manager_kobj_init(struct omap_overlay_manager *mgr, + struct platform_device *pdev) +{ + return kobject_init_and_add(&mgr->kobj, &manager_ktype, + &pdev->dev.kobj, "manager%d", mgr->id); +} + +void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) +{ + kobject_del(&mgr->kobj); + kobject_put(&mgr->kobj); +} diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 53710fadc82d..c54d2f620ce3 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -36,463 +36,15 @@ static int num_managers; static struct omap_overlay_manager *managers; -static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) +static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) { - return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); + return mgr->output ? mgr->output->device : NULL; } -static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - mgr->device ? mgr->device->name : "<none>"); -} - -static ssize_t manager_display_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - int r = 0; - size_t len = size; - struct omap_dss_device *dssdev = NULL; - - int match(struct omap_dss_device *dssdev, void *data) - { - const char *str = data; - return sysfs_streq(dssdev->name, str); - } - - if (buf[size-1] == '\n') - --len; - - if (len > 0) - dssdev = omap_dss_find_device((void *)buf, match); - - if (len > 0 && dssdev == NULL) - return -EINVAL; - - if (dssdev) - DSSDBG("display %s found\n", dssdev->name); - - if (mgr->device) { - r = mgr->unset_device(mgr); - if (r) { - DSSERR("failed to unset display\n"); - goto put_device; - } - } - - if (dssdev) { - r = mgr->set_device(mgr, dssdev); - if (r) { - DSSERR("failed to set manager\n"); - goto put_device; - } - - r = mgr->apply(mgr); - if (r) { - DSSERR("failed to apply dispc config\n"); - goto put_device; - } - } - -put_device: - if (dssdev) - omap_dss_put_device(dssdev); - - return r ? r : size; -} - -static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); -} - -static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 color; - int r; - - r = kstrtouint(buf, 0, &color); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.default_color = color; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static const char *trans_key_type_str[] = { - "gfx-destination", - "video-source", -}; - -static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, - char *buf) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - key_type = info.trans_key_type; - BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); - - return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); -} - -static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - int r; - - for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; - key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { - if (sysfs_streq(buf, trans_key_type_str[key_type])) - break; - } - - if (key_type == ARRAY_SIZE(trans_key_type_str)) - return -EINVAL; - - mgr->get_manager_info(mgr, &info); - - info.trans_key_type = key_type; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); -} - -static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 key_value; - int r; - - r = kstrtouint(buf, 0, &key_value); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_key = key_value; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); -} - -static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_alpha_blending_enabled_show( - struct omap_overlay_manager *mgr, char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.partial_alpha_enabled); -} - -static ssize_t manager_alpha_blending_enabled_store( - struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.partial_alpha_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); -} - -static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - int r; - bool enable; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - if (info.cpr_enable == enable) - return size; - - info.cpr_enable = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, - "%d %d %d %d %d %d %d %d %d\n", - info.cpr_coefs.rr, - info.cpr_coefs.rg, - info.cpr_coefs.rb, - info.cpr_coefs.gr, - info.cpr_coefs.gg, - info.cpr_coefs.gb, - info.cpr_coefs.br, - info.cpr_coefs.bg, - info.cpr_coefs.bb); -} - -static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - struct omap_dss_cpr_coefs coefs; - int r, i; - s16 *arr; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", - &coefs.rr, &coefs.rg, &coefs.rb, - &coefs.gr, &coefs.gg, &coefs.gb, - &coefs.br, &coefs.bg, &coefs.bb) != 9) - return -EINVAL; - - arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, - coefs.gr, coefs.gg, coefs.gb, - coefs.br, coefs.bg, coefs.bb }; - - for (i = 0; i < 9; ++i) { - if (arr[i] < -512 || arr[i] > 511) - return -EINVAL; - } - - mgr->get_manager_info(mgr, &info); - - info.cpr_coefs = coefs; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -struct manager_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay_manager *, char *); - ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); -}; - -#define MANAGER_ATTR(_name, _mode, _show, _store) \ - struct manager_attribute manager_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); -static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, - manager_display_show, manager_display_store); -static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, - manager_default_color_show, manager_default_color_store); -static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, - manager_trans_key_type_show, manager_trans_key_type_store); -static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, - manager_trans_key_value_show, manager_trans_key_value_store); -static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, - manager_trans_key_enabled_show, - manager_trans_key_enabled_store); -static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, - manager_alpha_blending_enabled_show, - manager_alpha_blending_enabled_store); -static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, - manager_cpr_enable_show, - manager_cpr_enable_store); -static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, - manager_cpr_coef_show, - manager_cpr_coef_store); - - -static struct attribute *manager_sysfs_attrs[] = { - &manager_attr_name.attr, - &manager_attr_display.attr, - &manager_attr_default_color.attr, - &manager_attr_trans_key_type.attr, - &manager_attr_trans_key_value.attr, - &manager_attr_trans_key_enabled.attr, - &manager_attr_alpha_blending_enabled.attr, - &manager_attr_cpr_enable.attr, - &manager_attr_cpr_coef.attr, - NULL -}; - -static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->show) - return -ENOENT; - - return manager_attr->show(manager, buf); -} - -static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->store) - return -ENOENT; - - return manager_attr->store(manager, buf, size); -} - -static const struct sysfs_ops manager_sysfs_ops = { - .show = manager_attr_show, - .store = manager_attr_store, -}; - -static struct kobj_type manager_ktype = { - .sysfs_ops = &manager_sysfs_ops, - .default_attrs = manager_sysfs_attrs, -}; - static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); + struct omap_dss_device *dssdev = mgr->get_device(mgr); u32 irq; int r; @@ -500,9 +52,9 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) if (r) return r; - if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) irq = DISPC_IRQ_EVSYNC_ODD; - else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) + else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) irq = DISPC_IRQ_EVSYNC_EVEN; else irq = dispc_mgr_get_vsync_irq(mgr->id); @@ -547,23 +99,24 @@ int dss_init_overlay_managers(struct platform_device *pdev) break; } - mgr->set_device = &dss_mgr_set_device; - mgr->unset_device = &dss_mgr_unset_device; + mgr->set_output = &dss_mgr_set_output; + mgr->unset_output = &dss_mgr_unset_output; mgr->apply = &omap_dss_mgr_apply; mgr->set_manager_info = &dss_mgr_set_info; mgr->get_manager_info = &dss_mgr_get_info; mgr->wait_for_go = &dss_mgr_wait_for_go; mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; + mgr->get_device = &dss_mgr_get_device; mgr->caps = 0; mgr->supported_displays = dss_feat_get_supported_displays(mgr->id); + mgr->supported_outputs = + dss_feat_get_supported_outputs(mgr->id); INIT_LIST_HEAD(&mgr->overlays); - r = kobject_init_and_add(&mgr->kobj, &manager_ktype, - &pdev->dev.kobj, "manager%d", i); - + r = dss_manager_kobj_init(mgr, pdev); if (r) DSSERR("failed to create sysfs file\n"); } @@ -577,9 +130,7 @@ void dss_uninit_overlay_managers(struct platform_device *pdev) for (i = 0; i < num_managers; ++i) { struct omap_overlay_manager *mgr = &managers[i]; - - kobject_del(&mgr->kobj); - kobject_put(&mgr->kobj); + dss_manager_kobj_uninit(mgr); } kfree(managers); diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c new file mode 100644 index 000000000000..813f26682b7a --- /dev/null +++ b/drivers/video/omap2/dss/output.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2012 Texas Instruments Ltd + * Author: Archit Taneja <archit@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <video/omapdss.h> + +#include "dss.h" + +static LIST_HEAD(output_list); +static DEFINE_MUTEX(output_lock); + +int omapdss_output_set_device(struct omap_dss_output *out, + struct omap_dss_device *dssdev) +{ + int r; + + mutex_lock(&output_lock); + + if (out->device) { + DSSERR("output already has device %s connected to it\n", + out->device->name); + r = -EINVAL; + goto err; + } + + if (out->type != dssdev->type) { + DSSERR("output type and display type don't match\n"); + r = -EINVAL; + goto err; + } + + out->device = dssdev; + dssdev->output = out; + + mutex_unlock(&output_lock); + + return 0; +err: + mutex_unlock(&output_lock); + + return r; +} +EXPORT_SYMBOL(omapdss_output_set_device); + +int omapdss_output_unset_device(struct omap_dss_output *out) +{ + int r; + + mutex_lock(&output_lock); + + if (!out->device) { + DSSERR("output doesn't have a device connected to it\n"); + r = -EINVAL; + goto err; + } + + if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) { + DSSERR("device %s is not disabled, cannot unset device\n", + out->device->name); + r = -EINVAL; + goto err; + } + + out->device->output = NULL; + out->device = NULL; + + mutex_unlock(&output_lock); + + return 0; +err: + mutex_unlock(&output_lock); + + return r; +} +EXPORT_SYMBOL(omapdss_output_unset_device); + +void dss_register_output(struct omap_dss_output *out) +{ + list_add_tail(&out->list, &output_list); +} + +void dss_unregister_output(struct omap_dss_output *out) +{ + list_del(&out->list); +} + +struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) +{ + struct omap_dss_output *out; + + list_for_each_entry(out, &output_list, list) { + if (out->id == id) + return out; + } + + return NULL; +} + +struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev) +{ + struct omap_dss_output *out = NULL; + enum omap_dss_output_id id; + + switch (dssdev->type) { + case OMAP_DISPLAY_TYPE_DPI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI); + break; + case OMAP_DISPLAY_TYPE_DBI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI); + break; + case OMAP_DISPLAY_TYPE_SDI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI); + break; + case OMAP_DISPLAY_TYPE_VENC: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC); + break; + case OMAP_DISPLAY_TYPE_HDMI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI); + break; + case OMAP_DISPLAY_TYPE_DSI: + id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 : + OMAP_DSS_OUTPUT_DSI2; + out = omap_dss_get_output(id); + break; + default: + break; + } + + return out; +} diff --git a/drivers/video/omap2/dss/overlay-sysfs.c b/drivers/video/omap2/dss/overlay-sysfs.c new file mode 100644 index 000000000000..4cc5ddebfb34 --- /dev/null +++ b/drivers/video/omap2/dss/overlay-sysfs.c @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "OVERLAY" + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/kobject.h> +#include <linux/platform_device.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); +} + +static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", + ovl->manager ? ovl->manager->name : "<none>"); +} + +static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, + size_t size) +{ + int i, r; + struct omap_overlay_manager *mgr = NULL; + struct omap_overlay_manager *old_mgr; + int len = size; + + if (buf[size-1] == '\n') + --len; + + if (len > 0) { + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + mgr = omap_dss_get_overlay_manager(i); + + if (sysfs_streq(buf, mgr->name)) + break; + + mgr = NULL; + } + } + + if (len > 0 && mgr == NULL) + return -EINVAL; + + if (mgr) + DSSDBG("manager %s found\n", mgr->name); + + if (mgr == ovl->manager) + return size; + + old_mgr = ovl->manager; + + r = dispc_runtime_get(); + if (r) + return r; + + /* detach old manager */ + if (old_mgr) { + r = ovl->unset_manager(ovl); + if (r) { + DSSERR("detach failed\n"); + goto err; + } + + r = old_mgr->apply(old_mgr); + if (r) + goto err; + } + + if (mgr) { + r = ovl->set_manager(ovl, mgr); + if (r) { + DSSERR("Failed to attach overlay\n"); + goto err; + } + + r = mgr->apply(mgr); + if (r) + goto err; + } + + dispc_runtime_put(); + + return size; + +err: + dispc_runtime_put(); + return r; +} + +static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.width, info.height); +} + +static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); +} + +static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.pos_x, info.pos_y); +} + +static ssize_t overlay_position_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + char *last; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.pos_x = simple_strtoul(buf, &last, 10); + ++last; + if (last - buf >= size) + return -EINVAL; + + info.pos_y = simple_strtoul(last, &last, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.out_width, info.out_height); +} + +static ssize_t overlay_output_size_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + char *last; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.out_width = simple_strtoul(buf, &last, 10); + ++last; + if (last - buf >= size) + return -EINVAL; + + info.out_height = simple_strtoul(last, &last, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); +} + +static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, + size_t size) +{ + int r; + bool enable; + + r = strtobool(buf, &enable); + if (r) + return r; + + if (enable) + r = ovl->enable(ovl); + else + r = ovl->disable(ovl); + + if (r) + return r; + + return size; +} + +static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.global_alpha); +} + +static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 alpha; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &alpha); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.global_alpha = alpha; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, + char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.pre_mult_alpha); +} + +static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 alpha; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &alpha); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.pre_mult_alpha = alpha; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); +} + +static ssize_t overlay_zorder_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 zorder; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &zorder); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.zorder = zorder; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +struct overlay_attribute { + struct attribute attr; + ssize_t (*show)(struct omap_overlay *, char *); + ssize_t (*store)(struct omap_overlay *, const char *, size_t); +}; + +#define OVERLAY_ATTR(_name, _mode, _show, _store) \ + struct overlay_attribute overlay_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); +static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, + overlay_manager_show, overlay_manager_store); +static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); +static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); +static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, + overlay_position_show, overlay_position_store); +static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, + overlay_output_size_show, overlay_output_size_store); +static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, + overlay_enabled_show, overlay_enabled_store); +static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, + overlay_global_alpha_show, overlay_global_alpha_store); +static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, + overlay_pre_mult_alpha_show, + overlay_pre_mult_alpha_store); +static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, + overlay_zorder_show, overlay_zorder_store); + +static struct attribute *overlay_sysfs_attrs[] = { + &overlay_attr_name.attr, + &overlay_attr_manager.attr, + &overlay_attr_input_size.attr, + &overlay_attr_screen_width.attr, + &overlay_attr_position.attr, + &overlay_attr_output_size.attr, + &overlay_attr_enabled.attr, + &overlay_attr_global_alpha.attr, + &overlay_attr_pre_mult_alpha.attr, + &overlay_attr_zorder.attr, + NULL +}; + +static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct omap_overlay *overlay; + struct overlay_attribute *overlay_attr; + + overlay = container_of(kobj, struct omap_overlay, kobj); + overlay_attr = container_of(attr, struct overlay_attribute, attr); + + if (!overlay_attr->show) + return -ENOENT; + + return overlay_attr->show(overlay, buf); +} + +static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + struct omap_overlay *overlay; + struct overlay_attribute *overlay_attr; + + overlay = container_of(kobj, struct omap_overlay, kobj); + overlay_attr = container_of(attr, struct overlay_attribute, attr); + + if (!overlay_attr->store) + return -ENOENT; + + return overlay_attr->store(overlay, buf, size); +} + +static const struct sysfs_ops overlay_sysfs_ops = { + .show = overlay_attr_show, + .store = overlay_attr_store, +}; + +static struct kobj_type overlay_ktype = { + .sysfs_ops = &overlay_sysfs_ops, + .default_attrs = overlay_sysfs_attrs, +}; + +int dss_overlay_kobj_init(struct omap_overlay *ovl, + struct platform_device *pdev) +{ + return kobject_init_and_add(&ovl->kobj, &overlay_ktype, + &pdev->dev.kobj, "overlay%d", ovl->id); +} + +void dss_overlay_kobj_uninit(struct omap_overlay *ovl) +{ + kobject_del(&ovl->kobj); + kobject_put(&ovl->kobj); +} diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 952c6fad9a81..45f4994bc6b0 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -26,13 +26,11 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/sysfs.h> -#include <linux/kobject.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/slab.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -40,417 +38,13 @@ static int num_overlays; static struct omap_overlay *overlays; -static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) +static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) { - return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); + return ovl->manager ? + (ovl->manager->output ? ovl->manager->output->device : NULL) : + NULL; } -static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - ovl->manager ? ovl->manager->name : "<none>"); -} - -static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int i, r; - struct omap_overlay_manager *mgr = NULL; - struct omap_overlay_manager *old_mgr; - int len = size; - - if (buf[size-1] == '\n') - --len; - - if (len > 0) { - for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { - mgr = omap_dss_get_overlay_manager(i); - - if (sysfs_streq(buf, mgr->name)) - break; - - mgr = NULL; - } - } - - if (len > 0 && mgr == NULL) - return -EINVAL; - - if (mgr) - DSSDBG("manager %s found\n", mgr->name); - - if (mgr == ovl->manager) - return size; - - old_mgr = ovl->manager; - - r = dispc_runtime_get(); - if (r) - return r; - - /* detach old manager */ - if (old_mgr) { - r = ovl->unset_manager(ovl); - if (r) { - DSSERR("detach failed\n"); - goto err; - } - - r = old_mgr->apply(old_mgr); - if (r) - goto err; - } - - if (mgr) { - r = ovl->set_manager(ovl, mgr); - if (r) { - DSSERR("Failed to attach overlay\n"); - goto err; - } - - r = mgr->apply(mgr); - if (r) - goto err; - } - - dispc_runtime_put(); - - return size; - -err: - dispc_runtime_put(); - return r; -} - -static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.width, info.height); -} - -static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); -} - -static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.pos_x, info.pos_y); -} - -static ssize_t overlay_position_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.pos_x = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.pos_y = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.out_width, info.out_height); -} - -static ssize_t overlay_output_size_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.out_width = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.out_height = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); -} - -static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int r; - bool enable; - - r = strtobool(buf, &enable); - if (r) - return r; - - if (enable) - r = ovl->enable(ovl); - else - r = ovl->disable(ovl); - - if (r) - return r; - - return size; -} - -static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.global_alpha); -} - -static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.global_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, - char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.pre_mult_alpha); -} - -static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.pre_mult_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); -} - -static ssize_t overlay_zorder_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 zorder; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &zorder); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.zorder = zorder; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -struct overlay_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay *, char *); - ssize_t (*store)(struct omap_overlay *, const char *, size_t); -}; - -#define OVERLAY_ATTR(_name, _mode, _show, _store) \ - struct overlay_attribute overlay_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); -static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, - overlay_manager_show, overlay_manager_store); -static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); -static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); -static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, - overlay_position_show, overlay_position_store); -static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, - overlay_output_size_show, overlay_output_size_store); -static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, - overlay_enabled_show, overlay_enabled_store); -static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, - overlay_global_alpha_show, overlay_global_alpha_store); -static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, - overlay_pre_mult_alpha_show, - overlay_pre_mult_alpha_store); -static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, - overlay_zorder_show, overlay_zorder_store); - -static struct attribute *overlay_sysfs_attrs[] = { - &overlay_attr_name.attr, - &overlay_attr_manager.attr, - &overlay_attr_input_size.attr, - &overlay_attr_screen_width.attr, - &overlay_attr_position.attr, - &overlay_attr_output_size.attr, - &overlay_attr_enabled.attr, - &overlay_attr_global_alpha.attr, - &overlay_attr_pre_mult_alpha.attr, - &overlay_attr_zorder.attr, - NULL -}; - -static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->show) - return -ENOENT; - - return overlay_attr->show(overlay, buf); -} - -static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->store) - return -ENOENT; - - return overlay_attr->store(overlay, buf, size); -} - -static const struct sysfs_ops overlay_sysfs_ops = { - .show = overlay_attr_show, - .store = overlay_attr_store, -}; - -static struct kobj_type overlay_ktype = { - .sysfs_ops = &overlay_sysfs_ops, - .default_attrs = overlay_sysfs_attrs, -}; - int omap_dss_get_num_overlays(void) { return num_overlays; @@ -507,97 +101,25 @@ void dss_init_overlays(struct platform_device *pdev) ovl->set_overlay_info = &dss_ovl_set_info; ovl->get_overlay_info = &dss_ovl_get_info; ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; + ovl->get_device = &dss_ovl_get_device; ovl->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); - r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, - &pdev->dev.kobj, "overlay%d", i); - + r = dss_overlay_kobj_init(ovl, pdev); if (r) DSSERR("failed to create sysfs file\n"); } } -/* connect overlays to the new device, if not already connected. if force - * selected, connect always. */ -void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) -{ - int i; - struct omap_overlay_manager *lcd_mgr; - struct omap_overlay_manager *tv_mgr; - struct omap_overlay_manager *lcd2_mgr = NULL; - struct omap_overlay_manager *lcd3_mgr = NULL; - struct omap_overlay_manager *mgr = NULL; - - lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD); - tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT); - if (dss_has_feature(FEAT_MGR_LCD3)) - lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3); - if (dss_has_feature(FEAT_MGR_LCD2)) - lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2); - - if (dssdev->channel == OMAP_DSS_CHANNEL_LCD3) { - if (!lcd3_mgr->device || force) { - if (lcd3_mgr->device) - lcd3_mgr->unset_device(lcd3_mgr); - lcd3_mgr->set_device(lcd3_mgr, dssdev); - mgr = lcd3_mgr; - } - } else if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { - if (!lcd2_mgr->device || force) { - if (lcd2_mgr->device) - lcd2_mgr->unset_device(lcd2_mgr); - lcd2_mgr->set_device(lcd2_mgr, dssdev); - mgr = lcd2_mgr; - } - } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC - && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) { - if (!lcd_mgr->device || force) { - if (lcd_mgr->device) - lcd_mgr->unset_device(lcd_mgr); - lcd_mgr->set_device(lcd_mgr, dssdev); - mgr = lcd_mgr; - } - } - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - if (!tv_mgr->device || force) { - if (tv_mgr->device) - tv_mgr->unset_device(tv_mgr); - tv_mgr->set_device(tv_mgr, dssdev); - mgr = tv_mgr; - } - } - - if (mgr) { - dispc_runtime_get(); - - for (i = 0; i < dss_feat_get_num_ovls(); i++) { - struct omap_overlay *ovl; - ovl = omap_dss_get_overlay(i); - if (!ovl->manager || force) { - if (ovl->manager) - ovl->unset_manager(ovl); - ovl->set_manager(ovl, mgr); - } - } - - dispc_runtime_put(); - } -} - void dss_uninit_overlays(struct platform_device *pdev) { int i; for (i = 0; i < num_overlays; ++i) { struct omap_overlay *ovl = &overlays[i]; - - kobject_del(&ovl->kobj); - kobject_put(&ovl->kobj); + dss_overlay_kobj_uninit(ovl); } kfree(overlays); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 7c087424b634..7282e5af3e1a 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -111,6 +111,13 @@ static struct { struct omap_dss_device *dssdev[2]; struct semaphore bus_lock; + + struct omap_video_timings timings; + int pixel_size; + int data_lines; + struct rfbi_timings intf_timings; + + struct omap_dss_output output; } rfbi; static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) @@ -300,30 +307,23 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, } EXPORT_SYMBOL(omap_rfbi_write_pixels); -static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, - u16 height, void (*callback)(void *data), void *data) +static int rfbi_transfer_area(struct omap_dss_device *dssdev, + void (*callback)(void *data), void *data) { u32 l; int r; - struct omap_video_timings timings = { - .hsw = 1, - .hfp = 1, - .hbp = 1, - .vsw = 1, - .vfp = 0, - .vbp = 0, - .x_res = width, - .y_res = height, - }; + struct omap_overlay_manager *mgr = dssdev->output->manager; + u16 width = rfbi.timings.x_res; + u16 height = rfbi.timings.y_res; /*BUG_ON(callback == 0);*/ BUG_ON(rfbi.framedone_callback != NULL); DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - dss_mgr_set_timings(dssdev->manager, &timings); + dss_mgr_set_timings(mgr, &rfbi.timings); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) return r; @@ -770,62 +770,45 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines) return 0; } -int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size, - int data_lines) +int omap_rfbi_configure(struct omap_dss_device *dssdev) { - return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines); + return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, + rfbi.data_lines); } EXPORT_SYMBOL(omap_rfbi_configure); -int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h) +int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), + void *data) { - u16 dw, dh; - struct omap_video_timings timings = { - .hsw = 1, - .hfp = 1, - .hbp = 1, - .vsw = 1, - .vfp = 0, - .vbp = 0, - .x_res = *w, - .y_res = *h, - }; - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - if (*x > dw || *y > dh) - return -EINVAL; - - if (*x + *w > dw) - return -EINVAL; - - if (*y + *h > dh) - return -EINVAL; - - if (*w == 1) - return -EINVAL; - - if (*w == 0 || *h == 0) - return -EINVAL; - - dss_mgr_set_timings(dssdev->manager, &timings); + return rfbi_transfer_area(dssdev, callback, data); +} +EXPORT_SYMBOL(omap_rfbi_update); - return 0; +void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) +{ + rfbi.timings.x_res = w; + rfbi.timings.y_res = h; } -EXPORT_SYMBOL(omap_rfbi_prepare_update); +EXPORT_SYMBOL(omapdss_rfbi_set_size); -int omap_rfbi_update(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h, - void (*callback)(void *), void *data) +void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size) { - int r; + rfbi.pixel_size = pixel_size; +} +EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size); - r = rfbi_transfer_area(dssdev, w, h, callback, data); +void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) +{ + rfbi.data_lines = data_lines; +} +EXPORT_SYMBOL(omapdss_rfbi_set_data_lines); - return r; +void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev, + struct rfbi_timings *timings) +{ + rfbi.intf_timings = *timings; } -EXPORT_SYMBOL(omap_rfbi_update); +EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings); static void rfbi_dump_regs(struct seq_file *s) { @@ -869,6 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s) static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; struct dss_lcd_mgr_config mgr_config; mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; @@ -877,18 +861,40 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) /* Do we need fifohandcheck for RFBI? */ mgr_config.fifohandcheck = false; - mgr_config.video_port_width = dssdev->ctrl.pixel_size; + mgr_config.video_port_width = rfbi.pixel_size; mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &mgr_config); + dss_mgr_set_lcd_config(mgr, &mgr_config); + + /* + * Set rfbi.timings with default values, the x_res and y_res fields + * are expected to be already configured by the panel driver via + * omapdss_rfbi_set_size() + */ + rfbi.timings.hsw = 1; + rfbi.timings.hfp = 1; + rfbi.timings.hbp = 1; + rfbi.timings.vsw = 1; + rfbi.timings.vfp = 0; + rfbi.timings.vbp = 0; + + rfbi.timings.interlace = false; + rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + + dss_mgr_set_timings(mgr, &rfbi.timings); } int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_output *out = dssdev->output; int r; - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -911,13 +917,10 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) rfbi_config_lcd_manager(dssdev); - rfbi_configure(dssdev->phy.rfbi.channel, - dssdev->ctrl.pixel_size, - dssdev->phy.rfbi.data_lines); - - rfbi_set_timings(dssdev->phy.rfbi.channel, - &dssdev->ctrl.rfbi_timings); + rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, + rfbi.data_lines); + rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings); return 0; err1: @@ -941,14 +944,17 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable); static int __init rfbi_init_display(struct omap_dss_device *dssdev) { rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; return 0; } -static void __init rfbi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -956,17 +962,67 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_DBI) continue; - r = rfbi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init rfbi_probe_pdata(struct platform_device *rfbidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = rfbi_find_dssdev(rfbidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&rfbidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + r = rfbi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init rfbi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &rfbi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_DBI; + out->type = OMAP_DISPLAY_TYPE_DBI; + + dss_register_output(out); +} + +static void __exit rfbi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &rfbi.output; + + dss_unregister_output(out); } /* RFBI HW IP initialisation */ @@ -1020,6 +1076,8 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev) dss_debugfs_create_file("rfbi", rfbi_dump_regs); + rfbi_init_output(pdev); + rfbi_probe_pdata(pdev); return 0; @@ -1031,8 +1089,12 @@ err_runtime_get: static int __exit omap_rfbihw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + rfbi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); + return 0; } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index f43bfe17b3b6..7760851f6e5d 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -25,6 +25,7 @@ #include <linux/regulator/consumer.h> #include <linux/export.h> #include <linux/platform_device.h> +#include <linux/string.h> #include <video/omapdss.h> #include "dss.h" @@ -34,10 +35,16 @@ static struct { struct regulator *vdds_sdi_reg; struct dss_lcd_mgr_config mgr_config; + struct omap_video_timings timings; + int datapairs; + + struct omap_dss_output output; } sdi; static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; sdi.mgr_config.stallmode = false; @@ -46,19 +53,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) sdi.mgr_config.video_port_width = 24; sdi.mgr_config.lcden_sig_polarity = 1; - dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config); + dss_mgr_set_lcd_config(mgr, &sdi.mgr_config); } int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) { - struct omap_video_timings *t = &dssdev->panel.timings; + struct omap_dss_output *out = dssdev->output; + struct omap_video_timings *t = &sdi.timings; struct dss_clock_info dss_cinfo; struct dispc_clock_info dispc_cinfo; unsigned long pck; int r; - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -77,8 +85,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) goto err_get_dispc; /* 15.5.9.1.2 */ - dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); if (r) @@ -97,7 +105,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) } - dss_mgr_set_timings(dssdev->manager, t); + dss_mgr_set_timings(out->manager, t); r = dss_set_clock_div(&dss_cinfo); if (r) @@ -116,16 +124,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(dssdev->manager->id, - &sdi.mgr_config.clock_info); + dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info); - dss_sdi_init(dssdev->phy.sdi.datapairs); + dss_sdi_init(sdi.datapairs); r = dss_sdi_enable(); if (r) goto err_sdi_enable; mdelay(2); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(out->manager); if (r) goto err_mgr_enable; @@ -148,7 +155,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + dss_mgr_disable(mgr); dss_sdi_disable(); @@ -160,6 +169,19 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omapdss_sdi_display_disable); +void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + sdi.timings = *timings; +} +EXPORT_SYMBOL(omapdss_sdi_set_timings); + +void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) +{ + sdi.datapairs = datapairs; +} +EXPORT_SYMBOL(omapdss_sdi_set_datapairs); + static int __init sdi_init_display(struct omap_dss_device *dssdev) { DSSDBG("SDI init\n"); @@ -180,10 +202,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __init sdi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -191,21 +217,73 @@ static void __init sdi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) continue; - r = sdi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init sdi_probe_pdata(struct platform_device *sdidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = sdi_find_dssdev(sdidev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&sdidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = sdi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init sdi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &sdi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_SDI; + out->type = OMAP_DISPLAY_TYPE_SDI; + + dss_register_output(out); +} + +static void __exit sdi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &sdi.output; + + dss_unregister_output(out); } static int __init omap_sdi_probe(struct platform_device *pdev) { + sdi_init_output(pdev); + sdi_probe_pdata(pdev); return 0; @@ -213,7 +291,9 @@ static int __init omap_sdi_probe(struct platform_device *pdev) static int __exit omap_sdi_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + sdi_uninit_output(pdev); return 0; } diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 3a220877461a..56efa3bb465d 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -36,7 +36,6 @@ #include <linux/pm_runtime.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -300,6 +299,12 @@ static struct { struct regulator *vdda_dac_reg; struct clk *tv_dac_clk; + + struct omap_video_timings timings; + enum omap_dss_venc_type type; + bool invert_polarity; + + struct omap_dss_output output; } venc; static inline void venc_write_reg(int idx, u32 val) @@ -424,65 +429,67 @@ static const struct venc_config *venc_timings_to_config( static int venc_power_on(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; u32 l; int r; + r = venc_runtime_get(); + if (r) + goto err0; + venc_reset(); - venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); + venc_write_config(venc_timings_to_config(&venc.timings)); - dss_set_venc_output(dssdev->phy.venc.type); + dss_set_venc_output(venc.type); dss_set_dac_pwrdn_bgz(1); l = 0; - if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) + if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) l |= 1 << 1; else /* S-Video */ l |= (1 << 0) | (1 << 2); - if (dssdev->phy.venc.invert_polarity == false) + if (venc.invert_polarity == false) l |= 1 << 3; venc_write_reg(VENC_OUTPUT_CONTROL, l); - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); + dss_mgr_set_timings(mgr, &venc.timings); r = regulator_enable(venc.vdda_dac_reg); if (r) - goto err; - - if (dssdev->platform_enable) - dssdev->platform_enable(dssdev); + goto err1; - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) - goto err; + goto err2; return 0; -err: +err2: + regulator_disable(venc.vdda_dac_reg); +err1: venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - regulator_disable(venc.vdda_dac_reg); - + venc_runtime_put(); +err0: return r; } static void venc_power_off(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - dss_mgr_disable(dssdev->manager); - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + dss_mgr_disable(mgr); regulator_disable(venc.vdda_dac_reg); + + venc_runtime_put(); } unsigned long venc_get_pixel_clock(void) @@ -491,171 +498,83 @@ unsigned long venc_get_pixel_clock(void) return 13500000; } -static ssize_t display_output_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +int omapdss_venc_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *dssdev = to_dss_device(dev); - const char *ret; - - switch (dssdev->phy.venc.type) { - case OMAP_DSS_VENC_TYPE_COMPOSITE: - ret = "composite"; - break; - case OMAP_DSS_VENC_TYPE_SVIDEO: - ret = "svideo"; - break; - default: - return -EINVAL; - } - - return snprintf(buf, PAGE_SIZE, "%s\n", ret); -} + struct omap_dss_output *out = dssdev->output; + int r; -static ssize_t display_output_type_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - enum omap_dss_venc_type new_type; - - if (sysfs_streq("composite", buf)) - new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; - else if (sysfs_streq("svideo", buf)) - new_type = OMAP_DSS_VENC_TYPE_SVIDEO; - else - return -EINVAL; + DSSDBG("venc_display_enable\n"); mutex_lock(&venc.venc_lock); - if (dssdev->phy.venc.type != new_type) { - dssdev->phy.venc.type = new_type; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - venc_power_off(dssdev); - venc_power_on(dssdev); - } + if (out == NULL || out->manager == NULL) { + DSSERR("Failed to enable display: no output/manager\n"); + r = -ENODEV; + goto err0; } - mutex_unlock(&venc.venc_lock); - - return size; -} - -static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, - display_output_type_show, display_output_type_store); - -/* driver */ -static int venc_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.timings = omap_dss_pal_timings; - - return device_create_file(&dssdev->dev, &dev_attr_output_type); -} - -static void venc_panel_remove(struct omap_dss_device *dssdev) -{ - device_remove_file(&dssdev->dev, &dev_attr_output_type); -} - -static int venc_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - DSSDBG("venc_enable_display\n"); - - mutex_lock(&venc.venc_lock); - r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); goto err0; } - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { - r = -EINVAL; - goto err1; - } + if (dssdev->platform_enable) + dssdev->platform_enable(dssdev); - r = venc_runtime_get(); - if (r) - goto err1; r = venc_power_on(dssdev); if (r) - goto err2; + goto err1; venc.wss_data = 0; - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - mutex_unlock(&venc.venc_lock); + return 0; -err2: - venc_runtime_put(); err1: + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); omap_dss_stop_device(dssdev); err0: mutex_unlock(&venc.venc_lock); - return r; } -static void venc_panel_disable(struct omap_dss_device *dssdev) +void omapdss_venc_display_disable(struct omap_dss_device *dssdev) { - DSSDBG("venc_disable_display\n"); + DSSDBG("venc_display_disable\n"); mutex_lock(&venc.venc_lock); - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) - goto end; - - if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { - /* suspended is the same as disabled with venc */ - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - goto end; - } - venc_power_off(dssdev); - venc_runtime_put(); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - omap_dss_stop_device(dssdev); -end: - mutex_unlock(&venc.venc_lock); -} -static int venc_panel_suspend(struct omap_dss_device *dssdev) -{ - venc_panel_disable(dssdev); - return 0; -} + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); -static int venc_panel_resume(struct omap_dss_device *dssdev) -{ - return venc_panel_enable(dssdev); + mutex_unlock(&venc.venc_lock); } -static void venc_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +void omapdss_venc_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { DSSDBG("venc_set_timings\n"); + mutex_lock(&venc.venc_lock); + /* Reset WSS data when the TV standard changes. */ - if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings))) + if (memcmp(&venc.timings, timings, sizeof(*timings))) venc.wss_data = 0; - dssdev->panel.timings = *timings; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - /* turn the venc off and on to get new timings to use */ - venc_panel_disable(dssdev); - venc_panel_enable(dssdev); - } else { - dss_mgr_set_timings(dssdev->manager, timings); - } + venc.timings = *timings; + + mutex_unlock(&venc.venc_lock); } -static int venc_check_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +int omapdss_venc_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { DSSDBG("venc_check_timings\n"); @@ -668,13 +587,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev, return -EINVAL; } -static u32 venc_get_wss(struct omap_dss_device *dssdev) +u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) { /* Invert due to VENC_L21_WC_CTL:INV=1 */ return (venc.wss_data >> 8) ^ 0xfffff; } -static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) +int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss) { const struct venc_config *config; int r; @@ -683,7 +602,7 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) mutex_lock(&venc.venc_lock); - config = venc_timings_to_config(&dssdev->panel.timings); + config = venc_timings_to_config(&venc.timings); /* Invert due to VENC_L21_WC_CTL:INV=1 */ venc.wss_data = (wss ^ 0xfffff) << 8; @@ -703,30 +622,25 @@ err: return r; } -static struct omap_dss_driver venc_driver = { - .probe = venc_panel_probe, - .remove = venc_panel_remove, +void omapdss_venc_set_type(struct omap_dss_device *dssdev, + enum omap_dss_venc_type type) +{ + mutex_lock(&venc.venc_lock); - .enable = venc_panel_enable, - .disable = venc_panel_disable, - .suspend = venc_panel_suspend, - .resume = venc_panel_resume, + venc.type = type; - .get_resolution = omapdss_default_get_resolution, - .get_recommended_bpp = omapdss_default_get_recommended_bpp, + mutex_unlock(&venc.venc_lock); +} - .set_timings = venc_set_timings, - .check_timings = venc_check_timings, +void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, + bool invert_polarity) +{ + mutex_lock(&venc.venc_lock); - .get_wss = venc_get_wss, - .set_wss = venc_set_wss, + venc.invert_polarity = invert_polarity; - .driver = { - .name = "venc", - .owner = THIS_MODULE, - }, -}; -/* driver end */ + mutex_unlock(&venc.venc_lock); +} static int __init venc_init_display(struct omap_dss_device *dssdev) { @@ -752,11 +666,6 @@ static void venc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) - if (cpu_is_omap44xx()) { - seq_printf(s, "VENC currently disabled on OMAP44xx\n"); - return; - } - if (venc_runtime_get()) return; @@ -832,10 +741,14 @@ static void venc_put_clocks(void) clk_put(venc.tv_dac_clk); } -static void __init venc_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int r, i; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -843,17 +756,69 @@ static void __init venc_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) continue; - r = venc_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init venc_probe_pdata(struct platform_device *vencdev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = venc_find_dssdev(vencdev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&vencdev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + + r = venc_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init venc_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &venc.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_VENC; + out->type = OMAP_DISPLAY_TYPE_VENC; + + dss_register_output(out); +} + +static void __exit venc_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &venc.output; + + dss_unregister_output(out); } /* VENC HW IP initialisation */ @@ -897,17 +862,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev) venc_runtime_put(); - r = omap_dss_register_driver(&venc_driver); + r = venc_panel_init(); if (r) - goto err_reg_panel_driver; + goto err_panel_init; dss_debugfs_create_file("venc", venc_dump_regs); + venc_init_output(pdev); + venc_probe_pdata(pdev); return 0; -err_reg_panel_driver: +err_panel_init: err_runtime_get: pm_runtime_disable(&pdev->dev); venc_put_clocks(); @@ -916,14 +883,16 @@ err_runtime_get: static int __exit omap_venchw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); if (venc.vdda_dac_reg != NULL) { regulator_put(venc.vdda_dac_reg); venc.vdda_dac_reg = NULL; } - omap_dss_unregister_driver(&venc_driver); + venc_panel_exit(); + + venc_uninit_output(pdev); pm_runtime_disable(&pdev->dev); venc_put_clocks(); @@ -971,16 +940,10 @@ static struct platform_driver omap_venchw_driver = { int __init venc_init_platform_driver(void) { - if (cpu_is_omap44xx()) - return 0; - return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); } void __exit venc_uninit_platform_driver(void) { - if (cpu_is_omap44xx()) - return; - platform_driver_unregister(&omap_venchw_driver); } diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c new file mode 100644 index 000000000000..d55b8784ecfd --- /dev/null +++ b/drivers/video/omap2/dss/venc_panel.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * VENC panel driver + * + * 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/kernel.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/mutex.h> +#include <linux/module.h> + +#include <video/omapdss.h> + +#include "dss.h" + +static struct { + struct mutex lock; +} venc_panel; + +static ssize_t display_output_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + const char *ret; + + switch (dssdev->phy.venc.type) { + case OMAP_DSS_VENC_TYPE_COMPOSITE: + ret = "composite"; + break; + case OMAP_DSS_VENC_TYPE_SVIDEO: + ret = "svideo"; + break; + default: + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", ret); +} + +static ssize_t display_output_type_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + enum omap_dss_venc_type new_type; + + if (sysfs_streq("composite", buf)) + new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; + else if (sysfs_streq("svideo", buf)) + new_type = OMAP_DSS_VENC_TYPE_SVIDEO; + else + return -EINVAL; + + mutex_lock(&venc_panel.lock); + + if (dssdev->phy.venc.type != new_type) { + dssdev->phy.venc.type = new_type; + omapdss_venc_set_type(dssdev, new_type); + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + omapdss_venc_display_disable(dssdev); + omapdss_venc_display_enable(dssdev); + } + } + + mutex_unlock(&venc_panel.lock); + + return size; +} + +static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, + display_output_type_show, display_output_type_store); + +static int venc_panel_probe(struct omap_dss_device *dssdev) +{ + /* set default timings to PAL */ + const struct omap_video_timings default_timings = { + .x_res = 720, + .y_res = 574, + .pixel_clock = 13500, + .hsw = 64, + .hfp = 12, + .hbp = 68, + .vsw = 5, + .vfp = 5, + .vbp = 41, + + .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, + .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, + + .interlace = true, + }; + + mutex_init(&venc_panel.lock); + + dssdev->panel.timings = default_timings; + + return device_create_file(&dssdev->dev, &dev_attr_output_type); +} + +static void venc_panel_remove(struct omap_dss_device *dssdev) +{ + device_remove_file(&dssdev->dev, &dev_attr_output_type); +} + +static int venc_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + dev_dbg(&dssdev->dev, "venc_panel_enable\n"); + + mutex_lock(&venc_panel.lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { + r = -EINVAL; + goto err; + } + + omapdss_venc_set_timings(dssdev, &dssdev->panel.timings); + omapdss_venc_set_type(dssdev, dssdev->phy.venc.type); + omapdss_venc_invert_vid_out_polarity(dssdev, + dssdev->phy.venc.invert_polarity); + + r = omapdss_venc_display_enable(dssdev); + if (r) + goto err; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&venc_panel.lock); + + return 0; +err: + mutex_unlock(&venc_panel.lock); + + return r; +} + +static void venc_panel_disable(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "venc_panel_disable\n"); + + mutex_lock(&venc_panel.lock); + + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) + goto end; + + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { + /* suspended is the same as disabled with venc */ + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + goto end; + } + + omapdss_venc_display_disable(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +end: + mutex_unlock(&venc_panel.lock); +} + +static int venc_panel_suspend(struct omap_dss_device *dssdev) +{ + venc_panel_disable(dssdev); + return 0; +} + +static int venc_panel_resume(struct omap_dss_device *dssdev) +{ + return venc_panel_enable(dssdev); +} + +static void venc_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dev_dbg(&dssdev->dev, "venc_panel_set_timings\n"); + + mutex_lock(&venc_panel.lock); + + omapdss_venc_set_timings(dssdev, timings); + dssdev->panel.timings = *timings; + + mutex_unlock(&venc_panel.lock); +} + +static int venc_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dev_dbg(&dssdev->dev, "venc_panel_check_timings\n"); + + return omapdss_venc_check_timings(dssdev, timings); +} + +static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "venc_panel_get_wss\n"); + + return omapdss_venc_get_wss(dssdev); +} + +static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) +{ + dev_dbg(&dssdev->dev, "venc_panel_set_wss\n"); + + return omapdss_venc_set_wss(dssdev, wss); +} + +static struct omap_dss_driver venc_driver = { + .probe = venc_panel_probe, + .remove = venc_panel_remove, + + .enable = venc_panel_enable, + .disable = venc_panel_disable, + .suspend = venc_panel_suspend, + .resume = venc_panel_resume, + + .get_resolution = omapdss_default_get_resolution, + .get_recommended_bpp = omapdss_default_get_recommended_bpp, + + .set_timings = venc_panel_set_timings, + .check_timings = venc_panel_check_timings, + + .get_wss = venc_panel_get_wss, + .set_wss = venc_panel_set_wss, + + .driver = { + .name = "venc", + .owner = THIS_MODULE, + }, +}; + +int venc_panel_init(void) +{ + return omap_dss_register_driver(&venc_driver); +} + +void venc_panel_exit(void) +{ + omap_dss_unregister_driver(&venc_driver); +} diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index c6cf372d22c5..606b89f12351 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -599,6 +599,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display = fb2display(fbi); + struct omap_overlay_manager *mgr; union { struct omapfb_update_window_old uwnd_o; @@ -786,12 +787,14 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); - if (!display) { + if (!display && !display->output && !display->output->manager) { r = -EINVAL; break; } - r = display->manager->wait_for_vsync(display->manager); + mgr = display->output->manager; + + r = mgr->wait_for_vsync(mgr); break; case OMAPFB_WAITFORGO: diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index fc671d3d8004..b103793516db 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1592,6 +1592,20 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) return 0; } +static void omapfb_clear_fb(struct fb_info *fbi) +{ + const struct fb_fillrect rect = { + .dx = 0, + .dy = 0, + .width = fbi->var.xres_virtual, + .height = fbi->var.yres_virtual, + .color = 0, + .rop = ROP_COPY, + }; + + cfb_fillrect(fbi, &rect); +} + int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) { struct omapfb_info *ofbi = FB2OFB(fbi); @@ -1661,6 +1675,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) goto err; } + omapfb_clear_fb(fbi); + return 0; err: omapfb_free_fbmem(fbi); @@ -1945,6 +1961,16 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) } } + for (i = 0; i < fbdev->num_fbs; i++) { + struct fb_info *fbi = fbdev->fbs[i]; + struct omapfb_info *ofbi = FB2OFB(fbi); + + if (ofbi->region->size == 0) + continue; + + omapfb_clear_fb(fbi); + } + DBG("fb_infos initialized\n"); for (i = 0; i < fbdev->num_fbs; i++) { @@ -2353,6 +2379,7 @@ static int __init omapfb_probe(struct platform_device *pdev) struct omap_overlay *ovl; struct omap_dss_device *def_display; struct omap_dss_device *dssdev; + struct omap_dss_device *ovl_device; DBG("omapfb_probe\n"); @@ -2426,8 +2453,9 @@ static int __init omapfb_probe(struct platform_device *pdev) /* gfx overlay should be the default one. find a display * connected to that, and use it as default display */ ovl = omap_dss_get_overlay(0); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; + ovl_device = ovl->get_device(ovl); + if (ovl_device) { + def_display = ovl_device; } else { dev_warn(&pdev->dev, "cannot find default display\n"); def_display = NULL; diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 30361a09aecd..5ced9b334d35 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -148,8 +148,9 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) /* XXX: returns the display connected to first attached overlay */ for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->manager) - return ofbi->overlays[i]->manager->device; + struct omap_overlay *ovl = ofbi->overlays[i]; + + return ovl->get_device(ovl); } return NULL; diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 87e421e25afe..f2b15c4a75bc 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -34,7 +34,6 @@ #include <asm/setup.h> #include <plat/vram.h> -#include <plat/dma.h> #ifdef DEBUG #define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__) @@ -250,59 +249,6 @@ int omap_vram_reserve(unsigned long paddr, size_t size) } EXPORT_SYMBOL(omap_vram_reserve); -static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data) -{ - struct completion *compl = data; - complete(compl); -} - -static int _omap_vram_clear(u32 paddr, unsigned pages) -{ - struct completion compl; - unsigned elem_count; - unsigned frame_count; - int r; - int lch; - - init_completion(&compl); - - r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA", - _omap_vram_dma_cb, - &compl, &lch); - if (r) { - pr_err("VRAM: request_dma failed for memory clear\n"); - return -EBUSY; - } - - elem_count = pages * PAGE_SIZE / 4; - frame_count = 1; - - omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32, - elem_count, frame_count, - OMAP_DMA_SYNC_ELEMENT, - 0, 0); - - omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC, - paddr, 0, 0); - - omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000); - - omap_start_dma(lch); - - if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) { - omap_stop_dma(lch); - pr_err("VRAM: dma timeout while clearing memory\n"); - r = -EIO; - goto err; - } - - r = 0; -err: - omap_free_dma(lch); - - return r; -} - static int _omap_vram_alloc(unsigned pages, unsigned long *paddr) { struct vram_region *rm; @@ -337,8 +283,6 @@ found: *paddr = start; - _omap_vram_clear(start, pages); - return 0; } diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index 3fe82d0e8caa..5b06d31ab6a9 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -166,18 +166,17 @@ static long booke_wdt_ioctl(struct file *file, switch (cmd) { case WDIOC_GETSUPPORT: - if (copy_to_user((void *)arg, &ident, sizeof(ident))) - return -EFAULT; + return copy_to_user(p, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: return put_user(0, p); case WDIOC_GETBOOTSTATUS: /* XXX: something is clearing TSR */ tmp = mfspr(SPRN_TSR) & TSR_WRS(3); /* returns CARDRESET if last reset was caused by the WDT */ - return (tmp ? WDIOF_CARDRESET : 0); + return put_user((tmp ? WDIOF_CARDRESET : 0), p); case WDIOC_SETOPTIONS: if (get_user(tmp, p)) - return -EINVAL; + return -EFAULT; if (tmp == WDIOS_ENABLECARD) { booke_wdt_ping(); break; diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index 3f75129eb0a9..f7abbaeebcaf 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c @@ -21,7 +21,6 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/jiffies.h> -#include <linux/delay.h> #include <linux/mfd/da9052/reg.h> #include <linux/mfd/da9052/da9052.h> diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c index d4c50d63acbc..97ca359ae2bd 100644 --- a/drivers/xen/platform-pci.c +++ b/drivers/xen/platform-pci.c @@ -101,19 +101,6 @@ static int platform_pci_resume(struct pci_dev *pdev) return 0; } -static void __devinit prepare_shared_info(void) -{ -#ifdef CONFIG_KEXEC - unsigned long addr; - struct shared_info *hvm_shared_info; - - addr = alloc_xen_mmio(PAGE_SIZE); - hvm_shared_info = ioremap(addr, PAGE_SIZE); - memset(hvm_shared_info, 0, PAGE_SIZE); - xen_hvm_prepare_kexec(hvm_shared_info, addr >> PAGE_SHIFT); -#endif -} - static int __devinit platform_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -151,8 +138,6 @@ static int __devinit platform_pci_init(struct pci_dev *pdev, platform_mmio = mmio_addr; platform_mmiolen = mmio_len; - prepare_shared_info(); - if (!xen_have_vector_callback) { ret = xen_allocate_irq(pdev); if (ret) { @@ -73,7 +73,7 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size) { unsigned int sz = sizeof(struct bio) + extra_size; struct kmem_cache *slab = NULL; - struct bio_slab *bslab; + struct bio_slab *bslab, *new_bio_slabs; unsigned int i, entry = -1; mutex_lock(&bio_slab_lock); @@ -97,11 +97,12 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size) if (bio_slab_nr == bio_slab_max && entry == -1) { bio_slab_max <<= 1; - bio_slabs = krealloc(bio_slabs, - bio_slab_max * sizeof(struct bio_slab), - GFP_KERNEL); - if (!bio_slabs) + new_bio_slabs = krealloc(bio_slabs, + bio_slab_max * sizeof(struct bio_slab), + GFP_KERNEL); + if (!new_bio_slabs) goto out_unlock; + bio_slabs = new_bio_slabs; } if (entry == -1) entry = bio_slab_nr++; diff --git a/fs/block_dev.c b/fs/block_dev.c index 1e519195d45b..38e721b35d45 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1578,10 +1578,12 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { struct file *file = iocb->ki_filp; + struct blk_plug plug; ssize_t ret; BUG_ON(iocb->ki_pos != pos); + blk_start_plug(&plug); ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); if (ret > 0 || ret == -EIOCBQUEUED) { ssize_t err; @@ -1590,6 +1592,7 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, if (err < 0 && ret > 0) ret = err; } + blk_finish_plug(&plug); return ret; } EXPORT_SYMBOL_GPL(blkdev_aio_write); diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index a256f3b2a845..ff6475f409d6 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -1438,10 +1438,10 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, ret = extent_from_logical(fs_info, logical, path, &found_key); btrfs_release_path(path); - if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) - ret = -EINVAL; if (ret < 0) return ret; + if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) + return -EINVAL; extent_item_pos = logical - found_key.objectid; ret = iterate_extent_inodes(fs_info, found_key.objectid, diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 86eff48dab78..43d1c5a3a030 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -818,6 +818,7 @@ static void free_workspace(int type, struct list_head *workspace) btrfs_compress_op[idx]->free_workspace(workspace); atomic_dec(alloc_workspace); wake: + smp_mb(); if (waitqueue_active(workspace_wait)) wake_up(workspace_wait); } diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 9d7621f271ff..6d183f60d63a 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -421,12 +421,6 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, spin_unlock(&fs_info->tree_mod_seq_lock); /* - * we removed the lowest blocker from the blocker list, so there may be - * more processible delayed refs. - */ - wake_up(&fs_info->tree_mod_seq_wait); - - /* * anything that's lower than the lowest existing (read: blocked) * sequence number can be removed from the tree. */ @@ -631,6 +625,9 @@ __tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) u32 nritems; int ret; + if (btrfs_header_level(eb) == 0) + return; + nritems = btrfs_header_nritems(eb); for (i = nritems - 1; i >= 0; i--) { ret = tree_mod_log_insert_key_locked(fs_info, eb, i, diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 4bab807227ad..0d195b507660 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1252,7 +1252,6 @@ struct btrfs_fs_info { atomic_t tree_mod_seq; struct list_head tree_mod_seq_list; struct seq_list tree_mod_seq_elem; - wait_queue_head_t tree_mod_seq_wait; /* this protects tree_mod_log */ rwlock_t tree_mod_log_lock; @@ -3192,7 +3191,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, struct bio *bio, u32 *dst); int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u64 logical_offset, u32 *dst); + struct bio *bio, u64 logical_offset); int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 pos, diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 335605c8ceab..07d5eeb1e6f1 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -512,8 +512,8 @@ static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item) rb_erase(&delayed_item->rb_node, root); delayed_item->delayed_node->count--; - atomic_dec(&delayed_root->items); - if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND && + if (atomic_dec_return(&delayed_root->items) < + BTRFS_DELAYED_BACKGROUND && waitqueue_active(&delayed_root->wait)) wake_up(&delayed_root->wait); } @@ -1028,9 +1028,10 @@ do_again: btrfs_release_delayed_item(prev); ret = 0; btrfs_release_path(path); - if (curr) + if (curr) { + mutex_unlock(&node->mutex); goto do_again; - else + } else goto delete_fail; } @@ -1055,8 +1056,7 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node) delayed_node->count--; delayed_root = delayed_node->root->fs_info->delayed_root; - atomic_dec(&delayed_root->items); - if (atomic_read(&delayed_root->items) < + if (atomic_dec_return(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND && waitqueue_active(&delayed_root->wait)) wake_up(&delayed_root->wait); diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index da7419ed01bb..ae9411773397 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -38,17 +38,14 @@ static int comp_tree_refs(struct btrfs_delayed_tree_ref *ref2, struct btrfs_delayed_tree_ref *ref1) { - if (ref1->node.type == BTRFS_TREE_BLOCK_REF_KEY) { - if (ref1->root < ref2->root) - return -1; - if (ref1->root > ref2->root) - return 1; - } else { - if (ref1->parent < ref2->parent) - return -1; - if (ref1->parent > ref2->parent) - return 1; - } + if (ref1->root < ref2->root) + return -1; + if (ref1->root > ref2->root) + return 1; + if (ref1->parent < ref2->parent) + return -1; + if (ref1->parent > ref2->parent) + return 1; return 0; } @@ -85,7 +82,8 @@ static int comp_data_refs(struct btrfs_delayed_data_ref *ref2, * type of the delayed backrefs and content of delayed backrefs. */ static int comp_entry(struct btrfs_delayed_ref_node *ref2, - struct btrfs_delayed_ref_node *ref1) + struct btrfs_delayed_ref_node *ref1, + bool compare_seq) { if (ref1->bytenr < ref2->bytenr) return -1; @@ -102,10 +100,12 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2, if (ref1->type > ref2->type) return 1; /* merging of sequenced refs is not allowed */ - if (ref1->seq < ref2->seq) - return -1; - if (ref1->seq > ref2->seq) - return 1; + if (compare_seq) { + if (ref1->seq < ref2->seq) + return -1; + if (ref1->seq > ref2->seq) + return 1; + } if (ref1->type == BTRFS_TREE_BLOCK_REF_KEY || ref1->type == BTRFS_SHARED_BLOCK_REF_KEY) { return comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref2), @@ -139,7 +139,7 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root, entry = rb_entry(parent_node, struct btrfs_delayed_ref_node, rb_node); - cmp = comp_entry(entry, ins); + cmp = comp_entry(entry, ins, 1); if (cmp < 0) p = &(*p)->rb_left; else if (cmp > 0) @@ -233,6 +233,114 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, return 0; } +static void inline drop_delayed_ref(struct btrfs_trans_handle *trans, + struct btrfs_delayed_ref_root *delayed_refs, + struct btrfs_delayed_ref_node *ref) +{ + rb_erase(&ref->rb_node, &delayed_refs->root); + ref->in_tree = 0; + btrfs_put_delayed_ref(ref); + delayed_refs->num_entries--; + if (trans->delayed_ref_updates) + trans->delayed_ref_updates--; +} + +static int merge_ref(struct btrfs_trans_handle *trans, + struct btrfs_delayed_ref_root *delayed_refs, + struct btrfs_delayed_ref_node *ref, u64 seq) +{ + struct rb_node *node; + int merged = 0; + int mod = 0; + int done = 0; + + node = rb_prev(&ref->rb_node); + while (node) { + struct btrfs_delayed_ref_node *next; + + next = rb_entry(node, struct btrfs_delayed_ref_node, rb_node); + node = rb_prev(node); + if (next->bytenr != ref->bytenr) + break; + if (seq && next->seq >= seq) + break; + if (comp_entry(ref, next, 0)) + continue; + + if (ref->action == next->action) { + mod = next->ref_mod; + } else { + if (ref->ref_mod < next->ref_mod) { + struct btrfs_delayed_ref_node *tmp; + + tmp = ref; + ref = next; + next = tmp; + done = 1; + } + mod = -next->ref_mod; + } + + merged++; + drop_delayed_ref(trans, delayed_refs, next); + ref->ref_mod += mod; + if (ref->ref_mod == 0) { + drop_delayed_ref(trans, delayed_refs, ref); + break; + } else { + /* + * You can't have multiples of the same ref on a tree + * block. + */ + WARN_ON(ref->type == BTRFS_TREE_BLOCK_REF_KEY || + ref->type == BTRFS_SHARED_BLOCK_REF_KEY); + } + + if (done) + break; + node = rb_prev(&ref->rb_node); + } + + return merged; +} + +void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, + struct btrfs_delayed_ref_root *delayed_refs, + struct btrfs_delayed_ref_head *head) +{ + struct rb_node *node; + u64 seq = 0; + + spin_lock(&fs_info->tree_mod_seq_lock); + if (!list_empty(&fs_info->tree_mod_seq_list)) { + struct seq_list *elem; + + elem = list_first_entry(&fs_info->tree_mod_seq_list, + struct seq_list, list); + seq = elem->seq; + } + spin_unlock(&fs_info->tree_mod_seq_lock); + + node = rb_prev(&head->node.rb_node); + while (node) { + struct btrfs_delayed_ref_node *ref; + + ref = rb_entry(node, struct btrfs_delayed_ref_node, + rb_node); + if (ref->bytenr != head->node.bytenr) + break; + + /* We can't merge refs that are outside of our seq count */ + if (seq && ref->seq >= seq) + break; + if (merge_ref(trans, delayed_refs, ref, seq)) + node = rb_prev(&head->node.rb_node); + else + node = rb_prev(node); + } +} + int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, struct btrfs_delayed_ref_root *delayed_refs, u64 seq) @@ -336,18 +444,11 @@ update_existing_ref(struct btrfs_trans_handle *trans, * every changing the extent allocation tree. */ existing->ref_mod--; - if (existing->ref_mod == 0) { - rb_erase(&existing->rb_node, - &delayed_refs->root); - existing->in_tree = 0; - btrfs_put_delayed_ref(existing); - delayed_refs->num_entries--; - if (trans->delayed_ref_updates) - trans->delayed_ref_updates--; - } else { + if (existing->ref_mod == 0) + drop_delayed_ref(trans, delayed_refs, existing); + else WARN_ON(existing->type == BTRFS_TREE_BLOCK_REF_KEY || existing->type == BTRFS_SHARED_BLOCK_REF_KEY); - } } else { WARN_ON(existing->type == BTRFS_TREE_BLOCK_REF_KEY || existing->type == BTRFS_SHARED_BLOCK_REF_KEY); @@ -662,9 +763,6 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr, num_bytes, parent, ref_root, level, action, for_cow); - if (!need_ref_seq(for_cow, ref_root) && - waitqueue_active(&fs_info->tree_mod_seq_wait)) - wake_up(&fs_info->tree_mod_seq_wait); spin_unlock(&delayed_refs->lock); if (need_ref_seq(for_cow, ref_root)) btrfs_qgroup_record_ref(trans, &ref->node, extent_op); @@ -713,9 +811,6 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, add_delayed_data_ref(fs_info, trans, &ref->node, bytenr, num_bytes, parent, ref_root, owner, offset, action, for_cow); - if (!need_ref_seq(for_cow, ref_root) && - waitqueue_active(&fs_info->tree_mod_seq_wait)) - wake_up(&fs_info->tree_mod_seq_wait); spin_unlock(&delayed_refs->lock); if (need_ref_seq(for_cow, ref_root)) btrfs_qgroup_record_ref(trans, &ref->node, extent_op); @@ -744,8 +839,6 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, num_bytes, BTRFS_UPDATE_DELAYED_HEAD, extent_op->is_data); - if (waitqueue_active(&fs_info->tree_mod_seq_wait)) - wake_up(&fs_info->tree_mod_seq_wait); spin_unlock(&delayed_refs->lock); return 0; } diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index 0d7c90c366b6..ab5300595847 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -167,6 +167,10 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, struct btrfs_trans_handle *trans, u64 bytenr, u64 num_bytes, struct btrfs_delayed_extent_op *extent_op); +void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, + struct btrfs_fs_info *fs_info, + struct btrfs_delayed_ref_root *delayed_refs, + struct btrfs_delayed_ref_head *head); struct btrfs_delayed_ref_head * btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 62e0cafd6e25..22e98e04c2ea 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -377,9 +377,13 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, ret = read_extent_buffer_pages(io_tree, eb, start, WAIT_COMPLETE, btree_get_extent, mirror_num); - if (!ret && !verify_parent_transid(io_tree, eb, + if (!ret) { + if (!verify_parent_transid(io_tree, eb, parent_transid, 0)) - break; + break; + else + ret = -EIO; + } /* * This buffer's crc is fine, but its contents are corrupted, so @@ -754,9 +758,7 @@ static void run_one_async_done(struct btrfs_work *work) limit = btrfs_async_submit_limit(fs_info); limit = limit * 2 / 3; - atomic_dec(&fs_info->nr_async_submits); - - if (atomic_read(&fs_info->nr_async_submits) < limit && + if (atomic_dec_return(&fs_info->nr_async_submits) < limit && waitqueue_active(&fs_info->async_submit_wait)) wake_up(&fs_info->async_submit_wait); @@ -2032,8 +2034,6 @@ int open_ctree(struct super_block *sb, fs_info->free_chunk_space = 0; fs_info->tree_mod_log = RB_ROOT; - init_waitqueue_head(&fs_info->tree_mod_seq_wait); - /* readahead state */ INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT); spin_lock_init(&fs_info->reada_lock); @@ -2528,8 +2528,7 @@ retry_root_backup: goto fail_trans_kthread; /* do not make disk changes in broken FS */ - if (btrfs_super_log_root(disk_super) != 0 && - !(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) { + if (btrfs_super_log_root(disk_super) != 0) { u64 bytenr = btrfs_super_log_root(disk_super); if (fs_devices->rw_devices == 0) { @@ -3189,30 +3188,14 @@ int close_ctree(struct btrfs_root *root) /* clear out the rbtree of defraggable inodes */ btrfs_run_defrag_inodes(fs_info); - /* - * Here come 2 situations when btrfs is broken to flip readonly: - * - * 1. when btrfs flips readonly somewhere else before - * btrfs_commit_super, sb->s_flags has MS_RDONLY flag, - * and btrfs will skip to write sb directly to keep - * ERROR state on disk. - * - * 2. when btrfs flips readonly just in btrfs_commit_super, - * and in such case, btrfs cannot write sb via btrfs_commit_super, - * and since fs_state has been set BTRFS_SUPER_FLAG_ERROR flag, - * btrfs will cleanup all FS resources first and write sb then. - */ if (!(fs_info->sb->s_flags & MS_RDONLY)) { ret = btrfs_commit_super(root); if (ret) printk(KERN_ERR "btrfs: commit super ret %d\n", ret); } - if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { - ret = btrfs_error_commit_super(root); - if (ret) - printk(KERN_ERR "btrfs: commit super ret %d\n", ret); - } + if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) + btrfs_error_commit_super(root); btrfs_put_block_group_cache(fs_info); @@ -3434,18 +3417,11 @@ static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, if (read_only) return 0; - if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { - printk(KERN_WARNING "warning: mount fs with errors, " - "running btrfsck is recommended\n"); - } - return 0; } -int btrfs_error_commit_super(struct btrfs_root *root) +void btrfs_error_commit_super(struct btrfs_root *root) { - int ret; - mutex_lock(&root->fs_info->cleaner_mutex); btrfs_run_delayed_iputs(root); mutex_unlock(&root->fs_info->cleaner_mutex); @@ -3455,10 +3431,6 @@ int btrfs_error_commit_super(struct btrfs_root *root) /* cleanup FS via transaction */ btrfs_cleanup_transaction(root); - - ret = write_ctree_super(NULL, root, 0); - - return ret; } static void btrfs_destroy_ordered_operations(struct btrfs_root *root) @@ -3782,14 +3754,17 @@ int btrfs_cleanup_transaction(struct btrfs_root *root) /* FIXME: cleanup wait for commit */ t->in_commit = 1; t->blocked = 1; + smp_mb(); if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) wake_up(&root->fs_info->transaction_blocked_wait); t->blocked = 0; + smp_mb(); if (waitqueue_active(&root->fs_info->transaction_wait)) wake_up(&root->fs_info->transaction_wait); t->commit_done = 1; + smp_mb(); if (waitqueue_active(&t->commit_wait)) wake_up(&t->commit_wait); diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 95e147eea239..c5b00a735fef 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -54,7 +54,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, int max_mirrors); struct buffer_head *btrfs_read_dev_super(struct block_device *bdev); int btrfs_commit_super(struct btrfs_root *root); -int btrfs_error_commit_super(struct btrfs_root *root); +void btrfs_error_commit_super(struct btrfs_root *root); struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize); struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4e1b153b7c47..ba58024d40d3 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2252,6 +2252,16 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, } /* + * We need to try and merge add/drops of the same ref since we + * can run into issues with relocate dropping the implicit ref + * and then it being added back again before the drop can + * finish. If we merged anything we need to re-loop so we can + * get a good ref. + */ + btrfs_merge_delayed_refs(trans, fs_info, delayed_refs, + locked_ref); + + /* * locked_ref is the head node, so we have to go one * node back for any delayed ref updates */ @@ -2318,12 +2328,23 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, ref->in_tree = 0; rb_erase(&ref->rb_node, &delayed_refs->root); delayed_refs->num_entries--; - /* - * we modified num_entries, but as we're currently running - * delayed refs, skip - * wake_up(&delayed_refs->seq_wait); - * here. - */ + if (locked_ref) { + /* + * when we play the delayed ref, also correct the + * ref_mod on head + */ + switch (ref->action) { + case BTRFS_ADD_DELAYED_REF: + case BTRFS_ADD_DELAYED_EXTENT: + locked_ref->node.ref_mod -= ref->ref_mod; + break; + case BTRFS_DROP_DELAYED_REF: + locked_ref->node.ref_mod += ref->ref_mod; + break; + default: + WARN_ON(1); + } + } spin_unlock(&delayed_refs->lock); ret = run_one_delayed_ref(trans, root, ref, extent_op, @@ -2350,22 +2371,6 @@ next: return count; } -static void wait_for_more_refs(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_root *delayed_refs, - unsigned long num_refs, - struct list_head *first_seq) -{ - spin_unlock(&delayed_refs->lock); - pr_debug("waiting for more refs (num %ld, first %p)\n", - num_refs, first_seq); - wait_event(fs_info->tree_mod_seq_wait, - num_refs != delayed_refs->num_entries || - fs_info->tree_mod_seq_list.next != first_seq); - pr_debug("done waiting for more refs (num %ld, first %p)\n", - delayed_refs->num_entries, fs_info->tree_mod_seq_list.next); - spin_lock(&delayed_refs->lock); -} - #ifdef SCRAMBLE_DELAYED_REFS /* * Normally delayed refs get processed in ascending bytenr order. This @@ -2460,13 +2465,11 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_node *ref; struct list_head cluster; - struct list_head *first_seq = NULL; int ret; u64 delayed_start; int run_all = count == (unsigned long)-1; int run_most = 0; - unsigned long num_refs = 0; - int consider_waiting; + int loops; /* We'll clean this up in btrfs_cleanup_transaction */ if (trans->aborted) @@ -2484,7 +2487,7 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, delayed_refs = &trans->transaction->delayed_refs; INIT_LIST_HEAD(&cluster); again: - consider_waiting = 0; + loops = 0; spin_lock(&delayed_refs->lock); #ifdef SCRAMBLE_DELAYED_REFS @@ -2512,31 +2515,6 @@ again: if (ret) break; - if (delayed_start >= delayed_refs->run_delayed_start) { - if (consider_waiting == 0) { - /* - * btrfs_find_ref_cluster looped. let's do one - * more cycle. if we don't run any delayed ref - * during that cycle (because we can't because - * all of them are blocked) and if the number of - * refs doesn't change, we avoid busy waiting. - */ - consider_waiting = 1; - num_refs = delayed_refs->num_entries; - first_seq = root->fs_info->tree_mod_seq_list.next; - } else { - wait_for_more_refs(root->fs_info, delayed_refs, - num_refs, first_seq); - /* - * after waiting, things have changed. we - * dropped the lock and someone else might have - * run some refs, built new clusters and so on. - * therefore, we restart staleness detection. - */ - consider_waiting = 0; - } - } - ret = run_clustered_refs(trans, root, &cluster); if (ret < 0) { spin_unlock(&delayed_refs->lock); @@ -2549,9 +2527,26 @@ again: if (count == 0) break; - if (ret || delayed_refs->run_delayed_start == 0) { + if (delayed_start >= delayed_refs->run_delayed_start) { + if (loops == 0) { + /* + * btrfs_find_ref_cluster looped. let's do one + * more cycle. if we don't run any delayed ref + * during that cycle (because we can't because + * all of them are blocked), bail out. + */ + loops = 1; + } else { + /* + * no runnable refs left, stop trying + */ + BUG_ON(run_all); + break; + } + } + if (ret) { /* refs were run, let's reset staleness detection */ - consider_waiting = 0; + loops = 0; } } @@ -3007,17 +3002,16 @@ again: } spin_unlock(&block_group->lock); - num_pages = (int)div64_u64(block_group->key.offset, 1024 * 1024 * 1024); + /* + * Try to preallocate enough space based on how big the block group is. + * Keep in mind this has to include any pinned space which could end up + * taking up quite a bit since it's not folded into the other space + * cache. + */ + num_pages = (int)div64_u64(block_group->key.offset, 256 * 1024 * 1024); if (!num_pages) num_pages = 1; - /* - * Just to make absolutely sure we have enough space, we're going to - * preallocate 12 pages worth of space for each block group. In - * practice we ought to use at most 8, but we need extra space so we can - * add our header and have a terminator between the extents and the - * bitmaps. - */ num_pages *= 16; num_pages *= PAGE_CACHE_SIZE; @@ -4571,8 +4565,10 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) if (root->fs_info->quota_enabled) { ret = btrfs_qgroup_reserve(root, num_bytes + nr_extents * root->leafsize); - if (ret) + if (ret) { + mutex_unlock(&BTRFS_I(inode)->delalloc_mutex); return ret; + } } ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush); @@ -5294,9 +5290,6 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, rb_erase(&head->node.rb_node, &delayed_refs->root); delayed_refs->num_entries--; - smp_mb(); - if (waitqueue_active(&root->fs_info->tree_mod_seq_wait)) - wake_up(&root->fs_info->tree_mod_seq_wait); /* * we don't take a ref on the node because we're removing it from the diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 45c81bb4ac82..4c878476bb91 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2330,23 +2330,10 @@ static void end_bio_extent_readpage(struct bio *bio, int err) if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { ret = tree->ops->readpage_end_io_hook(page, start, end, state, mirror); - if (ret) { - /* no IO indicated but software detected errors - * in the block, either checksum errors or - * issues with the contents */ - struct btrfs_root *root = - BTRFS_I(page->mapping->host)->root; - struct btrfs_device *device; - + if (ret) uptodate = 0; - device = btrfs_find_device_for_logical( - root, start, mirror); - if (device) - btrfs_dev_stat_inc_and_print(device, - BTRFS_DEV_STAT_CORRUPTION_ERRS); - } else { + else clean_io_failure(start, page); - } } if (!uptodate && tree->ops && tree->ops->readpage_io_failed_hook) { diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index b45b9de0c21d..857d93cd01dc 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -272,9 +272,9 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, } int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u64 offset, u32 *dst) + struct bio *bio, u64 offset) { - return __btrfs_lookup_bio_sums(root, inode, bio, offset, dst, 1); + return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); } int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6e8f416773d4..ec154f954646 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1008,9 +1008,7 @@ static noinline void async_cow_submit(struct btrfs_work *work) nr_pages = (async_cow->end - async_cow->start + PAGE_CACHE_SIZE) >> PAGE_CACHE_SHIFT; - atomic_sub(nr_pages, &root->fs_info->async_delalloc_pages); - - if (atomic_read(&root->fs_info->async_delalloc_pages) < + if (atomic_sub_return(nr_pages, &root->fs_info->async_delalloc_pages) < 5 * 1024 * 1024 && waitqueue_active(&root->fs_info->async_submit_wait)) wake_up(&root->fs_info->async_submit_wait); @@ -1885,8 +1883,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) trans = btrfs_join_transaction_nolock(root); else trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + trans = NULL; + goto out; + } trans->block_rsv = &root->fs_info->delalloc_block_rsv; ret = btrfs_update_inode_fallback(trans, root, inode); if (ret) /* -ENOMEM or corruption */ @@ -3174,7 +3175,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, btrfs_i_size_write(dir, dir->i_size - name_len * 2); inode_inc_iversion(dir); dir->i_mtime = dir->i_ctime = CURRENT_TIME; - ret = btrfs_update_inode(trans, root, dir); + ret = btrfs_update_inode_fallback(trans, root, dir); if (ret) btrfs_abort_transaction(trans, root, ret); out: @@ -5774,18 +5775,112 @@ out: return ret; } +static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, + struct extent_state **cached_state, int writing) +{ + struct btrfs_ordered_extent *ordered; + int ret = 0; + + while (1) { + lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, + 0, cached_state); + /* + * We're concerned with the entire range that we're going to be + * doing DIO to, so we need to make sure theres no ordered + * extents in this range. + */ + ordered = btrfs_lookup_ordered_range(inode, lockstart, + lockend - lockstart + 1); + + /* + * We need to make sure there are no buffered pages in this + * range either, we could have raced between the invalidate in + * generic_file_direct_write and locking the extent. The + * invalidate needs to happen so that reads after a write do not + * get stale data. + */ + if (!ordered && (!writing || + !test_range_bit(&BTRFS_I(inode)->io_tree, + lockstart, lockend, EXTENT_UPTODATE, 0, + *cached_state))) + break; + + unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, + cached_state, GFP_NOFS); + + if (ordered) { + btrfs_start_ordered_extent(inode, ordered, 1); + btrfs_put_ordered_extent(ordered); + } else { + /* Screw you mmap */ + ret = filemap_write_and_wait_range(inode->i_mapping, + lockstart, + lockend); + if (ret) + break; + + /* + * If we found a page that couldn't be invalidated just + * fall back to buffered. + */ + ret = invalidate_inode_pages2_range(inode->i_mapping, + lockstart >> PAGE_CACHE_SHIFT, + lockend >> PAGE_CACHE_SHIFT); + if (ret) + break; + } + + cond_resched(); + } + + return ret; +} + static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { struct extent_map *em; struct btrfs_root *root = BTRFS_I(inode)->root; + struct extent_state *cached_state = NULL; u64 start = iblock << inode->i_blkbits; + u64 lockstart, lockend; u64 len = bh_result->b_size; struct btrfs_trans_handle *trans; + int unlock_bits = EXTENT_LOCKED; + int ret; + + if (create) { + ret = btrfs_delalloc_reserve_space(inode, len); + if (ret) + return ret; + unlock_bits |= EXTENT_DELALLOC | EXTENT_DIRTY; + } else { + len = min_t(u64, len, root->sectorsize); + } + + lockstart = start; + lockend = start + len - 1; + + /* + * If this errors out it's because we couldn't invalidate pagecache for + * this range and we need to fallback to buffered. + */ + if (lock_extent_direct(inode, lockstart, lockend, &cached_state, create)) + return -ENOTBLK; + + if (create) { + ret = set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, + lockend, EXTENT_DELALLOC, NULL, + &cached_state, GFP_NOFS); + if (ret) + goto unlock_err; + } em = btrfs_get_extent(inode, NULL, 0, start, len, 0); - if (IS_ERR(em)) - return PTR_ERR(em); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto unlock_err; + } /* * Ok for INLINE and COMPRESSED extents we need to fallback on buffered @@ -5804,17 +5899,16 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) || em->block_start == EXTENT_MAP_INLINE) { free_extent_map(em); - return -ENOTBLK; + ret = -ENOTBLK; + goto unlock_err; } /* Just a good old fashioned hole, return */ if (!create && (em->block_start == EXTENT_MAP_HOLE || test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { free_extent_map(em); - /* DIO will do one hole at a time, so just unlock a sector */ - unlock_extent(&BTRFS_I(inode)->io_tree, start, - start + root->sectorsize - 1); - return 0; + ret = 0; + goto unlock_err; } /* @@ -5827,8 +5921,9 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, * */ if (!create) { - len = em->len - (start - em->start); - goto map; + len = min(len, em->len - (start - em->start)); + lockstart = start + len; + goto unlock; } if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || @@ -5860,7 +5955,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, btrfs_end_transaction(trans, root); if (ret) { free_extent_map(em); - return ret; + goto unlock_err; } goto unlock; } @@ -5873,14 +5968,12 @@ must_cow: */ len = bh_result->b_size; em = btrfs_new_extent_direct(inode, em, start, len); - if (IS_ERR(em)) - return PTR_ERR(em); + if (IS_ERR(em)) { + ret = PTR_ERR(em); + goto unlock_err; + } len = min(len, em->len - (start - em->start)); unlock: - clear_extent_bit(&BTRFS_I(inode)->io_tree, start, start + len - 1, - EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_DIRTY, 1, - 0, NULL, GFP_NOFS); -map: bh_result->b_blocknr = (em->block_start + (start - em->start)) >> inode->i_blkbits; bh_result->b_size = len; @@ -5898,9 +5991,44 @@ map: i_size_write(inode, start + len); } + /* + * In the case of write we need to clear and unlock the entire range, + * in the case of read we need to unlock only the end area that we + * aren't using if there is any left over space. + */ + if (lockstart < lockend) { + if (create && len < lockend - lockstart) { + clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, + lockstart + len - 1, unlock_bits, 1, 0, + &cached_state, GFP_NOFS); + /* + * Beside unlock, we also need to cleanup reserved space + * for the left range by attaching EXTENT_DO_ACCOUNTING. + */ + clear_extent_bit(&BTRFS_I(inode)->io_tree, + lockstart + len, lockend, + unlock_bits | EXTENT_DO_ACCOUNTING, + 1, 0, NULL, GFP_NOFS); + } else { + clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, + lockend, unlock_bits, 1, 0, + &cached_state, GFP_NOFS); + } + } else { + free_extent_state(cached_state); + } + free_extent_map(em); return 0; + +unlock_err: + if (create) + unlock_bits |= EXTENT_DO_ACCOUNTING; + + clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend, + unlock_bits, 1, 0, &cached_state, GFP_NOFS); + return ret; } struct btrfs_dio_private { @@ -5908,7 +6036,6 @@ struct btrfs_dio_private { u64 logical_offset; u64 disk_bytenr; u64 bytes; - u32 *csums; void *private; /* number of bios pending for this dio */ @@ -5928,7 +6055,6 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) struct inode *inode = dip->inode; struct btrfs_root *root = BTRFS_I(inode)->root; u64 start; - u32 *private = dip->csums; start = dip->logical_offset; do { @@ -5936,8 +6062,12 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) struct page *page = bvec->bv_page; char *kaddr; u32 csum = ~(u32)0; + u64 private = ~(u32)0; unsigned long flags; + if (get_state_private(&BTRFS_I(inode)->io_tree, + start, &private)) + goto failed; local_irq_save(flags); kaddr = kmap_atomic(page); csum = btrfs_csum_data(root, kaddr + bvec->bv_offset, @@ -5947,18 +6077,18 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) local_irq_restore(flags); flush_dcache_page(bvec->bv_page); - if (csum != *private) { + if (csum != private) { +failed: printk(KERN_ERR "btrfs csum failed ino %llu off" " %llu csum %u private %u\n", (unsigned long long)btrfs_ino(inode), (unsigned long long)start, - csum, *private); + csum, (unsigned)private); err = -EIO; } } start += bvec->bv_len; - private++; bvec++; } while (bvec <= bvec_end); @@ -5966,7 +6096,6 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) dip->logical_offset + dip->bytes - 1); bio->bi_private = dip->private; - kfree(dip->csums); kfree(dip); /* If we had a csum failure make sure to clear the uptodate flag */ @@ -6072,7 +6201,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, int rw, u64 file_offset, int skip_sum, - u32 *csums, int async_submit) + int async_submit) { int write = rw & REQ_WRITE; struct btrfs_root *root = BTRFS_I(inode)->root; @@ -6105,8 +6234,7 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, if (ret) goto err; } else if (!skip_sum) { - ret = btrfs_lookup_bio_sums_dio(root, inode, bio, - file_offset, csums); + ret = btrfs_lookup_bio_sums_dio(root, inode, bio, file_offset); if (ret) goto err; } @@ -6132,10 +6260,8 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, u64 submit_len = 0; u64 map_length; int nr_pages = 0; - u32 *csums = dip->csums; int ret = 0; int async_submit = 0; - int write = rw & REQ_WRITE; map_length = orig_bio->bi_size; ret = btrfs_map_block(map_tree, READ, start_sector << 9, @@ -6171,16 +6297,13 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, atomic_inc(&dip->pending_bios); ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, - csums, async_submit); + async_submit); if (ret) { bio_put(bio); atomic_dec(&dip->pending_bios); goto out_err; } - /* Write's use the ordered csums */ - if (!write && !skip_sum) - csums = csums + nr_pages; start_sector += submit_len >> 9; file_offset += submit_len; @@ -6210,7 +6333,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, submit: ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, - csums, async_submit); + async_submit); if (!ret) return 0; @@ -6246,17 +6369,6 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, ret = -ENOMEM; goto free_ordered; } - dip->csums = NULL; - - /* Write's use the ordered csum stuff, so we don't need dip->csums */ - if (!write && !skip_sum) { - dip->csums = kmalloc(sizeof(u32) * bio->bi_vcnt, GFP_NOFS); - if (!dip->csums) { - kfree(dip); - ret = -ENOMEM; - goto free_ordered; - } - } dip->private = bio->bi_private; dip->inode = inode; @@ -6341,132 +6453,22 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io out: return retval; } + static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct btrfs_ordered_extent *ordered; - struct extent_state *cached_state = NULL; - u64 lockstart, lockend; - ssize_t ret; - int writing = rw & WRITE; - int write_bits = 0; - size_t count = iov_length(iov, nr_segs); if (check_direct_IO(BTRFS_I(inode)->root, rw, iocb, iov, - offset, nr_segs)) { + offset, nr_segs)) return 0; - } - - lockstart = offset; - lockend = offset + count - 1; - - if (writing) { - ret = btrfs_delalloc_reserve_space(inode, count); - if (ret) - goto out; - } - - while (1) { - lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, - 0, &cached_state); - /* - * We're concerned with the entire range that we're going to be - * doing DIO to, so we need to make sure theres no ordered - * extents in this range. - */ - ordered = btrfs_lookup_ordered_range(inode, lockstart, - lockend - lockstart + 1); - - /* - * We need to make sure there are no buffered pages in this - * range either, we could have raced between the invalidate in - * generic_file_direct_write and locking the extent. The - * invalidate needs to happen so that reads after a write do not - * get stale data. - */ - if (!ordered && (!writing || - !test_range_bit(&BTRFS_I(inode)->io_tree, - lockstart, lockend, EXTENT_UPTODATE, 0, - cached_state))) - break; - - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state, GFP_NOFS); - - if (ordered) { - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - } else { - /* Screw you mmap */ - ret = filemap_write_and_wait_range(file->f_mapping, - lockstart, - lockend); - if (ret) - goto out; - - /* - * If we found a page that couldn't be invalidated just - * fall back to buffered. - */ - ret = invalidate_inode_pages2_range(file->f_mapping, - lockstart >> PAGE_CACHE_SHIFT, - lockend >> PAGE_CACHE_SHIFT); - if (ret) { - if (ret == -EBUSY) - ret = 0; - goto out; - } - } - - cond_resched(); - } - /* - * we don't use btrfs_set_extent_delalloc because we don't want - * the dirty or uptodate bits - */ - if (writing) { - write_bits = EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING; - ret = set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend, - EXTENT_DELALLOC, NULL, &cached_state, - GFP_NOFS); - if (ret) { - clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, - lockend, EXTENT_LOCKED | write_bits, - 1, 0, &cached_state, GFP_NOFS); - goto out; - } - } - - free_extent_state(cached_state); - cached_state = NULL; - - ret = __blockdev_direct_IO(rw, iocb, inode, + return __blockdev_direct_IO(rw, iocb, inode, BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, iov, offset, nr_segs, btrfs_get_blocks_direct, NULL, btrfs_submit_direct, 0); - - if (ret < 0 && ret != -EIOCBQUEUED) { - clear_extent_bit(&BTRFS_I(inode)->io_tree, offset, - offset + iov_length(iov, nr_segs) - 1, - EXTENT_LOCKED | write_bits, 1, 0, - &cached_state, GFP_NOFS); - } else if (ret >= 0 && ret < iov_length(iov, nr_segs)) { - /* - * We're falling back to buffered, unlock the section we didn't - * do IO on. - */ - clear_extent_bit(&BTRFS_I(inode)->io_tree, offset + ret, - offset + iov_length(iov, nr_segs) - 1, - EXTENT_LOCKED | write_bits, 1, 0, - &cached_state, GFP_NOFS); - } -out: - free_extent_state(cached_state); - return ret; } static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 7bb755677a22..9df50fa8a078 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -424,7 +424,7 @@ static noinline int create_subvol(struct btrfs_root *root, uuid_le_gen(&new_uuid); memcpy(root_item.uuid, new_uuid.b, BTRFS_UUID_SIZE); root_item.otime.sec = cpu_to_le64(cur_time.tv_sec); - root_item.otime.nsec = cpu_to_le64(cur_time.tv_nsec); + root_item.otime.nsec = cpu_to_le32(cur_time.tv_nsec); root_item.ctime = root_item.otime; btrfs_set_root_ctransid(&root_item, trans->transid); btrfs_set_root_otransid(&root_item, trans->transid); diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c index a44eff074805..2a1762c66041 100644 --- a/fs/btrfs/locking.c +++ b/fs/btrfs/locking.c @@ -67,7 +67,7 @@ void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw) { if (eb->lock_nested) { read_lock(&eb->lock); - if (&eb->lock_nested && current->pid == eb->lock_owner) { + if (eb->lock_nested && current->pid == eb->lock_owner) { read_unlock(&eb->lock); return; } diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index bc424ae5a81a..38b42e7bc91d 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1364,13 +1364,17 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, spin_lock(&fs_info->qgroup_lock); dstgroup = add_qgroup_rb(fs_info, objectid); - if (!dstgroup) + if (IS_ERR(dstgroup)) { + ret = PTR_ERR(dstgroup); goto unlock; + } if (srcid) { srcgroup = find_qgroup_rb(fs_info, srcid); - if (!srcgroup) + if (!srcgroup) { + ret = -EINVAL; goto unlock; + } dstgroup->rfer = srcgroup->rfer - level_size; dstgroup->rfer_cmpr = srcgroup->rfer_cmpr - level_size; srcgroup->excl = level_size; @@ -1379,8 +1383,10 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, qgroup_dirty(fs_info, srcgroup); } - if (!inherit) + if (!inherit) { + ret = -EINVAL; goto unlock; + } i_qgroups = (u64 *)(inherit + 1); for (i = 0; i < inherit->num_qgroups; ++i) { diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 6bb465cca20f..10d8e4d88071 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -544,8 +544,8 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans, struct timespec ct = CURRENT_TIME; spin_lock(&root->root_times_lock); - item->ctransid = trans->transid; + item->ctransid = cpu_to_le64(trans->transid); item->ctime.sec = cpu_to_le64(ct.tv_sec); - item->ctime.nsec = cpu_to_le64(ct.tv_nsec); + item->ctime.nsec = cpu_to_le32(ct.tv_nsec); spin_unlock(&root->root_times_lock); } diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f2eb24c477a3..83d6f9f9c220 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -838,7 +838,6 @@ int btrfs_sync_fs(struct super_block *sb, int wait) struct btrfs_trans_handle *trans; struct btrfs_fs_info *fs_info = btrfs_sb(sb); struct btrfs_root *root = fs_info->tree_root; - int ret; trace_btrfs_sync_fs(wait); @@ -849,11 +848,17 @@ int btrfs_sync_fs(struct super_block *sb, int wait) btrfs_wait_ordered_extents(root, 0, 0); - trans = btrfs_start_transaction(root, 0); + spin_lock(&fs_info->trans_lock); + if (!fs_info->running_transaction) { + spin_unlock(&fs_info->trans_lock); + return 0; + } + spin_unlock(&fs_info->trans_lock); + + trans = btrfs_join_transaction(root); if (IS_ERR(trans)) return PTR_ERR(trans); - ret = btrfs_commit_transaction(trans, root); - return ret; + return btrfs_commit_transaction(trans, root); } static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) @@ -1530,6 +1535,8 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root) while (cur_devices) { head = &cur_devices->devices; list_for_each_entry(dev, head, dev_list) { + if (dev->missing) + continue; if (!first_dev || dev->devid < first_dev->devid) first_dev = dev; } diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 17be3dedacba..27c26004e050 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -1031,6 +1031,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, btrfs_i_size_write(parent_inode, parent_inode->i_size + dentry->d_name.len * 2); + parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, parent_root, parent_inode); if (ret) goto abort_trans_dput; @@ -1066,7 +1067,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, memcpy(new_root_item->parent_uuid, root->root_item.uuid, BTRFS_UUID_SIZE); new_root_item->otime.sec = cpu_to_le64(cur_time.tv_sec); - new_root_item->otime.nsec = cpu_to_le64(cur_time.tv_nsec); + new_root_item->otime.nsec = cpu_to_le32(cur_time.tv_nsec); btrfs_set_root_otransid(new_root_item, trans->transid); memset(&new_root_item->stime, 0, sizeof(new_root_item->stime)); memset(&new_root_item->rtime, 0, sizeof(new_root_item->rtime)); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e86ae04abe6a..88b969aeeb71 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -227,9 +227,8 @@ loop_lock: cur = pending; pending = pending->bi_next; cur->bi_next = NULL; - atomic_dec(&fs_info->nr_async_bios); - if (atomic_read(&fs_info->nr_async_bios) < limit && + if (atomic_dec_return(&fs_info->nr_async_bios) < limit && waitqueue_active(&fs_info->async_submit_wait)) wake_up(&fs_info->async_submit_wait); @@ -569,9 +568,11 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) memcpy(new_device, device, sizeof(*new_device)); /* Safe because we are under uuid_mutex */ - name = rcu_string_strdup(device->name->str, GFP_NOFS); - BUG_ON(device->name && !name); /* -ENOMEM */ - rcu_assign_pointer(new_device->name, name); + if (device->name) { + name = rcu_string_strdup(device->name->str, GFP_NOFS); + BUG_ON(device->name && !name); /* -ENOMEM */ + rcu_assign_pointer(new_device->name, name); + } new_device->bdev = NULL; new_device->writeable = 0; new_device->in_fs_metadata = 0; @@ -4605,28 +4606,6 @@ int btrfs_read_sys_array(struct btrfs_root *root) return ret; } -struct btrfs_device *btrfs_find_device_for_logical(struct btrfs_root *root, - u64 logical, int mirror_num) -{ - struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; - int ret; - u64 map_length = 0; - struct btrfs_bio *bbio = NULL; - struct btrfs_device *device; - - BUG_ON(mirror_num == 0); - ret = btrfs_map_block(map_tree, WRITE, logical, &map_length, &bbio, - mirror_num); - if (ret) { - BUG_ON(bbio != NULL); - return NULL; - } - BUG_ON(mirror_num != bbio->mirror_num); - device = bbio->stripes[mirror_num - 1].dev; - kfree(bbio); - return device; -} - int btrfs_read_chunk_tree(struct btrfs_root *root) { struct btrfs_path *path; diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 5479325987b3..53c06af92e8d 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -289,8 +289,6 @@ int btrfs_cancel_balance(struct btrfs_fs_info *fs_info); int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, u64 *start, u64 *max_avail); -struct btrfs_device *btrfs_find_device_for_logical(struct btrfs_root *root, - u64 logical, int mirror_num); void btrfs_dev_stat_print_on_error(struct btrfs_device *device); void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); int btrfs_get_dev_stats(struct btrfs_root *root, diff --git a/fs/buffer.c b/fs/buffer.c index 9f6d2e41281d..58e2e7b77372 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -914,7 +914,7 @@ link_dev_buffers(struct page *page, struct buffer_head *head) /* * Initialise the state of a blockdev page's buffers. */ -static void +static sector_t init_page_buffers(struct page *page, struct block_device *bdev, sector_t block, int size) { @@ -936,33 +936,41 @@ init_page_buffers(struct page *page, struct block_device *bdev, block++; bh = bh->b_this_page; } while (bh != head); + + /* + * Caller needs to validate requested block against end of device. + */ + return end_block; } /* * Create the page-cache page that contains the requested block. * - * This is user purely for blockdev mappings. + * This is used purely for blockdev mappings. */ -static struct page * +static int grow_dev_page(struct block_device *bdev, sector_t block, - pgoff_t index, int size) + pgoff_t index, int size, int sizebits) { struct inode *inode = bdev->bd_inode; struct page *page; struct buffer_head *bh; + sector_t end_block; + int ret = 0; /* Will call free_more_memory() */ page = find_or_create_page(inode->i_mapping, index, (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE); if (!page) - return NULL; + return ret; BUG_ON(!PageLocked(page)); if (page_has_buffers(page)) { bh = page_buffers(page); if (bh->b_size == size) { - init_page_buffers(page, bdev, block, size); - return page; + end_block = init_page_buffers(page, bdev, + index << sizebits, size); + goto done; } if (!try_to_free_buffers(page)) goto failed; @@ -982,14 +990,14 @@ grow_dev_page(struct block_device *bdev, sector_t block, */ spin_lock(&inode->i_mapping->private_lock); link_dev_buffers(page, bh); - init_page_buffers(page, bdev, block, size); + end_block = init_page_buffers(page, bdev, index << sizebits, size); spin_unlock(&inode->i_mapping->private_lock); - return page; - +done: + ret = (block < end_block) ? 1 : -ENXIO; failed: unlock_page(page); page_cache_release(page); - return NULL; + return ret; } /* @@ -999,7 +1007,6 @@ failed: static int grow_buffers(struct block_device *bdev, sector_t block, int size) { - struct page *page; pgoff_t index; int sizebits; @@ -1023,22 +1030,14 @@ grow_buffers(struct block_device *bdev, sector_t block, int size) bdevname(bdev, b)); return -EIO; } - block = index << sizebits; + /* Create a page with the proper size buffers.. */ - page = grow_dev_page(bdev, block, index, size); - if (!page) - return 0; - unlock_page(page); - page_cache_release(page); - return 1; + return grow_dev_page(bdev, block, index, size, sizebits); } static struct buffer_head * __getblk_slow(struct block_device *bdev, sector_t block, int size) { - int ret; - struct buffer_head *bh; - /* Size must be multiple of hard sectorsize */ if (unlikely(size & (bdev_logical_block_size(bdev)-1) || (size < 512 || size > PAGE_SIZE))) { @@ -1051,21 +1050,20 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) return NULL; } -retry: - bh = __find_get_block(bdev, block, size); - if (bh) - return bh; + for (;;) { + struct buffer_head *bh; + int ret; - ret = grow_buffers(bdev, block, size); - if (ret == 0) { - free_more_memory(); - goto retry; - } else if (ret > 0) { bh = __find_get_block(bdev, block, size); if (bh) return bh; + + ret = grow_buffers(bdev, block, size); + if (ret < 0) + return NULL; + if (ret == 0) + free_more_memory(); } - return NULL; } /* @@ -1321,10 +1319,6 @@ EXPORT_SYMBOL(__find_get_block); * which corresponds to the passed block_device, block and size. The * returned buffer has its reference count incremented. * - * __getblk() cannot fail - it just keeps trying. If you pass it an - * illegal block number, __getblk() will happily return a buffer_head - * which represents the non-existent block. Very weird. - * * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers() * attempt is failing. FIXME, perhaps? */ diff --git a/fs/direct-io.c b/fs/direct-io.c index 1faf4cb56f39..f86c720dba0e 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1062,6 +1062,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, unsigned long user_addr; size_t bytes; struct buffer_head map_bh = { 0, }; + struct blk_plug plug; if (rw & WRITE) rw = WRITE_ODIRECT; @@ -1177,6 +1178,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, PAGE_SIZE - user_addr / PAGE_SIZE); } + blk_start_plug(&plug); + for (seg = 0; seg < nr_segs; seg++) { user_addr = (unsigned long)iov[seg].iov_base; sdio.size += bytes = iov[seg].iov_len; @@ -1235,6 +1238,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, if (sdio.bio) dio_bio_submit(dio, &sdio); + blk_finish_plug(&plug); + /* * It is possible that, we return short IO due to end of file. * In that case, we need to release all the pages we got hold on. diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 09357508ec9a..a2862339323b 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1113,6 +1113,11 @@ static void mark_journal_empty(journal_t *journal) BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); spin_lock(&journal->j_state_lock); + /* Is it already empty? */ + if (sb->s_start == 0) { + spin_unlock(&journal->j_state_lock); + return; + } jbd_debug(1, "JBD: Marking journal as empty (seq %d)\n", journal->j_tail_sequence); diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index df0de27c2733..e784a217b500 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -26,6 +26,7 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw) struct completion complete; bio_init(&bio); + bio.bi_max_vecs = 1; bio.bi_io_vec = &bio_vec; bio_vec.bv_page = page; bio_vec.bv_len = PAGE_SIZE; @@ -95,12 +96,11 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, struct address_space *mapping = super->s_mapping_inode->i_mapping; struct bio *bio; struct page *page; - struct request_queue *q = bdev_get_queue(sb->s_bdev); - unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); + unsigned int max_pages; int i; - if (max_pages > BIO_MAX_PAGES) - max_pages = BIO_MAX_PAGES; + max_pages = min(nr_pages, (size_t) bio_get_nr_vecs(super->s_bdev)); + bio = bio_alloc(GFP_NOFS, max_pages); BUG_ON(!bio); @@ -190,12 +190,11 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, { struct logfs_super *super = logfs_super(sb); struct bio *bio; - struct request_queue *q = bdev_get_queue(sb->s_bdev); - unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); + unsigned int max_pages; int i; - if (max_pages > BIO_MAX_PAGES) - max_pages = BIO_MAX_PAGES; + max_pages = min(nr_pages, (size_t) bio_get_nr_vecs(super->s_bdev)); + bio = bio_alloc(GFP_NOFS, max_pages); BUG_ON(!bio); diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index a422f42238b2..6984562738d3 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c @@ -156,10 +156,26 @@ static void __logfs_destroy_inode(struct inode *inode) call_rcu(&inode->i_rcu, logfs_i_callback); } +static void __logfs_destroy_meta_inode(struct inode *inode) +{ + struct logfs_inode *li = logfs_inode(inode); + BUG_ON(li->li_block); + call_rcu(&inode->i_rcu, logfs_i_callback); +} + static void logfs_destroy_inode(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); + if (inode->i_ino < LOGFS_RESERVED_INOS) { + /* + * The reserved inodes are never destroyed unless we are in + * unmont path. + */ + __logfs_destroy_meta_inode(inode); + return; + } + BUG_ON(list_empty(&li->li_freeing_list)); spin_lock(&logfs_inode_lock); li->li_refcount--; @@ -373,8 +389,8 @@ static void logfs_put_super(struct super_block *sb) { struct logfs_super *super = logfs_super(sb); /* kill the meta-inodes */ - iput(super->s_master_inode); iput(super->s_segfile_inode); + iput(super->s_master_inode); iput(super->s_mapping_inode); } diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index 1e1c369df22b..2a09b8d73989 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c @@ -565,7 +565,7 @@ static void write_wbuf(struct super_block *sb, struct logfs_area *area, index = ofs >> PAGE_SHIFT; page_ofs = ofs & (PAGE_SIZE - 1); - page = find_lock_page(mapping, index); + page = find_or_create_page(mapping, index, GFP_NOFS); BUG_ON(!page); memcpy(wbuf, page_address(page) + page_ofs, super->s_writesize); unlock_page(page); diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index f1cb512c5019..5be0abef603d 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c @@ -2189,7 +2189,6 @@ void logfs_evict_inode(struct inode *inode) return; } - BUG_ON(inode->i_ino < LOGFS_RESERVED_INOS); page = inode_to_page(inode); BUG_ON(!page); /* FIXME: Use emergency page */ logfs_put_write_page(page); diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index e28d090c98d6..038da0991794 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c @@ -886,7 +886,7 @@ static struct logfs_area *alloc_area(struct super_block *sb) static void map_invalidatepage(struct page *page, unsigned long l) { - BUG(); + return; } static int map_releasepage(struct page *page, gfp_t g) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index cbaf4f8bb7b7..4c7bd35b1876 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -651,12 +651,12 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c if (clp->cl_minorversion == 0) { if (!clp->cl_cred.cr_principal && - (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) + (clp->cl_cred.cr_flavor >= RPC_AUTH_GSS_KRB5)) return -EINVAL; args.client_name = clp->cl_cred.cr_principal; args.prognumber = conn->cb_prog, args.protocol = XPRT_TRANSPORT_TCP; - args.authflavor = clp->cl_flavor; + args.authflavor = clp->cl_cred.cr_flavor; clp->cl_cb_ident = conn->cb_ident; } else { if (!conn->cb_xprt) diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index e6173147f982..22bd0a66c356 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -231,7 +231,6 @@ struct nfs4_client { nfs4_verifier cl_verifier; /* generated by client */ time_t cl_time; /* time of last lease renewal */ struct sockaddr_storage cl_addr; /* client ipaddress */ - u32 cl_flavor; /* setclientid pseudoflavor */ struct svc_cred cl_cred; /* setclientid principal */ clientid_t cl_clientid; /* generated by server */ nfs4_verifier cl_confirm; /* generated by server */ diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 36a29b753c79..c495a3055e2a 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -1589,10 +1589,10 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) goto out; } - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) warn[cnt].w_type = QUOTA_NL_NOWARN; + down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); spin_lock(&dq_data_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (!dquots[cnt]) diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 4c0c7d163d15..a98b7740a0fc 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -1334,9 +1334,7 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, else if (bitmap == 0) block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1; - reiserfs_write_unlock(sb); bh = sb_bread(sb, block); - reiserfs_write_lock(sb); if (bh == NULL) reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) " "reading failed", __func__, block); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index a6d4268fb6c1..855da58db145 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -76,10 +76,10 @@ void reiserfs_evict_inode(struct inode *inode) ; } out: + reiserfs_write_unlock_once(inode->i_sb, depth); clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */ dquot_drop(inode); inode->i_blocks = 0; - reiserfs_write_unlock_once(inode->i_sb, depth); return; no_delete: diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 8b8cc4e945f4..760de723dadb 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -167,7 +167,7 @@ struct ubifs_global_debug_info { #define ubifs_dbg_msg(type, fmt, ...) \ pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__) -#define DBG_KEY_BUF_LEN 32 +#define DBG_KEY_BUF_LEN 48 #define ubifs_dbg_msg_key(type, key, fmt, ...) do { \ char __tmp_key_buf[DBG_KEY_BUF_LEN]; \ pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__, \ diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c index ce33b2beb151..8640920766ed 100644 --- a/fs/ubifs/lpt.c +++ b/fs/ubifs/lpt.c @@ -1749,7 +1749,10 @@ int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr) return 0; out_err: - ubifs_lpt_free(c, 0); + if (wr) + ubifs_lpt_free(c, 1); + if (rd) + ubifs_lpt_free(c, 0); return err; } diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index c30d976b4be8..edeec499c048 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -788,7 +788,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, corrupted_rescan: /* Re-scan the corrupted data with verbose messages */ - ubifs_err("corruptio %d", ret); + ubifs_err("corruption %d", ret); ubifs_scan_a_node(c, buf, len, lnum, offs, 1); corrupted: ubifs_scanned_corruption(c, lnum, offs, buf); diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index eba46d4a7619..94d78fc5d4e0 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c @@ -1026,7 +1026,6 @@ int ubifs_replay_journal(struct ubifs_info *c) c->replaying = 1; lnum = c->ltail_lnum = c->lhead_lnum; - lnum = UBIFS_LOG_LNUM; do { err = replay_log_leb(c, lnum, 0, c->sbuf); if (err == 1) @@ -1035,7 +1034,7 @@ int ubifs_replay_journal(struct ubifs_info *c) if (err) goto out; lnum = ubifs_next_log_lnum(c, lnum); - } while (lnum != UBIFS_LOG_LNUM); + } while (lnum != c->ltail_lnum); err = replay_buds(c); if (err) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index c3fa6c5327a3..71a197f0f93d 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1157,9 +1157,6 @@ static int check_free_space(struct ubifs_info *c) * * This function mounts UBIFS file system. Returns zero in case of success and * a negative error code in case of failure. - * - * Note, the function does not de-allocate resources it it fails half way - * through, and the caller has to do this instead. */ static int mount_ubifs(struct ubifs_info *c) { diff --git a/fs/udf/inode.c b/fs/udf/inode.c index fafaad795cd6..aa233469b3c1 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1124,14 +1124,17 @@ int udf_setsize(struct inode *inode, loff_t newsize) if (err) return err; down_write(&iinfo->i_data_sem); - } else + } else { iinfo->i_lenAlloc = newsize; + goto set_size; + } } err = udf_extend_file(inode, newsize); if (err) { up_write(&iinfo->i_data_sem); return err; } +set_size: truncate_setsize(inode, newsize); up_write(&iinfo->i_data_sem); } else { diff --git a/fs/udf/super.c b/fs/udf/super.c index dcbf98722afc..18fc038a438d 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1344,6 +1344,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, udf_err(sb, "error loading logical volume descriptor: " "Partition table too long (%u > %lu)\n", table_len, sb->s_blocksize - sizeof(*lvd)); + ret = 1; goto out_bh; } @@ -1388,8 +1389,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { if (udf_load_sparable_map(sb, map, - (struct sparablePartitionMap *)gpm) < 0) + (struct sparablePartitionMap *)gpm) < 0) { + ret = 1; goto out_bh; + } } else if (!strncmp(upm2->partIdent.ident, UDF_ID_METADATA, strlen(UDF_ID_METADATA))) { @@ -2000,6 +2003,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) if (!silent) pr_notice("Rescanning with blocksize %d\n", UDF_DEFAULT_BLOCKSIZE); + brelse(sbi->s_lvid_bh); + sbi->s_lvid_bh = NULL; uopt.blocksize = UDF_DEFAULT_BLOCKSIZE; ret = udf_load_vrs(sb, &uopt, silent, &fileset); } diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c index f9c3fe304a17..69cf4fcde03e 100644 --- a/fs/xfs/xfs_discard.c +++ b/fs/xfs/xfs_discard.c @@ -179,12 +179,14 @@ xfs_ioc_trim( * used by the fstrim application. In the end it really doesn't * matter as trimming blocks is an advisory interface. */ + if (range.start >= XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks) || + range.minlen > XFS_FSB_TO_B(mp, XFS_ALLOC_AG_MAX_USABLE(mp))) + return -XFS_ERROR(EINVAL); + start = BTOBB(range.start); end = start + BTOBBT(range.len) - 1; minlen = BTOBB(max_t(u64, granularity, range.minlen)); - if (XFS_BB_TO_FSB(mp, start) >= mp->m_sb.sb_dblocks) - return -XFS_ERROR(EINVAL); if (end > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) - 1) end = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)- 1; diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 21e37b55f7e5..5aceb3f8ecd6 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -962,23 +962,22 @@ xfs_dialloc( if (!pag->pagi_freecount && !okalloc) goto nextag; + /* + * Then read in the AGI buffer and recheck with the AGI buffer + * lock held. + */ error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); if (error) goto out_error; - /* - * Once the AGI has been read in we have to recheck - * pagi_freecount with the AGI buffer lock held. - */ if (pag->pagi_freecount) { xfs_perag_put(pag); goto out_alloc; } - if (!okalloc) { - xfs_trans_brelse(tp, agbp); - goto nextag; - } + if (!okalloc) + goto nextag_relse_buffer; + error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced); if (error) { @@ -1007,6 +1006,8 @@ xfs_dialloc( return 0; } +nextag_relse_buffer: + xfs_trans_brelse(tp, agbp); nextag: xfs_perag_put(pag); if (++agno == mp->m_sb.sb_agcount) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 92d4331cd4f1..ca28a4ba4b54 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -857,7 +857,7 @@ xfs_rtbuf_get( xfs_buf_t *bp; /* block buffer, result */ xfs_inode_t *ip; /* bitmap or summary inode */ xfs_bmbt_irec_t map; - int nmap; + int nmap = 1; int error; /* error value */ ip = issum ? mp->m_rsumip : mp->m_rbmip; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index ced362533e3c..bfacf0d5a225 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -118,7 +118,8 @@ enum drm_mode_status { .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ - .vscan = (vs), .flags = (f), .vrefresh = 0 + .vscan = (vs), .flags = (f), .vrefresh = 0, \ + .base.type = DRM_MODE_OBJECT_MODE #define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index 5581980b14f6..3d6301b6ec16 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -359,8 +359,9 @@ struct drm_mode_mode_cmd { struct drm_mode_modeinfo mode; }; -#define DRM_MODE_CURSOR_BO (1<<0) -#define DRM_MODE_CURSOR_MOVE (1<<1) +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 +#define DRM_MODE_CURSOR_FLAGS 0x03 /* * depending on the value in flags different members are used. diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 4e72a9d48232..4a2ab7c85393 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -601,7 +601,7 @@ static inline void blk_clear_rl_full(struct request_list *rl, bool sync) * it already be started by driver. */ #define RQ_NOMERGE_FLAGS \ - (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA) + (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_DISCARD) #define rq_mergeable(rq) \ (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \ (((rq)->cmd_flags & REQ_DISCARD) || \ @@ -894,6 +894,8 @@ extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable); extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *); +extern int blk_bio_map_sg(struct request_queue *q, struct bio *bio, + struct scatterlist *sglist); extern void blk_dump_rq_flags(struct request *, char *); extern long nr_blockdev_pages(void); @@ -1139,6 +1141,16 @@ static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector & (lim->discard_granularity - 1); } +static inline int bdev_discard_alignment(struct block_device *bdev) +{ + struct request_queue *q = bdev_get_queue(bdev); + + if (bdev != bdev->bd_contains) + return bdev->bd_part->discard_alignment; + + return q->limits.discard_alignment; +} + static inline unsigned int queue_discard_zeroes_data(struct request_queue *q) { if (q->limits.max_discard_sectors && q->limits.discard_zeroes_data == 1) diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 040b13b5c14a..279b1eaa8b73 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -194,6 +194,10 @@ static inline int cpuidle_play_dead(void) {return -ENODEV; } #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a); +#else +static inline void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a) +{ +} #endif /****************************** diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 603bec2913b0..06177ba10a16 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -58,13 +58,6 @@ union ktime { typedef union ktime ktime_t; /* Kill this */ -#define KTIME_MAX ((s64)~((u64)1 << 63)) -#if (BITS_PER_LONG == 64) -# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) -#else -# define KTIME_SEC_MAX LONG_MAX -#endif - /* * ktime_t definitions when using the 64-bit scalar representation: */ diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h index 51bf8ada6dc0..49258e0ed1c6 100644 --- a/include/linux/mv643xx_eth.h +++ b/include/linux/mv643xx_eth.h @@ -15,6 +15,8 @@ #define MV643XX_ETH_SIZE_REG_4 0x2224 #define MV643XX_ETH_BASE_ADDR_ENABLE_REG 0x2290 +#define MV643XX_TX_CSUM_DEFAULT_LIMIT 0 + struct mv643xx_eth_shared_platform_data { struct mbus_dram_target_info *dram; struct platform_device *shared_smi; diff --git a/include/linux/time.h b/include/linux/time.h index c81c5e40fcb5..b51e664c83e7 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -107,11 +107,36 @@ static inline struct timespec timespec_sub(struct timespec lhs, return ts_delta; } +#define KTIME_MAX ((s64)~((u64)1 << 63)) +#if (BITS_PER_LONG == 64) +# define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) +#else +# define KTIME_SEC_MAX LONG_MAX +#endif + /* * Returns true if the timespec is norm, false if denorm: */ -#define timespec_valid(ts) \ - (((ts)->tv_sec >= 0) && (((unsigned long) (ts)->tv_nsec) < NSEC_PER_SEC)) +static inline bool timespec_valid(const struct timespec *ts) +{ + /* Dates before 1970 are bogus */ + if (ts->tv_sec < 0) + return false; + /* Can't have more nanoseconds then a second */ + if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) + return false; + return true; +} + +static inline bool timespec_valid_strict(const struct timespec *ts) +{ + if (!timespec_valid(ts)) + return false; + /* Disallow values that could overflow ktime_t */ + if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) + return false; + return true; +} extern void read_persistent_clock(struct timespec *ts); extern void read_boot_clock(struct timespec *ts); diff --git a/include/video/omapdss.h b/include/video/omapdss.h index a6267a2d292b..3729173b7fbc 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -48,10 +48,10 @@ #define DISPC_IRQ_FRAMEDONEWB (1 << 23) #define DISPC_IRQ_FRAMEDONETV (1 << 24) #define DISPC_IRQ_WBBUFFEROVERFLOW (1 << 25) -#define DISPC_IRQ_FRAMEDONE3 (1 << 26) -#define DISPC_IRQ_VSYNC3 (1 << 27) -#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 28) -#define DISPC_IRQ_SYNC_LOST3 (1 << 29) +#define DISPC_IRQ_SYNC_LOST3 (1 << 27) +#define DISPC_IRQ_VSYNC3 (1 << 28) +#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) +#define DISPC_IRQ_FRAMEDONE3 (1 << 30) struct omap_dss_device; struct omap_overlay_manager; @@ -73,6 +73,7 @@ enum omap_plane { OMAP_DSS_VIDEO1 = 1, OMAP_DSS_VIDEO2 = 2, OMAP_DSS_VIDEO3 = 3, + OMAP_DSS_WB = 4, }; enum omap_channel { @@ -186,6 +187,8 @@ enum omap_overlay_caps { OMAP_DSS_OVL_CAP_GLOBAL_ALPHA = 1 << 1, OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA = 1 << 2, OMAP_DSS_OVL_CAP_ZORDER = 1 << 3, + OMAP_DSS_OVL_CAP_POS = 1 << 4, + OMAP_DSS_OVL_CAP_REPLICATION = 1 << 5, }; enum omap_overlay_manager_caps { @@ -207,6 +210,16 @@ enum omap_hdmi_flags { OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0, }; +enum omap_dss_output_id { + OMAP_DSS_OUTPUT_DPI = 1 << 0, + OMAP_DSS_OUTPUT_DBI = 1 << 1, + OMAP_DSS_OUTPUT_SDI = 1 << 2, + OMAP_DSS_OUTPUT_DSI1 = 1 << 3, + OMAP_DSS_OUTPUT_DSI2 = 1 << 4, + OMAP_DSS_OUTPUT_VENC = 1 << 5, + OMAP_DSS_OUTPUT_HDMI = 1 << 6, +}; + /* RFBI */ struct rfbi_timings { @@ -243,7 +256,7 @@ void rfbi_bus_unlock(void); /* DSI */ -struct omap_dss_dsi_videomode_data { +struct omap_dss_dsi_videomode_timings { /* DSI video mode blanking data */ /* Unit: byte clock cycles */ u16 hsa; @@ -424,6 +437,8 @@ struct omap_overlay { struct omap_overlay_info *info); int (*wait_for_go)(struct omap_overlay *ovl); + + struct omap_dss_device *(*get_device)(struct omap_overlay *ovl); }; struct omap_overlay_manager_info { @@ -448,9 +463,10 @@ struct omap_overlay_manager { enum omap_overlay_manager_caps caps; struct list_head overlays; enum omap_display_type supported_displays; + enum omap_dss_output_id supported_outputs; /* dynamic fields */ - struct omap_dss_device *device; + struct omap_dss_output *output; /* * The following functions do not block: @@ -463,9 +479,9 @@ struct omap_overlay_manager { * interrupt context */ - int (*set_device)(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev); - int (*unset_device)(struct omap_overlay_manager *mgr); + int (*set_output)(struct omap_overlay_manager *mgr, + struct omap_dss_output *output); + int (*unset_output)(struct omap_overlay_manager *mgr); int (*set_manager_info)(struct omap_overlay_manager *mgr, struct omap_overlay_manager_info *info); @@ -475,6 +491,8 @@ struct omap_overlay_manager { int (*apply)(struct omap_overlay_manager *mgr); int (*wait_for_go)(struct omap_overlay_manager *mgr); int (*wait_for_vsync)(struct omap_overlay_manager *mgr); + + struct omap_dss_device *(*get_device)(struct omap_overlay_manager *mgr); }; /* 22 pins means 1 clk lane and 10 data lanes */ @@ -492,6 +510,37 @@ struct omap_dsi_pin_config { int pins[OMAP_DSS_MAX_DSI_PINS]; }; +struct omap_dss_writeback_info { + u32 paddr; + u32 p_uv_addr; + u16 buf_width; + u16 width; + u16 height; + enum omap_color_mode color_mode; + u8 rotation; + enum omap_dss_rotation_type rotation_type; + bool mirror; + u8 pre_mult_alpha; +}; + +struct omap_dss_output { + struct list_head list; + + /* display type supported by the output */ + enum omap_display_type type; + + /* output instance */ + enum omap_dss_output_id id; + + /* output's platform device pointer */ + struct platform_device *pdev; + + /* dynamic fields */ + struct omap_overlay_manager *manager; + + struct omap_dss_device *device; +}; + struct omap_dss_device { struct device dev; @@ -564,7 +613,7 @@ struct omap_dss_device { enum omap_dss_dsi_pixel_format dsi_pix_fmt; enum omap_dss_dsi_mode dsi_mode; - struct omap_dss_dsi_videomode_data dsi_vm_data; + struct omap_dss_dsi_videomode_timings dsi_vm_timings; } panel; struct { @@ -590,7 +639,7 @@ struct omap_dss_device { enum omap_display_caps caps; - struct omap_overlay_manager *manager; + struct omap_dss_output *output; enum omap_dss_display_state state; @@ -605,6 +654,8 @@ struct omap_dss_device { struct omap_dss_hdmi_data { + int ct_cp_hpd_gpio; + int ls_oe_gpio; int hpd_gpio; }; @@ -699,6 +750,11 @@ struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); int omap_dss_get_num_overlays(void); struct omap_overlay *omap_dss_get_overlay(int num); +struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id); +int omapdss_output_set_device(struct omap_dss_output *out, + struct omap_dss_device *dssdev); +int omapdss_output_unset_device(struct omap_dss_output *out); + void omapdss_default_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres); int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev); @@ -719,6 +775,15 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable); int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); +void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h); +void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, + enum omap_dss_dsi_pixel_format fmt); +void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, + enum omap_dss_dsi_mode mode); +void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, + struct omap_dss_dsi_videomode_timings *timings); int omap_dsi_update(struct omap_dss_device *dssdev, int channel, void (*callback)(int, void *), void *data); @@ -727,6 +792,8 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id); void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel); int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, const struct omap_dsi_pin_config *pin_cfg); +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, + unsigned long ddr_clk, unsigned long lp_clk); int omapdss_dsi_display_enable(struct omap_dss_device *dssdev); void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, @@ -734,22 +801,29 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, int omapdss_dpi_display_enable(struct omap_dss_device *dssdev); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev); -void dpi_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings); +void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings); +void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines); int omapdss_sdi_display_enable(struct omap_dss_device *dssdev); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev); +void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs); int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev); void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev); -int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h); -int omap_rfbi_update(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h, - void (*callback)(void *), void *data); -int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size, +int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), + void *data); +int omap_rfbi_configure(struct omap_dss_device *dssdev); +void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h); +void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, + int pixel_size); +void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines); +void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev, + struct rfbi_timings *timings); #endif diff --git a/include/xen/events.h b/include/xen/events.h index 9c641deb65d2..04399b28e821 100644 --- a/include/xen/events.h +++ b/include/xen/events.h @@ -58,8 +58,6 @@ void notify_remote_via_irq(int irq); void xen_irq_resume(void); -void xen_hvm_prepare_kexec(struct shared_info *sip, unsigned long pfn); - /* Clear an irq's pending state, in preparation for polling on it */ void xen_clear_irq_pending(int irq); void xen_set_irq_pending(int irq); diff --git a/kernel/fork.c b/kernel/fork.c index 3bd2280d79f6..2c8857e12855 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -455,8 +455,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) if (retval) goto out; - if (file && uprobe_mmap(tmp)) - goto out; + if (file) + uprobe_mmap(tmp); } /* a new mm has just been created */ arch_dup_mmap(oldmm, mm); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index e16af197a2bc..34e5eac81424 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -115,6 +115,7 @@ static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts) { tk->xtime_sec += ts->tv_sec; tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift; + tk_normalize_xtime(tk); } static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm) @@ -276,7 +277,7 @@ static void timekeeping_forward_now(struct timekeeper *tk) tk->xtime_nsec += cycle_delta * tk->mult; /* If arch requires, add in gettimeoffset() */ - tk->xtime_nsec += arch_gettimeoffset() << tk->shift; + tk->xtime_nsec += (u64)arch_gettimeoffset() << tk->shift; tk_normalize_xtime(tk); @@ -427,7 +428,7 @@ int do_settimeofday(const struct timespec *tv) struct timespec ts_delta, xt; unsigned long flags; - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + if (!timespec_valid_strict(tv)) return -EINVAL; write_seqlock_irqsave(&tk->lock, flags); @@ -463,6 +464,8 @@ int timekeeping_inject_offset(struct timespec *ts) { struct timekeeper *tk = &timekeeper; unsigned long flags; + struct timespec tmp; + int ret = 0; if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) return -EINVAL; @@ -471,10 +474,17 @@ int timekeeping_inject_offset(struct timespec *ts) timekeeping_forward_now(tk); + /* Make sure the proposed value is valid */ + tmp = timespec_add(tk_xtime(tk), *ts); + if (!timespec_valid_strict(&tmp)) { + ret = -EINVAL; + goto error; + } tk_xtime_add(tk, ts); tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts)); +error: /* even if we error out, we forwarded the time, so call update */ timekeeping_update(tk, true); write_sequnlock_irqrestore(&tk->lock, flags); @@ -482,7 +492,7 @@ int timekeeping_inject_offset(struct timespec *ts) /* signal hrtimers about time change */ clock_was_set(); - return 0; + return ret; } EXPORT_SYMBOL(timekeeping_inject_offset); @@ -649,7 +659,20 @@ void __init timekeeping_init(void) struct timespec now, boot, tmp; read_persistent_clock(&now); + if (!timespec_valid_strict(&now)) { + pr_warn("WARNING: Persistent clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + now.tv_sec = 0; + now.tv_nsec = 0; + } + read_boot_clock(&boot); + if (!timespec_valid_strict(&boot)) { + pr_warn("WARNING: Boot clock returned invalid value!\n" + " Check your CMOS/BIOS settings.\n"); + boot.tv_sec = 0; + boot.tv_nsec = 0; + } seqlock_init(&tk->lock); @@ -690,7 +713,7 @@ static struct timespec timekeeping_suspend_time; static void __timekeeping_inject_sleeptime(struct timekeeper *tk, struct timespec *delta) { - if (!timespec_valid(delta)) { + if (!timespec_valid_strict(delta)) { printk(KERN_WARNING "__timekeeping_inject_sleeptime: Invalid " "sleep delta value!\n"); return; @@ -1129,6 +1152,10 @@ static void update_wall_time(void) offset = (clock->read(clock) - clock->cycle_last) & clock->mask; #endif + /* Check if there's really nothing to do */ + if (offset < tk->cycle_interval) + goto out; + /* * With NO_HZ we may have to accumulate many cycle_intervals * (think "ticks") worth of time at once. To do this efficiently, @@ -1161,9 +1188,9 @@ static void update_wall_time(void) * the vsyscall implementations are converted to use xtime_nsec * (shifted nanoseconds), this can be killed. */ - remainder = tk->xtime_nsec & ((1 << tk->shift) - 1); + remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); tk->xtime_nsec -= remainder; - tk->xtime_nsec += 1 << tk->shift; + tk->xtime_nsec += 1ULL << tk->shift; tk->ntp_error += remainder << tk->ntp_error_shift; /* diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 60e4d7875672..6b245f64c8dd 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -506,6 +506,8 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id) int size; syscall_nr = syscall_get_nr(current, regs); + if (syscall_nr < 0) + return; if (!test_bit(syscall_nr, enabled_perf_enter_syscalls)) return; @@ -580,6 +582,8 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret) int size; syscall_nr = syscall_get_nr(current, regs); + if (syscall_nr < 0) + return; if (!test_bit(syscall_nr, enabled_perf_exit_syscalls)) return; diff --git a/mm/filemap.c b/mm/filemap.c index fa5ca304148e..384344575c37 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1412,12 +1412,8 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, retval = filemap_write_and_wait_range(mapping, pos, pos + iov_length(iov, nr_segs) - 1); if (!retval) { - struct blk_plug plug; - - blk_start_plug(&plug); retval = mapping->a_ops->direct_IO(READ, iocb, iov, pos, nr_segs); - blk_finish_plug(&plug); } if (retval > 0) { *ppos = pos + retval; @@ -2527,14 +2523,12 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct blk_plug plug; ssize_t ret; BUG_ON(iocb->ki_pos != pos); sb_start_write(inode->i_sb); mutex_lock(&inode->i_mutex); - blk_start_plug(&plug); ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); mutex_unlock(&inode->i_mutex); @@ -2545,7 +2539,6 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (err < 0 && ret > 0) ret = err; } - blk_finish_plug(&plug); sb_end_write(inode->i_sb); return ret; } diff --git a/mm/mmap.c b/mm/mmap.c index 9adee9fc0d8a..ae18a48e7e4e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1356,9 +1356,8 @@ out: } else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) make_pages_present(addr, addr + len); - if (file && uprobe_mmap(vma)) - /* matching probes but cannot insert */ - goto unmap_and_free_vma; + if (file) + uprobe_mmap(vma); return addr; diff --git a/mm/slab.c b/mm/slab.c index f8b0d539b482..811af03a14ef 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3260,6 +3260,7 @@ force_grow: /* cache_grow can reenable interrupts, then ac could change. */ ac = cpu_cache_get(cachep); + node = numa_mem_id(); /* no objects in sight? abort */ if (!x && (ac->avail == 0 || force_refill)) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 88f2bf671960..bac973a31367 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -316,7 +316,6 @@ static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) */ void svc_xprt_enqueue(struct svc_xprt *xprt) { - struct svc_serv *serv = xprt->xpt_server; struct svc_pool *pool; struct svc_rqst *rqstp; int cpu; @@ -362,8 +361,6 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) rqstp, rqstp->rq_xprt); rqstp->rq_xprt = xprt; svc_xprt_get(xprt); - rqstp->rq_reserved = serv->sv_max_mesg; - atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); pool->sp_stats.threads_woken++; wake_up(&rqstp->rq_wait); } else { @@ -640,8 +637,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) if (xprt) { rqstp->rq_xprt = xprt; svc_xprt_get(xprt); - rqstp->rq_reserved = serv->sv_max_mesg; - atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); /* As there is a shortage of threads and this request * had to be queued, don't allow the thread to wait so @@ -738,6 +733,8 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) else len = xprt->xpt_ops->xpo_recvfrom(rqstp); dprintk("svc: got len=%d\n", len); + rqstp->rq_reserved = serv->sv_max_mesg; + atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); } svc_xprt_received(xprt); @@ -794,7 +791,8 @@ int svc_send(struct svc_rqst *rqstp) /* Grab mutex to serialize outgoing data. */ mutex_lock(&xprt->xpt_mutex); - if (test_bit(XPT_DEAD, &xprt->xpt_flags)) + if (test_bit(XPT_DEAD, &xprt->xpt_flags) + || test_bit(XPT_CLOSE, &xprt->xpt_flags)) len = -ENOTCONN; else len = xprt->xpt_ops->xpo_sendto(rqstp); diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 18bc130255a7..998aa8c1807c 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1129,9 +1129,9 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) if (len >= 0) svsk->sk_tcplen += len; if (len != want) { + svc_tcp_save_pages(svsk, rqstp); if (len < 0 && len != -EAGAIN) goto err_other; - svc_tcp_save_pages(svsk, rqstp); dprintk("svc: incomplete TCP record (%d of %d)\n", svsk->sk_tcplen, svsk->sk_reclen); goto err_noclose; diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 2884e67ee625..213362850abd 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -10,10 +10,12 @@ util/ctype.c util/evlist.c util/evsel.c util/cpumap.c +util/hweight.c util/thread_map.c util/util.c util/xyarray.c util/cgroup.c util/debugfs.c +util/rblist.c util/strlist.c ../../lib/rbtree.c diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 246852397e30..d617f69131d7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1976,9 +1976,10 @@ static long kvm_vcpu_compat_ioctl(struct file *filp, if (copy_from_user(&csigset, sigmask_arg->sigset, sizeof csigset)) goto out; - } - sigset_from_compat(&sigset, &csigset); - r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); + sigset_from_compat(&sigset, &csigset); + r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); + } else + r = kvm_vcpu_ioctl_set_sigmask(vcpu, NULL); break; } default: |