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