mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-21 00:47:56 +07:00
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:
commit
0c5286a822
@ -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.
|
@ -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 {
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
||||
};
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
@ -1,4 +1,8 @@
|
||||
Simple display panel
|
||||
====================
|
||||
|
||||
panel node
|
||||
----------
|
||||
|
||||
Required properties:
|
||||
- power-supply: See panel-common.txt
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
21
Documentation/gpu/drivers.rst
Normal file
21
Documentation/gpu/drivers.rst
Normal 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`
|
@ -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
|
||||
================
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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 *
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
448
drivers/gpu/drm/panel/panel-raydium-rm68200.c
Normal file
448
drivers/gpu/drm/panel/panel-raydium-rm68200.c
Normal 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");
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user