Merge tag 'tags/drm-for-v4.12' into drm-intel-next-queued
Backmerge the main drm-next pull to sync up.
Chris also pointed out that
commit ade0b0c965
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Sat Apr 22 09:15:37 2017 +0100
    drm/i915: Confirm the request is still active before adding it to the await
is double-applied in the git merge, so make sure we get this right.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
			
			
This commit is contained in:
		
							
								
								
									
										2
									
								
								.mailmap
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								.mailmap
									
									
									
									
									
								
							| @@ -99,6 +99,8 @@ Linas Vepstas <linas@austin.ibm.com> | ||||
| Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de> | ||||
| Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch> | ||||
| Mark Brown <broonie@sirena.org.uk> | ||||
| Martin Kepplinger <martink@posteo.de> <martin.kepplinger@theobroma-systems.com> | ||||
| Martin Kepplinger <martink@posteo.de> <martin.kepplinger@ginzinger.com> | ||||
| Matthieu CASTET <castet.matthieu@free.fr> | ||||
| Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@brturbo.com.br> | ||||
| Mauro Carvalho Chehab <mchehab@kernel.org> <maurochehab@gmail.com> | ||||
|   | ||||
| @@ -0,0 +1,26 @@ | ||||
| Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel | ||||
|  | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
|  | ||||
| Required properties: | ||||
| - compatible: should be "ampire,am-480272h3tmqw-t01h" | ||||
|  | ||||
| Optional properties: | ||||
| - power-supply: regulator to provide the supply voltage | ||||
| - enable-gpios: GPIO pin to enable or disable the panel | ||||
| - backlight: phandle of the backlight device attached to the panel | ||||
|  | ||||
| Optional nodes: | ||||
| - Video port for RGB input. | ||||
|  | ||||
| Example: | ||||
| 	panel_rgb: panel-rgb { | ||||
| 		compatible = "ampire,am-480272h3tmqw-t01h"; | ||||
| 		enable-gpios = <&gpioa 8 1>; | ||||
| 		port { | ||||
| 			panel_in_rgb: endpoint { | ||||
| 				remote-endpoint = <&controller_out_rgb>; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
| @@ -0,0 +1,28 @@ | ||||
| Samsung S6E3HA2 5.7" 1440x2560 AMOLED panel | ||||
|  | ||||
| Required properties: | ||||
|   - compatible: "samsung,s6e3ha2" | ||||
|   - reg: the virtual channel number of a DSI peripheral | ||||
|   - vdd3-supply: I/O voltage supply | ||||
|   - vci-supply: voltage supply for analog circuits | ||||
|   - reset-gpios: a GPIO spec for the reset pin (active low) | ||||
|   - enable-gpios: a GPIO spec for the panel enable pin (active high) | ||||
|  | ||||
| Optional properties: | ||||
|   - te-gpios: a GPIO spec for the tearing effect synchronization signal | ||||
|     gpio pin (active high) | ||||
|  | ||||
| Example: | ||||
| &dsi { | ||||
| 	... | ||||
|  | ||||
| 	panel@0 { | ||||
| 		compatible = "samsung,s6e3ha2"; | ||||
| 		reg = <0>; | ||||
| 		vdd3-supply = <&ldo27_reg>; | ||||
| 		vci-supply = <&ldo28_reg>; | ||||
| 		reset-gpios = <&gpg0 0 GPIO_ACTIVE_LOW>; | ||||
| 		enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>; | ||||
| 		te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>; | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,37 @@ | ||||
| Sitronix ST7789V RGB panel with SPI control bus | ||||
|  | ||||
| Required properties: | ||||
|   - compatible: "sitronix,st7789v" | ||||
|   - reg: Chip select of the panel on the SPI bus | ||||
|   - reset-gpios: a GPIO phandle for the reset pin | ||||
|   - power-supply: phandle of the regulator that provides the supply voltage | ||||
|  | ||||
| Optional properties: | ||||
|   - backlight: phandle to the backlight used | ||||
|  | ||||
| The generic bindings for the SPI slaves documented in [1] also applies | ||||
|  | ||||
| The device node can contain one 'port' child node with one child | ||||
| 'endpoint' node, according to the bindings defined in [2]. This | ||||
| node should describe panel's video bus. | ||||
|  | ||||
| [1]: Documentation/devicetree/bindings/spi/spi-bus.txt | ||||
| [2]: Documentation/devicetree/bindings/graph.txt | ||||
|  | ||||
| Example: | ||||
|  | ||||
| panel@0 { | ||||
| 	compatible = "sitronix,st7789v"; | ||||
| 	reg = <0>; | ||||
| 	reset-gpios = <&pio 6 11 GPIO_ACTIVE_LOW>; | ||||
| 	backlight = <&pwm_bl>; | ||||
| 	spi-max-frequency = <100000>; | ||||
| 	spi-cpol; | ||||
| 	spi-cpha; | ||||
|  | ||||
| 	port { | ||||
| 		panel_input: endpoint { | ||||
| 			remote-endpoint = <&tcon0_out_panel>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,48 @@ | ||||
| Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel | ||||
|  | ||||
| Required properties: | ||||
| - compatible: should be "winstar,wf35ltiacd" | ||||
| - power-supply: regulator to provide the VCC supply voltage (3.3 volts) | ||||
|  | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
|  | ||||
| Example: | ||||
| 	backlight: backlight { | ||||
| 		compatible = "pwm-backlight"; | ||||
| 		pwms = <&hlcdc_pwm 0 50000 PWM_POLARITY_INVERTED>; | ||||
| 		brightness-levels = <0 31 63 95 127 159 191 223 255>; | ||||
| 		default-brightness-level = <191>; | ||||
| 		power-supply = <&bl_reg>; | ||||
| 	}; | ||||
|  | ||||
| 	bl_reg: backlight_regulator { | ||||
| 		compatible = "regulator-fixed"; | ||||
| 		regulator-name = "backlight-power-supply"; | ||||
| 		regulator-min-microvolt = <5000000>; | ||||
| 		regulator-max-microvolt = <5000000>; | ||||
| 	}; | ||||
|  | ||||
| 	panel: panel { | ||||
| 		compatible = "winstar,wf35ltiacd", "simple-panel"; | ||||
| 		backlight = <&backlight>; | ||||
| 		power-supply = <&panel_reg>; | ||||
| 		#address-cells = <1>; | ||||
| 		#size-cells = <0>; | ||||
|  | ||||
| 		port { | ||||
| 			#address-cells = <1>; | ||||
| 			#size-cells = <0>; | ||||
|  | ||||
| 			panel_input: endpoint { | ||||
| 				remote-endpoint = <&hlcdc_panel_output>; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	panel_reg: panel_regulator { | ||||
| 		compatible = "regulator-fixed"; | ||||
| 		regulator-name = "panel-power-supply"; | ||||
| 		regulator-min-microvolt = <3300000>; | ||||
| 		regulator-max-microvolt = <3300000>; | ||||
| 	}; | ||||
| @@ -336,6 +336,7 @@ wd	Western Digital Corp. | ||||
| wetek	WeTek Electronics, limited. | ||||
| wexler	Wexler | ||||
| winbond Winbond Electronics corp. | ||||
| winstar	Winstar Display Corp. | ||||
| wlf	Wolfson Microelectronics | ||||
| wm	Wondermedia Technologies, Inc. | ||||
| x-powers	X-Powers | ||||
|   | ||||
| @@ -4247,6 +4247,7 @@ L:	dri-devel@lists.freedesktop.org | ||||
| S:	Supported | ||||
| F:	drivers/gpu/drm/sun4i/ | ||||
| F:	Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | ||||
| T:	git git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux.git | ||||
|  | ||||
| DRM DRIVERS FOR AMLOGIC SOCS | ||||
| M:	Neil Armstrong <narmstrong@baylibre.com> | ||||
| @@ -4417,7 +4418,7 @@ DRM DRIVERS FOR STI | ||||
| M:	Benjamin Gaignard <benjamin.gaignard@linaro.org> | ||||
| M:	Vincent Abriou <vincent.abriou@st.com> | ||||
| L:	dri-devel@lists.freedesktop.org | ||||
| T:	git http://git.linaro.org/people/benjamin.gaignard/kernel.git | ||||
| T:	git git://anongit.freedesktop.org/drm/drm-misc | ||||
| S:	Maintained | ||||
| F:	drivers/gpu/drm/sti | ||||
| F:	Documentation/devicetree/bindings/display/st,stih4xx.txt | ||||
| @@ -13331,7 +13332,7 @@ F:	drivers/virtio/ | ||||
| F:	tools/virtio/ | ||||
| F:	drivers/net/virtio_net.c | ||||
| F:	drivers/block/virtio_blk.c | ||||
| F:	include/linux/virtio_*.h | ||||
| F:	include/linux/virtio*.h | ||||
| F:	include/uapi/linux/virtio_*.h | ||||
| F:	drivers/crypto/virtio/ | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| VERSION = 4 | ||||
| PATCHLEVEL = 11 | ||||
| SUBLEVEL = 0 | ||||
| EXTRAVERSION = -rc6 | ||||
| EXTRAVERSION = -rc7 | ||||
| NAME = Fearless Coyote | ||||
|  | ||||
| # *DOCUMENTATION* | ||||
|   | ||||
| @@ -371,6 +371,8 @@ | ||||
|  | ||||
| 	phy1: ethernet-phy@1 { | ||||
| 		reg = <7>; | ||||
| 		eee-broken-100tx; | ||||
| 		eee-broken-1000t; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -672,6 +672,7 @@ | ||||
| 	ti,non-removable; | ||||
| 	bus-width = <4>; | ||||
| 	cap-power-off-card; | ||||
| 	keep-power-in-suspend; | ||||
| 	pinctrl-names = "default"; | ||||
| 	pinctrl-0 = <&mmc2_pins>; | ||||
|  | ||||
|   | ||||
| @@ -283,6 +283,7 @@ | ||||
| 				device_type = "pci"; | ||||
| 				ranges = <0x81000000 0 0          0x03000 0 0x00010000 | ||||
| 					  0x82000000 0 0x20013000 0x13000 0 0xffed000>; | ||||
| 				bus-range = <0x00 0xff>; | ||||
| 				#interrupt-cells = <1>; | ||||
| 				num-lanes = <1>; | ||||
| 				linux,pci-domain = <0>; | ||||
| @@ -319,6 +320,7 @@ | ||||
| 				device_type = "pci"; | ||||
| 				ranges = <0x81000000 0 0          0x03000 0 0x00010000 | ||||
| 					  0x82000000 0 0x30013000 0x13000 0 0xffed000>; | ||||
| 				bus-range = <0x00 0xff>; | ||||
| 				#interrupt-cells = <1>; | ||||
| 				num-lanes = <1>; | ||||
| 				linux,pci-domain = <1>; | ||||
|   | ||||
| @@ -121,7 +121,7 @@ | ||||
| &i2c3 { | ||||
| 	clock-frequency = <400000>; | ||||
| 	at24@50 { | ||||
| 		compatible = "at24,24c02"; | ||||
| 		compatible = "atmel,24c64"; | ||||
| 		readonly; | ||||
| 		reg = <0x50>; | ||||
| 	}; | ||||
|   | ||||
| @@ -66,12 +66,6 @@ | ||||
| 			opp-microvolt = <1200000>; | ||||
| 			clock-latency-ns = <244144>; /* 8 32k periods */ | ||||
| 		}; | ||||
|  | ||||
| 		opp@1200000000 { | ||||
| 			opp-hz = /bits/ 64 <1200000000>; | ||||
| 			opp-microvolt = <1320000>; | ||||
| 			clock-latency-ns = <244144>; /* 8 32k periods */ | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	cpus { | ||||
| @@ -81,16 +75,22 @@ | ||||
| 			operating-points-v2 = <&cpu0_opp_table>; | ||||
| 		}; | ||||
|  | ||||
| 		cpu@1 { | ||||
| 			operating-points-v2 = <&cpu0_opp_table>; | ||||
| 		}; | ||||
|  | ||||
| 		cpu@2 { | ||||
| 			compatible = "arm,cortex-a7"; | ||||
| 			device_type = "cpu"; | ||||
| 			reg = <2>; | ||||
| 			operating-points-v2 = <&cpu0_opp_table>; | ||||
| 		}; | ||||
|  | ||||
| 		cpu@3 { | ||||
| 			compatible = "arm,cortex-a7"; | ||||
| 			device_type = "cpu"; | ||||
| 			reg = <3>; | ||||
| 			operating-points-v2 = <&cpu0_opp_table>; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -270,6 +270,7 @@ extern const struct smp_operations omap4_smp_ops; | ||||
| extern int omap4_mpuss_init(void); | ||||
| extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); | ||||
| extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state); | ||||
| extern u32 omap4_get_cpu1_ns_pa_addr(void); | ||||
| #else | ||||
| static inline int omap4_enter_lowpower(unsigned int cpu, | ||||
| 					unsigned int power_state) | ||||
|   | ||||
| @@ -50,7 +50,7 @@ void omap4_cpu_die(unsigned int cpu) | ||||
| 		omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF); | ||||
| 
 | ||||
| 		if (omap_secure_apis_support()) | ||||
| 			boot_cpu = omap_read_auxcoreboot0(); | ||||
| 			boot_cpu = omap_read_auxcoreboot0() >> 9; | ||||
| 		else | ||||
| 			boot_cpu = | ||||
| 				readl_relaxed(base + OMAP_AUX_CORE_BOOT_0) >> 5; | ||||
|   | ||||
| @@ -64,6 +64,7 @@ | ||||
| #include "prm-regbits-44xx.h" | ||||
| 
 | ||||
| static void __iomem *sar_base; | ||||
| static u32 old_cpu1_ns_pa_addr; | ||||
| 
 | ||||
| #if defined(CONFIG_PM) && defined(CONFIG_SMP) | ||||
| 
 | ||||
| @@ -212,6 +213,11 @@ static void __init save_l2x0_context(void) | ||||
| {} | ||||
| #endif | ||||
| 
 | ||||
| u32 omap4_get_cpu1_ns_pa_addr(void) | ||||
| { | ||||
| 	return old_cpu1_ns_pa_addr; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function | ||||
|  * The purpose of this function is to manage low power programming | ||||
| @@ -460,22 +466,30 @@ int __init omap4_mpuss_init(void) | ||||
| void __init omap4_mpuss_early_init(void) | ||||
| { | ||||
| 	unsigned long startup_pa; | ||||
| 	void __iomem *ns_pa_addr; | ||||
| 
 | ||||
| 	if (!(cpu_is_omap44xx() || soc_is_omap54xx())) | ||||
| 	if (!(soc_is_omap44xx() || soc_is_omap54xx())) | ||||
| 		return; | ||||
| 
 | ||||
| 	sar_base = omap4_get_sar_ram_base(); | ||||
| 
 | ||||
| 	if (cpu_is_omap443x()) | ||||
| 	/* Save old NS_PA_ADDR for validity checks later on */ | ||||
| 	if (soc_is_omap44xx()) | ||||
| 		ns_pa_addr = sar_base + CPU1_WAKEUP_NS_PA_ADDR_OFFSET; | ||||
| 	else | ||||
| 		ns_pa_addr = sar_base + OMAP5_CPU1_WAKEUP_NS_PA_ADDR_OFFSET; | ||||
| 	old_cpu1_ns_pa_addr = readl_relaxed(ns_pa_addr); | ||||
| 
 | ||||
| 	if (soc_is_omap443x()) | ||||
| 		startup_pa = __pa_symbol(omap4_secondary_startup); | ||||
| 	else if (cpu_is_omap446x()) | ||||
| 	else if (soc_is_omap446x()) | ||||
| 		startup_pa = __pa_symbol(omap4460_secondary_startup); | ||||
| 	else if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE) | ||||
| 		startup_pa = __pa_symbol(omap5_secondary_hyp_startup); | ||||
| 	else | ||||
| 		startup_pa = __pa_symbol(omap5_secondary_startup); | ||||
| 
 | ||||
| 	if (cpu_is_omap44xx()) | ||||
| 	if (soc_is_omap44xx()) | ||||
| 		writel_relaxed(startup_pa, sar_base + | ||||
| 			       CPU1_WAKEUP_NS_PA_ADDR_OFFSET); | ||||
| 	else | ||||
|   | ||||
| @@ -94,6 +94,5 @@ ENTRY(omap_read_auxcoreboot0) | ||||
| 	ldr	r12, =0x103 | ||||
| 	dsb | ||||
| 	smc	#0 | ||||
| 	mov	r0, r0, lsr #9 | ||||
| 	ldmfd   sp!, {r2-r12, pc} | ||||
| ENDPROC(omap_read_auxcoreboot0) | ||||
|   | ||||
| @@ -21,6 +21,7 @@ | ||||
| #include <linux/io.h> | ||||
| #include <linux/irqchip/arm-gic.h> | ||||
| 
 | ||||
| #include <asm/sections.h> | ||||
| #include <asm/smp_scu.h> | ||||
| #include <asm/virt.h> | ||||
| 
 | ||||
| @@ -40,10 +41,14 @@ | ||||
| 
 | ||||
| #define OMAP5_CORE_COUNT	0x2 | ||||
| 
 | ||||
| #define AUX_CORE_BOOT0_GP_RELEASE	0x020 | ||||
| #define AUX_CORE_BOOT0_HS_RELEASE	0x200 | ||||
| 
 | ||||
| struct omap_smp_config { | ||||
| 	unsigned long cpu1_rstctrl_pa; | ||||
| 	void __iomem *cpu1_rstctrl_va; | ||||
| 	void __iomem *scu_base; | ||||
| 	void __iomem *wakeupgen_base; | ||||
| 	void *startup_addr; | ||||
| }; | ||||
| 
 | ||||
| @@ -140,7 +145,6 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||||
| 	static struct clockdomain *cpu1_clkdm; | ||||
| 	static bool booted; | ||||
| 	static struct powerdomain *cpu1_pwrdm; | ||||
| 	void __iomem *base = omap_get_wakeupgen_base(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Set synchronisation state between this boot processor | ||||
| @@ -155,9 +159,11 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||||
| 	 * A barrier is added to ensure that write buffer is drained | ||||
| 	 */ | ||||
| 	if (omap_secure_apis_support()) | ||||
| 		omap_modify_auxcoreboot0(0x200, 0xfffffdff); | ||||
| 		omap_modify_auxcoreboot0(AUX_CORE_BOOT0_HS_RELEASE, | ||||
| 					 0xfffffdff); | ||||
| 	else | ||||
| 		writel_relaxed(0x20, base + OMAP_AUX_CORE_BOOT_0); | ||||
| 		writel_relaxed(AUX_CORE_BOOT0_GP_RELEASE, | ||||
| 			       cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_0); | ||||
| 
 | ||||
| 	if (!cpu1_clkdm && !cpu1_pwrdm) { | ||||
| 		cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); | ||||
| @@ -261,9 +267,72 @@ static void __init omap4_smp_init_cpus(void) | ||||
| 		set_cpu_possible(i, true); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * For now, just make sure the start-up address is not within the booting | ||||
|  * kernel space as that means we just overwrote whatever secondary_startup() | ||||
|  * code there was. | ||||
|  */ | ||||
| static bool __init omap4_smp_cpu1_startup_valid(unsigned long addr) | ||||
| { | ||||
| 	if ((addr >= __pa(PAGE_OFFSET)) && (addr <= __pa(__bss_start))) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * We may need to reset CPU1 before configuring, otherwise kexec boot can end | ||||
|  * up trying to use old kernel startup address or suspend-resume will | ||||
|  * occasionally fail to bring up CPU1 on 4430 if CPU1 fails to enter deeper | ||||
|  * idle states. | ||||
|  */ | ||||
| static void __init omap4_smp_maybe_reset_cpu1(struct omap_smp_config *c) | ||||
| { | ||||
| 	unsigned long cpu1_startup_pa, cpu1_ns_pa_addr; | ||||
| 	bool needs_reset = false; | ||||
| 	u32 released; | ||||
| 
 | ||||
| 	if (omap_secure_apis_support()) | ||||
| 		released = omap_read_auxcoreboot0() & AUX_CORE_BOOT0_HS_RELEASE; | ||||
| 	else | ||||
| 		released = readl_relaxed(cfg.wakeupgen_base + | ||||
| 					 OMAP_AUX_CORE_BOOT_0) & | ||||
| 						AUX_CORE_BOOT0_GP_RELEASE; | ||||
| 	if (released) { | ||||
| 		pr_warn("smp: CPU1 not parked?\n"); | ||||
| 
 | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	cpu1_startup_pa = readl_relaxed(cfg.wakeupgen_base + | ||||
| 					OMAP_AUX_CORE_BOOT_1); | ||||
| 	cpu1_ns_pa_addr = omap4_get_cpu1_ns_pa_addr(); | ||||
| 
 | ||||
| 	/* Did the configured secondary_startup() get overwritten? */ | ||||
| 	if (!omap4_smp_cpu1_startup_valid(cpu1_startup_pa)) | ||||
| 		needs_reset = true; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If omap4 or 5 has NS_PA_ADDR configured, CPU1 may be in a | ||||
| 	 * deeper idle state in WFI and will wake to an invalid address. | ||||
| 	 */ | ||||
| 	if ((soc_is_omap44xx() || soc_is_omap54xx()) && | ||||
| 	    !omap4_smp_cpu1_startup_valid(cpu1_ns_pa_addr)) | ||||
| 		needs_reset = true; | ||||
| 
 | ||||
| 	if (!needs_reset || !c->cpu1_rstctrl_va) | ||||
| 		return; | ||||
| 
 | ||||
| 	pr_info("smp: CPU1 parked within kernel, needs reset (0x%lx 0x%lx)\n", | ||||
| 		cpu1_startup_pa, cpu1_ns_pa_addr); | ||||
| 
 | ||||
| 	writel_relaxed(1, c->cpu1_rstctrl_va); | ||||
| 	readl_relaxed(c->cpu1_rstctrl_va); | ||||
| 	writel_relaxed(0, c->cpu1_rstctrl_va); | ||||
| } | ||||
| 
 | ||||
| static void __init omap4_smp_prepare_cpus(unsigned int max_cpus) | ||||
| { | ||||
| 	void __iomem *base = omap_get_wakeupgen_base(); | ||||
| 	const struct omap_smp_config *c = NULL; | ||||
| 
 | ||||
| 	if (soc_is_omap443x()) | ||||
| @@ -281,6 +350,7 @@ static void __init omap4_smp_prepare_cpus(unsigned int max_cpus) | ||||
| 	/* Must preserve cfg.scu_base set earlier */ | ||||
| 	cfg.cpu1_rstctrl_pa = c->cpu1_rstctrl_pa; | ||||
| 	cfg.startup_addr = c->startup_addr; | ||||
| 	cfg.wakeupgen_base = omap_get_wakeupgen_base(); | ||||
| 
 | ||||
| 	if (soc_is_dra74x() || soc_is_omap54xx()) { | ||||
| 		if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE) | ||||
| @@ -299,15 +369,7 @@ static void __init omap4_smp_prepare_cpus(unsigned int max_cpus) | ||||
| 	if (cfg.scu_base) | ||||
| 		scu_enable(cfg.scu_base); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Reset CPU1 before configuring, otherwise kexec will | ||||
| 	 * end up trying to use old kernel startup address. | ||||
| 	 */ | ||||
| 	if (cfg.cpu1_rstctrl_va) { | ||||
| 		writel_relaxed(1, cfg.cpu1_rstctrl_va); | ||||
| 		readl_relaxed(cfg.cpu1_rstctrl_va); | ||||
| 		writel_relaxed(0, cfg.cpu1_rstctrl_va); | ||||
| 	} | ||||
| 	omap4_smp_maybe_reset_cpu1(&cfg); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Write the address of secondary startup routine into the | ||||
| @@ -319,7 +381,7 @@ static void __init omap4_smp_prepare_cpus(unsigned int max_cpus) | ||||
| 		omap_auxcoreboot_addr(__pa_symbol(cfg.startup_addr)); | ||||
| 	else | ||||
| 		writel_relaxed(__pa_symbol(cfg.startup_addr), | ||||
| 			       base + OMAP_AUX_CORE_BOOT_1); | ||||
| 			       cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_1); | ||||
| } | ||||
| 
 | ||||
| const struct smp_operations omap4_smp_ops __initconst = { | ||||
|   | ||||
| @@ -222,6 +222,14 @@ static int _omap_device_notifier_call(struct notifier_block *nb, | ||||
| 				dev_err(dev, "failed to idle\n"); | ||||
| 		} | ||||
| 		break; | ||||
| 	case BUS_NOTIFY_BIND_DRIVER: | ||||
| 		od = to_omap_device(pdev); | ||||
| 		if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED) && | ||||
| 		    pm_runtime_status_suspended(dev)) { | ||||
| 			od->_driver_status = BUS_NOTIFY_BIND_DRIVER; | ||||
| 			pm_runtime_set_active(dev); | ||||
| 		} | ||||
| 		break; | ||||
| 	case BUS_NOTIFY_ADD_DEVICE: | ||||
| 		if (pdev->dev.of_node) | ||||
| 			omap_device_build_from_dt(pdev); | ||||
|   | ||||
| @@ -6,6 +6,7 @@ menuconfig ARCH_ORION5X | ||||
| 	select GPIOLIB | ||||
| 	select MVEBU_MBUS | ||||
| 	select PCI | ||||
| 	select PHYLIB if NETDEVICES | ||||
| 	select PLAT_ORION_LEGACY | ||||
| 	help | ||||
| 	  Support for the following Marvell Orion 5x series SoCs: | ||||
|   | ||||
| @@ -468,6 +468,7 @@ void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, | ||||
| 		    eth_data, &orion_ge11); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_ARCH_ORION5X | ||||
| /*****************************************************************************
 | ||||
|  * Ethernet switch | ||||
|  ****************************************************************************/ | ||||
| @@ -480,6 +481,9 @@ void __init orion_ge00_switch_init(struct dsa_chip_data *d) | ||||
| 	struct mdio_board_info *bd; | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	if (!IS_BUILTIN(CONFIG_PHYLIB)) | ||||
| 		return; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(d->port_names); i++) | ||||
| 		if (!strcmp(d->port_names[i], "cpu")) | ||||
| 			break; | ||||
| @@ -493,6 +497,7 @@ void __init orion_ge00_switch_init(struct dsa_chip_data *d) | ||||
| 
 | ||||
| 	mdiobus_register_board_info(&orion_ge00_switch_board_info, 1); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  * I2C | ||||
|   | ||||
| @@ -179,8 +179,10 @@ | ||||
| 		usbphy: phy@01c19400 { | ||||
| 			compatible = "allwinner,sun50i-a64-usb-phy"; | ||||
| 			reg = <0x01c19400 0x14>, | ||||
| 			      <0x01c1a800 0x4>, | ||||
| 			      <0x01c1b800 0x4>; | ||||
| 			reg-names = "phy_ctrl", | ||||
| 				    "pmu0", | ||||
| 				    "pmu1"; | ||||
| 			clocks = <&ccu CLK_USB_PHY0>, | ||||
| 				 <&ccu CLK_USB_PHY1>; | ||||
|   | ||||
							
								
								
									
										29
									
								
								arch/ia64/include/asm/asm-prototypes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								arch/ia64/include/asm/asm-prototypes.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #ifndef _ASM_IA64_ASM_PROTOTYPES_H | ||||
| #define _ASM_IA64_ASM_PROTOTYPES_H | ||||
| 
 | ||||
| #include <asm/cacheflush.h> | ||||
| #include <asm/checksum.h> | ||||
| #include <asm/esi.h> | ||||
| #include <asm/ftrace.h> | ||||
| #include <asm/page.h> | ||||
| #include <asm/pal.h> | ||||
| #include <asm/string.h> | ||||
| #include <asm/uaccess.h> | ||||
| #include <asm/unwind.h> | ||||
| #include <asm/xor.h> | ||||
| 
 | ||||
| extern const char ia64_ivt[]; | ||||
| 
 | ||||
| signed int __divsi3(signed int, unsigned int); | ||||
| signed int __modsi3(signed int, unsigned int); | ||||
| 
 | ||||
| signed long long __divdi3(signed long long, unsigned long long); | ||||
| signed long long __moddi3(signed long long, unsigned long long); | ||||
| 
 | ||||
| unsigned int __udivsi3(unsigned int, unsigned int); | ||||
| unsigned int __umodsi3(unsigned int, unsigned int); | ||||
| 
 | ||||
| unsigned long long __udivdi3(unsigned long long, unsigned long long); | ||||
| unsigned long long __umoddi3(unsigned long long, unsigned long long); | ||||
| 
 | ||||
| #endif /* _ASM_IA64_ASM_PROTOTYPES_H */ | ||||
| @@ -24,25 +24,25 @@ AFLAGS___modsi3.o	=	     -DMODULO | ||||
| AFLAGS___umodsi3.o	= -DUNSIGNED -DMODULO | ||||
|  | ||||
| $(obj)/__divdi3.o: $(src)/idiv64.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|  | ||||
| $(obj)/__udivdi3.o: $(src)/idiv64.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|  | ||||
| $(obj)/__moddi3.o: $(src)/idiv64.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|  | ||||
| $(obj)/__umoddi3.o: $(src)/idiv64.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|  | ||||
| $(obj)/__divsi3.o: $(src)/idiv32.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|  | ||||
| $(obj)/__udivsi3.o: $(src)/idiv32.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|  | ||||
| $(obj)/__modsi3.o: $(src)/idiv32.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|  | ||||
| $(obj)/__umodsi3.o: $(src)/idiv32.S FORCE | ||||
| 	$(call if_changed_dep,as_o_S) | ||||
| 	$(call if_changed_rule,as_o_S) | ||||
|   | ||||
| @@ -201,7 +201,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	add	dst,len,end | ||||
|  | ||||
| 	/* short copy with less than 16 bytes? */ | ||||
| 	cmpib,>>=,n 15,len,.Lbyte_loop | ||||
| 	cmpib,COND(>>=),n 15,len,.Lbyte_loop | ||||
|  | ||||
| 	/* same alignment? */ | ||||
| 	xor	src,dst,t0 | ||||
| @@ -216,7 +216,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	/* loop until we are 64-bit aligned */ | ||||
| .Lalign_loop64: | ||||
| 	extru	dst,31,3,t1 | ||||
| 	cmpib,=,n	0,t1,.Lcopy_loop_16 | ||||
| 	cmpib,=,n	0,t1,.Lcopy_loop_16_start | ||||
| 20:	ldb,ma	1(srcspc,src),t1 | ||||
| 21:	stb,ma	t1,1(dstspc,dst) | ||||
| 	b	.Lalign_loop64 | ||||
| @@ -225,6 +225,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done) | ||||
|  | ||||
| .Lcopy_loop_16_start: | ||||
| 	ldi	31,t0 | ||||
| .Lcopy_loop_16: | ||||
| 	cmpb,COND(>>=),n t0,len,.Lword_loop | ||||
| @@ -267,7 +268,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	/* loop until we are 32-bit aligned */ | ||||
| .Lalign_loop32: | ||||
| 	extru	dst,31,2,t1 | ||||
| 	cmpib,=,n	0,t1,.Lcopy_loop_4 | ||||
| 	cmpib,=,n	0,t1,.Lcopy_loop_8 | ||||
| 20:	ldb,ma	1(srcspc,src),t1 | ||||
| 21:	stb,ma	t1,1(dstspc,dst) | ||||
| 	b	.Lalign_loop32 | ||||
| @@ -277,7 +278,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done) | ||||
|  | ||||
|  | ||||
| .Lcopy_loop_4: | ||||
| .Lcopy_loop_8: | ||||
| 	cmpib,COND(>>=),n 15,len,.Lbyte_loop | ||||
|  | ||||
| 10:	ldw	0(srcspc,src),t1 | ||||
| @@ -299,7 +300,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done) | ||||
|  | ||||
| 	b	.Lcopy_loop_4 | ||||
| 	b	.Lcopy_loop_8 | ||||
| 	ldo	-16(len),len | ||||
|  | ||||
| .Lbyte_loop: | ||||
| @@ -324,7 +325,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| .Lunaligned_copy: | ||||
| 	/* align until dst is 32bit-word-aligned */ | ||||
| 	extru	dst,31,2,t1 | ||||
| 	cmpib,COND(=),n	0,t1,.Lcopy_dstaligned | ||||
| 	cmpib,=,n	0,t1,.Lcopy_dstaligned | ||||
| 20:	ldb	0(srcspc,src),t1 | ||||
| 	ldo	1(src),src | ||||
| 21:	stb,ma	t1,1(dstspc,dst) | ||||
| @@ -362,7 +363,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	cmpiclr,<> 1,t0,%r0 | ||||
| 	b,n .Lcase1 | ||||
| .Lcase0: | ||||
| 	cmpb,= %r0,len,.Lcda_finish | ||||
| 	cmpb,COND(=) %r0,len,.Lcda_finish | ||||
| 	nop | ||||
|  | ||||
| 1:	ldw,ma 4(srcspc,src), a3 | ||||
| @@ -376,7 +377,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 1:	ldw,ma 4(srcspc,src), a3 | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault) | ||||
| 	ldo -1(len),len | ||||
| 	cmpb,=,n %r0,len,.Ldo0 | ||||
| 	cmpb,COND(=),n %r0,len,.Ldo0 | ||||
| .Ldo4: | ||||
| 1:	ldw,ma 4(srcspc,src), a0 | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault) | ||||
| @@ -402,7 +403,7 @@ ENTRY_CFI(pa_memcpy) | ||||
| 1:	stw,ma t0, 4(dstspc,dst) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done) | ||||
| 	ldo -4(len),len | ||||
| 	cmpb,<> %r0,len,.Ldo4 | ||||
| 	cmpb,COND(<>) %r0,len,.Ldo4 | ||||
| 	nop | ||||
| .Ldo0: | ||||
| 	shrpw a2, a3, %sar, t0 | ||||
| @@ -436,14 +437,14 @@ ENTRY_CFI(pa_memcpy) | ||||
| 	/* fault exception fixup handlers: */ | ||||
| #ifdef CONFIG_64BIT | ||||
| .Lcopy16_fault: | ||||
| 10:	b	.Lcopy_done | ||||
| 	std,ma	t1,8(dstspc,dst) | ||||
| 	b	.Lcopy_done | ||||
| 10:	std,ma	t1,8(dstspc,dst) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done) | ||||
| #endif | ||||
|  | ||||
| .Lcopy8_fault: | ||||
| 10:	b	.Lcopy_done | ||||
| 	stw,ma	t1,4(dstspc,dst) | ||||
| 	b	.Lcopy_done | ||||
| 10:	stw,ma	t1,4(dstspc,dst) | ||||
| 	ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done) | ||||
|  | ||||
| 	.exit | ||||
|   | ||||
| @@ -30,8 +30,10 @@ static int __init vdso32_setup(char *s) | ||||
| { | ||||
| 	vdso32_enabled = simple_strtoul(s, NULL, 0); | ||||
| 
 | ||||
| 	if (vdso32_enabled > 1) | ||||
| 	if (vdso32_enabled > 1) { | ||||
| 		pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n"); | ||||
| 		vdso32_enabled = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| @@ -62,13 +64,18 @@ subsys_initcall(sysenter_setup); | ||||
| /* Register vsyscall32 into the ABI table */ | ||||
| #include <linux/sysctl.h> | ||||
| 
 | ||||
| static const int zero; | ||||
| static const int one = 1; | ||||
| 
 | ||||
| static struct ctl_table abi_table2[] = { | ||||
| 	{ | ||||
| 		.procname	= "vsyscall32", | ||||
| 		.data		= &vdso32_enabled, | ||||
| 		.maxlen		= sizeof(int), | ||||
| 		.mode		= 0644, | ||||
| 		.proc_handler	= proc_dointvec | ||||
| 		.proc_handler	= proc_dointvec_minmax, | ||||
| 		.extra1		= (int *)&zero, | ||||
| 		.extra2		= (int *)&one, | ||||
| 	}, | ||||
| 	{} | ||||
| }; | ||||
|   | ||||
| @@ -507,6 +507,9 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) | ||||
| 		cpuc->lbr_entries[i].to		= msr_lastbranch.to; | ||||
| 		cpuc->lbr_entries[i].mispred	= 0; | ||||
| 		cpuc->lbr_entries[i].predicted	= 0; | ||||
| 		cpuc->lbr_entries[i].in_tx	= 0; | ||||
| 		cpuc->lbr_entries[i].abort	= 0; | ||||
| 		cpuc->lbr_entries[i].cycles	= 0; | ||||
| 		cpuc->lbr_entries[i].reserved	= 0; | ||||
| 	} | ||||
| 	cpuc->lbr_stack.nr = i; | ||||
|   | ||||
| @@ -287,7 +287,7 @@ struct task_struct; | ||||
| 
 | ||||
| #define	ARCH_DLINFO_IA32						\ | ||||
| do {									\ | ||||
| 	if (vdso32_enabled) {						\ | ||||
| 	if (VDSO_CURRENT_BASE) {					\ | ||||
| 		NEW_AUX_ENT(AT_SYSINFO,	VDSO_ENTRY);			\ | ||||
| 		NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE);	\ | ||||
| 	}								\ | ||||
|   | ||||
| @@ -55,7 +55,8 @@ static inline int arch_memcpy_from_pmem(void *dst, const void *src, size_t n) | ||||
|  * @size:	number of bytes to write back | ||||
|  * | ||||
|  * Write back a cache range using the CLWB (cache line write back) | ||||
|  * instruction. | ||||
|  * instruction. Note that @size is internally rounded up to be cache | ||||
|  * line size aligned. | ||||
|  */ | ||||
| static inline void arch_wb_cache_pmem(void *addr, size_t size) | ||||
| { | ||||
| @@ -69,15 +70,6 @@ static inline void arch_wb_cache_pmem(void *addr, size_t size) | ||||
| 		clwb(p); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * copy_from_iter_nocache() on x86 only uses non-temporal stores for iovec | ||||
|  * iterators, so for other types (bvec & kvec) we must do a cache write-back. | ||||
|  */ | ||||
| static inline bool __iter_needs_pmem_wb(struct iov_iter *i) | ||||
| { | ||||
| 	return iter_is_iovec(i) == false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * arch_copy_from_iter_pmem - copy data from an iterator to PMEM | ||||
|  * @addr:	PMEM destination address | ||||
| @@ -94,7 +86,35 @@ static inline size_t arch_copy_from_iter_pmem(void *addr, size_t bytes, | ||||
| 	/* TODO: skip the write-back by always using non-temporal stores */ | ||||
| 	len = copy_from_iter_nocache(addr, bytes, i); | ||||
| 
 | ||||
| 	if (__iter_needs_pmem_wb(i)) | ||||
| 	/*
 | ||||
| 	 * In the iovec case on x86_64 copy_from_iter_nocache() uses | ||||
| 	 * non-temporal stores for the bulk of the transfer, but we need | ||||
| 	 * to manually flush if the transfer is unaligned. A cached | ||||
| 	 * memory copy is used when destination or size is not naturally | ||||
| 	 * aligned. That is: | ||||
| 	 *   - Require 8-byte alignment when size is 8 bytes or larger. | ||||
| 	 *   - Require 4-byte alignment when size is 4 bytes. | ||||
| 	 * | ||||
| 	 * In the non-iovec case the entire destination needs to be | ||||
| 	 * flushed. | ||||
| 	 */ | ||||
| 	if (iter_is_iovec(i)) { | ||||
| 		unsigned long flushed, dest = (unsigned long) addr; | ||||
| 
 | ||||
| 		if (bytes < 8) { | ||||
| 			if (!IS_ALIGNED(dest, 4) || (bytes != 4)) | ||||
| 				arch_wb_cache_pmem(addr, 1); | ||||
| 		} else { | ||||
| 			if (!IS_ALIGNED(dest, 8)) { | ||||
| 				dest = ALIGN(dest, boot_cpu_data.x86_clflush_size); | ||||
| 				arch_wb_cache_pmem(addr, 1); | ||||
| 			} | ||||
| 
 | ||||
| 			flushed = dest - (unsigned long) addr; | ||||
| 			if (bytes > flushed && !IS_ALIGNED(bytes - flushed, 8)) | ||||
| 				arch_wb_cache_pmem(addr + bytes - 1, 1); | ||||
| 		} | ||||
| 	} else | ||||
| 		arch_wb_cache_pmem(addr, bytes); | ||||
| 
 | ||||
| 	return len; | ||||
|   | ||||
| @@ -200,11 +200,11 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of, | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	rdtgroup_kn_unlock(of->kn); | ||||
| 	for_each_enabled_rdt_resource(r) { | ||||
| 		kfree(r->tmp_cbms); | ||||
| 		r->tmp_cbms = NULL; | ||||
| 	} | ||||
| 	rdtgroup_kn_unlock(of->kn); | ||||
| 	return ret ?: nbytes; | ||||
| } | ||||
| 
 | ||||
|   | ||||
| @@ -846,7 +846,7 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where) | ||||
| 		       task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG, | ||||
| 		       me->comm, me->pid, where, frame, | ||||
| 		       regs->ip, regs->sp, regs->orig_ax); | ||||
| 		print_vma_addr(" in ", regs->ip); | ||||
| 		print_vma_addr(KERN_CONT " in ", regs->ip); | ||||
| 		pr_cont("\n"); | ||||
| 	} | ||||
| 
 | ||||
|   | ||||
| @@ -151,8 +151,8 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from, | ||||
| 
 | ||||
| 				if (from->si_signo == SIGSEGV) { | ||||
| 					if (from->si_code == SEGV_BNDERR) { | ||||
| 						compat_uptr_t lower = (unsigned long)&to->si_lower; | ||||
| 						compat_uptr_t upper = (unsigned long)&to->si_upper; | ||||
| 						compat_uptr_t lower = (unsigned long)from->si_lower; | ||||
| 						compat_uptr_t upper = (unsigned long)from->si_upper; | ||||
| 						put_user_ex(lower, &to->si_lower); | ||||
| 						put_user_ex(upper, &to->si_upper); | ||||
| 					} | ||||
|   | ||||
| @@ -255,7 +255,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | ||||
| 		pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx", | ||||
| 			tsk->comm, tsk->pid, str, | ||||
| 			regs->ip, regs->sp, error_code); | ||||
| 		print_vma_addr(" in ", regs->ip); | ||||
| 		print_vma_addr(KERN_CONT " in ", regs->ip); | ||||
| 		pr_cont("\n"); | ||||
| 	} | ||||
| 
 | ||||
| @@ -519,7 +519,7 @@ do_general_protection(struct pt_regs *regs, long error_code) | ||||
| 		pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx", | ||||
| 			tsk->comm, task_pid_nr(tsk), | ||||
| 			regs->ip, regs->sp, error_code); | ||||
| 		print_vma_addr(" in ", regs->ip); | ||||
| 		print_vma_addr(KERN_CONT " in ", regs->ip); | ||||
| 		pr_cont("\n"); | ||||
| 	} | ||||
| 
 | ||||
|   | ||||
| @@ -643,21 +643,40 @@ void __init init_mem_mapping(void) | ||||
|  * devmem_is_allowed() checks to see if /dev/mem access to a certain address | ||||
|  * is valid. The argument is a physical page number. | ||||
|  * | ||||
|  * | ||||
|  * On x86, access has to be given to the first megabyte of ram because that area | ||||
|  * contains BIOS code and data regions used by X and dosemu and similar apps. | ||||
|  * Access has to be given to non-kernel-ram areas as well, these contain the PCI | ||||
|  * mmio resources as well as potential bios/acpi data regions. | ||||
|  * On x86, access has to be given to the first megabyte of RAM because that | ||||
|  * area traditionally contains BIOS code and data regions used by X, dosemu, | ||||
|  * and similar apps. Since they map the entire memory range, the whole range | ||||
|  * must be allowed (for mapping), but any areas that would otherwise be | ||||
|  * disallowed are flagged as being "zero filled" instead of rejected. | ||||
|  * Access has to be given to non-kernel-ram areas as well, these contain the | ||||
|  * PCI mmio resources as well as potential bios/acpi data regions. | ||||
|  */ | ||||
| int devmem_is_allowed(unsigned long pagenr) | ||||
| { | ||||
| 	if (pagenr < 256) | ||||
| 		return 1; | ||||
| 	if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) | ||||
| 	if (page_is_ram(pagenr)) { | ||||
| 		/*
 | ||||
| 		 * For disallowed memory regions in the low 1MB range, | ||||
| 		 * request that the page be shown as all zeros. | ||||
| 		 */ | ||||
| 		if (pagenr < 256) | ||||
| 			return 2; | ||||
| 
 | ||||
| 		return 0; | ||||
| 	if (!page_is_ram(pagenr)) | ||||
| 		return 1; | ||||
| 	return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This must follow RAM test, since System RAM is considered a | ||||
| 	 * restricted resource under CONFIG_STRICT_IOMEM. | ||||
| 	 */ | ||||
| 	if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) { | ||||
| 		/* Low 1MB bypasses iomem restrictions. */ | ||||
| 		if (pagenr < 256) | ||||
| 			return 1; | ||||
| 
 | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| void free_init_pages(char *what, unsigned long begin, unsigned long end) | ||||
|   | ||||
| @@ -201,6 +201,10 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* No need to reserve regions that will never be freed. */ | ||||
| 	if (md.attribute & EFI_MEMORY_RUNTIME) | ||||
| 		return; | ||||
| 
 | ||||
| 	size += addr % EFI_PAGE_SIZE; | ||||
| 	size = round_up(size, EFI_PAGE_SIZE); | ||||
| 	addr = round_down(addr, EFI_PAGE_SIZE); | ||||
|   | ||||
| @@ -421,10 +421,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, | ||||
| 
 | ||||
| 	ACPI_FUNCTION_TRACE(ut_walk_aml_resources); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The absolute minimum resource template is one end_tag descriptor. | ||||
| 	 * However, we will treat a lone end_tag as just a simple buffer. | ||||
| 	 */ | ||||
| 	/* The absolute minimum resource template is one end_tag descriptor */ | ||||
| 
 | ||||
| 	if (aml_length < sizeof(struct aml_resource_end_tag)) { | ||||
| 		return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); | ||||
| 	} | ||||
| @@ -456,8 +454,9 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, | ||||
| 		/* Invoke the user function */ | ||||
| 
 | ||||
| 		if (user_function) { | ||||
| 			status = user_function(aml, length, offset, | ||||
| 					       resource_index, context); | ||||
| 			status = | ||||
| 			    user_function(aml, length, offset, resource_index, | ||||
| 					  context); | ||||
| 			if (ACPI_FAILURE(status)) { | ||||
| 				return_ACPI_STATUS(status); | ||||
| 			} | ||||
| @@ -481,12 +480,6 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, | ||||
| 				*context = aml; | ||||
| 			} | ||||
| 
 | ||||
| 			/* Check if buffer is defined to be longer than the resource length */ | ||||
| 
 | ||||
| 			if (aml_length > (offset + length)) { | ||||
| 				return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); | ||||
| 			} | ||||
| 
 | ||||
| 			/* Normal exit */ | ||||
| 
 | ||||
| 			return_ACPI_STATUS(AE_OK); | ||||
|   | ||||
| @@ -1617,7 +1617,11 @@ static int cmp_map(const void *m0, const void *m1) | ||||
| 	const struct nfit_set_info_map *map0 = m0; | ||||
| 	const struct nfit_set_info_map *map1 = m1; | ||||
| 
 | ||||
| 	return map0->region_offset - map1->region_offset; | ||||
| 	if (map0->region_offset < map1->region_offset) | ||||
| 		return -1; | ||||
| 	else if (map0->region_offset > map1->region_offset) | ||||
| 		return 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Retrieve the nth entry referencing this spa */ | ||||
|   | ||||
| @@ -1857,15 +1857,20 @@ static void acpi_bus_attach(struct acpi_device *device) | ||||
| 		return; | ||||
| 
 | ||||
| 	device->flags.match_driver = true; | ||||
| 	if (!ret) { | ||||
| 		ret = device_attach(&device->dev); | ||||
| 		if (ret < 0) | ||||
| 			return; | ||||
| 
 | ||||
| 		if (!ret && device->pnp.type.platform_id) | ||||
| 			acpi_default_enumeration(device); | ||||
| 	if (ret > 0) { | ||||
| 		acpi_device_set_enumerated(device); | ||||
| 		goto ok; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = device_attach(&device->dev); | ||||
| 	if (ret < 0) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (ret > 0 || !device->pnp.type.platform_id) | ||||
| 		acpi_device_set_enumerated(device); | ||||
| 	else | ||||
| 		acpi_default_enumeration(device); | ||||
| 
 | ||||
|  ok: | ||||
| 	list_for_each_entry(child, &device->children, node) | ||||
| 		acpi_bus_attach(child); | ||||
|   | ||||
| @@ -278,11 +278,6 @@ static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | ||||
| 	}; | ||||
| 	const struct ata_port_info *ppi[] = { &info, &info }; | ||||
| 
 | ||||
| 	/* SB600/700 don't have secondary port wired */ | ||||
| 	if ((pdev->device == PCI_DEVICE_ID_ATI_IXP600_IDE) || | ||||
| 		(pdev->device == PCI_DEVICE_ID_ATI_IXP700_IDE)) | ||||
| 		ppi[1] = &ata_dummy_port_info; | ||||
| 
 | ||||
| 	return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL, | ||||
| 				      ATA_HOST_PARALLEL_SCAN); | ||||
| } | ||||
|   | ||||
| @@ -644,14 +644,16 @@ static void svia_configure(struct pci_dev *pdev, int board_id, | ||||
| 		pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); | ||||
| 	} | ||||
| 
 | ||||
| 	/* enable IRQ on hotplug */ | ||||
| 	pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8); | ||||
| 	if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) { | ||||
| 		dev_dbg(&pdev->dev, | ||||
| 			"enabling SATA hotplug (0x%x)\n", | ||||
| 			(int) tmp8); | ||||
| 		tmp8 |= SATA_HOTPLUG; | ||||
| 		pci_write_config_byte(pdev, SVIA_MISC_3, tmp8); | ||||
| 	if (board_id == vt6421) { | ||||
| 		/* enable IRQ on hotplug */ | ||||
| 		pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8); | ||||
| 		if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) { | ||||
| 			dev_dbg(&pdev->dev, | ||||
| 				"enabling SATA hotplug (0x%x)\n", | ||||
| 				(int) tmp8); | ||||
| 			tmp8 |= SATA_HOTPLUG; | ||||
| 			pci_write_config_byte(pdev, SVIA_MISC_3, tmp8); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
|   | ||||
| @@ -523,7 +523,7 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index) | ||||
| 
 | ||||
| 	cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO); | ||||
| 	if (size == PAGE_SIZE) { | ||||
| 		copy_page(mem, cmem); | ||||
| 		memcpy(mem, cmem, PAGE_SIZE); | ||||
| 	} else { | ||||
| 		struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp); | ||||
| 
 | ||||
| @@ -717,7 +717,7 @@ compress_again: | ||||
| 
 | ||||
| 	if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) { | ||||
| 		src = kmap_atomic(page); | ||||
| 		copy_page(cmem, src); | ||||
| 		memcpy(cmem, src, PAGE_SIZE); | ||||
| 		kunmap_atomic(src); | ||||
| 	} else { | ||||
| 		memcpy(cmem, src, clen); | ||||
| @@ -928,7 +928,7 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector, | ||||
| 	} | ||||
| 
 | ||||
| 	index = sector >> SECTORS_PER_PAGE_SHIFT; | ||||
| 	offset = sector & (SECTORS_PER_PAGE - 1) << SECTOR_SHIFT; | ||||
| 	offset = (sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; | ||||
| 
 | ||||
| 	bv.bv_page = page; | ||||
| 	bv.bv_len = PAGE_SIZE; | ||||
|   | ||||
| @@ -60,6 +60,10 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_STRICT_DEVMEM | ||||
| static inline int page_is_allowed(unsigned long pfn) | ||||
| { | ||||
| 	return devmem_is_allowed(pfn); | ||||
| } | ||||
| static inline int range_is_allowed(unsigned long pfn, unsigned long size) | ||||
| { | ||||
| 	u64 from = ((u64)pfn) << PAGE_SHIFT; | ||||
| @@ -75,6 +79,10 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) | ||||
| 	return 1; | ||||
| } | ||||
| #else | ||||
| static inline int page_is_allowed(unsigned long pfn) | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
| static inline int range_is_allowed(unsigned long pfn, unsigned long size) | ||||
| { | ||||
| 	return 1; | ||||
| @@ -122,23 +130,31 @@ static ssize_t read_mem(struct file *file, char __user *buf, | ||||
| 
 | ||||
| 	while (count > 0) { | ||||
| 		unsigned long remaining; | ||||
| 		int allowed; | ||||
| 
 | ||||
| 		sz = size_inside_page(p, count); | ||||
| 
 | ||||
| 		if (!range_is_allowed(p >> PAGE_SHIFT, count)) | ||||
| 		allowed = page_is_allowed(p >> PAGE_SHIFT); | ||||
| 		if (!allowed) | ||||
| 			return -EPERM; | ||||
| 		if (allowed == 2) { | ||||
| 			/* Show zeros for restricted memory. */ | ||||
| 			remaining = clear_user(buf, sz); | ||||
| 		} else { | ||||
| 			/*
 | ||||
| 			 * On ia64 if a page has been mapped somewhere as | ||||
| 			 * uncached, then it must also be accessed uncached | ||||
| 			 * by the kernel or data corruption may occur. | ||||
| 			 */ | ||||
| 			ptr = xlate_dev_mem_ptr(p); | ||||
| 			if (!ptr) | ||||
| 				return -EFAULT; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * On ia64 if a page has been mapped somewhere as uncached, then | ||||
| 		 * it must also be accessed uncached by the kernel or data | ||||
| 		 * corruption may occur. | ||||
| 		 */ | ||||
| 		ptr = xlate_dev_mem_ptr(p); | ||||
| 		if (!ptr) | ||||
| 			return -EFAULT; | ||||
| 			remaining = copy_to_user(buf, ptr, sz); | ||||
| 
 | ||||
| 			unxlate_dev_mem_ptr(p, ptr); | ||||
| 		} | ||||
| 
 | ||||
| 		remaining = copy_to_user(buf, ptr, sz); | ||||
| 		unxlate_dev_mem_ptr(p, ptr); | ||||
| 		if (remaining) | ||||
| 			return -EFAULT; | ||||
| 
 | ||||
| @@ -181,30 +197,36 @@ static ssize_t write_mem(struct file *file, const char __user *buf, | ||||
| #endif | ||||
| 
 | ||||
| 	while (count > 0) { | ||||
| 		int allowed; | ||||
| 
 | ||||
| 		sz = size_inside_page(p, count); | ||||
| 
 | ||||
| 		if (!range_is_allowed(p >> PAGE_SHIFT, sz)) | ||||
| 		allowed = page_is_allowed(p >> PAGE_SHIFT); | ||||
| 		if (!allowed) | ||||
| 			return -EPERM; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * On ia64 if a page has been mapped somewhere as uncached, then | ||||
| 		 * it must also be accessed uncached by the kernel or data | ||||
| 		 * corruption may occur. | ||||
| 		 */ | ||||
| 		ptr = xlate_dev_mem_ptr(p); | ||||
| 		if (!ptr) { | ||||
| 			if (written) | ||||
| 				break; | ||||
| 			return -EFAULT; | ||||
| 		} | ||||
| 		/* Skip actual writing when a page is marked as restricted. */ | ||||
| 		if (allowed == 1) { | ||||
| 			/*
 | ||||
| 			 * On ia64 if a page has been mapped somewhere as | ||||
| 			 * uncached, then it must also be accessed uncached | ||||
| 			 * by the kernel or data corruption may occur. | ||||
| 			 */ | ||||
| 			ptr = xlate_dev_mem_ptr(p); | ||||
| 			if (!ptr) { | ||||
| 				if (written) | ||||
| 					break; | ||||
| 				return -EFAULT; | ||||
| 			} | ||||
| 
 | ||||
| 		copied = copy_from_user(ptr, buf, sz); | ||||
| 		unxlate_dev_mem_ptr(p, ptr); | ||||
| 		if (copied) { | ||||
| 			written += sz - copied; | ||||
| 			if (written) | ||||
| 				break; | ||||
| 			return -EFAULT; | ||||
| 			copied = copy_from_user(ptr, buf, sz); | ||||
| 			unxlate_dev_mem_ptr(p, ptr); | ||||
| 			if (copied) { | ||||
| 				written += sz - copied; | ||||
| 				if (written) | ||||
| 					break; | ||||
| 				return -EFAULT; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		buf += sz; | ||||
|   | ||||
| @@ -2202,14 +2202,16 @@ static int virtcons_freeze(struct virtio_device *vdev) | ||||
| 
 | ||||
| 	vdev->config->reset(vdev); | ||||
| 
 | ||||
| 	virtqueue_disable_cb(portdev->c_ivq); | ||||
| 	if (use_multiport(portdev)) | ||||
| 		virtqueue_disable_cb(portdev->c_ivq); | ||||
| 	cancel_work_sync(&portdev->control_work); | ||||
| 	cancel_work_sync(&portdev->config_work); | ||||
| 	/*
 | ||||
| 	 * Once more: if control_work_handler() was running, it would | ||||
| 	 * enable the cb as the last step. | ||||
| 	 */ | ||||
| 	virtqueue_disable_cb(portdev->c_ivq); | ||||
| 	if (use_multiport(portdev)) | ||||
| 		virtqueue_disable_cb(portdev->c_ivq); | ||||
| 	remove_controlq_data(portdev); | ||||
| 
 | ||||
| 	list_for_each_entry(port, &portdev->ports, list) { | ||||
|   | ||||
| @@ -2398,6 +2398,20 @@ EXPORT_SYMBOL_GPL(cpufreq_boost_enabled); | ||||
|  *********************************************************************/ | ||||
| static enum cpuhp_state hp_online; | ||||
| 
 | ||||
| static int cpuhp_cpufreq_online(unsigned int cpu) | ||||
| { | ||||
| 	cpufreq_online(cpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int cpuhp_cpufreq_offline(unsigned int cpu) | ||||
| { | ||||
| 	cpufreq_offline(cpu); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * cpufreq_register_driver - register a CPU Frequency driver | ||||
|  * @driver_data: A struct cpufreq_driver containing the values# | ||||
| @@ -2460,8 +2474,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) | ||||
| 	} | ||||
| 
 | ||||
| 	ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "cpufreq:online", | ||||
| 					cpufreq_online, | ||||
| 					cpufreq_offline); | ||||
| 					cpuhp_cpufreq_online, | ||||
| 					cpuhp_cpufreq_offline); | ||||
| 	if (ret < 0) | ||||
| 		goto err_if_unreg; | ||||
| 	hp_online = ret; | ||||
|   | ||||
| @@ -506,7 +506,7 @@ static int caam_rsa_init_tfm(struct crypto_akcipher *tfm) | ||||
| 	ctx->dev = caam_jr_alloc(); | ||||
| 
 | ||||
| 	if (IS_ERR(ctx->dev)) { | ||||
| 		dev_err(ctx->dev, "Job Ring Device allocation for transform failed\n"); | ||||
| 		pr_err("Job Ring Device allocation for transform failed\n"); | ||||
| 		return PTR_ERR(ctx->dev); | ||||
| 	} | ||||
| 
 | ||||
|   | ||||
| @@ -281,7 +281,8 @@ static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask) | ||||
| 			/* Try to run it through DECO0 */ | ||||
| 			ret = run_descriptor_deco0(ctrldev, desc, &status); | ||||
| 
 | ||||
| 			if (ret || status) { | ||||
| 			if (ret || | ||||
| 			    (status && status != JRSTA_SSRC_JUMP_HALT_CC)) { | ||||
| 				dev_err(ctrldev, | ||||
| 					"Failed to deinstantiate RNG4 SH%d\n", | ||||
| 					sh_idx); | ||||
| @@ -301,15 +302,13 @@ static int caam_remove(struct platform_device *pdev) | ||||
| 	struct device *ctrldev; | ||||
| 	struct caam_drv_private *ctrlpriv; | ||||
| 	struct caam_ctrl __iomem *ctrl; | ||||
| 	int ring; | ||||
| 
 | ||||
| 	ctrldev = &pdev->dev; | ||||
| 	ctrlpriv = dev_get_drvdata(ctrldev); | ||||
| 	ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; | ||||
| 
 | ||||
| 	/* Remove platform devices for JobRs */ | ||||
| 	for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) | ||||
| 		of_device_unregister(ctrlpriv->jrpdev[ring]); | ||||
| 	/* Remove platform devices under the crypto node */ | ||||
| 	of_platform_depopulate(ctrldev); | ||||
| 
 | ||||
| 	/* De-initialize RNG state handles initialized by this driver. */ | ||||
| 	if (ctrlpriv->rng4_sh_init) | ||||
| @@ -418,10 +417,21 @@ DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n"); | ||||
| DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n"); | ||||
| #endif | ||||
| 
 | ||||
| static const struct of_device_id caam_match[] = { | ||||
| 	{ | ||||
| 		.compatible = "fsl,sec-v4.0", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.compatible = "fsl,sec4.0", | ||||
| 	}, | ||||
| 	{}, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, caam_match); | ||||
| 
 | ||||
| /* Probe routine for CAAM top (controller) level */ | ||||
| static int caam_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	int ret, ring, ridx, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; | ||||
| 	int ret, ring, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; | ||||
| 	u64 caam_id; | ||||
| 	struct device *dev; | ||||
| 	struct device_node *nprop, *np; | ||||
| @@ -597,47 +607,24 @@ static int caam_probe(struct platform_device *pdev) | ||||
| 		goto iounmap_ctrl; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Detect and enable JobRs | ||||
| 	 * First, find out how many ring spec'ed, allocate references | ||||
| 	 * for all, then go probe each one. | ||||
| 	 */ | ||||
| 	rspec = 0; | ||||
| 	for_each_available_child_of_node(nprop, np) | ||||
| 		if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || | ||||
| 		    of_device_is_compatible(np, "fsl,sec4.0-job-ring")) | ||||
| 			rspec++; | ||||
| 
 | ||||
| 	ctrlpriv->jrpdev = devm_kcalloc(&pdev->dev, rspec, | ||||
| 					sizeof(*ctrlpriv->jrpdev), GFP_KERNEL); | ||||
| 	if (ctrlpriv->jrpdev == NULL) { | ||||
| 		ret = -ENOMEM; | ||||
| 	ret = of_platform_populate(nprop, caam_match, NULL, dev); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "JR platform devices creation error\n"); | ||||
| 		goto iounmap_ctrl; | ||||
| 	} | ||||
| 
 | ||||
| 	ring = 0; | ||||
| 	ridx = 0; | ||||
| 	ctrlpriv->total_jobrs = 0; | ||||
| 	for_each_available_child_of_node(nprop, np) | ||||
| 		if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || | ||||
| 		    of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { | ||||
| 			ctrlpriv->jrpdev[ring] = | ||||
| 				of_platform_device_create(np, NULL, dev); | ||||
| 			if (!ctrlpriv->jrpdev[ring]) { | ||||
| 				pr_warn("JR physical index %d: Platform device creation error\n", | ||||
| 					ridx); | ||||
| 				ridx++; | ||||
| 				continue; | ||||
| 			} | ||||
| 			ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *) | ||||
| 					     ((__force uint8_t *)ctrl + | ||||
| 					     (ridx + JR_BLOCK_NUMBER) * | ||||
| 					     (ring + JR_BLOCK_NUMBER) * | ||||
| 					      BLOCK_OFFSET | ||||
| 					     ); | ||||
| 			ctrlpriv->total_jobrs++; | ||||
| 			ring++; | ||||
| 			ridx++; | ||||
| 	} | ||||
| 		} | ||||
| 
 | ||||
| 	/* Check to see if QI present. If so, enable */ | ||||
| 	ctrlpriv->qi_present = | ||||
| @@ -847,17 +834,6 @@ disable_caam_ipg: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static struct of_device_id caam_match[] = { | ||||
| 	{ | ||||
| 		.compatible = "fsl,sec-v4.0", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.compatible = "fsl,sec4.0", | ||||
| 	}, | ||||
| 	{}, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, caam_match); | ||||
| 
 | ||||
| static struct platform_driver caam_driver = { | ||||
| 	.driver = { | ||||
| 		.name = "caam", | ||||
|   | ||||
| @@ -66,7 +66,6 @@ struct caam_drv_private_jr { | ||||
| struct caam_drv_private { | ||||
| 
 | ||||
| 	struct device *dev; | ||||
| 	struct platform_device **jrpdev; /* Alloc'ed array per sub-device */ | ||||
| 	struct platform_device *pdev; | ||||
| 
 | ||||
| 	/* Physical-presence section */ | ||||
|   | ||||
| @@ -2,6 +2,7 @@ menuconfig DEV_DAX | ||||
| 	tristate "DAX: direct access to differentiated memory" | ||||
| 	default m if NVDIMM_DAX | ||||
| 	depends on TRANSPARENT_HUGEPAGE | ||||
| 	select SRCU | ||||
| 	help | ||||
| 	  Support raw access to differentiated (persistence, bandwidth, | ||||
| 	  latency...) memory via an mmap(2) capable character | ||||
|   | ||||
| @@ -25,6 +25,7 @@ | ||||
| #include "dax.h" | ||||
| 
 | ||||
| static dev_t dax_devt; | ||||
| DEFINE_STATIC_SRCU(dax_srcu); | ||||
| static struct class *dax_class; | ||||
| static DEFINE_IDA(dax_minor_ida); | ||||
| static int nr_dax = CONFIG_NR_DEV_DAX; | ||||
| @@ -60,7 +61,7 @@ struct dax_region { | ||||
|  * @region - parent region | ||||
|  * @dev - device backing the character device | ||||
|  * @cdev - core chardev data | ||||
|  * @alive - !alive + rcu grace period == no new mappings can be established | ||||
|  * @alive - !alive + srcu grace period == no new mappings can be established | ||||
|  * @id - child id in the region | ||||
|  * @num_resources - number of physical address extents in this device | ||||
|  * @res - array of physical address ranges | ||||
| @@ -569,7 +570,7 @@ static int __dax_dev_pud_fault(struct dax_dev *dax_dev, struct vm_fault *vmf) | ||||
| static int dax_dev_huge_fault(struct vm_fault *vmf, | ||||
| 		enum page_entry_size pe_size) | ||||
| { | ||||
| 	int rc; | ||||
| 	int rc, id; | ||||
| 	struct file *filp = vmf->vma->vm_file; | ||||
| 	struct dax_dev *dax_dev = filp->private_data; | ||||
| 
 | ||||
| @@ -578,7 +579,7 @@ static int dax_dev_huge_fault(struct vm_fault *vmf, | ||||
| 			? "write" : "read", | ||||
| 			vmf->vma->vm_start, vmf->vma->vm_end); | ||||
| 
 | ||||
| 	rcu_read_lock(); | ||||
| 	id = srcu_read_lock(&dax_srcu); | ||||
| 	switch (pe_size) { | ||||
| 	case PE_SIZE_PTE: | ||||
| 		rc = __dax_dev_pte_fault(dax_dev, vmf); | ||||
| @@ -592,7 +593,7 @@ static int dax_dev_huge_fault(struct vm_fault *vmf, | ||||
| 	default: | ||||
| 		return VM_FAULT_FALLBACK; | ||||
| 	} | ||||
| 	rcu_read_unlock(); | ||||
| 	srcu_read_unlock(&dax_srcu, id); | ||||
| 
 | ||||
| 	return rc; | ||||
| } | ||||
| @@ -713,11 +714,11 @@ static void unregister_dax_dev(void *dev) | ||||
| 	 * Note, rcu is not protecting the liveness of dax_dev, rcu is | ||||
| 	 * ensuring that any fault handlers that might have seen | ||||
| 	 * dax_dev->alive == true, have completed.  Any fault handlers | ||||
| 	 * that start after synchronize_rcu() has started will abort | ||||
| 	 * that start after synchronize_srcu() has started will abort | ||||
| 	 * upon seeing dax_dev->alive == false. | ||||
| 	 */ | ||||
| 	dax_dev->alive = false; | ||||
| 	synchronize_rcu(); | ||||
| 	synchronize_srcu(&dax_srcu); | ||||
| 	unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1); | ||||
| 	cdev_del(cdev); | ||||
| 	device_unregister(dev); | ||||
|   | ||||
| @@ -405,8 +405,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) | ||||
| 			  || !exp_info->ops->map_dma_buf | ||||
| 			  || !exp_info->ops->unmap_dma_buf | ||||
| 			  || !exp_info->ops->release | ||||
| 			  || !exp_info->ops->kmap_atomic | ||||
| 			  || !exp_info->ops->kmap | ||||
| 			  || !exp_info->ops->map_atomic | ||||
| 			  || !exp_info->ops->map | ||||
| 			  || !exp_info->ops->mmap)) { | ||||
| 		return ERR_PTR(-EINVAL); | ||||
| 	} | ||||
| @@ -872,7 +872,7 @@ void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num) | ||||
| { | ||||
| 	WARN_ON(!dmabuf); | ||||
| 
 | ||||
| 	return dmabuf->ops->kmap_atomic(dmabuf, page_num); | ||||
| 	return dmabuf->ops->map_atomic(dmabuf, page_num); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic); | ||||
| 
 | ||||
| @@ -889,8 +889,8 @@ void dma_buf_kunmap_atomic(struct dma_buf *dmabuf, unsigned long page_num, | ||||
| { | ||||
| 	WARN_ON(!dmabuf); | ||||
| 
 | ||||
| 	if (dmabuf->ops->kunmap_atomic) | ||||
| 		dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr); | ||||
| 	if (dmabuf->ops->unmap_atomic) | ||||
| 		dmabuf->ops->unmap_atomic(dmabuf, page_num, vaddr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic); | ||||
| 
 | ||||
| @@ -907,7 +907,7 @@ void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long page_num) | ||||
| { | ||||
| 	WARN_ON(!dmabuf); | ||||
| 
 | ||||
| 	return dmabuf->ops->kmap(dmabuf, page_num); | ||||
| 	return dmabuf->ops->map(dmabuf, page_num); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(dma_buf_kmap); | ||||
| 
 | ||||
| @@ -924,8 +924,8 @@ void dma_buf_kunmap(struct dma_buf *dmabuf, unsigned long page_num, | ||||
| { | ||||
| 	WARN_ON(!dmabuf); | ||||
| 
 | ||||
| 	if (dmabuf->ops->kunmap) | ||||
| 		dmabuf->ops->kunmap(dmabuf, page_num, vaddr); | ||||
| 	if (dmabuf->ops->unmap) | ||||
| 		dmabuf->ops->unmap(dmabuf, page_num, vaddr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(dma_buf_kunmap); | ||||
| 
 | ||||
|   | ||||
| @@ -149,7 +149,8 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, | ||||
| 
 | ||||
| 		status = __gop_query32(sys_table_arg, gop32, &info, &size, | ||||
| 				       ¤t_fb_base); | ||||
| 		if (status == EFI_SUCCESS && (!first_gop || conout_found)) { | ||||
| 		if (status == EFI_SUCCESS && (!first_gop || conout_found) && | ||||
| 		    info->pixel_format != PIXEL_BLT_ONLY) { | ||||
| 			/*
 | ||||
| 			 * Systems that use the UEFI Console Splitter may | ||||
| 			 * provide multiple GOP devices, not all of which are | ||||
| @@ -266,7 +267,8 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, | ||||
| 
 | ||||
| 		status = __gop_query64(sys_table_arg, gop64, &info, &size, | ||||
| 				       ¤t_fb_base); | ||||
| 		if (status == EFI_SUCCESS && (!first_gop || conout_found)) { | ||||
| 		if (status == EFI_SUCCESS && (!first_gop || conout_found) && | ||||
| 		    info->pixel_format != PIXEL_BLT_ONLY) { | ||||
| 			/*
 | ||||
| 			 * Systems that use the UEFI Console Splitter may | ||||
| 			 * provide multiple GOP devices, not all of which are | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
| #include <drm/drm_crtc.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <video/videomode.h> | ||||
| 
 | ||||
| #include "malidp_drv.h" | ||||
| @@ -35,13 +36,6 @@ static bool malidp_crtc_mode_fixup(struct drm_crtc *crtc, | ||||
| 	long rate, req_rate = mode->crtc_clock * 1000; | ||||
| 
 | ||||
| 	if (req_rate) { | ||||
| 		rate = clk_round_rate(hwdev->mclk, req_rate); | ||||
| 		if (rate < req_rate) { | ||||
| 			DRM_DEBUG_DRIVER("mclk clock unable to reach %d kHz\n", | ||||
| 					 mode->crtc_clock); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		rate = clk_round_rate(hwdev->pxlclk, req_rate); | ||||
| 		if (rate != req_rate) { | ||||
| 			DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n", | ||||
| @@ -58,9 +52,14 @@ static void malidp_crtc_enable(struct drm_crtc *crtc) | ||||
| 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 	struct videomode vm; | ||||
| 	int err = pm_runtime_get_sync(crtc->dev->dev); | ||||
| 
 | ||||
| 	if (err < 0) { | ||||
| 		DRM_DEBUG_DRIVER("Failed to enable runtime power management: %d\n", err); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm); | ||||
| 
 | ||||
| 	clk_prepare_enable(hwdev->pxlclk); | ||||
| 
 | ||||
| 	/* We rely on firmware to set mclk to a sensible level. */ | ||||
| @@ -75,10 +74,254 @@ static void malidp_crtc_disable(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 	int err; | ||||
| 
 | ||||
| 	drm_crtc_vblank_off(crtc); | ||||
| 	hwdev->enter_config_mode(hwdev); | ||||
| 	clk_disable_unprepare(hwdev->pxlclk); | ||||
| 
 | ||||
| 	err = pm_runtime_put(crtc->dev->dev); | ||||
| 	if (err < 0) { | ||||
| 		DRM_DEBUG_DRIVER("Failed to disable runtime power management: %d\n", err); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static const struct gamma_curve_segment { | ||||
| 	u16 start; | ||||
| 	u16 end; | ||||
| } segments[MALIDP_COEFFTAB_NUM_COEFFS] = { | ||||
| 	/* sector 0 */ | ||||
| 	{    0,    0 }, {    1,    1 }, {    2,    2 }, {    3,    3 }, | ||||
| 	{    4,    4 }, {    5,    5 }, {    6,    6 }, {    7,    7 }, | ||||
| 	{    8,    8 }, {    9,    9 }, {   10,   10 }, {   11,   11 }, | ||||
| 	{   12,   12 }, {   13,   13 }, {   14,   14 }, {   15,   15 }, | ||||
| 	/* sector 1 */ | ||||
| 	{   16,   19 }, {   20,   23 }, {   24,   27 }, {   28,   31 }, | ||||
| 	/* sector 2 */ | ||||
| 	{   32,   39 }, {   40,   47 }, {   48,   55 }, {   56,   63 }, | ||||
| 	/* sector 3 */ | ||||
| 	{   64,   79 }, {   80,   95 }, {   96,  111 }, {  112,  127 }, | ||||
| 	/* sector 4 */ | ||||
| 	{  128,  159 }, {  160,  191 }, {  192,  223 }, {  224,  255 }, | ||||
| 	/* sector 5 */ | ||||
| 	{  256,  319 }, {  320,  383 }, {  384,  447 }, {  448,  511 }, | ||||
| 	/* sector 6 */ | ||||
| 	{  512,  639 }, {  640,  767 }, {  768,  895 }, {  896, 1023 }, | ||||
| 	{ 1024, 1151 }, { 1152, 1279 }, { 1280, 1407 }, { 1408, 1535 }, | ||||
| 	{ 1536, 1663 }, { 1664, 1791 }, { 1792, 1919 }, { 1920, 2047 }, | ||||
| 	{ 2048, 2175 }, { 2176, 2303 }, { 2304, 2431 }, { 2432, 2559 }, | ||||
| 	{ 2560, 2687 }, { 2688, 2815 }, { 2816, 2943 }, { 2944, 3071 }, | ||||
| 	{ 3072, 3199 }, { 3200, 3327 }, { 3328, 3455 }, { 3456, 3583 }, | ||||
| 	{ 3584, 3711 }, { 3712, 3839 }, { 3840, 3967 }, { 3968, 4095 }, | ||||
| }; | ||||
| 
 | ||||
| #define DE_COEFTAB_DATA(a, b) ((((a) & 0xfff) << 16) | (((b) & 0xfff))) | ||||
| 
 | ||||
| static void malidp_generate_gamma_table(struct drm_property_blob *lut_blob, | ||||
| 					u32 coeffs[MALIDP_COEFFTAB_NUM_COEFFS]) | ||||
| { | ||||
| 	struct drm_color_lut *lut = (struct drm_color_lut *)lut_blob->data; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i) { | ||||
| 		u32 a, b, delta_in, out_start, out_end; | ||||
| 
 | ||||
| 		delta_in = segments[i].end - segments[i].start; | ||||
| 		/* DP has 12-bit internal precision for its LUTs. */ | ||||
| 		out_start = drm_color_lut_extract(lut[segments[i].start].green, | ||||
| 						  12); | ||||
| 		out_end = drm_color_lut_extract(lut[segments[i].end].green, 12); | ||||
| 		a = (delta_in == 0) ? 0 : ((out_end - out_start) * 256) / delta_in; | ||||
| 		b = out_start; | ||||
| 		coeffs[i] = DE_COEFTAB_DATA(a, b); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check if there is a new gamma LUT and if it is of an acceptable size. Also, | ||||
|  * reject any LUTs that use distinct red, green, and blue curves. | ||||
|  */ | ||||
| static int malidp_crtc_atomic_check_gamma(struct drm_crtc *crtc, | ||||
| 					  struct drm_crtc_state *state) | ||||
| { | ||||
| 	struct malidp_crtc_state *mc = to_malidp_crtc_state(state); | ||||
| 	struct drm_color_lut *lut; | ||||
| 	size_t lut_size; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!state->color_mgmt_changed || !state->gamma_lut) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (crtc->state->gamma_lut && | ||||
| 	    (crtc->state->gamma_lut->base.id == state->gamma_lut->base.id)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (state->gamma_lut->length % sizeof(struct drm_color_lut)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	lut_size = state->gamma_lut->length / sizeof(struct drm_color_lut); | ||||
| 	if (lut_size != MALIDP_GAMMA_LUT_SIZE) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	lut = (struct drm_color_lut *)state->gamma_lut->data; | ||||
| 	for (i = 0; i < lut_size; ++i) | ||||
| 		if (!((lut[i].red == lut[i].green) && | ||||
| 		      (lut[i].red == lut[i].blue))) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 	if (!state->mode_changed) { | ||||
| 		int ret; | ||||
| 
 | ||||
| 		state->mode_changed = true; | ||||
| 		/*
 | ||||
| 		 * Kerneldoc for drm_atomic_helper_check_modeset mandates that | ||||
| 		 * it be invoked when the driver sets ->mode_changed. Since | ||||
| 		 * changing the gamma LUT doesn't depend on any external | ||||
| 		 * resources, it is safe to call it only once. | ||||
| 		 */ | ||||
| 		ret = drm_atomic_helper_check_modeset(crtc->dev, state->state); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	malidp_generate_gamma_table(state->gamma_lut, mc->gamma_coeffs); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check if there is a new CTM and if it contains valid input. Valid here means | ||||
|  * that the number is inside the representable range for a Q3.12 number, | ||||
|  * excluding truncating the fractional part of the input data. | ||||
|  * | ||||
|  * The COLORADJ registers can be changed atomically. | ||||
|  */ | ||||
| static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, | ||||
| 					struct drm_crtc_state *state) | ||||
| { | ||||
| 	struct malidp_crtc_state *mc = to_malidp_crtc_state(state); | ||||
| 	struct drm_color_ctm *ctm; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!state->color_mgmt_changed) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (!state->ctm) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (crtc->state->ctm && (crtc->state->ctm->base.id == | ||||
| 				 state->ctm->base.id)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The size of the ctm is checked in | ||||
| 	 * drm_atomic_replace_property_blob_from_id. | ||||
| 	 */ | ||||
| 	ctm = (struct drm_color_ctm *)state->ctm->data; | ||||
| 	for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) { | ||||
| 		/* Convert from S31.32 to Q3.12. */ | ||||
| 		s64 val = ctm->matrix[i]; | ||||
| 		u32 mag = ((((u64)val) & ~BIT_ULL(63)) >> 20) & | ||||
| 			  GENMASK_ULL(14, 0); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Convert to 2s complement and check the destination's top bit | ||||
| 		 * for overflow. NB: Can't check before converting or it'd | ||||
| 		 * incorrectly reject the case: | ||||
| 		 * sign == 1 | ||||
| 		 * mag == 0x2000 | ||||
| 		 */ | ||||
| 		if (val & BIT_ULL(63)) | ||||
| 			mag = ~mag + 1; | ||||
| 		if (!!(val & BIT_ULL(63)) != !!(mag & BIT(14))) | ||||
| 			return -EINVAL; | ||||
| 		mc->coloradj_coeffs[i] = mag; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int malidp_crtc_atomic_check_scaling(struct drm_crtc *crtc, | ||||
| 					    struct drm_crtc_state *state) | ||||
| { | ||||
| 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 	struct malidp_crtc_state *cs = to_malidp_crtc_state(state); | ||||
| 	struct malidp_se_config *s = &cs->scaler_config; | ||||
| 	struct drm_plane *plane; | ||||
| 	struct videomode vm; | ||||
| 	const struct drm_plane_state *pstate; | ||||
| 	u32 h_upscale_factor = 0; /* U16.16 */ | ||||
| 	u32 v_upscale_factor = 0; /* U16.16 */ | ||||
| 	u8 scaling = cs->scaled_planes_mask; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!scaling) { | ||||
| 		s->scale_enable = false; | ||||
| 		goto mclk_calc; | ||||
| 	} | ||||
| 
 | ||||
| 	/* The scaling engine can only handle one plane at a time. */ | ||||
| 	if (scaling & (scaling - 1)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { | ||||
| 		struct malidp_plane *mp = to_malidp_plane(plane); | ||||
| 		u32 phase; | ||||
| 
 | ||||
| 		if (!(mp->layer->id & scaling)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Convert crtc_[w|h] to U32.32, then divide by U16.16 src_[w|h] | ||||
| 		 * to get the U16.16 result. | ||||
| 		 */ | ||||
| 		h_upscale_factor = div_u64((u64)pstate->crtc_w << 32, | ||||
| 					   pstate->src_w); | ||||
| 		v_upscale_factor = div_u64((u64)pstate->crtc_h << 32, | ||||
| 					   pstate->src_h); | ||||
| 
 | ||||
| 		s->enhancer_enable = ((h_upscale_factor >> 16) >= 2 || | ||||
| 				      (v_upscale_factor >> 16) >= 2); | ||||
| 
 | ||||
| 		s->input_w = pstate->src_w >> 16; | ||||
| 		s->input_h = pstate->src_h >> 16; | ||||
| 		s->output_w = pstate->crtc_w; | ||||
| 		s->output_h = pstate->crtc_h; | ||||
| 
 | ||||
| #define SE_N_PHASE 4 | ||||
| #define SE_SHIFT_N_PHASE 12 | ||||
| 		/* Calculate initial_phase and delta_phase for horizontal. */ | ||||
| 		phase = s->input_w; | ||||
| 		s->h_init_phase = | ||||
| 				((phase << SE_N_PHASE) / s->output_w + 1) / 2; | ||||
| 
 | ||||
| 		phase = s->input_w; | ||||
| 		phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE); | ||||
| 		s->h_delta_phase = phase / s->output_w; | ||||
| 
 | ||||
| 		/* Same for vertical. */ | ||||
| 		phase = s->input_h; | ||||
| 		s->v_init_phase = | ||||
| 				((phase << SE_N_PHASE) / s->output_h + 1) / 2; | ||||
| 
 | ||||
| 		phase = s->input_h; | ||||
| 		phase <<= (SE_SHIFT_N_PHASE + SE_N_PHASE); | ||||
| 		s->v_delta_phase = phase / s->output_h; | ||||
| #undef SE_N_PHASE | ||||
| #undef SE_SHIFT_N_PHASE | ||||
| 		s->plane_src_id = mp->layer->id; | ||||
| 	} | ||||
| 
 | ||||
| 	s->scale_enable = true; | ||||
| 	s->hcoeff = malidp_se_select_coeffs(h_upscale_factor); | ||||
| 	s->vcoeff = malidp_se_select_coeffs(v_upscale_factor); | ||||
| 
 | ||||
| mclk_calc: | ||||
| 	drm_display_mode_to_videomode(&state->adjusted_mode, &vm); | ||||
| 	ret = hwdev->se_calc_mclk(hwdev, s, &vm); | ||||
| 	if (ret < 0) | ||||
| 		return -EINVAL; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int malidp_crtc_atomic_check(struct drm_crtc *crtc, | ||||
| @@ -90,6 +333,7 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, | ||||
| 	const struct drm_plane_state *pstate; | ||||
| 	u32 rot_mem_free, rot_mem_usable; | ||||
| 	int rotated_planes = 0; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * check if there is enough rotation memory available for planes | ||||
| @@ -156,7 +400,11 @@ static int malidp_crtc_atomic_check(struct drm_crtc *crtc, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	ret = malidp_crtc_atomic_check_gamma(crtc, state); | ||||
| 	ret = ret ? ret : malidp_crtc_atomic_check_ctm(crtc, state); | ||||
| 	ret = ret ? ret : malidp_crtc_atomic_check_scaling(crtc, state); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { | ||||
| @@ -166,6 +414,60 @@ static const struct drm_crtc_helper_funcs malidp_crtc_helper_funcs = { | ||||
| 	.atomic_check = malidp_crtc_atomic_check, | ||||
| }; | ||||
| 
 | ||||
| static struct drm_crtc_state *malidp_crtc_duplicate_state(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct malidp_crtc_state *state, *old_state; | ||||
| 
 | ||||
| 	if (WARN_ON(!crtc->state)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	old_state = to_malidp_crtc_state(crtc->state); | ||||
| 	state = kmalloc(sizeof(*state), GFP_KERNEL); | ||||
| 	if (!state) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	__drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); | ||||
| 	memcpy(state->gamma_coeffs, old_state->gamma_coeffs, | ||||
| 	       sizeof(state->gamma_coeffs)); | ||||
| 	memcpy(state->coloradj_coeffs, old_state->coloradj_coeffs, | ||||
| 	       sizeof(state->coloradj_coeffs)); | ||||
| 	memcpy(&state->scaler_config, &old_state->scaler_config, | ||||
| 	       sizeof(state->scaler_config)); | ||||
| 	state->scaled_planes_mask = 0; | ||||
| 
 | ||||
| 	return &state->base; | ||||
| } | ||||
| 
 | ||||
| static void malidp_crtc_reset(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct malidp_crtc_state *state = NULL; | ||||
| 
 | ||||
| 	if (crtc->state) { | ||||
| 		state = to_malidp_crtc_state(crtc->state); | ||||
| 		__drm_atomic_helper_crtc_destroy_state(crtc->state); | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(state); | ||||
| 	state = kzalloc(sizeof(*state), GFP_KERNEL); | ||||
| 	if (state) { | ||||
| 		crtc->state = &state->base; | ||||
| 		crtc->state->crtc = crtc; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void malidp_crtc_destroy_state(struct drm_crtc *crtc, | ||||
| 				      struct drm_crtc_state *state) | ||||
| { | ||||
| 	struct malidp_crtc_state *mali_state = NULL; | ||||
| 
 | ||||
| 	if (state) { | ||||
| 		mali_state = to_malidp_crtc_state(state); | ||||
| 		__drm_atomic_helper_crtc_destroy_state(state); | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(mali_state); | ||||
| } | ||||
| 
 | ||||
| static int malidp_crtc_enable_vblank(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||||
| @@ -186,12 +488,13 @@ static void malidp_crtc_disable_vblank(struct drm_crtc *crtc) | ||||
| } | ||||
| 
 | ||||
| static const struct drm_crtc_funcs malidp_crtc_funcs = { | ||||
| 	.gamma_set = drm_atomic_helper_legacy_gamma_set, | ||||
| 	.destroy = drm_crtc_cleanup, | ||||
| 	.set_config = drm_atomic_helper_set_config, | ||||
| 	.page_flip = drm_atomic_helper_page_flip, | ||||
| 	.reset = drm_atomic_helper_crtc_reset, | ||||
| 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||||
| 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||||
| 	.reset = malidp_crtc_reset, | ||||
| 	.atomic_duplicate_state = malidp_crtc_duplicate_state, | ||||
| 	.atomic_destroy_state = malidp_crtc_destroy_state, | ||||
| 	.enable_vblank = malidp_crtc_enable_vblank, | ||||
| 	.disable_vblank = malidp_crtc_disable_vblank, | ||||
| }; | ||||
| @@ -223,11 +526,17 @@ int malidp_crtc_init(struct drm_device *drm) | ||||
| 
 | ||||
| 	ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL, | ||||
| 					&malidp_crtc_funcs, NULL); | ||||
| 	if (ret) | ||||
| 		goto crtc_cleanup_planes; | ||||
| 
 | ||||
| 	if (!ret) { | ||||
| 		drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); | ||||
| 	drm_mode_crtc_set_gamma_size(&malidp->crtc, MALIDP_GAMMA_LUT_SIZE); | ||||
| 	/* No inverse-gamma: it is per-plane. */ | ||||
| 	drm_crtc_enable_color_mgmt(&malidp->crtc, 0, true, MALIDP_GAMMA_LUT_SIZE); | ||||
| 
 | ||||
| 	malidp_se_set_enh_coeffs(malidp->dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| crtc_cleanup_planes: | ||||
| 	malidp_de_planes_destroy(drm); | ||||
|   | ||||
| @@ -13,9 +13,11 @@ | ||||
| #include <linux/module.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/component.h> | ||||
| #include <linux/console.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/of_graph.h> | ||||
| #include <linux/of_reserved_mem.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| 
 | ||||
| #include <drm/drmP.h> | ||||
| #include <drm/drm_atomic.h> | ||||
| @@ -32,6 +34,131 @@ | ||||
| 
 | ||||
| #define MALIDP_CONF_VALID_TIMEOUT	250 | ||||
| 
 | ||||
| static void malidp_write_gamma_table(struct malidp_hw_device *hwdev, | ||||
| 				     u32 data[MALIDP_COEFFTAB_NUM_COEFFS]) | ||||
| { | ||||
| 	int i; | ||||
| 	/* Update all channels with a single gamma curve. */ | ||||
| 	const u32 gamma_write_mask = GENMASK(18, 16); | ||||
| 	/*
 | ||||
| 	 * Always write an entire table, so the address field in | ||||
| 	 * DE_COEFFTAB_ADDR is 0 and we can use the gamma_write_mask bitmask | ||||
| 	 * directly. | ||||
| 	 */ | ||||
| 	malidp_hw_write(hwdev, gamma_write_mask, | ||||
| 			hwdev->map.coeffs_base + MALIDP_COEF_TABLE_ADDR); | ||||
| 	for (i = 0; i < MALIDP_COEFFTAB_NUM_COEFFS; ++i) | ||||
| 		malidp_hw_write(hwdev, data[i], | ||||
| 				hwdev->map.coeffs_base + | ||||
| 				MALIDP_COEF_TABLE_DATA); | ||||
| } | ||||
| 
 | ||||
| static void malidp_atomic_commit_update_gamma(struct drm_crtc *crtc, | ||||
| 					      struct drm_crtc_state *old_state) | ||||
| { | ||||
| 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 
 | ||||
| 	if (!crtc->state->color_mgmt_changed) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!crtc->state->gamma_lut) { | ||||
| 		malidp_hw_clearbits(hwdev, | ||||
| 				    MALIDP_DISP_FUNC_GAMMA, | ||||
| 				    MALIDP_DE_DISPLAY_FUNC); | ||||
| 	} else { | ||||
| 		struct malidp_crtc_state *mc = | ||||
| 			to_malidp_crtc_state(crtc->state); | ||||
| 
 | ||||
| 		if (!old_state->gamma_lut || (crtc->state->gamma_lut->base.id != | ||||
| 					      old_state->gamma_lut->base.id)) | ||||
| 			malidp_write_gamma_table(hwdev, mc->gamma_coeffs); | ||||
| 
 | ||||
| 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_GAMMA, | ||||
| 				  MALIDP_DE_DISPLAY_FUNC); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static | ||||
| void malidp_atomic_commit_update_coloradj(struct drm_crtc *crtc, | ||||
| 					  struct drm_crtc_state *old_state) | ||||
| { | ||||
| 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!crtc->state->color_mgmt_changed) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!crtc->state->ctm) { | ||||
| 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_CADJ, | ||||
| 				    MALIDP_DE_DISPLAY_FUNC); | ||||
| 	} else { | ||||
| 		struct malidp_crtc_state *mc = | ||||
| 			to_malidp_crtc_state(crtc->state); | ||||
| 
 | ||||
| 		if (!old_state->ctm || (crtc->state->ctm->base.id != | ||||
| 					old_state->ctm->base.id)) | ||||
| 			for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; ++i) | ||||
| 				malidp_hw_write(hwdev, | ||||
| 						mc->coloradj_coeffs[i], | ||||
| 						hwdev->map.coeffs_base + | ||||
| 						MALIDP_COLOR_ADJ_COEF + 4 * i); | ||||
| 
 | ||||
| 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_CADJ, | ||||
| 				  MALIDP_DE_DISPLAY_FUNC); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void malidp_atomic_commit_se_config(struct drm_crtc *crtc, | ||||
| 					   struct drm_crtc_state *old_state) | ||||
| { | ||||
| 	struct malidp_crtc_state *cs = to_malidp_crtc_state(crtc->state); | ||||
| 	struct malidp_crtc_state *old_cs = to_malidp_crtc_state(old_state); | ||||
| 	struct malidp_drm *malidp = crtc_to_malidp_device(crtc); | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 	struct malidp_se_config *s = &cs->scaler_config; | ||||
| 	struct malidp_se_config *old_s = &old_cs->scaler_config; | ||||
| 	u32 se_control = hwdev->map.se_base + | ||||
| 			 ((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ? | ||||
| 			 0x10 : 0xC); | ||||
| 	u32 layer_control = se_control + MALIDP_SE_LAYER_CONTROL; | ||||
| 	u32 scr = se_control + MALIDP_SE_SCALING_CONTROL; | ||||
| 	u32 val; | ||||
| 
 | ||||
| 	/* Set SE_CONTROL */ | ||||
| 	if (!s->scale_enable) { | ||||
| 		val = malidp_hw_read(hwdev, se_control); | ||||
| 		val &= ~MALIDP_SE_SCALING_EN; | ||||
| 		malidp_hw_write(hwdev, val, se_control); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	hwdev->se_set_scaling_coeffs(hwdev, s, old_s); | ||||
| 	val = malidp_hw_read(hwdev, se_control); | ||||
| 	val |= MALIDP_SE_SCALING_EN | MALIDP_SE_ALPHA_EN; | ||||
| 
 | ||||
| 	val &= ~MALIDP_SE_ENH(MALIDP_SE_ENH_MASK); | ||||
| 	val |= s->enhancer_enable ? MALIDP_SE_ENH(3) : 0; | ||||
| 
 | ||||
| 	val |= MALIDP_SE_RGBO_IF_EN; | ||||
| 	malidp_hw_write(hwdev, val, se_control); | ||||
| 
 | ||||
| 	/* Set IN_SIZE & OUT_SIZE. */ | ||||
| 	val = MALIDP_SE_SET_V_SIZE(s->input_h) | | ||||
| 	      MALIDP_SE_SET_H_SIZE(s->input_w); | ||||
| 	malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_IN_SIZE); | ||||
| 	val = MALIDP_SE_SET_V_SIZE(s->output_h) | | ||||
| 	      MALIDP_SE_SET_H_SIZE(s->output_w); | ||||
| 	malidp_hw_write(hwdev, val, layer_control + MALIDP_SE_L0_OUT_SIZE); | ||||
| 
 | ||||
| 	/* Set phase regs. */ | ||||
| 	malidp_hw_write(hwdev, s->h_init_phase, scr + MALIDP_SE_H_INIT_PH); | ||||
| 	malidp_hw_write(hwdev, s->h_delta_phase, scr + MALIDP_SE_H_DELTA_PH); | ||||
| 	malidp_hw_write(hwdev, s->v_init_phase, scr + MALIDP_SE_V_INIT_PH); | ||||
| 	malidp_hw_write(hwdev, s->v_delta_phase, scr + MALIDP_SE_V_DELTA_PH); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * set the "config valid" bit and wait until the hardware acts on it | ||||
|  */ | ||||
| @@ -66,10 +193,12 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) | ||||
| 	struct drm_pending_vblank_event *event; | ||||
| 	struct drm_device *drm = state->dev; | ||||
| 	struct malidp_drm *malidp = drm->dev_private; | ||||
| 	int ret = malidp_set_and_wait_config_valid(drm); | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n"); | ||||
| 	if (malidp->crtc.enabled) { | ||||
| 		/* only set config_valid if the CRTC is enabled */ | ||||
| 		if (malidp_set_and_wait_config_valid(drm)) | ||||
| 			DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	event = malidp->crtc.state->event; | ||||
| 	if (event) { | ||||
| @@ -88,15 +217,30 @@ static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state) | ||||
| static void malidp_atomic_commit_tail(struct drm_atomic_state *state) | ||||
| { | ||||
| 	struct drm_device *drm = state->dev; | ||||
| 	struct drm_crtc *crtc; | ||||
| 	struct drm_crtc_state *old_crtc_state; | ||||
| 	int i; | ||||
| 
 | ||||
| 	pm_runtime_get_sync(drm->dev); | ||||
| 
 | ||||
| 	drm_atomic_helper_commit_modeset_disables(drm, state); | ||||
| 	drm_atomic_helper_commit_modeset_enables(drm, state); | ||||
| 
 | ||||
| 	for_each_crtc_in_state(state, crtc, old_crtc_state, i) { | ||||
| 		malidp_atomic_commit_update_gamma(crtc, old_crtc_state); | ||||
| 		malidp_atomic_commit_update_coloradj(crtc, old_crtc_state); | ||||
| 		malidp_atomic_commit_se_config(crtc, old_crtc_state); | ||||
| 	} | ||||
| 
 | ||||
| 	drm_atomic_helper_commit_planes(drm, state, 0); | ||||
| 
 | ||||
| 	drm_atomic_helper_commit_modeset_enables(drm, state); | ||||
| 
 | ||||
| 	malidp_atomic_commit_hw_done(state); | ||||
| 
 | ||||
| 	drm_atomic_helper_wait_for_vblanks(drm, state); | ||||
| 
 | ||||
| 	pm_runtime_put(drm->dev); | ||||
| 
 | ||||
| 	drm_atomic_helper_cleanup_planes(drm, state); | ||||
| } | ||||
| 
 | ||||
| @@ -277,8 +421,65 @@ static bool malidp_has_sufficient_address_space(const struct resource *res, | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static ssize_t core_id_show(struct device *dev, struct device_attribute *attr, | ||||
| 			    char *buf) | ||||
| { | ||||
| 	struct drm_device *drm = dev_get_drvdata(dev); | ||||
| 	struct malidp_drm *malidp = drm->dev_private; | ||||
| 
 | ||||
| 	return snprintf(buf, PAGE_SIZE, "%08x\n", malidp->core_id); | ||||
| } | ||||
| 
 | ||||
| DEVICE_ATTR_RO(core_id); | ||||
| 
 | ||||
| static int malidp_init_sysfs(struct device *dev) | ||||
| { | ||||
| 	int ret = device_create_file(dev, &dev_attr_core_id); | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		DRM_ERROR("failed to create device file for core_id\n"); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void malidp_fini_sysfs(struct device *dev) | ||||
| { | ||||
| 	device_remove_file(dev, &dev_attr_core_id); | ||||
| } | ||||
| 
 | ||||
| #define MAX_OUTPUT_CHANNELS	3 | ||||
| 
 | ||||
| static int malidp_runtime_pm_suspend(struct device *dev) | ||||
| { | ||||
| 	struct drm_device *drm = dev_get_drvdata(dev); | ||||
| 	struct malidp_drm *malidp = drm->dev_private; | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 
 | ||||
| 	/* we can only suspend if the hardware is in config mode */ | ||||
| 	WARN_ON(!hwdev->in_config_mode(hwdev)); | ||||
| 
 | ||||
| 	hwdev->pm_suspended = true; | ||||
| 	clk_disable_unprepare(hwdev->mclk); | ||||
| 	clk_disable_unprepare(hwdev->aclk); | ||||
| 	clk_disable_unprepare(hwdev->pclk); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int malidp_runtime_pm_resume(struct device *dev) | ||||
| { | ||||
| 	struct drm_device *drm = dev_get_drvdata(dev); | ||||
| 	struct malidp_drm *malidp = drm->dev_private; | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 
 | ||||
| 	clk_prepare_enable(hwdev->pclk); | ||||
| 	clk_prepare_enable(hwdev->aclk); | ||||
| 	clk_prepare_enable(hwdev->mclk); | ||||
| 	hwdev->pm_suspended = false; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int malidp_bind(struct device *dev) | ||||
| { | ||||
| 	struct resource *res; | ||||
| @@ -307,7 +508,6 @@ static int malidp_bind(struct device *dev) | ||||
| 	memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev)); | ||||
| 	malidp->dev = hwdev; | ||||
| 
 | ||||
| 
 | ||||
| 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||
| 	hwdev->regs = devm_ioremap_resource(dev, res); | ||||
| 	if (IS_ERR(hwdev->regs)) | ||||
| @@ -340,14 +540,17 @@ static int malidp_bind(struct device *dev) | ||||
| 		goto alloc_fail; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Enable APB clock in order to get access to the registers */ | ||||
| 	clk_prepare_enable(hwdev->pclk); | ||||
| 	/*
 | ||||
| 	 * Enable AXI clock and main clock so that prefetch can start once | ||||
| 	 * the registers are set | ||||
| 	 */ | ||||
| 	clk_prepare_enable(hwdev->aclk); | ||||
| 	clk_prepare_enable(hwdev->mclk); | ||||
| 	drm->dev_private = malidp; | ||||
| 	dev_set_drvdata(dev, drm); | ||||
| 
 | ||||
| 	/* Enable power management */ | ||||
| 	pm_runtime_enable(dev); | ||||
| 
 | ||||
| 	/* Resume device to enable the clocks */ | ||||
| 	if (pm_runtime_enabled(dev)) | ||||
| 		pm_runtime_get_sync(dev); | ||||
| 	else | ||||
| 		malidp_runtime_pm_resume(dev); | ||||
| 
 | ||||
| 	dev_id = of_match_device(malidp_drm_of_match, dev); | ||||
| 	if (!dev_id) { | ||||
| @@ -376,6 +579,8 @@ static int malidp_bind(struct device *dev) | ||||
| 	DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16, | ||||
| 		 (version >> 12) & 0xf, (version >> 8) & 0xf); | ||||
| 
 | ||||
| 	malidp->core_id = version; | ||||
| 
 | ||||
| 	/* set the number of lines used for output of RGB data */ | ||||
| 	ret = of_property_read_u8_array(dev->of_node, | ||||
| 					"arm,malidp-output-port-lines", | ||||
| @@ -387,13 +592,15 @@ static int malidp_bind(struct device *dev) | ||||
| 		out_depth = (out_depth << 8) | (output_width[i] & 0xf); | ||||
| 	malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base); | ||||
| 
 | ||||
| 	drm->dev_private = malidp; | ||||
| 	dev_set_drvdata(dev, drm); | ||||
| 	atomic_set(&malidp->config_valid, 0); | ||||
| 	init_waitqueue_head(&malidp->wq); | ||||
| 
 | ||||
| 	ret = malidp_init(drm); | ||||
| 	if (ret < 0) | ||||
| 		goto query_hw_fail; | ||||
| 
 | ||||
| 	ret = malidp_init_sysfs(dev); | ||||
| 	if (ret) | ||||
| 		goto init_fail; | ||||
| 
 | ||||
| 	/* Set the CRTC's port so that the encoder component can find it */ | ||||
| @@ -416,6 +623,7 @@ static int malidp_bind(struct device *dev) | ||||
| 		DRM_ERROR("failed to initialise vblank\n"); | ||||
| 		goto vblank_fail; | ||||
| 	} | ||||
| 	pm_runtime_put(dev); | ||||
| 
 | ||||
| 	drm_mode_config_reset(drm); | ||||
| 
 | ||||
| @@ -441,7 +649,9 @@ register_fail: | ||||
| 		drm_fbdev_cma_fini(malidp->fbdev); | ||||
| 		malidp->fbdev = NULL; | ||||
| 	} | ||||
| 	drm_kms_helper_poll_fini(drm); | ||||
| fbdev_fail: | ||||
| 	pm_runtime_get_sync(dev); | ||||
| 	drm_vblank_cleanup(drm); | ||||
| vblank_fail: | ||||
| 	malidp_se_irq_fini(drm); | ||||
| @@ -452,14 +662,17 @@ irq_init_fail: | ||||
| bind_fail: | ||||
| 	of_node_put(malidp->crtc.port); | ||||
| 	malidp->crtc.port = NULL; | ||||
| 	malidp_fini(drm); | ||||
| init_fail: | ||||
| 	malidp_fini_sysfs(dev); | ||||
| 	malidp_fini(drm); | ||||
| query_hw_fail: | ||||
| 	pm_runtime_put(dev); | ||||
| 	if (pm_runtime_enabled(dev)) | ||||
| 		pm_runtime_disable(dev); | ||||
| 	else | ||||
| 		malidp_runtime_pm_suspend(dev); | ||||
| 	drm->dev_private = NULL; | ||||
| 	dev_set_drvdata(dev, NULL); | ||||
| query_hw_fail: | ||||
| 	clk_disable_unprepare(hwdev->mclk); | ||||
| 	clk_disable_unprepare(hwdev->aclk); | ||||
| 	clk_disable_unprepare(hwdev->pclk); | ||||
| 	drm_dev_unref(drm); | ||||
| alloc_fail: | ||||
| 	of_reserved_mem_device_release(dev); | ||||
| @@ -471,7 +684,6 @@ static void malidp_unbind(struct device *dev) | ||||
| { | ||||
| 	struct drm_device *drm = dev_get_drvdata(dev); | ||||
| 	struct malidp_drm *malidp = drm->dev_private; | ||||
| 	struct malidp_hw_device *hwdev = malidp->dev; | ||||
| 
 | ||||
| 	drm_dev_unregister(drm); | ||||
| 	if (malidp->fbdev) { | ||||
| @@ -479,18 +691,22 @@ static void malidp_unbind(struct device *dev) | ||||
| 		malidp->fbdev = NULL; | ||||
| 	} | ||||
| 	drm_kms_helper_poll_fini(drm); | ||||
| 	pm_runtime_get_sync(dev); | ||||
| 	drm_vblank_cleanup(drm); | ||||
| 	malidp_se_irq_fini(drm); | ||||
| 	malidp_de_irq_fini(drm); | ||||
| 	drm_vblank_cleanup(drm); | ||||
| 	component_unbind_all(dev, drm); | ||||
| 	of_node_put(malidp->crtc.port); | ||||
| 	malidp->crtc.port = NULL; | ||||
| 	malidp_fini_sysfs(dev); | ||||
| 	malidp_fini(drm); | ||||
| 	pm_runtime_put(dev); | ||||
| 	if (pm_runtime_enabled(dev)) | ||||
| 		pm_runtime_disable(dev); | ||||
| 	else | ||||
| 		malidp_runtime_pm_suspend(dev); | ||||
| 	drm->dev_private = NULL; | ||||
| 	dev_set_drvdata(dev, NULL); | ||||
| 	clk_disable_unprepare(hwdev->mclk); | ||||
| 	clk_disable_unprepare(hwdev->aclk); | ||||
| 	clk_disable_unprepare(hwdev->pclk); | ||||
| 	drm_dev_unref(drm); | ||||
| 	of_reserved_mem_device_release(dev); | ||||
| } | ||||
| @@ -533,11 +749,52 @@ static int malidp_platform_remove(struct platform_device *pdev) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int __maybe_unused malidp_pm_suspend(struct device *dev) | ||||
| { | ||||
| 	struct drm_device *drm = dev_get_drvdata(dev); | ||||
| 	struct malidp_drm *malidp = drm->dev_private; | ||||
| 
 | ||||
| 	drm_kms_helper_poll_disable(drm); | ||||
| 	console_lock(); | ||||
| 	drm_fbdev_cma_set_suspend(malidp->fbdev, 1); | ||||
| 	console_unlock(); | ||||
| 	malidp->pm_state = drm_atomic_helper_suspend(drm); | ||||
| 	if (IS_ERR(malidp->pm_state)) { | ||||
| 		console_lock(); | ||||
| 		drm_fbdev_cma_set_suspend(malidp->fbdev, 0); | ||||
| 		console_unlock(); | ||||
| 		drm_kms_helper_poll_enable(drm); | ||||
| 		return PTR_ERR(malidp->pm_state); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int __maybe_unused malidp_pm_resume(struct device *dev) | ||||
| { | ||||
| 	struct drm_device *drm = dev_get_drvdata(dev); | ||||
| 	struct malidp_drm *malidp = drm->dev_private; | ||||
| 
 | ||||
| 	drm_atomic_helper_resume(drm, malidp->pm_state); | ||||
| 	console_lock(); | ||||
| 	drm_fbdev_cma_set_suspend(malidp->fbdev, 0); | ||||
| 	console_unlock(); | ||||
| 	drm_kms_helper_poll_enable(drm); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct dev_pm_ops malidp_pm_ops = { | ||||
| 	SET_SYSTEM_SLEEP_PM_OPS(malidp_pm_suspend, malidp_pm_resume) \ | ||||
| 	SET_RUNTIME_PM_OPS(malidp_runtime_pm_suspend, malidp_runtime_pm_resume, NULL) | ||||
| }; | ||||
| 
 | ||||
| static struct platform_driver malidp_platform_driver = { | ||||
| 	.probe		= malidp_platform_probe, | ||||
| 	.remove		= malidp_platform_remove, | ||||
| 	.driver	= { | ||||
| 		.name = "mali-dp", | ||||
| 		.pm = &malidp_pm_ops, | ||||
| 		.of_match_table	= malidp_drm_of_match, | ||||
| 	}, | ||||
| }; | ||||
|   | ||||
| @@ -24,6 +24,8 @@ struct malidp_drm { | ||||
| 	struct drm_crtc crtc; | ||||
| 	wait_queue_head_t wq; | ||||
| 	atomic_t config_valid; | ||||
| 	struct drm_atomic_state *pm_state; | ||||
| 	u32 core_id; | ||||
| }; | ||||
| 
 | ||||
| #define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc) | ||||
| @@ -47,6 +49,17 @@ struct malidp_plane_state { | ||||
| #define to_malidp_plane(x) container_of(x, struct malidp_plane, base) | ||||
| #define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, base) | ||||
| 
 | ||||
| struct malidp_crtc_state { | ||||
| 	struct drm_crtc_state base; | ||||
| 	u32 gamma_coeffs[MALIDP_COEFFTAB_NUM_COEFFS]; | ||||
| 	u32 coloradj_coeffs[MALIDP_COLORADJ_NUM_COEFFS]; | ||||
| 	struct malidp_se_config scaler_config; | ||||
| 	/* Bitfield of all the planes that have requested a scaled output. */ | ||||
| 	u8 scaled_planes_mask; | ||||
| }; | ||||
| 
 | ||||
| #define to_malidp_crtc_state(x) container_of(x, struct malidp_crtc_state, base) | ||||
| 
 | ||||
| int malidp_de_planes_init(struct drm_device *drm); | ||||
| void malidp_de_planes_destroy(struct drm_device *drm); | ||||
| int malidp_crtc_init(struct drm_device *drm); | ||||
|   | ||||
| @@ -12,6 +12,7 @@ | ||||
|  * in an attempt to provide to the rest of the driver code a unified view | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/clk.h> | ||||
| #include <linux/types.h> | ||||
| #include <linux/io.h> | ||||
| #include <drm/drmP.h> | ||||
| @@ -86,6 +87,80 @@ static const struct malidp_layer malidp550_layers[] = { | ||||
| 	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE }, | ||||
| }; | ||||
| 
 | ||||
| #define SE_N_SCALING_COEFFS	96 | ||||
| static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = { | ||||
| 	[MALIDP_UPSCALING_COEFFS - 1] = { | ||||
| 		0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052, | ||||
| 		0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f, | ||||
| 		0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a, | ||||
| 		0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40, | ||||
| 		0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c, | ||||
| 		0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5, | ||||
| 		0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15, | ||||
| 		0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5, | ||||
| 		0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0, | ||||
| 		0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6, | ||||
| 		0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073, | ||||
| 		0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001 | ||||
| 	}, | ||||
| 	[MALIDP_DOWNSCALING_1_5_COEFFS - 1] = { | ||||
| 		0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4, | ||||
| 		0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c, | ||||
| 		0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5, | ||||
| 		0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8, | ||||
| 		0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba, | ||||
| 		0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20, | ||||
| 		0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03, | ||||
| 		0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d, | ||||
| 		0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68, | ||||
| 		0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f, | ||||
| 		0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62, | ||||
| 		0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f | ||||
| 	}, | ||||
| 	[MALIDP_DOWNSCALING_2_COEFFS - 1] = { | ||||
| 		0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9, | ||||
| 		0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52, | ||||
| 		0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158, | ||||
| 		0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455, | ||||
| 		0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e, | ||||
| 		0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887, | ||||
| 		0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5, | ||||
| 		0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e, | ||||
| 		0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d, | ||||
| 		0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0, | ||||
| 		0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf, | ||||
| 		0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03 | ||||
| 	}, | ||||
| 	[MALIDP_DOWNSCALING_2_75_COEFFS - 1] = { | ||||
| 		0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3, | ||||
| 		0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106, | ||||
| 		0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280, | ||||
| 		0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410, | ||||
| 		0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533, | ||||
| 		0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3, | ||||
| 		0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566, | ||||
| 		0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468, | ||||
| 		0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4, | ||||
| 		0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160, | ||||
| 		0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f, | ||||
| 		0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60 | ||||
| 	}, | ||||
| 	[MALIDP_DOWNSCALING_4_COEFFS - 1] = { | ||||
| 		0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f, | ||||
| 		0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff, | ||||
| 		0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd, | ||||
| 		0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374, | ||||
| 		0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db, | ||||
| 		0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a, | ||||
| 		0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed, | ||||
| 		0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397, | ||||
| 		0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb, | ||||
| 		0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233, | ||||
| 		0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160, | ||||
| 		0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9 | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| #define MALIDP_DE_DEFAULT_PREFETCH_START	5 | ||||
| 
 | ||||
| static int malidp500_query_hw(struct malidp_hw_device *hwdev) | ||||
| @@ -211,6 +286,88 @@ static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 | ||||
| 	return w * drm_format_plane_cpp(fmt, 0) * 8; | ||||
| } | ||||
| 
 | ||||
| static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev, | ||||
| 					   u32 direction, | ||||
| 					   u16 addr, | ||||
| 					   u8 coeffs_id) | ||||
| { | ||||
| 	int i; | ||||
| 	u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL; | ||||
| 
 | ||||
| 	malidp_hw_write(hwdev, | ||||
| 			direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK), | ||||
| 			scaling_control + MALIDP_SE_COEFFTAB_ADDR); | ||||
| 	for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i) | ||||
| 		malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA( | ||||
| 				dp500_se_scaling_coeffs[coeffs_id][i]), | ||||
| 				scaling_control + MALIDP_SE_COEFFTAB_DATA); | ||||
| } | ||||
| 
 | ||||
| static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, | ||||
| 					   struct malidp_se_config *se_config, | ||||
| 					   struct malidp_se_config *old_config) | ||||
| { | ||||
| 	/* Get array indices into dp500_se_scaling_coeffs. */ | ||||
| 	u8 h = (u8)se_config->hcoeff - 1; | ||||
| 	u8 v = (u8)se_config->vcoeff - 1; | ||||
| 
 | ||||
| 	if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) || | ||||
| 		    v >= ARRAY_SIZE(dp500_se_scaling_coeffs))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if ((h == v) && (se_config->hcoeff != old_config->hcoeff || | ||||
| 			 se_config->vcoeff != old_config->vcoeff)) { | ||||
| 		malidp500_se_write_pp_coefftab(hwdev, | ||||
| 					       (MALIDP_SE_V_COEFFTAB | | ||||
| 						MALIDP_SE_H_COEFFTAB), | ||||
| 					       0, v); | ||||
| 	} else { | ||||
| 		if (se_config->vcoeff != old_config->vcoeff) | ||||
| 			malidp500_se_write_pp_coefftab(hwdev, | ||||
| 						       MALIDP_SE_V_COEFFTAB, | ||||
| 						       0, v); | ||||
| 		if (se_config->hcoeff != old_config->hcoeff) | ||||
| 			malidp500_se_write_pp_coefftab(hwdev, | ||||
| 						       MALIDP_SE_H_COEFFTAB, | ||||
| 						       0, h); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev, | ||||
| 				   struct malidp_se_config *se_config, | ||||
| 				   struct videomode *vm) | ||||
| { | ||||
| 	unsigned long mclk; | ||||
| 	unsigned long pxlclk = vm->pixelclock; /* Hz */ | ||||
| 	unsigned long htotal = vm->hactive + vm->hfront_porch + | ||||
| 			       vm->hback_porch + vm->hsync_len; | ||||
| 	unsigned long input_size = se_config->input_w * se_config->input_h; | ||||
| 	unsigned long a = 10; | ||||
| 	long ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * mclk = max(a, 1.5) * pxlclk | ||||
| 	 * | ||||
| 	 * To avoid float calculaiton, using 15 instead of 1.5 and div by | ||||
| 	 * 10 to get mclk. | ||||
| 	 */ | ||||
| 	if (se_config->scale_enable) { | ||||
| 		a = 15 * input_size / (htotal * se_config->output_h); | ||||
| 		if (a < 15) | ||||
| 			a = 15; | ||||
| 	} | ||||
| 	mclk = a * pxlclk / 10; | ||||
| 	ret = clk_get_rate(hwdev->mclk); | ||||
| 	if (ret < mclk) { | ||||
| 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", | ||||
| 				 mclk / 1000); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int malidp550_query_hw(struct malidp_hw_device *hwdev) | ||||
| { | ||||
| 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); | ||||
| @@ -384,6 +541,53 @@ static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 | ||||
| 	return w * bytes_per_col; | ||||
| } | ||||
| 
 | ||||
| static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev, | ||||
| 					   struct malidp_se_config *se_config, | ||||
| 					   struct malidp_se_config *old_config) | ||||
| { | ||||
| 	u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) | | ||||
| 		   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK); | ||||
| 	u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) | | ||||
| 			MALIDP550_SE_CTL_HCSEL(se_config->hcoeff); | ||||
| 
 | ||||
| 	malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL); | ||||
| 	malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev, | ||||
| 				   struct malidp_se_config *se_config, | ||||
| 				   struct videomode *vm) | ||||
| { | ||||
| 	unsigned long mclk; | ||||
| 	unsigned long pxlclk = vm->pixelclock; | ||||
| 	unsigned long htotal = vm->hactive + vm->hfront_porch + | ||||
| 			       vm->hback_porch + vm->hsync_len; | ||||
| 	unsigned long numerator = 1, denominator = 1; | ||||
| 	long ret; | ||||
| 
 | ||||
| 	if (se_config->scale_enable) { | ||||
| 		numerator = max(se_config->input_w, se_config->output_w) * | ||||
| 			    se_config->input_h; | ||||
| 		numerator += se_config->output_w * | ||||
| 			     (se_config->output_h - | ||||
| 			      min(se_config->input_h, se_config->output_h)); | ||||
| 		denominator = (htotal - 2) * se_config->output_h; | ||||
| 	} | ||||
| 
 | ||||
| 	/* mclk can't be slower than pxlclk. */ | ||||
| 	if (numerator < denominator) | ||||
| 		numerator = denominator = 1; | ||||
| 	mclk = (pxlclk * numerator) / denominator; | ||||
| 	ret = clk_get_rate(hwdev->mclk); | ||||
| 	if (ret < mclk) { | ||||
| 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n", | ||||
| 				 mclk / 1000); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int malidp650_query_hw(struct malidp_hw_device *hwdev) | ||||
| { | ||||
| 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); | ||||
| @@ -415,6 +619,7 @@ static int malidp650_query_hw(struct malidp_hw_device *hwdev) | ||||
| const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { | ||||
| 	[MALIDP_500] = { | ||||
| 		.map = { | ||||
| 			.coeffs_base = MALIDP500_COEFFS_BASE, | ||||
| 			.se_base = MALIDP500_SE_BASE, | ||||
| 			.dc_base = MALIDP500_DC_BASE, | ||||
| 			.out_depth_base = MALIDP500_OUTPUT_DEPTH, | ||||
| @@ -447,10 +652,13 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { | ||||
| 		.set_config_valid = malidp500_set_config_valid, | ||||
| 		.modeset = malidp500_modeset, | ||||
| 		.rotmem_required = malidp500_rotmem_required, | ||||
| 		.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs, | ||||
| 		.se_calc_mclk = malidp500_se_calc_mclk, | ||||
| 		.features = MALIDP_DEVICE_LV_HAS_3_STRIDES, | ||||
| 	}, | ||||
| 	[MALIDP_550] = { | ||||
| 		.map = { | ||||
| 			.coeffs_base = MALIDP550_COEFFS_BASE, | ||||
| 			.se_base = MALIDP550_SE_BASE, | ||||
| 			.dc_base = MALIDP550_DC_BASE, | ||||
| 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, | ||||
| @@ -481,10 +689,13 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { | ||||
| 		.set_config_valid = malidp550_set_config_valid, | ||||
| 		.modeset = malidp550_modeset, | ||||
| 		.rotmem_required = malidp550_rotmem_required, | ||||
| 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, | ||||
| 		.se_calc_mclk = malidp550_se_calc_mclk, | ||||
| 		.features = 0, | ||||
| 	}, | ||||
| 	[MALIDP_650] = { | ||||
| 		.map = { | ||||
| 			.coeffs_base = MALIDP550_COEFFS_BASE, | ||||
| 			.se_base = MALIDP550_SE_BASE, | ||||
| 			.dc_base = MALIDP550_DC_BASE, | ||||
| 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, | ||||
| @@ -516,6 +727,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { | ||||
| 		.set_config_valid = malidp550_set_config_valid, | ||||
| 		.modeset = malidp550_modeset, | ||||
| 		.rotmem_required = malidp550_rotmem_required, | ||||
| 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs, | ||||
| 		.se_calc_mclk = malidp550_se_calc_mclk, | ||||
| 		.features = 0, | ||||
| 	}, | ||||
| }; | ||||
|   | ||||
| @@ -61,12 +61,34 @@ struct malidp_layer { | ||||
| 	u16 stride_offset;	/* Offset to the first stride register. */ | ||||
| }; | ||||
| 
 | ||||
| enum malidp_scaling_coeff_set { | ||||
| 	MALIDP_UPSCALING_COEFFS = 1, | ||||
| 	MALIDP_DOWNSCALING_1_5_COEFFS = 2, | ||||
| 	MALIDP_DOWNSCALING_2_COEFFS = 3, | ||||
| 	MALIDP_DOWNSCALING_2_75_COEFFS = 4, | ||||
| 	MALIDP_DOWNSCALING_4_COEFFS = 5, | ||||
| }; | ||||
| 
 | ||||
| struct malidp_se_config { | ||||
| 	u8 scale_enable : 1; | ||||
| 	u8 enhancer_enable : 1; | ||||
| 	u8 hcoeff : 3; | ||||
| 	u8 vcoeff : 3; | ||||
| 	u8 plane_src_id; | ||||
| 	u16 input_w, input_h; | ||||
| 	u16 output_w, output_h; | ||||
| 	u32 h_init_phase, h_delta_phase; | ||||
| 	u32 v_init_phase, v_delta_phase; | ||||
| }; | ||||
| 
 | ||||
| /* regmap features */ | ||||
| #define MALIDP_REGMAP_HAS_CLEARIRQ	(1 << 0) | ||||
| 
 | ||||
| struct malidp_hw_regmap { | ||||
| 	/* address offset of the DE register bank */ | ||||
| 	/* is always 0x0000 */ | ||||
| 	/* address offset of the DE coefficients registers */ | ||||
| 	const u16 coeffs_base; | ||||
| 	/* address offset of the SE registers bank */ | ||||
| 	const u16 se_base; | ||||
| 	/* address offset of the DC registers bank */ | ||||
| @@ -151,11 +173,22 @@ struct malidp_hw_device { | ||||
| 	 */ | ||||
| 	int (*rotmem_required)(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt); | ||||
| 
 | ||||
| 	int (*se_set_scaling_coeffs)(struct malidp_hw_device *hwdev, | ||||
| 				     struct malidp_se_config *se_config, | ||||
| 				     struct malidp_se_config *old_config); | ||||
| 
 | ||||
| 	long (*se_calc_mclk)(struct malidp_hw_device *hwdev, | ||||
| 			     struct malidp_se_config *se_config, | ||||
| 			     struct videomode *vm); | ||||
| 
 | ||||
| 	u8 features; | ||||
| 
 | ||||
| 	u8 min_line_size; | ||||
| 	u16 max_line_size; | ||||
| 
 | ||||
| 	/* track the device PM state */ | ||||
| 	bool pm_suspended; | ||||
| 
 | ||||
| 	/* size of memory used for rotating layers, up to two banks available */ | ||||
| 	u32 rotation_memory[2]; | ||||
| }; | ||||
| @@ -173,12 +206,14 @@ extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES]; | ||||
| 
 | ||||
| static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg) | ||||
| { | ||||
| 	WARN_ON(hwdev->pm_suspended); | ||||
| 	return readl(hwdev->regs + reg); | ||||
| } | ||||
| 
 | ||||
| static inline void malidp_hw_write(struct malidp_hw_device *hwdev, | ||||
| 				   u32 value, u32 reg) | ||||
| { | ||||
| 	WARN_ON(hwdev->pm_suspended); | ||||
| 	writel(value, hwdev->regs + reg); | ||||
| } | ||||
| 
 | ||||
| @@ -243,6 +278,47 @@ static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev, | ||||
| 	return !(pitch & (hwdev->map.bus_align_bytes - 1)); | ||||
| } | ||||
| 
 | ||||
| /* U16.16 */ | ||||
| #define FP_1_00000	0x00010000	/* 1.0 */ | ||||
| #define FP_0_66667	0x0000AAAA	/* 0.6667 = 1/1.5 */ | ||||
| #define FP_0_50000	0x00008000	/* 0.5 = 1/2 */ | ||||
| #define FP_0_36363	0x00005D17	/* 0.36363 = 1/2.75 */ | ||||
| #define FP_0_25000	0x00004000	/* 0.25 = 1/4 */ | ||||
| 
 | ||||
| static inline enum malidp_scaling_coeff_set | ||||
| malidp_se_select_coeffs(u32 upscale_factor) | ||||
| { | ||||
| 	return (upscale_factor >= FP_1_00000) ? MALIDP_UPSCALING_COEFFS : | ||||
| 	       (upscale_factor >= FP_0_66667) ? MALIDP_DOWNSCALING_1_5_COEFFS : | ||||
| 	       (upscale_factor >= FP_0_50000) ? MALIDP_DOWNSCALING_2_COEFFS : | ||||
| 	       (upscale_factor >= FP_0_36363) ? MALIDP_DOWNSCALING_2_75_COEFFS : | ||||
| 	       MALIDP_DOWNSCALING_4_COEFFS; | ||||
| } | ||||
| 
 | ||||
| #undef FP_0_25000 | ||||
| #undef FP_0_36363 | ||||
| #undef FP_0_50000 | ||||
| #undef FP_0_66667 | ||||
| #undef FP_1_00000 | ||||
| 
 | ||||
| static inline void malidp_se_set_enh_coeffs(struct malidp_hw_device *hwdev) | ||||
| { | ||||
| 	static const s32 enhancer_coeffs[] = { | ||||
| 		-8, -8, -8, -8, 128, -8, -8, -8, -8 | ||||
| 	}; | ||||
| 	u32 val = MALIDP_SE_SET_ENH_LIMIT_LOW(MALIDP_SE_ENH_LOW_LEVEL) | | ||||
| 		  MALIDP_SE_SET_ENH_LIMIT_HIGH(MALIDP_SE_ENH_HIGH_LEVEL); | ||||
| 	u32 image_enh = hwdev->map.se_base + | ||||
| 			((hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ) ? | ||||
| 			 0x10 : 0xC) + MALIDP_SE_IMAGE_ENH; | ||||
| 	u32 enh_coeffs = image_enh + MALIDP_SE_ENH_COEFF0; | ||||
| 	int i; | ||||
| 
 | ||||
| 	malidp_hw_write(hwdev, val, image_enh); | ||||
| 	for (i = 0; i < ARRAY_SIZE(enhancer_coeffs); ++i) | ||||
| 		malidp_hw_write(hwdev, enhancer_coeffs[i], enh_coeffs + i * 4); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * background color components are defined as 12bits values, | ||||
|  * they will be shifted right when stored on hardware that | ||||
| @@ -252,4 +328,9 @@ static inline bool malidp_hw_pitch_valid(struct malidp_hw_device *hwdev, | ||||
| #define MALIDP_BGND_COLOR_G		0x000 | ||||
| #define MALIDP_BGND_COLOR_B		0x000 | ||||
| 
 | ||||
| #define MALIDP_COLORADJ_NUM_COEFFS	12 | ||||
| #define MALIDP_COEFFTAB_NUM_COEFFS	64 | ||||
| 
 | ||||
| #define MALIDP_GAMMA_LUT_SIZE		4096 | ||||
| 
 | ||||
| #endif  /* __MALIDP_HW_H__ */ | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
| #include <drm/drm_fb_cma_helper.h> | ||||
| #include <drm/drm_gem_cma_helper.h> | ||||
| #include <drm/drm_plane_helper.h> | ||||
| #include <drm/drm_print.h> | ||||
| 
 | ||||
| #include "malidp_hw.h" | ||||
| #include "malidp_drv.h" | ||||
| @@ -24,6 +25,9 @@ | ||||
| #define MALIDP_LAYER_FORMAT		0x000 | ||||
| #define MALIDP_LAYER_CONTROL		0x004 | ||||
| #define   LAYER_ENABLE			(1 << 0) | ||||
| #define   LAYER_FLOWCFG_MASK		7 | ||||
| #define   LAYER_FLOWCFG(x)		(((x) & LAYER_FLOWCFG_MASK) << 1) | ||||
| #define     LAYER_FLOWCFG_SCALE_SE	3 | ||||
| #define   LAYER_ROT_OFFSET		8 | ||||
| #define   LAYER_H_FLIP			(1 << 10) | ||||
| #define   LAYER_V_FLIP			(1 << 11) | ||||
| @@ -60,6 +64,27 @@ static void malidp_de_plane_destroy(struct drm_plane *plane) | ||||
| 	devm_kfree(plane->dev->dev, mp); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Replicate what the default ->reset hook does: free the state pointer and | ||||
|  * allocate a new empty object. We just need enough space to store | ||||
|  * a malidp_plane_state instead of a drm_plane_state. | ||||
|  */ | ||||
| static void malidp_plane_reset(struct drm_plane *plane) | ||||
| { | ||||
| 	struct malidp_plane_state *state = to_malidp_plane_state(plane->state); | ||||
| 
 | ||||
| 	if (state) | ||||
| 		__drm_atomic_helper_plane_destroy_state(&state->base); | ||||
| 	kfree(state); | ||||
| 	plane->state = NULL; | ||||
| 	state = kzalloc(sizeof(*state), GFP_KERNEL); | ||||
| 	if (state) { | ||||
| 		state->base.plane = plane; | ||||
| 		state->base.rotation = DRM_ROTATE_0; | ||||
| 		plane->state = &state->base; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static struct | ||||
| drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) | ||||
| { | ||||
| @@ -90,26 +115,71 @@ static void malidp_destroy_plane_state(struct drm_plane *plane, | ||||
| 	kfree(m_state); | ||||
| } | ||||
| 
 | ||||
| static void malidp_plane_atomic_print_state(struct drm_printer *p, | ||||
| 					    const struct drm_plane_state *state) | ||||
| { | ||||
| 	struct malidp_plane_state *ms = to_malidp_plane_state(state); | ||||
| 
 | ||||
| 	drm_printf(p, "\trotmem_size=%u\n", ms->rotmem_size); | ||||
| 	drm_printf(p, "\tformat_id=%u\n", ms->format); | ||||
| 	drm_printf(p, "\tn_planes=%u\n", ms->n_planes); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_plane_funcs malidp_de_plane_funcs = { | ||||
| 	.update_plane = drm_atomic_helper_update_plane, | ||||
| 	.disable_plane = drm_atomic_helper_disable_plane, | ||||
| 	.set_property = drm_atomic_helper_plane_set_property, | ||||
| 	.destroy = malidp_de_plane_destroy, | ||||
| 	.reset = drm_atomic_helper_plane_reset, | ||||
| 	.reset = malidp_plane_reset, | ||||
| 	.atomic_duplicate_state = malidp_duplicate_plane_state, | ||||
| 	.atomic_destroy_state = malidp_destroy_plane_state, | ||||
| 	.atomic_print_state = malidp_plane_atomic_print_state, | ||||
| }; | ||||
| 
 | ||||
| static int malidp_se_check_scaling(struct malidp_plane *mp, | ||||
| 				   struct drm_plane_state *state) | ||||
| { | ||||
| 	struct drm_crtc_state *crtc_state = | ||||
| 		drm_atomic_get_existing_crtc_state(state->state, state->crtc); | ||||
| 	struct malidp_crtc_state *mc; | ||||
| 	struct drm_rect clip = { 0 }; | ||||
| 	u32 src_w, src_h; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!crtc_state) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	clip.x2 = crtc_state->adjusted_mode.hdisplay; | ||||
| 	clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||||
| 	ret = drm_plane_helper_check_state(state, &clip, 0, INT_MAX, true, true); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	src_w = state->src_w >> 16; | ||||
| 	src_h = state->src_h >> 16; | ||||
| 	if ((state->crtc_w == src_w) && (state->crtc_h == src_h)) { | ||||
| 		/* Scaling not necessary for this plane. */ | ||||
| 		mc->scaled_planes_mask &= ~(mp->layer->id); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (mp->layer->id & (DE_SMART | DE_GRAPHICS2)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	mc = to_malidp_crtc_state(crtc_state); | ||||
| 
 | ||||
| 	mc->scaled_planes_mask |= mp->layer->id; | ||||
| 	/* Defer scaling requirements calculation to the crtc check. */ | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int malidp_de_plane_check(struct drm_plane *plane, | ||||
| 				 struct drm_plane_state *state) | ||||
| { | ||||
| 	struct malidp_plane *mp = to_malidp_plane(plane); | ||||
| 	struct malidp_plane_state *ms = to_malidp_plane_state(state); | ||||
| 	struct drm_crtc_state *crtc_state; | ||||
| 	struct drm_framebuffer *fb; | ||||
| 	struct drm_rect clip = { 0 }; | ||||
| 	int i, ret; | ||||
| 	u32 src_w, src_h; | ||||
| 
 | ||||
| 	if (!state->crtc || !state->fb) | ||||
| 		return 0; | ||||
| @@ -130,9 +200,6 @@ static int malidp_de_plane_check(struct drm_plane *plane, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	src_w = state->src_w >> 16; | ||||
| 	src_h = state->src_h >> 16; | ||||
| 
 | ||||
| 	if ((state->crtc_w > mp->hwdev->max_line_size) || | ||||
| 	    (state->crtc_h > mp->hwdev->max_line_size) || | ||||
| 	    (state->crtc_w < mp->hwdev->min_line_size) || | ||||
| @@ -149,22 +216,16 @@ static int malidp_de_plane_check(struct drm_plane *plane, | ||||
| 	    (state->fb->pitches[1] != state->fb->pitches[2])) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	ret = malidp_se_check_scaling(mp, state); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/* packed RGB888 / BGR888 can't be rotated or flipped */ | ||||
| 	if (state->rotation != DRM_ROTATE_0 && | ||||
| 	    (fb->format->format == DRM_FORMAT_RGB888 || | ||||
| 	     fb->format->format == DRM_FORMAT_BGR888)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc); | ||||
| 	clip.x2 = crtc_state->adjusted_mode.hdisplay; | ||||
| 	clip.y2 = crtc_state->adjusted_mode.vdisplay; | ||||
| 	ret = drm_plane_helper_check_state(state, &clip, | ||||
| 					   DRM_PLANE_HELPER_NO_SCALING, | ||||
| 					   DRM_PLANE_HELPER_NO_SCALING, | ||||
| 					   true, true); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ms->rotmem_size = 0; | ||||
| 	if (state->rotation & MALIDP_ROTATED_MASK) { | ||||
| 		int val; | ||||
| @@ -269,6 +330,16 @@ static void malidp_de_plane_update(struct drm_plane *plane, | ||||
| 	val &= ~LAYER_COMP_MASK; | ||||
| 	val |= LAYER_COMP_PIXEL; | ||||
| 
 | ||||
| 	val &= ~LAYER_FLOWCFG(LAYER_FLOWCFG_MASK); | ||||
| 	if (plane->state->crtc) { | ||||
| 		struct malidp_crtc_state *m = | ||||
| 			to_malidp_crtc_state(plane->state->crtc->state); | ||||
| 
 | ||||
| 		if (m->scaler_config.scale_enable && | ||||
| 		    m->scaler_config.plane_src_id == mp->layer->id) | ||||
| 			val |= LAYER_FLOWCFG(LAYER_FLOWCFG_SCALE_SE); | ||||
| 	} | ||||
| 
 | ||||
| 	/* set the 'enable layer' bit */ | ||||
| 	val |= LAYER_ENABLE; | ||||
| 
 | ||||
| @@ -281,7 +352,8 @@ static void malidp_de_plane_disable(struct drm_plane *plane, | ||||
| { | ||||
| 	struct malidp_plane *mp = to_malidp_plane(plane); | ||||
| 
 | ||||
| 	malidp_hw_clearbits(mp->hwdev, LAYER_ENABLE, | ||||
| 	malidp_hw_clearbits(mp->hwdev, | ||||
| 			    LAYER_ENABLE | LAYER_FLOWCFG(LAYER_FLOWCFG_MASK), | ||||
| 			    mp->layer->base + MALIDP_LAYER_CONTROL); | ||||
| } | ||||
| 
 | ||||
|   | ||||
| @@ -63,6 +63,8 @@ | ||||
| 
 | ||||
| /* bit masks that are common between products */ | ||||
| #define   MALIDP_CFG_VALID		(1 << 0) | ||||
| #define   MALIDP_DISP_FUNC_GAMMA	(1 << 0) | ||||
| #define   MALIDP_DISP_FUNC_CADJ		(1 << 4) | ||||
| #define   MALIDP_DISP_FUNC_ILACED	(1 << 8) | ||||
| 
 | ||||
| /* register offsets for IRQ management */ | ||||
| @@ -99,6 +101,58 @@ | ||||
| 
 | ||||
| #define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16) | ||||
| 
 | ||||
| /* register offsets relative to MALIDP5x0_COEFFS_BASE */ | ||||
| #define MALIDP_COLOR_ADJ_COEF		0x00000 | ||||
| #define MALIDP_COEF_TABLE_ADDR		0x00030 | ||||
| #define MALIDP_COEF_TABLE_DATA		0x00034 | ||||
| 
 | ||||
| /* Scaling engine registers and masks. */ | ||||
| #define   MALIDP_SE_SCALING_EN			(1 << 0) | ||||
| #define   MALIDP_SE_ALPHA_EN			(1 << 1) | ||||
| #define   MALIDP_SE_ENH_MASK			3 | ||||
| #define   MALIDP_SE_ENH(x)			(((x) & MALIDP_SE_ENH_MASK) << 2) | ||||
| #define   MALIDP_SE_RGBO_IF_EN			(1 << 4) | ||||
| #define   MALIDP550_SE_CTL_SEL_MASK		7 | ||||
| #define   MALIDP550_SE_CTL_VCSEL(x) \ | ||||
| 		(((x) & MALIDP550_SE_CTL_SEL_MASK) << 20) | ||||
| #define   MALIDP550_SE_CTL_HCSEL(x) \ | ||||
| 		(((x) & MALIDP550_SE_CTL_SEL_MASK) << 16) | ||||
| 
 | ||||
| /* Blocks with offsets from SE_CONTROL register. */ | ||||
| #define MALIDP_SE_LAYER_CONTROL			0x14 | ||||
| #define   MALIDP_SE_L0_IN_SIZE			0x00 | ||||
| #define   MALIDP_SE_L0_OUT_SIZE			0x04 | ||||
| #define   MALIDP_SE_SET_V_SIZE(x)		(((x) & 0x1fff) << 16) | ||||
| #define   MALIDP_SE_SET_H_SIZE(x)		(((x) & 0x1fff) << 0) | ||||
| #define MALIDP_SE_SCALING_CONTROL		0x24 | ||||
| #define   MALIDP_SE_H_INIT_PH			0x00 | ||||
| #define   MALIDP_SE_H_DELTA_PH			0x04 | ||||
| #define   MALIDP_SE_V_INIT_PH			0x08 | ||||
| #define   MALIDP_SE_V_DELTA_PH			0x0c | ||||
| #define   MALIDP_SE_COEFFTAB_ADDR		0x10 | ||||
| #define     MALIDP_SE_COEFFTAB_ADDR_MASK	0x7f | ||||
| #define     MALIDP_SE_V_COEFFTAB		(1 << 8) | ||||
| #define     MALIDP_SE_H_COEFFTAB		(1 << 9) | ||||
| #define     MALIDP_SE_SET_V_COEFFTAB_ADDR(x) \ | ||||
| 		(MALIDP_SE_V_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK)) | ||||
| #define     MALIDP_SE_SET_H_COEFFTAB_ADDR(x) \ | ||||
| 		(MALIDP_SE_H_COEFFTAB | ((x) & MALIDP_SE_COEFFTAB_ADDR_MASK)) | ||||
| #define   MALIDP_SE_COEFFTAB_DATA		0x14 | ||||
| #define     MALIDP_SE_COEFFTAB_DATA_MASK	0x3fff | ||||
| #define     MALIDP_SE_SET_COEFFTAB_DATA(x) \ | ||||
| 		((x) & MALIDP_SE_COEFFTAB_DATA_MASK) | ||||
| /* Enhance coeffents reigster offset */ | ||||
| #define MALIDP_SE_IMAGE_ENH			0x3C | ||||
| /* ENH_LIMITS offset 0x0 */ | ||||
| #define     MALIDP_SE_ENH_LOW_LEVEL		24 | ||||
| #define     MALIDP_SE_ENH_HIGH_LEVEL		63 | ||||
| #define     MALIDP_SE_ENH_LIMIT_MASK		0xfff | ||||
| #define     MALIDP_SE_SET_ENH_LIMIT_LOW(x) \ | ||||
| 		((x) & MALIDP_SE_ENH_LIMIT_MASK) | ||||
| #define     MALIDP_SE_SET_ENH_LIMIT_HIGH(x) \ | ||||
| 		(((x) & MALIDP_SE_ENH_LIMIT_MASK) << 16) | ||||
| #define   MALIDP_SE_ENH_COEFF0			0x04 | ||||
| 
 | ||||
| /* register offsets and bits specific to DP500 */ | ||||
| #define MALIDP500_ADDR_SPACE_SIZE	0x01000 | ||||
| #define MALIDP500_DC_BASE		0x00000 | ||||
| @@ -120,6 +174,18 @@ | ||||
| #define MALIDP500_COLOR_ADJ_COEF	0x00078 | ||||
| #define MALIDP500_COEF_TABLE_ADDR	0x000a8 | ||||
| #define MALIDP500_COEF_TABLE_DATA	0x000ac | ||||
| 
 | ||||
| /*
 | ||||
|  * The YUV2RGB coefficients on the DP500 are not in the video layer's register | ||||
|  * block. They belong in a separate block above the layer's registers, hence | ||||
|  * the negative offset. | ||||
|  */ | ||||
| #define MALIDP500_LV_YUV2RGB		((s16)(-0xB8)) | ||||
| /*
 | ||||
|  * To match DP550/650, the start of the coeffs registers is | ||||
|  * at COLORADJ_COEFF0 instead of at YUV_RGB_COEF1. | ||||
|  */ | ||||
| #define MALIDP500_COEFFS_BASE		0x00078 | ||||
| #define MALIDP500_DE_LV_BASE		0x00100 | ||||
| #define MALIDP500_DE_LV_PTR_BASE	0x00124 | ||||
| #define MALIDP500_DE_LG1_BASE		0x00200 | ||||
| @@ -127,6 +193,7 @@ | ||||
| #define MALIDP500_DE_LG2_BASE		0x00300 | ||||
| #define MALIDP500_DE_LG2_PTR_BASE	0x0031c | ||||
| #define MALIDP500_SE_BASE		0x00c00 | ||||
| #define MALIDP500_SE_CONTROL		0x00c0c | ||||
| #define MALIDP500_SE_PTR_BASE		0x00e0c | ||||
| #define MALIDP500_DC_IRQ_BASE		0x00f00 | ||||
| #define MALIDP500_CONFIG_VALID		0x00f00 | ||||
| @@ -145,9 +212,7 @@ | ||||
| #define MALIDP550_DE_DISP_SIDEBAND	0x00040 | ||||
| #define MALIDP550_DE_BGND_COLOR		0x00044 | ||||
| #define MALIDP550_DE_OUTPUT_DEPTH	0x0004c | ||||
| #define MALIDP550_DE_COLOR_COEF		0x00050 | ||||
| #define MALIDP550_DE_COEF_TABLE_ADDR	0x00080 | ||||
| #define MALIDP550_DE_COEF_TABLE_DATA	0x00084 | ||||
| #define MALIDP550_COEFFS_BASE		0x00050 | ||||
| #define MALIDP550_DE_LV1_BASE		0x00100 | ||||
| #define MALIDP550_DE_LV1_PTR_BASE	0x00124 | ||||
| #define MALIDP550_DE_LV2_BASE		0x00200 | ||||
| @@ -158,6 +223,7 @@ | ||||
| #define MALIDP550_DE_LS_PTR_BASE	0x0042c | ||||
| #define MALIDP550_DE_PERF_BASE		0x00500 | ||||
| #define MALIDP550_SE_BASE		0x08000 | ||||
| #define MALIDP550_SE_CONTROL		0x08010 | ||||
| #define MALIDP550_DC_BASE		0x0c000 | ||||
| #define MALIDP550_DC_CONTROL		0x0c010 | ||||
| #define   MALIDP550_DC_CONFIG_REQ	(1 << 16) | ||||
|   | ||||
| @@ -529,10 +529,10 @@ static const struct dma_buf_ops armada_gem_prime_dmabuf_ops = { | ||||
| 	.map_dma_buf	= armada_gem_prime_map_dma_buf, | ||||
| 	.unmap_dma_buf	= armada_gem_prime_unmap_dma_buf, | ||||
| 	.release	= drm_gem_dmabuf_release, | ||||
| 	.kmap_atomic	= armada_gem_dmabuf_no_kmap, | ||||
| 	.kunmap_atomic	= armada_gem_dmabuf_no_kunmap, | ||||
| 	.kmap		= armada_gem_dmabuf_no_kmap, | ||||
| 	.kunmap		= armada_gem_dmabuf_no_kunmap, | ||||
| 	.map_atomic	= armada_gem_dmabuf_no_kmap, | ||||
| 	.unmap_atomic	= armada_gem_dmabuf_no_kunmap, | ||||
| 	.map		= armada_gem_dmabuf_no_kmap, | ||||
| 	.unmap		= armada_gem_dmabuf_no_kunmap, | ||||
| 	.mmap		= armada_gem_dmabuf_mmap, | ||||
| }; | ||||
| 
 | ||||
|   | ||||
| @@ -221,7 +221,8 @@ err_encoder_cleanup: | ||||
| int atmel_hlcdc_create_outputs(struct drm_device *dev) | ||||
| { | ||||
| 	struct device_node *remote; | ||||
| 	int ret, endpoint = 0; | ||||
| 	int ret = -ENODEV; | ||||
| 	int endpoint = 0; | ||||
| 
 | ||||
| 	while (true) { | ||||
| 		/* Loop thru possible multiple connections to the output */ | ||||
| @@ -236,7 +237,5 @@ int atmel_hlcdc_create_outputs(struct drm_device *dev) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!endpoint) | ||||
| 		return -ENODEV; | ||||
| 	return ret; | ||||
| } | ||||
|   | ||||
| @@ -1947,6 +1947,20 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, | ||||
| 				      const struct drm_display_mode *orig_mode, | ||||
| 				      struct drm_display_mode *mode) | ||||
| { | ||||
| 	struct dw_hdmi *hdmi = bridge->driver_private; | ||||
| 	struct drm_connector *connector = &hdmi->connector; | ||||
| 	enum drm_mode_status status; | ||||
| 
 | ||||
| 	status = dw_hdmi_connector_mode_valid(connector, mode); | ||||
| 	if (status != MODE_OK) | ||||
| 		return false; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge, | ||||
| 				    struct drm_display_mode *orig_mode, | ||||
| 				    struct drm_display_mode *mode) | ||||
| @@ -1988,6 +2002,7 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = { | ||||
| 	.enable = dw_hdmi_bridge_enable, | ||||
| 	.disable = dw_hdmi_bridge_disable, | ||||
| 	.mode_set = dw_hdmi_bridge_mode_set, | ||||
| 	.mode_fixup = dw_hdmi_bridge_mode_fixup, | ||||
| }; | ||||
| 
 | ||||
| static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi) | ||||
|   | ||||
| @@ -403,10 +403,10 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  { | ||||
| 	.map_dma_buf = drm_gem_map_dma_buf, | ||||
| 	.unmap_dma_buf = drm_gem_unmap_dma_buf, | ||||
| 	.release = drm_gem_dmabuf_release, | ||||
| 	.kmap = drm_gem_dmabuf_kmap, | ||||
| 	.kmap_atomic = drm_gem_dmabuf_kmap_atomic, | ||||
| 	.kunmap = drm_gem_dmabuf_kunmap, | ||||
| 	.kunmap_atomic = drm_gem_dmabuf_kunmap_atomic, | ||||
| 	.map = drm_gem_dmabuf_kmap, | ||||
| 	.map_atomic = drm_gem_dmabuf_kmap_atomic, | ||||
| 	.unmap = drm_gem_dmabuf_kunmap, | ||||
| 	.unmap_atomic = drm_gem_dmabuf_kunmap_atomic, | ||||
| 	.mmap = drm_gem_dmabuf_mmap, | ||||
| 	.vmap = drm_gem_dmabuf_vmap, | ||||
| 	.vunmap = drm_gem_dmabuf_vunmap, | ||||
|   | ||||
| @@ -476,7 +476,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, | ||||
| 	    drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { | ||||
| 		list_for_each_entry(prop_enum, &property->enum_list, head) { | ||||
| 			enum_count++; | ||||
| 			if (out_resp->count_enum_blobs <= enum_count) | ||||
| 			if (out_resp->count_enum_blobs < enum_count) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (copy_to_user(&enum_ptr[copied].value, | ||||
|   | ||||
| @@ -1333,7 +1333,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, | ||||
| 	if (!fence) { | ||||
| 		event_free(gpu, event); | ||||
| 		ret = -ENOMEM; | ||||
| 		goto out_pm_put; | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	gpu->event[event].fence = fence; | ||||
| @@ -1373,6 +1373,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, | ||||
| 	hangcheck_timer_reset(gpu); | ||||
| 	ret = 0; | ||||
| 
 | ||||
| out_unlock: | ||||
| 	mutex_unlock(&gpu->lock); | ||||
| 
 | ||||
| out_pm_put: | ||||
|   | ||||
| @@ -285,9 +285,6 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset, | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (vgpu->failsafe) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (WARN_ON(bytes > 4)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
|   | ||||
| @@ -616,9 +616,6 @@ static inline u32 get_opcode(u32 cmd, int ring_id) | ||||
| { | ||||
| 	struct decode_info *d_info; | ||||
| 
 | ||||
| 	if (ring_id >= I915_NUM_ENGINES) | ||||
| 		return INVALID_OP; | ||||
| 
 | ||||
| 	d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)]; | ||||
| 	if (d_info == NULL) | ||||
| 		return INVALID_OP; | ||||
| @@ -661,9 +658,6 @@ static inline void print_opcode(u32 cmd, int ring_id) | ||||
| 	struct decode_info *d_info; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (ring_id >= I915_NUM_ENGINES) | ||||
| 		return; | ||||
| 
 | ||||
| 	d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)]; | ||||
| 	if (d_info == NULL) | ||||
| 		return; | ||||
| @@ -2483,7 +2477,7 @@ static int cmd_parser_exec(struct parser_exec_state *s) | ||||
| 
 | ||||
| 	t1 = get_cycles(); | ||||
| 
 | ||||
| 	memcpy(&s_before_advance_custom, s, sizeof(struct parser_exec_state)); | ||||
| 	s_before_advance_custom = *s; | ||||
| 
 | ||||
| 	if (info->handler) { | ||||
| 		ret = info->handler(s); | ||||
|   | ||||
| @@ -189,17 +189,44 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) | ||||
| 	} | ||||
| 
 | ||||
| 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) { | ||||
| 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTB_HOTPLUG_CPT; | ||||
| 		vgpu_vreg(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIB_DETECTED; | ||||
| 		vgpu_vreg(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &= | ||||
| 			~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK | | ||||
| 			TRANS_DDI_PORT_MASK); | ||||
| 		vgpu_vreg(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |= | ||||
| 			(TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST | | ||||
| 			(PORT_B << TRANS_DDI_PORT_SHIFT) | | ||||
| 			TRANS_DDI_FUNC_ENABLE); | ||||
| 		vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_B)) |= DDI_BUF_CTL_ENABLE; | ||||
| 		vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_B)) &= ~DDI_BUF_IS_IDLE; | ||||
| 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTB_HOTPLUG_CPT; | ||||
| 	} | ||||
| 
 | ||||
| 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) { | ||||
| 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTC_HOTPLUG_CPT; | ||||
| 		vgpu_vreg(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &= | ||||
| 			~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK | | ||||
| 			TRANS_DDI_PORT_MASK); | ||||
| 		vgpu_vreg(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |= | ||||
| 			(TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST | | ||||
| 			(PORT_C << TRANS_DDI_PORT_SHIFT) | | ||||
| 			TRANS_DDI_FUNC_ENABLE); | ||||
| 		vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_C)) |= DDI_BUF_CTL_ENABLE; | ||||
| 		vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_C)) &= ~DDI_BUF_IS_IDLE; | ||||
| 		vgpu_vreg(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIC_DETECTED; | ||||
| 	} | ||||
| 
 | ||||
| 	if (intel_vgpu_has_monitor_on_port(vgpu, PORT_D)) { | ||||
| 		vgpu_vreg(vgpu, SDEISR) |= SDE_PORTD_HOTPLUG_CPT; | ||||
| 		vgpu_vreg(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &= | ||||
| 			~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK | | ||||
| 			TRANS_DDI_PORT_MASK); | ||||
| 		vgpu_vreg(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |= | ||||
| 			(TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST | | ||||
| 			(PORT_D << TRANS_DDI_PORT_SHIFT) | | ||||
| 			TRANS_DDI_FUNC_ENABLE); | ||||
| 		vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_D)) |= DDI_BUF_CTL_ENABLE; | ||||
| 		vgpu_vreg(vgpu, DDI_BUF_CTL(PORT_D)) &= ~DDI_BUF_IS_IDLE; | ||||
| 		vgpu_vreg(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDID_DETECTED; | ||||
| 	} | ||||
| 
 | ||||
|   | ||||
| @@ -56,8 +56,8 @@ static int context_switch_events[] = { | ||||
| 
 | ||||
| static int ring_id_to_context_switch_event(int ring_id) | ||||
| { | ||||
| 	if (WARN_ON(ring_id < RCS && ring_id > | ||||
| 				ARRAY_SIZE(context_switch_events))) | ||||
| 	if (WARN_ON(ring_id < RCS || | ||||
| 		    ring_id >= ARRAY_SIZE(context_switch_events))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	return context_switch_events[ring_id]; | ||||
| @@ -687,9 +687,7 @@ static int submit_context(struct intel_vgpu *vgpu, int ring_id, | ||||
| 	} | ||||
| 
 | ||||
| 	if (emulate_schedule_in) | ||||
| 		memcpy(&workload->elsp_dwords, | ||||
| 				&vgpu->execlist[ring_id].elsp_dwords, | ||||
| 				sizeof(workload->elsp_dwords)); | ||||
| 		workload->elsp_dwords = vgpu->execlist[ring_id].elsp_dwords; | ||||
| 
 | ||||
| 	gvt_dbg_el("workload %p ring id %d head %x tail %x start %x ctl %x\n", | ||||
| 			workload, ring_id, head, tail, start, ctl); | ||||
| @@ -776,7 +774,8 @@ static void init_vgpu_execlist(struct intel_vgpu *vgpu, int ring_id) | ||||
| 			_EL_OFFSET_STATUS_PTR); | ||||
| 
 | ||||
| 	ctx_status_ptr.dw = vgpu_vreg(vgpu, ctx_status_ptr_reg); | ||||
| 	ctx_status_ptr.read_ptr = ctx_status_ptr.write_ptr = 0x7; | ||||
| 	ctx_status_ptr.read_ptr = 0; | ||||
| 	ctx_status_ptr.write_ptr = 0x7; | ||||
| 	vgpu_vreg(vgpu, ctx_status_ptr_reg) = ctx_status_ptr.dw; | ||||
| } | ||||
| 
 | ||||
|   | ||||
| @@ -75,11 +75,11 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt) | ||||
| 	struct gvt_firmware_header *h; | ||||
| 	void *firmware; | ||||
| 	void *p; | ||||
| 	unsigned long size; | ||||
| 	unsigned long size, crc32_start; | ||||
| 	int i; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	size = sizeof(*h) + info->mmio_size + info->cfg_space_size - 1; | ||||
| 	size = sizeof(*h) + info->mmio_size + info->cfg_space_size; | ||||
| 	firmware = vzalloc(size); | ||||
| 	if (!firmware) | ||||
| 		return -ENOMEM; | ||||
| @@ -112,6 +112,9 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt) | ||||
| 
 | ||||
| 	memcpy(gvt->firmware.mmio, p, info->mmio_size); | ||||
| 
 | ||||
| 	crc32_start = offsetof(struct gvt_firmware_header, crc32) + 4; | ||||
| 	h->crc32 = crc32_le(0, firmware + crc32_start, size - crc32_start); | ||||
| 
 | ||||
| 	firmware_attr.size = size; | ||||
| 	firmware_attr.private = firmware; | ||||
| 
 | ||||
| @@ -234,7 +237,7 @@ int intel_gvt_load_firmware(struct intel_gvt *gvt) | ||||
| 
 | ||||
| 	firmware->mmio = mem; | ||||
| 
 | ||||
| 	sprintf(path, "%s/vid_0x%04x_did_0x%04x_rid_0x%04x.golden_hw_state", | ||||
| 	sprintf(path, "%s/vid_0x%04x_did_0x%04x_rid_0x%02x.golden_hw_state", | ||||
| 		 GVT_FIRMWARE_PATH, pdev->vendor, pdev->device, | ||||
| 		 pdev->revision); | ||||
| 
 | ||||
|   | ||||
| @@ -2294,12 +2294,15 @@ void intel_gvt_clean_gtt(struct intel_gvt *gvt) | ||||
| void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu) | ||||
| { | ||||
| 	struct intel_gvt *gvt = vgpu->gvt; | ||||
| 	struct drm_i915_private *dev_priv = gvt->dev_priv; | ||||
| 	struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; | ||||
| 	u32 index; | ||||
| 	u32 offset; | ||||
| 	u32 num_entries; | ||||
| 	struct intel_gvt_gtt_entry e; | ||||
| 
 | ||||
| 	intel_runtime_pm_get(dev_priv); | ||||
| 
 | ||||
| 	memset(&e, 0, sizeof(struct intel_gvt_gtt_entry)); | ||||
| 	e.type = GTT_TYPE_GGTT_PTE; | ||||
| 	ops->set_pfn(&e, gvt->gtt.scratch_ggtt_mfn); | ||||
| @@ -2314,6 +2317,8 @@ void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu) | ||||
| 	num_entries = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT; | ||||
| 	for (offset = 0; offset < num_entries; offset++) | ||||
| 		ops->set_entry(NULL, &e, index + offset, false, 0, vgpu); | ||||
| 
 | ||||
| 	intel_runtime_pm_put(dev_priv); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   | ||||
| @@ -52,6 +52,8 @@ static const struct intel_gvt_ops intel_gvt_ops = { | ||||
| 	.vgpu_create = intel_gvt_create_vgpu, | ||||
| 	.vgpu_destroy = intel_gvt_destroy_vgpu, | ||||
| 	.vgpu_reset = intel_gvt_reset_vgpu, | ||||
| 	.vgpu_activate = intel_gvt_activate_vgpu, | ||||
| 	.vgpu_deactivate = intel_gvt_deactivate_vgpu, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|   | ||||
| @@ -395,7 +395,8 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu); | ||||
| void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr, | ||||
| 				 unsigned int engine_mask); | ||||
| void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu); | ||||
| 
 | ||||
| void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu); | ||||
| void intel_gvt_deactivate_vgpu(struct intel_vgpu *vgpu); | ||||
| 
 | ||||
| /* validating GM functions */ | ||||
| #define vgpu_gmadr_is_aperture(vgpu, gmadr) \ | ||||
| @@ -462,6 +463,8 @@ struct intel_gvt_ops { | ||||
| 				struct intel_vgpu_type *); | ||||
| 	void (*vgpu_destroy)(struct intel_vgpu *); | ||||
| 	void (*vgpu_reset)(struct intel_vgpu *); | ||||
| 	void (*vgpu_activate)(struct intel_vgpu *); | ||||
| 	void (*vgpu_deactivate)(struct intel_vgpu *); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|   | ||||
| @@ -546,6 +546,8 @@ static int intel_vgpu_open(struct mdev_device *mdev) | ||||
| 	if (ret) | ||||
| 		goto undo_group; | ||||
| 
 | ||||
| 	intel_gvt_ops->vgpu_activate(vgpu); | ||||
| 
 | ||||
| 	atomic_set(&vgpu->vdev.released, 0); | ||||
| 	return ret; | ||||
| 
 | ||||
| @@ -571,6 +573,8 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu) | ||||
| 	if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1)) | ||||
| 		return; | ||||
| 
 | ||||
| 	intel_gvt_ops->vgpu_deactivate(vgpu); | ||||
| 
 | ||||
| 	ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_IOMMU_NOTIFY, | ||||
| 					&vgpu->vdev.iommu_notifier); | ||||
| 	WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret); | ||||
|   | ||||
| @@ -44,7 +44,7 @@ struct render_mmio { | ||||
| 	u32 value; | ||||
| }; | ||||
| 
 | ||||
| static struct render_mmio gen8_render_mmio_list[] = { | ||||
| static struct render_mmio gen8_render_mmio_list[] __cacheline_aligned = { | ||||
| 	{RCS, _MMIO(0x229c), 0xffff, false}, | ||||
| 	{RCS, _MMIO(0x2248), 0x0, false}, | ||||
| 	{RCS, _MMIO(0x2098), 0x0, false}, | ||||
| @@ -75,7 +75,7 @@ static struct render_mmio gen8_render_mmio_list[] = { | ||||
| 	{BCS, _MMIO(0x22028), 0x0, false}, | ||||
| }; | ||||
| 
 | ||||
| static struct render_mmio gen9_render_mmio_list[] = { | ||||
| static struct render_mmio gen9_render_mmio_list[] __cacheline_aligned = { | ||||
| 	{RCS, _MMIO(0x229c), 0xffff, false}, | ||||
| 	{RCS, _MMIO(0x2248), 0x0, false}, | ||||
| 	{RCS, _MMIO(0x2098), 0x0, false}, | ||||
| @@ -204,9 +204,6 @@ static void load_mocs(struct intel_vgpu *vgpu, int ring_id) | ||||
| 	if (WARN_ON(ring_id >= ARRAY_SIZE(regs))) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))) | ||||
| 		return; | ||||
| 
 | ||||
| 	offset.reg = regs[ring_id]; | ||||
| 	for (i = 0; i < 64; i++) { | ||||
| 		gen9_render_mocs[ring_id][i] = I915_READ(offset); | ||||
| @@ -242,9 +239,6 @@ static void restore_mocs(struct intel_vgpu *vgpu, int ring_id) | ||||
| 	if (WARN_ON(ring_id >= ARRAY_SIZE(regs))) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))) | ||||
| 		return; | ||||
| 
 | ||||
| 	offset.reg = regs[ring_id]; | ||||
| 	for (i = 0; i < 64; i++) { | ||||
| 		vgpu_vreg(vgpu, offset) = I915_READ(offset); | ||||
|   | ||||
| @@ -133,9 +133,6 @@ static void try_to_schedule_next_vgpu(struct intel_gvt *gvt) | ||||
| 	if (!scheduler->next_vgpu) | ||||
| 		return; | ||||
| 
 | ||||
| 	gvt_dbg_sched("try to schedule next vgpu %d\n", | ||||
| 			scheduler->next_vgpu->id); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * after the flag is set, workload dispatch thread will | ||||
| 	 * stop dispatching workload for current vgpu | ||||
| @@ -144,15 +141,10 @@ static void try_to_schedule_next_vgpu(struct intel_gvt *gvt) | ||||
| 
 | ||||
| 	/* still have uncompleted workload? */ | ||||
| 	for_each_engine(engine, gvt->dev_priv, i) { | ||||
| 		if (scheduler->current_workload[i]) { | ||||
| 			gvt_dbg_sched("still have running workload\n"); | ||||
| 		if (scheduler->current_workload[i]) | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	gvt_dbg_sched("switch to next vgpu %d\n", | ||||
| 			scheduler->next_vgpu->id); | ||||
| 
 | ||||
| 	cur_time = ktime_get(); | ||||
| 	if (scheduler->current_vgpu) { | ||||
| 		vgpu_data = scheduler->current_vgpu->sched_data; | ||||
| @@ -224,17 +216,12 @@ static void tbs_sched_func(struct gvt_sched_data *sched_data) | ||||
| 		list_del_init(&vgpu_data->lru_list); | ||||
| 		list_add_tail(&vgpu_data->lru_list, | ||||
| 				&sched_data->lru_runq_head); | ||||
| 
 | ||||
| 		gvt_dbg_sched("pick next vgpu %d\n", vgpu->id); | ||||
| 	} else { | ||||
| 		scheduler->next_vgpu = gvt->idle_vgpu; | ||||
| 	} | ||||
| out: | ||||
| 	if (scheduler->next_vgpu) { | ||||
| 		gvt_dbg_sched("try to schedule next vgpu %d\n", | ||||
| 				scheduler->next_vgpu->id); | ||||
| 	if (scheduler->next_vgpu) | ||||
| 		try_to_schedule_next_vgpu(gvt); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void intel_gvt_schedule(struct intel_gvt *gvt) | ||||
|   | ||||
| @@ -278,11 +278,8 @@ static struct intel_vgpu_workload *pick_next_workload( | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (list_empty(workload_q_head(scheduler->current_vgpu, ring_id))) { | ||||
| 		gvt_dbg_sched("ring id %d stop - no available workload\n", | ||||
| 				ring_id); | ||||
| 	if (list_empty(workload_q_head(scheduler->current_vgpu, ring_id))) | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * still have current workload, maybe the workload disptacher | ||||
|   | ||||
| @@ -195,6 +195,47 @@ static void intel_gvt_update_vgpu_types(struct intel_gvt *gvt) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * intel_gvt_active_vgpu - activate a virtual GPU | ||||
|  * @vgpu: virtual GPU | ||||
|  * | ||||
|  * This function is called when user wants to activate a virtual GPU. | ||||
|  * | ||||
|  */ | ||||
| void intel_gvt_activate_vgpu(struct intel_vgpu *vgpu) | ||||
| { | ||||
| 	mutex_lock(&vgpu->gvt->lock); | ||||
| 	vgpu->active = true; | ||||
| 	mutex_unlock(&vgpu->gvt->lock); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * intel_gvt_deactive_vgpu - deactivate a virtual GPU | ||||
|  * @vgpu: virtual GPU | ||||
|  * | ||||
|  * This function is called when user wants to deactivate a virtual GPU. | ||||
|  * All virtual GPU runtime information will be destroyed. | ||||
|  * | ||||
|  */ | ||||
| void intel_gvt_deactivate_vgpu(struct intel_vgpu *vgpu) | ||||
| { | ||||
| 	struct intel_gvt *gvt = vgpu->gvt; | ||||
| 
 | ||||
| 	mutex_lock(&gvt->lock); | ||||
| 
 | ||||
| 	vgpu->active = false; | ||||
| 
 | ||||
| 	if (atomic_read(&vgpu->running_workload_num)) { | ||||
| 		mutex_unlock(&gvt->lock); | ||||
| 		intel_gvt_wait_vgpu_idle(vgpu); | ||||
| 		mutex_lock(&gvt->lock); | ||||
| 	} | ||||
| 
 | ||||
| 	intel_vgpu_stop_schedule(vgpu); | ||||
| 
 | ||||
| 	mutex_unlock(&gvt->lock); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * intel_gvt_destroy_vgpu - destroy a virtual GPU | ||||
|  * @vgpu: virtual GPU | ||||
| @@ -208,16 +249,9 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu) | ||||
| 
 | ||||
| 	mutex_lock(&gvt->lock); | ||||
| 
 | ||||
| 	vgpu->active = false; | ||||
| 	WARN(vgpu->active, "vGPU is still active!\n"); | ||||
| 
 | ||||
| 	idr_remove(&gvt->vgpu_idr, vgpu->id); | ||||
| 
 | ||||
| 	if (atomic_read(&vgpu->running_workload_num)) { | ||||
| 		mutex_unlock(&gvt->lock); | ||||
| 		intel_gvt_wait_vgpu_idle(vgpu); | ||||
| 		mutex_lock(&gvt->lock); | ||||
| 	} | ||||
| 
 | ||||
| 	intel_vgpu_stop_schedule(vgpu); | ||||
| 	intel_vgpu_clean_sched_policy(vgpu); | ||||
| 	intel_vgpu_clean_gvt_context(vgpu); | ||||
| 	intel_vgpu_clean_execlist(vgpu); | ||||
| @@ -349,7 +383,6 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, | ||||
| 	if (ret) | ||||
| 		goto out_clean_shadow_ctx; | ||||
| 
 | ||||
| 	vgpu->active = true; | ||||
| 	mutex_unlock(&gvt->lock); | ||||
| 
 | ||||
| 	return vgpu; | ||||
|   | ||||
| @@ -200,10 +200,10 @@ static const struct dma_buf_ops i915_dmabuf_ops =  { | ||||
| 	.map_dma_buf = i915_gem_map_dma_buf, | ||||
| 	.unmap_dma_buf = i915_gem_unmap_dma_buf, | ||||
| 	.release = drm_gem_dmabuf_release, | ||||
| 	.kmap = i915_gem_dmabuf_kmap, | ||||
| 	.kmap_atomic = i915_gem_dmabuf_kmap_atomic, | ||||
| 	.kunmap = i915_gem_dmabuf_kunmap, | ||||
| 	.kunmap_atomic = i915_gem_dmabuf_kunmap_atomic, | ||||
| 	.map = i915_gem_dmabuf_kmap, | ||||
| 	.map_atomic = i915_gem_dmabuf_kmap_atomic, | ||||
| 	.unmap = i915_gem_dmabuf_kunmap, | ||||
| 	.unmap_atomic = i915_gem_dmabuf_kunmap_atomic, | ||||
| 	.mmap = i915_gem_dmabuf_mmap, | ||||
| 	.vmap = i915_gem_dmabuf_vmap, | ||||
| 	.vunmap = i915_gem_dmabuf_vunmap, | ||||
|   | ||||
| @@ -129,10 +129,10 @@ static const struct dma_buf_ops mock_dmabuf_ops =  { | ||||
| 	.map_dma_buf = mock_map_dma_buf, | ||||
| 	.unmap_dma_buf = mock_unmap_dma_buf, | ||||
| 	.release = mock_dmabuf_release, | ||||
| 	.kmap = mock_dmabuf_kmap, | ||||
| 	.kmap_atomic = mock_dmabuf_kmap_atomic, | ||||
| 	.kunmap = mock_dmabuf_kunmap, | ||||
| 	.kunmap_atomic = mock_dmabuf_kunmap_atomic, | ||||
| 	.map = mock_dmabuf_kmap, | ||||
| 	.map_atomic = mock_dmabuf_kmap_atomic, | ||||
| 	.unmap = mock_dmabuf_kunmap, | ||||
| 	.unmap_atomic = mock_dmabuf_kunmap_atomic, | ||||
| 	.mmap = mock_dmabuf_mmap, | ||||
| 	.vmap = mock_dmabuf_vmap, | ||||
| 	.vunmap = mock_dmabuf_vunmap, | ||||
|   | ||||
| @@ -111,7 +111,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | ||||
| 	}; | ||||
| 	struct nouveau_display *disp = nouveau_display(crtc->dev); | ||||
| 	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; | ||||
| 	int ret, retry = 1; | ||||
| 	int ret, retry = 20; | ||||
| 
 | ||||
| 	do { | ||||
| 		ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); | ||||
|   | ||||
| @@ -44,6 +44,8 @@ nv40_fifo_dma_engine(struct nvkm_engine *engine, u32 *reg, u32 *ctx) | ||||
| 		*ctx = 0x38; | ||||
| 		return true; | ||||
| 	case NVKM_ENGINE_MPEG: | ||||
| 		if (engine->subdev.device->chipset < 0x44) | ||||
| 			return false; | ||||
| 		*reg = 0x00330c; | ||||
| 		*ctx = 0x54; | ||||
| 		return true; | ||||
|   | ||||
| @@ -33,7 +33,7 @@ nvbios_boostTe(struct nvkm_bios *bios, | ||||
| 	u32 boost = 0; | ||||
| 
 | ||||
| 	if (!bit_entry(bios, 'P', &bit_P)) { | ||||
| 		if (bit_P.version == 2) | ||||
| 		if (bit_P.version == 2 && bit_P.length >= 0x34) | ||||
| 			boost = nvbios_rd32(bios, bit_P.offset + 0x30); | ||||
| 
 | ||||
| 		if (boost) { | ||||
|   | ||||
| @@ -33,7 +33,7 @@ nvbios_cstepTe(struct nvkm_bios *bios, | ||||
| 	u32 cstep = 0; | ||||
| 
 | ||||
| 	if (!bit_entry(bios, 'P', &bit_P)) { | ||||
| 		if (bit_P.version == 2) | ||||
| 		if (bit_P.version == 2 && bit_P.length >= 0x38) | ||||
| 			cstep = nvbios_rd32(bios, bit_P.offset + 0x34); | ||||
| 
 | ||||
| 		if (cstep) { | ||||
|   | ||||
| @@ -32,7 +32,7 @@ nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) | ||||
| 	u32 fan = 0; | ||||
| 
 | ||||
| 	if (!bit_entry(bios, 'P', &bit_P)) { | ||||
| 		if (bit_P.version == 2 && bit_P.length >= 0x5a) | ||||
| 		if (bit_P.version == 2 && bit_P.length >= 0x5c) | ||||
| 			fan = nvbios_rd32(bios, bit_P.offset + 0x58); | ||||
| 
 | ||||
| 		if (fan) { | ||||
|   | ||||
| @@ -33,7 +33,7 @@ nvbios_power_budget_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, | ||||
| 	u32 power_budget; | ||||
| 
 | ||||
| 	if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 || | ||||
| 	    bit_P.length < 0x2c) | ||||
| 	    bit_P.length < 0x30) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	power_budget = nvbios_rd32(bios, bit_P.offset + 0x2c); | ||||
|   | ||||
| @@ -31,7 +31,7 @@ nvbios_vpstate_offset(struct nvkm_bios *b) | ||||
| 	struct bit_entry bit_P; | ||||
| 
 | ||||
| 	if (!bit_entry(b, 'P', &bit_P)) { | ||||
| 		if (bit_P.version == 2) | ||||
| 		if (bit_P.version == 2 && bit_P.length >= 0x3c) | ||||
| 			return nvbios_rd32(b, bit_P.offset + 0x38); | ||||
| 	} | ||||
| 
 | ||||
|   | ||||
| @@ -589,7 +589,7 @@ gf100_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb, | ||||
| 			nvkm_debug(subdev, "FBP %d: %4d MiB, %d LTC(s)\n", | ||||
| 				   fbp, size, ltcs); | ||||
| 			lcomm  = min(lcomm, (u64)(size / ltcs) << 20); | ||||
| 			total += size << 20; | ||||
| 			total += (u64) size << 20; | ||||
| 			ltcn  += ltcs; | ||||
| 		} else { | ||||
| 			nvkm_debug(subdev, "FBP %d: disabled\n", fbp); | ||||
|   | ||||
| @@ -48,7 +48,7 @@ gm20b_secboot_tegra_read_wpr(struct gm200_secboot *gsb, u32 mc_base) | ||||
| 	mc = ioremap(mc_base, 0xd00); | ||||
| 	if (!mc) { | ||||
| 		nvkm_error(&sb->subdev, "Cannot map Tegra MC registers\n"); | ||||
| 		return PTR_ERR(mc); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 	sb->wpr_addr = ioread32_native(mc + MC_SECURITY_CARVEOUT2_BOM_0) | | ||||
| 	      ((u64)ioread32_native(mc + MC_SECURITY_CARVEOUT2_BOM_HI_0) << 32); | ||||
|   | ||||
| @@ -160,10 +160,10 @@ static struct dma_buf_ops omap_dmabuf_ops = { | ||||
| 	.release = omap_gem_dmabuf_release, | ||||
| 	.begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, | ||||
| 	.end_cpu_access = omap_gem_dmabuf_end_cpu_access, | ||||
| 	.kmap_atomic = omap_gem_dmabuf_kmap_atomic, | ||||
| 	.kunmap_atomic = omap_gem_dmabuf_kunmap_atomic, | ||||
| 	.kmap = omap_gem_dmabuf_kmap, | ||||
| 	.kunmap = omap_gem_dmabuf_kunmap, | ||||
| 	.map_atomic = omap_gem_dmabuf_kmap_atomic, | ||||
| 	.unmap_atomic = omap_gem_dmabuf_kunmap_atomic, | ||||
| 	.map = omap_gem_dmabuf_kmap, | ||||
| 	.unmap = omap_gem_dmabuf_kunmap, | ||||
| 	.mmap = omap_gem_dmabuf_mmap, | ||||
| }; | ||||
| 
 | ||||
|   | ||||
| @@ -62,6 +62,12 @@ config DRM_PANEL_PANASONIC_VVX10F034N00 | ||||
| 	  WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some | ||||
| 	  Xperia Z2 tablets | ||||
|  | ||||
| config DRM_PANEL_SAMSUNG_S6E3HA2 | ||||
| 	tristate "Samsung S6E3HA2 DSI video mode panel" | ||||
| 	depends on OF | ||||
| 	depends on DRM_MIPI_DSI | ||||
| 	select VIDEOMODE_HELPERS | ||||
|  | ||||
| config DRM_PANEL_SAMSUNG_S6E8AA0 | ||||
| 	tristate "Samsung S6E8AA0 DSI video mode panel" | ||||
| 	depends on OF | ||||
| @@ -91,4 +97,11 @@ config DRM_PANEL_SHARP_LS043T1LE01 | ||||
| 	  Say Y here if you want to enable support for Sharp LS043T1LE01 qHD | ||||
| 	  (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard | ||||
|  | ||||
| config DRM_PANEL_SITRONIX_ST7789V | ||||
| 	tristate "Sitronix ST7789V panel" | ||||
| 	depends on OF && SPI | ||||
| 	help | ||||
| 	  Say Y here if you want to enable support for the Sitronix | ||||
| 	  ST7789V controller for 240x320 LCD panels | ||||
|  | ||||
| endmenu | ||||
|   | ||||
| @@ -4,6 +4,8 @@ obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o | ||||
| obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o | ||||
| obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o | ||||
| obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o | ||||
| obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o | ||||
| obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o | ||||
| obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o | ||||
| obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o | ||||
| obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o | ||||
|   | ||||
							
								
								
									
										739
									
								
								drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										739
									
								
								drivers/gpu/drm/panel/panel-samsung-s6e3ha2.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,739 @@ | ||||
| /*
 | ||||
|  * MIPI-DSI based s6e3ha2 AMOLED 5.7 inch panel driver. | ||||
|  * | ||||
|  * Copyright (c) 2016 Samsung Electronics Co., Ltd. | ||||
|  * Donghwa Lee <dh09.lee@samsung.com> | ||||
|  * Hyungwon Hwang <human.hwang@samsung.com> | ||||
|  * Hoegeun Kwon <hoegeun.kwon@samsung.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
| 
 | ||||
| #include <drm/drmP.h> | ||||
| #include <drm/drm_mipi_dsi.h> | ||||
| #include <drm/drm_panel.h> | ||||
| #include <linux/backlight.h> | ||||
| #include <linux/gpio/consumer.h> | ||||
| #include <linux/regulator/consumer.h> | ||||
| 
 | ||||
| #define S6E3HA2_MIN_BRIGHTNESS		0 | ||||
| #define S6E3HA2_MAX_BRIGHTNESS		100 | ||||
| #define S6E3HA2_DEFAULT_BRIGHTNESS	80 | ||||
| 
 | ||||
| #define S6E3HA2_NUM_GAMMA_STEPS		46 | ||||
| #define S6E3HA2_GAMMA_CMD_CNT		35 | ||||
| #define S6E3HA2_VINT_STATUS_MAX		10 | ||||
| 
 | ||||
| static const u8 gamma_tbl[S6E3HA2_NUM_GAMMA_STEPS][S6E3HA2_GAMMA_CMD_CNT] = { | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x82, 0x83, | ||||
| 	  0x85, 0x88, 0x8b, 0x8b, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8c, | ||||
| 	  0x94, 0x84, 0xb1, 0xaf, 0x8e, 0xcf, 0xad, 0xc9, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x84, 0x84, | ||||
| 	  0x85, 0x87, 0x8b, 0x8a, 0x84, 0x88, 0x82, 0x82, 0x89, 0x86, 0x8a, | ||||
| 	  0x93, 0x84, 0xb0, 0xae, 0x8e, 0xc9, 0xa8, 0xc5, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x8a, 0x8a, 0x84, 0x88, 0x81, 0x84, 0x8a, 0x88, 0x8a, | ||||
| 	  0x91, 0x84, 0xb1, 0xae, 0x8b, 0xd5, 0xb2, 0xcc, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x8a, 0x8a, 0x84, 0x87, 0x81, 0x84, 0x8a, 0x87, 0x8a, | ||||
| 	  0x91, 0x85, 0xae, 0xac, 0x8a, 0xc3, 0xa3, 0xc0, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x85, 0x85, | ||||
| 	  0x86, 0x85, 0x88, 0x89, 0x84, 0x89, 0x82, 0x84, 0x87, 0x85, 0x8b, | ||||
| 	  0x91, 0x88, 0xad, 0xab, 0x8a, 0xb7, 0x9b, 0xb6, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x89, 0x8a, 0x84, 0x89, 0x83, 0x83, 0x86, 0x84, 0x8b, | ||||
| 	  0x90, 0x84, 0xb0, 0xae, 0x8b, 0xce, 0xad, 0xc8, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x89, | ||||
| 	  0x8f, 0x84, 0xac, 0xaa, 0x89, 0xb1, 0x98, 0xaf, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x88, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8c, | ||||
| 	  0x91, 0x86, 0xac, 0xaa, 0x89, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x85, 0x87, 0x89, 0x8a, 0x83, 0x87, 0x82, 0x85, 0x88, 0x87, 0x88, | ||||
| 	  0x8b, 0x82, 0xad, 0xaa, 0x8a, 0xc2, 0xa5, 0xbd, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x89, 0x87, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x82, 0x85, 0x84, 0x8a, | ||||
| 	  0x8e, 0x84, 0xae, 0xac, 0x89, 0xda, 0xb7, 0xd0, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x85, 0x86, 0x87, 0x89, 0x84, 0x88, 0x83, 0x80, 0x83, 0x82, 0x8b, | ||||
| 	  0x8e, 0x85, 0xac, 0xaa, 0x89, 0xc8, 0xaa, 0xc1, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x85, 0x86, 0x87, 0x89, 0x81, 0x85, 0x81, 0x84, 0x86, 0x84, 0x8c, | ||||
| 	  0x8c, 0x84, 0xa9, 0xa8, 0x87, 0xa3, 0x92, 0xa1, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x85, 0x86, 0x87, 0x89, 0x84, 0x86, 0x83, 0x80, 0x83, 0x81, 0x8c, | ||||
| 	  0x8d, 0x84, 0xaa, 0xaa, 0x89, 0xce, 0xaf, 0xc5, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x85, 0x86, 0x87, 0x89, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c, | ||||
| 	  0x8c, 0x84, 0xa8, 0xa8, 0x88, 0xb5, 0x9f, 0xb0, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x83, 0x85, 0x85, 0x8c, | ||||
| 	  0x8b, 0x84, 0xab, 0xa8, 0x86, 0xd4, 0xb4, 0xc9, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x86, 0x86, 0x87, 0x88, 0x81, 0x83, 0x80, 0x84, 0x84, 0x85, 0x8b, | ||||
| 	  0x8a, 0x83, 0xa6, 0xa5, 0x84, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x84, 0x84, | ||||
| 	  0x86, 0x85, 0x86, 0x86, 0x82, 0x85, 0x81, 0x82, 0x83, 0x84, 0x8e, | ||||
| 	  0x8b, 0x83, 0xa4, 0xa3, 0x8a, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8e, | ||||
| 	  0x8b, 0x83, 0xa4, 0xa2, 0x86, 0xc1, 0xa9, 0xb7, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x82, 0x82, 0x84, 0x8d, | ||||
| 	  0x89, 0x82, 0xa2, 0xa1, 0x84, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xb8, 0x00, 0xc3, 0x00, 0xb1, 0x88, 0x86, 0x87, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x87, 0x87, 0x82, 0x85, 0x81, 0x83, 0x83, 0x85, 0x8c, | ||||
| 	  0x87, 0x7f, 0xa2, 0x9d, 0x88, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xbb, 0x00, 0xc5, 0x00, 0xb4, 0x87, 0x86, 0x86, 0x84, 0x83, | ||||
| 	  0x86, 0x87, 0x87, 0x87, 0x80, 0x82, 0x7f, 0x86, 0x86, 0x88, 0x8a, | ||||
| 	  0x84, 0x7e, 0x9d, 0x9c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xbd, 0x00, 0xc7, 0x00, 0xb7, 0x87, 0x85, 0x85, 0x84, 0x83, | ||||
| 	  0x86, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x83, 0x84, 0x85, 0x8a, | ||||
| 	  0x85, 0x7e, 0x9c, 0x9b, 0x85, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xc0, 0x00, 0xca, 0x00, 0xbb, 0x87, 0x86, 0x85, 0x83, 0x83, | ||||
| 	  0x85, 0x86, 0x86, 0x88, 0x81, 0x83, 0x80, 0x84, 0x85, 0x86, 0x89, | ||||
| 	  0x83, 0x7d, 0x9c, 0x99, 0x87, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xc4, 0x00, 0xcd, 0x00, 0xbe, 0x87, 0x86, 0x85, 0x83, 0x83, | ||||
| 	  0x86, 0x85, 0x85, 0x87, 0x81, 0x82, 0x80, 0x82, 0x82, 0x83, 0x8a, | ||||
| 	  0x85, 0x7f, 0x9f, 0x9b, 0x86, 0xb4, 0xa1, 0xac, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xc7, 0x00, 0xd0, 0x00, 0xc2, 0x87, 0x85, 0x85, 0x83, 0x82, | ||||
| 	  0x85, 0x85, 0x85, 0x86, 0x82, 0x83, 0x80, 0x82, 0x82, 0x84, 0x87, | ||||
| 	  0x86, 0x80, 0x9e, 0x9a, 0x87, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xca, 0x00, 0xd2, 0x00, 0xc5, 0x87, 0x85, 0x84, 0x82, 0x82, | ||||
| 	  0x84, 0x85, 0x85, 0x86, 0x81, 0x82, 0x7f, 0x82, 0x82, 0x84, 0x88, | ||||
| 	  0x86, 0x81, 0x9d, 0x98, 0x86, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xce, 0x00, 0xd6, 0x00, 0xca, 0x86, 0x85, 0x84, 0x83, 0x83, | ||||
| 	  0x85, 0x84, 0x84, 0x85, 0x81, 0x82, 0x80, 0x81, 0x81, 0x82, 0x89, | ||||
| 	  0x86, 0x81, 0x9c, 0x97, 0x86, 0xa7, 0x98, 0xa1, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xd1, 0x00, 0xd9, 0x00, 0xce, 0x86, 0x84, 0x83, 0x83, 0x82, | ||||
| 	  0x85, 0x85, 0x85, 0x86, 0x81, 0x83, 0x81, 0x82, 0x82, 0x83, 0x86, | ||||
| 	  0x83, 0x7f, 0x99, 0x95, 0x86, 0xbb, 0xa4, 0xb3, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xd4, 0x00, 0xdb, 0x00, 0xd1, 0x86, 0x85, 0x83, 0x83, 0x82, | ||||
| 	  0x85, 0x84, 0x84, 0x85, 0x80, 0x83, 0x82, 0x80, 0x80, 0x81, 0x87, | ||||
| 	  0x84, 0x81, 0x98, 0x93, 0x85, 0xae, 0x9c, 0xa8, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xd8, 0x00, 0xde, 0x00, 0xd6, 0x86, 0x84, 0x83, 0x81, 0x81, | ||||
| 	  0x83, 0x85, 0x85, 0x85, 0x82, 0x83, 0x81, 0x81, 0x81, 0x83, 0x86, | ||||
| 	  0x84, 0x80, 0x98, 0x91, 0x85, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xdc, 0x00, 0xe2, 0x00, 0xda, 0x85, 0x84, 0x83, 0x82, 0x82, | ||||
| 	  0x84, 0x84, 0x84, 0x85, 0x81, 0x82, 0x82, 0x80, 0x80, 0x81, 0x83, | ||||
| 	  0x82, 0x7f, 0x99, 0x93, 0x86, 0x94, 0x8b, 0x92, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xdf, 0x00, 0xe5, 0x00, 0xde, 0x85, 0x84, 0x82, 0x82, 0x82, | ||||
| 	  0x84, 0x83, 0x83, 0x84, 0x81, 0x81, 0x80, 0x83, 0x82, 0x84, 0x82, | ||||
| 	  0x81, 0x7f, 0x99, 0x92, 0x86, 0x7b, 0x7b, 0x7c, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81, | ||||
| 	  0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x83, 0x83, 0x84, 0x80, | ||||
| 	  0x81, 0x7c, 0x99, 0x92, 0x87, 0xa1, 0x93, 0x9d, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x85, 0x84, 0x83, 0x81, 0x81, | ||||
| 	  0x82, 0x82, 0x82, 0x83, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83, | ||||
| 	  0x82, 0x80, 0x91, 0x8d, 0x83, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81, | ||||
| 	  0x82, 0x83, 0x83, 0x84, 0x80, 0x81, 0x80, 0x81, 0x80, 0x82, 0x83, | ||||
| 	  0x81, 0x7f, 0x91, 0x8c, 0x82, 0x8d, 0x88, 0x8b, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81, | ||||
| 	  0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x82, | ||||
| 	  0x82, 0x7f, 0x94, 0x89, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81, | ||||
| 	  0x82, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x81, 0x80, 0x82, 0x83, | ||||
| 	  0x82, 0x7f, 0x91, 0x85, 0x81, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x81, 0x81, | ||||
| 	  0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x83, 0x82, 0x84, 0x83, | ||||
| 	  0x82, 0x7f, 0x90, 0x84, 0x81, 0x9a, 0x90, 0x96, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe4, 0x00, 0xe9, 0x00, 0xe3, 0x84, 0x83, 0x82, 0x80, 0x80, | ||||
| 	  0x82, 0x83, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x81, | ||||
| 	  0x82, 0x83, 0x7e, 0x80, 0x7c, 0xa4, 0x97, 0x9f, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xe9, 0x00, 0xec, 0x00, 0xe8, 0x84, 0x83, 0x82, 0x81, 0x81, | ||||
| 	  0x82, 0x82, 0x82, 0x83, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x83, | ||||
| 	  0x83, 0x84, 0x79, 0x7c, 0x79, 0xb1, 0xa0, 0xaa, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xed, 0x00, 0xf0, 0x00, 0xec, 0x83, 0x83, 0x82, 0x80, 0x80, | ||||
| 	  0x81, 0x82, 0x82, 0x82, 0x7f, 0x7f, 0x7e, 0x81, 0x81, 0x82, 0x80, | ||||
| 	  0x81, 0x81, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xf1, 0x00, 0xf4, 0x00, 0xf1, 0x83, 0x82, 0x82, 0x80, 0x80, | ||||
| 	  0x81, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x7d, | ||||
| 	  0x7e, 0x7f, 0x84, 0x84, 0x83, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf5, 0x82, 0x82, 0x81, 0x80, 0x80, | ||||
| 	  0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x82, | ||||
| 	  0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfa, 0x81, 0x81, 0x81, 0x80, 0x80, | ||||
| 	  0x80, 0x82, 0x82, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, | ||||
| 	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, | ||||
| 	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, | ||||
| 	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 }, | ||||
| 	{ 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, | ||||
| 	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, | ||||
| 	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, | ||||
| 	  0x00, 0x00 } | ||||
| }; | ||||
| 
 | ||||
| unsigned char vint_table[S6E3HA2_VINT_STATUS_MAX] = { | ||||
| 	0x18, 0x19, 0x1a, 0x1b, 0x1c, | ||||
| 	0x1d, 0x1e, 0x1f, 0x20, 0x21 | ||||
| }; | ||||
| 
 | ||||
| struct s6e3ha2 { | ||||
| 	struct device *dev; | ||||
| 	struct drm_panel panel; | ||||
| 	struct backlight_device *bl_dev; | ||||
| 
 | ||||
| 	struct regulator_bulk_data supplies[2]; | ||||
| 	struct gpio_desc *reset_gpio; | ||||
| 	struct gpio_desc *enable_gpio; | ||||
| }; | ||||
| 
 | ||||
| static int s6e3ha2_dcs_write(struct s6e3ha2 *ctx, const void *data, size_t len) | ||||
| { | ||||
| 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||||
| 
 | ||||
| 	return mipi_dsi_dcs_write_buffer(dsi, data, len); | ||||
| } | ||||
| 
 | ||||
| #define s6e3ha2_dcs_write_seq_static(ctx, seq...) do {	\ | ||||
| 	static const u8 d[] = { seq };			\ | ||||
| 	int ret;					\ | ||||
| 	ret = s6e3ha2_dcs_write(ctx, d, ARRAY_SIZE(d));	\ | ||||
| 	if (ret < 0)					\ | ||||
| 		return ret;				\ | ||||
| } while (0) | ||||
| 
 | ||||
| #define s6e3ha2_call_write_func(ret, func) do {	\ | ||||
| 	ret = (func);				\ | ||||
| 	if (ret < 0)				\ | ||||
| 		return ret;			\ | ||||
| } while (0) | ||||
| 
 | ||||
| static int s6e3ha2_test_key_on_f0(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_test_key_off_f0(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xf0, 0xa5, 0xa5); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_test_key_on_fc(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_test_key_off_fc(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xfc, 0xa5, 0xa5); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_single_dsi_set(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xf2, 0x67); | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xf9, 0x09); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_freq_calibration(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xfd, 0x1c); | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20, 0x39); | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0xa0); | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x20); | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xce, 0x03, 0x3b, 0x12, 0x62, 0x40, | ||||
| 				0x80, 0xc0, 0x28, 0x28, 0x28, 0x28, 0x39, 0xc5); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_aor_control(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xb2, 0x03, 0x10); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_caps_elvss_set(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xb6, 0x9c, 0x0a); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_acl_off(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0x55, 0x00); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_acl_off_opr(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xb5, 0x40); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_test_global(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x07); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_test(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xb8, 0x19); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_touch_hsync_on1(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xbd, 0x33, 0x11, 0x02, | ||||
| 					0x16, 0x02, 0x16); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_pentile_control(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xc0, 0x00, 0x00, 0xd8, 0xd8); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_poc_global(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xb0, 0x20); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_poc_setting(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xfe, 0x08); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_pcd_set_off(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xcc, 0x40, 0x51); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_err_fg_set(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xed, 0x44); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_hbm_off(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0x53, 0x00); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_te_start_setting(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xb9, 0x10, 0x09, 0xff, 0x00, 0x09); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_gamma_update(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x03); | ||||
| 	ndelay(100); /* need for 100ns delay */ | ||||
| 	s6e3ha2_dcs_write_seq_static(ctx, 0xf7, 0x00); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_get_brightness(struct backlight_device *bl_dev) | ||||
| { | ||||
| 	return bl_dev->props.brightness; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_set_vint(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	struct backlight_device *bl_dev = ctx->bl_dev; | ||||
| 	unsigned int brightness = bl_dev->props.brightness; | ||||
| 	unsigned char data[] = { 0xf4, 0x8b, | ||||
| 			vint_table[brightness * (S6E3HA2_VINT_STATUS_MAX - 1) / | ||||
| 			S6E3HA2_MAX_BRIGHTNESS] }; | ||||
| 
 | ||||
| 	return s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data)); | ||||
| } | ||||
| 
 | ||||
| static unsigned int s6e3ha2_get_brightness_index(unsigned int brightness) | ||||
| { | ||||
| 	return (brightness * (S6E3HA2_NUM_GAMMA_STEPS - 1)) / | ||||
| 		S6E3HA2_MAX_BRIGHTNESS; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_update_gamma(struct s6e3ha2 *ctx, unsigned int brightness) | ||||
| { | ||||
| 	struct backlight_device *bl_dev = ctx->bl_dev; | ||||
| 	unsigned int index = s6e3ha2_get_brightness_index(brightness); | ||||
| 	u8 data[S6E3HA2_GAMMA_CMD_CNT + 1] = { 0xca, }; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	memcpy(data + 1, gamma_tbl + index, S6E3HA2_GAMMA_CMD_CNT); | ||||
| 	s6e3ha2_call_write_func(ret, | ||||
| 				s6e3ha2_dcs_write(ctx, data, ARRAY_SIZE(data))); | ||||
| 
 | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx)); | ||||
| 	bl_dev->props.brightness = brightness; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_set_brightness(struct backlight_device *bl_dev) | ||||
| { | ||||
| 	struct s6e3ha2 *ctx = bl_get_data(bl_dev); | ||||
| 	unsigned int brightness = bl_dev->props.brightness; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (brightness < S6E3HA2_MIN_BRIGHTNESS || | ||||
| 		brightness > bl_dev->props.max_brightness) { | ||||
| 		dev_err(ctx->dev, "Invalid brightness: %u\n", brightness); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (bl_dev->props.power > FB_BLANK_NORMAL) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_update_gamma(ctx, brightness)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_set_vint(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct backlight_ops s6e3ha2_bl_ops = { | ||||
| 	.get_brightness = s6e3ha2_get_brightness, | ||||
| 	.update_status = s6e3ha2_set_brightness, | ||||
| }; | ||||
| 
 | ||||
| static int s6e3ha2_panel_init(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_exit_sleep_mode(dsi)); | ||||
| 	usleep_range(5000, 6000); | ||||
| 
 | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_single_dsi_set(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_freq_calibration(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx)); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_power_off(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_disable(struct drm_panel *panel) | ||||
| { | ||||
| 	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel); | ||||
| 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_enter_sleep_mode(dsi)); | ||||
| 	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_off(dsi)); | ||||
| 
 | ||||
| 	msleep(40); | ||||
| 	ctx->bl_dev->props.power = FB_BLANK_NORMAL; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_unprepare(struct drm_panel *panel) | ||||
| { | ||||
| 	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel); | ||||
| 
 | ||||
| 	return s6e3ha2_power_off(ctx); | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_power_on(struct s6e3ha2 *ctx) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	msleep(120); | ||||
| 
 | ||||
| 	gpiod_set_value(ctx->enable_gpio, 0); | ||||
| 	usleep_range(5000, 6000); | ||||
| 	gpiod_set_value(ctx->enable_gpio, 1); | ||||
| 
 | ||||
| 	gpiod_set_value(ctx->reset_gpio, 1); | ||||
| 	usleep_range(5000, 6000); | ||||
| 	gpiod_set_value(ctx->reset_gpio, 0); | ||||
| 	usleep_range(5000, 6000); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| static int s6e3ha2_prepare(struct drm_panel *panel) | ||||
| { | ||||
| 	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = s6e3ha2_power_on(ctx); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ret = s6e3ha2_panel_init(ctx); | ||||
| 	if (ret < 0) | ||||
| 		goto err; | ||||
| 
 | ||||
| 	ctx->bl_dev->props.power = FB_BLANK_NORMAL; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	s6e3ha2_power_off(ctx); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_enable(struct drm_panel *panel) | ||||
| { | ||||
| 	struct s6e3ha2 *ctx = container_of(panel, struct s6e3ha2, panel); | ||||
| 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* common setting */ | ||||
| 	s6e3ha2_call_write_func(ret, | ||||
| 		mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK)); | ||||
| 
 | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_f0(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_on_fc(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_touch_hsync_on1(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_pentile_control(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_poc_global(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_poc_setting(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_fc(ctx)); | ||||
| 
 | ||||
| 	/* pcd setting off for TB */ | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_pcd_set_off(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_err_fg_set(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_te_start_setting(ctx)); | ||||
| 
 | ||||
| 	/* brightness setting */ | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_set_brightness(ctx->bl_dev)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_aor_control(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_caps_elvss_set(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_gamma_update(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_acl_off(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_acl_off_opr(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_hbm_off(ctx)); | ||||
| 
 | ||||
| 	/* elvss temp compensation */ | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_global(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test(ctx)); | ||||
| 	s6e3ha2_call_write_func(ret, s6e3ha2_test_key_off_f0(ctx)); | ||||
| 
 | ||||
| 	s6e3ha2_call_write_func(ret, mipi_dsi_dcs_set_display_on(dsi)); | ||||
| 	ctx->bl_dev->props.power = FB_BLANK_UNBLANK; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct drm_display_mode default_mode = { | ||||
| 	.clock = 222372, | ||||
| 	.hdisplay = 1440, | ||||
| 	.hsync_start = 1440 + 1, | ||||
| 	.hsync_end = 1440 + 1 + 1, | ||||
| 	.htotal = 1440 + 1 + 1 + 1, | ||||
| 	.vdisplay = 2560, | ||||
| 	.vsync_start = 2560 + 1, | ||||
| 	.vsync_end = 2560 + 1 + 1, | ||||
| 	.vtotal = 2560 + 1 + 1 + 15, | ||||
| 	.vrefresh = 60, | ||||
| 	.flags = 0, | ||||
| }; | ||||
| 
 | ||||
| static int s6e3ha2_get_modes(struct drm_panel *panel) | ||||
| { | ||||
| 	struct drm_connector *connector = panel->connector; | ||||
| 	struct drm_display_mode *mode; | ||||
| 
 | ||||
| 	mode = drm_mode_duplicate(panel->drm, &default_mode); | ||||
| 	if (!mode) { | ||||
| 		DRM_ERROR("failed to add mode %ux%ux@%u\n", | ||||
| 				default_mode.hdisplay, default_mode.vdisplay, | ||||
| 				default_mode.vrefresh); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	drm_mode_set_name(mode); | ||||
| 
 | ||||
| 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||||
| 	drm_mode_probed_add(connector, mode); | ||||
| 
 | ||||
| 	connector->display_info.width_mm = 71; | ||||
| 	connector->display_info.height_mm = 125; | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static const struct drm_panel_funcs s6e3ha2_drm_funcs = { | ||||
| 	.disable = s6e3ha2_disable, | ||||
| 	.unprepare = s6e3ha2_unprepare, | ||||
| 	.prepare = s6e3ha2_prepare, | ||||
| 	.enable = s6e3ha2_enable, | ||||
| 	.get_modes = s6e3ha2_get_modes, | ||||
| }; | ||||
| 
 | ||||
| static int s6e3ha2_probe(struct mipi_dsi_device *dsi) | ||||
| { | ||||
| 	struct device *dev = &dsi->dev; | ||||
| 	struct s6e3ha2 *ctx; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | ||||
| 	if (!ctx) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	mipi_dsi_set_drvdata(dsi, ctx); | ||||
| 
 | ||||
| 	ctx->dev = dev; | ||||
| 
 | ||||
| 	dsi->lanes = 4; | ||||
| 	dsi->format = MIPI_DSI_FMT_RGB888; | ||||
| 	dsi->mode_flags = MIPI_DSI_CLOCK_NON_CONTINUOUS; | ||||
| 
 | ||||
| 	ctx->supplies[0].supply = "vdd3"; | ||||
| 	ctx->supplies[1].supply = "vci"; | ||||
| 
 | ||||
| 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), | ||||
| 				      ctx->supplies); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(dev, "failed to get regulators: %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | ||||
| 	if (IS_ERR(ctx->reset_gpio)) { | ||||
| 		dev_err(dev, "cannot get reset-gpios %ld\n", | ||||
| 			PTR_ERR(ctx->reset_gpio)); | ||||
| 		return PTR_ERR(ctx->reset_gpio); | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); | ||||
| 	if (IS_ERR(ctx->enable_gpio)) { | ||||
| 		dev_err(dev, "cannot get enable-gpios %ld\n", | ||||
| 			PTR_ERR(ctx->enable_gpio)); | ||||
| 		return PTR_ERR(ctx->enable_gpio); | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->bl_dev = backlight_device_register("s6e3ha2", dev, ctx, | ||||
| 						&s6e3ha2_bl_ops, NULL); | ||||
| 	if (IS_ERR(ctx->bl_dev)) { | ||||
| 		dev_err(dev, "failed to register backlight device\n"); | ||||
| 		return PTR_ERR(ctx->bl_dev); | ||||
| 	} | ||||
| 
 | ||||
| 	ctx->bl_dev->props.max_brightness = S6E3HA2_MAX_BRIGHTNESS; | ||||
| 	ctx->bl_dev->props.brightness = S6E3HA2_DEFAULT_BRIGHTNESS; | ||||
| 	ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; | ||||
| 
 | ||||
| 	drm_panel_init(&ctx->panel); | ||||
| 	ctx->panel.dev = dev; | ||||
| 	ctx->panel.funcs = &s6e3ha2_drm_funcs; | ||||
| 
 | ||||
| 	ret = drm_panel_add(&ctx->panel); | ||||
| 	if (ret < 0) | ||||
| 		goto unregister_backlight; | ||||
| 
 | ||||
| 	ret = mipi_dsi_attach(dsi); | ||||
| 	if (ret < 0) | ||||
| 		goto remove_panel; | ||||
| 
 | ||||
| 	return ret; | ||||
| 
 | ||||
| remove_panel: | ||||
| 	drm_panel_remove(&ctx->panel); | ||||
| 
 | ||||
| unregister_backlight: | ||||
| 	backlight_device_unregister(ctx->bl_dev); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int s6e3ha2_remove(struct mipi_dsi_device *dsi) | ||||
| { | ||||
| 	struct s6e3ha2 *ctx = mipi_dsi_get_drvdata(dsi); | ||||
| 
 | ||||
| 	mipi_dsi_detach(dsi); | ||||
| 	drm_panel_remove(&ctx->panel); | ||||
| 	backlight_device_unregister(ctx->bl_dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct of_device_id s6e3ha2_of_match[] = { | ||||
| 	{ .compatible = "samsung,s6e3ha2" }, | ||||
| 	{ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, s6e3ha2_of_match); | ||||
| 
 | ||||
| static struct mipi_dsi_driver s6e3ha2_driver = { | ||||
| 	.probe = s6e3ha2_probe, | ||||
| 	.remove = s6e3ha2_remove, | ||||
| 	.driver = { | ||||
| 		.name = "panel-samsung-s6e3ha2", | ||||
| 		.of_match_table = s6e3ha2_of_match, | ||||
| 	}, | ||||
| }; | ||||
| module_mipi_dsi_driver(s6e3ha2_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); | ||||
| MODULE_AUTHOR("Hyungwon Hwang <human.hwang@samsung.com>"); | ||||
| MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>"); | ||||
| MODULE_DESCRIPTION("MIPI-DSI based s6e3ha2 AMOLED Panel Driver"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| @@ -386,6 +386,31 @@ static void panel_simple_shutdown(struct device *dev) | ||||
| 	panel_simple_disable(&panel->base); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = { | ||||
| 	.clock = 9000, | ||||
| 	.hdisplay = 480, | ||||
| 	.hsync_start = 480 + 2, | ||||
| 	.hsync_end = 480 + 2 + 41, | ||||
| 	.htotal = 480 + 2 + 41 + 2, | ||||
| 	.vdisplay = 272, | ||||
| 	.vsync_start = 272 + 2, | ||||
| 	.vsync_end = 272 + 2 + 10, | ||||
| 	.vtotal = 272 + 2 + 10 + 2, | ||||
| 	.vrefresh = 60, | ||||
| 	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc ampire_am_480272h3tmqw_t01h = { | ||||
| 	.modes = &ire_am_480272h3tmqw_t01h_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 8, | ||||
| 	.size = { | ||||
| 		.width = 105, | ||||
| 		.height = 67, | ||||
| 	}, | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = { | ||||
| 	.clock = 33333, | ||||
| 	.hdisplay = 800, | ||||
| @@ -1806,8 +1831,36 @@ static const struct panel_desc urt_umsh_8596md_parallel = { | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB666_1X18, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode winstar_wf35ltiacd_mode = { | ||||
| 	.clock = 6410, | ||||
| 	.hdisplay = 320, | ||||
| 	.hsync_start = 320 + 20, | ||||
| 	.hsync_end = 320 + 20 + 30, | ||||
| 	.htotal = 320 + 20 + 30 + 38, | ||||
| 	.vdisplay = 240, | ||||
| 	.vsync_start = 240 + 4, | ||||
| 	.vsync_end = 240 + 4 + 3, | ||||
| 	.vtotal = 240 + 4 + 3 + 15, | ||||
| 	.vrefresh = 60, | ||||
| 	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc winstar_wf35ltiacd = { | ||||
| 	.modes = &winstar_wf35ltiacd_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 8, | ||||
| 	.size = { | ||||
| 		.width = 70, | ||||
| 		.height = 53, | ||||
| 	}, | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||||
| }; | ||||
| 
 | ||||
| static const struct of_device_id platform_of_match[] = { | ||||
| 	{ | ||||
| 		.compatible = "ampire,am-480272h3tmqw-t01h", | ||||
| 		.data = &ire_am_480272h3tmqw_t01h, | ||||
| 	}, { | ||||
| 		.compatible = "ampire,am800480r3tmqwa1h", | ||||
| 		.data = &ire_am800480r3tmqwa1h, | ||||
| 	}, { | ||||
| @@ -1993,6 +2046,9 @@ static const struct of_device_id platform_of_match[] = { | ||||
| 	}, { | ||||
| 		.compatible = "urt,umsh-8596md-20t", | ||||
| 		.data = &urt_umsh_8596md_parallel, | ||||
| 	}, { | ||||
| 		.compatible = "winstar,wf35ltiacd", | ||||
| 		.data = &winstar_wf35ltiacd, | ||||
| 	}, { | ||||
| 		/* sentinel */ | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										449
									
								
								drivers/gpu/drm/panel/panel-sitronix-st7789v.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										449
									
								
								drivers/gpu/drm/panel/panel-sitronix-st7789v.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,449 @@ | ||||
| /*
 | ||||
|  * Copyright (C) 2017 Free Electrons | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU General Public License version | ||||
|  * 2 as published by the Free Software Foundation. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/gpio/consumer.h> | ||||
| #include <linux/regulator/consumer.h> | ||||
| #include <linux/spi/spi.h> | ||||
| 
 | ||||
| #include <drm/drmP.h> | ||||
| #include <drm/drm_panel.h> | ||||
| 
 | ||||
| #include <video/mipi_display.h> | ||||
| 
 | ||||
| #define ST7789V_COLMOD_RGB_FMT_18BITS		(6 << 4) | ||||
| #define ST7789V_COLMOD_CTRL_FMT_18BITS		(6 << 0) | ||||
| 
 | ||||
| #define ST7789V_RAMCTRL_CMD		0xb0 | ||||
| #define ST7789V_RAMCTRL_RM_RGB			BIT(4) | ||||
| #define ST7789V_RAMCTRL_DM_RGB			BIT(0) | ||||
| #define ST7789V_RAMCTRL_MAGIC			(3 << 6) | ||||
| #define ST7789V_RAMCTRL_EPF(n)			(((n) & 3) << 4) | ||||
| 
 | ||||
| #define ST7789V_RGBCTRL_CMD		0xb1 | ||||
| #define ST7789V_RGBCTRL_WO			BIT(7) | ||||
| #define ST7789V_RGBCTRL_RCM(n)			(((n) & 3) << 5) | ||||
| #define ST7789V_RGBCTRL_VSYNC_HIGH		BIT(3) | ||||
| #define ST7789V_RGBCTRL_HSYNC_HIGH		BIT(2) | ||||
| #define ST7789V_RGBCTRL_PCLK_HIGH		BIT(1) | ||||
| #define ST7789V_RGBCTRL_VBP(n)			((n) & 0x7f) | ||||
| #define ST7789V_RGBCTRL_HBP(n)			((n) & 0x1f) | ||||
| 
 | ||||
| #define ST7789V_PORCTRL_CMD		0xb2 | ||||
| #define ST7789V_PORCTRL_IDLE_BP(n)		(((n) & 0xf) << 4) | ||||
| #define ST7789V_PORCTRL_IDLE_FP(n)		((n) & 0xf) | ||||
| #define ST7789V_PORCTRL_PARTIAL_BP(n)		(((n) & 0xf) << 4) | ||||
| #define ST7789V_PORCTRL_PARTIAL_FP(n)		((n) & 0xf) | ||||
| 
 | ||||
| #define ST7789V_GCTRL_CMD		0xb7 | ||||
| #define ST7789V_GCTRL_VGHS(n)			(((n) & 7) << 4) | ||||
| #define ST7789V_GCTRL_VGLS(n)			((n) & 7) | ||||
| 
 | ||||
| #define ST7789V_VCOMS_CMD		0xbb | ||||
| 
 | ||||
| #define ST7789V_LCMCTRL_CMD		0xc0 | ||||
| #define ST7789V_LCMCTRL_XBGR			BIT(5) | ||||
| #define ST7789V_LCMCTRL_XMX			BIT(3) | ||||
| #define ST7789V_LCMCTRL_XMH			BIT(2) | ||||
| 
 | ||||
| #define ST7789V_VDVVRHEN_CMD		0xc2 | ||||
| #define ST7789V_VDVVRHEN_CMDEN			BIT(0) | ||||
| 
 | ||||
| #define ST7789V_VRHS_CMD		0xc3 | ||||
| 
 | ||||
| #define ST7789V_VDVS_CMD		0xc4 | ||||
| 
 | ||||
| #define ST7789V_FRCTRL2_CMD		0xc6 | ||||
| 
 | ||||
| #define ST7789V_PWCTRL1_CMD		0xd0 | ||||
| #define ST7789V_PWCTRL1_MAGIC			0xa4 | ||||
| #define ST7789V_PWCTRL1_AVDD(n)			(((n) & 3) << 6) | ||||
| #define ST7789V_PWCTRL1_AVCL(n)			(((n) & 3) << 4) | ||||
| #define ST7789V_PWCTRL1_VDS(n)			((n) & 3) | ||||
| 
 | ||||
| #define ST7789V_PVGAMCTRL_CMD		0xe0 | ||||
| #define ST7789V_PVGAMCTRL_JP0(n)		(((n) & 3) << 4) | ||||
| #define ST7789V_PVGAMCTRL_JP1(n)		(((n) & 3) << 4) | ||||
| #define ST7789V_PVGAMCTRL_VP0(n)		((n) & 0xf) | ||||
| #define ST7789V_PVGAMCTRL_VP1(n)		((n) & 0x3f) | ||||
| #define ST7789V_PVGAMCTRL_VP2(n)		((n) & 0x3f) | ||||
| #define ST7789V_PVGAMCTRL_VP4(n)		((n) & 0x1f) | ||||
| #define ST7789V_PVGAMCTRL_VP6(n)		((n) & 0x1f) | ||||
| #define ST7789V_PVGAMCTRL_VP13(n)		((n) & 0xf) | ||||
| #define ST7789V_PVGAMCTRL_VP20(n)		((n) & 0x7f) | ||||
| #define ST7789V_PVGAMCTRL_VP27(n)		((n) & 7) | ||||
| #define ST7789V_PVGAMCTRL_VP36(n)		(((n) & 7) << 4) | ||||
| #define ST7789V_PVGAMCTRL_VP43(n)		((n) & 0x7f) | ||||
| #define ST7789V_PVGAMCTRL_VP50(n)		((n) & 0xf) | ||||
| #define ST7789V_PVGAMCTRL_VP57(n)		((n) & 0x1f) | ||||
| #define ST7789V_PVGAMCTRL_VP59(n)		((n) & 0x1f) | ||||
| #define ST7789V_PVGAMCTRL_VP61(n)		((n) & 0x3f) | ||||
| #define ST7789V_PVGAMCTRL_VP62(n)		((n) & 0x3f) | ||||
| #define ST7789V_PVGAMCTRL_VP63(n)		(((n) & 0xf) << 4) | ||||
| 
 | ||||
| #define ST7789V_NVGAMCTRL_CMD		0xe1 | ||||
| #define ST7789V_NVGAMCTRL_JN0(n)		(((n) & 3) << 4) | ||||
| #define ST7789V_NVGAMCTRL_JN1(n)		(((n) & 3) << 4) | ||||
| #define ST7789V_NVGAMCTRL_VN0(n)		((n) & 0xf) | ||||
| #define ST7789V_NVGAMCTRL_VN1(n)		((n) & 0x3f) | ||||
| #define ST7789V_NVGAMCTRL_VN2(n)		((n) & 0x3f) | ||||
| #define ST7789V_NVGAMCTRL_VN4(n)		((n) & 0x1f) | ||||
| #define ST7789V_NVGAMCTRL_VN6(n)		((n) & 0x1f) | ||||
| #define ST7789V_NVGAMCTRL_VN13(n)		((n) & 0xf) | ||||
| #define ST7789V_NVGAMCTRL_VN20(n)		((n) & 0x7f) | ||||
| #define ST7789V_NVGAMCTRL_VN27(n)		((n) & 7) | ||||
| #define ST7789V_NVGAMCTRL_VN36(n)		(((n) & 7) << 4) | ||||
| #define ST7789V_NVGAMCTRL_VN43(n)		((n) & 0x7f) | ||||
| #define ST7789V_NVGAMCTRL_VN50(n)		((n) & 0xf) | ||||
| #define ST7789V_NVGAMCTRL_VN57(n)		((n) & 0x1f) | ||||
| #define ST7789V_NVGAMCTRL_VN59(n)		((n) & 0x1f) | ||||
| #define ST7789V_NVGAMCTRL_VN61(n)		((n) & 0x3f) | ||||
| #define ST7789V_NVGAMCTRL_VN62(n)		((n) & 0x3f) | ||||
| #define ST7789V_NVGAMCTRL_VN63(n)		(((n) & 0xf) << 4) | ||||
| 
 | ||||
| #define ST7789V_TEST(val, func)			\ | ||||
| 	do {					\ | ||||
| 		if ((val = (func)))		\ | ||||
| 			return val;		\ | ||||
| 	} while (0) | ||||
| 
 | ||||
| struct st7789v { | ||||
| 	struct drm_panel panel; | ||||
| 	struct spi_device *spi; | ||||
| 	struct gpio_desc *reset; | ||||
| 	struct backlight_device *backlight; | ||||
| 	struct regulator *power; | ||||
| }; | ||||
| 
 | ||||
| enum st7789v_prefix { | ||||
| 	ST7789V_COMMAND = 0, | ||||
| 	ST7789V_DATA = 1, | ||||
| }; | ||||
| 
 | ||||
| static inline struct st7789v *panel_to_st7789v(struct drm_panel *panel) | ||||
| { | ||||
| 	return container_of(panel, struct st7789v, panel); | ||||
| } | ||||
| 
 | ||||
| static int st7789v_spi_write(struct st7789v *ctx, enum st7789v_prefix prefix, | ||||
| 			     u8 data) | ||||
| { | ||||
| 	struct spi_transfer xfer = { }; | ||||
| 	struct spi_message msg; | ||||
| 	u16 txbuf = ((prefix & 1) << 8) | data; | ||||
| 
 | ||||
| 	spi_message_init(&msg); | ||||
| 
 | ||||
| 	xfer.tx_buf = &txbuf; | ||||
| 	xfer.bits_per_word = 9; | ||||
| 	xfer.len = sizeof(txbuf); | ||||
| 
 | ||||
| 	spi_message_add_tail(&xfer, &msg); | ||||
| 	return spi_sync(ctx->spi, &msg); | ||||
| } | ||||
| 
 | ||||
| static int st7789v_write_command(struct st7789v *ctx, u8 cmd) | ||||
| { | ||||
| 	return st7789v_spi_write(ctx, ST7789V_COMMAND, cmd); | ||||
| } | ||||
| 
 | ||||
| static int st7789v_write_data(struct st7789v *ctx, u8 cmd) | ||||
| { | ||||
| 	return st7789v_spi_write(ctx, ST7789V_DATA, cmd); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_display_mode default_mode = { | ||||
| 	.clock = 7000, | ||||
| 	.hdisplay = 240, | ||||
| 	.hsync_start = 240 + 38, | ||||
| 	.hsync_end = 240 + 38 + 10, | ||||
| 	.htotal = 240 + 38 + 10 + 10, | ||||
| 	.vdisplay = 320, | ||||
| 	.vsync_start = 320 + 8, | ||||
| 	.vsync_end = 320 + 8 + 4, | ||||
| 	.vtotal = 320 + 8 + 4 + 4, | ||||
| 	.vrefresh = 60, | ||||
| }; | ||||
| 
 | ||||
| static int st7789v_get_modes(struct drm_panel *panel) | ||||
| { | ||||
| 	struct drm_connector *connector = panel->connector; | ||||
| 	struct drm_display_mode *mode; | ||||
| 
 | ||||
| 	mode = drm_mode_duplicate(panel->drm, &default_mode); | ||||
| 	if (!mode) { | ||||
| 		dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n", | ||||
| 			default_mode.hdisplay, default_mode.vdisplay, | ||||
| 			default_mode.vrefresh); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	drm_mode_set_name(mode); | ||||
| 
 | ||||
| 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | ||||
| 	drm_mode_probed_add(connector, mode); | ||||
| 
 | ||||
| 	panel->connector->display_info.width_mm = 61; | ||||
| 	panel->connector->display_info.height_mm = 103; | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static int st7789v_prepare(struct drm_panel *panel) | ||||
| { | ||||
| 	struct st7789v *ctx = panel_to_st7789v(panel); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = regulator_enable(ctx->power); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	gpiod_set_value(ctx->reset, 1); | ||||
| 	msleep(30); | ||||
| 	gpiod_set_value(ctx->reset, 0); | ||||
| 	msleep(120); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_EXIT_SLEEP_MODE)); | ||||
| 
 | ||||
| 	/* We need to wait 120ms after a sleep out command */ | ||||
| 	msleep(120); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, | ||||
| 						MIPI_DCS_SET_ADDRESS_MODE)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, | ||||
| 						MIPI_DCS_SET_PIXEL_FORMAT)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, | ||||
| 					     (MIPI_DCS_PIXEL_FMT_18BIT << 4) | | ||||
| 					     (MIPI_DCS_PIXEL_FMT_18BIT))); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PORCTRL_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0xc)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0xc)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PORCTRL_IDLE_BP(3) | | ||||
| 					     ST7789V_PORCTRL_IDLE_FP(3))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, | ||||
| 					     ST7789V_PORCTRL_PARTIAL_BP(3) | | ||||
| 					     ST7789V_PORCTRL_PARTIAL_FP(3))); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_GCTRL_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_GCTRL_VGLS(5) | | ||||
| 					     ST7789V_GCTRL_VGHS(3))); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VCOMS_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0x2b)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_LCMCTRL_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_LCMCTRL_XMH | | ||||
| 					     ST7789V_LCMCTRL_XMX | | ||||
| 					     ST7789V_LCMCTRL_XBGR)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VDVVRHEN_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_VDVVRHEN_CMDEN)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VRHS_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0xf)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_VDVS_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0x20)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_FRCTRL2_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, 0xf)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PWCTRL1_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PWCTRL1_MAGIC)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PWCTRL1_AVDD(2) | | ||||
| 					     ST7789V_PWCTRL1_AVCL(2) | | ||||
| 					     ST7789V_PWCTRL1_VDS(1))); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_PVGAMCTRL_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP63(0xd))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP1(0xca))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP2(0xe))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP4(8))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP6(9))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP13(7))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP20(0x2d))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP27(0xb) | | ||||
| 					     ST7789V_PVGAMCTRL_VP36(3))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP43(0x3d))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_JP1(3) | | ||||
| 					     ST7789V_PVGAMCTRL_VP50(4))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP57(0xa))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP59(0xa))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP61(0x1b))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_PVGAMCTRL_VP62(0x28))); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_NVGAMCTRL_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN63(0xd))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN1(0xca))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN2(0xf))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN4(8))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN6(8))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN13(7))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN20(0x2e))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN27(0xc) | | ||||
| 					     ST7789V_NVGAMCTRL_VN36(5))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN43(0x40))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_JN1(3) | | ||||
| 					     ST7789V_NVGAMCTRL_VN50(4))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN57(9))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN59(0xb))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN61(0x1b))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_NVGAMCTRL_VN62(0x28))); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_ENTER_INVERT_MODE)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_RAMCTRL_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RAMCTRL_DM_RGB | | ||||
| 					     ST7789V_RAMCTRL_RM_RGB)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RAMCTRL_EPF(3) | | ||||
| 					     ST7789V_RAMCTRL_MAGIC)); | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, ST7789V_RGBCTRL_CMD)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_WO | | ||||
| 					     ST7789V_RGBCTRL_RCM(2) | | ||||
| 					     ST7789V_RGBCTRL_VSYNC_HIGH | | ||||
| 					     ST7789V_RGBCTRL_HSYNC_HIGH | | ||||
| 					     ST7789V_RGBCTRL_PCLK_HIGH)); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_VBP(8))); | ||||
| 	ST7789V_TEST(ret, st7789v_write_data(ctx, ST7789V_RGBCTRL_HBP(20))); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int st7789v_enable(struct drm_panel *panel) | ||||
| { | ||||
| 	struct st7789v *ctx = panel_to_st7789v(panel); | ||||
| 
 | ||||
| 	if (ctx->backlight) { | ||||
| 		ctx->backlight->props.state &= ~BL_CORE_FBBLANK; | ||||
| 		ctx->backlight->props.power = FB_BLANK_UNBLANK; | ||||
| 		backlight_update_status(ctx->backlight); | ||||
| 	} | ||||
| 
 | ||||
| 	return st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_ON); | ||||
| } | ||||
| 
 | ||||
| static int st7789v_disable(struct drm_panel *panel) | ||||
| { | ||||
| 	struct st7789v *ctx = panel_to_st7789v(panel); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_SET_DISPLAY_OFF)); | ||||
| 
 | ||||
| 	if (ctx->backlight) { | ||||
| 		ctx->backlight->props.power = FB_BLANK_POWERDOWN; | ||||
| 		ctx->backlight->props.state |= BL_CORE_FBBLANK; | ||||
| 		backlight_update_status(ctx->backlight); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int st7789v_unprepare(struct drm_panel *panel) | ||||
| { | ||||
| 	struct st7789v *ctx = panel_to_st7789v(panel); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_ENTER_SLEEP_MODE)); | ||||
| 
 | ||||
| 	regulator_disable(ctx->power); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct drm_panel_funcs st7789v_drm_funcs = { | ||||
| 	.disable	= st7789v_disable, | ||||
| 	.enable		= st7789v_enable, | ||||
| 	.get_modes	= st7789v_get_modes, | ||||
| 	.prepare	= st7789v_prepare, | ||||
| 	.unprepare	= st7789v_unprepare, | ||||
| }; | ||||
| 
 | ||||
| static int st7789v_probe(struct spi_device *spi) | ||||
| { | ||||
| 	struct device_node *backlight; | ||||
| 	struct st7789v *ctx; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL); | ||||
| 	if (!ctx) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	spi_set_drvdata(spi, ctx); | ||||
| 	ctx->spi = spi; | ||||
| 
 | ||||
| 	ctx->panel.dev = &spi->dev; | ||||
| 	ctx->panel.funcs = &st7789v_drm_funcs; | ||||
| 
 | ||||
| 	ctx->power = devm_regulator_get(&spi->dev, "power"); | ||||
| 	if (IS_ERR(ctx->power)) | ||||
| 		return PTR_ERR(ctx->power); | ||||
| 
 | ||||
| 	ctx->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); | ||||
| 	if (IS_ERR(ctx->reset)) { | ||||
| 		dev_err(&spi->dev, "Couldn't get our reset line\n"); | ||||
| 		return PTR_ERR(ctx->reset); | ||||
| 	} | ||||
| 
 | ||||
| 	backlight = of_parse_phandle(spi->dev.of_node, "backlight", 0); | ||||
| 	if (backlight) { | ||||
| 		ctx->backlight = of_find_backlight_by_node(backlight); | ||||
| 		of_node_put(backlight); | ||||
| 
 | ||||
| 		if (!ctx->backlight) | ||||
| 			return -EPROBE_DEFER; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = drm_panel_add(&ctx->panel); | ||||
| 	if (ret < 0) | ||||
| 		goto err_free_backlight; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_free_backlight: | ||||
| 	if (ctx->backlight) | ||||
| 		put_device(&ctx->backlight->dev); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int st7789v_remove(struct spi_device *spi) | ||||
| { | ||||
| 	struct st7789v *ctx = spi_get_drvdata(spi); | ||||
| 
 | ||||
| 	drm_panel_detach(&ctx->panel); | ||||
| 	drm_panel_remove(&ctx->panel); | ||||
| 
 | ||||
| 	if (ctx->backlight) | ||||
| 		put_device(&ctx->backlight->dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct of_device_id st7789v_of_match[] = { | ||||
| 	{ .compatible = "sitronix,st7789v" }, | ||||
| 	{ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, st7789v_of_match); | ||||
| 
 | ||||
| static struct spi_driver st7789v_driver = { | ||||
| 	.probe = st7789v_probe, | ||||
| 	.remove = st7789v_remove, | ||||
| 	.driver = { | ||||
| 		.name = "st7789v", | ||||
| 		.of_match_table = st7789v_of_match, | ||||
| 	}, | ||||
| }; | ||||
| module_spi_driver(st7789v_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||||
| MODULE_DESCRIPTION("Sitronix st7789v LCD Driver"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| @@ -66,7 +66,9 @@ static struct gdp_format_to_str { | ||||
| #define GAM_GDP_ALPHARANGE_255  BIT(5) | ||||
| #define GAM_GDP_AGC_FULL_RANGE  0x00808080 | ||||
| #define GAM_GDP_PPT_IGNORE      (BIT(1) | BIT(0)) | ||||
| #define GAM_GDP_SIZE_MAX        0x7FF | ||||
| 
 | ||||
| #define GAM_GDP_SIZE_MAX_WIDTH  3840 | ||||
| #define GAM_GDP_SIZE_MAX_HEIGHT 2160 | ||||
| 
 | ||||
| #define GDP_NODE_NB_BANK        2 | ||||
| #define GDP_NODE_PER_FIELD      2 | ||||
| @@ -632,8 +634,8 @@ static int sti_gdp_atomic_check(struct drm_plane *drm_plane, | ||||
| 	/* src_x are in 16.16 format */ | ||||
| 	src_x = state->src_x >> 16; | ||||
| 	src_y = state->src_y >> 16; | ||||
| 	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX); | ||||
| 	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX); | ||||
| 	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX_WIDTH); | ||||
| 	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX_HEIGHT); | ||||
| 
 | ||||
| 	format = sti_gdp_fourcc2format(fb->format->format); | ||||
| 	if (format == -1) { | ||||
| @@ -741,8 +743,8 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, | ||||
| 	/* src_x are in 16.16 format */ | ||||
| 	src_x = state->src_x >> 16; | ||||
| 	src_y = state->src_y >> 16; | ||||
| 	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX); | ||||
| 	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX); | ||||
| 	src_w = clamp_val(state->src_w >> 16, 0, GAM_GDP_SIZE_MAX_WIDTH); | ||||
| 	src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX_HEIGHT); | ||||
| 
 | ||||
| 	list = sti_gdp_get_free_nodes(gdp); | ||||
| 	top_field = list->top_field; | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| sun4i-drm-y += sun4i_crtc.o | ||||
| sun4i-drm-y += sun4i_drv.o | ||||
| sun4i-drm-y += sun4i_framebuffer.o | ||||
| sun4i-drm-y += sun4i_layer.o | ||||
|  | ||||
| sun4i-tcon-y += sun4i_tcon.o | ||||
| sun4i-tcon-y += sun4i_rgb.o | ||||
| sun4i-tcon-y += sun4i_dotclock.o | ||||
| sun4i-tcon-y += sun4i_crtc.o | ||||
| sun4i-tcon-y += sun4i_layer.o | ||||
|  | ||||
| obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o | ||||
| obj-$(CONFIG_DRM_SUN4I)		+= sun4i_backend.o | ||||
|   | ||||
| @@ -24,7 +24,7 @@ | ||||
| #include "sun4i_backend.h" | ||||
| #include "sun4i_drv.h" | ||||
| 
 | ||||
| static u32 sunxi_rgb2yuv_coef[12] = { | ||||
| static const u32 sunxi_rgb2yuv_coef[12] = { | ||||
| 	0x00000107, 0x00000204, 0x00000064, 0x00000108, | ||||
| 	0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, | ||||
| 	0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
| #include <linux/clk-provider.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/of_address.h> | ||||
| #include <linux/of_graph.h> | ||||
| #include <linux/of_irq.h> | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| @@ -27,6 +28,7 @@ | ||||
| #include "sun4i_backend.h" | ||||
| #include "sun4i_crtc.h" | ||||
| #include "sun4i_drv.h" | ||||
| #include "sun4i_layer.h" | ||||
| #include "sun4i_tcon.h" | ||||
| 
 | ||||
| static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, | ||||
| @@ -50,12 +52,11 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, | ||||
| 				    struct drm_crtc_state *old_state) | ||||
| { | ||||
| 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | ||||
| 	struct sun4i_drv *drv = scrtc->drv; | ||||
| 	struct drm_pending_vblank_event *event = crtc->state->event; | ||||
| 
 | ||||
| 	DRM_DEBUG_DRIVER("Committing plane changes\n"); | ||||
| 
 | ||||
| 	sun4i_backend_commit(drv->backend); | ||||
| 	sun4i_backend_commit(scrtc->backend); | ||||
| 
 | ||||
| 	if (event) { | ||||
| 		crtc->state->event = NULL; | ||||
| @@ -72,11 +73,10 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc, | ||||
| static void sun4i_crtc_disable(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | ||||
| 	struct sun4i_drv *drv = scrtc->drv; | ||||
| 
 | ||||
| 	DRM_DEBUG_DRIVER("Disabling the CRTC\n"); | ||||
| 
 | ||||
| 	sun4i_tcon_disable(drv->tcon); | ||||
| 	sun4i_tcon_disable(scrtc->tcon); | ||||
| 
 | ||||
| 	if (crtc->state->event && !crtc->state->active) { | ||||
| 		spin_lock_irq(&crtc->dev->event_lock); | ||||
| @@ -90,11 +90,10 @@ static void sun4i_crtc_disable(struct drm_crtc *crtc) | ||||
| static void sun4i_crtc_enable(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | ||||
| 	struct sun4i_drv *drv = scrtc->drv; | ||||
| 
 | ||||
| 	DRM_DEBUG_DRIVER("Enabling the CRTC\n"); | ||||
| 
 | ||||
| 	sun4i_tcon_enable(drv->tcon); | ||||
| 	sun4i_tcon_enable(scrtc->tcon); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { | ||||
| @@ -107,11 +106,10 @@ static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = { | ||||
| static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | ||||
| 	struct sun4i_drv *drv = scrtc->drv; | ||||
| 
 | ||||
| 	DRM_DEBUG_DRIVER("Enabling VBLANK on crtc %p\n", crtc); | ||||
| 
 | ||||
| 	sun4i_tcon_enable_vblank(drv->tcon, true); | ||||
| 	sun4i_tcon_enable_vblank(scrtc->tcon, true); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @@ -119,11 +117,10 @@ static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc) | ||||
| static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc) | ||||
| { | ||||
| 	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); | ||||
| 	struct sun4i_drv *drv = scrtc->drv; | ||||
| 
 | ||||
| 	DRM_DEBUG_DRIVER("Disabling VBLANK on crtc %p\n", crtc); | ||||
| 
 | ||||
| 	sun4i_tcon_enable_vblank(drv->tcon, false); | ||||
| 	sun4i_tcon_enable_vblank(scrtc->tcon, false); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_crtc_funcs sun4i_crtc_funcs = { | ||||
| @@ -137,28 +134,67 @@ static const struct drm_crtc_funcs sun4i_crtc_funcs = { | ||||
| 	.disable_vblank		= sun4i_crtc_disable_vblank, | ||||
| }; | ||||
| 
 | ||||
| struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm) | ||||
| struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, | ||||
| 				   struct sun4i_backend *backend, | ||||
| 				   struct sun4i_tcon *tcon) | ||||
| { | ||||
| 	struct sun4i_drv *drv = drm->dev_private; | ||||
| 	struct sun4i_crtc *scrtc; | ||||
| 	int ret; | ||||
| 	struct drm_plane *primary = NULL, *cursor = NULL; | ||||
| 	int ret, i; | ||||
| 
 | ||||
| 	scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL); | ||||
| 	if (!scrtc) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 	scrtc->backend = backend; | ||||
| 	scrtc->tcon = tcon; | ||||
| 
 | ||||
| 	/* Create our layers */ | ||||
| 	scrtc->layers = sun4i_layers_init(drm, scrtc->backend); | ||||
| 	if (IS_ERR(scrtc->layers)) { | ||||
| 		dev_err(drm->dev, "Couldn't create the planes\n"); | ||||
| 		return NULL; | ||||
| 	scrtc->drv = drv; | ||||
| 	} | ||||
| 
 | ||||
| 	/* find primary and cursor planes for drm_crtc_init_with_planes */ | ||||
| 	for (i = 0; scrtc->layers[i]; i++) { | ||||
| 		struct sun4i_layer *layer = scrtc->layers[i]; | ||||
| 
 | ||||
| 		switch (layer->plane.type) { | ||||
| 		case DRM_PLANE_TYPE_PRIMARY: | ||||
| 			primary = &layer->plane; | ||||
| 			break; | ||||
| 		case DRM_PLANE_TYPE_CURSOR: | ||||
| 			cursor = &layer->plane; | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ret = drm_crtc_init_with_planes(drm, &scrtc->crtc, | ||||
| 					drv->primary, | ||||
| 					NULL, | ||||
| 					primary, | ||||
| 					cursor, | ||||
| 					&sun4i_crtc_funcs, | ||||
| 					NULL); | ||||
| 	if (ret) { | ||||
| 		dev_err(drm->dev, "Couldn't init DRM CRTC\n"); | ||||
| 		return NULL; | ||||
| 		return ERR_PTR(ret); | ||||
| 	} | ||||
| 
 | ||||
| 	drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs); | ||||
| 
 | ||||
| 	/* Set crtc.port to output port node of the tcon */ | ||||
| 	scrtc->crtc.port = of_graph_get_port_by_id(scrtc->tcon->dev->of_node, | ||||
| 						   1); | ||||
| 
 | ||||
| 	/* Set possible_crtcs to this crtc for overlay planes */ | ||||
| 	for (i = 0; scrtc->layers[i]; i++) { | ||||
| 		uint32_t possible_crtcs = BIT(drm_crtc_index(&scrtc->crtc)); | ||||
| 		struct sun4i_layer *layer = scrtc->layers[i]; | ||||
| 
 | ||||
| 		if (layer->plane.type == DRM_PLANE_TYPE_OVERLAY) | ||||
| 			layer->plane.possible_crtcs = possible_crtcs; | ||||
| 	} | ||||
| 
 | ||||
| 	return scrtc; | ||||
| } | ||||
|   | ||||
| @@ -17,7 +17,9 @@ struct sun4i_crtc { | ||||
| 	struct drm_crtc			crtc; | ||||
| 	struct drm_pending_vblank_event	*event; | ||||
| 
 | ||||
| 	struct sun4i_drv		*drv; | ||||
| 	struct sun4i_backend		*backend; | ||||
| 	struct sun4i_tcon		*tcon; | ||||
| 	struct sun4i_layer		**layers; | ||||
| }; | ||||
| 
 | ||||
| static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc) | ||||
| @@ -25,6 +27,8 @@ static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc) | ||||
| 	return container_of(crtc, struct sun4i_crtc, crtc); | ||||
| } | ||||
| 
 | ||||
| struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm); | ||||
| struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, | ||||
| 				   struct sun4i_backend *backend, | ||||
| 				   struct sun4i_tcon *tcon); | ||||
| 
 | ||||
| #endif /* _SUN4I_CRTC_H_ */ | ||||
|   | ||||
| @@ -12,6 +12,7 @@ | ||||
| 
 | ||||
| #include <linux/component.h> | ||||
| #include <linux/of_graph.h> | ||||
| #include <linux/of_reserved_mem.h> | ||||
| 
 | ||||
| #include <drm/drmP.h> | ||||
| #include <drm/drm_crtc_helper.h> | ||||
| @@ -20,10 +21,9 @@ | ||||
| #include <drm/drm_fb_helper.h> | ||||
| #include <drm/drm_of.h> | ||||
| 
 | ||||
| #include "sun4i_crtc.h" | ||||
| #include "sun4i_drv.h" | ||||
| #include "sun4i_framebuffer.h" | ||||
| #include "sun4i_layer.h" | ||||
| #include "sun4i_tcon.h" | ||||
| 
 | ||||
| DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); | ||||
| 
 | ||||
| @@ -92,30 +92,25 @@ static int sun4i_drv_bind(struct device *dev) | ||||
| 	} | ||||
| 	drm->dev_private = drv; | ||||
| 
 | ||||
| 	drm_vblank_init(drm, 1); | ||||
| 	ret = of_reserved_mem_device_init(dev); | ||||
| 	if (ret && ret != -ENODEV) { | ||||
| 		dev_err(drm->dev, "Couldn't claim our memory region\n"); | ||||
| 		goto free_drm; | ||||
| 	} | ||||
| 
 | ||||
| 	/* drm_vblank_init calls kcalloc, which can fail */ | ||||
| 	ret = drm_vblank_init(drm, 1); | ||||
| 	if (ret) | ||||
| 		goto free_mem_region; | ||||
| 
 | ||||
| 	drm_mode_config_init(drm); | ||||
| 
 | ||||
| 	ret = component_bind_all(drm->dev, drm); | ||||
| 	if (ret) { | ||||
| 		dev_err(drm->dev, "Couldn't bind all pipelines components\n"); | ||||
| 		goto free_drm; | ||||
| 		goto cleanup_mode_config; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Create our layers */ | ||||
| 	drv->layers = sun4i_layers_init(drm); | ||||
| 	if (IS_ERR(drv->layers)) { | ||||
| 		dev_err(drm->dev, "Couldn't create the planes\n"); | ||||
| 		ret = PTR_ERR(drv->layers); | ||||
| 		goto free_drm; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Create our CRTC */ | ||||
| 	drv->crtc = sun4i_crtc_init(drm); | ||||
| 	if (!drv->crtc) { | ||||
| 		dev_err(drm->dev, "Couldn't create the CRTC\n"); | ||||
| 		ret = -EINVAL; | ||||
| 		goto free_drm; | ||||
| 	} | ||||
| 	drm->irq_enabled = true; | ||||
| 
 | ||||
| 	/* Remove early framebuffers (ie. simplefb) */ | ||||
| @@ -126,7 +121,7 @@ static int sun4i_drv_bind(struct device *dev) | ||||
| 	if (IS_ERR(drv->fbdev)) { | ||||
| 		dev_err(drm->dev, "Couldn't create our framebuffer\n"); | ||||
| 		ret = PTR_ERR(drv->fbdev); | ||||
| 		goto free_drm; | ||||
| 		goto cleanup_mode_config; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Enable connectors polling */ | ||||
| @@ -134,10 +129,18 @@ static int sun4i_drv_bind(struct device *dev) | ||||
| 
 | ||||
| 	ret = drm_dev_register(drm, 0); | ||||
| 	if (ret) | ||||
| 		goto free_drm; | ||||
| 		goto finish_poll; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| finish_poll: | ||||
| 	drm_kms_helper_poll_fini(drm); | ||||
| 	sun4i_framebuffer_free(drm); | ||||
| cleanup_mode_config: | ||||
| 	drm_mode_config_cleanup(drm); | ||||
| 	drm_vblank_cleanup(drm); | ||||
| free_mem_region: | ||||
| 	of_reserved_mem_device_release(dev); | ||||
| free_drm: | ||||
| 	drm_dev_unref(drm); | ||||
| 	return ret; | ||||
| @@ -150,7 +153,9 @@ static void sun4i_drv_unbind(struct device *dev) | ||||
| 	drm_dev_unregister(drm); | ||||
| 	drm_kms_helper_poll_fini(drm); | ||||
| 	sun4i_framebuffer_free(drm); | ||||
| 	drm_mode_config_cleanup(drm); | ||||
| 	drm_vblank_cleanup(drm); | ||||
| 	of_reserved_mem_device_release(dev); | ||||
| 	drm_dev_unref(drm); | ||||
| } | ||||
| 
 | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user