drm-misc-next for 4.17:

Cross-subsystem Changes:
  dt-bindings: Add emtrion vendor prefix (Jan)
 
 Core Changes:
  drm_print: More object size reductions (Joe)
 
 Driver Changes:
  vc4: Fix alpha blending on bottom plane (Stefan)
  panel: Add Raydium RM68200 panel support (Phillipe)
  panel: Add AUO G104SN02 V2 panel support (Christoph)
  panel: Add KEO TX31D200VM0BAA panel support (Jagan)
  vga_switcheroo: Use device link to bookkeep HDA runtime pm (Lukas)
  rockchip: More CrOS kevin patches trickling in (various
  sun4i: Add A80 support (Chen-Yu)
  sun4i: Add YUV plane support (Maxime)
  meson: Multiple (mostly error-path) fixups (Christophe/Wei)
 
 Cc: Stefan Schake <stschake@gmail.com>
 Cc: Philippe CORNU <philippe.cornu@st.com>
 Cc: jan.tuerk@emtrion.com
 Cc: Christoph Fritz <chf.fritz@googlemail.com>
 Cc: Jagan Teki <jagannadh.teki@gmail.com>
 Cc: Lukas Wunner <lukas@wunner.de>
 Cc: Joe Perches <joe@perches.com>
 Cc: Chen-Yu Tsai <wens@csie.org>
 Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
 Cc: Wei Yongjun <weiyongjun1@huawei.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEfxcpfMSgdnQMs+QqlvcN/ahKBwoFAlqyb4kACgkQlvcN/ahK
 BwqHhwf/YdsRWUEWhk1nmb+zAJfB9NVggy+q8fsQywz1gRU+VLjDgX4B/W71qiyj
 blIi+iqtEW7INQ5J3izs1N2NXMBG/zL+Ik3eZurM0T9dL1gQ21gEkR5FNsU6vlhC
 JrBDl0eeKVM9iLdv7MPHXwaf8I6UjYu+WHZpPJ2j6hLnu3QLxMF1zejJjaqMkPvL
 TPfMMxN6Af9VA0JpnFCLcxb7/+rNiBxV4r84wjPlHAyjoEd0HTP+iFG+ANxPve7a
 AgYWKj+Xq/NHVyqB2V9hfEb7et8h3Z9SE0zrZRlQxz+tFpzQ389R2Kw/363JRlKB
 cv7saBx/cx22mdSE67AI/IJrjjPFLw==
 =Mo+Y
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2018-03-21' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 4.17:

Cross-subsystem Changes:
 dt-bindings: Add emtrion vendor prefix (Jan)

Core Changes:
 drm_print: More object size reductions (Joe)

Driver Changes:
 vc4: Fix alpha blending on bottom plane (Stefan)
 panel: Add Raydium RM68200 panel support (Phillipe)
 panel: Add AUO G104SN02 V2 panel support (Christoph)
 panel: Add KEO TX31D200VM0BAA panel support (Jagan)
 vga_switcheroo: Use device link to bookkeep HDA runtime pm (Lukas)
 rockchip: More CrOS kevin patches trickling in (various
 sun4i: Add A80 support (Chen-Yu)
 sun4i: Add YUV plane support (Maxime)
 meson: Multiple (mostly error-path) fixups (Christophe/Wei)

Cc: Stefan Schake <stschake@gmail.com>
Cc: Philippe CORNU <philippe.cornu@st.com>
Cc: jan.tuerk@emtrion.com
Cc: Christoph Fritz <chf.fritz@googlemail.com>
Cc: Jagan Teki <jagannadh.teki@gmail.com>
Cc: Lukas Wunner <lukas@wunner.de>
Cc: Joe Perches <joe@perches.com>
Cc: Chen-Yu Tsai <wens@csie.org>
Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Cc: Wei Yongjun <weiyongjun1@huawei.com>

* tag 'drm-misc-next-2018-03-21' of git://anongit.freedesktop.org/drm/drm-misc: (70 commits)
  drm/qxl: Replace drm_gem_object_reference/unreference() with _get/put()
  drm/meson: Fix potential NULL dereference in meson_drv_bind_master()
  drm/sun4i: backend: Support YUV planes
  drm/sun4i: backend: Check that we only have a single YUV plane
  drm/sun4i: Add driver support for A80 display pipeline
  drm/sun4i: Add compatible strings for the A80 display pipeline
  drm/sun4i: Add support for A80 TCONs
  drm/sun4i: Add DT binding for Detail Enhancement Unit in Allwinner A80 SoC
  drm/sun4i: Add compatible strings for A80 TCONs
  drm: Reduce object size of DRM_DEV_<LEVEL> uses
  drm/doc: Put all driver docs into a separate chapter
  drm: dma_bufs: Fixed checkpatch issues
  drm: remove drm_mode_object_{un/reference} aliases
  drm: Add PSR version 3 macro
  drm/vc4_validate: Remove VLA usage
  drm: Make drm_mode_vrefresh() a bit more accurate
  drm: Nuke the useless 'ret' variable from drm_mode_convert_umode()
  drm/i915: Use drm_color_lut_size()
  drm/i915: Remove the blob->data casts
  drm: Introduce drm_color_lut_size()
  ...
This commit is contained in:
Dave Airlie 2018-03-22 05:36:14 +10:00
commit 0c5286a822
85 changed files with 2219 additions and 643 deletions

View File

@ -0,0 +1,12 @@
AU Optronics Corporation 10.4" (800x600) color TFT LCD panel
Required properties:
- compatible: should be "auo,g104sn02"
- power-supply: as specified in the base binding
Optional properties:
- backlight: as specified in the base binding
- enable-gpios: as specified in the base binding
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.

View File

@ -80,6 +80,11 @@ The parameters are defined as:
| | v | | |
+----------+-------------------------------------+----------+-------+
Note: In addition to being used as subnode(s) of display-timings, the timing
subnode may also be used on its own. This is appropriate if only one mode
need be conveyed. In this case, the node should be named 'panel-timing'.
Example:
display-timings {

View File

@ -0,0 +1,25 @@
Kaohsiung Opto-Electronics. TX31D200VM0BAA 12.3" HSXGA LVDS 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 "koe,tx31d200vm0baa"
Optional properties:
- backlight: phandle of the backlight device attached to the panel
Optional nodes:
- Video port for LVDS panel input.
Example:
panel {
compatible = "koe,tx31d200vm0baa";
backlight = <&backlight_lvds>;
port {
panel_in: endpoint {
remote-endpoint = <&lvds0_out>;
};
};
};

View File

@ -9,6 +9,7 @@ Required properties:
Optional properties:
- reset-gpios: a GPIO spec for the reset pin (active low).
- power-supply: phandle of the regulator that provides the supply voltage.
Example:
&dsi {
@ -17,5 +18,6 @@ Example:
compatible = "orisetech,otm8009a";
reg = <0>;
reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>;
power-supply = <&v1v8>;
};
};

View File

@ -0,0 +1,25 @@
Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel
The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD
panel connected using a MIPI-DSI video interface.
Required properties:
- compatible: "raydium,rm68200"
- reg: the virtual channel number of a DSI peripheral
Optional properties:
- reset-gpios: a GPIO spec for the reset pin (active low).
- power-supply: phandle of the regulator that provides the supply voltage.
- backlight: phandle of the backlight device attached to the panel.
Example:
&dsi {
...
panel@0 {
compatible = "raydium,rm68200";
reg = <0>;
reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>;
power-supply = <&v1v8>;
backlight = <&pwm_backlight>;
};
};

View File

@ -1,4 +1,8 @@
Simple display panel
====================
panel node
----------
Required properties:
- power-supply: See panel-common.txt

View File

@ -146,13 +146,16 @@ Required properties:
* allwinner,sun8i-a83t-tcon-lcd
* allwinner,sun8i-a83t-tcon-tv
* allwinner,sun8i-v3s-tcon
* allwinner,sun9i-a80-tcon-lcd
* allwinner,sun9i-a80-tcon-tv
- reg: base address and size of memory-mapped region
- interrupts: interrupt associated to this IP
- clocks: phandles to the clocks feeding the TCON.
- 'ahb': the interface clocks
- 'tcon-ch0': The clock driving the TCON channel 0, except for A83T TV TCON
- 'tcon-ch0': The clock driving the TCON channel 0, if supported
- resets: phandles to the reset controllers driving the encoder
- "lcd": the reset line for the TCON channel 0
- "lcd": the reset line for the TCON
- "edp": the reset line for the eDP block (A80 only)
- clock-names: the clock names mentioned above
- reset-names: the reset names mentioned above
@ -171,7 +174,9 @@ Required properties:
channel the endpoint is associated to. If that property is not
present, the endpoint number will be used as the channel number.
On SoCs other than the A33 and V3s, there is one more clock required:
For TCONs with channel 0, there is one more clock required:
- 'tcon-ch0': The clock driving the TCON channel 0
For TCONs with channel 1, there is one more clock required:
- 'tcon-ch1': The clock driving the TCON channel 1
When TCON support LVDS (all TCONs except TV TCON on A83T and those found
@ -186,7 +191,7 @@ DRC
---
The DRC (Dynamic Range Controller), found in the latest Allwinner SoCs
(A31, A23, A33), allows to dynamically adjust pixel
(A31, A23, A33, A80), allows to dynamically adjust pixel
brightness/contrast based on histogram measurements for LCD content
adaptive backlight control.
@ -196,6 +201,7 @@ Required properties:
* allwinner,sun6i-a31-drc
* allwinner,sun6i-a31s-drc
* allwinner,sun8i-a33-drc
* allwinner,sun9i-a80-drc
- reg: base address and size of the memory-mapped region.
- interrupts: interrupt associated to this IP
- clocks: phandles to the clocks feeding the DRC
@ -222,6 +228,7 @@ Required properties:
* allwinner,sun6i-a31-display-backend
* allwinner,sun7i-a20-display-backend
* allwinner,sun8i-a33-display-backend
* allwinner,sun9i-a80-display-backend
- reg: base address and size of the memory-mapped region.
- interrupts: interrupt associated to this IP
- clocks: phandles to the clocks feeding the frontend and backend
@ -243,6 +250,28 @@ On the A33, some additional properties are required:
- resets and reset-names need to have a phandle to the SAT bus
resets, whose name will be "sat"
DEU
---
The DEU (Detail Enhancement Unit), found in the Allwinner A80 SoC,
can sharpen the display content in both luma and chroma channels.
Required properties:
- compatible: value must be one of:
* allwinner,sun9i-a80-deu
- reg: base address and size of the memory-mapped region.
- interrupts: interrupt associated to this IP
- clocks: phandles to the clocks feeding the DEU
* ahb: the DEU interface clock
* mod: the DEU module clock
* ram: the DEU DRAM clock
- clock-names: the clock names mentioned above
- resets: phandles to the reset line driving the DEU
- ports: A ports node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt. The
first port should be the input endpoints, the second one the outputs
Display Engine Frontend
-----------------------
@ -256,6 +285,7 @@ Required properties:
* allwinner,sun6i-a31-display-frontend
* allwinner,sun7i-a20-display-frontend
* allwinner,sun8i-a33-display-frontend
* allwinner,sun9i-a80-display-frontend
- reg: base address and size of the memory-mapped region.
- interrupts: interrupt associated to this IP
- clocks: phandles to the clocks feeding the frontend and backend
@ -312,6 +342,7 @@ Required properties:
* allwinner,sun8i-a83t-display-engine
* allwinner,sun8i-h3-display-engine
* allwinner,sun8i-v3s-display-engine
* allwinner,sun9i-a80-display-engine
- allwinner,pipelines: list of phandle to the display engine
frontends (DE 1.0) or mixers (DE 2.0) available.

View File

@ -104,6 +104,7 @@ eeti eGalax_eMPIA Technology Inc
elan Elan Microelectronic Corp.
embest Shenzhen Embest Technology Co., Ltd.
emmicro EM Microelectronic
emtrion emtrion GmbH
energymicro Silicon Laboratories (formerly Energy Micro AS)
engicam Engicam S.r.l.
epcos EPCOS AG

View File

@ -0,0 +1,21 @@
========================
GPU Driver Documentation
========================
.. toctree::
i915
meson
pl111
tegra
tinydrm
tve200
vc4
bridge/dw-hdmi
.. only:: subproject and html
Indices
=======
* :ref:`genindex`

View File

@ -286,6 +286,9 @@ Atomic Mode Setting Function Reference
.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
:export:
.. kernel-doc:: drivers/gpu/drm/drm_atomic.c
:internal:
CRTC Abstraction
================

View File

@ -10,16 +10,9 @@ Linux GPU Driver Developer's Guide
drm-kms
drm-kms-helpers
drm-uapi
i915
meson
pl111
tegra
tinydrm
tve200
vc4
drivers
vga-switcheroo
vgaarbiter
bridge/dw-hdmi
todo
.. only:: subproject and html

View File

@ -738,7 +738,6 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev)
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
drm_kms_helper_poll_disable(drm_dev);
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
ret = amdgpu_device_suspend(drm_dev, false, false);
pci_save_state(pdev);
@ -775,7 +774,6 @@ static int amdgpu_pmops_runtime_resume(struct device *dev)
ret = amdgpu_device_resume(drm_dev, false, false);
drm_kms_helper_poll_enable(drm_dev);
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
return 0;
}

View File

@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
@ -35,6 +36,8 @@
#define to_dp(nm) container_of(nm, struct analogix_dp_device, nm)
static const bool verify_fast_training;
struct bridge_init {
struct i2c_client *client;
struct device_node *node;
@ -98,18 +101,18 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
return 0;
}
int analogix_dp_psr_supported(struct analogix_dp_device *dp)
int analogix_dp_psr_enabled(struct analogix_dp_device *dp)
{
return dp->psr_support;
return dp->psr_enable;
}
EXPORT_SYMBOL_GPL(analogix_dp_psr_supported);
EXPORT_SYMBOL_GPL(analogix_dp_psr_enabled);
int analogix_dp_enable_psr(struct analogix_dp_device *dp)
{
struct edp_vsc_psr psr_vsc;
if (!dp->psr_support)
if (!dp->psr_enable)
return 0;
/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
@ -122,8 +125,7 @@ int analogix_dp_enable_psr(struct analogix_dp_device *dp)
psr_vsc.DB0 = 0;
psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
analogix_dp_send_psr_spd(dp, &psr_vsc);
return 0;
return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
}
EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
@ -132,7 +134,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp)
struct edp_vsc_psr psr_vsc;
int ret;
if (!dp->psr_support)
if (!dp->psr_enable)
return 0;
/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
@ -149,8 +151,7 @@ int analogix_dp_disable_psr(struct analogix_dp_device *dp)
if (ret != 1)
dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret);
analogix_dp_send_psr_spd(dp, &psr_vsc);
return 0;
return analogix_dp_send_psr_spd(dp, &psr_vsc, false);
}
EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
@ -530,7 +531,7 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
{
int lane, lane_count, retval;
u32 reg;
u8 link_align, link_status[2], adjust_request[2];
u8 link_align, link_status[2], adjust_request[2], spread;
usleep_range(400, 401);
@ -573,6 +574,20 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp)
dev_dbg(dp->dev, "final lane count = %.2x\n",
dp->link_train.lane_count);
retval = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD,
&spread);
if (retval != 1) {
dev_err(dp->dev, "failed to read downspread %d\n",
retval);
dp->fast_train_support = false;
} else {
dp->fast_train_support =
(spread & DP_NO_AUX_HANDSHAKE_LINK_TRAINING) ?
true : false;
}
dev_dbg(dp->dev, "fast link training %s\n",
dp->fast_train_support ? "supported" : "unsupported");
/* set enhanced mode if available */
analogix_dp_set_enhanced_mode(dp);
dp->link_train.lt_state = FINISHED;
@ -629,10 +644,12 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp,
*lane_count = DPCD_MAX_LANE_COUNT(data);
}
static void analogix_dp_init_training(struct analogix_dp_device *dp,
enum link_lane_count_type max_lane,
int max_rate)
static int analogix_dp_full_link_train(struct analogix_dp_device *dp,
u32 max_lanes, u32 max_rate)
{
int retval = 0;
bool training_finished = false;
/*
* MACRO_RST must be applied after the PLL_LOCK to avoid
* the DP inter pair skew issue for at least 10 us
@ -658,18 +675,13 @@ static void analogix_dp_init_training(struct analogix_dp_device *dp,
}
/* Setup TX lane count & rate */
if (dp->link_train.lane_count > max_lane)
dp->link_train.lane_count = max_lane;
if (dp->link_train.lane_count > max_lanes)
dp->link_train.lane_count = max_lanes;
if (dp->link_train.link_rate > max_rate)
dp->link_train.link_rate = max_rate;
/* All DP analog module power up */
analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
}
static int analogix_dp_sw_link_training(struct analogix_dp_device *dp)
{
int retval = 0, training_finished = 0;
dp->link_train.lt_state = START;
@ -704,22 +716,88 @@ static int analogix_dp_sw_link_training(struct analogix_dp_device *dp)
return retval;
}
static int analogix_dp_set_link_train(struct analogix_dp_device *dp,
u32 count, u32 bwtype)
static int analogix_dp_fast_link_train(struct analogix_dp_device *dp)
{
int i;
int retval;
int i, ret;
u8 link_align, link_status[2];
enum pll_status status;
for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
analogix_dp_init_training(dp, count, bwtype);
retval = analogix_dp_sw_link_training(dp);
if (retval == 0)
break;
analogix_dp_reset_macro(dp);
usleep_range(100, 110);
analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
for (i = 0; i < dp->link_train.lane_count; i++) {
analogix_dp_set_lane_link_training(dp,
dp->link_train.training_lane[i], i);
}
return retval;
ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status,
status != PLL_UNLOCKED, 120,
120 * DP_TIMEOUT_LOOP_COUNT);
if (ret) {
DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", ret);
return ret;
}
/* source Set training pattern 1 */
analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
/* From DP spec, pattern must be on-screen for a minimum 500us */
usleep_range(500, 600);
analogix_dp_set_training_pattern(dp, TRAINING_PTN2);
/* From DP spec, pattern must be on-screen for a minimum 500us */
usleep_range(500, 600);
/* TODO: enhanced_mode?*/
analogix_dp_set_training_pattern(dp, DP_NONE);
/*
* Useful for debugging issues with fast link training, disable for more
* speed
*/
if (verify_fast_training) {
ret = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED,
&link_align);
if (ret < 0) {
DRM_DEV_ERROR(dp->dev, "Read align status failed %d\n",
ret);
return ret;
}
ret = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status,
2);
if (ret < 0) {
DRM_DEV_ERROR(dp->dev, "Read link status failed %d\n",
ret);
return ret;
}
if (analogix_dp_clock_recovery_ok(link_status,
dp->link_train.lane_count)) {
DRM_DEV_ERROR(dp->dev, "Clock recovery failed\n");
analogix_dp_reduce_link_rate(dp);
return -EIO;
}
if (analogix_dp_channel_eq_ok(link_status, link_align,
dp->link_train.lane_count)) {
DRM_DEV_ERROR(dp->dev, "Channel EQ failed\n");
analogix_dp_reduce_link_rate(dp);
return -EIO;
}
}
return 0;
}
static int analogix_dp_train_link(struct analogix_dp_device *dp)
{
if (dp->fast_train_support)
return analogix_dp_fast_link_train(dp);
return analogix_dp_full_link_train(dp, dp->video_info.max_lane_count,
dp->video_info.max_link_rate);
}
static int analogix_dp_config_video(struct analogix_dp_device *dp)
@ -848,10 +926,10 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
DRM_ERROR("failed to disable the panel\n");
}
ret = analogix_dp_set_link_train(dp, dp->video_info.max_lane_count,
dp->video_info.max_link_rate);
ret = readx_poll_timeout(analogix_dp_train_link, dp, ret, !ret, 100,
DP_TIMEOUT_TRAINING_US * 5);
if (ret) {
dev_err(dp->dev, "unable to do link train\n");
dev_err(dp->dev, "unable to do link train, ret=%d\n", ret);
return;
}
@ -873,8 +951,8 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
/* Enable video */
analogix_dp_start_video(dp);
dp->psr_support = analogix_dp_detect_sink_psr(dp);
if (dp->psr_support)
dp->psr_enable = analogix_dp_detect_sink_psr(dp);
if (dp->psr_enable)
analogix_dp_enable_sink_psr(dp);
}
@ -1119,6 +1197,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
if (ret)
DRM_ERROR("failed to setup the panel ret = %d\n", ret);
dp->psr_enable = false;
dp->dpms_mode = DRM_MODE_DPMS_OFF;
}

View File

@ -20,6 +20,10 @@
#define MAX_CR_LOOP 5
#define MAX_EQ_LOOP 5
/* Training takes 22ms if AUX channel comm fails. Use this as retry interval */
#define DP_TIMEOUT_TRAINING_US 22000
#define DP_TIMEOUT_PSR_LOOP_MS 300
/* DP_MAX_LANE_COUNT */
#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1)
#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f)
@ -168,7 +172,8 @@ struct analogix_dp_device {
int dpms_mode;
int hpd_gpio;
bool force_hpd;
bool psr_support;
bool psr_enable;
bool fast_train_support;
struct mutex panel_lock;
bool panel_is_modeset;
@ -247,8 +252,8 @@ void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp);
void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
struct edp_vsc_psr *vsc);
int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
struct edp_vsc_psr *vsc, bool blocking);
ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
struct drm_dp_aux_msg *msg);

View File

@ -10,10 +10,11 @@
* option) any later version.
*/
#include <linux/device.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <drm/bridge/analogix_dp.h>
@ -992,10 +993,25 @@ void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp)
writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
}
void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
struct edp_vsc_psr *vsc)
static ssize_t analogix_dp_get_psr_status(struct analogix_dp_device *dp)
{
ssize_t val;
u8 status;
val = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &status);
if (val < 0) {
dev_err(dp->dev, "PSR_STATUS read failed ret=%zd", val);
return val;
}
return status;
}
int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
struct edp_vsc_psr *vsc, bool blocking)
{
unsigned int val;
int ret;
ssize_t psr_status;
/* don't send info frame */
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
@ -1036,6 +1052,20 @@ void analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
val |= IF_EN;
writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
if (!blocking)
return 0;
ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status,
psr_status >= 0 &&
((vsc->DB1 && psr_status == DP_PSR_SINK_ACTIVE_RFB) ||
(!vsc->DB1 && psr_status == DP_PSR_SINK_INACTIVE)), 1500,
DP_TIMEOUT_PSR_LOOP_MS * 1000);
if (ret) {
dev_warn(dp->dev, "Failed to apply PSR %d\n", ret);
return ret;
}
return 0;
}
ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,

View File

@ -147,7 +147,6 @@ struct dw_hdmi {
int vic;
u8 edid[HDMI_EDID_LEN];
bool cable_plugin;
struct {
const struct dw_hdmi_phy_ops *ops;
@ -1679,12 +1678,6 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
}
static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
@ -1774,8 +1767,6 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_tx_hdcp_config(hdmi);
dw_hdmi_clear_overflow(hdmi);
if (hdmi->cable_plugin && hdmi->sink_is_hdmi)
hdmi_enable_overflow_interrupts(hdmi);
return 0;
}

View File

@ -391,8 +391,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
if (blob) {
if (blob->length != sizeof(struct drm_mode_modeinfo) ||
drm_mode_convert_umode(state->crtc->dev, &state->mode,
(const struct drm_mode_modeinfo *)
blob->data))
blob->data))
return -EINVAL;
state->mode_blob = drm_property_blob_get(blob);
@ -409,11 +408,36 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
}
EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
/**
* drm_atomic_replace_property_blob_from_id - lookup the new blob and replace the old one with it
* @dev: DRM device
* @blob: a pointer to the member blob to be replaced
* @blob_id: ID of the new blob
* @expected_size: total expected size of the blob data (in bytes)
* @expected_elem_size: expected element size of the blob data (in bytes)
* @replaced: did the blob get replaced?
*
* Replace @blob with another blob with the ID @blob_id. If @blob_id is zero
* @blob becomes NULL.
*
* If @expected_size is positive the new blob length is expected to be equal
* to @expected_size bytes. If @expected_elem_size is positive the new blob
* length is expected to be a multiple of @expected_elem_size bytes. Otherwise
* an error is returned.
*
* @replaced will indicate to the caller whether the blob was replaced or not.
* If the old and new blobs were in fact the same blob @replaced will be false
* otherwise it will be true.
*
* RETURNS:
* Zero on success, error code on failure.
*/
static int
drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
struct drm_property_blob **blob,
uint64_t blob_id,
ssize_t expected_size,
ssize_t expected_elem_size,
bool *replaced)
{
struct drm_property_blob *new_blob = NULL;
@ -423,7 +447,13 @@ drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
if (new_blob == NULL)
return -EINVAL;
if (expected_size > 0 && expected_size != new_blob->length) {
if (expected_size > 0 &&
new_blob->length != expected_size) {
drm_property_blob_put(new_blob);
return -EINVAL;
}
if (expected_elem_size > 0 &&
new_blob->length % expected_elem_size != 0) {
drm_property_blob_put(new_blob);
return -EINVAL;
}
@ -471,7 +501,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
ret = drm_atomic_replace_property_blob_from_id(dev,
&state->degamma_lut,
val,
-1,
-1, sizeof(struct drm_color_lut),
&replaced);
state->color_mgmt_changed |= replaced;
return ret;
@ -479,7 +509,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
ret = drm_atomic_replace_property_blob_from_id(dev,
&state->ctm,
val,
sizeof(struct drm_color_ctm),
sizeof(struct drm_color_ctm), -1,
&replaced);
state->color_mgmt_changed |= replaced;
return ret;
@ -487,7 +517,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
ret = drm_atomic_replace_property_blob_from_id(dev,
&state->gamma_lut,
val,
-1,
-1, sizeof(struct drm_color_lut),
&replaced);
state->color_mgmt_changed |= replaced;
return ret;

View File

@ -3818,7 +3818,7 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
}
/* Prepare GAMMA_LUT with the legacy values. */
blob_data = (struct drm_color_lut *) blob->data;
blob_data = blob->data;
for (i = 0; i < size; i++) {
blob_data[i].red = red[i];
blob_data[i].green = green[i];

View File

@ -129,10 +129,10 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
* type. Adds the map to the map list drm_device::maplist. Adds MTRR's where
* applicable and if supported by the kernel.
*/
static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
static int drm_addmap_core(struct drm_device *dev, resource_size_t offset,
unsigned int size, enum drm_map_type type,
enum drm_map_flags flags,
struct drm_map_list ** maplist)
struct drm_map_list **maplist)
{
struct drm_local_map *map;
struct drm_map_list *list;
@ -224,7 +224,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
case _DRM_SHM:
list = drm_find_matching_map(dev, map);
if (list != NULL) {
if(list->map->size != map->size) {
if (list->map->size != map->size) {
DRM_DEBUG("Matching maps of type %d with "
"mismatched sizes, (%ld vs %ld)\n",
map->type, map->size, list->map->size);
@ -361,7 +361,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
return 0;
}
int drm_legacy_addmap(struct drm_device * dev, resource_size_t offset,
int drm_legacy_addmap(struct drm_device *dev, resource_size_t offset,
unsigned int size, enum drm_map_type type,
enum drm_map_flags flags, struct drm_local_map **map_ptr)
{
@ -637,8 +637,8 @@ int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data,
*
* Frees any pages and buffers associated with the given entry.
*/
static void drm_cleanup_buf_error(struct drm_device * dev,
struct drm_buf_entry * entry)
static void drm_cleanup_buf_error(struct drm_device *dev,
struct drm_buf_entry *entry)
{
int i;
@ -1446,8 +1446,8 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p,
void __user **v,
int (*f)(void *, int, unsigned long,
struct drm_buf *),
struct drm_file *file_priv)
struct drm_buf *),
struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int retcode = 0;

View File

@ -1554,8 +1554,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
struct edid *override = NULL;
if (connector->override_edid)
override = drm_edid_duplicate((const struct edid *)
connector->edid_blob_ptr->data);
override = drm_edid_duplicate(connector->edid_blob_ptr->data);
if (!override)
override = drm_load_edid_firmware(connector);

View File

@ -1351,7 +1351,7 @@ static struct drm_property_blob *setcmap_new_gamma_lut(struct drm_crtc *crtc,
if (IS_ERR(gamma_lut))
return gamma_lut;
lut = (struct drm_color_lut *)gamma_lut->data;
lut = gamma_lut->data;
if (cmap->start || cmap->len != size) {
u16 *r = crtc->gamma_store;
u16 *g = r + crtc->gamma_size;

View File

@ -158,9 +158,10 @@ static int framebuffer_check(struct drm_device *dev,
info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN);
if (!info) {
struct drm_format_name_buf format_name;
DRM_DEBUG_KMS("bad framebuffer format %s\n",
drm_get_format_name(r->pixel_format,
&format_name));
drm_get_format_name(r->pixel_format,
&format_name));
return -EINVAL;
}

View File

@ -773,24 +773,23 @@ EXPORT_SYMBOL(drm_mode_hsync);
int drm_mode_vrefresh(const struct drm_display_mode *mode)
{
int refresh = 0;
unsigned int calc_val;
if (mode->vrefresh > 0)
refresh = mode->vrefresh;
else if (mode->htotal > 0 && mode->vtotal > 0) {
int vtotal;
vtotal = mode->vtotal;
/* work out vrefresh the value will be x1000 */
calc_val = (mode->clock * 1000);
calc_val /= mode->htotal;
refresh = (calc_val + vtotal / 2) / vtotal;
unsigned int num, den;
num = mode->clock * 1000;
den = mode->htotal * mode->vtotal;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
refresh *= 2;
num *= 2;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
refresh /= 2;
den *= 2;
if (mode->vscan > 1)
refresh /= mode->vscan;
den *= mode->vscan;
refresh = DIV_ROUND_CLOSEST(num, den);
}
return refresh;
}
@ -1596,12 +1595,8 @@ int drm_mode_convert_umode(struct drm_device *dev,
struct drm_display_mode *out,
const struct drm_mode_modeinfo *in)
{
int ret = -EINVAL;
if (in->clock > INT_MAX || in->vrefresh > INT_MAX) {
ret = -ERANGE;
goto out;
}
if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
return -ERANGE;
out->clock = in->clock;
out->hdisplay = in->hdisplay;
@ -1622,14 +1617,11 @@ int drm_mode_convert_umode(struct drm_device *dev,
out->status = drm_mode_validate_driver(dev, out);
if (out->status != MODE_OK)
goto out;
return -EINVAL;
drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
ret = 0;
out:
return ret;
return 0;
}
/**

View File

@ -104,7 +104,7 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
if (IS_ERR(blob))
return -1;
blob_data = (struct drm_format_modifier_blob *)blob->data;
blob_data = blob->data;
blob_data->version = FORMAT_BLOB_CURRENT;
blob_data->count_formats = plane->format_count;
blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);

View File

@ -63,16 +63,34 @@ void drm_printf(struct drm_printer *p, const char *f, ...)
}
EXPORT_SYMBOL(drm_printf);
#define DRM_PRINTK_FMT "[" DRM_NAME ":%s]%s %pV"
void drm_dev_printk(const struct device *dev, const char *level,
unsigned int category, const char *function_name,
const char *prefix, const char *format, ...)
const char *format, ...)
{
struct va_format vaf;
va_list args;
if (category != DRM_UT_NONE && !(drm_debug & category))
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
if (dev)
dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV",
__builtin_return_address(0), &vaf);
else
printk("%s" "[" DRM_NAME ":%ps] %pV",
level, __builtin_return_address(0), &vaf);
va_end(args);
}
EXPORT_SYMBOL(drm_dev_printk);
void drm_dev_dbg(const struct device *dev, unsigned int category,
const char *format, ...)
{
struct va_format vaf;
va_list args;
if (!(drm_debug & category))
return;
va_start(args, format);
@ -80,32 +98,47 @@ void drm_dev_printk(const struct device *dev, const char *level,
vaf.va = &args;
if (dev)
dev_printk(level, dev, DRM_PRINTK_FMT, function_name, prefix,
&vaf);
dev_printk(KERN_DEBUG, dev, "[" DRM_NAME ":%ps] %pV",
__builtin_return_address(0), &vaf);
else
printk("%s" DRM_PRINTK_FMT, level, function_name, prefix, &vaf);
printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
__builtin_return_address(0), &vaf);
va_end(args);
}
EXPORT_SYMBOL(drm_dev_printk);
EXPORT_SYMBOL(drm_dev_dbg);
void drm_printk(const char *level, unsigned int category,
const char *format, ...)
void drm_dbg(unsigned int category, const char *format, ...)
{
struct va_format vaf;
va_list args;
if (category != DRM_UT_NONE && !(drm_debug & category))
if (!(drm_debug & category))
return;
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
printk("%s" "[" DRM_NAME ":%ps]%s %pV",
level, __builtin_return_address(0),
strcmp(level, KERN_ERR) == 0 ? " *ERROR*" : "", &vaf);
printk(KERN_DEBUG "[" DRM_NAME ":%ps] %pV",
__builtin_return_address(0), &vaf);
va_end(args);
}
EXPORT_SYMBOL(drm_printk);
EXPORT_SYMBOL(drm_dbg);
void drm_err(const char *format, ...)
{
struct va_format vaf;
va_list args;
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
printk(KERN_ERR "[" DRM_NAME ":%ps] *ERROR* %pV",
__builtin_return_address(0), &vaf);
va_end(args);
}
EXPORT_SYMBOL(drm_err);

View File

@ -567,6 +567,7 @@ drm_property_create_blob(struct drm_device *dev, size_t length,
/* This must be explicitly initialised, so we can safely call list_del
* on it in the removal handler, even if it isn't in a file list. */
INIT_LIST_HEAD(&blob->head_file);
blob->data = (void *)blob + sizeof(*blob);
blob->length = length;
blob->dev = dev;

View File

@ -39,7 +39,7 @@
#define CTM_COEFF_NEGATIVE(coeff) (((coeff) & CTM_COEFF_SIGN) != 0)
#define CTM_COEFF_ABS(coeff) ((coeff) & (CTM_COEFF_SIGN - 1))
#define LEGACY_LUT_LENGTH (sizeof(struct drm_color_lut) * 256)
#define LEGACY_LUT_LENGTH 256
/* Post offset values for RGB->YCBCR conversion */
#define POSTOFF_RGB_TO_YUV_HI 0x800
@ -79,7 +79,7 @@ static bool crtc_state_is_legacy_gamma(struct drm_crtc_state *state)
return !state->degamma_lut &&
!state->ctm &&
state->gamma_lut &&
state->gamma_lut->length == LEGACY_LUT_LENGTH;
drm_color_lut_size(state->gamma_lut) == LEGACY_LUT_LENGTH;
}
/*
@ -153,8 +153,7 @@ static void ilk_load_csc_matrix(struct drm_crtc_state *crtc_state)
ilk_load_ycbcr_conversion_matrix(intel_crtc);
return;
} else if (crtc_state->ctm) {
struct drm_color_ctm *ctm =
(struct drm_color_ctm *)crtc_state->ctm->data;
struct drm_color_ctm *ctm = crtc_state->ctm->data;
const u64 *input;
u64 temp[9];
@ -262,8 +261,7 @@ static void cherryview_load_csc_matrix(struct drm_crtc_state *state)
uint32_t mode;
if (state->ctm) {
struct drm_color_ctm *ctm =
(struct drm_color_ctm *) state->ctm->data;
struct drm_color_ctm *ctm = state->ctm->data;
uint16_t coeffs[9] = { 0, };
int i;
@ -330,7 +328,7 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc,
}
if (blob) {
struct drm_color_lut *lut = (struct drm_color_lut *) blob->data;
struct drm_color_lut *lut = blob->data;
for (i = 0; i < 256; i++) {
uint32_t word =
(drm_color_lut_extract(lut[i].red, 8) << 16) |
@ -400,8 +398,7 @@ static void bdw_load_degamma_lut(struct drm_crtc_state *state)
PAL_PREC_SPLIT_MODE | PAL_PREC_AUTO_INCREMENT);
if (state->degamma_lut) {
struct drm_color_lut *lut =
(struct drm_color_lut *) state->degamma_lut->data;
struct drm_color_lut *lut = state->degamma_lut->data;
for (i = 0; i < lut_size; i++) {
uint32_t word =
@ -435,8 +432,7 @@ static void bdw_load_gamma_lut(struct drm_crtc_state *state, u32 offset)
offset);
if (state->gamma_lut) {
struct drm_color_lut *lut =
(struct drm_color_lut *) state->gamma_lut->data;
struct drm_color_lut *lut = state->gamma_lut->data;
for (i = 0; i < lut_size; i++) {
uint32_t word =
@ -568,7 +564,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
}
if (state->degamma_lut) {
lut = (struct drm_color_lut *) state->degamma_lut->data;
lut = state->degamma_lut->data;
lut_size = INTEL_INFO(dev_priv)->color.degamma_lut_size;
for (i = 0; i < lut_size; i++) {
/* Write LUT in U0.14 format. */
@ -583,7 +579,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
}
if (state->gamma_lut) {
lut = (struct drm_color_lut *) state->gamma_lut->data;
lut = state->gamma_lut->data;
lut_size = INTEL_INFO(dev_priv)->color.gamma_lut_size;
for (i = 0; i < lut_size; i++) {
/* Write LUT in U0.10 format. */
@ -623,19 +619,17 @@ int intel_color_check(struct drm_crtc *crtc,
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
size_t gamma_length, degamma_length;
degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size *
sizeof(struct drm_color_lut);
gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size *
sizeof(struct drm_color_lut);
degamma_length = INTEL_INFO(dev_priv)->color.degamma_lut_size;
gamma_length = INTEL_INFO(dev_priv)->color.gamma_lut_size;
/*
* We allow both degamma & gamma luts at the right size or
* NULL.
*/
if ((!crtc_state->degamma_lut ||
crtc_state->degamma_lut->length == degamma_length) &&
drm_color_lut_size(crtc_state->degamma_lut) == degamma_length) &&
(!crtc_state->gamma_lut ||
crtc_state->gamma_lut->length == gamma_length))
drm_color_lut_size(crtc_state->gamma_lut) == gamma_length))
return 0;
/*

View File

@ -11059,24 +11059,17 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n,
static void __printf(3, 4)
pipe_config_err(bool adjust, const char *name, const char *format, ...)
{
char *level;
unsigned int category;
struct va_format vaf;
va_list args;
if (adjust) {
level = KERN_DEBUG;
category = DRM_UT_KMS;
} else {
level = KERN_ERR;
category = DRM_UT_NONE;
}
va_start(args, format);
vaf.fmt = format;
vaf.va = &args;
drm_printk(level, category, "mismatch in %s %pV", name, &vaf);
if (adjust)
drm_dbg(DRM_UT_KMS, "mismatch in %s %pV", name, &vaf);
else
drm_err("mismatch in %s %pV", name, &vaf);
va_end(args);
}

View File

@ -189,40 +189,55 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu");
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
if (IS_ERR(regs)) {
ret = PTR_ERR(regs);
goto free_drm;
}
priv->io_base = regs;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
if (!res)
return -EINVAL;
/* Simply ioremap since it may be a shared register zone */
regs = devm_ioremap(dev, res->start, resource_size(res));
if (!regs)
return -EADDRNOTAVAIL;
if (!regs) {
ret = -EADDRNOTAVAIL;
goto free_drm;
}
priv->hhi = devm_regmap_init_mmio(dev, regs,
&meson_regmap_config);
if (IS_ERR(priv->hhi)) {
dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
return PTR_ERR(priv->hhi);
ret = PTR_ERR(priv->hhi);
goto free_drm;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
if (!res)
return -EINVAL;
/* Simply ioremap since it may be a shared register zone */
regs = devm_ioremap(dev, res->start, resource_size(res));
if (!regs)
return -EADDRNOTAVAIL;
if (!regs) {
ret = -EADDRNOTAVAIL;
goto free_drm;
}
priv->dmc = devm_regmap_init_mmio(dev, regs,
&meson_regmap_config);
if (IS_ERR(priv->dmc)) {
dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
return PTR_ERR(priv->dmc);
ret = PTR_ERR(priv->dmc);
goto free_drm;
}
priv->vsync_irq = platform_get_irq(pdev, 0);
drm_vblank_init(drm, 1);
ret = drm_vblank_init(drm, 1);
if (ret)
goto free_drm;
drm_mode_config_init(drm);
drm->mode_config.max_width = 3840;
drm->mode_config.max_height = 2160;
@ -281,7 +296,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
return 0;
free_drm:
drm_dev_unref(drm);
drm_dev_put(drm);
return ret;
}
@ -300,7 +315,7 @@ static void meson_drv_unbind(struct device *dev)
drm_kms_helper_poll_fini(drm);
drm_fbdev_cma_fini(priv->fbdev);
drm_mode_config_cleanup(drm);
drm_dev_unref(drm);
drm_dev_put(drm);
}

View File

@ -538,7 +538,6 @@ static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
/* TOFIX Enable support for non-vic modes */
static enum drm_mode_status
dw_hdmi_mode_valid(struct drm_connector *connector,
const struct drm_display_mode *mode)
@ -555,12 +554,12 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
mode->vdisplay, mode->vsync_start,
mode->vsync_end, mode->vtotal, mode->type, mode->flags);
/* For now, only accept VIC modes */
if (!vic)
return MODE_BAD;
/* For now, filter by supported VIC modes */
if (!meson_venc_hdmi_supported_vic(vic))
/* Check against non-VIC supported modes */
if (!vic) {
if (!meson_venc_hdmi_supported_mode(mode))
return MODE_BAD;
/* Check against supported VIC modes */
} else if (!meson_venc_hdmi_supported_vic(vic))
return MODE_BAD;
vclk_freq = mode->clock;
@ -586,9 +585,14 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
/* Finally filter by configurable vclk frequencies */
switch (vclk_freq) {
case 25175:
case 40000:
case 54000:
case 65000:
case 74250:
case 108000:
case 148500:
case 162000:
case 297000:
case 594000:
return MODE_OK;
@ -653,10 +657,6 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
mode->base.id, mode->name, vic);
/* Should have been filtered */
if (!vic)
return;
/* VENC + VENC-DVI Mode setup */
meson_venc_hdmi_mode_set(priv, vic, mode);

View File

@ -328,14 +328,24 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
#define MESON_VCLK_HDMI_DDR_54000 2
/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
#define MESON_VCLK_HDMI_DDR_148500 3
/* 4028 /4 /4 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_25175 4
/* 3200 /4 /2 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_40000 5
/* 5200 /4 /2 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_65000 6
/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
#define MESON_VCLK_HDMI_74250 4
#define MESON_VCLK_HDMI_74250 7
/* 4320 /4 /1 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_108000 8
/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
#define MESON_VCLK_HDMI_148500 5
#define MESON_VCLK_HDMI_148500 9
/* 3240 /2 /1 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_162000 10
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
#define MESON_VCLK_HDMI_297000 6
#define MESON_VCLK_HDMI_297000 11
/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
#define MESON_VCLK_HDMI_594000 7
#define MESON_VCLK_HDMI_594000 12
struct meson_vclk_params {
unsigned int pll_base_freq;
@ -401,6 +411,46 @@ struct meson_vclk_params {
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 1,
},
[MESON_VCLK_HDMI_25175] = {
.pll_base_freq = 4028000,
.pll_od1 = 4,
.pll_od2 = 4,
.pll_od3 = 1,
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
[MESON_VCLK_HDMI_40000] = {
.pll_base_freq = 3200000,
.pll_od1 = 4,
.pll_od2 = 2,
.pll_od3 = 1,
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
[MESON_VCLK_HDMI_65000] = {
.pll_base_freq = 5200000,
.pll_od1 = 4,
.pll_od2 = 2,
.pll_od3 = 1,
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
[MESON_VCLK_HDMI_108000] = {
.pll_base_freq = 4320000,
.pll_od1 = 4,
.pll_od2 = 1,
.pll_od3 = 1,
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
[MESON_VCLK_HDMI_162000] = {
.pll_base_freq = 3240000,
.pll_od1 = 2,
.pll_od2 = 1,
.pll_od3 = 1,
.vid_pll_div = VID_PLL_DIV_5,
.vclk_div = 2,
},
};
static inline unsigned int pll_od_to_reg(unsigned int od)
@ -451,6 +501,90 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
0xFFFF, 0x4e00);
break;
case 3200000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
/* unreset */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
BIT(28), 0);
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0);
/* div_frac */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
0xFFFF, 0x4aab);
break;
case 3240000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
/* unreset */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
BIT(28), 0);
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0);
/* div_frac */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
0xFFFF, 0x4800);
break;
case 3865000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
/* unreset */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
BIT(28), 0);
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0);
/* div_frac */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
0xFFFF, 0x4855);
break;
case 4028000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
/* unreset */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
BIT(28), 0);
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0);
/* div_frac */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
0xFFFF, 0x4eab);
break;
case 4320000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
@ -477,6 +611,23 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
/* unreset */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
BIT(28), 0);
/* Poll for lock bit */
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
val, (val & HDMI_PLL_LOCK), 10, 0);
break;
case 5200000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
/* unreset */
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
BIT(28), 0);
@ -498,6 +649,42 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
case 3200000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
case 3240000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
case 3865000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
case 4028000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
case 4320000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
@ -516,6 +703,15 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
case 5200000:
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
break;
};
/* Reset PLL */
@ -590,15 +786,30 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
else
freq = MESON_VCLK_HDMI_DDR_54000;
break;
case 25175:
freq = MESON_VCLK_HDMI_25175;
break;
case 40000:
freq = MESON_VCLK_HDMI_40000;
break;
case 65000:
freq = MESON_VCLK_HDMI_65000;
break;
case 74250:
freq = MESON_VCLK_HDMI_74250;
break;
case 108000:
freq = MESON_VCLK_HDMI_108000;
break;
case 148500:
if (dac_freq != 148500)
freq = MESON_VCLK_HDMI_DDR_148500;
else
freq = MESON_VCLK_HDMI_148500;
break;
case 162000:
freq = MESON_VCLK_HDMI_162000;
break;
case 297000:
freq = MESON_VCLK_HDMI_297000;
break;

View File

@ -697,6 +697,314 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
},
};
union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = {
.encp = {
.dvi_settings = 0x21,
.video_mode = 0x4040,
.video_mode_adv = 0x18,
/* video_prog_mode */
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
/* video_ofld_voav_ofst */
/* yfp1_htime */
/* yfp2_htime */
.max_pxcnt = 0x31f,
/* hspuls_begin */
/* hspuls_end */
/* hspuls_switch */
/* vspuls_begin */
/* vspuls_end */
/* vspuls_bline */
/* vspuls_eline */
.havon_begin = 0x90,
.havon_end = 0x30f,
.vavon_bline = 0x23,
.vavon_eline = 0x202,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 0,
.hso_end = 0x60,
.vso_begin = 0x1e,
.vso_end = 0x32,
.vso_bline = 0,
.vso_eline = 2,
.vso_eline_present = true,
/* sy_val */
/* sy2_val */
.max_lncnt = 0x20c,
},
};
union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = {
.encp = {
.dvi_settings = 0x21,
.video_mode = 0x4040,
.video_mode_adv = 0x18,
/* video_prog_mode */
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
/* video_ofld_voav_ofst */
/* yfp1_htime */
/* yfp2_htime */
.max_pxcnt = 0x41f,
/* hspuls_begin */
/* hspuls_end */
/* hspuls_switch */
/* vspuls_begin */
/* vspuls_end */
/* vspuls_bline */
/* vspuls_eline */
.havon_begin = 0xD8,
.havon_end = 0x3f7,
.vavon_bline = 0x1b,
.vavon_eline = 0x272,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 0,
.hso_end = 0x80,
.vso_begin = 0x1e,
.vso_end = 0x32,
.vso_bline = 0,
.vso_eline = 4,
.vso_eline_present = true,
/* sy_val */
/* sy2_val */
.max_lncnt = 0x273,
},
};
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = {
.encp = {
.dvi_settings = 0x21,
.video_mode = 0x4040,
.video_mode_adv = 0x18,
/* video_prog_mode */
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
/* video_ofld_voav_ofst */
/* yfp1_htime */
/* yfp2_htime */
.max_pxcnt = 1343,
/* hspuls_begin */
/* hspuls_end */
/* hspuls_switch */
/* vspuls_begin */
/* vspuls_end */
/* vspuls_bline */
/* vspuls_eline */
.havon_begin = 296,
.havon_end = 1319,
.vavon_bline = 35,
.vavon_eline = 802,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 0,
.hso_end = 136,
.vso_begin = 30,
.vso_end = 50,
.vso_bline = 0,
.vso_eline = 6,
.vso_eline_present = true,
/* sy_val */
/* sy2_val */
.max_lncnt = 805,
},
};
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = {
.encp = {
.dvi_settings = 0x21,
.video_mode = 0x4040,
.video_mode_adv = 0x18,
/* video_prog_mode */
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
/* video_ofld_voav_ofst */
/* yfp1_htime */
/* yfp2_htime */
.max_pxcnt = 0x63f,
/* hspuls_begin */
/* hspuls_end */
/* hspuls_switch */
/* vspuls_begin */
/* vspuls_end */
/* vspuls_bline */
/* vspuls_eline */
.havon_begin = 0x180,
.havon_end = 0x5ff,
.vavon_bline = 0x23,
.vavon_eline = 0x382,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 0,
.hso_end = 0x80,
.vso_begin = 0x1e,
.vso_end = 0x32,
.vso_bline = 0,
.vso_eline = 3,
.vso_eline_present = true,
/* sy_val */
/* sy2_val */
.max_lncnt = 0x383,
},
};
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = {
.encp = {
.dvi_settings = 0x21,
.video_mode = 0x4040,
.video_mode_adv = 0x18,
/* video_prog_mode */
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
/* video_ofld_voav_ofst */
/* yfp1_htime */
/* yfp2_htime */
.max_pxcnt = 0x697,
/* hspuls_begin */
/* hspuls_end */
/* hspuls_switch */
/* vspuls_begin */
/* vspuls_end */
/* vspuls_bline */
/* vspuls_eline */
.havon_begin = 0x168,
.havon_end = 0x667,
.vavon_bline = 0x29,
.vavon_eline = 0x428,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 0,
.hso_end = 0x70,
.vso_begin = 0x1e,
.vso_end = 0x32,
.vso_bline = 0,
.vso_eline = 3,
.vso_eline_present = true,
/* sy_val */
/* sy2_val */
.max_lncnt = 0x429,
},
};
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = {
.encp = {
.dvi_settings = 0x21,
.video_mode = 0x4040,
.video_mode_adv = 0x18,
/* video_prog_mode */
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
/* video_ofld_voav_ofst */
/* yfp1_htime */
/* yfp2_htime */
.max_pxcnt = 0x86f,
/* hspuls_begin */
/* hspuls_end */
/* hspuls_switch */
/* vspuls_begin */
/* vspuls_end */
/* vspuls_bline */
/* vspuls_eline */
.havon_begin = 0x1f0,
.havon_end = 0x82f,
.vavon_bline = 0x31,
.vavon_eline = 0x4e0,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 0,
.hso_end = 0xc0,
.vso_begin = 0x1e,
.vso_end = 0x32,
.vso_bline = 0,
.vso_eline = 3,
.vso_eline_present = true,
/* sy_val */
/* sy2_val */
.max_lncnt = 0x4e1,
},
};
struct meson_hdmi_venc_dmt_mode {
struct drm_display_mode drm_mode;
union meson_hdmi_venc_mode *mode;
} meson_hdmi_venc_dmt_modes[] = {
/* 640x480@60Hz */
{
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
&meson_hdmi_encp_mode_640x480_60,
},
/* 800x600@60Hz */
{
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
968, 1056, 0, 600, 601, 605, 628, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
&meson_hdmi_encp_mode_800x600_60,
},
/* 1024x768@60Hz */
{
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024,
1048, 1184, 1344, 0, 768, 771, 777, 806, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
&meson_hdmi_encp_mode_1024x768_60,
},
/* 1152x864@75Hz */
{
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152,
1216, 1344, 1600, 0, 864, 865, 868, 900, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
&meson_hdmi_encp_mode_1152x864_75,
},
/* 1280x1024@60Hz */
{
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280,
1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
&meson_hdmi_encp_mode_1280x1024_60,
},
/* 1600x1200@60Hz */
{
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600,
1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
&meson_hdmi_encp_mode_1600x1200_60,
},
/* 1920x1080@60Hz */
{
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920,
2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
&meson_hdmi_encp_mode_1080p60
},
{ }, /* sentinel */
};
struct meson_hdmi_venc_vic_mode {
unsigned int vic;
union meson_hdmi_venc_mode *mode;
@ -736,6 +1044,20 @@ static unsigned long modulo(unsigned long a, unsigned long b)
return a;
}
bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
{
struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
while (vmode->mode) {
if (drm_mode_equal(&vmode->drm_mode, mode))
return true;
vmode++;
}
return false;
}
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode);
bool meson_venc_hdmi_supported_vic(int vic)
{
struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
@ -750,6 +1072,20 @@ bool meson_venc_hdmi_supported_vic(int vic)
}
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);
static union meson_hdmi_venc_mode
*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode)
{
struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
while (vmode->mode) {
if (drm_mode_equal(&vmode->drm_mode, mode))
return vmode->mode;
vmode++;
}
return NULL;
}
static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic)
{
struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
@ -811,10 +1147,13 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
unsigned int sof_lines;
unsigned int vsync_lines;
vmode = meson_venc_hdmi_get_vic_vmode(vic);
if (meson_venc_hdmi_supported_vic(vic))
vmode = meson_venc_hdmi_get_vic_vmode(vic);
else
vmode = meson_venc_hdmi_get_dmt_vmode(mode);
if (!vmode) {
dev_err(priv->dev, "%s: Fatal Error, unsupported vic %d\n",
__func__, vic);
dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode));
return;
}
@ -864,7 +1203,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
hsync_pixels_venc *= 2;
/* Disable VDACs */
writel_bits_relaxed(0x1f, 0x1f,
writel_bits_relaxed(0xff, 0xff,
priv->io_base + _REG(VENC_VDAC_SETTING));
writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));

View File

@ -58,6 +58,7 @@ struct meson_cvbs_enci_mode {
};
/* HDMI Clock parameters */
bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode);
bool meson_venc_hdmi_supported_vic(int vic);
bool meson_venc_hdmi_venc_repeat(int vic);

View File

@ -510,37 +510,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
return 0;
}
#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
static void
nouveau_get_hdmi_dev(struct nouveau_drm *drm)
{
struct pci_dev *pdev = drm->dev->pdev;
if (!pdev) {
NV_DEBUG(drm, "not a PCI device; no HDMI\n");
drm->hdmi_device = NULL;
return;
}
/* subfunction one is a hdmi audio device? */
drm->hdmi_device = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
(unsigned int)pdev->bus->number,
PCI_DEVFN(PCI_SLOT(pdev->devfn), 1));
if (!drm->hdmi_device) {
NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1);
return;
}
if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) {
NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class);
pci_dev_put(drm->hdmi_device);
drm->hdmi_device = NULL;
return;
}
}
static int
nouveau_drm_load(struct drm_device *dev, unsigned long flags)
{
@ -568,8 +537,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
INIT_LIST_HEAD(&drm->clients);
spin_lock_init(&drm->tile.lock);
nouveau_get_hdmi_dev(drm);
/* workaround an odd issue on nvc1 by disabling the device's
* nosnoop capability. hopefully won't cause issues until a
* better fix is found - assuming there is one...
@ -655,8 +622,6 @@ nouveau_drm_unload(struct drm_device *dev)
nouveau_ttm_fini(drm);
nouveau_vga_fini(drm);
if (drm->hdmi_device)
pci_dev_put(drm->hdmi_device);
nouveau_cli_fini(&drm->client);
nouveau_cli_fini(&drm->master);
kfree(drm);
@ -856,7 +821,6 @@ nouveau_pmops_runtime_suspend(struct device *dev)
}
drm_kms_helper_poll_disable(drm_dev);
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
nouveau_switcheroo_optimus_dsm();
ret = nouveau_do_suspend(drm_dev, true);
pci_save_state(pdev);
@ -891,7 +855,6 @@ nouveau_pmops_runtime_resume(struct device *dev)
/* do magic */
nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25));
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
/* Monitors may have been connected / disconnected during suspend */
@ -913,15 +876,6 @@ nouveau_pmops_runtime_idle(struct device *dev)
return -EBUSY;
}
/* if we have a hdmi audio device - make sure it has a driver loaded */
if (drm->hdmi_device) {
if (!drm->hdmi_device->driver) {
DRM_DEBUG_DRIVER("failing to power off - no HDMI audio driver loaded\n");
pm_runtime_mark_last_busy(dev);
return -EBUSY;
}
}
list_for_each_entry(crtc, &drm->dev->mode_config.crtc_list, head) {
if (crtc->enabled) {
DRM_DEBUG_DRIVER("failing to power off - crtc active\n");

View File

@ -208,7 +208,6 @@ struct nouveau_drm {
bool have_disp_power_ref;
struct dev_pm_domain vga_pm_domain;
struct pci_dev *hdmi_device;
};
static inline struct nouveau_drm *

View File

@ -108,6 +108,15 @@ config DRM_PANEL_RASPBERRYPI_TOUCHSCREEN
Pi 7" Touchscreen. To compile this driver as a module,
choose M here.
config DRM_PANEL_RAYDIUM_RM68200
tristate "Raydium RM68200 720x1280 DSI video mode panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to enable support for Raydium RM68200
720x1280 DSI video mode panel.
config DRM_PANEL_SAMSUNG_S6E3HA2
tristate "Samsung S6E3HA2 DSI video mode panel"
depends on OF

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_ORISETECH_OTM8009A) += panel-orisetech-otm8009a.o
obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o
obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.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_S6E63J0X03) += panel-samsung-s6e63j0x03.o

View File

@ -179,7 +179,7 @@ enum ili9322_input {
ILI9322_INPUT_UNKNOWN = 0xc,
};
const char *ili9322_inputs[] = {
static const char * const ili9322_inputs[] = {
"8 bit serial RGB through",
"8 bit serial RGB aligned",
"8 bit serial RGB dummy 320x240",
@ -340,7 +340,7 @@ static bool ili9322_writeable_reg(struct device *dev, unsigned int reg)
return true;
}
const struct regmap_config ili9322_regmap_config = {
static const struct regmap_config ili9322_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x44,

View File

@ -1,5 +1,5 @@
/*
* rcar_du_crtc.c -- R-Car Display Unit CRTCs
* Generic LVDS panel driver
*
* Copyright (C) 2016 Laurent Pinchart
* Copyright (C) 2016 Renesas Electronics Corporation

View File

@ -1,16 +1,17 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2017
*
* Authors: Philippe Cornu <philippe.cornu@st.com>
* Yannick Fertre <yannick.fertre@st.com>
*
* License terms: GNU General Public License (GPL), version 2
*/
#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>
#include <video/mipi_display.h>
#define DRV_NAME "orisetech_otm8009a"
@ -62,6 +63,7 @@ struct otm8009a {
struct drm_panel panel;
struct backlight_device *bl_dev;
struct gpio_desc *reset_gpio;
struct regulator *supply;
bool prepared;
bool enabled;
};
@ -279,6 +281,8 @@ static int otm8009a_unprepare(struct drm_panel *panel)
msleep(20);
}
regulator_disable(ctx->supply);
ctx->prepared = false;
return 0;
@ -292,6 +296,12 @@ static int otm8009a_prepare(struct drm_panel *panel)
if (ctx->prepared)
return 0;
ret = regulator_enable(ctx->supply);
if (ret < 0) {
DRM_ERROR("failed to enable supply: %d\n", ret);
return ret;
}
if (ctx->reset_gpio) {
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
@ -414,6 +424,13 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi)
return PTR_ERR(ctx->reset_gpio);
}
ctx->supply = devm_regulator_get(dev, "power");
if (IS_ERR(ctx->supply)) {
ret = PTR_ERR(ctx->supply);
dev_err(dev, "failed to request regulator: %d\n", ret);
return ret;
}
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dev = dev;

View File

@ -0,0 +1,448 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2017
*
* Authors: Philippe Cornu <philippe.cornu@st.com>
* Yannick Fertre <yannick.fertre@st.com>
*/
#include <linux/backlight.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drmP.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
/*** Manufacturer Command Set ***/
#define MCS_CMD_MODE_SW 0xFE /* CMD Mode Switch */
#define MCS_CMD1_UCS 0x00 /* User Command Set (UCS = CMD1) */
#define MCS_CMD2_P0 0x01 /* Manufacture Command Set Page0 (CMD2 P0) */
#define MCS_CMD2_P1 0x02 /* Manufacture Command Set Page1 (CMD2 P1) */
#define MCS_CMD2_P2 0x03 /* Manufacture Command Set Page2 (CMD2 P2) */
#define MCS_CMD2_P3 0x04 /* Manufacture Command Set Page3 (CMD2 P3) */
/* CMD2 P0 commands (Display Options and Power) */
#define MCS_STBCTR 0x12 /* TE1 Output Setting Zig-Zag Connection */
#define MCS_SGOPCTR 0x16 /* Source Bias Current */
#define MCS_SDCTR 0x1A /* Source Output Delay Time */
#define MCS_INVCTR 0x1B /* Inversion Type */
#define MCS_EXT_PWR_IC 0x24 /* External PWR IC Control */
#define MCS_SETAVDD 0x27 /* PFM Control for AVDD Output */
#define MCS_SETAVEE 0x29 /* PFM Control for AVEE Output */
#define MCS_BT2CTR 0x2B /* DDVDL Charge Pump Control */
#define MCS_BT3CTR 0x2F /* VGH Charge Pump Control */
#define MCS_BT4CTR 0x34 /* VGL Charge Pump Control */
#define MCS_VCMCTR 0x46 /* VCOM Output Level Control */
#define MCS_SETVGN 0x52 /* VG M/S N Control */
#define MCS_SETVGP 0x54 /* VG M/S P Control */
#define MCS_SW_CTRL 0x5F /* Interface Control for PFM and MIPI */
/* CMD2 P2 commands (GOA Timing Control) - no description in datasheet */
#define GOA_VSTV1 0x00
#define GOA_VSTV2 0x07
#define GOA_VCLK1 0x0E
#define GOA_VCLK2 0x17
#define GOA_VCLK_OPT1 0x20
#define GOA_BICLK1 0x2A
#define GOA_BICLK2 0x37
#define GOA_BICLK3 0x44
#define GOA_BICLK4 0x4F
#define GOA_BICLK_OPT1 0x5B
#define GOA_BICLK_OPT2 0x60
#define MCS_GOA_GPO1 0x6D
#define MCS_GOA_GPO2 0x71
#define MCS_GOA_EQ 0x74
#define MCS_GOA_CLK_GALLON 0x7C
#define MCS_GOA_FS_SEL0 0x7E
#define MCS_GOA_FS_SEL1 0x87
#define MCS_GOA_FS_SEL2 0x91
#define MCS_GOA_FS_SEL3 0x9B
#define MCS_GOA_BS_SEL0 0xAC
#define MCS_GOA_BS_SEL1 0xB5
#define MCS_GOA_BS_SEL2 0xBF
#define MCS_GOA_BS_SEL3 0xC9
#define MCS_GOA_BS_SEL4 0xD3
/* CMD2 P3 commands (Gamma) */
#define MCS_GAMMA_VP 0x60 /* Gamma VP1~VP16 */
#define MCS_GAMMA_VN 0x70 /* Gamma VN1~VN16 */
struct rm68200 {
struct device *dev;
struct drm_panel panel;
struct gpio_desc *reset_gpio;
struct regulator *supply;
struct backlight_device *backlight;
bool prepared;
bool enabled;
};
static const struct drm_display_mode default_mode = {
.clock = 52582,
.hdisplay = 720,
.hsync_start = 720 + 38,
.hsync_end = 720 + 38 + 8,
.htotal = 720 + 38 + 8 + 38,
.vdisplay = 1280,
.vsync_start = 1280 + 12,
.vsync_end = 1280 + 12 + 4,
.vtotal = 1280 + 12 + 4 + 12,
.vrefresh = 50,
.flags = 0,
.width_mm = 68,
.height_mm = 122,
};
static inline struct rm68200 *panel_to_rm68200(struct drm_panel *panel)
{
return container_of(panel, struct rm68200, panel);
}
static void rm68200_dcs_write_buf(struct rm68200 *ctx, const void *data,
size_t len)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int err;
err = mipi_dsi_dcs_write_buffer(dsi, data, len);
if (err < 0)
DRM_ERROR_RATELIMITED("MIPI DSI DCS write buffer failed: %d\n",
err);
}
static void rm68200_dcs_write_cmd(struct rm68200 *ctx, u8 cmd, u8 value)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int err;
err = mipi_dsi_dcs_write(dsi, cmd, &value, 1);
if (err < 0)
DRM_ERROR_RATELIMITED("MIPI DSI DCS write failed: %d\n", err);
}
#define dcs_write_seq(ctx, seq...) \
({ \
static const u8 d[] = { seq }; \
\
rm68200_dcs_write_buf(ctx, d, ARRAY_SIZE(d)); \
})
/*
* This panel is not able to auto-increment all cmd addresses so for some of
* them, we need to send them one by one...
*/
#define dcs_write_cmd_seq(ctx, cmd, seq...) \
({ \
static const u8 d[] = { seq }; \
unsigned int i; \
\
for (i = 0; i < ARRAY_SIZE(d) ; i++) \
rm68200_dcs_write_cmd(ctx, cmd + i, d[i]); \
})
static void rm68200_init_sequence(struct rm68200 *ctx)
{
/* Enter CMD2 with page 0 */
dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P0);
dcs_write_cmd_seq(ctx, MCS_EXT_PWR_IC, 0xC0, 0x53, 0x00);
dcs_write_seq(ctx, MCS_BT2CTR, 0xE5);
dcs_write_seq(ctx, MCS_SETAVDD, 0x0A);
dcs_write_seq(ctx, MCS_SETAVEE, 0x0A);
dcs_write_seq(ctx, MCS_SGOPCTR, 0x52);
dcs_write_seq(ctx, MCS_BT3CTR, 0x53);
dcs_write_seq(ctx, MCS_BT4CTR, 0x5A);
dcs_write_seq(ctx, MCS_INVCTR, 0x00);
dcs_write_seq(ctx, MCS_STBCTR, 0x0A);
dcs_write_seq(ctx, MCS_SDCTR, 0x06);
dcs_write_seq(ctx, MCS_VCMCTR, 0x56);
dcs_write_seq(ctx, MCS_SETVGN, 0xA0, 0x00);
dcs_write_seq(ctx, MCS_SETVGP, 0xA0, 0x00);
dcs_write_seq(ctx, MCS_SW_CTRL, 0x11); /* 2 data lanes, see doc */
dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P2);
dcs_write_seq(ctx, GOA_VSTV1, 0x05);
dcs_write_seq(ctx, 0x02, 0x0B);
dcs_write_seq(ctx, 0x03, 0x0F);
dcs_write_seq(ctx, 0x04, 0x7D, 0x00, 0x50);
dcs_write_cmd_seq(ctx, GOA_VSTV2, 0x05, 0x16, 0x0D, 0x11, 0x7D, 0x00,
0x50);
dcs_write_cmd_seq(ctx, GOA_VCLK1, 0x07, 0x08, 0x01, 0x02, 0x00, 0x7D,
0x00, 0x85, 0x08);
dcs_write_cmd_seq(ctx, GOA_VCLK2, 0x03, 0x04, 0x05, 0x06, 0x00, 0x7D,
0x00, 0x85, 0x08);
dcs_write_seq(ctx, GOA_VCLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00);
dcs_write_cmd_seq(ctx, GOA_BICLK1, 0x07, 0x08);
dcs_write_seq(ctx, 0x2D, 0x01);
dcs_write_seq(ctx, 0x2F, 0x02, 0x00, 0x40, 0x05, 0x08, 0x54, 0x7D,
0x00);
dcs_write_cmd_seq(ctx, GOA_BICLK2, 0x03, 0x04, 0x05, 0x06, 0x00);
dcs_write_seq(ctx, 0x3D, 0x40);
dcs_write_seq(ctx, 0x3F, 0x05, 0x08, 0x54, 0x7D, 0x00);
dcs_write_seq(ctx, GOA_BICLK3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00);
dcs_write_seq(ctx, GOA_BICLK4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00);
dcs_write_seq(ctx, 0x58, 0x00, 0x00, 0x00);
dcs_write_seq(ctx, GOA_BICLK_OPT1, 0x00, 0x00, 0x00, 0x00, 0x00);
dcs_write_seq(ctx, GOA_BICLK_OPT2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
dcs_write_seq(ctx, MCS_GOA_GPO1, 0x00, 0x00, 0x00, 0x00);
dcs_write_seq(ctx, MCS_GOA_GPO2, 0x00, 0x20, 0x00);
dcs_write_seq(ctx, MCS_GOA_EQ, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00);
dcs_write_seq(ctx, MCS_GOA_CLK_GALLON, 0x00, 0x00);
dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL0, 0xBF, 0x02, 0x06, 0x14, 0x10,
0x16, 0x12, 0x08, 0x3F);
dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0C,
0x0A, 0x0E, 0x3F, 0x3F, 0x00);
dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL2, 0x04, 0x3F, 0x3F, 0x3F, 0x3F,
0x05, 0x01, 0x3F, 0x3F, 0x0F);
dcs_write_cmd_seq(ctx, MCS_GOA_FS_SEL3, 0x0B, 0x0D, 0x3F, 0x3F, 0x3F,
0x3F);
dcs_write_cmd_seq(ctx, 0xA2, 0x3F, 0x09, 0x13, 0x17, 0x11, 0x15);
dcs_write_cmd_seq(ctx, 0xA9, 0x07, 0x03, 0x3F);
dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL0, 0x3F, 0x05, 0x01, 0x17, 0x13,
0x15, 0x11, 0x0F, 0x3F);
dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL1, 0x3F, 0x3F, 0x3F, 0x3F, 0x0B,
0x0D, 0x09, 0x3F, 0x3F, 0x07);
dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL2, 0x03, 0x3F, 0x3F, 0x3F, 0x3F,
0x02, 0x06, 0x3F, 0x3F, 0x08);
dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL3, 0x0C, 0x0A, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x0E, 0x10, 0x14);
dcs_write_cmd_seq(ctx, MCS_GOA_BS_SEL4, 0x12, 0x16, 0x00, 0x04, 0x3F);
dcs_write_seq(ctx, 0xDC, 0x02);
dcs_write_seq(ctx, 0xDE, 0x12);
dcs_write_seq(ctx, MCS_CMD_MODE_SW, 0x0E); /* No documentation */
dcs_write_seq(ctx, 0x01, 0x75);
dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD2_P3);
dcs_write_cmd_seq(ctx, MCS_GAMMA_VP, 0x00, 0x0C, 0x12, 0x0E, 0x06,
0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F,
0x12, 0x0C, 0x00);
dcs_write_cmd_seq(ctx, MCS_GAMMA_VN, 0x00, 0x0C, 0x12, 0x0E, 0x06,
0x12, 0x0E, 0x0B, 0x15, 0x0B, 0x10, 0x07, 0x0F,
0x12, 0x0C, 0x00);
/* Exit CMD2 */
dcs_write_seq(ctx, MCS_CMD_MODE_SW, MCS_CMD1_UCS);
}
static int rm68200_disable(struct drm_panel *panel)
{
struct rm68200 *ctx = panel_to_rm68200(panel);
if (!ctx->enabled)
return 0;
backlight_disable(ctx->backlight);
ctx->enabled = false;
return 0;
}
static int rm68200_unprepare(struct drm_panel *panel)
{
struct rm68200 *ctx = panel_to_rm68200(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
if (!ctx->prepared)
return 0;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret)
DRM_WARN("failed to set display off: %d\n", ret);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret)
DRM_WARN("failed to enter sleep mode: %d\n", ret);
msleep(120);
if (ctx->reset_gpio) {
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
msleep(20);
}
regulator_disable(ctx->supply);
ctx->prepared = false;
return 0;
}
static int rm68200_prepare(struct drm_panel *panel)
{
struct rm68200 *ctx = panel_to_rm68200(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
if (ctx->prepared)
return 0;
ret = regulator_enable(ctx->supply);
if (ret < 0) {
DRM_ERROR("failed to enable supply: %d\n", ret);
return ret;
}
if (ctx->reset_gpio) {
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
msleep(20);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
msleep(100);
}
rm68200_init_sequence(ctx);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret)
return ret;
msleep(125);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret)
return ret;
msleep(20);
ctx->prepared = true;
return 0;
}
static int rm68200_enable(struct drm_panel *panel)
{
struct rm68200 *ctx = panel_to_rm68200(panel);
if (ctx->enabled)
return 0;
backlight_enable(ctx->backlight);
ctx->enabled = true;
return 0;
}
static int rm68200_get_modes(struct drm_panel *panel)
{
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(panel->connector, mode);
panel->connector->display_info.width_mm = mode->width_mm;
panel->connector->display_info.height_mm = mode->height_mm;
return 1;
}
static const struct drm_panel_funcs rm68200_drm_funcs = {
.disable = rm68200_disable,
.unprepare = rm68200_unprepare,
.prepare = rm68200_prepare,
.enable = rm68200_enable,
.get_modes = rm68200_get_modes,
};
static int rm68200_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct rm68200 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
ret = PTR_ERR(ctx->reset_gpio);
dev_err(dev, "cannot get reset GPIO: %d\n", ret);
return ret;
}
ctx->supply = devm_regulator_get(dev, "power");
if (IS_ERR(ctx->supply)) {
ret = PTR_ERR(ctx->supply);
dev_err(dev, "cannot get regulator: %d\n", ret);
return ret;
}
ctx->backlight = devm_of_find_backlight(dev);
if (IS_ERR(ctx->backlight))
return PTR_ERR(ctx->backlight);
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dev = dev;
dsi->lanes = 2;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM;
drm_panel_init(&ctx->panel);
ctx->panel.dev = dev;
ctx->panel.funcs = &rm68200_drm_funcs;
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
return 0;
}
static int rm68200_remove(struct mipi_dsi_device *dsi)
{
struct rm68200 *ctx = mipi_dsi_get_drvdata(dsi);
mipi_dsi_detach(dsi);
drm_panel_remove(&ctx->panel);
return 0;
}
static const struct of_device_id raydium_rm68200_of_match[] = {
{ .compatible = "raydium,rm68200" },
{ }
};
MODULE_DEVICE_TABLE(of, raydium_rm68200_of_match);
static struct mipi_dsi_driver raydium_rm68200_driver = {
.probe = rm68200_probe,
.remove = rm68200_remove,
.driver = {
.name = "panel-raydium-rm68200",
.of_match_table = raydium_rm68200_of_match,
},
};
module_mipi_dsi_driver(raydium_rm68200_driver);
MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
MODULE_DESCRIPTION("DRM Driver for Raydium RM68200 MIPI DSI panel");
MODULE_LICENSE("GPL v2");

View File

@ -581,6 +581,29 @@ static const struct panel_desc auo_b133htn01 = {
},
};
static const struct drm_display_mode auo_g104sn02_mode = {
.clock = 40000,
.hdisplay = 800,
.hsync_start = 800 + 40,
.hsync_end = 800 + 40 + 216,
.htotal = 800 + 40 + 216 + 128,
.vdisplay = 600,
.vsync_start = 600 + 10,
.vsync_end = 600 + 10 + 35,
.vtotal = 600 + 10 + 35 + 2,
.vrefresh = 60,
};
static const struct panel_desc auo_g104sn02 = {
.modes = &auo_g104sn02_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 211,
.height = 158,
},
};
static const struct display_timing auo_g133han01_timings = {
.pixelclock = { 134000000, 141200000, 149000000 },
.hactive = { 1920, 1920, 1920 },
@ -1217,6 +1240,30 @@ static const struct panel_desc innolux_zj070na_01p = {
},
};
static const struct display_timing koe_tx31d200vm0baa_timing = {
.pixelclock = { 39600000, 43200000, 48000000 },
.hactive = { 1280, 1280, 1280 },
.hfront_porch = { 16, 36, 56 },
.hback_porch = { 16, 36, 56 },
.hsync_len = { 8, 8, 8 },
.vactive = { 480, 480, 480 },
.vfront_porch = { 6, 21, 33.5 },
.vback_porch = { 6, 21, 33.5 },
.vsync_len = { 8, 8, 8 },
.flags = DISPLAY_FLAGS_DE_HIGH,
};
static const struct panel_desc koe_tx31d200vm0baa = {
.timings = &koe_tx31d200vm0baa_timing,
.num_timings = 1,
.bpc = 6,
.size = {
.width = 292,
.height = 109,
},
.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
};
static const struct display_timing kyo_tcg121xglp_timing = {
.pixelclock = { 52000000, 65000000, 71000000 },
.hactive = { 1024, 1024, 1024 },
@ -1597,7 +1644,7 @@ static const struct panel_desc ontat_yx700wv03 = {
.width = 154,
.height = 83,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
};
static const struct drm_display_mode ortustech_com43h4m85ulc_mode = {
@ -1741,23 +1788,22 @@ static const struct panel_desc sharp_lq101k1ly04 = {
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
};
static const struct drm_display_mode sharp_lq123p1jx31_mode = {
.clock = 252750,
.hdisplay = 2400,
.hsync_start = 2400 + 48,
.hsync_end = 2400 + 48 + 32,
.htotal = 2400 + 48 + 32 + 80,
.vdisplay = 1600,
.vsync_start = 1600 + 3,
.vsync_end = 1600 + 3 + 10,
.vtotal = 1600 + 3 + 10 + 33,
.vrefresh = 60,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
static const struct display_timing sharp_lq123p1jx31_timing = {
.pixelclock = { 252750000, 252750000, 266604720 },
.hactive = { 2400, 2400, 2400 },
.hfront_porch = { 48, 48, 48 },
.hback_porch = { 80, 80, 84 },
.hsync_len = { 32, 32, 32 },
.vactive = { 1600, 1600, 1600 },
.vfront_porch = { 3, 3, 3 },
.vback_porch = { 33, 33, 120 },
.vsync_len = { 10, 10, 10 },
.flags = DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_HSYNC_LOW,
};
static const struct panel_desc sharp_lq123p1jx31 = {
.modes = &sharp_lq123p1jx31_mode,
.num_modes = 1,
.timings = &sharp_lq123p1jx31_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 259,
@ -2048,6 +2094,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "auo,b133xtn01",
.data = &auo_b133xtn01,
}, {
.compatible = "auo,g104sn02",
.data = &auo_g104sn02,
}, {
.compatible = "auo,g133han01",
.data = &auo_g133han01,
@ -2123,6 +2172,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "innolux,zj070na-01p",
.data = &innolux_zj070na_01p,
}, {
.compatible = "koe,tx31d200vm0baa",
.data = &koe_tx31d200vm0baa,
}, {
.compatible = "kyo,tcg121xglp",
.data = &kyo_tcg121xglp,

View File

@ -309,7 +309,7 @@ void qxl_user_framebuffer_destroy(struct drm_framebuffer *fb)
struct qxl_bo *bo = gem_to_qxl_bo(qxl_fb->obj);
WARN_ON(bo->shadow);
drm_gem_object_unreference_unlocked(qxl_fb->obj);
drm_gem_object_put_unlocked(qxl_fb->obj);
drm_framebuffer_cleanup(fb);
kfree(qxl_fb);
}
@ -1215,7 +1215,7 @@ qxl_user_framebuffer_create(struct drm_device *dev,
ret = qxl_framebuffer_init(dev, qxl_fb, mode_cmd, obj, &qxl_fb_funcs);
if (ret) {
kfree(qxl_fb);
drm_gem_object_unreference_unlocked(obj);
drm_gem_object_put_unlocked(obj);
return NULL;
}

View File

@ -82,6 +82,6 @@ int qxl_mode_dumb_mmap(struct drm_file *file_priv,
return -ENOENT;
qobj = gem_to_qxl_bo(gobj);
*offset_p = qxl_bo_mmap_offset(qobj);
drm_gem_object_unreference_unlocked(gobj);
drm_gem_object_put_unlocked(gobj);
return 0;
}

View File

@ -95,7 +95,7 @@ static void qxlfb_destroy_pinned_object(struct drm_gem_object *gobj)
qxl_bo_kunmap(qbo);
qxl_bo_unpin(qbo);
drm_gem_object_unreference_unlocked(gobj);
drm_gem_object_put_unlocked(gobj);
}
int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
@ -316,11 +316,11 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev,
qxl_bo_unpin(qbo);
}
if (fb && ret) {
drm_gem_object_unreference_unlocked(gobj);
drm_gem_object_put_unlocked(gobj);
drm_framebuffer_cleanup(fb);
kfree(fb);
}
drm_gem_object_unreference_unlocked(gobj);
drm_gem_object_put_unlocked(gobj);
return ret;
}

View File

@ -98,7 +98,7 @@ int qxl_gem_object_create_with_handle(struct qxl_device *qdev,
return r;
/* drop reference from allocate - handle holds it now */
*qobj = gem_to_qxl_bo(gobj);
drm_gem_object_unreference_unlocked(gobj);
drm_gem_object_put_unlocked(gobj);
return 0;
}

View File

@ -121,7 +121,7 @@ static int qxlhw_handle_to_bo(struct drm_file *file_priv, uint64_t handle,
qobj = gem_to_qxl_bo(gobj);
ret = qxl_release_list_add(release, qobj);
drm_gem_object_unreference_unlocked(gobj);
drm_gem_object_put_unlocked(gobj);
if (ret)
return ret;
@ -343,7 +343,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
qxl_bo_unreserve(qobj);
out:
drm_gem_object_unreference_unlocked(gobj);
drm_gem_object_put_unlocked(gobj);
return ret;
}

View File

@ -211,13 +211,13 @@ void qxl_bo_unref(struct qxl_bo **bo)
if ((*bo) == NULL)
return;
drm_gem_object_unreference_unlocked(&(*bo)->gem_base);
drm_gem_object_put_unlocked(&(*bo)->gem_base);
*bo = NULL;
}
struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)
{
drm_gem_object_reference(&bo->gem_base);
drm_gem_object_get(&bo->gem_base);
return bo;
}
@ -318,7 +318,7 @@ void qxl_bo_force_delete(struct qxl_device *qdev)
list_del_init(&bo->list);
mutex_unlock(&qdev->gem.mutex);
/* this should unref the ttm bo */
drm_gem_object_unreference_unlocked(&bo->gem_base);
drm_gem_object_put_unlocked(&bo->gem_base);
}
}

View File

@ -415,7 +415,6 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
drm_kms_helper_poll_disable(drm_dev);
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
ret = radeon_suspend_kms(drm_dev, false, false, false);
pci_save_state(pdev);
@ -452,7 +451,6 @@ static int radeon_pmops_runtime_resume(struct device *dev)
ret = radeon_resume_kms(drm_dev, false, false);
drm_kms_helper_poll_enable(drm_dev);
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
return 0;
}

View File

@ -71,10 +71,6 @@ struct rockchip_dp_device {
struct regmap *grf;
struct reset_control *rst;
struct work_struct psr_work;
struct mutex psr_lock;
unsigned int psr_state;
const struct rockchip_dp_chip_data *data;
struct analogix_dp_device *adp;
@ -84,28 +80,13 @@ struct rockchip_dp_device {
static void analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
{
struct rockchip_dp_device *dp = to_dp(encoder);
int ret;
if (!analogix_dp_psr_supported(dp->adp))
if (!analogix_dp_psr_enabled(dp->adp))
return;
DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
mutex_lock(&dp->psr_lock);
if (enabled)
dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
else
dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
schedule_work(&dp->psr_work);
mutex_unlock(&dp->psr_lock);
}
static void analogix_dp_psr_work(struct work_struct *work)
{
struct rockchip_dp_device *dp =
container_of(work, typeof(*dp), psr_work);
int ret;
ret = rockchip_drm_wait_vact_end(dp->encoder.crtc,
PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
if (ret) {
@ -113,12 +94,10 @@ static void analogix_dp_psr_work(struct work_struct *work)
return;
}
mutex_lock(&dp->psr_lock);
if (dp->psr_state == EDP_VSC_PSR_STATE_ACTIVE)
if (enabled)
analogix_dp_enable_psr(dp->adp);
else
analogix_dp_disable_psr(dp->adp);
mutex_unlock(&dp->psr_lock);
}
static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
@ -135,8 +114,6 @@ static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
struct rockchip_dp_device *dp = to_dp(plat_data);
int ret;
cancel_work_sync(&dp->psr_work);
ret = clk_prepare_enable(dp->pclk);
if (ret < 0) {
DRM_DEV_ERROR(dp->dev, "failed to enable pclk %d\n", ret);
@ -355,10 +332,6 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
mutex_init(&dp->psr_lock);
dp->psr_state = ~EDP_VSC_PSR_STATE_ACTIVE;
INIT_WORK(&dp->psr_work, analogix_dp_psr_work);
ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
if (ret < 0)
goto err_cleanup_encoder;

View File

@ -43,8 +43,6 @@
#define GRF_SOC_CON9 0x6224
#define DP_SEL_VOP_LIT BIT(12)
#define GRF_SOC_CON26 0x6268
#define UPHY_SEL_BIT 3
#define UPHY_SEL_MASK BIT(19)
#define DPTX_HPD_SEL (3 << 12)
#define DPTX_HPD_DEL (2 << 12)
#define DPTX_HPD_SEL_MASK (3 << 28)
@ -394,11 +392,6 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
union extcon_property_value property;
int ret;
ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
(port->id << UPHY_SEL_BIT) | UPHY_SEL_MASK);
if (ret)
return ret;
if (!port->phy_enabled) {
ret = phy_power_on(port->phy);
if (ret) {

View File

@ -117,6 +117,8 @@ struct vop {
spinlock_t reg_lock;
/* lock vop irq reg */
spinlock_t irq_lock;
/* protects crtc enable/disable */
struct mutex vop_lock;
unsigned int irq;
@ -517,7 +519,10 @@ static int vop_enable(struct drm_crtc *crtc)
goto err_disable_aclk;
}
memcpy(vop->regs, vop->regsbak, vop->len);
spin_lock(&vop->reg_lock);
for (i = 0; i < vop->len; i += 4)
writel_relaxed(vop->regsbak[i / 4], vop->regs + i);
/*
* We need to make sure that all windows are disabled before we
* enable the crtc. Otherwise we might try to scan from a destroyed
@ -527,10 +532,9 @@ static int vop_enable(struct drm_crtc *crtc)
struct vop_win *vop_win = &vop->win[i];
const struct vop_win_data *win = vop_win->data;
spin_lock(&vop->reg_lock);
VOP_WIN_SET(vop, win, enable, 0);
spin_unlock(&vop->reg_lock);
}
spin_unlock(&vop->reg_lock);
vop_cfg_done(vop);
@ -569,6 +573,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
WARN_ON(vop->event);
mutex_lock(&vop->vop_lock);
drm_crtc_vblank_off(crtc);
/*
@ -604,6 +609,7 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
clk_disable(vop->aclk);
clk_disable(vop->hclk);
pm_runtime_put(vop->dev);
mutex_unlock(&vop->vop_lock);
if (crtc->state->event && !crtc->state->active) {
spin_lock_irq(&crtc->dev->event_lock);
@ -868,10 +874,13 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
uint32_t pin_pol, val;
int ret;
mutex_lock(&vop->vop_lock);
WARN_ON(vop->event);
ret = vop_enable(crtc);
if (ret) {
mutex_unlock(&vop->vop_lock);
DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret);
return;
}
@ -935,6 +944,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
clk_set_rate(vop->dclk, adjusted_mode->clock * 1000);
VOP_REG_SET(vop, common, standby, 0);
mutex_unlock(&vop->vop_lock);
}
static bool vop_fs_irq_is_pending(struct vop *vop)
@ -1137,15 +1147,14 @@ static void vop_handle_vblank(struct vop *vop)
{
struct drm_device *drm = vop->drm_dev;
struct drm_crtc *crtc = &vop->crtc;
unsigned long flags;
spin_lock_irqsave(&drm->event_lock, flags);
spin_lock(&drm->event_lock);
if (vop->event) {
drm_crtc_send_vblank_event(crtc, vop->event);
drm_crtc_vblank_put(crtc);
vop->event = NULL;
}
spin_unlock_irqrestore(&drm->event_lock, flags);
spin_unlock(&drm->event_lock);
if (test_and_clear_bit(VOP_PENDING_FB_UNREF, &vop->pending))
drm_flip_work_commit(&vop->fb_unref_work, system_unbound_wq);
@ -1156,21 +1165,20 @@ static irqreturn_t vop_isr(int irq, void *data)
struct vop *vop = data;
struct drm_crtc *crtc = &vop->crtc;
uint32_t active_irqs;
unsigned long flags;
int ret = IRQ_NONE;
/*
* interrupt register has interrupt status, enable and clear bits, we
* must hold irq_lock to avoid a race with enable/disable_vblank().
*/
spin_lock_irqsave(&vop->irq_lock, flags);
spin_lock(&vop->irq_lock);
active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK);
/* Clear all active interrupt sources */
if (active_irqs)
VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1);
spin_unlock_irqrestore(&vop->irq_lock, flags);
spin_unlock(&vop->irq_lock);
/* This is expected for vop iommu irqs, since the irq is shared */
if (!active_irqs)
@ -1393,7 +1401,11 @@ static int vop_initial(struct vop *vop)
usleep_range(10, 20);
reset_control_deassert(ahb_rst);
memcpy(vop->regsbak, vop->regs, vop->len);
VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1);
VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0);
for (i = 0; i < vop->len; i += sizeof(u32))
vop->regsbak[i / 4] = readl_relaxed(vop->regs + i);
VOP_REG_SET(vop, misc, global_regdone_en, 1);
VOP_REG_SET(vop, common, dsp_blank, 0);
@ -1473,15 +1485,21 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
{
struct vop *vop = to_vop(crtc);
unsigned long jiffies_left;
int ret = 0;
if (!crtc || !vop->is_enabled)
return -ENODEV;
if (mstimeout <= 0)
return -EINVAL;
mutex_lock(&vop->vop_lock);
if (mstimeout <= 0) {
ret = -EINVAL;
goto out;
}
if (vop_line_flag_irq_is_enabled(vop))
return -EBUSY;
if (vop_line_flag_irq_is_enabled(vop)) {
ret = -EBUSY;
goto out;
}
reinit_completion(&vop->line_flag_completion);
vop_line_flag_irq_enable(vop);
@ -1492,10 +1510,13 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
if (jiffies_left == 0) {
DRM_DEV_ERROR(vop->dev, "Timeout waiting for IRQ\n");
return -ETIMEDOUT;
ret = -ETIMEDOUT;
goto out;
}
return 0;
out:
mutex_unlock(&vop->vop_lock);
return ret;
}
EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
@ -1545,18 +1566,11 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
spin_lock_init(&vop->reg_lock);
spin_lock_init(&vop->irq_lock);
ret = devm_request_irq(dev, vop->irq, vop_isr,
IRQF_SHARED, dev_name(dev), vop);
if (ret)
return ret;
/* IRQ is initially disabled; it gets enabled in power_on */
disable_irq(vop->irq);
mutex_init(&vop->vop_lock);
ret = vop_create_crtc(vop);
if (ret)
goto err_enable_irq;
return ret;
pm_runtime_enable(&pdev->dev);
@ -1567,13 +1581,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
goto err_disable_pm_runtime;
}
ret = devm_request_irq(dev, vop->irq, vop_isr,
IRQF_SHARED, dev_name(dev), vop);
if (ret)
goto err_disable_pm_runtime;
/* IRQ is initially disabled; it gets enabled in power_on */
disable_irq(vop->irq);
return 0;
err_disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
vop_destroy_crtc(vop);
err_enable_irq:
enable_irq(vop->irq); /* To balance out the disable_irq above */
return ret;
}

View File

@ -42,6 +42,56 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
};
/*
* These coefficients are taken from the A33 BSP from Allwinner.
*
* The formula is for each component, each coefficient being multiplied by
* 1024 and each constant being multiplied by 16:
* G = 1.164 * Y - 0.391 * U - 0.813 * V + 135
* R = 1.164 * Y + 1.596 * V - 222
* B = 1.164 * Y + 2.018 * U + 276
*
* This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255],
* following the BT601 spec.
*/
static const u32 sunxi_bt601_yuv2rgb_coef[12] = {
0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877,
0x000004a7, 0x00000000, 0x00000662, 0x00003211,
0x000004a7, 0x00000812, 0x00000000, 0x00002eb1,
};
static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format)
{
switch (format) {
case DRM_FORMAT_YUV411:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YUV444:
return true;
default:
return false;
}
}
static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format)
{
switch (format) {
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
return true;
default:
return false;
}
}
static inline bool sun4i_backend_format_is_yuv(uint32_t format)
{
return sun4i_backend_format_is_planar_yuv(format) ||
sun4i_backend_format_is_packed_yuv422(format);
}
static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine)
{
int i;
@ -166,6 +216,61 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
return 0;
}
static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
int layer, struct drm_plane *plane)
{
struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb;
uint32_t format = fb->format->format;
u32 val = SUN4I_BACKEND_IYUVCTL_EN;
int i;
for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
regmap_write(backend->engine.regs,
SUN4I_BACKEND_YGCOEF_REG(i),
sunxi_bt601_yuv2rgb_coef[i]);
/*
* We should do that only for a single plane, but the
* framebuffer's atomic_check has our back on this.
*/
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN,
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN);
/* TODO: Add support for the multi-planar YUV formats */
if (sun4i_backend_format_is_packed_yuv422(format))
val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422;
else
DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format);
/*
* Allwinner seems to list the pixel sequence from right to left, while
* DRM lists it from left to right.
*/
switch (format) {
case DRM_FORMAT_YUYV:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY;
break;
case DRM_FORMAT_YVYU:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY;
break;
case DRM_FORMAT_UYVY:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU;
break;
case DRM_FORMAT_VYUY:
val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV;
break;
default:
DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n",
format);
}
regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val);
return 0;
}
int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
int layer, struct drm_plane *plane)
{
@ -175,6 +280,10 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
u32 val;
int ret;
/* Clear the YUV mode */
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0);
if (plane->state->crtc)
interlaced = plane->state->crtc->state->adjusted_mode.flags
& DRM_MODE_FLAG_INTERLACE;
@ -186,6 +295,9 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
interlaced ? "on" : "off");
if (sun4i_backend_format_is_yuv(fb->format->format))
return sun4i_backend_update_yuv_format(backend, layer, plane);
ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val);
if (ret) {
DRM_DEBUG_DRIVER("Invalid format\n");
@ -223,6 +335,21 @@ int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
return 0;
}
static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend,
struct drm_framebuffer *fb,
dma_addr_t paddr)
{
/* TODO: Add support for the multi-planar YUV formats */
DRM_DEBUG_DRIVER("Setting packed YUV buffer address to %pad\n", &paddr);
regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr);
DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0),
fb->pitches[0] * 8);
return 0;
}
int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
int layer, struct drm_plane *plane)
{
@ -248,6 +375,9 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
*/
paddr -= PHYS_OFFSET;
if (sun4i_backend_format_is_yuv(fb->format->format))
return sun4i_backend_update_yuv_buffer(backend, fb, paddr);
/* Write the 32 lower bits of the address (in bits) */
lo_paddr = paddr << 3;
DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
@ -330,6 +460,7 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
unsigned int num_planes = 0;
unsigned int num_alpha_planes = 0;
unsigned int num_frontend_planes = 0;
unsigned int num_yuv_planes = 0;
unsigned int current_pipe = 0;
unsigned int i;
@ -362,6 +493,11 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
if (fb->format->has_alpha)
num_alpha_planes++;
if (sun4i_backend_format_is_yuv(fb->format->format)) {
DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
num_yuv_planes++;
}
DRM_DEBUG_DRIVER("Plane zpos is %d\n",
plane_state->normalized_zpos);
@ -430,13 +566,20 @@ static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
s_state->pipe = current_pipe;
}
/* We can only have a single YUV plane at a time */
if (num_yuv_planes > SUN4I_BACKEND_NUM_YUV_PLANES) {
DRM_DEBUG_DRIVER("Too many planes with YUV, rejecting...\n");
return -EINVAL;
}
if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
return -EINVAL;
}
DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video\n",
num_planes, num_alpha_planes, num_frontend_planes);
DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video, %u YUV\n",
num_planes, num_alpha_planes, num_frontend_planes,
num_yuv_planes);
return 0;
}
@ -793,6 +936,9 @@ static const struct sun4i_backend_quirks sun7i_backend_quirks = {
static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
};
static const struct sun4i_backend_quirks sun9i_backend_quirks = {
};
static const struct of_device_id sun4i_backend_of_table[] = {
{
.compatible = "allwinner,sun4i-a10-display-backend",
@ -814,6 +960,10 @@ static const struct of_device_id sun4i_backend_of_table[] = {
.compatible = "allwinner,sun8i-a33-display-backend",
.data = &sun8i_a33_backend_quirks,
},
{
.compatible = "allwinner,sun9i-a80-display-backend",
.data = &sun9i_backend_quirks,
},
{ }
};
MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);

View File

@ -72,6 +72,7 @@
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x) ((x) << 15)
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK GENMASK(11, 10)
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x) ((x) << 10)
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN BIT(2)
#define SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN BIT(1)
#define SUN4I_BACKEND_ATTCTL_REG1(l) (0x8a0 + (0x4 * (l)))
@ -110,7 +111,23 @@
#define SUN4I_BACKEND_SPREN_REG 0x900
#define SUN4I_BACKEND_SPRFMTCTL_REG 0x908
#define SUN4I_BACKEND_SPRALPHACTL_REG 0x90c
#define SUN4I_BACKEND_IYUVCTL_REG 0x920
#define SUN4I_BACKEND_IYUVCTL_FBFMT_MASK GENMASK(14, 12)
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV444 (4 << 12)
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422 (3 << 12)
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV444 (2 << 12)
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV222 (1 << 12)
#define SUN4I_BACKEND_IYUVCTL_FBFMT_PLANAR_YUV111 (0 << 12)
#define SUN4I_BACKEND_IYUVCTL_FBPS_MASK GENMASK(9, 8)
#define SUN4I_BACKEND_IYUVCTL_FBPS_YVYU (3 << 8)
#define SUN4I_BACKEND_IYUVCTL_FBPS_VYUY (2 << 8)
#define SUN4I_BACKEND_IYUVCTL_FBPS_YUYV (1 << 8)
#define SUN4I_BACKEND_IYUVCTL_FBPS_UYVY (0 << 8)
#define SUN4I_BACKEND_IYUVCTL_FBPS_VUYA (1 << 8)
#define SUN4I_BACKEND_IYUVCTL_FBPS_AYUV (0 << 8)
#define SUN4I_BACKEND_IYUVCTL_EN BIT(0)
#define SUN4I_BACKEND_IYUVADD_REG(c) (0x930 + (0x4 * (c)))
#define SUN4I_BACKEND_IYUVLINEWIDTH_REG(c) (0x940 + (0x4 * (c)))
@ -149,6 +166,7 @@
#define SUN4I_BACKEND_NUM_LAYERS 4
#define SUN4I_BACKEND_NUM_ALPHA_LAYERS 1
#define SUN4I_BACKEND_NUM_FRONTEND_LAYERS 1
#define SUN4I_BACKEND_NUM_YUV_PLANES 1
struct sun4i_backend {
struct sunxi_engine engine;

View File

@ -176,7 +176,13 @@ static bool sun4i_drv_node_is_frontend(struct device_node *node)
of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun6i-a31-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun7i-a20-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend");
of_device_is_compatible(node, "allwinner,sun8i-a33-display-frontend") ||
of_device_is_compatible(node, "allwinner,sun9i-a80-display-frontend");
}
static bool sun4i_drv_node_is_deu(struct device_node *node)
{
return of_device_is_compatible(node, "allwinner,sun9i-a80-deu");
}
static bool sun4i_drv_node_is_supported_frontend(struct device_node *node)
@ -257,7 +263,8 @@ static int sun4i_drv_add_endpoints(struct device *dev,
* enabled frontend supported by the driver, we add it to our
* component list.
*/
if (!sun4i_drv_node_is_frontend(node) ||
if (!(sun4i_drv_node_is_frontend(node) ||
sun4i_drv_node_is_deu(node)) ||
(sun4i_drv_node_is_supported_frontend(node) &&
of_device_is_available(node))) {
/* Add current component */
@ -361,6 +368,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
{ .compatible = "allwinner,sun8i-a83t-display-engine" },
{ .compatible = "allwinner,sun8i-h3-display-engine" },
{ .compatible = "allwinner,sun8i-v3s-display-engine" },
{ .compatible = "allwinner,sun9i-a80-display-engine" },
{ }
};
MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);

View File

@ -134,7 +134,11 @@ static const uint32_t sun4i_backend_layer_formats[] = {
DRM_FORMAT_RGBA4444,
DRM_FORMAT_RGB888,
DRM_FORMAT_RGB565,
DRM_FORMAT_UYVY,
DRM_FORMAT_VYUY,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_YUYV,
DRM_FORMAT_YVYU,
};
static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,

View File

@ -94,9 +94,64 @@ static void sun4i_lvds_encoder_disable(struct drm_encoder *encoder)
}
}
static enum drm_mode_status sun4i_lvds_encoder_mode_valid(struct drm_encoder *crtc,
const struct drm_display_mode *mode)
{
struct sun4i_lvds *lvds = drm_encoder_to_sun4i_lvds(crtc);
struct sun4i_tcon *tcon = lvds->tcon;
u32 hsync = mode->hsync_end - mode->hsync_start;
u32 vsync = mode->vsync_end - mode->vsync_start;
unsigned long rate = mode->clock * 1000;
long rounded_rate;
DRM_DEBUG_DRIVER("Validating modes...\n");
if (hsync < 1)
return MODE_HSYNC_NARROW;
if (hsync > 0x3ff)
return MODE_HSYNC_WIDE;
if ((mode->hdisplay < 1) || (mode->htotal < 1))
return MODE_H_ILLEGAL;
if ((mode->hdisplay > 0x7ff) || (mode->htotal > 0xfff))
return MODE_BAD_HVALUE;
DRM_DEBUG_DRIVER("Horizontal parameters OK\n");
if (vsync < 1)
return MODE_VSYNC_NARROW;
if (vsync > 0x3ff)
return MODE_VSYNC_WIDE;
if ((mode->vdisplay < 1) || (mode->vtotal < 1))
return MODE_V_ILLEGAL;
if ((mode->vdisplay > 0x7ff) || (mode->vtotal > 0xfff))
return MODE_BAD_VVALUE;
DRM_DEBUG_DRIVER("Vertical parameters OK\n");
tcon->dclk_min_div = 7;
tcon->dclk_max_div = 7;
rounded_rate = clk_round_rate(tcon->dclk, rate);
if (rounded_rate < rate)
return MODE_CLOCK_LOW;
if (rounded_rate > rate)
return MODE_CLOCK_HIGH;
DRM_DEBUG_DRIVER("Clock rate OK\n");
return MODE_OK;
}
static const struct drm_encoder_helper_funcs sun4i_lvds_enc_helper_funcs = {
.disable = sun4i_lvds_encoder_disable,
.enable = sun4i_lvds_encoder_enable,
.mode_valid = sun4i_lvds_encoder_mode_valid,
};
static const struct drm_encoder_funcs sun4i_lvds_enc_funcs = {

View File

@ -52,10 +52,10 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector)
return drm_panel_get_modes(tcon->panel);
}
static int sun4i_rgb_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
static enum drm_mode_status sun4i_rgb_mode_valid(struct drm_encoder *crtc,
const struct drm_display_mode *mode)
{
struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(crtc);
struct sun4i_tcon *tcon = rgb->tcon;
u32 hsync = mode->hsync_end - mode->hsync_start;
u32 vsync = mode->vsync_end - mode->vsync_start;
@ -106,7 +106,6 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector,
static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
.get_modes = sun4i_rgb_get_modes,
.mode_valid = sun4i_rgb_mode_valid,
};
static void
@ -156,6 +155,7 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
.disable = sun4i_rgb_encoder_disable,
.enable = sun4i_rgb_encoder_enable,
.mode_valid = sun4i_rgb_mode_valid,
};
static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder)

View File

@ -17,6 +17,7 @@
#include <drm/drm_encoder.h>
#include <drm/drm_modes.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <uapi/drm/drm_mode.h>
@ -343,6 +344,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
const struct drm_display_mode *mode)
{
struct drm_panel *panel = tcon->panel;
struct drm_connector *connector = panel->connector;
struct drm_display_info display_info = connector->display_info;
unsigned int bp, hsync, vsync;
u8 clk_delay;
u32 val = 0;
@ -400,6 +404,27 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
/*
* On A20 and similar SoCs, the only way to achieve Positive Edge
* (Rising Edge), is setting dclk clock phase to 2/3(240°).
* By default TCON works in Negative Edge(Falling Edge),
* this is why phase is set to 0 in that case.
* Unfortunately there's no way to logically invert dclk through
* IO_POL register.
* The only acceptable way to work, triple checked with scope,
* is using clock phase set to 0° for Negative Edge and set to 240°
* for Positive Edge.
* On A33 and similar SoCs there would be a 90° phase option,
* but it divides also dclk by 2.
* Following code is a way to avoid quirks all around TCON
* and DOTCLOCK drivers.
*/
if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
clk_set_phase(tcon->dclk, 240);
if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
clk_set_phase(tcon->dclk, 0);
regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE,
val);
@ -850,6 +875,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
struct sunxi_engine *engine;
struct device_node *remote;
struct sun4i_tcon *tcon;
struct reset_control *edp_rstc;
bool has_lvds_rst, has_lvds_alt, can_lvds;
int ret;
@ -874,6 +900,20 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
return PTR_ERR(tcon->lcd_rst);
}
if (tcon->quirks->needs_edp_reset) {
edp_rstc = devm_reset_control_get_shared(dev, "edp");
if (IS_ERR(edp_rstc)) {
dev_err(dev, "Couldn't get edp reset line\n");
return PTR_ERR(edp_rstc);
}
ret = reset_control_deassert(edp_rstc);
if (ret) {
dev_err(dev, "Couldn't deassert edp reset line\n");
return ret;
}
}
/* Make sure our TCON is reset */
ret = reset_control_reset(tcon->lcd_rst);
if (ret) {
@ -1166,6 +1206,16 @@ static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
.has_channel_0 = true,
};
static const struct sun4i_tcon_quirks sun9i_a80_tcon_lcd_quirks = {
.has_channel_0 = true,
.needs_edp_reset = true,
};
static const struct sun4i_tcon_quirks sun9i_a80_tcon_tv_quirks = {
.has_channel_1 = true,
.needs_edp_reset = true,
};
/* sun4i_drv uses this list to check if a device node is a TCON */
const struct of_device_id sun4i_tcon_of_table[] = {
{ .compatible = "allwinner,sun4i-a10-tcon", .data = &sun4i_a10_quirks },
@ -1177,6 +1227,8 @@ const struct of_device_id sun4i_tcon_of_table[] = {
{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
{ .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
{ .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
{ }
};
MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);

View File

@ -176,6 +176,7 @@ struct sun4i_tcon_quirks {
bool has_channel_1; /* a33 does not have channel 1 */
bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */
bool needs_de_be_mux; /* sun6i needs mux to select backend */
bool needs_edp_reset; /* a80 edp reset needed for tcon0 access */
/* callback to handle tcon muxing options */
int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);

View File

@ -101,6 +101,7 @@ static const struct of_device_id sun6i_drc_of_table[] = {
{ .compatible = "allwinner,sun6i-a31-drc" },
{ .compatible = "allwinner,sun6i-a31s-drc" },
{ .compatible = "allwinner,sun8i-a33-drc" },
{ .compatible = "allwinner,sun9i-a80-drc" },
{ }
};
MODULE_DEVICE_TABLE(of, sun6i_drc_of_table);

View File

@ -643,9 +643,12 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
struct drm_plane *plane;
struct vc4_plane_state *vc4_plane_state;
bool debug_dump_regs = false;
bool enable_bg_fill = false;
u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start;
u32 __iomem *dlist_next = dlist_start;
@ -656,6 +659,20 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
/* Copy all the active planes' dlist contents to the hardware dlist. */
drm_atomic_crtc_for_each_plane(plane, crtc) {
/* Is this the first active plane? */
if (dlist_next == dlist_start) {
/* We need to enable background fill when a plane
* could be alpha blending from the background, i.e.
* where no other plane is underneath. It suffices to
* consider the first active plane here since we set
* needs_bg_fill such that either the first plane
* already needs it or all planes on top blend from
* the first or a lower plane.
*/
vc4_plane_state = to_vc4_plane_state(plane->state);
enable_bg_fill = vc4_plane_state->needs_bg_fill;
}
dlist_next += vc4_plane_write_dlist(plane, dlist_next);
}
@ -664,6 +681,14 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size);
if (enable_bg_fill)
/* This sets a black background color fill, as is the case
* with other DRM drivers.
*/
HVS_WRITE(SCALER_DISPBKGNDX(vc4_crtc->channel),
HVS_READ(SCALER_DISPBKGNDX(vc4_crtc->channel)) |
SCALER_DISPBKGND_FILL);
/* Only update DISPLIST if the CRTC was already running and is not
* being disabled.
* vc4_crtc_enable() takes care of updating the dlist just after

View File

@ -310,6 +310,66 @@ to_vc4_plane(struct drm_plane *plane)
return (struct vc4_plane *)plane;
}
enum vc4_scaling_mode {
VC4_SCALING_NONE,
VC4_SCALING_TPZ,
VC4_SCALING_PPF,
};
struct vc4_plane_state {
struct drm_plane_state base;
/* System memory copy of the display list for this element, computed
* at atomic_check time.
*/
u32 *dlist;
u32 dlist_size; /* Number of dwords allocated for the display list */
u32 dlist_count; /* Number of used dwords in the display list. */
/* Offset in the dlist to various words, for pageflip or
* cursor updates.
*/
u32 pos0_offset;
u32 pos2_offset;
u32 ptr0_offset;
/* Offset where the plane's dlist was last stored in the
* hardware at vc4_crtc_atomic_flush() time.
*/
u32 __iomem *hw_dlist;
/* Clipped coordinates of the plane on the display. */
int crtc_x, crtc_y, crtc_w, crtc_h;
/* Clipped area being scanned from in the FB. */
u32 src_x, src_y;
u32 src_w[2], src_h[2];
/* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
enum vc4_scaling_mode x_scaling[2], y_scaling[2];
bool is_unity;
bool is_yuv;
/* Offset to start scanning out from the start of the plane's
* BO.
*/
u32 offsets[3];
/* Our allocation in LBM for temporary storage during scaling. */
struct drm_mm_node lbm;
/* Set when the plane has per-pixel alpha content or does not cover
* the entire screen. This is a hint to the CRTC that it might need
* to enable background color fill.
*/
bool needs_bg_fill;
};
static inline struct vc4_plane_state *
to_vc4_plane_state(struct drm_plane_state *state)
{
return (struct vc4_plane_state *)state;
}
enum vc4_encoder_type {
VC4_ENCODER_TYPE_NONE,
VC4_ENCODER_TYPE_HDMI,

View File

@ -27,60 +27,6 @@
#include "vc4_drv.h"
#include "vc4_regs.h"
enum vc4_scaling_mode {
VC4_SCALING_NONE,
VC4_SCALING_TPZ,
VC4_SCALING_PPF,
};
struct vc4_plane_state {
struct drm_plane_state base;
/* System memory copy of the display list for this element, computed
* at atomic_check time.
*/
u32 *dlist;
u32 dlist_size; /* Number of dwords allocated for the display list */
u32 dlist_count; /* Number of used dwords in the display list. */
/* Offset in the dlist to various words, for pageflip or
* cursor updates.
*/
u32 pos0_offset;
u32 pos2_offset;
u32 ptr0_offset;
/* Offset where the plane's dlist was last stored in the
* hardware at vc4_crtc_atomic_flush() time.
*/
u32 __iomem *hw_dlist;
/* Clipped coordinates of the plane on the display. */
int crtc_x, crtc_y, crtc_w, crtc_h;
/* Clipped area being scanned from in the FB. */
u32 src_x, src_y;
u32 src_w[2], src_h[2];
/* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */
enum vc4_scaling_mode x_scaling[2], y_scaling[2];
bool is_unity;
bool is_yuv;
/* Offset to start scanning out from the start of the plane's
* BO.
*/
u32 offsets[3];
/* Our allocation in LBM for temporary storage during scaling. */
struct drm_mm_node lbm;
};
static inline struct vc4_plane_state *
to_vc4_plane_state(struct drm_plane_state *state)
{
return (struct vc4_plane_state *)state;
}
static const struct hvs_format {
u32 drm; /* DRM_FORMAT_* */
u32 hvs; /* HVS_FORMAT_* */
@ -521,6 +467,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
u32 ctl0_offset = vc4_state->dlist_count;
const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
int num_planes = drm_format_num_planes(format->drm);
bool covers_screen;
u32 scl0, scl1, pitch0;
u32 lbm_size, tiling;
unsigned long irqflags;
@ -618,13 +565,14 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
SCALER_POS1_SCL_HEIGHT));
}
/* Position Word 2: Source Image Size, Alpha Mode */
/* Position Word 2: Source Image Size, Alpha */
vc4_state->pos2_offset = vc4_state->dlist_count;
vc4_dlist_write(vc4_state,
VC4_SET_FIELD(fb->format->has_alpha ?
SCALER_POS2_ALPHA_MODE_PIPELINE :
SCALER_POS2_ALPHA_MODE_FIXED,
SCALER_POS2_ALPHA_MODE) |
(fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) |
VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) |
VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT));
@ -700,6 +648,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
vc4_state->dlist[ctl0_offset] |=
VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
/* crtc_* are already clipped coordinates. */
covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
vc4_state->crtc_w == state->crtc->mode.hdisplay &&
vc4_state->crtc_h == state->crtc->mode.vdisplay;
/* Background fill might be necessary when the plane has per-pixel
* alpha content and blends from the background or does not cover
* the entire screen.
*/
vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen;
return 0;
}

View File

@ -848,6 +848,7 @@ enum hvs_pixel_format {
#define SCALER_POS2_ALPHA_MODE_FIXED 1
#define SCALER_POS2_ALPHA_MODE_FIXED_NONZERO 2
#define SCALER_POS2_ALPHA_MODE_FIXED_OVER_0x07 3
#define SCALER_POS2_ALPHA_PREMULT BIT(29)
#define SCALER_POS2_HEIGHT_MASK VC4_MASK(27, 16)
#define SCALER_POS2_HEIGHT_SHIFT 16

View File

@ -753,7 +753,7 @@ validate_gl_shader_rec(struct drm_device *dev,
28, /* cs */
};
uint32_t shader_reloc_count = ARRAY_SIZE(shader_reloc_offsets);
struct drm_gem_cma_object *bo[shader_reloc_count + 8];
struct drm_gem_cma_object *bo[ARRAY_SIZE(shader_reloc_offsets) + 8];
uint32_t nr_attributes, nr_relocs, packet_size;
int i;

View File

@ -500,7 +500,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par,
}
if (cur_fb) {
drm_framebuffer_unreference(cur_fb);
drm_framebuffer_put(cur_fb);
par->set_fb = NULL;
}

View File

@ -316,7 +316,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
out_no_surface:
ttm_read_unlock(&dev_priv->reservation_sem);
out_no_ttm_lock:
drm_framebuffer_unreference(fb);
drm_framebuffer_put(fb);
out_no_fb:
drm_modeset_unlock_all(dev);
out_no_copy:
@ -393,7 +393,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
ttm_read_unlock(&dev_priv->reservation_sem);
out_no_ttm_lock:
drm_framebuffer_unreference(fb);
drm_framebuffer_put(fb);
out_no_fb:
drm_modeset_unlock_all(dev);
out_no_copy:

View File

@ -92,7 +92,8 @@
* struct vga_switcheroo_client - registered client
* @pdev: client pci device
* @fb_info: framebuffer to which console is remapped on switching
* @pwr_state: current power state
* @pwr_state: current power state if manual power control is used.
* For driver power control, call vga_switcheroo_pwr_state().
* @ops: client callbacks
* @id: client identifier. Determining the id requires the handler,
* so gpus are initially assigned VGA_SWITCHEROO_UNKNOWN_ID
@ -104,8 +105,7 @@
* @list: client list
*
* Registered client. A client can be either a GPU or an audio device on a GPU.
* For audio clients, the @fb_info, @active and @driver_power_control members
* are bogus.
* For audio clients, the @fb_info and @active members are bogus.
*/
struct vga_switcheroo_client {
struct pci_dev *pdev;
@ -331,8 +331,8 @@ EXPORT_SYMBOL(vga_switcheroo_register_client);
* @ops: client callbacks
* @id: client identifier
*
* Register audio client (audio device on a GPU). The power state of the
* client is assumed to be ON. Beforehand, vga_switcheroo_client_probe_defer()
* Register audio client (audio device on a GPU). The client is assumed
* to use runtime PM. Beforehand, vga_switcheroo_client_probe_defer()
* shall be called to ensure that all prerequisites are met.
*
* Return: 0 on success, -ENOMEM on memory allocation error.
@ -341,7 +341,7 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
const struct vga_switcheroo_client_ops *ops,
enum vga_switcheroo_client_id id)
{
return register_client(pdev, ops, id | ID_BIT_AUDIO, false, false);
return register_client(pdev, ops, id | ID_BIT_AUDIO, false, true);
}
EXPORT_SYMBOL(vga_switcheroo_register_audio_client);
@ -406,6 +406,19 @@ bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev)
}
EXPORT_SYMBOL(vga_switcheroo_client_probe_defer);
static enum vga_switcheroo_state
vga_switcheroo_pwr_state(struct vga_switcheroo_client *client)
{
if (client->driver_power_control)
if (pm_runtime_enabled(&client->pdev->dev) &&
pm_runtime_active(&client->pdev->dev))
return VGA_SWITCHEROO_ON;
else
return VGA_SWITCHEROO_OFF;
else
return client->pwr_state;
}
/**
* vga_switcheroo_get_client_state() - obtain power state of a given client
* @pdev: client pci device
@ -425,7 +438,7 @@ enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *pdev)
if (!client)
ret = VGA_SWITCHEROO_NOT_FOUND;
else
ret = client->pwr_state;
ret = vga_switcheroo_pwr_state(client);
mutex_unlock(&vgasr_mutex);
return ret;
}
@ -598,7 +611,7 @@ static int vga_switcheroo_show(struct seq_file *m, void *v)
client_is_vga(client) ? "" : "-Audio",
client->active ? '+' : ' ',
client->driver_power_control ? "Dyn" : "",
client->pwr_state ? "Pwr" : "Off",
vga_switcheroo_pwr_state(client) ? "Pwr" : "Off",
pci_name(client->pdev));
i++;
}
@ -641,10 +654,8 @@ static void set_audio_state(enum vga_switcheroo_client_id id,
struct vga_switcheroo_client *client;
client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO);
if (client && client->pwr_state != state) {
if (client)
client->ops->set_gpu_state(client->pdev, state);
client->pwr_state = state;
}
}
/* stage one happens before delay */
@ -656,7 +667,7 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
if (!active)
return 0;
if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
if (vga_switcheroo_pwr_state(new_client) == VGA_SWITCHEROO_OFF)
vga_switchon(new_client);
vga_set_default_device(new_client->pdev);
@ -675,7 +686,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
active->active = false;
set_audio_state(active->id, VGA_SWITCHEROO_OFF);
/* let HDA controller autosuspend if GPU uses driver power control */
if (!active->driver_power_control)
set_audio_state(active->id, VGA_SWITCHEROO_OFF);
if (new_client->fb_info) {
struct fb_event event;
@ -695,10 +708,12 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
if (active->pwr_state == VGA_SWITCHEROO_ON)
if (vga_switcheroo_pwr_state(active) == VGA_SWITCHEROO_ON)
vga_switchoff(active);
set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
/* let HDA controller autoresume if GPU uses driver power control */
if (!new_client->driver_power_control)
set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
new_client->active = true;
return 0;
@ -939,11 +954,6 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
* Specifying nouveau.runpm=0, radeon.runpm=0 or amdgpu.runpm=0 on the kernel
* command line disables it.
*
* When the driver decides to power up or down, it notifies vga_switcheroo
* thereof so that it can (a) power the audio device on the GPU up or down,
* and (b) update its internal power state representation for the device.
* This is achieved by vga_switcheroo_set_dynamic_switch().
*
* After the GPU has been suspended, the handler needs to be called to cut
* power to the GPU. Likewise it needs to reinstate power before the GPU
* can resume. This is achieved by vga_switcheroo_init_domain_pm_ops(),
@ -951,8 +961,9 @@ EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
* calls to the handler.
*
* When the audio device resumes, the GPU needs to be woken. This is achieved
* by vga_switcheroo_init_domain_pm_optimus_hdmi_audio(), which augments the
* audio device's resume function.
* by a PCI quirk which calls device_link_add() to declare a dependency on the
* GPU. That way, the GPU is kept awake whenever and as long as the audio
* device is in use.
*
* On muxed machines, if the mux is initially switched to the discrete GPU,
* the user ends up with a black screen when the GPU powers down after boot.
@ -978,35 +989,6 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev,
vgasr_priv.handler->power_state(client->id, state);
}
/**
* vga_switcheroo_set_dynamic_switch() - helper for driver power control
* @pdev: client pci device
* @dynamic: new power state
*
* Helper for GPUs whose power state is controlled by the driver's runtime pm.
* When the driver decides to power up or down, it notifies vga_switcheroo
* thereof using this helper so that it can (a) power the audio device on
* the GPU up or down, and (b) update its internal power state representation
* for the device.
*/
void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev,
enum vga_switcheroo_state dynamic)
{
struct vga_switcheroo_client *client;
mutex_lock(&vgasr_mutex);
client = find_client_from_pci(&vgasr_priv.clients, pdev);
if (!client || !client->driver_power_control) {
mutex_unlock(&vgasr_mutex);
return;
}
client->pwr_state = dynamic;
set_audio_state(client->id, dynamic);
mutex_unlock(&vgasr_mutex);
}
EXPORT_SYMBOL(vga_switcheroo_set_dynamic_switch);
/* switcheroo power domain */
static int vga_switcheroo_runtime_suspend(struct device *dev)
{
@ -1022,6 +1004,7 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
mutex_unlock(&vgasr_priv.mux_hw_lock);
}
pci_bus_set_current_state(pdev->bus, PCI_D3cold);
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
mutex_unlock(&vgasr_mutex);
return 0;
@ -1035,6 +1018,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev)
mutex_lock(&vgasr_mutex);
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON);
mutex_unlock(&vgasr_mutex);
pci_wakeup_bus(pdev->bus);
ret = dev->bus->pm->runtime_resume(dev);
if (ret)
return ret;
@ -1076,69 +1060,3 @@ void vga_switcheroo_fini_domain_pm_ops(struct device *dev)
dev_pm_domain_set(dev, NULL);
}
EXPORT_SYMBOL(vga_switcheroo_fini_domain_pm_ops);
static int vga_switcheroo_runtime_resume_hdmi_audio(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct vga_switcheroo_client *client;
struct device *video_dev = NULL;
int ret;
/* we need to check if we have to switch back on the video
* device so the audio device can come back
*/
mutex_lock(&vgasr_mutex);
list_for_each_entry(client, &vgasr_priv.clients, list) {
if (PCI_SLOT(client->pdev->devfn) == PCI_SLOT(pdev->devfn) &&
client_is_vga(client)) {
video_dev = &client->pdev->dev;
break;
}
}
mutex_unlock(&vgasr_mutex);
if (video_dev) {
ret = pm_runtime_get_sync(video_dev);
if (ret && ret != 1)
return ret;
}
ret = dev->bus->pm->runtime_resume(dev);
/* put the reference for the gpu */
if (video_dev) {
pm_runtime_mark_last_busy(video_dev);
pm_runtime_put_autosuspend(video_dev);
}
return ret;
}
/**
* vga_switcheroo_init_domain_pm_optimus_hdmi_audio() - helper for driver
* power control
* @dev: audio client device
* @domain: power domain
*
* Helper for GPUs whose power state is controlled by the driver's runtime pm.
* When the audio device resumes, the GPU needs to be woken. This helper
* augments the audio device's resume function to do that.
*
* Return: 0 on success, -EINVAL if no power management operations are
* defined for this device.
*/
int
vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev,
struct dev_pm_domain *domain)
{
/* copy over all the bus versions */
if (dev->bus && dev->bus->pm) {
domain->ops = *dev->bus->pm;
domain->ops.runtime_resume =
vga_switcheroo_runtime_resume_hdmi_audio;
dev_pm_domain_set(dev, domain);
return 0;
}
dev_pm_domain_set(dev, NULL);
return -EINVAL;
}
EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio);

View File

@ -1224,11 +1224,14 @@ static int pci_pm_runtime_suspend(struct device *dev)
int error;
/*
* If pci_dev->driver is not set (unbound), the device should
* always remain in D0 regardless of the runtime PM status
* If pci_dev->driver is not set (unbound), we leave the device in D0,
* but it may go to D3cold when the bridge above it runtime suspends.
* Save its config space in case that happens.
*/
if (!pci_dev->driver)
if (!pci_dev->driver) {
pci_save_state(pci_dev);
return 0;
}
if (!pm || !pm->runtime_suspend)
return -ENOSYS;
@ -1276,16 +1279,18 @@ static int pci_pm_runtime_resume(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
/*
* If pci_dev->driver is not set (unbound), the device should
* always remain in D0 regardless of the runtime PM status
* Restoring config space is necessary even if the device is not bound
* to a driver because although we left it in D0, it may have gone to
* D3cold when the bridge above it runtime suspended.
*/
pci_restore_standard_config(pci_dev);
if (!pci_dev->driver)
return 0;
if (!pm || !pm->runtime_resume)
return -ENOSYS;
pci_restore_standard_config(pci_dev);
pci_fixup_device(pci_fixup_resume_early, pci_dev);
pci_enable_wake(pci_dev, PCI_D0, false);
pci_fixup_device(pci_fixup_resume, pci_dev);

View File

@ -800,7 +800,7 @@ static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
* pci_wakeup_bus - Walk given bus and wake up devices on it
* @bus: Top bus of the subtree to walk.
*/
static void pci_wakeup_bus(struct pci_bus *bus)
void pci_wakeup_bus(struct pci_bus *bus)
{
if (bus)
pci_walk_bus(bus, pci_wakeup, NULL);
@ -850,11 +850,11 @@ static int __pci_dev_set_current_state(struct pci_dev *dev, void *data)
}
/**
* __pci_bus_set_current_state - Walk given bus and set current state of devices
* pci_bus_set_current_state - Walk given bus and set current state of devices
* @bus: Top bus of the subtree to walk.
* @state: state to be set
*/
static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
{
if (bus)
pci_walk_bus(bus, __pci_dev_set_current_state, &state);
@ -876,7 +876,7 @@ int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
ret = pci_platform_power_transition(dev, state);
/* Power off the bridge may power off the whole hierarchy */
if (!ret && state == PCI_D3cold)
__pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
return ret;
}
EXPORT_SYMBOL_GPL(__pci_complete_power_transition);

View File

@ -26,6 +26,7 @@
#include <linux/ktime.h>
#include <linux/mm.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/pm_runtime.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
@ -4832,3 +4833,41 @@ static void quirk_fsl_no_msi(struct pci_dev *pdev)
pdev->no_msi = 1;
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_no_msi);
/*
* GPUs with integrated HDA controller for streaming audio to attached displays
* need a device link from the HDA controller (consumer) to the GPU (supplier)
* so that the GPU is powered up whenever the HDA controller is accessed.
* The GPU and HDA controller are functions 0 and 1 of the same PCI device.
* The device link stays in place until shutdown (or removal of the PCI device
* if it's hotplugged). Runtime PM is allowed by default on the HDA controller
* to prevent it from permanently keeping the GPU awake.
*/
static void quirk_gpu_hda(struct pci_dev *hda)
{
struct pci_dev *gpu;
if (PCI_FUNC(hda->devfn) != 1)
return;
gpu = pci_get_domain_bus_and_slot(pci_domain_nr(hda->bus),
hda->bus->number,
PCI_DEVFN(PCI_SLOT(hda->devfn), 0));
if (!gpu || (gpu->class >> 16) != PCI_BASE_CLASS_DISPLAY) {
pci_dev_put(gpu);
return;
}
if (!device_link_add(&hda->dev, &gpu->dev,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME))
pci_err(hda, "cannot link HDA to GPU %s\n", pci_name(gpu));
pm_runtime_allow(&hda->dev);
pci_dev_put(gpu);
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_AMD, PCI_ANY_ID,
PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_CLASS_MULTIMEDIA_HD_AUDIO, 8, quirk_gpu_hda);

View File

@ -41,7 +41,7 @@ struct analogix_dp_plat_data {
struct drm_connector *);
};
int analogix_dp_psr_supported(struct analogix_dp_device *dp);
int analogix_dp_psr_enabled(struct analogix_dp_device *dp);
int analogix_dp_enable_psr(struct analogix_dp_device *dp);
int analogix_dp_disable_psr(struct analogix_dp_device *dp);

View File

@ -38,6 +38,18 @@ void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
int gamma_size);
/**
* drm_color_lut_size - calculate the number of entries in the LUT
* @blob: blob containing the LUT
*
* Returns:
* The number of entries in the color LUT stored in @blob.
*/
static inline int drm_color_lut_size(const struct drm_property_blob *blob)
{
return blob->length / sizeof(struct drm_color_lut);
}
enum drm_color_encoding {
DRM_COLOR_YCBCR_BT601,
DRM_COLOR_YCBCR_BT709,

View File

@ -288,6 +288,7 @@
#define DP_PSR_SUPPORT 0x070 /* XXX 1.2? */
# define DP_PSR_IS_SUPPORTED 1
# define DP_PSR2_IS_SUPPORTED 2 /* eDP 1.4 */
# define DP_PSR2_WITH_Y_COORD_IS_SUPPORTED 3 /* eDP 1.4a */
#define DP_PSR_CAPS 0x071 /* XXX 1.2? */
# define DP_PSR_NO_TRAIN_ON_EXIT 1

View File

@ -120,30 +120,6 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
void drm_mode_object_get(struct drm_mode_object *obj);
void drm_mode_object_put(struct drm_mode_object *obj);
/**
* drm_mode_object_reference - acquire a mode object reference
* @obj: DRM mode object
*
* This is a compatibility alias for drm_mode_object_get() and should not be
* used by new code.
*/
static inline void drm_mode_object_reference(struct drm_mode_object *obj)
{
drm_mode_object_get(obj);
}
/**
* drm_mode_object_unreference - release a mode object reference
* @obj: DRM mode object
*
* This is a compatibility alias for drm_mode_object_put() and should not be
* used by new code.
*/
static inline void drm_mode_object_unreference(struct drm_mode_object *obj)
{
drm_mode_object_put(obj);
}
int drm_object_property_set_value(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t val);

View File

@ -196,21 +196,22 @@ static inline struct drm_printer drm_debug_printer(const char *prefix)
#define DRM_UT_STATE 0x40
#define DRM_UT_LEASE 0x80
__printf(6, 7)
void drm_dev_printk(const struct device *dev, const char *level,
unsigned int category, const char *function_name,
const char *prefix, const char *format, ...);
__printf(3, 4)
void drm_printk(const char *level, unsigned int category,
const char *format, ...);
void drm_dev_printk(const struct device *dev, const char *level,
const char *format, ...);
__printf(3, 4)
void drm_dev_dbg(const struct device *dev, unsigned int category,
const char *format, ...);
__printf(2, 3)
void drm_dbg(unsigned int category, const char *format, ...);
__printf(1, 2)
void drm_err(const char *format, ...);
/* Macros to make printk easier */
#define _DRM_PRINTK(once, level, fmt, ...) \
do { \
printk##once(KERN_##level "[" DRM_NAME "] " fmt, \
##__VA_ARGS__); \
} while (0)
printk##once(KERN_##level "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
#define DRM_INFO(fmt, ...) \
_DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__)
@ -233,10 +234,9 @@ void drm_printk(const char *level, unsigned int category,
* @fmt: printf() like format string.
*/
#define DRM_DEV_ERROR(dev, fmt, ...) \
drm_dev_printk(dev, KERN_ERR, DRM_UT_NONE, __func__, " *ERROR*",\
fmt, ##__VA_ARGS__)
drm_dev_printk(dev, KERN_ERR, "*ERROR* " fmt, ##__VA_ARGS__)
#define DRM_ERROR(fmt, ...) \
drm_printk(KERN_ERR, DRM_UT_NONE, fmt, ##__VA_ARGS__)
drm_err(fmt, ##__VA_ARGS__)
/**
* Rate limited error output. Like DRM_ERROR() but won't flood the log.
@ -257,8 +257,7 @@ void drm_printk(const char *level, unsigned int category,
DRM_DEV_ERROR_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
#define DRM_DEV_INFO(dev, fmt, ...) \
drm_dev_printk(dev, KERN_INFO, DRM_UT_NONE, __func__, "", fmt, \
##__VA_ARGS__)
drm_dev_printk(dev, KERN_INFO, fmt, ##__VA_ARGS__)
#define DRM_DEV_INFO_ONCE(dev, fmt, ...) \
({ \
@ -275,53 +274,46 @@ void drm_printk(const char *level, unsigned int category,
* @dev: device pointer
* @fmt: printf() like format string.
*/
#define DRM_DEV_DEBUG(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_CORE, __func__, "", fmt, \
##args)
#define DRM_DEV_DEBUG(dev, fmt, ...) \
drm_dev_dbg(dev, DRM_UT_CORE, fmt, ##__VA_ARGS__)
#define DRM_DEBUG(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_CORE, fmt, ##__VA_ARGS__)
drm_dbg(DRM_UT_CORE, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_DRIVER(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_DRIVER, __func__, "", \
fmt, ##args)
#define DRM_DEV_DEBUG_DRIVER(dev, fmt, ...) \
drm_dev_dbg(dev, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
#define DRM_DEBUG_DRIVER(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
drm_dbg(DRM_UT_DRIVER, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_KMS(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_KMS, __func__, "", fmt, \
##args)
#define DRM_DEBUG_KMS(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_KMS, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_KMS(dev, fmt, ...) \
drm_dev_dbg(dev, DRM_UT_KMS, fmt, ##__VA_ARGS__)
#define DRM_DEBUG_KMS(fmt, ...) \
drm_dbg(DRM_UT_KMS, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_PRIME(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_PRIME, __func__, "", \
fmt, ##args)
#define DRM_DEV_DEBUG_PRIME(dev, fmt, ...) \
drm_dev_dbg(dev, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
#define DRM_DEBUG_PRIME(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_PRIME, fmt, ##__VA_ARGS__)
drm_dbg(DRM_UT_PRIME, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ATOMIC, __func__, "", \
fmt, ##args)
#define DRM_DEV_DEBUG_ATOMIC(dev, fmt, ...) \
drm_dev_dbg(dev, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
#define DRM_DEBUG_ATOMIC(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
drm_dbg(DRM_UT_ATOMIC, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_VBL(dev, fmt, args...) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_VBL, __func__, "", fmt, \
##args)
#define DRM_DEBUG_VBL(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_VBL, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_VBL(dev, fmt, ...) \
drm_dev_dbg(dev, DRM_UT_VBL, fmt, ##__VA_ARGS__)
#define DRM_DEBUG_VBL(fmt, ...) \
drm_dbg(DRM_UT_VBL, fmt, ##__VA_ARGS__)
#define DRM_DEBUG_LEASE(fmt, ...) \
drm_printk(KERN_DEBUG, DRM_UT_LEASE, fmt, ##__VA_ARGS__)
drm_dbg(DRM_UT_LEASE, fmt, ##__VA_ARGS__)
#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, level, fmt, args...) \
#define _DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, category, fmt, ...) \
({ \
static DEFINE_RATELIMIT_STATE(_rs, \
DEFAULT_RATELIMIT_INTERVAL, \
DEFAULT_RATELIMIT_BURST); \
if (__ratelimit(&_rs)) \
drm_dev_printk(dev, KERN_DEBUG, DRM_UT_ ## level, \
__func__, "", fmt, ##args); \
drm_dev_dbg(dev, category, fmt, ##__VA_ARGS__); \
})
/**
@ -330,21 +322,28 @@ void drm_printk(const char *level, unsigned int category,
* @dev: device pointer
* @fmt: printf() like format string.
*/
#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, args...) \
DEV__DRM_DEFINE_DEBUG_RATELIMITED(dev, CORE, fmt, ##args)
#define DRM_DEBUG_RATELIMITED(fmt, args...) \
DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##args)
#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, args...) \
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRIVER, fmt, ##args)
#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, args...) \
DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##args)
#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, args...) \
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, KMS, fmt, ##args)
#define DRM_DEBUG_KMS_RATELIMITED(fmt, args...) \
DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##args)
#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, args...) \
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, PRIME, fmt, ##args)
#define DRM_DEBUG_PRIME_RATELIMITED(fmt, args...) \
DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##args)
#define DRM_DEV_DEBUG_RATELIMITED(dev, fmt, ...) \
_DEV_DRM_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_CORE, \
fmt, ##__VA_ARGS__)
#define DRM_DEBUG_RATELIMITED(fmt, ...) \
DRM_DEV_DEBUG_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_DRIVER_RATELIMITED(dev, fmt, ...) \
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_DRIVER, \
fmt, ##__VA_ARGS__)
#define DRM_DEBUG_DRIVER_RATELIMITED(fmt, ...) \
DRM_DEV_DEBUG_DRIVER_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_KMS_RATELIMITED(dev, fmt, ...) \
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_KMS, \
fmt, ##__VA_ARGS__)
#define DRM_DEBUG_KMS_RATELIMITED(fmt, ...) \
DRM_DEV_DEBUG_KMS_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
#define DRM_DEV_DEBUG_PRIME_RATELIMITED(dev, fmt, ...) \
_DRM_DEV_DEFINE_DEBUG_RATELIMITED(dev, DRM_UT_PRIME, \
fmt, ##__VA_ARGS__)
#define DRM_DEBUG_PRIME_RATELIMITED(fmt, ...) \
DRM_DEV_DEBUG_PRIME_RATELIMITED(NULL, fmt, ##__VA_ARGS__)
#endif /* DRM_PRINT_H_ */

View File

@ -209,7 +209,7 @@ struct drm_property_blob {
struct list_head head_global;
struct list_head head_file;
size_t length;
unsigned char data[];
void *data;
};
struct drm_prop_enum_list {

View File

@ -1147,6 +1147,8 @@ void pci_pme_wakeup_bus(struct pci_bus *bus);
void pci_d3cold_enable(struct pci_dev *dev);
void pci_d3cold_disable(struct pci_dev *dev);
bool pcie_relaxed_ordering_enabled(struct pci_dev *dev);
void pci_wakeup_bus(struct pci_bus *bus);
void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state);
/* PCI Virtual Channel */
int pci_save_vc_state(struct pci_dev *dev);

View File

@ -45,6 +45,7 @@
#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400
#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
#define PCI_CLASS_MULTIMEDIA_PHONE 0x0402
#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480
#define PCI_BASE_CLASS_MEMORY 0x05

View File

@ -168,11 +168,8 @@ int vga_switcheroo_process_delayed_switch(void);
bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev);
enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev);
void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic);
int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain);
void vga_switcheroo_fini_domain_pm_ops(struct device *dev);
int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain);
#else
static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
@ -192,11 +189,8 @@ static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
static inline bool vga_switcheroo_client_probe_defer(struct pci_dev *pdev) { return false; }
static inline enum vga_switcheroo_state vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {}
static inline int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
static inline void vga_switcheroo_fini_domain_pm_ops(struct device *dev) {}
static inline int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
#endif
#endif /* _LINUX_VGA_SWITCHEROO_H_ */

View File

@ -227,9 +227,6 @@ struct hdac_io_ops {
#define HDA_UNSOL_QUEUE_SIZE 64
#define HDA_MAX_CODECS 8 /* limit by controller side */
/* HD Audio class code */
#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
/*
* CORB/RIRB
*

View File

@ -16,12 +16,6 @@ expression object;
@@
(
- drm_mode_object_reference(object)
+ drm_mode_object_get(object)
|
- drm_mode_object_unreference(object)
+ drm_mode_object_put(object)
|
- drm_connector_reference(object)
+ drm_connector_get(object)
|
@ -62,10 +56,6 @@ position p;
@@
(
drm_mode_object_unreference@p(object)
|
drm_mode_object_reference@p(object)
|
drm_connector_unreference@p(object)
|
drm_connector_reference@p(object)

View File

@ -1227,6 +1227,7 @@ static void azx_vs_set_state(struct pci_dev *pci,
struct snd_card *card = pci_get_drvdata(pci);
struct azx *chip = card->private_data;
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
struct hda_codec *codec;
bool disabled;
wait_for_completion(&hda->probe_wait);
@ -1251,8 +1252,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
dev_info(chip->card->dev, "%s via vga_switcheroo\n",
disabled ? "Disabling" : "Enabling");
if (disabled) {
pm_runtime_put_sync_suspend(card->dev);
azx_suspend(card->dev);
list_for_each_codec(codec, &chip->bus) {
pm_runtime_suspend(hda_codec_dev(codec));
pm_runtime_disable(hda_codec_dev(codec));
}
pm_runtime_suspend(card->dev);
pm_runtime_disable(card->dev);
/* when we get suspended by vga_switcheroo we end up in D3cold,
* however we have no ACPI handle, so pci/acpi can't put us there,
* put ourselves there */
@ -1263,9 +1268,12 @@ static void azx_vs_set_state(struct pci_dev *pci,
"Cannot lock devices!\n");
} else {
snd_hda_unlock_devices(&chip->bus);
pm_runtime_get_noresume(card->dev);
chip->disabled = false;
azx_resume(card->dev);
pm_runtime_enable(card->dev);
list_for_each_codec(codec, &chip->bus) {
pm_runtime_enable(hda_codec_dev(codec));
pm_runtime_resume(hda_codec_dev(codec));
}
}
}
}
@ -1295,6 +1303,7 @@ static void init_vga_switcheroo(struct azx *chip)
dev_info(chip->card->dev,
"Handle vga_switcheroo audio client\n");
hda->use_vga_switcheroo = 1;
chip->driver_caps |= AZX_DCAPS_PM_RUNTIME;
pci_dev_put(p);
}
}
@ -1320,9 +1329,6 @@ static int register_vga_switcheroo(struct azx *chip)
return err;
hda->vga_switcheroo_registered = 1;
/* register as an optimus hdmi audio power domain */
vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev,
&hda->hdmi_pm_domain);
return 0;
}
#else
@ -1351,10 +1357,8 @@ static int azx_free(struct azx *chip)
if (use_vga_switcheroo(hda)) {
if (chip->disabled && hda->probe_continued)
snd_hda_unlock_devices(&chip->bus);
if (hda->vga_switcheroo_registered) {
if (hda->vga_switcheroo_registered)
vga_switcheroo_unregister_client(chip->pci);
vga_switcheroo_fini_domain_pm_ops(chip->card->dev);
}
}
if (bus->chip_init) {
@ -2197,6 +2201,7 @@ static int azx_probe_continue(struct azx *chip)
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
struct hdac_bus *bus = azx_bus(chip);
struct pci_dev *pci = chip->pci;
struct hda_codec *codec;
int dev = chip->dev_index;
int err;
@ -2278,8 +2283,17 @@ static int azx_probe_continue(struct azx *chip)
chip->running = 1;
azx_add_card_list(chip);
/*
* The discrete GPU cannot power down unless the HDA controller runtime
* suspends, so activate runtime PM on codecs even if power_save == 0.
*/
if (use_vga_switcheroo(hda))
list_for_each_codec(codec, &chip->bus)
codec->auto_runtime_pm = 1;
snd_hda_set_power_save(&chip->bus, power_save * 1000);
if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
if (azx_has_pm_runtime(chip))
pm_runtime_put_autosuspend(&pci->dev);
out_free:

View File

@ -40,9 +40,6 @@ struct hda_intel {
unsigned int vga_switcheroo_registered:1;
unsigned int init_failed:1; /* delayed init failed */
/* secondary power domain for hdmi audio under vga device */
struct dev_pm_domain hdmi_pm_domain;
bool need_i915_power:1; /* the hda controller needs i915 power */
};