main drm pull request for 4.12 kernel

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJZCTzvAAoJEAx081l5xIa+9kcQAJsQiija4/7QGx6IzakOMqjx
 WulJ3zYG/cU/HLwCBcuWRDF6wAj+7iWNeLCPmolHwEazcI8tQVdgMlWtbdMbDh8U
 ckzD3FBXsEVfIfab+u6tyoUkm3l/VDhMXbjkUK7NTo/+dkRqe5LuFfZPCGN09jft
 Y+5salkRXzDhXPSFsqmjfzhx1v7PTgf0a5HUenKWEWOv+sJQaW4/iPvcDSIcg5qR
 l9WjAqro1NpFYhUodnh6DkLeledL1U5whdtp/yvrUAck8y+WP/jwGYmQ7pZ0UkQm
 f0M3kV6K67ox9eqN++jsGX5o8sB1qF01Uh95kBAnyzYzsw4ZlMCx6pV7PDX+J88M
 UBNMEqX10hrLkNJA9lGjPWx+/6fudcwg9anKvTRO3Uyx7MbYoJAgjzAM+yBqqtV0
 8Otxa4Bw0V2pmUD+0lqJDERRvE77VCXkLb8SaI5lQo0MHpQqT2cZA+GD+B+rZHO6
 Ie5LDFY87vM2GG1IECufG+xOa3v6sn2FfQ1ouu1KNGKOAMBKcQCQyQx3kGVuNW2i
 HDACVXALJgXdRlVLm4jydOCZdRoguX7AWmRjtdwxgaO+lBcGfLhkXdjLQ7Ho+29p
 32ArJfkZPfA53vMB6lHxAfbtrs1q2RzyVnPHj/KqeJnGZbABKTsF2HQ5BQc4Xq/J
 mqXoz6Oubdvk4Pwyx7Ne
 =UxFF
 -----END PGP SIGNATURE-----

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:
Daniel Vetter 2017-05-03 21:41:35 +02:00
commit ad15f74ac6
240 changed files with 4768 additions and 1374 deletions

View File

@ -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@web.de>
Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch> Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
Mark Brown <broonie@sirena.org.uk> 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> Matthieu CASTET <castet.matthieu@free.fr>
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@brturbo.com.br> Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@brturbo.com.br>
Mauro Carvalho Chehab <mchehab@kernel.org> <maurochehab@gmail.com> Mauro Carvalho Chehab <mchehab@kernel.org> <maurochehab@gmail.com>

View File

@ -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>;
};
};
};

View File

@ -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>;
};
};

View File

@ -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>;
};
};
};

View File

@ -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>;
};

View File

@ -336,6 +336,7 @@ wd Western Digital Corp.
wetek WeTek Electronics, limited. wetek WeTek Electronics, limited.
wexler Wexler wexler Wexler
winbond Winbond Electronics corp. winbond Winbond Electronics corp.
winstar Winstar Display Corp.
wlf Wolfson Microelectronics wlf Wolfson Microelectronics
wm Wondermedia Technologies, Inc. wm Wondermedia Technologies, Inc.
x-powers X-Powers x-powers X-Powers

View File

@ -4247,6 +4247,7 @@ L: dri-devel@lists.freedesktop.org
S: Supported S: Supported
F: drivers/gpu/drm/sun4i/ F: drivers/gpu/drm/sun4i/
F: Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt 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 DRM DRIVERS FOR AMLOGIC SOCS
M: Neil Armstrong <narmstrong@baylibre.com> M: Neil Armstrong <narmstrong@baylibre.com>
@ -4417,7 +4418,7 @@ DRM DRIVERS FOR STI
M: Benjamin Gaignard <benjamin.gaignard@linaro.org> M: Benjamin Gaignard <benjamin.gaignard@linaro.org>
M: Vincent Abriou <vincent.abriou@st.com> M: Vincent Abriou <vincent.abriou@st.com>
L: dri-devel@lists.freedesktop.org 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 S: Maintained
F: drivers/gpu/drm/sti F: drivers/gpu/drm/sti
F: Documentation/devicetree/bindings/display/st,stih4xx.txt F: Documentation/devicetree/bindings/display/st,stih4xx.txt
@ -13331,7 +13332,7 @@ F: drivers/virtio/
F: tools/virtio/ F: tools/virtio/
F: drivers/net/virtio_net.c F: drivers/net/virtio_net.c
F: drivers/block/virtio_blk.c F: drivers/block/virtio_blk.c
F: include/linux/virtio_*.h F: include/linux/virtio*.h
F: include/uapi/linux/virtio_*.h F: include/uapi/linux/virtio_*.h
F: drivers/crypto/virtio/ F: drivers/crypto/virtio/

View File

@ -1,7 +1,7 @@
VERSION = 4 VERSION = 4
PATCHLEVEL = 11 PATCHLEVEL = 11
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -rc6 EXTRAVERSION = -rc7
NAME = Fearless Coyote NAME = Fearless Coyote
# *DOCUMENTATION* # *DOCUMENTATION*

View File

@ -371,6 +371,8 @@
phy1: ethernet-phy@1 { phy1: ethernet-phy@1 {
reg = <7>; reg = <7>;
eee-broken-100tx;
eee-broken-1000t;
}; };
}; };

View File

@ -672,6 +672,7 @@
ti,non-removable; ti,non-removable;
bus-width = <4>; bus-width = <4>;
cap-power-off-card; cap-power-off-card;
keep-power-in-suspend;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&mmc2_pins>; pinctrl-0 = <&mmc2_pins>;

View File

@ -283,6 +283,7 @@
device_type = "pci"; device_type = "pci";
ranges = <0x81000000 0 0 0x03000 0 0x00010000 ranges = <0x81000000 0 0 0x03000 0 0x00010000
0x82000000 0 0x20013000 0x13000 0 0xffed000>; 0x82000000 0 0x20013000 0x13000 0 0xffed000>;
bus-range = <0x00 0xff>;
#interrupt-cells = <1>; #interrupt-cells = <1>;
num-lanes = <1>; num-lanes = <1>;
linux,pci-domain = <0>; linux,pci-domain = <0>;
@ -319,6 +320,7 @@
device_type = "pci"; device_type = "pci";
ranges = <0x81000000 0 0 0x03000 0 0x00010000 ranges = <0x81000000 0 0 0x03000 0 0x00010000
0x82000000 0 0x30013000 0x13000 0 0xffed000>; 0x82000000 0 0x30013000 0x13000 0 0xffed000>;
bus-range = <0x00 0xff>;
#interrupt-cells = <1>; #interrupt-cells = <1>;
num-lanes = <1>; num-lanes = <1>;
linux,pci-domain = <1>; linux,pci-domain = <1>;

View File

@ -121,7 +121,7 @@
&i2c3 { &i2c3 {
clock-frequency = <400000>; clock-frequency = <400000>;
at24@50 { at24@50 {
compatible = "at24,24c02"; compatible = "atmel,24c64";
readonly; readonly;
reg = <0x50>; reg = <0x50>;
}; };

View File

@ -66,12 +66,6 @@
opp-microvolt = <1200000>; opp-microvolt = <1200000>;
clock-latency-ns = <244144>; /* 8 32k periods */ 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 { cpus {
@ -81,16 +75,22 @@
operating-points-v2 = <&cpu0_opp_table>; operating-points-v2 = <&cpu0_opp_table>;
}; };
cpu@1 {
operating-points-v2 = <&cpu0_opp_table>;
};
cpu@2 { cpu@2 {
compatible = "arm,cortex-a7"; compatible = "arm,cortex-a7";
device_type = "cpu"; device_type = "cpu";
reg = <2>; reg = <2>;
operating-points-v2 = <&cpu0_opp_table>;
}; };
cpu@3 { cpu@3 {
compatible = "arm,cortex-a7"; compatible = "arm,cortex-a7";
device_type = "cpu"; device_type = "cpu";
reg = <3>; reg = <3>;
operating-points-v2 = <&cpu0_opp_table>;
}; };
}; };

View File

@ -270,6 +270,7 @@ extern const struct smp_operations omap4_smp_ops;
extern int omap4_mpuss_init(void); extern int omap4_mpuss_init(void);
extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state); 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 int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state);
extern u32 omap4_get_cpu1_ns_pa_addr(void);
#else #else
static inline int omap4_enter_lowpower(unsigned int cpu, static inline int omap4_enter_lowpower(unsigned int cpu,
unsigned int power_state) unsigned int power_state)

View File

@ -50,7 +50,7 @@ void omap4_cpu_die(unsigned int cpu)
omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF); omap4_hotplug_cpu(cpu, PWRDM_POWER_OFF);
if (omap_secure_apis_support()) if (omap_secure_apis_support())
boot_cpu = omap_read_auxcoreboot0(); boot_cpu = omap_read_auxcoreboot0() >> 9;
else else
boot_cpu = boot_cpu =
readl_relaxed(base + OMAP_AUX_CORE_BOOT_0) >> 5; readl_relaxed(base + OMAP_AUX_CORE_BOOT_0) >> 5;

View File

@ -64,6 +64,7 @@
#include "prm-regbits-44xx.h" #include "prm-regbits-44xx.h"
static void __iomem *sar_base; static void __iomem *sar_base;
static u32 old_cpu1_ns_pa_addr;
#if defined(CONFIG_PM) && defined(CONFIG_SMP) #if defined(CONFIG_PM) && defined(CONFIG_SMP)
@ -212,6 +213,11 @@ static void __init save_l2x0_context(void)
{} {}
#endif #endif
u32 omap4_get_cpu1_ns_pa_addr(void)
{
return old_cpu1_ns_pa_addr;
}
/** /**
* omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
* The purpose of this function is to manage low power programming * 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) void __init omap4_mpuss_early_init(void)
{ {
unsigned long startup_pa; unsigned long startup_pa;
void __iomem *ns_pa_addr;
if (!(cpu_is_omap44xx() || soc_is_omap54xx())) if (!(soc_is_omap44xx() || soc_is_omap54xx()))
return; return;
sar_base = omap4_get_sar_ram_base(); 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); startup_pa = __pa_symbol(omap4_secondary_startup);
else if (cpu_is_omap446x()) else if (soc_is_omap446x())
startup_pa = __pa_symbol(omap4460_secondary_startup); startup_pa = __pa_symbol(omap4460_secondary_startup);
else if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE) else if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE)
startup_pa = __pa_symbol(omap5_secondary_hyp_startup); startup_pa = __pa_symbol(omap5_secondary_hyp_startup);
else else
startup_pa = __pa_symbol(omap5_secondary_startup); startup_pa = __pa_symbol(omap5_secondary_startup);
if (cpu_is_omap44xx()) if (soc_is_omap44xx())
writel_relaxed(startup_pa, sar_base + writel_relaxed(startup_pa, sar_base +
CPU1_WAKEUP_NS_PA_ADDR_OFFSET); CPU1_WAKEUP_NS_PA_ADDR_OFFSET);
else else

View File

@ -94,6 +94,5 @@ ENTRY(omap_read_auxcoreboot0)
ldr r12, =0x103 ldr r12, =0x103
dsb dsb
smc #0 smc #0
mov r0, r0, lsr #9
ldmfd sp!, {r2-r12, pc} ldmfd sp!, {r2-r12, pc}
ENDPROC(omap_read_auxcoreboot0) ENDPROC(omap_read_auxcoreboot0)

View File

@ -21,6 +21,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic.h>
#include <asm/sections.h>
#include <asm/smp_scu.h> #include <asm/smp_scu.h>
#include <asm/virt.h> #include <asm/virt.h>
@ -40,10 +41,14 @@
#define OMAP5_CORE_COUNT 0x2 #define OMAP5_CORE_COUNT 0x2
#define AUX_CORE_BOOT0_GP_RELEASE 0x020
#define AUX_CORE_BOOT0_HS_RELEASE 0x200
struct omap_smp_config { struct omap_smp_config {
unsigned long cpu1_rstctrl_pa; unsigned long cpu1_rstctrl_pa;
void __iomem *cpu1_rstctrl_va; void __iomem *cpu1_rstctrl_va;
void __iomem *scu_base; void __iomem *scu_base;
void __iomem *wakeupgen_base;
void *startup_addr; 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 struct clockdomain *cpu1_clkdm;
static bool booted; static bool booted;
static struct powerdomain *cpu1_pwrdm; static struct powerdomain *cpu1_pwrdm;
void __iomem *base = omap_get_wakeupgen_base();
/* /*
* Set synchronisation state between this boot processor * 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 * A barrier is added to ensure that write buffer is drained
*/ */
if (omap_secure_apis_support()) if (omap_secure_apis_support())
omap_modify_auxcoreboot0(0x200, 0xfffffdff); omap_modify_auxcoreboot0(AUX_CORE_BOOT0_HS_RELEASE,
0xfffffdff);
else 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) { if (!cpu1_clkdm && !cpu1_pwrdm) {
cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); cpu1_clkdm = clkdm_lookup("mpu1_clkdm");
@ -261,9 +267,72 @@ static void __init omap4_smp_init_cpus(void)
set_cpu_possible(i, true); 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) 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; const struct omap_smp_config *c = NULL;
if (soc_is_omap443x()) 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 */ /* Must preserve cfg.scu_base set earlier */
cfg.cpu1_rstctrl_pa = c->cpu1_rstctrl_pa; cfg.cpu1_rstctrl_pa = c->cpu1_rstctrl_pa;
cfg.startup_addr = c->startup_addr; cfg.startup_addr = c->startup_addr;
cfg.wakeupgen_base = omap_get_wakeupgen_base();
if (soc_is_dra74x() || soc_is_omap54xx()) { if (soc_is_dra74x() || soc_is_omap54xx()) {
if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE) 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) if (cfg.scu_base)
scu_enable(cfg.scu_base); scu_enable(cfg.scu_base);
/* omap4_smp_maybe_reset_cpu1(&cfg);
* 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);
}
/* /*
* Write the address of secondary startup routine into the * 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)); omap_auxcoreboot_addr(__pa_symbol(cfg.startup_addr));
else else
writel_relaxed(__pa_symbol(cfg.startup_addr), 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 = { const struct smp_operations omap4_smp_ops __initconst = {

View File

@ -222,6 +222,14 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
dev_err(dev, "failed to idle\n"); dev_err(dev, "failed to idle\n");
} }
break; 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: case BUS_NOTIFY_ADD_DEVICE:
if (pdev->dev.of_node) if (pdev->dev.of_node)
omap_device_build_from_dt(pdev); omap_device_build_from_dt(pdev);

View File

@ -6,6 +6,7 @@ menuconfig ARCH_ORION5X
select GPIOLIB select GPIOLIB
select MVEBU_MBUS select MVEBU_MBUS
select PCI select PCI
select PHYLIB if NETDEVICES
select PLAT_ORION_LEGACY select PLAT_ORION_LEGACY
help help
Support for the following Marvell Orion 5x series SoCs: Support for the following Marvell Orion 5x series SoCs:

View File

@ -468,6 +468,7 @@ void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
eth_data, &orion_ge11); eth_data, &orion_ge11);
} }
#ifdef CONFIG_ARCH_ORION5X
/***************************************************************************** /*****************************************************************************
* Ethernet switch * Ethernet switch
****************************************************************************/ ****************************************************************************/
@ -480,6 +481,9 @@ void __init orion_ge00_switch_init(struct dsa_chip_data *d)
struct mdio_board_info *bd; struct mdio_board_info *bd;
unsigned int i; unsigned int i;
if (!IS_BUILTIN(CONFIG_PHYLIB))
return;
for (i = 0; i < ARRAY_SIZE(d->port_names); i++) for (i = 0; i < ARRAY_SIZE(d->port_names); i++)
if (!strcmp(d->port_names[i], "cpu")) if (!strcmp(d->port_names[i], "cpu"))
break; 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); mdiobus_register_board_info(&orion_ge00_switch_board_info, 1);
} }
#endif
/***************************************************************************** /*****************************************************************************
* I2C * I2C

View File

@ -179,8 +179,10 @@
usbphy: phy@01c19400 { usbphy: phy@01c19400 {
compatible = "allwinner,sun50i-a64-usb-phy"; compatible = "allwinner,sun50i-a64-usb-phy";
reg = <0x01c19400 0x14>, reg = <0x01c19400 0x14>,
<0x01c1a800 0x4>,
<0x01c1b800 0x4>; <0x01c1b800 0x4>;
reg-names = "phy_ctrl", reg-names = "phy_ctrl",
"pmu0",
"pmu1"; "pmu1";
clocks = <&ccu CLK_USB_PHY0>, clocks = <&ccu CLK_USB_PHY0>,
<&ccu CLK_USB_PHY1>; <&ccu CLK_USB_PHY1>;

View 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 */

View File

@ -24,25 +24,25 @@ AFLAGS___modsi3.o = -DMODULO
AFLAGS___umodsi3.o = -DUNSIGNED -DMODULO AFLAGS___umodsi3.o = -DUNSIGNED -DMODULO
$(obj)/__divdi3.o: $(src)/idiv64.S FORCE $(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 $(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 $(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 $(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 $(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 $(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 $(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 $(obj)/__umodsi3.o: $(src)/idiv32.S FORCE
$(call if_changed_dep,as_o_S) $(call if_changed_rule,as_o_S)

View File

@ -201,7 +201,7 @@ ENTRY_CFI(pa_memcpy)
add dst,len,end add dst,len,end
/* short copy with less than 16 bytes? */ /* short copy with less than 16 bytes? */
cmpib,>>=,n 15,len,.Lbyte_loop cmpib,COND(>>=),n 15,len,.Lbyte_loop
/* same alignment? */ /* same alignment? */
xor src,dst,t0 xor src,dst,t0
@ -216,7 +216,7 @@ ENTRY_CFI(pa_memcpy)
/* loop until we are 64-bit aligned */ /* loop until we are 64-bit aligned */
.Lalign_loop64: .Lalign_loop64:
extru dst,31,3,t1 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 20: ldb,ma 1(srcspc,src),t1
21: stb,ma t1,1(dstspc,dst) 21: stb,ma t1,1(dstspc,dst)
b .Lalign_loop64 b .Lalign_loop64
@ -225,6 +225,7 @@ ENTRY_CFI(pa_memcpy)
ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
.Lcopy_loop_16_start:
ldi 31,t0 ldi 31,t0
.Lcopy_loop_16: .Lcopy_loop_16:
cmpb,COND(>>=),n t0,len,.Lword_loop cmpb,COND(>>=),n t0,len,.Lword_loop
@ -267,7 +268,7 @@ ENTRY_CFI(pa_memcpy)
/* loop until we are 32-bit aligned */ /* loop until we are 32-bit aligned */
.Lalign_loop32: .Lalign_loop32:
extru dst,31,2,t1 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 20: ldb,ma 1(srcspc,src),t1
21: stb,ma t1,1(dstspc,dst) 21: stb,ma t1,1(dstspc,dst)
b .Lalign_loop32 b .Lalign_loop32
@ -277,7 +278,7 @@ ENTRY_CFI(pa_memcpy)
ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
.Lcopy_loop_4: .Lcopy_loop_8:
cmpib,COND(>>=),n 15,len,.Lbyte_loop cmpib,COND(>>=),n 15,len,.Lbyte_loop
10: ldw 0(srcspc,src),t1 10: ldw 0(srcspc,src),t1
@ -299,7 +300,7 @@ ENTRY_CFI(pa_memcpy)
ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
b .Lcopy_loop_4 b .Lcopy_loop_8
ldo -16(len),len ldo -16(len),len
.Lbyte_loop: .Lbyte_loop:
@ -324,7 +325,7 @@ ENTRY_CFI(pa_memcpy)
.Lunaligned_copy: .Lunaligned_copy:
/* align until dst is 32bit-word-aligned */ /* align until dst is 32bit-word-aligned */
extru dst,31,2,t1 extru dst,31,2,t1
cmpib,COND(=),n 0,t1,.Lcopy_dstaligned cmpib,=,n 0,t1,.Lcopy_dstaligned
20: ldb 0(srcspc,src),t1 20: ldb 0(srcspc,src),t1
ldo 1(src),src ldo 1(src),src
21: stb,ma t1,1(dstspc,dst) 21: stb,ma t1,1(dstspc,dst)
@ -362,7 +363,7 @@ ENTRY_CFI(pa_memcpy)
cmpiclr,<> 1,t0,%r0 cmpiclr,<> 1,t0,%r0
b,n .Lcase1 b,n .Lcase1
.Lcase0: .Lcase0:
cmpb,= %r0,len,.Lcda_finish cmpb,COND(=) %r0,len,.Lcda_finish
nop nop
1: ldw,ma 4(srcspc,src), a3 1: ldw,ma 4(srcspc,src), a3
@ -376,7 +377,7 @@ ENTRY_CFI(pa_memcpy)
1: ldw,ma 4(srcspc,src), a3 1: ldw,ma 4(srcspc,src), a3
ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault) ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
ldo -1(len),len ldo -1(len),len
cmpb,=,n %r0,len,.Ldo0 cmpb,COND(=),n %r0,len,.Ldo0
.Ldo4: .Ldo4:
1: ldw,ma 4(srcspc,src), a0 1: ldw,ma 4(srcspc,src), a0
ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault) ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
@ -402,7 +403,7 @@ ENTRY_CFI(pa_memcpy)
1: stw,ma t0, 4(dstspc,dst) 1: stw,ma t0, 4(dstspc,dst)
ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
ldo -4(len),len ldo -4(len),len
cmpb,<> %r0,len,.Ldo4 cmpb,COND(<>) %r0,len,.Ldo4
nop nop
.Ldo0: .Ldo0:
shrpw a2, a3, %sar, t0 shrpw a2, a3, %sar, t0
@ -436,14 +437,14 @@ ENTRY_CFI(pa_memcpy)
/* fault exception fixup handlers: */ /* fault exception fixup handlers: */
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
.Lcopy16_fault: .Lcopy16_fault:
10: b .Lcopy_done b .Lcopy_done
std,ma t1,8(dstspc,dst) 10: std,ma t1,8(dstspc,dst)
ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
#endif #endif
.Lcopy8_fault: .Lcopy8_fault:
10: b .Lcopy_done b .Lcopy_done
stw,ma t1,4(dstspc,dst) 10: stw,ma t1,4(dstspc,dst)
ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done) ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
.exit .exit

View File

@ -30,8 +30,10 @@ static int __init vdso32_setup(char *s)
{ {
vdso32_enabled = simple_strtoul(s, NULL, 0); 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"); pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
vdso32_enabled = 0;
}
return 1; return 1;
} }
@ -62,13 +64,18 @@ subsys_initcall(sysenter_setup);
/* Register vsyscall32 into the ABI table */ /* Register vsyscall32 into the ABI table */
#include <linux/sysctl.h> #include <linux/sysctl.h>
static const int zero;
static const int one = 1;
static struct ctl_table abi_table2[] = { static struct ctl_table abi_table2[] = {
{ {
.procname = "vsyscall32", .procname = "vsyscall32",
.data = &vdso32_enabled, .data = &vdso32_enabled,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec .proc_handler = proc_dointvec_minmax,
.extra1 = (int *)&zero,
.extra2 = (int *)&one,
}, },
{} {}
}; };

View File

@ -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].to = msr_lastbranch.to;
cpuc->lbr_entries[i].mispred = 0; cpuc->lbr_entries[i].mispred = 0;
cpuc->lbr_entries[i].predicted = 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_entries[i].reserved = 0;
} }
cpuc->lbr_stack.nr = i; cpuc->lbr_stack.nr = i;

View File

@ -287,7 +287,7 @@ struct task_struct;
#define ARCH_DLINFO_IA32 \ #define ARCH_DLINFO_IA32 \
do { \ do { \
if (vdso32_enabled) { \ if (VDSO_CURRENT_BASE) { \
NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \ NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \
NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \
} \ } \

View File

@ -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 * @size: number of bytes to write back
* *
* Write back a cache range using the CLWB (cache line 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) 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); 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 * arch_copy_from_iter_pmem - copy data from an iterator to PMEM
* @addr: PMEM destination address * @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 */ /* TODO: skip the write-back by always using non-temporal stores */
len = copy_from_iter_nocache(addr, bytes, i); 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); arch_wb_cache_pmem(addr, bytes);
return len; return len;

View File

@ -200,11 +200,11 @@ ssize_t rdtgroup_schemata_write(struct kernfs_open_file *of,
} }
out: out:
rdtgroup_kn_unlock(of->kn);
for_each_enabled_rdt_resource(r) { for_each_enabled_rdt_resource(r) {
kfree(r->tmp_cbms); kfree(r->tmp_cbms);
r->tmp_cbms = NULL; r->tmp_cbms = NULL;
} }
rdtgroup_kn_unlock(of->kn);
return ret ?: nbytes; return ret ?: nbytes;
} }

View File

@ -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, task_pid_nr(current) > 1 ? KERN_INFO : KERN_EMERG,
me->comm, me->pid, where, frame, me->comm, me->pid, where, frame,
regs->ip, regs->sp, regs->orig_ax); regs->ip, regs->sp, regs->orig_ax);
print_vma_addr(" in ", regs->ip); print_vma_addr(KERN_CONT " in ", regs->ip);
pr_cont("\n"); pr_cont("\n");
} }

View File

@ -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_signo == SIGSEGV) {
if (from->si_code == SEGV_BNDERR) { if (from->si_code == SEGV_BNDERR) {
compat_uptr_t lower = (unsigned long)&to->si_lower; compat_uptr_t lower = (unsigned long)from->si_lower;
compat_uptr_t upper = (unsigned long)&to->si_upper; compat_uptr_t upper = (unsigned long)from->si_upper;
put_user_ex(lower, &to->si_lower); put_user_ex(lower, &to->si_lower);
put_user_ex(upper, &to->si_upper); put_user_ex(upper, &to->si_upper);
} }

View File

@ -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", pr_info("%s[%d] trap %s ip:%lx sp:%lx error:%lx",
tsk->comm, tsk->pid, str, tsk->comm, tsk->pid, str,
regs->ip, regs->sp, error_code); regs->ip, regs->sp, error_code);
print_vma_addr(" in ", regs->ip); print_vma_addr(KERN_CONT " in ", regs->ip);
pr_cont("\n"); 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", pr_info("%s[%d] general protection ip:%lx sp:%lx error:%lx",
tsk->comm, task_pid_nr(tsk), tsk->comm, task_pid_nr(tsk),
regs->ip, regs->sp, error_code); regs->ip, regs->sp, error_code);
print_vma_addr(" in ", regs->ip); print_vma_addr(KERN_CONT " in ", regs->ip);
pr_cont("\n"); pr_cont("\n");
} }

View File

@ -643,21 +643,40 @@ void __init init_mem_mapping(void)
* devmem_is_allowed() checks to see if /dev/mem access to a certain address * devmem_is_allowed() checks to see if /dev/mem access to a certain address
* is valid. The argument is a physical page number. * is valid. The argument is a physical page number.
* *
* * On x86, access has to be given to the first megabyte of RAM because that
* On x86, access has to be given to the first megabyte of ram because that area * area traditionally contains BIOS code and data regions used by X, dosemu,
* contains BIOS code and data regions used by X and dosemu and similar apps. * and similar apps. Since they map the entire memory range, the whole range
* Access has to be given to non-kernel-ram areas as well, these contain the PCI * must be allowed (for mapping), but any areas that would otherwise be
* mmio resources as well as potential bios/acpi data regions. * 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) int devmem_is_allowed(unsigned long pagenr)
{ {
if (pagenr < 256) if (page_is_ram(pagenr)) {
return 1; /*
if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) * 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; 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) void free_init_pages(char *what, unsigned long begin, unsigned long end)

View File

@ -201,6 +201,10 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size)
return; return;
} }
/* No need to reserve regions that will never be freed. */
if (md.attribute & EFI_MEMORY_RUNTIME)
return;
size += addr % EFI_PAGE_SIZE; size += addr % EFI_PAGE_SIZE;
size = round_up(size, EFI_PAGE_SIZE); size = round_up(size, EFI_PAGE_SIZE);
addr = round_down(addr, EFI_PAGE_SIZE); addr = round_down(addr, EFI_PAGE_SIZE);

View File

@ -421,10 +421,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE(ut_walk_aml_resources); ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
/* /* The absolute minimum resource template is one end_tag descriptor */
* The absolute minimum resource template is one end_tag descriptor.
* However, we will treat a lone end_tag as just a simple buffer.
*/
if (aml_length < sizeof(struct aml_resource_end_tag)) { if (aml_length < sizeof(struct aml_resource_end_tag)) {
return_ACPI_STATUS(AE_AML_NO_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 */ /* Invoke the user function */
if (user_function) { if (user_function) {
status = user_function(aml, length, offset, status =
resource_index, context); user_function(aml, length, offset, resource_index,
context);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
@ -481,12 +480,6 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
*context = aml; *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 */ /* Normal exit */
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);

View File

@ -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 *map0 = m0;
const struct nfit_set_info_map *map1 = m1; 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 */ /* Retrieve the nth entry referencing this spa */

View File

@ -1857,15 +1857,20 @@ static void acpi_bus_attach(struct acpi_device *device)
return; return;
device->flags.match_driver = true; device->flags.match_driver = true;
if (!ret) { if (ret > 0) {
ret = device_attach(&device->dev); acpi_device_set_enumerated(device);
if (ret < 0) goto ok;
return;
if (!ret && device->pnp.type.platform_id)
acpi_default_enumeration(device);
} }
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: ok:
list_for_each_entry(child, &device->children, node) list_for_each_entry(child, &device->children, node)
acpi_bus_attach(child); acpi_bus_attach(child);

View File

@ -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 }; 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, return ata_pci_bmdma_init_one(pdev, ppi, &atiixp_sht, NULL,
ATA_HOST_PARALLEL_SCAN); ATA_HOST_PARALLEL_SCAN);
} }

View File

@ -644,14 +644,16 @@ static void svia_configure(struct pci_dev *pdev, int board_id,
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
} }
/* enable IRQ on hotplug */ if (board_id == vt6421) {
pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8); /* enable IRQ on hotplug */
if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) { pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8);
dev_dbg(&pdev->dev, if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) {
"enabling SATA hotplug (0x%x)\n", dev_dbg(&pdev->dev,
(int) tmp8); "enabling SATA hotplug (0x%x)\n",
tmp8 |= SATA_HOTPLUG; (int) tmp8);
pci_write_config_byte(pdev, SVIA_MISC_3, tmp8); tmp8 |= SATA_HOTPLUG;
pci_write_config_byte(pdev, SVIA_MISC_3, tmp8);
}
} }
/* /*

View File

@ -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); cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
if (size == PAGE_SIZE) { if (size == PAGE_SIZE) {
copy_page(mem, cmem); memcpy(mem, cmem, PAGE_SIZE);
} else { } else {
struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp); struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp);
@ -717,7 +717,7 @@ compress_again:
if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) { if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
src = kmap_atomic(page); src = kmap_atomic(page);
copy_page(cmem, src); memcpy(cmem, src, PAGE_SIZE);
kunmap_atomic(src); kunmap_atomic(src);
} else { } else {
memcpy(cmem, src, clen); 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; 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_page = page;
bv.bv_len = PAGE_SIZE; bv.bv_len = PAGE_SIZE;

View File

@ -60,6 +60,10 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
#endif #endif
#ifdef CONFIG_STRICT_DEVMEM #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) static inline int range_is_allowed(unsigned long pfn, unsigned long size)
{ {
u64 from = ((u64)pfn) << PAGE_SHIFT; u64 from = ((u64)pfn) << PAGE_SHIFT;
@ -75,6 +79,10 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
return 1; return 1;
} }
#else #else
static inline int page_is_allowed(unsigned long pfn)
{
return 1;
}
static inline int range_is_allowed(unsigned long pfn, unsigned long size) static inline int range_is_allowed(unsigned long pfn, unsigned long size)
{ {
return 1; return 1;
@ -122,23 +130,31 @@ static ssize_t read_mem(struct file *file, char __user *buf,
while (count > 0) { while (count > 0) {
unsigned long remaining; unsigned long remaining;
int allowed;
sz = size_inside_page(p, count); 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; 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;
/* remaining = copy_to_user(buf, ptr, sz);
* On ia64 if a page has been mapped somewhere as uncached, then
* it must also be accessed uncached by the kernel or data unxlate_dev_mem_ptr(p, ptr);
* 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);
if (remaining) if (remaining)
return -EFAULT; return -EFAULT;
@ -181,30 +197,36 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
#endif #endif
while (count > 0) { while (count > 0) {
int allowed;
sz = size_inside_page(p, count); 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; return -EPERM;
/* /* Skip actual writing when a page is marked as restricted. */
* On ia64 if a page has been mapped somewhere as uncached, then if (allowed == 1) {
* it must also be accessed uncached by the kernel or data /*
* corruption may occur. * On ia64 if a page has been mapped somewhere as
*/ * uncached, then it must also be accessed uncached
ptr = xlate_dev_mem_ptr(p); * by the kernel or data corruption may occur.
if (!ptr) { */
if (written) ptr = xlate_dev_mem_ptr(p);
break; if (!ptr) {
return -EFAULT; if (written)
} break;
return -EFAULT;
}
copied = copy_from_user(ptr, buf, sz); copied = copy_from_user(ptr, buf, sz);
unxlate_dev_mem_ptr(p, ptr); unxlate_dev_mem_ptr(p, ptr);
if (copied) { if (copied) {
written += sz - copied; written += sz - copied;
if (written) if (written)
break; break;
return -EFAULT; return -EFAULT;
}
} }
buf += sz; buf += sz;

View File

@ -2202,14 +2202,16 @@ static int virtcons_freeze(struct virtio_device *vdev)
vdev->config->reset(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->control_work);
cancel_work_sync(&portdev->config_work); cancel_work_sync(&portdev->config_work);
/* /*
* Once more: if control_work_handler() was running, it would * Once more: if control_work_handler() was running, it would
* enable the cb as the last step. * 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); remove_controlq_data(portdev);
list_for_each_entry(port, &portdev->ports, list) { list_for_each_entry(port, &portdev->ports, list) {

View File

@ -2398,6 +2398,20 @@ EXPORT_SYMBOL_GPL(cpufreq_boost_enabled);
*********************************************************************/ *********************************************************************/
static enum cpuhp_state hp_online; 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 * cpufreq_register_driver - register a CPU Frequency driver
* @driver_data: A struct cpufreq_driver containing the values# * @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", ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "cpufreq:online",
cpufreq_online, cpuhp_cpufreq_online,
cpufreq_offline); cpuhp_cpufreq_offline);
if (ret < 0) if (ret < 0)
goto err_if_unreg; goto err_if_unreg;
hp_online = ret; hp_online = ret;

View File

@ -506,7 +506,7 @@ static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
ctx->dev = caam_jr_alloc(); ctx->dev = caam_jr_alloc();
if (IS_ERR(ctx->dev)) { 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); return PTR_ERR(ctx->dev);
} }

View File

@ -281,7 +281,8 @@ static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
/* Try to run it through DECO0 */ /* Try to run it through DECO0 */
ret = run_descriptor_deco0(ctrldev, desc, &status); ret = run_descriptor_deco0(ctrldev, desc, &status);
if (ret || status) { if (ret ||
(status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
dev_err(ctrldev, dev_err(ctrldev,
"Failed to deinstantiate RNG4 SH%d\n", "Failed to deinstantiate RNG4 SH%d\n",
sh_idx); sh_idx);
@ -301,15 +302,13 @@ static int caam_remove(struct platform_device *pdev)
struct device *ctrldev; struct device *ctrldev;
struct caam_drv_private *ctrlpriv; struct caam_drv_private *ctrlpriv;
struct caam_ctrl __iomem *ctrl; struct caam_ctrl __iomem *ctrl;
int ring;
ctrldev = &pdev->dev; ctrldev = &pdev->dev;
ctrlpriv = dev_get_drvdata(ctrldev); ctrlpriv = dev_get_drvdata(ctrldev);
ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
/* Remove platform devices for JobRs */ /* Remove platform devices under the crypto node */
for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) of_platform_depopulate(ctrldev);
of_device_unregister(ctrlpriv->jrpdev[ring]);
/* De-initialize RNG state handles initialized by this driver. */ /* De-initialize RNG state handles initialized by this driver. */
if (ctrlpriv->rng4_sh_init) 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"); DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n");
#endif #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 */ /* Probe routine for CAAM top (controller) level */
static int caam_probe(struct platform_device *pdev) 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; u64 caam_id;
struct device *dev; struct device *dev;
struct device_node *nprop, *np; struct device_node *nprop, *np;
@ -597,47 +607,24 @@ static int caam_probe(struct platform_device *pdev)
goto iounmap_ctrl; goto iounmap_ctrl;
} }
/* ret = of_platform_populate(nprop, caam_match, NULL, dev);
* Detect and enable JobRs if (ret) {
* First, find out how many ring spec'ed, allocate references dev_err(dev, "JR platform devices creation error\n");
* 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;
goto iounmap_ctrl; goto iounmap_ctrl;
} }
ring = 0; ring = 0;
ridx = 0;
ctrlpriv->total_jobrs = 0;
for_each_available_child_of_node(nprop, np) for_each_available_child_of_node(nprop, np)
if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
of_device_is_compatible(np, "fsl,sec4.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 *) ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *)
((__force uint8_t *)ctrl + ((__force uint8_t *)ctrl +
(ridx + JR_BLOCK_NUMBER) * (ring + JR_BLOCK_NUMBER) *
BLOCK_OFFSET BLOCK_OFFSET
); );
ctrlpriv->total_jobrs++; ctrlpriv->total_jobrs++;
ring++; ring++;
ridx++; }
}
/* Check to see if QI present. If so, enable */ /* Check to see if QI present. If so, enable */
ctrlpriv->qi_present = ctrlpriv->qi_present =
@ -847,17 +834,6 @@ disable_caam_ipg:
return ret; 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 = { static struct platform_driver caam_driver = {
.driver = { .driver = {
.name = "caam", .name = "caam",

View File

@ -66,7 +66,6 @@ struct caam_drv_private_jr {
struct caam_drv_private { struct caam_drv_private {
struct device *dev; struct device *dev;
struct platform_device **jrpdev; /* Alloc'ed array per sub-device */
struct platform_device *pdev; struct platform_device *pdev;
/* Physical-presence section */ /* Physical-presence section */

View File

@ -2,6 +2,7 @@ menuconfig DEV_DAX
tristate "DAX: direct access to differentiated memory" tristate "DAX: direct access to differentiated memory"
default m if NVDIMM_DAX default m if NVDIMM_DAX
depends on TRANSPARENT_HUGEPAGE depends on TRANSPARENT_HUGEPAGE
select SRCU
help help
Support raw access to differentiated (persistence, bandwidth, Support raw access to differentiated (persistence, bandwidth,
latency...) memory via an mmap(2) capable character latency...) memory via an mmap(2) capable character

View File

@ -25,6 +25,7 @@
#include "dax.h" #include "dax.h"
static dev_t dax_devt; static dev_t dax_devt;
DEFINE_STATIC_SRCU(dax_srcu);
static struct class *dax_class; static struct class *dax_class;
static DEFINE_IDA(dax_minor_ida); static DEFINE_IDA(dax_minor_ida);
static int nr_dax = CONFIG_NR_DEV_DAX; static int nr_dax = CONFIG_NR_DEV_DAX;
@ -60,7 +61,7 @@ struct dax_region {
* @region - parent region * @region - parent region
* @dev - device backing the character device * @dev - device backing the character device
* @cdev - core chardev data * @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 * @id - child id in the region
* @num_resources - number of physical address extents in this device * @num_resources - number of physical address extents in this device
* @res - array of physical address ranges * @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, static int dax_dev_huge_fault(struct vm_fault *vmf,
enum page_entry_size pe_size) enum page_entry_size pe_size)
{ {
int rc; int rc, id;
struct file *filp = vmf->vma->vm_file; struct file *filp = vmf->vma->vm_file;
struct dax_dev *dax_dev = filp->private_data; struct dax_dev *dax_dev = filp->private_data;
@ -578,7 +579,7 @@ static int dax_dev_huge_fault(struct vm_fault *vmf,
? "write" : "read", ? "write" : "read",
vmf->vma->vm_start, vmf->vma->vm_end); vmf->vma->vm_start, vmf->vma->vm_end);
rcu_read_lock(); id = srcu_read_lock(&dax_srcu);
switch (pe_size) { switch (pe_size) {
case PE_SIZE_PTE: case PE_SIZE_PTE:
rc = __dax_dev_pte_fault(dax_dev, vmf); rc = __dax_dev_pte_fault(dax_dev, vmf);
@ -592,7 +593,7 @@ static int dax_dev_huge_fault(struct vm_fault *vmf,
default: default:
return VM_FAULT_FALLBACK; return VM_FAULT_FALLBACK;
} }
rcu_read_unlock(); srcu_read_unlock(&dax_srcu, id);
return rc; 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 * Note, rcu is not protecting the liveness of dax_dev, rcu is
* ensuring that any fault handlers that might have seen * ensuring that any fault handlers that might have seen
* dax_dev->alive == true, have completed. Any fault handlers * 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. * upon seeing dax_dev->alive == false.
*/ */
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); unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1);
cdev_del(cdev); cdev_del(cdev);
device_unregister(dev); device_unregister(dev);

View File

@ -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->map_dma_buf
|| !exp_info->ops->unmap_dma_buf || !exp_info->ops->unmap_dma_buf
|| !exp_info->ops->release || !exp_info->ops->release
|| !exp_info->ops->kmap_atomic || !exp_info->ops->map_atomic
|| !exp_info->ops->kmap || !exp_info->ops->map
|| !exp_info->ops->mmap)) { || !exp_info->ops->mmap)) {
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
@ -872,7 +872,7 @@ void *dma_buf_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
{ {
WARN_ON(!dmabuf); 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); 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); WARN_ON(!dmabuf);
if (dmabuf->ops->kunmap_atomic) if (dmabuf->ops->unmap_atomic)
dmabuf->ops->kunmap_atomic(dmabuf, page_num, vaddr); dmabuf->ops->unmap_atomic(dmabuf, page_num, vaddr);
} }
EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic); 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); WARN_ON(!dmabuf);
return dmabuf->ops->kmap(dmabuf, page_num); return dmabuf->ops->map(dmabuf, page_num);
} }
EXPORT_SYMBOL_GPL(dma_buf_kmap); 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); WARN_ON(!dmabuf);
if (dmabuf->ops->kunmap) if (dmabuf->ops->unmap)
dmabuf->ops->kunmap(dmabuf, page_num, vaddr); dmabuf->ops->unmap(dmabuf, page_num, vaddr);
} }
EXPORT_SYMBOL_GPL(dma_buf_kunmap); EXPORT_SYMBOL_GPL(dma_buf_kunmap);

View File

@ -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, status = __gop_query32(sys_table_arg, gop32, &info, &size,
&current_fb_base); &current_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 * Systems that use the UEFI Console Splitter may
* provide multiple GOP devices, not all of which are * 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, status = __gop_query64(sys_table_arg, gop64, &info, &size,
&current_fb_base); &current_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 * Systems that use the UEFI Console Splitter may
* provide multiple GOP devices, not all of which are * provide multiple GOP devices, not all of which are

View File

@ -16,6 +16,7 @@
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <video/videomode.h> #include <video/videomode.h>
#include "malidp_drv.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; long rate, req_rate = mode->crtc_clock * 1000;
if (req_rate) { 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); rate = clk_round_rate(hwdev->pxlclk, req_rate);
if (rate != req_rate) { if (rate != req_rate) {
DRM_DEBUG_DRIVER("pxlclk doesn't support %ld Hz\n", 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_drm *malidp = crtc_to_malidp_device(crtc);
struct malidp_hw_device *hwdev = malidp->dev; struct malidp_hw_device *hwdev = malidp->dev;
struct videomode vm; 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); drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm);
clk_prepare_enable(hwdev->pxlclk); clk_prepare_enable(hwdev->pxlclk);
/* We rely on firmware to set mclk to a sensible level. */ /* 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_drm *malidp = crtc_to_malidp_device(crtc);
struct malidp_hw_device *hwdev = malidp->dev; struct malidp_hw_device *hwdev = malidp->dev;
int err;
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
hwdev->enter_config_mode(hwdev); hwdev->enter_config_mode(hwdev);
clk_disable_unprepare(hwdev->pxlclk); 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, 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; const struct drm_plane_state *pstate;
u32 rot_mem_free, rot_mem_usable; u32 rot_mem_free, rot_mem_usable;
int rotated_planes = 0; int rotated_planes = 0;
int ret;
/* /*
* check if there is enough rotation memory available for planes * 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 = { 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, .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) static int malidp_crtc_enable_vblank(struct drm_crtc *crtc)
{ {
struct malidp_drm *malidp = crtc_to_malidp_device(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 = { static const struct drm_crtc_funcs malidp_crtc_funcs = {
.gamma_set = drm_atomic_helper_legacy_gamma_set,
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
.reset = drm_atomic_helper_crtc_reset, .reset = malidp_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_duplicate_state = malidp_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_destroy_state = malidp_crtc_destroy_state,
.enable_vblank = malidp_crtc_enable_vblank, .enable_vblank = malidp_crtc_enable_vblank,
.disable_vblank = malidp_crtc_disable_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, ret = drm_crtc_init_with_planes(drm, &malidp->crtc, primary, NULL,
&malidp_crtc_funcs, NULL); &malidp_crtc_funcs, NULL);
if (ret)
goto crtc_cleanup_planes;
if (!ret) { drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs);
drm_crtc_helper_add(&malidp->crtc, &malidp_crtc_helper_funcs); drm_mode_crtc_set_gamma_size(&malidp->crtc, MALIDP_GAMMA_LUT_SIZE);
return 0; /* 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: crtc_cleanup_planes:
malidp_de_planes_destroy(drm); malidp_de_planes_destroy(drm);

View File

@ -13,9 +13,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/console.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/of_reserved_mem.h> #include <linux/of_reserved_mem.h>
#include <linux/pm_runtime.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
@ -32,6 +34,131 @@
#define MALIDP_CONF_VALID_TIMEOUT 250 #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 * 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_pending_vblank_event *event;
struct drm_device *drm = state->dev; struct drm_device *drm = state->dev;
struct malidp_drm *malidp = drm->dev_private; struct malidp_drm *malidp = drm->dev_private;
int ret = malidp_set_and_wait_config_valid(drm);
if (ret) if (malidp->crtc.enabled) {
DRM_DEBUG_DRIVER("timed out waiting for updated configuration\n"); /* 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; event = malidp->crtc.state->event;
if (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) static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
{ {
struct drm_device *drm = state->dev; 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_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_planes(drm, state, 0);
drm_atomic_helper_commit_modeset_enables(drm, state);
malidp_atomic_commit_hw_done(state); malidp_atomic_commit_hw_done(state);
drm_atomic_helper_wait_for_vblanks(drm, state); drm_atomic_helper_wait_for_vblanks(drm, state);
pm_runtime_put(drm->dev);
drm_atomic_helper_cleanup_planes(drm, state); drm_atomic_helper_cleanup_planes(drm, state);
} }
@ -277,8 +421,65 @@ static bool malidp_has_sufficient_address_space(const struct resource *res,
return true; 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 #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) static int malidp_bind(struct device *dev)
{ {
struct resource *res; struct resource *res;
@ -307,7 +508,6 @@ static int malidp_bind(struct device *dev)
memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev)); memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev));
malidp->dev = hwdev; malidp->dev = hwdev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hwdev->regs = devm_ioremap_resource(dev, res); hwdev->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(hwdev->regs)) if (IS_ERR(hwdev->regs))
@ -340,14 +540,17 @@ static int malidp_bind(struct device *dev)
goto alloc_fail; goto alloc_fail;
} }
/* Enable APB clock in order to get access to the registers */ drm->dev_private = malidp;
clk_prepare_enable(hwdev->pclk); dev_set_drvdata(dev, drm);
/*
* Enable AXI clock and main clock so that prefetch can start once /* Enable power management */
* the registers are set pm_runtime_enable(dev);
*/
clk_prepare_enable(hwdev->aclk); /* Resume device to enable the clocks */
clk_prepare_enable(hwdev->mclk); 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); dev_id = of_match_device(malidp_drm_of_match, dev);
if (!dev_id) { 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, DRM_INFO("found ARM Mali-DP%3x version r%dp%d\n", version >> 16,
(version >> 12) & 0xf, (version >> 8) & 0xf); (version >> 12) & 0xf, (version >> 8) & 0xf);
malidp->core_id = version;
/* set the number of lines used for output of RGB data */ /* set the number of lines used for output of RGB data */
ret = of_property_read_u8_array(dev->of_node, ret = of_property_read_u8_array(dev->of_node,
"arm,malidp-output-port-lines", "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); out_depth = (out_depth << 8) | (output_width[i] & 0xf);
malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base); 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); atomic_set(&malidp->config_valid, 0);
init_waitqueue_head(&malidp->wq); init_waitqueue_head(&malidp->wq);
ret = malidp_init(drm); ret = malidp_init(drm);
if (ret < 0) if (ret < 0)
goto query_hw_fail;
ret = malidp_init_sysfs(dev);
if (ret)
goto init_fail; goto init_fail;
/* Set the CRTC's port so that the encoder component can find it */ /* 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"); DRM_ERROR("failed to initialise vblank\n");
goto vblank_fail; goto vblank_fail;
} }
pm_runtime_put(dev);
drm_mode_config_reset(drm); drm_mode_config_reset(drm);
@ -441,7 +649,9 @@ register_fail:
drm_fbdev_cma_fini(malidp->fbdev); drm_fbdev_cma_fini(malidp->fbdev);
malidp->fbdev = NULL; malidp->fbdev = NULL;
} }
drm_kms_helper_poll_fini(drm);
fbdev_fail: fbdev_fail:
pm_runtime_get_sync(dev);
drm_vblank_cleanup(drm); drm_vblank_cleanup(drm);
vblank_fail: vblank_fail:
malidp_se_irq_fini(drm); malidp_se_irq_fini(drm);
@ -452,14 +662,17 @@ irq_init_fail:
bind_fail: bind_fail:
of_node_put(malidp->crtc.port); of_node_put(malidp->crtc.port);
malidp->crtc.port = NULL; malidp->crtc.port = NULL;
malidp_fini(drm);
init_fail: 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; drm->dev_private = NULL;
dev_set_drvdata(dev, 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); drm_dev_unref(drm);
alloc_fail: alloc_fail:
of_reserved_mem_device_release(dev); 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 drm_device *drm = dev_get_drvdata(dev);
struct malidp_drm *malidp = drm->dev_private; struct malidp_drm *malidp = drm->dev_private;
struct malidp_hw_device *hwdev = malidp->dev;
drm_dev_unregister(drm); drm_dev_unregister(drm);
if (malidp->fbdev) { if (malidp->fbdev) {
@ -479,18 +691,22 @@ static void malidp_unbind(struct device *dev)
malidp->fbdev = NULL; malidp->fbdev = NULL;
} }
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
pm_runtime_get_sync(dev);
drm_vblank_cleanup(drm);
malidp_se_irq_fini(drm); malidp_se_irq_fini(drm);
malidp_de_irq_fini(drm); malidp_de_irq_fini(drm);
drm_vblank_cleanup(drm);
component_unbind_all(dev, drm); component_unbind_all(dev, drm);
of_node_put(malidp->crtc.port); of_node_put(malidp->crtc.port);
malidp->crtc.port = NULL; malidp->crtc.port = NULL;
malidp_fini_sysfs(dev);
malidp_fini(drm); 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; drm->dev_private = NULL;
dev_set_drvdata(dev, 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); drm_dev_unref(drm);
of_reserved_mem_device_release(dev); of_reserved_mem_device_release(dev);
} }
@ -533,11 +749,52 @@ static int malidp_platform_remove(struct platform_device *pdev)
return 0; 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 = { static struct platform_driver malidp_platform_driver = {
.probe = malidp_platform_probe, .probe = malidp_platform_probe,
.remove = malidp_platform_remove, .remove = malidp_platform_remove,
.driver = { .driver = {
.name = "mali-dp", .name = "mali-dp",
.pm = &malidp_pm_ops,
.of_match_table = malidp_drm_of_match, .of_match_table = malidp_drm_of_match,
}, },
}; };

View File

@ -24,6 +24,8 @@ struct malidp_drm {
struct drm_crtc crtc; struct drm_crtc crtc;
wait_queue_head_t wq; wait_queue_head_t wq;
atomic_t config_valid; 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) #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(x) container_of(x, struct malidp_plane, base)
#define to_malidp_plane_state(x) container_of(x, struct malidp_plane_state, 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); int malidp_de_planes_init(struct drm_device *drm);
void malidp_de_planes_destroy(struct drm_device *drm); void malidp_de_planes_destroy(struct drm_device *drm);
int malidp_crtc_init(struct drm_device *drm); int malidp_crtc_init(struct drm_device *drm);

View File

@ -12,6 +12,7 @@
* in an attempt to provide to the rest of the driver code a unified view * 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/types.h>
#include <linux/io.h> #include <linux/io.h>
#include <drm/drmP.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 }, { 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 #define MALIDP_DE_DEFAULT_PREFETCH_START 5
static int malidp500_query_hw(struct malidp_hw_device *hwdev) 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; 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) static int malidp550_query_hw(struct malidp_hw_device *hwdev)
{ {
u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 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; 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) static int malidp650_query_hw(struct malidp_hw_device *hwdev)
{ {
u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID); 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] = { const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
[MALIDP_500] = { [MALIDP_500] = {
.map = { .map = {
.coeffs_base = MALIDP500_COEFFS_BASE,
.se_base = MALIDP500_SE_BASE, .se_base = MALIDP500_SE_BASE,
.dc_base = MALIDP500_DC_BASE, .dc_base = MALIDP500_DC_BASE,
.out_depth_base = MALIDP500_OUTPUT_DEPTH, .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, .set_config_valid = malidp500_set_config_valid,
.modeset = malidp500_modeset, .modeset = malidp500_modeset,
.rotmem_required = malidp500_rotmem_required, .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, .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
}, },
[MALIDP_550] = { [MALIDP_550] = {
.map = { .map = {
.coeffs_base = MALIDP550_COEFFS_BASE,
.se_base = MALIDP550_SE_BASE, .se_base = MALIDP550_SE_BASE,
.dc_base = MALIDP550_DC_BASE, .dc_base = MALIDP550_DC_BASE,
.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, .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, .set_config_valid = malidp550_set_config_valid,
.modeset = malidp550_modeset, .modeset = malidp550_modeset,
.rotmem_required = malidp550_rotmem_required, .rotmem_required = malidp550_rotmem_required,
.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
.se_calc_mclk = malidp550_se_calc_mclk,
.features = 0, .features = 0,
}, },
[MALIDP_650] = { [MALIDP_650] = {
.map = { .map = {
.coeffs_base = MALIDP550_COEFFS_BASE,
.se_base = MALIDP550_SE_BASE, .se_base = MALIDP550_SE_BASE,
.dc_base = MALIDP550_DC_BASE, .dc_base = MALIDP550_DC_BASE,
.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH, .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, .set_config_valid = malidp550_set_config_valid,
.modeset = malidp550_modeset, .modeset = malidp550_modeset,
.rotmem_required = malidp550_rotmem_required, .rotmem_required = malidp550_rotmem_required,
.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
.se_calc_mclk = malidp550_se_calc_mclk,
.features = 0, .features = 0,
}, },
}; };

View File

@ -61,12 +61,34 @@ struct malidp_layer {
u16 stride_offset; /* Offset to the first stride register. */ 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 */ /* regmap features */
#define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0) #define MALIDP_REGMAP_HAS_CLEARIRQ (1 << 0)
struct malidp_hw_regmap { struct malidp_hw_regmap {
/* address offset of the DE register bank */ /* address offset of the DE register bank */
/* is always 0x0000 */ /* is always 0x0000 */
/* address offset of the DE coefficients registers */
const u16 coeffs_base;
/* address offset of the SE registers bank */ /* address offset of the SE registers bank */
const u16 se_base; const u16 se_base;
/* address offset of the DC registers bank */ /* 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 (*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 features;
u8 min_line_size; u8 min_line_size;
u16 max_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 */ /* size of memory used for rotating layers, up to two banks available */
u32 rotation_memory[2]; 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) static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg)
{ {
WARN_ON(hwdev->pm_suspended);
return readl(hwdev->regs + reg); return readl(hwdev->regs + reg);
} }
static inline void malidp_hw_write(struct malidp_hw_device *hwdev, static inline void malidp_hw_write(struct malidp_hw_device *hwdev,
u32 value, u32 reg) u32 value, u32 reg)
{ {
WARN_ON(hwdev->pm_suspended);
writel(value, hwdev->regs + reg); 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)); 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, * background color components are defined as 12bits values,
* they will be shifted right when stored on hardware that * 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_G 0x000
#define MALIDP_BGND_COLOR_B 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__ */ #endif /* __MALIDP_HW_H__ */

View File

@ -16,6 +16,7 @@
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include "malidp_hw.h" #include "malidp_hw.h"
#include "malidp_drv.h" #include "malidp_drv.h"
@ -24,6 +25,9 @@
#define MALIDP_LAYER_FORMAT 0x000 #define MALIDP_LAYER_FORMAT 0x000
#define MALIDP_LAYER_CONTROL 0x004 #define MALIDP_LAYER_CONTROL 0x004
#define LAYER_ENABLE (1 << 0) #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_ROT_OFFSET 8
#define LAYER_H_FLIP (1 << 10) #define LAYER_H_FLIP (1 << 10)
#define LAYER_V_FLIP (1 << 11) #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); 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 static struct
drm_plane_state *malidp_duplicate_plane_state(struct drm_plane *plane) 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); 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 = { static const struct drm_plane_funcs malidp_de_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
.set_property = drm_atomic_helper_plane_set_property, .set_property = drm_atomic_helper_plane_set_property,
.destroy = malidp_de_plane_destroy, .destroy = malidp_de_plane_destroy,
.reset = drm_atomic_helper_plane_reset, .reset = malidp_plane_reset,
.atomic_duplicate_state = malidp_duplicate_plane_state, .atomic_duplicate_state = malidp_duplicate_plane_state,
.atomic_destroy_state = malidp_destroy_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, static int malidp_de_plane_check(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
struct malidp_plane *mp = to_malidp_plane(plane); struct malidp_plane *mp = to_malidp_plane(plane);
struct malidp_plane_state *ms = to_malidp_plane_state(state); struct malidp_plane_state *ms = to_malidp_plane_state(state);
struct drm_crtc_state *crtc_state;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct drm_rect clip = { 0 };
int i, ret; int i, ret;
u32 src_w, src_h;
if (!state->crtc || !state->fb) if (!state->crtc || !state->fb)
return 0; 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) || if ((state->crtc_w > mp->hwdev->max_line_size) ||
(state->crtc_h > mp->hwdev->max_line_size) || (state->crtc_h > mp->hwdev->max_line_size) ||
(state->crtc_w < mp->hwdev->min_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])) (state->fb->pitches[1] != state->fb->pitches[2]))
return -EINVAL; return -EINVAL;
ret = malidp_se_check_scaling(mp, state);
if (ret)
return ret;
/* packed RGB888 / BGR888 can't be rotated or flipped */ /* packed RGB888 / BGR888 can't be rotated or flipped */
if (state->rotation != DRM_ROTATE_0 && if (state->rotation != DRM_ROTATE_0 &&
(fb->format->format == DRM_FORMAT_RGB888 || (fb->format->format == DRM_FORMAT_RGB888 ||
fb->format->format == DRM_FORMAT_BGR888)) fb->format->format == DRM_FORMAT_BGR888))
return -EINVAL; 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; ms->rotmem_size = 0;
if (state->rotation & MALIDP_ROTATED_MASK) { if (state->rotation & MALIDP_ROTATED_MASK) {
int val; int val;
@ -269,6 +330,16 @@ static void malidp_de_plane_update(struct drm_plane *plane,
val &= ~LAYER_COMP_MASK; val &= ~LAYER_COMP_MASK;
val |= LAYER_COMP_PIXEL; 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 */ /* set the 'enable layer' bit */
val |= LAYER_ENABLE; 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); 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); mp->layer->base + MALIDP_LAYER_CONTROL);
} }

View File

@ -63,6 +63,8 @@
/* bit masks that are common between products */ /* bit masks that are common between products */
#define MALIDP_CFG_VALID (1 << 0) #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) #define MALIDP_DISP_FUNC_ILACED (1 << 8)
/* register offsets for IRQ management */ /* register offsets for IRQ management */
@ -99,6 +101,58 @@
#define MALIDP_PRODUCT_ID(__core_id) ((u32)(__core_id) >> 16) #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 */ /* register offsets and bits specific to DP500 */
#define MALIDP500_ADDR_SPACE_SIZE 0x01000 #define MALIDP500_ADDR_SPACE_SIZE 0x01000
#define MALIDP500_DC_BASE 0x00000 #define MALIDP500_DC_BASE 0x00000
@ -120,6 +174,18 @@
#define MALIDP500_COLOR_ADJ_COEF 0x00078 #define MALIDP500_COLOR_ADJ_COEF 0x00078
#define MALIDP500_COEF_TABLE_ADDR 0x000a8 #define MALIDP500_COEF_TABLE_ADDR 0x000a8
#define MALIDP500_COEF_TABLE_DATA 0x000ac #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_BASE 0x00100
#define MALIDP500_DE_LV_PTR_BASE 0x00124 #define MALIDP500_DE_LV_PTR_BASE 0x00124
#define MALIDP500_DE_LG1_BASE 0x00200 #define MALIDP500_DE_LG1_BASE 0x00200
@ -127,6 +193,7 @@
#define MALIDP500_DE_LG2_BASE 0x00300 #define MALIDP500_DE_LG2_BASE 0x00300
#define MALIDP500_DE_LG2_PTR_BASE 0x0031c #define MALIDP500_DE_LG2_PTR_BASE 0x0031c
#define MALIDP500_SE_BASE 0x00c00 #define MALIDP500_SE_BASE 0x00c00
#define MALIDP500_SE_CONTROL 0x00c0c
#define MALIDP500_SE_PTR_BASE 0x00e0c #define MALIDP500_SE_PTR_BASE 0x00e0c
#define MALIDP500_DC_IRQ_BASE 0x00f00 #define MALIDP500_DC_IRQ_BASE 0x00f00
#define MALIDP500_CONFIG_VALID 0x00f00 #define MALIDP500_CONFIG_VALID 0x00f00
@ -145,9 +212,7 @@
#define MALIDP550_DE_DISP_SIDEBAND 0x00040 #define MALIDP550_DE_DISP_SIDEBAND 0x00040
#define MALIDP550_DE_BGND_COLOR 0x00044 #define MALIDP550_DE_BGND_COLOR 0x00044
#define MALIDP550_DE_OUTPUT_DEPTH 0x0004c #define MALIDP550_DE_OUTPUT_DEPTH 0x0004c
#define MALIDP550_DE_COLOR_COEF 0x00050 #define MALIDP550_COEFFS_BASE 0x00050
#define MALIDP550_DE_COEF_TABLE_ADDR 0x00080
#define MALIDP550_DE_COEF_TABLE_DATA 0x00084
#define MALIDP550_DE_LV1_BASE 0x00100 #define MALIDP550_DE_LV1_BASE 0x00100
#define MALIDP550_DE_LV1_PTR_BASE 0x00124 #define MALIDP550_DE_LV1_PTR_BASE 0x00124
#define MALIDP550_DE_LV2_BASE 0x00200 #define MALIDP550_DE_LV2_BASE 0x00200
@ -158,6 +223,7 @@
#define MALIDP550_DE_LS_PTR_BASE 0x0042c #define MALIDP550_DE_LS_PTR_BASE 0x0042c
#define MALIDP550_DE_PERF_BASE 0x00500 #define MALIDP550_DE_PERF_BASE 0x00500
#define MALIDP550_SE_BASE 0x08000 #define MALIDP550_SE_BASE 0x08000
#define MALIDP550_SE_CONTROL 0x08010
#define MALIDP550_DC_BASE 0x0c000 #define MALIDP550_DC_BASE 0x0c000
#define MALIDP550_DC_CONTROL 0x0c010 #define MALIDP550_DC_CONTROL 0x0c010
#define MALIDP550_DC_CONFIG_REQ (1 << 16) #define MALIDP550_DC_CONFIG_REQ (1 << 16)

View File

@ -529,10 +529,10 @@ static const struct dma_buf_ops armada_gem_prime_dmabuf_ops = {
.map_dma_buf = armada_gem_prime_map_dma_buf, .map_dma_buf = armada_gem_prime_map_dma_buf,
.unmap_dma_buf = armada_gem_prime_unmap_dma_buf, .unmap_dma_buf = armada_gem_prime_unmap_dma_buf,
.release = drm_gem_dmabuf_release, .release = drm_gem_dmabuf_release,
.kmap_atomic = armada_gem_dmabuf_no_kmap, .map_atomic = armada_gem_dmabuf_no_kmap,
.kunmap_atomic = armada_gem_dmabuf_no_kunmap, .unmap_atomic = armada_gem_dmabuf_no_kunmap,
.kmap = armada_gem_dmabuf_no_kmap, .map = armada_gem_dmabuf_no_kmap,
.kunmap = armada_gem_dmabuf_no_kunmap, .unmap = armada_gem_dmabuf_no_kunmap,
.mmap = armada_gem_dmabuf_mmap, .mmap = armada_gem_dmabuf_mmap,
}; };

View File

@ -221,7 +221,8 @@ err_encoder_cleanup:
int atmel_hlcdc_create_outputs(struct drm_device *dev) int atmel_hlcdc_create_outputs(struct drm_device *dev)
{ {
struct device_node *remote; struct device_node *remote;
int ret, endpoint = 0; int ret = -ENODEV;
int endpoint = 0;
while (true) { while (true) {
/* Loop thru possible multiple connections to the output */ /* Loop thru possible multiple connections to the output */
@ -236,7 +237,5 @@ int atmel_hlcdc_create_outputs(struct drm_device *dev)
return ret; return ret;
} }
if (!endpoint)
return -ENODEV;
return ret; return ret;
} }

View File

@ -1947,6 +1947,20 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
return 0; 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, static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
struct drm_display_mode *orig_mode, struct drm_display_mode *orig_mode,
struct drm_display_mode *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, .enable = dw_hdmi_bridge_enable,
.disable = dw_hdmi_bridge_disable, .disable = dw_hdmi_bridge_disable,
.mode_set = dw_hdmi_bridge_mode_set, .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) static irqreturn_t dw_hdmi_i2c_irq(struct dw_hdmi *hdmi)

View File

@ -403,10 +403,10 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
.map_dma_buf = drm_gem_map_dma_buf, .map_dma_buf = drm_gem_map_dma_buf,
.unmap_dma_buf = drm_gem_unmap_dma_buf, .unmap_dma_buf = drm_gem_unmap_dma_buf,
.release = drm_gem_dmabuf_release, .release = drm_gem_dmabuf_release,
.kmap = drm_gem_dmabuf_kmap, .map = drm_gem_dmabuf_kmap,
.kmap_atomic = drm_gem_dmabuf_kmap_atomic, .map_atomic = drm_gem_dmabuf_kmap_atomic,
.kunmap = drm_gem_dmabuf_kunmap, .unmap = drm_gem_dmabuf_kunmap,
.kunmap_atomic = drm_gem_dmabuf_kunmap_atomic, .unmap_atomic = drm_gem_dmabuf_kunmap_atomic,
.mmap = drm_gem_dmabuf_mmap, .mmap = drm_gem_dmabuf_mmap,
.vmap = drm_gem_dmabuf_vmap, .vmap = drm_gem_dmabuf_vmap,
.vunmap = drm_gem_dmabuf_vunmap, .vunmap = drm_gem_dmabuf_vunmap,

View File

@ -476,7 +476,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) { drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
list_for_each_entry(prop_enum, &property->enum_list, head) { list_for_each_entry(prop_enum, &property->enum_list, head) {
enum_count++; enum_count++;
if (out_resp->count_enum_blobs <= enum_count) if (out_resp->count_enum_blobs < enum_count)
continue; continue;
if (copy_to_user(&enum_ptr[copied].value, if (copy_to_user(&enum_ptr[copied].value,

View File

@ -1333,7 +1333,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
if (!fence) { if (!fence) {
event_free(gpu, event); event_free(gpu, event);
ret = -ENOMEM; ret = -ENOMEM;
goto out_pm_put; goto out_unlock;
} }
gpu->event[event].fence = fence; gpu->event[event].fence = fence;
@ -1373,6 +1373,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
hangcheck_timer_reset(gpu); hangcheck_timer_reset(gpu);
ret = 0; ret = 0;
out_unlock:
mutex_unlock(&gpu->lock); mutex_unlock(&gpu->lock);
out_pm_put: out_pm_put:

View File

@ -285,9 +285,6 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
{ {
int ret; int ret;
if (vgpu->failsafe)
return 0;
if (WARN_ON(bytes > 4)) if (WARN_ON(bytes > 4))
return -EINVAL; return -EINVAL;

View File

@ -616,9 +616,6 @@ static inline u32 get_opcode(u32 cmd, int ring_id)
{ {
struct decode_info *d_info; struct decode_info *d_info;
if (ring_id >= I915_NUM_ENGINES)
return INVALID_OP;
d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)]; d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)];
if (d_info == NULL) if (d_info == NULL)
return INVALID_OP; return INVALID_OP;
@ -661,9 +658,6 @@ static inline void print_opcode(u32 cmd, int ring_id)
struct decode_info *d_info; struct decode_info *d_info;
int i; int i;
if (ring_id >= I915_NUM_ENGINES)
return;
d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)]; d_info = ring_decode_info[ring_id][CMD_TYPE(cmd)];
if (d_info == NULL) if (d_info == NULL)
return; return;
@ -2483,7 +2477,7 @@ static int cmd_parser_exec(struct parser_exec_state *s)
t1 = get_cycles(); t1 = get_cycles();
memcpy(&s_before_advance_custom, s, sizeof(struct parser_exec_state)); s_before_advance_custom = *s;
if (info->handler) { if (info->handler) {
ret = info->handler(s); ret = info->handler(s);

View File

@ -189,17 +189,44 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
} }
if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) { 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, 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)) { if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
vgpu_vreg(vgpu, SDEISR) |= SDE_PORTC_HOTPLUG_CPT; 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; vgpu_vreg(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIC_DETECTED;
} }
if (intel_vgpu_has_monitor_on_port(vgpu, PORT_D)) { if (intel_vgpu_has_monitor_on_port(vgpu, PORT_D)) {
vgpu_vreg(vgpu, SDEISR) |= SDE_PORTD_HOTPLUG_CPT; 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; vgpu_vreg(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDID_DETECTED;
} }

View File

@ -56,8 +56,8 @@ static int context_switch_events[] = {
static int ring_id_to_context_switch_event(int ring_id) static int ring_id_to_context_switch_event(int ring_id)
{ {
if (WARN_ON(ring_id < RCS && ring_id > if (WARN_ON(ring_id < RCS ||
ARRAY_SIZE(context_switch_events))) ring_id >= ARRAY_SIZE(context_switch_events)))
return -EINVAL; return -EINVAL;
return context_switch_events[ring_id]; 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) if (emulate_schedule_in)
memcpy(&workload->elsp_dwords, workload->elsp_dwords = vgpu->execlist[ring_id].elsp_dwords;
&vgpu->execlist[ring_id].elsp_dwords,
sizeof(workload->elsp_dwords));
gvt_dbg_el("workload %p ring id %d head %x tail %x start %x ctl %x\n", gvt_dbg_el("workload %p ring id %d head %x tail %x start %x ctl %x\n",
workload, ring_id, head, tail, start, ctl); 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); _EL_OFFSET_STATUS_PTR);
ctx_status_ptr.dw = vgpu_vreg(vgpu, ctx_status_ptr_reg); 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; vgpu_vreg(vgpu, ctx_status_ptr_reg) = ctx_status_ptr.dw;
} }

View File

@ -75,11 +75,11 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt)
struct gvt_firmware_header *h; struct gvt_firmware_header *h;
void *firmware; void *firmware;
void *p; void *p;
unsigned long size; unsigned long size, crc32_start;
int i; int i;
int ret; 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); firmware = vzalloc(size);
if (!firmware) if (!firmware)
return -ENOMEM; return -ENOMEM;
@ -112,6 +112,9 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt)
memcpy(gvt->firmware.mmio, p, info->mmio_size); 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.size = size;
firmware_attr.private = firmware; firmware_attr.private = firmware;
@ -234,7 +237,7 @@ int intel_gvt_load_firmware(struct intel_gvt *gvt)
firmware->mmio = mem; 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, GVT_FIRMWARE_PATH, pdev->vendor, pdev->device,
pdev->revision); pdev->revision);

View File

@ -2294,12 +2294,15 @@ void intel_gvt_clean_gtt(struct intel_gvt *gvt)
void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu) void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu)
{ {
struct intel_gvt *gvt = vgpu->gvt; 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; struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
u32 index; u32 index;
u32 offset; u32 offset;
u32 num_entries; u32 num_entries;
struct intel_gvt_gtt_entry e; struct intel_gvt_gtt_entry e;
intel_runtime_pm_get(dev_priv);
memset(&e, 0, sizeof(struct intel_gvt_gtt_entry)); memset(&e, 0, sizeof(struct intel_gvt_gtt_entry));
e.type = GTT_TYPE_GGTT_PTE; e.type = GTT_TYPE_GGTT_PTE;
ops->set_pfn(&e, gvt->gtt.scratch_ggtt_mfn); 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; num_entries = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT;
for (offset = 0; offset < num_entries; offset++) for (offset = 0; offset < num_entries; offset++)
ops->set_entry(NULL, &e, index + offset, false, 0, vgpu); ops->set_entry(NULL, &e, index + offset, false, 0, vgpu);
intel_runtime_pm_put(dev_priv);
} }
/** /**

View File

@ -52,6 +52,8 @@ static const struct intel_gvt_ops intel_gvt_ops = {
.vgpu_create = intel_gvt_create_vgpu, .vgpu_create = intel_gvt_create_vgpu,
.vgpu_destroy = intel_gvt_destroy_vgpu, .vgpu_destroy = intel_gvt_destroy_vgpu,
.vgpu_reset = intel_gvt_reset_vgpu, .vgpu_reset = intel_gvt_reset_vgpu,
.vgpu_activate = intel_gvt_activate_vgpu,
.vgpu_deactivate = intel_gvt_deactivate_vgpu,
}; };
/** /**

View File

@ -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, void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
unsigned int engine_mask); unsigned int engine_mask);
void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu); 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 */ /* validating GM functions */
#define vgpu_gmadr_is_aperture(vgpu, gmadr) \ #define vgpu_gmadr_is_aperture(vgpu, gmadr) \
@ -462,6 +463,8 @@ struct intel_gvt_ops {
struct intel_vgpu_type *); struct intel_vgpu_type *);
void (*vgpu_destroy)(struct intel_vgpu *); void (*vgpu_destroy)(struct intel_vgpu *);
void (*vgpu_reset)(struct intel_vgpu *); void (*vgpu_reset)(struct intel_vgpu *);
void (*vgpu_activate)(struct intel_vgpu *);
void (*vgpu_deactivate)(struct intel_vgpu *);
}; };

View File

@ -546,6 +546,8 @@ static int intel_vgpu_open(struct mdev_device *mdev)
if (ret) if (ret)
goto undo_group; goto undo_group;
intel_gvt_ops->vgpu_activate(vgpu);
atomic_set(&vgpu->vdev.released, 0); atomic_set(&vgpu->vdev.released, 0);
return ret; return ret;
@ -571,6 +573,8 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu)
if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1)) if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1))
return; return;
intel_gvt_ops->vgpu_deactivate(vgpu);
ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_IOMMU_NOTIFY, ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_IOMMU_NOTIFY,
&vgpu->vdev.iommu_notifier); &vgpu->vdev.iommu_notifier);
WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret); WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret);

View File

@ -44,7 +44,7 @@ struct render_mmio {
u32 value; 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(0x229c), 0xffff, false},
{RCS, _MMIO(0x2248), 0x0, false}, {RCS, _MMIO(0x2248), 0x0, false},
{RCS, _MMIO(0x2098), 0x0, false}, {RCS, _MMIO(0x2098), 0x0, false},
@ -75,7 +75,7 @@ static struct render_mmio gen8_render_mmio_list[] = {
{BCS, _MMIO(0x22028), 0x0, false}, {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(0x229c), 0xffff, false},
{RCS, _MMIO(0x2248), 0x0, false}, {RCS, _MMIO(0x2248), 0x0, false},
{RCS, _MMIO(0x2098), 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))) if (WARN_ON(ring_id >= ARRAY_SIZE(regs)))
return; return;
if (!(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)))
return;
offset.reg = regs[ring_id]; offset.reg = regs[ring_id];
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
gen9_render_mocs[ring_id][i] = I915_READ(offset); 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))) if (WARN_ON(ring_id >= ARRAY_SIZE(regs)))
return; return;
if (!(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)))
return;
offset.reg = regs[ring_id]; offset.reg = regs[ring_id];
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
vgpu_vreg(vgpu, offset) = I915_READ(offset); vgpu_vreg(vgpu, offset) = I915_READ(offset);

View File

@ -133,9 +133,6 @@ static void try_to_schedule_next_vgpu(struct intel_gvt *gvt)
if (!scheduler->next_vgpu) if (!scheduler->next_vgpu)
return; return;
gvt_dbg_sched("try to schedule next vgpu %d\n",
scheduler->next_vgpu->id);
/* /*
* after the flag is set, workload dispatch thread will * after the flag is set, workload dispatch thread will
* stop dispatching workload for current vgpu * 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? */ /* still have uncompleted workload? */
for_each_engine(engine, gvt->dev_priv, i) { for_each_engine(engine, gvt->dev_priv, i) {
if (scheduler->current_workload[i]) { if (scheduler->current_workload[i])
gvt_dbg_sched("still have running workload\n");
return; return;
}
} }
gvt_dbg_sched("switch to next vgpu %d\n",
scheduler->next_vgpu->id);
cur_time = ktime_get(); cur_time = ktime_get();
if (scheduler->current_vgpu) { if (scheduler->current_vgpu) {
vgpu_data = scheduler->current_vgpu->sched_data; 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_del_init(&vgpu_data->lru_list);
list_add_tail(&vgpu_data->lru_list, list_add_tail(&vgpu_data->lru_list,
&sched_data->lru_runq_head); &sched_data->lru_runq_head);
gvt_dbg_sched("pick next vgpu %d\n", vgpu->id);
} else { } else {
scheduler->next_vgpu = gvt->idle_vgpu; scheduler->next_vgpu = gvt->idle_vgpu;
} }
out: out:
if (scheduler->next_vgpu) { if (scheduler->next_vgpu)
gvt_dbg_sched("try to schedule next vgpu %d\n",
scheduler->next_vgpu->id);
try_to_schedule_next_vgpu(gvt); try_to_schedule_next_vgpu(gvt);
}
} }
void intel_gvt_schedule(struct intel_gvt *gvt) void intel_gvt_schedule(struct intel_gvt *gvt)

View File

@ -278,11 +278,8 @@ static struct intel_vgpu_workload *pick_next_workload(
goto out; goto out;
} }
if (list_empty(workload_q_head(scheduler->current_vgpu, ring_id))) { if (list_empty(workload_q_head(scheduler->current_vgpu, ring_id)))
gvt_dbg_sched("ring id %d stop - no available workload\n",
ring_id);
goto out; goto out;
}
/* /*
* still have current workload, maybe the workload disptacher * still have current workload, maybe the workload disptacher

View File

@ -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 * intel_gvt_destroy_vgpu - destroy a virtual GPU
* @vgpu: virtual GPU * @vgpu: virtual GPU
@ -208,16 +249,9 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu)
mutex_lock(&gvt->lock); mutex_lock(&gvt->lock);
vgpu->active = false; WARN(vgpu->active, "vGPU is still active!\n");
idr_remove(&gvt->vgpu_idr, vgpu->id); 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_sched_policy(vgpu);
intel_vgpu_clean_gvt_context(vgpu); intel_vgpu_clean_gvt_context(vgpu);
intel_vgpu_clean_execlist(vgpu); intel_vgpu_clean_execlist(vgpu);
@ -349,7 +383,6 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
if (ret) if (ret)
goto out_clean_shadow_ctx; goto out_clean_shadow_ctx;
vgpu->active = true;
mutex_unlock(&gvt->lock); mutex_unlock(&gvt->lock);
return vgpu; return vgpu;

View File

@ -200,10 +200,10 @@ static const struct dma_buf_ops i915_dmabuf_ops = {
.map_dma_buf = i915_gem_map_dma_buf, .map_dma_buf = i915_gem_map_dma_buf,
.unmap_dma_buf = i915_gem_unmap_dma_buf, .unmap_dma_buf = i915_gem_unmap_dma_buf,
.release = drm_gem_dmabuf_release, .release = drm_gem_dmabuf_release,
.kmap = i915_gem_dmabuf_kmap, .map = i915_gem_dmabuf_kmap,
.kmap_atomic = i915_gem_dmabuf_kmap_atomic, .map_atomic = i915_gem_dmabuf_kmap_atomic,
.kunmap = i915_gem_dmabuf_kunmap, .unmap = i915_gem_dmabuf_kunmap,
.kunmap_atomic = i915_gem_dmabuf_kunmap_atomic, .unmap_atomic = i915_gem_dmabuf_kunmap_atomic,
.mmap = i915_gem_dmabuf_mmap, .mmap = i915_gem_dmabuf_mmap,
.vmap = i915_gem_dmabuf_vmap, .vmap = i915_gem_dmabuf_vmap,
.vunmap = i915_gem_dmabuf_vunmap, .vunmap = i915_gem_dmabuf_vunmap,

View File

@ -129,10 +129,10 @@ static const struct dma_buf_ops mock_dmabuf_ops = {
.map_dma_buf = mock_map_dma_buf, .map_dma_buf = mock_map_dma_buf,
.unmap_dma_buf = mock_unmap_dma_buf, .unmap_dma_buf = mock_unmap_dma_buf,
.release = mock_dmabuf_release, .release = mock_dmabuf_release,
.kmap = mock_dmabuf_kmap, .map = mock_dmabuf_kmap,
.kmap_atomic = mock_dmabuf_kmap_atomic, .map_atomic = mock_dmabuf_kmap_atomic,
.kunmap = mock_dmabuf_kunmap, .unmap = mock_dmabuf_kunmap,
.kunmap_atomic = mock_dmabuf_kunmap_atomic, .unmap_atomic = mock_dmabuf_kunmap_atomic,
.mmap = mock_dmabuf_mmap, .mmap = mock_dmabuf_mmap,
.vmap = mock_dmabuf_vmap, .vmap = mock_dmabuf_vmap,
.vunmap = mock_dmabuf_vunmap, .vunmap = mock_dmabuf_vunmap,

View File

@ -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 nouveau_display *disp = nouveau_display(crtc->dev);
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
int ret, retry = 1; int ret, retry = 20;
do { do {
ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args));

View File

@ -44,6 +44,8 @@ nv40_fifo_dma_engine(struct nvkm_engine *engine, u32 *reg, u32 *ctx)
*ctx = 0x38; *ctx = 0x38;
return true; return true;
case NVKM_ENGINE_MPEG: case NVKM_ENGINE_MPEG:
if (engine->subdev.device->chipset < 0x44)
return false;
*reg = 0x00330c; *reg = 0x00330c;
*ctx = 0x54; *ctx = 0x54;
return true; return true;

View File

@ -33,7 +33,7 @@ nvbios_boostTe(struct nvkm_bios *bios,
u32 boost = 0; u32 boost = 0;
if (!bit_entry(bios, 'P', &bit_P)) { 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); boost = nvbios_rd32(bios, bit_P.offset + 0x30);
if (boost) { if (boost) {

View File

@ -33,7 +33,7 @@ nvbios_cstepTe(struct nvkm_bios *bios,
u32 cstep = 0; u32 cstep = 0;
if (!bit_entry(bios, 'P', &bit_P)) { 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); cstep = nvbios_rd32(bios, bit_P.offset + 0x34);
if (cstep) { if (cstep) {

View File

@ -32,7 +32,7 @@ nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
u32 fan = 0; u32 fan = 0;
if (!bit_entry(bios, 'P', &bit_P)) { 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); fan = nvbios_rd32(bios, bit_P.offset + 0x58);
if (fan) { if (fan) {

View File

@ -33,7 +33,7 @@ nvbios_power_budget_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt,
u32 power_budget; u32 power_budget;
if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 || if (bit_entry(bios, 'P', &bit_P) || bit_P.version != 2 ||
bit_P.length < 0x2c) bit_P.length < 0x30)
return 0; return 0;
power_budget = nvbios_rd32(bios, bit_P.offset + 0x2c); power_budget = nvbios_rd32(bios, bit_P.offset + 0x2c);

View File

@ -31,7 +31,7 @@ nvbios_vpstate_offset(struct nvkm_bios *b)
struct bit_entry bit_P; struct bit_entry bit_P;
if (!bit_entry(b, 'P', &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); return nvbios_rd32(b, bit_P.offset + 0x38);
} }

View File

@ -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", nvkm_debug(subdev, "FBP %d: %4d MiB, %d LTC(s)\n",
fbp, size, ltcs); fbp, size, ltcs);
lcomm = min(lcomm, (u64)(size / ltcs) << 20); lcomm = min(lcomm, (u64)(size / ltcs) << 20);
total += size << 20; total += (u64) size << 20;
ltcn += ltcs; ltcn += ltcs;
} else { } else {
nvkm_debug(subdev, "FBP %d: disabled\n", fbp); nvkm_debug(subdev, "FBP %d: disabled\n", fbp);

View File

@ -48,7 +48,7 @@ gm20b_secboot_tegra_read_wpr(struct gm200_secboot *gsb, u32 mc_base)
mc = ioremap(mc_base, 0xd00); mc = ioremap(mc_base, 0xd00);
if (!mc) { if (!mc) {
nvkm_error(&sb->subdev, "Cannot map Tegra MC registers\n"); 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) | sb->wpr_addr = ioread32_native(mc + MC_SECURITY_CARVEOUT2_BOM_0) |
((u64)ioread32_native(mc + MC_SECURITY_CARVEOUT2_BOM_HI_0) << 32); ((u64)ioread32_native(mc + MC_SECURITY_CARVEOUT2_BOM_HI_0) << 32);

View File

@ -160,10 +160,10 @@ static struct dma_buf_ops omap_dmabuf_ops = {
.release = omap_gem_dmabuf_release, .release = omap_gem_dmabuf_release,
.begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
.end_cpu_access = omap_gem_dmabuf_end_cpu_access, .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
.kmap_atomic = omap_gem_dmabuf_kmap_atomic, .map_atomic = omap_gem_dmabuf_kmap_atomic,
.kunmap_atomic = omap_gem_dmabuf_kunmap_atomic, .unmap_atomic = omap_gem_dmabuf_kunmap_atomic,
.kmap = omap_gem_dmabuf_kmap, .map = omap_gem_dmabuf_kmap,
.kunmap = omap_gem_dmabuf_kunmap, .unmap = omap_gem_dmabuf_kunmap,
.mmap = omap_gem_dmabuf_mmap, .mmap = omap_gem_dmabuf_mmap,
}; };

View File

@ -62,6 +62,12 @@ config DRM_PANEL_PANASONIC_VVX10F034N00
WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some
Xperia Z2 tablets 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 config DRM_PANEL_SAMSUNG_S6E8AA0
tristate "Samsung S6E8AA0 DSI video mode panel" tristate "Samsung S6E8AA0 DSI video mode panel"
depends on OF 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 Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
(540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard (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 endmenu

View File

@ -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_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.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_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_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.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_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o

View 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");

View File

@ -386,6 +386,31 @@ static void panel_simple_shutdown(struct device *dev)
panel_simple_disable(&panel->base); 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 = &ampire_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 = { static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = {
.clock = 33333, .clock = 33333,
.hdisplay = 800, .hdisplay = 800,
@ -1806,8 +1831,36 @@ static const struct panel_desc urt_umsh_8596md_parallel = {
.bus_format = MEDIA_BUS_FMT_RGB666_1X18, .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[] = { static const struct of_device_id platform_of_match[] = {
{ {
.compatible = "ampire,am-480272h3tmqw-t01h",
.data = &ampire_am_480272h3tmqw_t01h,
}, {
.compatible = "ampire,am800480r3tmqwa1h", .compatible = "ampire,am800480r3tmqwa1h",
.data = &ampire_am800480r3tmqwa1h, .data = &ampire_am800480r3tmqwa1h,
}, { }, {
@ -1993,6 +2046,9 @@ static const struct of_device_id platform_of_match[] = {
}, { }, {
.compatible = "urt,umsh-8596md-20t", .compatible = "urt,umsh-8596md-20t",
.data = &urt_umsh_8596md_parallel, .data = &urt_umsh_8596md_parallel,
}, {
.compatible = "winstar,wf35ltiacd",
.data = &winstar_wf35ltiacd,
}, { }, {
/* sentinel */ /* sentinel */
} }

View 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");

View File

@ -66,7 +66,9 @@ static struct gdp_format_to_str {
#define GAM_GDP_ALPHARANGE_255 BIT(5) #define GAM_GDP_ALPHARANGE_255 BIT(5)
#define GAM_GDP_AGC_FULL_RANGE 0x00808080 #define GAM_GDP_AGC_FULL_RANGE 0x00808080
#define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0)) #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_NB_BANK 2
#define GDP_NODE_PER_FIELD 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 are in 16.16 format */
src_x = state->src_x >> 16; src_x = state->src_x >> 16;
src_y = state->src_y >> 16; src_y = state->src_y >> 16;
src_w = clamp_val(state->src_w >> 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); src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX_HEIGHT);
format = sti_gdp_fourcc2format(fb->format->format); format = sti_gdp_fourcc2format(fb->format->format);
if (format == -1) { 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 are in 16.16 format */
src_x = state->src_x >> 16; src_x = state->src_x >> 16;
src_y = state->src_y >> 16; src_y = state->src_y >> 16;
src_w = clamp_val(state->src_w >> 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); src_h = clamp_val(state->src_h >> 16, 0, GAM_GDP_SIZE_MAX_HEIGHT);
list = sti_gdp_get_free_nodes(gdp); list = sti_gdp_get_free_nodes(gdp);
top_field = list->top_field; top_field = list->top_field;

View File

@ -1,11 +1,11 @@
sun4i-drm-y += sun4i_crtc.o
sun4i-drm-y += sun4i_drv.o sun4i-drm-y += sun4i_drv.o
sun4i-drm-y += sun4i_framebuffer.o sun4i-drm-y += sun4i_framebuffer.o
sun4i-drm-y += sun4i_layer.o
sun4i-tcon-y += sun4i_tcon.o sun4i-tcon-y += sun4i_tcon.o
sun4i-tcon-y += sun4i_rgb.o sun4i-tcon-y += sun4i_rgb.o
sun4i-tcon-y += sun4i_dotclock.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-drm.o sun4i-tcon.o
obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o

View File

@ -24,7 +24,7 @@
#include "sun4i_backend.h" #include "sun4i_backend.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
static u32 sunxi_rgb2yuv_coef[12] = { static const u32 sunxi_rgb2yuv_coef[12] = {
0x00000107, 0x00000204, 0x00000064, 0x00000108, 0x00000107, 0x00000204, 0x00000064, 0x00000108,
0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808

View File

@ -19,6 +19,7 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_graph.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -27,6 +28,7 @@
#include "sun4i_backend.h" #include "sun4i_backend.h"
#include "sun4i_crtc.h" #include "sun4i_crtc.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
#include "sun4i_layer.h"
#include "sun4i_tcon.h" #include "sun4i_tcon.h"
static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc, 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 drm_crtc_state *old_state)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc); 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; struct drm_pending_vblank_event *event = crtc->state->event;
DRM_DEBUG_DRIVER("Committing plane changes\n"); DRM_DEBUG_DRIVER("Committing plane changes\n");
sun4i_backend_commit(drv->backend); sun4i_backend_commit(scrtc->backend);
if (event) { if (event) {
crtc->state->event = NULL; 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) static void sun4i_crtc_disable(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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"); DRM_DEBUG_DRIVER("Disabling the CRTC\n");
sun4i_tcon_disable(drv->tcon); sun4i_tcon_disable(scrtc->tcon);
if (crtc->state->event && !crtc->state->active) { if (crtc->state->event && !crtc->state->active) {
spin_lock_irq(&crtc->dev->event_lock); 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) static void sun4i_crtc_enable(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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"); 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 = { 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) static int sun4i_crtc_enable_vblank(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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); 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; 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) static void sun4i_crtc_disable_vblank(struct drm_crtc *crtc)
{ {
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_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); 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 = { 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, .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; 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); scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
if (!scrtc) 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; 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, ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
drv->primary, primary,
NULL, cursor,
&sun4i_crtc_funcs, &sun4i_crtc_funcs,
NULL); NULL);
if (ret) { if (ret) {
dev_err(drm->dev, "Couldn't init DRM CRTC\n"); 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); 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; return scrtc;
} }

View File

@ -17,7 +17,9 @@ struct sun4i_crtc {
struct drm_crtc crtc; struct drm_crtc crtc;
struct drm_pending_vblank_event *event; 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) 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); 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_ */ #endif /* _SUN4I_CRTC_H_ */

View File

@ -12,6 +12,7 @@
#include <linux/component.h> #include <linux/component.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/of_reserved_mem.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
@ -20,10 +21,9 @@
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include "sun4i_crtc.h"
#include "sun4i_drv.h" #include "sun4i_drv.h"
#include "sun4i_framebuffer.h" #include "sun4i_framebuffer.h"
#include "sun4i_layer.h" #include "sun4i_tcon.h"
DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops); 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->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); drm_mode_config_init(drm);
ret = component_bind_all(drm->dev, drm); ret = component_bind_all(drm->dev, drm);
if (ret) { if (ret) {
dev_err(drm->dev, "Couldn't bind all pipelines components\n"); 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; drm->irq_enabled = true;
/* Remove early framebuffers (ie. simplefb) */ /* Remove early framebuffers (ie. simplefb) */
@ -126,7 +121,7 @@ static int sun4i_drv_bind(struct device *dev)
if (IS_ERR(drv->fbdev)) { if (IS_ERR(drv->fbdev)) {
dev_err(drm->dev, "Couldn't create our framebuffer\n"); dev_err(drm->dev, "Couldn't create our framebuffer\n");
ret = PTR_ERR(drv->fbdev); ret = PTR_ERR(drv->fbdev);
goto free_drm; goto cleanup_mode_config;
} }
/* Enable connectors polling */ /* Enable connectors polling */
@ -134,10 +129,18 @@ static int sun4i_drv_bind(struct device *dev)
ret = drm_dev_register(drm, 0); ret = drm_dev_register(drm, 0);
if (ret) if (ret)
goto free_drm; goto finish_poll;
return 0; 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: free_drm:
drm_dev_unref(drm); drm_dev_unref(drm);
return ret; return ret;
@ -150,7 +153,9 @@ static void sun4i_drv_unbind(struct device *dev)
drm_dev_unregister(drm); drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm); drm_kms_helper_poll_fini(drm);
sun4i_framebuffer_free(drm); sun4i_framebuffer_free(drm);
drm_mode_config_cleanup(drm);
drm_vblank_cleanup(drm); drm_vblank_cleanup(drm);
of_reserved_mem_device_release(dev);
drm_dev_unref(drm); drm_dev_unref(drm);
} }

Some files were not shown because too many files have changed in this diff Show More