mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
drm-misc-next for 7.3:
UAPI Changes:
Cross-subsystem Changes:
Core Changes:
- blend: allow blend mode property without PREMULTI
- bridges:
- Rename drm_for_each_bridge_in_chain_scoped to
drm_for_each_bridge_in_chain
- Drop legacy bridges support
- gpusvm: Code reorganization to give drivers more flexibility
Driver Changes:
- etnaviv: Check if a reset has been successful
- nouveau: Create instmem iomapping at first use
- panthor: Remove redundant cleanup
- qxl: Convert to a simple encoder to a regular one
- bridges:
- Convert all remaining legacy bridges to atomic
- tc358767: clamp the reported AUX read size to the request
- panels:
- novatek-nt37801: Use mipi_dsi_*_multi() functions
- samsung-s6d16d0: Fix prepare error handling
-----BEGIN PGP SIGNATURE-----
iJUEABMJAB0WIQTkHFbLp4ejekA/qfgnX84Zoj2+dgUCaliKpwAKCRAnX84Zoj2+
dn97AYChSha31PCyoicBWbLiovMuDLyZzq7plQz/xdaRI5H0Z5aT1DkDAqeGLl+t
QLeAXKoBfjBp6OtRA7gBjEfwZPFpud58WxEmni4dU8hdHBQ1JW1R2ximQlsq5Y/A
/DESpMRzHg==
=9oKX
-----END PGP SIGNATURE-----
Merge tag 'drm-misc-next-2026-07-16' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for 7.3:
UAPI Changes:
Cross-subsystem Changes:
Core Changes:
- blend: allow blend mode property without PREMULTI
- bridges:
- Rename drm_for_each_bridge_in_chain_scoped to
drm_for_each_bridge_in_chain
- Drop legacy bridges support
- gpusvm: Code reorganization to give drivers more flexibility
Driver Changes:
- etnaviv: Check if a reset has been successful
- nouveau: Create instmem iomapping at first use
- panthor: Remove redundant cleanup
- qxl: Convert to a simple encoder to a regular one
- bridges:
- Convert all remaining legacy bridges to atomic
- tc358767: clamp the reported AUX read size to the request
- panels:
- novatek-nt37801: Use mipi_dsi_*_multi() functions
- samsung-s6d16d0: Fix prepare error handling
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20260716-famous-pastel-ostrich-a1aaef@houat
This commit is contained in:
commit
2e33bfe53c
|
|
@ -167,7 +167,7 @@ ForEachMacros:
|
|||
- 'drm_connector_for_each_possible_encoder'
|
||||
- 'drm_exec_for_each_locked_object'
|
||||
- 'drm_exec_for_each_locked_object_reverse'
|
||||
- 'drm_for_each_bridge_in_chain_scoped'
|
||||
- 'drm_for_each_bridge_in_chain'
|
||||
- 'drm_for_each_connector_iter'
|
||||
- 'drm_for_each_crtc'
|
||||
- 'drm_for_each_crtc_reverse'
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
|
||||
|
|
@ -222,6 +223,9 @@ static int adp_dsi_bridge_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs adp_dsi_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = adp_dsi_bridge_attach,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -566,7 +566,8 @@ anx6345_bridge_mode_valid(struct drm_bridge *bridge,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void anx6345_bridge_disable(struct drm_bridge *bridge)
|
||||
static void anx6345_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
|
||||
|
||||
|
|
@ -580,7 +581,8 @@ static void anx6345_bridge_disable(struct drm_bridge *bridge)
|
|||
anx6345_poweroff(anx6345);
|
||||
}
|
||||
|
||||
static void anx6345_bridge_enable(struct drm_bridge *bridge)
|
||||
static void anx6345_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
|
||||
int err;
|
||||
|
|
@ -600,11 +602,14 @@ static void anx6345_bridge_enable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs anx6345_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = anx6345_bridge_attach,
|
||||
.detach = anx6345_bridge_detach,
|
||||
.mode_valid = anx6345_bridge_mode_valid,
|
||||
.disable = anx6345_bridge_disable,
|
||||
.enable = anx6345_bridge_enable,
|
||||
.atomic_disable = anx6345_bridge_disable,
|
||||
.atomic_enable = anx6345_bridge_enable,
|
||||
};
|
||||
|
||||
static void unregister_i2c_dummy_clients(struct anx6345 *anx6345)
|
||||
|
|
|
|||
|
|
@ -937,7 +937,8 @@ anx78xx_bridge_mode_valid(struct drm_bridge *bridge,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void anx78xx_bridge_disable(struct drm_bridge *bridge)
|
||||
static void anx78xx_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
|
||||
|
||||
|
|
@ -975,7 +976,8 @@ static void anx78xx_bridge_mode_set(struct drm_bridge *bridge,
|
|||
mutex_unlock(&anx78xx->lock);
|
||||
}
|
||||
|
||||
static void anx78xx_bridge_enable(struct drm_bridge *bridge)
|
||||
static void anx78xx_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
|
||||
int err;
|
||||
|
|
@ -992,12 +994,15 @@ static void anx78xx_bridge_enable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs anx78xx_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = anx78xx_bridge_attach,
|
||||
.detach = anx78xx_bridge_detach,
|
||||
.mode_valid = anx78xx_bridge_mode_valid,
|
||||
.disable = anx78xx_bridge_disable,
|
||||
.atomic_disable = anx78xx_bridge_disable,
|
||||
.mode_set = anx78xx_bridge_mode_set,
|
||||
.enable = anx78xx_bridge_enable,
|
||||
.atomic_enable = anx78xx_bridge_enable,
|
||||
};
|
||||
|
||||
static irqreturn_t anx78xx_hpd_threaded_handler(int irq, void *data)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/bridge/aux-bridge.h>
|
||||
|
||||
|
|
@ -104,6 +105,9 @@ static int drm_aux_bridge_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs drm_aux_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = drm_aux_bridge_attach,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/bridge/aux-bridge.h>
|
||||
|
||||
|
|
@ -165,6 +166,9 @@ static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs drm_aux_hpd_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = drm_aux_hpd_bridge_attach,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -330,7 +330,8 @@ static enum drm_mode_status ch7033_bridge_mode_valid(struct drm_bridge *bridge,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void ch7033_bridge_disable(struct drm_bridge *bridge)
|
||||
static void ch7033_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
|
||||
|
||||
|
|
@ -338,7 +339,8 @@ static void ch7033_bridge_disable(struct drm_bridge *bridge)
|
|||
regmap_update_bits(priv->regmap, 0x52, RESETDB, 0x00);
|
||||
}
|
||||
|
||||
static void ch7033_bridge_enable(struct drm_bridge *bridge)
|
||||
static void ch7033_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
|
||||
|
||||
|
|
@ -514,11 +516,14 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs ch7033_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = ch7033_bridge_attach,
|
||||
.detach = ch7033_bridge_detach,
|
||||
.mode_valid = ch7033_bridge_mode_valid,
|
||||
.disable = ch7033_bridge_disable,
|
||||
.enable = ch7033_bridge_enable,
|
||||
.atomic_disable = ch7033_bridge_disable,
|
||||
.atomic_enable = ch7033_bridge_enable,
|
||||
.mode_set = ch7033_bridge_mode_set,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright 2020 Google LLC
|
||||
*/
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <linux/i2c.h>
|
||||
|
|
@ -92,6 +93,9 @@ static bool cros_ec_anx7688_bridge_mode_fixup(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs cros_ec_anx7688_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.mode_fixup = cros_ec_anx7688_bridge_mode_fixup,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_of.h>
|
||||
|
||||
|
|
@ -508,6 +509,9 @@ static const struct attribute_group *lt8713sx_attr_groups[] = {
|
|||
};
|
||||
|
||||
static const struct drm_bridge_funcs lt8713sx_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = lt8713sx_bridge_attach,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -457,7 +457,8 @@ static void lt8912_bridge_mode_set(struct drm_bridge *bridge,
|
|||
drm_display_mode_to_videomode(adj, <->mode);
|
||||
}
|
||||
|
||||
static void lt8912_bridge_enable(struct drm_bridge *bridge)
|
||||
static void lt8912_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct lt8912 *lt = bridge_to_lt8912(bridge);
|
||||
|
||||
|
|
@ -634,11 +635,14 @@ static const struct drm_edid *lt8912_bridge_edid_read(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs lt8912_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = lt8912_bridge_attach,
|
||||
.detach = lt8912_bridge_detach,
|
||||
.mode_valid = lt8912_bridge_mode_valid,
|
||||
.mode_set = lt8912_bridge_mode_set,
|
||||
.enable = lt8912_bridge_enable,
|
||||
.atomic_enable = lt8912_bridge_enable,
|
||||
.detect = lt8912_bridge_detect,
|
||||
.edid_read = lt8912_bridge_edid_read,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -465,6 +465,9 @@ static void lt9611uxc_hdmi_audio_shutdown(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = lt9611uxc_bridge_attach,
|
||||
.mode_valid = lt9611uxc_bridge_mode_valid,
|
||||
.mode_set = lt9611uxc_bridge_mode_set,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ static int lvds_codec_attach(struct drm_bridge *bridge,
|
|||
bridge, flags);
|
||||
}
|
||||
|
||||
static void lvds_codec_enable(struct drm_bridge *bridge)
|
||||
static void lvds_codec_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct lvds_codec *lvds_codec = to_lvds_codec(bridge);
|
||||
int ret;
|
||||
|
|
@ -59,7 +60,8 @@ static void lvds_codec_enable(struct drm_bridge *bridge)
|
|||
gpiod_set_value_cansleep(lvds_codec->powerdown_gpio, 0);
|
||||
}
|
||||
|
||||
static void lvds_codec_disable(struct drm_bridge *bridge)
|
||||
static void lvds_codec_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct lvds_codec *lvds_codec = to_lvds_codec(bridge);
|
||||
int ret;
|
||||
|
|
@ -100,8 +102,8 @@ lvds_codec_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
|||
|
||||
static const struct drm_bridge_funcs funcs = {
|
||||
.attach = lvds_codec_attach,
|
||||
.enable = lvds_codec_enable,
|
||||
.disable = lvds_codec_disable,
|
||||
.atomic_enable = lvds_codec_enable,
|
||||
.atomic_disable = lvds_codec_disable,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
|
|
|
|||
|
|
@ -214,6 +214,9 @@ static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs ge_b850v3_lvds_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = ge_b850v3_lvds_attach,
|
||||
.detect = ge_b850v3_lvds_bridge_detect,
|
||||
.edid_read = ge_b850v3_lvds_edid_read,
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ static void mchp_lvds_atomic_disable(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs mchp_lvds_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = mchp_lvds_attach,
|
||||
.atomic_enable = mchp_lvds_atomic_enable,
|
||||
.atomic_disable = mchp_lvds_atomic_disable,
|
||||
|
|
|
|||
|
|
@ -111,7 +111,8 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ptn3460_pre_enable(struct drm_bridge *bridge)
|
||||
static void ptn3460_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
|
||||
int ret;
|
||||
|
|
@ -139,7 +140,8 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
|
|||
ptn_bridge->enabled = true;
|
||||
}
|
||||
|
||||
static void ptn3460_disable(struct drm_bridge *bridge)
|
||||
static void ptn3460_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
|
||||
|
||||
|
|
@ -163,7 +165,7 @@ static const struct drm_edid *ptn3460_edid_read(struct drm_bridge *bridge,
|
|||
int ret;
|
||||
|
||||
power_off = !ptn_bridge->enabled;
|
||||
ptn3460_pre_enable(&ptn_bridge->bridge);
|
||||
ptn3460_pre_enable(&ptn_bridge->bridge, NULL);
|
||||
|
||||
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
|
||||
if (!edid) {
|
||||
|
|
@ -182,7 +184,7 @@ static const struct drm_edid *ptn3460_edid_read(struct drm_bridge *bridge,
|
|||
|
||||
out:
|
||||
if (power_off)
|
||||
ptn3460_disable(&ptn_bridge->bridge);
|
||||
ptn3460_disable(&ptn_bridge->bridge, NULL);
|
||||
|
||||
return drm_edid;
|
||||
}
|
||||
|
|
@ -248,8 +250,11 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs ptn3460_bridge_funcs = {
|
||||
.pre_enable = ptn3460_pre_enable,
|
||||
.disable = ptn3460_disable,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_pre_enable = ptn3460_pre_enable,
|
||||
.atomic_disable = ptn3460_disable,
|
||||
.attach = ptn3460_bridge_attach,
|
||||
.edid_read = ptn3460_edid_read,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
|
@ -52,6 +53,9 @@ static int of_display_mode_bridge_get_modes(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs of_display_mode_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = of_display_mode_bridge_attach,
|
||||
.get_modes = of_display_mode_bridge_get_modes,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -336,7 +336,8 @@ static const struct backlight_ops ps8622_backlight_ops = {
|
|||
.update_status = ps8622_backlight_update,
|
||||
};
|
||||
|
||||
static void ps8622_pre_enable(struct drm_bridge *bridge)
|
||||
static void ps8622_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
|
||||
int ret;
|
||||
|
|
@ -381,13 +382,15 @@ static void ps8622_pre_enable(struct drm_bridge *bridge)
|
|||
ps8622->enabled = true;
|
||||
}
|
||||
|
||||
static void ps8622_disable(struct drm_bridge *bridge)
|
||||
static void ps8622_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
/* Delay after panel is disabled */
|
||||
msleep(PS8622_PWMO_END_T12_MS);
|
||||
}
|
||||
|
||||
static void ps8622_post_disable(struct drm_bridge *bridge)
|
||||
static void ps8622_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
|
||||
|
||||
|
|
@ -428,9 +431,12 @@ static int ps8622_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs ps8622_bridge_funcs = {
|
||||
.pre_enable = ps8622_pre_enable,
|
||||
.disable = ps8622_disable,
|
||||
.post_disable = ps8622_post_disable,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_pre_enable = ps8622_pre_enable,
|
||||
.atomic_disable = ps8622_disable,
|
||||
.atomic_post_disable = ps8622_post_disable,
|
||||
.attach = ps8622_attach,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1919,7 +1919,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
|
|||
/*
|
||||
* of_graph_get_remote_node() produces a noisy error message if port
|
||||
* node isn't found and the absence of the port is a legit case here,
|
||||
* so at first we silently check whether graph presents in the
|
||||
* so at first we silently check whether a graph is present in the
|
||||
* device-tree node.
|
||||
*/
|
||||
if (!of_graph_is_present(np))
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* Dharam Kumar <dharam.kr@samsung.com>
|
||||
*/
|
||||
#include <drm/bridge/mhl.h>
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
|
@ -339,7 +340,7 @@ static int sii9234_cbus_reset(struct sii9234 *ctx)
|
|||
return sii9234_clear_error(ctx);
|
||||
}
|
||||
|
||||
/* Require to chek mhl imformation of samsung in cbus_init_register */
|
||||
/* Require to check mhl information of samsung in cbus_init_register */
|
||||
static int sii9234_cbus_init(struct sii9234 *ctx)
|
||||
{
|
||||
cbus_writeb(ctx, 0x07, 0xF2);
|
||||
|
|
@ -614,7 +615,7 @@ static void sii9234_cable_out(struct sii9234 *ctx)
|
|||
|
||||
disable_irq(to_i2c_client(ctx->dev)->irq);
|
||||
tpi_writeb(ctx, TPI_DPD_REG, 0);
|
||||
/* Turn on&off hpd festure for only QCT HDMI */
|
||||
/* Turn on&off hpd feature for only QCT HDMI */
|
||||
sii9234_hw_off(ctx);
|
||||
|
||||
ctx->state = ST_OFF;
|
||||
|
|
@ -708,7 +709,7 @@ static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx)
|
|||
{
|
||||
int value;
|
||||
|
||||
/* Work_around code to handle wrong interrupt */
|
||||
/* Workaround code to handle wrong interrupt */
|
||||
if (ctx->state != ST_RGND_1K) {
|
||||
dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n");
|
||||
return ST_FAILURE;
|
||||
|
|
@ -723,9 +724,9 @@ static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx)
|
|||
}
|
||||
dev_dbg(ctx->dev, "RSEN lost\n");
|
||||
/*
|
||||
* Once RSEN loss is confirmed,we need to check
|
||||
* based on cable status and chip power status,whether
|
||||
* it is SINK Loss(HDMI cable not connected, TV Off)
|
||||
* Once RSEN loss is confirmed, we need to check
|
||||
* based on cable status and chip power status, whether
|
||||
* it is SINK Loss (HDMI cable not connected, TV Off)
|
||||
* or MHL cable disconnection
|
||||
* TODO: Define the below mhl_disconnection()
|
||||
*/
|
||||
|
|
@ -820,26 +821,22 @@ static int sii9234_init_resources(struct sii9234 *ctx,
|
|||
int ret;
|
||||
|
||||
if (!ctx->dev->of_node) {
|
||||
dev_err(ctx->dev, "not DT device\n");
|
||||
dev_err(ctx->dev, "no DT device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->gpio_reset)) {
|
||||
dev_err(ctx->dev, "failed to get reset gpio from DT\n");
|
||||
return PTR_ERR(ctx->gpio_reset);
|
||||
}
|
||||
if (IS_ERR(ctx->gpio_reset))
|
||||
return dev_err_probe(ctx->dev, PTR_ERR(ctx->gpio_reset),
|
||||
"failed to get reset gpio from DT\n");
|
||||
|
||||
ctx->supplies[0].supply = "avcc12";
|
||||
ctx->supplies[1].supply = "avcc33";
|
||||
ctx->supplies[2].supply = "iovcc18";
|
||||
ctx->supplies[3].supply = "cvcc12";
|
||||
ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(ctx->dev, "regulator_bulk failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(ctx->dev, ret, "regulator_bulk failed\n");
|
||||
|
||||
ctx->client[I2C_MHL] = client;
|
||||
|
||||
|
|
@ -878,6 +875,9 @@ static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs sii9234_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.mode_valid = sii9234_mode_valid,
|
||||
};
|
||||
|
||||
|
|
@ -911,10 +911,9 @@ static int sii9234_probe(struct i2c_client *client)
|
|||
sii9234_irq_thread,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
"sii9234", ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to install IRQ handler\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to install IRQ handler\n");
|
||||
|
||||
ret = sii9234_init_resources(ctx, client);
|
||||
if (ret < 0)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/unaligned.h>
|
||||
|
||||
#include <drm/bridge/mhl.h>
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_edid.h>
|
||||
|
|
@ -2280,6 +2281,9 @@ static bool sii8620_mode_fixup(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs sii8620_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = sii8620_attach,
|
||||
.detach = sii8620_detach,
|
||||
.mode_fixup = sii8620_mode_fixup,
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ static int simple_bridge_attach(struct drm_bridge *bridge,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void simple_bridge_enable(struct drm_bridge *bridge)
|
||||
static void simple_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
|
||||
int ret;
|
||||
|
|
@ -146,7 +147,8 @@ static void simple_bridge_enable(struct drm_bridge *bridge)
|
|||
gpiod_set_value_cansleep(sbridge->enable, 1);
|
||||
}
|
||||
|
||||
static void simple_bridge_disable(struct drm_bridge *bridge)
|
||||
static void simple_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
|
||||
|
||||
|
|
@ -157,9 +159,12 @@ static void simple_bridge_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs simple_bridge_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = simple_bridge_attach,
|
||||
.enable = simple_bridge_enable,
|
||||
.disable = simple_bridge_disable,
|
||||
.atomic_enable = simple_bridge_enable,
|
||||
.atomic_disable = simple_bridge_disable,
|
||||
};
|
||||
|
||||
static int simple_bridge_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -266,7 +266,8 @@ static void tc358764_reset(struct tc358764 *ctx)
|
|||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
static void tc358764_post_disable(struct drm_bridge *bridge)
|
||||
static void tc358764_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct tc358764 *ctx = bridge_to_tc358764(bridge);
|
||||
int ret;
|
||||
|
|
@ -278,7 +279,8 @@ static void tc358764_post_disable(struct drm_bridge *bridge)
|
|||
dev_err(ctx->dev, "error disabling regulators (%d)\n", ret);
|
||||
}
|
||||
|
||||
static void tc358764_pre_enable(struct drm_bridge *bridge)
|
||||
static void tc358764_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct tc358764 *ctx = bridge_to_tc358764(bridge);
|
||||
int ret;
|
||||
|
|
@ -303,8 +305,11 @@ static int tc358764_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs tc358764_bridge_funcs = {
|
||||
.post_disable = tc358764_post_disable,
|
||||
.pre_enable = tc358764_pre_enable,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_post_disable = tc358764_post_disable,
|
||||
.atomic_pre_enable = tc358764_pre_enable,
|
||||
.attach = tc358764_attach,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -527,7 +527,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux,
|
|||
* address-only transfer
|
||||
*/
|
||||
if (size)
|
||||
size = FIELD_GET(AUX_BYTES, auxstatus);
|
||||
size = min_t(size_t, size, FIELD_GET(AUX_BYTES, auxstatus));
|
||||
msg->reply = FIELD_GET(AUX_STATUS, auxstatus);
|
||||
|
||||
switch (request) {
|
||||
|
|
|
|||
|
|
@ -1410,7 +1410,8 @@ static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void tda998x_bridge_enable(struct drm_bridge *bridge)
|
||||
static void tda998x_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
|
||||
|
||||
|
|
@ -1428,7 +1429,8 @@ static void tda998x_bridge_enable(struct drm_bridge *bridge)
|
|||
}
|
||||
}
|
||||
|
||||
static void tda998x_bridge_disable(struct drm_bridge *bridge)
|
||||
static void tda998x_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
|
||||
|
||||
|
|
@ -1745,12 +1747,15 @@ static void tda998x_bridge_hpd_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs tda998x_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = tda998x_bridge_attach,
|
||||
.detach = tda998x_bridge_detach,
|
||||
.mode_valid = tda998x_bridge_mode_valid,
|
||||
.disable = tda998x_bridge_disable,
|
||||
.atomic_disable = tda998x_bridge_disable,
|
||||
.mode_set = tda998x_bridge_mode_set,
|
||||
.enable = tda998x_bridge_enable,
|
||||
.atomic_enable = tda998x_bridge_enable,
|
||||
.edid_read = tda998x_bridge_edid_read,
|
||||
.detect = tda998x_bridge_detect,
|
||||
.hpd_enable = tda998x_bridge_hpd_enable,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
|
|
@ -81,7 +82,8 @@ static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge,
|
|||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void thc63_enable(struct drm_bridge *bridge)
|
||||
static void thc63_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct thc63_dev *thc63 = to_thc63(bridge);
|
||||
int ret;
|
||||
|
|
@ -97,7 +99,8 @@ static void thc63_enable(struct drm_bridge *bridge)
|
|||
gpiod_set_value(thc63->oe, 1);
|
||||
}
|
||||
|
||||
static void thc63_disable(struct drm_bridge *bridge)
|
||||
static void thc63_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct thc63_dev *thc63 = to_thc63(bridge);
|
||||
int ret;
|
||||
|
|
@ -112,10 +115,13 @@ static void thc63_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs thc63_bridge_func = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = thc63_attach,
|
||||
.mode_valid = thc63_mode_valid,
|
||||
.enable = thc63_enable,
|
||||
.disable = thc63_disable,
|
||||
.atomic_enable = thc63_enable,
|
||||
.atomic_disable = thc63_disable,
|
||||
};
|
||||
|
||||
static int thc63_parse_dt(struct thc63_dev *thc63)
|
||||
|
|
|
|||
|
|
@ -174,14 +174,16 @@ static void tfp410_detach(struct drm_bridge *bridge)
|
|||
}
|
||||
}
|
||||
|
||||
static void tfp410_enable(struct drm_bridge *bridge)
|
||||
static void tfp410_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
|
||||
|
||||
gpiod_set_value_cansleep(dvi->powerdown, 0);
|
||||
}
|
||||
|
||||
static void tfp410_disable(struct drm_bridge *bridge)
|
||||
static void tfp410_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
|
||||
|
||||
|
|
@ -242,8 +244,8 @@ static int tfp410_atomic_check(struct drm_bridge *bridge,
|
|||
static const struct drm_bridge_funcs tfp410_bridge_funcs = {
|
||||
.attach = tfp410_attach,
|
||||
.detach = tfp410_detach,
|
||||
.enable = tfp410_enable,
|
||||
.disable = tfp410_disable,
|
||||
.atomic_enable = tfp410_enable,
|
||||
.atomic_disable = tfp410_disable,
|
||||
.mode_valid = tfp410_mode_valid,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/of_graph.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
|
||||
struct tpd12s015_device {
|
||||
|
|
@ -96,6 +97,9 @@ static void tpd12s015_hpd_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs tpd12s015_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = tpd12s015_attach,
|
||||
.detach = tpd12s015_detach,
|
||||
.detect = tpd12s015_bridge_detect,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/of_graph.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_of.h>
|
||||
|
|
@ -92,7 +93,8 @@ static int ws_bridge_bridge_attach(struct drm_bridge *bridge,
|
|||
&ws->bridge, flags);
|
||||
}
|
||||
|
||||
static void ws_bridge_bridge_enable(struct drm_bridge *bridge)
|
||||
static void ws_bridge_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ws_bridge *ws = bridge_to_ws_bridge(bridge);
|
||||
|
||||
|
|
@ -100,7 +102,8 @@ static void ws_bridge_bridge_enable(struct drm_bridge *bridge)
|
|||
backlight_enable(ws->backlight);
|
||||
}
|
||||
|
||||
static void ws_bridge_bridge_disable(struct drm_bridge *bridge)
|
||||
static void ws_bridge_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct ws_bridge *ws = bridge_to_ws_bridge(bridge);
|
||||
|
||||
|
|
@ -109,8 +112,11 @@ static void ws_bridge_bridge_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs ws_bridge_bridge_funcs = {
|
||||
.enable = ws_bridge_bridge_enable,
|
||||
.disable = ws_bridge_bridge_disable,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_enable = ws_bridge_bridge_enable,
|
||||
.atomic_disable = ws_bridge_bridge_disable,
|
||||
.attach = ws_bridge_bridge_attach,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ static void drm_bridge_connector_hpd_notify(struct drm_connector *connector,
|
|||
to_drm_bridge_connector(connector);
|
||||
|
||||
/* Notify all bridges in the pipeline of hotplug events. */
|
||||
drm_for_each_bridge_in_chain_scoped(bridge_connector->encoder, bridge) {
|
||||
drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge) {
|
||||
if (bridge->funcs->hpd_notify)
|
||||
bridge->funcs->hpd_notify(bridge, connector, status);
|
||||
}
|
||||
|
|
@ -854,7 +854,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
|
|||
* detection are available, we don't support hotplug detection at all.
|
||||
*/
|
||||
connector_type = DRM_MODE_CONNECTOR_Unknown;
|
||||
drm_for_each_bridge_in_chain_scoped(encoder, bridge) {
|
||||
drm_for_each_bridge_in_chain(encoder, bridge) {
|
||||
if (!bridge->interlace_allowed)
|
||||
connector->interlace_allowed = false;
|
||||
if (!bridge->ycbcr_420_allowed)
|
||||
|
|
|
|||
|
|
@ -1554,7 +1554,7 @@ drm_atomic_add_encoder_bridges(struct drm_atomic_commit *state,
|
|||
"Adding all bridges for [encoder:%d:%s] to %p\n",
|
||||
encoder->base.id, encoder->name, state);
|
||||
|
||||
drm_for_each_bridge_in_chain_scoped(encoder, bridge) {
|
||||
drm_for_each_bridge_in_chain(encoder, bridge) {
|
||||
/* Skip bridges that don't implement the atomic state hooks. */
|
||||
if (!bridge->funcs->atomic_duplicate_state)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -563,10 +563,10 @@ EXPORT_SYMBOL(drm_atomic_normalize_zpos);
|
|||
/**
|
||||
* drm_plane_create_blend_mode_property - create a new blend mode property
|
||||
* @plane: drm plane
|
||||
* @supported_modes: bitmask of supported modes, must include
|
||||
* BIT(DRM_MODE_BLEND_PREMULTI). Current DRM assumption is
|
||||
* that alpha is premultiplied, and old userspace can break if
|
||||
* the property defaults to anything else.
|
||||
* @supported_modes: bitmask of supported modes. When
|
||||
* BIT(DRM_MODE_BLEND_PREMULTI) is included, it will be used
|
||||
* as the default. Otherwise, the default will fallback to one
|
||||
* of the supported modes.
|
||||
*
|
||||
* This creates a new property describing the blend mode.
|
||||
*
|
||||
|
|
@ -599,13 +599,14 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane,
|
|||
{ DRM_MODE_BLEND_PREMULTI, "Pre-multiplied" },
|
||||
{ DRM_MODE_BLEND_COVERAGE, "Coverage" },
|
||||
};
|
||||
unsigned int default_mode;
|
||||
unsigned int valid_mode_mask = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
|
||||
BIT(DRM_MODE_BLEND_PREMULTI) |
|
||||
BIT(DRM_MODE_BLEND_COVERAGE);
|
||||
int i;
|
||||
|
||||
if (WARN_ON((supported_modes & ~valid_mode_mask) ||
|
||||
((supported_modes & BIT(DRM_MODE_BLEND_PREMULTI)) == 0)))
|
||||
(supported_modes == 0)))
|
||||
return -EINVAL;
|
||||
|
||||
prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||
|
|
@ -630,7 +631,14 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane,
|
|||
}
|
||||
}
|
||||
|
||||
drm_object_attach_property(&plane->base, prop, DRM_MODE_BLEND_PREMULTI);
|
||||
if (supported_modes & BIT(DRM_MODE_BLEND_PREMULTI))
|
||||
default_mode = DRM_MODE_BLEND_PREMULTI;
|
||||
else if (supported_modes & BIT(DRM_MODE_BLEND_COVERAGE))
|
||||
default_mode = DRM_MODE_BLEND_COVERAGE;
|
||||
else
|
||||
default_mode = DRM_MODE_BLEND_PIXEL_NONE;
|
||||
|
||||
drm_object_attach_property(&plane->base, prop, default_mode);
|
||||
plane->blend_mode_property = prop;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -555,11 +555,6 @@ static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
|
|||
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
|
||||
};
|
||||
|
||||
static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
|
||||
{
|
||||
return bridge->funcs->atomic_create_state != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_bridge_attach - attach the bridge to an encoder's chain
|
||||
*
|
||||
|
|
@ -629,9 +624,8 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
|
|||
goto err_reset_bridge;
|
||||
}
|
||||
|
||||
if (drm_bridge_is_atomic(bridge))
|
||||
drm_atomic_private_obj_init(bridge->dev, &bridge->base,
|
||||
&drm_bridge_priv_state_funcs);
|
||||
drm_atomic_private_obj_init(bridge->dev, &bridge->base,
|
||||
&drm_bridge_priv_state_funcs);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -664,8 +658,7 @@ void drm_bridge_detach(struct drm_bridge *bridge)
|
|||
if (WARN_ON(!bridge->dev))
|
||||
return;
|
||||
|
||||
if (drm_bridge_is_atomic(bridge))
|
||||
drm_atomic_private_obj_fini(&bridge->base);
|
||||
drm_atomic_private_obj_fini(&bridge->base);
|
||||
|
||||
if (bridge->funcs->detach)
|
||||
bridge->funcs->detach(bridge);
|
||||
|
|
@ -690,9 +683,9 @@ void drm_bridge_detach(struct drm_bridge *bridge)
|
|||
* disable the bridge automatically.
|
||||
*
|
||||
* The enable and disable operations are split in
|
||||
* &drm_bridge_funcs.pre_enable, &drm_bridge_funcs.enable,
|
||||
* &drm_bridge_funcs.disable and &drm_bridge_funcs.post_disable to provide
|
||||
* finer-grained control.
|
||||
* &drm_bridge_funcs.atomic_pre_enable, &drm_bridge_funcs.atomic_enable,
|
||||
* &drm_bridge_funcs.atomic_disable and &drm_bridge_funcs.atomic_post_disable
|
||||
* to provide finer-grained control.
|
||||
*
|
||||
* Bridge drivers may implement the legacy version of those operations, or
|
||||
* the atomic version (prefixed with atomic\_), in which case they shall also
|
||||
|
|
@ -833,10 +826,9 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set);
|
|||
* @bridge: bridge control structure
|
||||
* @state: atomic state being committed
|
||||
*
|
||||
* Calls &drm_bridge_funcs.atomic_disable (falls back on
|
||||
* &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
|
||||
* starting from the last bridge to the first. These are called before calling
|
||||
* &drm_encoder_helper_funcs.atomic_disable
|
||||
* Calls &drm_bridge_funcs.atomic_disable op for all the bridges in the encoder
|
||||
* chain, starting from the last bridge to the first. These are called before
|
||||
* calling &drm_encoder_helper_funcs.atomic_disable
|
||||
*
|
||||
* Note: the bridge passed should be the one closest to the encoder
|
||||
*/
|
||||
|
|
@ -852,11 +844,8 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
|
|||
encoder = bridge->encoder;
|
||||
mutex_lock(&encoder->bridge_chain_mutex);
|
||||
list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) {
|
||||
if (iter->funcs->atomic_disable) {
|
||||
if (iter->funcs->atomic_disable)
|
||||
iter->funcs->atomic_disable(iter, state);
|
||||
} else if (iter->funcs->disable) {
|
||||
iter->funcs->disable(iter);
|
||||
}
|
||||
|
||||
if (iter == bridge)
|
||||
break;
|
||||
|
|
@ -870,8 +859,6 @@ static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
|
|||
{
|
||||
if (state && bridge->funcs->atomic_post_disable)
|
||||
bridge->funcs->atomic_post_disable(bridge, state);
|
||||
else if (bridge->funcs->post_disable)
|
||||
bridge->funcs->post_disable(bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -880,10 +867,9 @@ static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
|
|||
* @bridge: bridge control structure
|
||||
* @state: atomic state being committed
|
||||
*
|
||||
* Calls &drm_bridge_funcs.atomic_post_disable (falls back on
|
||||
* &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
|
||||
* starting from the first bridge to the last. These are called after completing
|
||||
* &drm_encoder_helper_funcs.atomic_disable
|
||||
* Calls &drm_bridge_funcs.atomic_post_disable op for all the bridges in the
|
||||
* encoder chain, starting from the first bridge to the last. These are called
|
||||
* after completing &drm_encoder_helper_funcs.atomic_disable
|
||||
*
|
||||
* If a bridge sets @pre_enable_prev_first, then the @post_disable for that
|
||||
* bridge will be called before the previous one to reverse the @pre_enable
|
||||
|
|
@ -967,8 +953,6 @@ static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
|
|||
{
|
||||
if (state && bridge->funcs->atomic_pre_enable)
|
||||
bridge->funcs->atomic_pre_enable(bridge, state);
|
||||
else if (bridge->funcs->pre_enable)
|
||||
bridge->funcs->pre_enable(bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -977,10 +961,9 @@ static void drm_atomic_bridge_call_pre_enable(struct drm_bridge *bridge,
|
|||
* @bridge: bridge control structure
|
||||
* @state: atomic state being committed
|
||||
*
|
||||
* Calls &drm_bridge_funcs.atomic_pre_enable (falls back on
|
||||
* &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
|
||||
* starting from the last bridge to the first. These are called before calling
|
||||
* &drm_encoder_helper_funcs.atomic_enable
|
||||
* Calls &drm_bridge_funcs.atomic_pre_enable op for all the bridges in the
|
||||
* encoder chain, starting from the last bridge to the first. These are called
|
||||
* before calling &drm_encoder_helper_funcs.atomic_enable
|
||||
*
|
||||
* If a bridge sets @pre_enable_prev_first, then the pre_enable for the
|
||||
* prev bridge will be called before pre_enable of this bridge.
|
||||
|
|
@ -1057,10 +1040,9 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable);
|
|||
* @first_bridge: bridge control structure
|
||||
* @state: atomic state being committed
|
||||
*
|
||||
* Calls &drm_bridge_funcs.atomic_enable (falls back on
|
||||
* &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
|
||||
* starting from the first bridge to the last. These are called after completing
|
||||
* &drm_encoder_helper_funcs.atomic_enable
|
||||
* Calls &drm_bridge_funcs.atomic_enable op for all the bridges in the encoder
|
||||
* chain, starting from the first bridge to the last. These are called after
|
||||
* completing &drm_encoder_helper_funcs.atomic_enable
|
||||
*
|
||||
* Note: the bridge passed should be the one closest to the encoder
|
||||
*/
|
||||
|
|
@ -1071,11 +1053,8 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *first_bridge,
|
|||
return;
|
||||
|
||||
drm_for_each_bridge_in_chain_from(first_bridge, bridge)
|
||||
if (bridge->funcs->atomic_enable) {
|
||||
if (bridge->funcs->atomic_enable)
|
||||
bridge->funcs->atomic_enable(bridge, state);
|
||||
} else if (bridge->funcs->enable) {
|
||||
bridge->funcs->enable(bridge);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_atomic_bridge_chain_enable);
|
||||
|
||||
|
|
@ -1717,7 +1696,7 @@ struct drm_bridge *of_drm_get_bridge_by_endpoint(const struct device_node *np,
|
|||
/*
|
||||
* of_graph_get_remote_node() produces a noisy error message if port
|
||||
* node isn't found and the absence of the port is a legit case here,
|
||||
* so at first we silently check whether graph is present in the
|
||||
* so at first we silently check whether a graph is present in the
|
||||
* device-tree node.
|
||||
*/
|
||||
if (!of_graph_is_present(np))
|
||||
|
|
@ -1817,7 +1796,7 @@ static int encoder_bridges_show(struct seq_file *m, void *data)
|
|||
struct drm_printer p = drm_seq_file_printer(m);
|
||||
unsigned int idx = 0;
|
||||
|
||||
drm_for_each_bridge_in_chain_scoped(encoder, bridge)
|
||||
drm_for_each_bridge_in_chain(encoder, bridge)
|
||||
drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, true);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,47 @@
|
|||
* event. As mentioned above, ranges are tracked in a notifier's Red-Black
|
||||
* tree.
|
||||
*
|
||||
* - Pages:
|
||||
* struct drm_gpusvm_pages holds the DMA mapping state for a range of
|
||||
* CPU virtual addresses: the DMA mapped device addresses,
|
||||
* the device private pagemap, the IOVA state, the per mapping
|
||||
* notifier sequence number, and the drm_device that owns the DMA
|
||||
* mappings.
|
||||
* A driver embeds one or more struct drm_gpusvm_pages alongside its
|
||||
* struct drm_gpusvm_range, choosing one of two layouts:
|
||||
*
|
||||
* 1:1 - one drm_gpusvm_pages per range (one drm_device). Simplest
|
||||
* layout; to mirror a VA range on several devices a driver uses a
|
||||
* separate range (and notifier) per device, so the HMM fault is taken
|
||||
* once per device.
|
||||
*
|
||||
* N:1 - one drm_gpusvm_pages per drm_device, all sharing one range and
|
||||
* notifier; only the per-device DMA mapping differs. The instances must
|
||||
* sit in contiguous memory so a single drm_gpusvm_range_set_unmapped()
|
||||
* can mark them all. A driver can keep one instance inline for the single
|
||||
* device case and switch to a heap array only when more devices join,
|
||||
* e.g.:
|
||||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* struct driver_range {
|
||||
* struct drm_gpusvm_range base;
|
||||
* unsigned int num_pages; // 1: inline_pages, >1: pages[]
|
||||
* union {
|
||||
* struct drm_gpusvm_pages inline_pages;
|
||||
* struct drm_gpusvm_pages *pages;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* In the N:1 case the driver allocates the pages array with a zeroing
|
||||
* allocator (e.g. kcalloc(num_pages, ...)), initialises each entry with
|
||||
* drm_gpusvm_init_pages(), and frees each entry with
|
||||
* drm_gpusvm_free_pages() plus the array itself, from its range free
|
||||
* callback. Each drm_gpusvm_pages is mapped independently by their own
|
||||
* drm_device.
|
||||
* Each drm_gpusvm_pages must be zero-initialised and initialised with
|
||||
* drm_gpusvm_init_pages(), called once per entry.
|
||||
*
|
||||
* - Operations:
|
||||
* Define the interface for driver-specific GPU SVM operations such as
|
||||
* range allocation, notifier allocation, and invalidations.
|
||||
|
|
@ -92,7 +133,7 @@
|
|||
* range RB tree and list, as well as the range's DMA mappings and sequence
|
||||
* number. GPU SVM manages all necessary locking and unlocking operations,
|
||||
* except for the recheck range's pages being valid
|
||||
* (drm_gpusvm_range_pages_valid) when the driver is committing GPU bindings.
|
||||
* (drm_gpusvm_pages_valid) when the driver is committing GPU bindings.
|
||||
* This lock corresponds to the ``driver->update`` lock mentioned in
|
||||
* Documentation/mm/hmm.rst. Future revisions may transition from a GPU SVM
|
||||
* global lock to a per-notifier lock if finer-grained locking is deemed
|
||||
|
|
@ -140,15 +181,20 @@
|
|||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* int driver_bind_range(struct drm_gpusvm *gpusvm, struct drm_gpusvm_range *range)
|
||||
* struct driver_range {
|
||||
* struct drm_gpusvm_range base;
|
||||
* struct drm_gpusvm_pages pages;
|
||||
* };
|
||||
*
|
||||
* int driver_bind_range(struct drm_gpusvm *gpusvm, struct driver_range *drange)
|
||||
* {
|
||||
* int err = 0;
|
||||
*
|
||||
* driver_alloc_and_setup_memory_for_bind(gpusvm, range);
|
||||
* driver_alloc_and_setup_memory_for_bind(gpusvm, drange);
|
||||
*
|
||||
* drm_gpusvm_notifier_lock(gpusvm);
|
||||
* if (drm_gpusvm_range_pages_valid(range))
|
||||
* driver_commit_bind(gpusvm, range);
|
||||
* if (drm_gpusvm_pages_valid(gpusvm, &drange->pages))
|
||||
* driver_commit_bind(gpusvm, drange);
|
||||
* else
|
||||
* err = -EAGAIN;
|
||||
* drm_gpusvm_notifier_unlock(gpusvm);
|
||||
|
|
@ -160,6 +206,8 @@
|
|||
* unsigned long gpuva_start, unsigned long gpuva_end)
|
||||
* {
|
||||
* struct drm_gpusvm_ctx ctx = {};
|
||||
* struct driver_range *drange;
|
||||
* struct drm_gpusvm_range *range;
|
||||
* int err;
|
||||
*
|
||||
* driver_svm_lock();
|
||||
|
|
@ -174,6 +222,7 @@
|
|||
* err = PTR_ERR(range);
|
||||
* goto unlock;
|
||||
* }
|
||||
* drange = container_of(range, struct driver_range, base);
|
||||
*
|
||||
* if (driver_migration_policy(range)) {
|
||||
* err = drm_pagemap_populate_mm(driver_choose_drm_pagemap(),
|
||||
|
|
@ -183,7 +232,10 @@
|
|||
* goto retry;
|
||||
* }
|
||||
*
|
||||
* err = drm_gpusvm_range_get_pages(gpusvm, range, &ctx);
|
||||
* err = drm_gpusvm_get_pages(gpusvm, &drange->pages,
|
||||
* gpusvm->mm, &range->notifier->notifier,
|
||||
* drm_gpusvm_range_start(range),
|
||||
* drm_gpusvm_range_end(range), &ctx);
|
||||
* if (err == -EOPNOTSUPP || err == -EFAULT || err == -EPERM) { // CPU mappings changed
|
||||
* if (err == -EOPNOTSUPP)
|
||||
* drm_gpusvm_range_evict(gpusvm, range);
|
||||
|
|
@ -192,7 +244,7 @@
|
|||
* goto unlock;
|
||||
* }
|
||||
*
|
||||
* err = driver_bind_range(gpusvm, range);
|
||||
* err = driver_bind_range(gpusvm, drange);
|
||||
* if (err == -EAGAIN) // CPU mappings changed
|
||||
* goto retry
|
||||
*
|
||||
|
|
@ -205,6 +257,21 @@
|
|||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* // The driver owns the drm_gpusvm_pages lifecycle. ops->range_free is
|
||||
* // the final fallback: drm_gpusvm_free_pages() unmaps any
|
||||
* // lingering DMA mapping and a no-op if already unmapped and frees the
|
||||
* // dma_addr array. The normal flow is to DMA unmap before
|
||||
* // drm_gpusvm_range_remove() (before the range leaves the tree).
|
||||
* void driver_range_free(struct drm_gpusvm_range *range)
|
||||
* {
|
||||
* struct driver_range *drange =
|
||||
* container_of(range, struct driver_range, base);
|
||||
*
|
||||
* drm_gpusvm_free_pages(range->gpusvm, &drange->pages,
|
||||
* drm_gpusvm_range_size(range) >> PAGE_SHIFT);
|
||||
* kfree(drange);
|
||||
* }
|
||||
*
|
||||
* void __driver_garbage_collector(struct drm_gpusvm *gpusvm,
|
||||
* struct drm_gpusvm_range *range)
|
||||
* {
|
||||
|
|
@ -215,6 +282,14 @@
|
|||
* drm_gpusvm_range_evict(gpusvm, range);
|
||||
*
|
||||
* driver_unbind_range(range);
|
||||
* // The pages must be DMA unmapped before drm_gpusvm_range_remove()
|
||||
* // , so a range is never off the MMU interval tree while still DMA
|
||||
* // mapped as the original drmsvm design flow. Otherwise a concurrent CPU
|
||||
* // munmap's notifier could miss this range and free pages still mapped
|
||||
* // for device DMA. This is the normal unmap point.
|
||||
* drm_gpusvm_unmap_pages(gpusvm, &drange->pages,
|
||||
* drm_gpusvm_range_size(range) >> PAGE_SHIFT,
|
||||
* &(struct drm_gpusvm_ctx){ .in_notifier = false });
|
||||
* drm_gpusvm_range_remove(gpusvm, range);
|
||||
* }
|
||||
*
|
||||
|
|
@ -236,17 +311,22 @@
|
|||
* {
|
||||
* struct drm_gpusvm_ctx ctx = { .in_notifier = true, };
|
||||
* struct drm_gpusvm_range *range = NULL;
|
||||
* struct driver_range *drange;
|
||||
*
|
||||
* driver_invalidate_device_pages(gpusvm, mmu_range->start, mmu_range->end);
|
||||
*
|
||||
* drm_gpusvm_for_each_range(range, notifier, mmu_range->start,
|
||||
* mmu_range->end) {
|
||||
* drm_gpusvm_range_unmap_pages(gpusvm, range, &ctx);
|
||||
* drange = container_of(range, struct driver_range, base);
|
||||
*
|
||||
* drm_gpusvm_unmap_pages(gpusvm, &drange->pages,
|
||||
* drm_gpusvm_range_size(range) >> PAGE_SHIFT,
|
||||
* &ctx);
|
||||
*
|
||||
* if (mmu_range->event != MMU_NOTIFY_UNMAP)
|
||||
* continue;
|
||||
*
|
||||
* drm_gpusvm_range_set_unmapped(range, mmu_range);
|
||||
* drm_gpusvm_range_set_unmapped(range, &drange->pages, 1, mmu_range);
|
||||
* driver_garbage_collector_add(gpusvm, range);
|
||||
* }
|
||||
* }
|
||||
|
|
@ -359,7 +439,6 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
|
|||
* drm_gpusvm_init() - Initialize the GPU SVM.
|
||||
* @gpusvm: Pointer to the GPU SVM structure.
|
||||
* @name: Name of the GPU SVM.
|
||||
* @drm: Pointer to the DRM device structure.
|
||||
* @mm: Pointer to the mm_struct for the address space.
|
||||
* @mm_start: Start address of GPU SVM.
|
||||
* @mm_range: Range of the GPU SVM.
|
||||
|
|
@ -373,7 +452,9 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
|
|||
* This function initializes the GPU SVM.
|
||||
*
|
||||
* Note: If only using the simple drm_gpusvm_pages API (get/unmap/free),
|
||||
* then only @gpusvm, @name, and @drm are expected. However, the same base
|
||||
* then only @gpusvm and @name are expected. The @drm drm_device for dma
|
||||
* mappings is bound per-pages via drm_gpusvm_init_pages() before the first
|
||||
* drm_gpusvm_get_pages() call. However, the same base
|
||||
* @gpusvm can also be used with both modes together in which case the full
|
||||
* setup is needed, where the core drm_gpusvm_pages API will simply never use
|
||||
* the other fields.
|
||||
|
|
@ -381,7 +462,7 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
|
|||
* Return: 0 on success, a negative error code on failure.
|
||||
*/
|
||||
int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
|
||||
const char *name, struct drm_device *drm,
|
||||
const char *name,
|
||||
struct mm_struct *mm,
|
||||
unsigned long mm_start, unsigned long mm_range,
|
||||
unsigned long notifier_size,
|
||||
|
|
@ -399,7 +480,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
|
|||
}
|
||||
|
||||
gpusvm->name = name;
|
||||
gpusvm->drm = drm;
|
||||
gpusvm->mm = mm;
|
||||
gpusvm->mm_start = mm_start;
|
||||
gpusvm->mm_range = mm_range;
|
||||
|
|
@ -640,8 +720,7 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm,
|
|||
range->itree.start = ALIGN_DOWN(fault_addr, chunk_size);
|
||||
range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1;
|
||||
INIT_LIST_HEAD(&range->entry);
|
||||
range->pages.notifier_seq = LONG_MAX;
|
||||
range->pages.flags.migrate_devmem = migrate_devmem ? 1 : 0;
|
||||
range->flags.migrate_devmem = migrate_devmem ? 1 : 0;
|
||||
|
||||
return range;
|
||||
}
|
||||
|
|
@ -929,7 +1008,7 @@ drm_gpusvm_range_chunk_size(struct drm_gpusvm *gpusvm,
|
|||
* mallocs 16k but the CPU VMA is ~128k which results in 64k SVM
|
||||
* ranges. When migrating the SVM ranges, some processes fail in
|
||||
* drm_pagemap_migrate_to_devmem with 'migrate.cpages != npages'
|
||||
* and then upon drm_gpusvm_range_get_pages device pages from
|
||||
* and then upon drm_gpusvm_get_pages device pages from
|
||||
* other processes are collected + faulted in which creates all
|
||||
* sorts of problems. Unsure exactly how this happening, also
|
||||
* problem goes away if 'xe_exec_system_allocator --r
|
||||
|
|
@ -1135,11 +1214,16 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
|
|||
unsigned long npages)
|
||||
{
|
||||
struct drm_pagemap *dpagemap = svm_pages->dpagemap;
|
||||
struct device *dev = gpusvm->drm->dev;
|
||||
struct device *dev;
|
||||
unsigned long i, j;
|
||||
|
||||
lockdep_assert_held(&gpusvm->notifier_lock);
|
||||
|
||||
if (!svm_pages->drm)
|
||||
return;
|
||||
|
||||
dev = svm_pages->drm->dev;
|
||||
|
||||
if (svm_pages->flags.has_dma_mapping) {
|
||||
struct drm_gpusvm_pages_flags flags = {
|
||||
.__flags = svm_pages->flags.__flags,
|
||||
|
|
@ -1222,12 +1306,17 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages);
|
|||
* This function removes the specified GPU SVM range and also removes the parent
|
||||
* GPU SVM notifier if no more ranges remain in the notifier. The caller must
|
||||
* hold a lock to protect range and notifier removal.
|
||||
*
|
||||
* This function does not unmap or free the drm_gpusvm_pages, the driver owns
|
||||
* that lifecycle. The caller must DMA unmap the range's pages before calling
|
||||
* this function, so a range is never removed from the MMU interval tree while
|
||||
* still DMA mapped. Typically the driver calls drm_gpusvm_unmap_pages() first.
|
||||
* And the range_free callback's drm_gpusvm_free_pages() is a final fallback safe
|
||||
* net.
|
||||
*/
|
||||
void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range)
|
||||
{
|
||||
unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
|
||||
drm_gpusvm_range_end(range));
|
||||
struct drm_gpusvm_notifier *notifier;
|
||||
|
||||
drm_gpusvm_driver_lock_held(gpusvm);
|
||||
|
|
@ -1239,8 +1328,6 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
|
|||
return;
|
||||
|
||||
drm_gpusvm_notifier_lock(gpusvm);
|
||||
__drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages);
|
||||
__drm_gpusvm_free_pages(gpusvm, &range->pages);
|
||||
__drm_gpusvm_range_remove(notifier, range);
|
||||
drm_gpusvm_notifier_unlock(gpusvm);
|
||||
|
||||
|
|
@ -1319,34 +1406,14 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
|
|||
*
|
||||
* Return: True if GPU SVM range has valid pages, False otherwise
|
||||
*/
|
||||
static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages)
|
||||
bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages)
|
||||
{
|
||||
lockdep_assert_held(&gpusvm->notifier_lock);
|
||||
|
||||
return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_pages_valid() - GPU SVM range pages valid
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @range: Pointer to the GPU SVM range structure
|
||||
*
|
||||
* This function determines if a GPU SVM range pages are valid. Expected be
|
||||
* called holding gpusvm->notifier_lock and as the last step before committing a
|
||||
* GPU binding. This is akin to a notifier seqno check in the HMM documentation
|
||||
* but due to wider notifiers (i.e., notifiers which span multiple ranges) this
|
||||
* function is required for finer grained checking (i.e., per range) if pages
|
||||
* are valid.
|
||||
*
|
||||
* Return: True if GPU SVM range has valid pages, False otherwise
|
||||
*/
|
||||
bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range)
|
||||
{
|
||||
return drm_gpusvm_pages_valid(gpusvm, &range->pages);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_pages_valid);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_pages_valid_unlocked() - GPU SVM pages valid unlocked
|
||||
|
|
@ -1421,6 +1488,9 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
DMA_BIDIRECTIONAL;
|
||||
struct dma_iova_state *state = &svm_pages->state;
|
||||
|
||||
if (!svm_pages->drm)
|
||||
return -EINVAL;
|
||||
|
||||
retry:
|
||||
if (time_after(jiffies, timeout))
|
||||
return -EBUSY;
|
||||
|
|
@ -1520,7 +1590,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
|
||||
pagemap = page_pgmap(page);
|
||||
dpagemap = drm_pagemap_page_to_dpagemap(page);
|
||||
if (drm_WARN_ON(gpusvm->drm, !dpagemap)) {
|
||||
if (drm_WARN_ON(svm_pages->drm, !dpagemap)) {
|
||||
/*
|
||||
* Raced. This is not supposed to happen
|
||||
* since hmm_range_fault() should've migrated
|
||||
|
|
@ -1532,10 +1602,10 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
}
|
||||
svm_pages->dma_addr[j] =
|
||||
dpagemap->ops->device_map(dpagemap,
|
||||
gpusvm->drm->dev,
|
||||
svm_pages->drm->dev,
|
||||
page, order,
|
||||
dma_dir);
|
||||
if (dma_mapping_error(gpusvm->drm->dev,
|
||||
if (dma_mapping_error(svm_pages->drm->dev,
|
||||
svm_pages->dma_addr[j].addr)) {
|
||||
err = -EFAULT;
|
||||
goto err_unmap;
|
||||
|
|
@ -1555,11 +1625,11 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
}
|
||||
|
||||
if (!i)
|
||||
dma_iova_try_alloc(gpusvm->drm->dev, state,
|
||||
dma_iova_try_alloc(svm_pages->drm->dev, state,
|
||||
0, npages * PAGE_SIZE);
|
||||
|
||||
if (dma_use_iova(state)) {
|
||||
err = dma_iova_link(gpusvm->drm->dev, state,
|
||||
err = dma_iova_link(svm_pages->drm->dev, state,
|
||||
hmm_pfn_to_phys(pfns[i]),
|
||||
svm_pages->state_offset,
|
||||
PAGE_SIZE << order,
|
||||
|
|
@ -1570,11 +1640,11 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
addr = state->addr + svm_pages->state_offset;
|
||||
svm_pages->state_offset += PAGE_SIZE << order;
|
||||
} else {
|
||||
addr = dma_map_page(gpusvm->drm->dev,
|
||||
addr = dma_map_page(svm_pages->drm->dev,
|
||||
page, 0,
|
||||
PAGE_SIZE << order,
|
||||
dma_dir);
|
||||
if (dma_mapping_error(gpusvm->drm->dev, addr)) {
|
||||
if (dma_mapping_error(svm_pages->drm->dev, addr)) {
|
||||
err = -EFAULT;
|
||||
goto err_unmap;
|
||||
}
|
||||
|
|
@ -1590,7 +1660,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
}
|
||||
|
||||
if (dma_use_iova(state)) {
|
||||
err = dma_iova_sync(gpusvm->drm->dev, state, 0,
|
||||
err = dma_iova_sync(svm_pages->drm->dev, state, 0,
|
||||
svm_pages->state_offset);
|
||||
if (err)
|
||||
goto err_unmap;
|
||||
|
|
@ -1625,28 +1695,6 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @range: Pointer to the GPU SVM range structure
|
||||
* @ctx: GPU SVM context
|
||||
*
|
||||
* This function gets pages for a GPU SVM range and ensures they are mapped for
|
||||
* DMA access.
|
||||
*
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range,
|
||||
const struct drm_gpusvm_ctx *ctx)
|
||||
{
|
||||
return drm_gpusvm_get_pages(gpusvm, &range->pages, gpusvm->mm,
|
||||
&range->notifier->notifier,
|
||||
drm_gpusvm_range_start(range),
|
||||
drm_gpusvm_range_end(range), ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_unmap_pages() - Unmap GPU svm pages
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
|
|
@ -1677,29 +1725,6 @@ void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_unmap_pages);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
* @range: Pointer to the GPU SVM range structure
|
||||
* @ctx: GPU SVM context
|
||||
*
|
||||
* This function unmaps pages associated with a GPU SVM range. If @in_notifier
|
||||
* is set, it is assumed that gpusvm->notifier_lock is held in write mode; if it
|
||||
* is clear, it acquires gpusvm->notifier_lock in read mode. Must be called on
|
||||
* each GPU SVM range attached to notifier in gpusvm->ops->invalidate for IOMMU
|
||||
* security model.
|
||||
*/
|
||||
void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range,
|
||||
const struct drm_gpusvm_ctx *ctx)
|
||||
{
|
||||
unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
|
||||
drm_gpusvm_range_end(range));
|
||||
|
||||
return drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages, ctx);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_range_evict() - Evict GPU SVM range
|
||||
* @gpusvm: Pointer to the GPU SVM structure
|
||||
|
|
@ -1784,20 +1809,40 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_has_mapping);
|
|||
/**
|
||||
* drm_gpusvm_range_set_unmapped() - Mark a GPU SVM range as unmapped
|
||||
* @range: Pointer to the GPU SVM range structure.
|
||||
* @pages: Pointer to the GPU SVM pages structure(s).
|
||||
* @pages_count: Number of GPU SVM pages structure(s) passed in.
|
||||
* @mmu_range: Pointer to the MMU notifier range structure.
|
||||
*
|
||||
* This function marks a GPU SVM range as unmapped and sets the partial_unmap flag
|
||||
* if the range partially falls within the provided MMU notifier range.
|
||||
*/
|
||||
void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
|
||||
struct drm_gpusvm_pages *pages,
|
||||
unsigned int pages_count,
|
||||
const struct mmu_notifier_range *mmu_range)
|
||||
{
|
||||
struct drm_gpusvm_range_flags range_flags = {
|
||||
.__flags = range->flags.__flags,
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
lockdep_assert_held_write(&range->gpusvm->notifier_lock);
|
||||
|
||||
range->pages.flags.unmapped = true;
|
||||
range_flags.unmapped = true;
|
||||
for (i = 0; i < pages_count; ++i) {
|
||||
struct drm_gpusvm_pages_flags flags = {
|
||||
.__flags = pages[i].flags.__flags,
|
||||
};
|
||||
|
||||
flags.unmapped = true;
|
||||
/* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */
|
||||
WRITE_ONCE(pages[i].flags.__flags, flags.__flags);
|
||||
}
|
||||
if (drm_gpusvm_range_start(range) < mmu_range->start ||
|
||||
drm_gpusvm_range_end(range) > mmu_range->end)
|
||||
range->pages.flags.partial_unmap = true;
|
||||
range_flags.partial_unmap = true;
|
||||
/* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */
|
||||
WRITE_ONCE(range->flags.__flags, range_flags.__flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drm_gpusvm_range_set_unmapped);
|
||||
|
||||
|
|
|
|||
|
|
@ -857,6 +857,25 @@ static void validate_encoder_possible_crtcs(struct drm_encoder *encoder)
|
|||
encoder->possible_crtcs, crtc_mask);
|
||||
}
|
||||
|
||||
static void validate_blend_mode_for_alpha_formats(struct drm_plane *plane)
|
||||
{
|
||||
const struct drm_format_info *fmt;
|
||||
u32 i;
|
||||
|
||||
/* blend mode property supported, no need to check anything */
|
||||
if (plane->blend_mode_property)
|
||||
return;
|
||||
|
||||
for (i = 0; i < plane->format_count; i++) {
|
||||
fmt = drm_format_info(plane->format_types[i]);
|
||||
if (fmt->has_alpha) {
|
||||
WARN(1, "[PLANE:%d:%s] pixel format with alpha exposed but blend mode not setup",
|
||||
plane->base.id, plane->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drm_mode_config_validate(struct drm_device *dev)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
|
|
@ -915,6 +934,8 @@ void drm_mode_config_validate(struct drm_device *dev)
|
|||
drm_for_each_plane(plane, dev) {
|
||||
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
|
||||
num_primary++;
|
||||
|
||||
validate_blend_mode_for_alpha_formats(plane);
|
||||
}
|
||||
|
||||
WARN(num_primary != dev->mode_config.num_crtc,
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ int drm_of_find_panel_or_bridge(const struct device_node *np,
|
|||
/*
|
||||
* of_graph_get_remote_node() produces a noisy error message if port
|
||||
* node isn't found and the absence of the port is a legit case here,
|
||||
* so at first we silently check whether graph presents in the
|
||||
* so at first we silently check whether a graph is present in the
|
||||
* device-tree node.
|
||||
*/
|
||||
if (!of_graph_is_present(np))
|
||||
|
|
|
|||
|
|
@ -584,9 +584,9 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
|
|||
/* read idle register. */
|
||||
idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
|
||||
|
||||
/* try resetting again if FE is not idle */
|
||||
if ((idle & VIVS_HI_IDLE_STATE_FE) == 0) {
|
||||
dev_dbg(gpu->dev, "FE is not idle\n");
|
||||
/* try resetting again if any module is not idle */
|
||||
if ((idle & gpu->idle_mask) != gpu->idle_mask) {
|
||||
dev_dbg(gpu->dev, "GPU modules not idle\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -600,6 +600,23 @@ static int etnaviv_hw_reset(struct etnaviv_gpu *gpu)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* try resetting again if MMUv2 is not disabled */
|
||||
if (gpu->identity.minor_features1 & chipMinorFeatures1_MMU_VERSION) {
|
||||
if (gpu->sec_mode == ETNA_SEC_KERNEL) {
|
||||
if (gpu_read(gpu, VIVS_MMUv2_SEC_CONTROL) &
|
||||
VIVS_MMUv2_SEC_CONTROL_ENABLE) {
|
||||
dev_dbg(gpu->dev, "MMU is not disabled\n");
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (gpu_read(gpu, VIVS_MMUv2_CONTROL) &
|
||||
VIVS_MMUv2_CONTROL_ENABLE) {
|
||||
dev_dbg(gpu->dev, "MMU is not disabled\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* enable debug register access */
|
||||
control &= ~VIVS_HI_CLOCK_CONTROL_DISABLE_DEBUG_REGISTERS;
|
||||
gpu_write(gpu, VIVS_HI_CLOCK_CONTROL, control);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <video/of_videomode.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
|
@ -228,7 +229,8 @@ static void mic_set_reg_on(struct exynos_mic *mic, bool enable)
|
|||
writel(reg, mic->reg + MIC_OP);
|
||||
}
|
||||
|
||||
static void mic_post_disable(struct drm_bridge *bridge)
|
||||
static void mic_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct exynos_mic *mic = bridge->driver_private;
|
||||
|
||||
|
|
@ -257,7 +259,8 @@ static void mic_mode_set(struct drm_bridge *bridge,
|
|||
mutex_unlock(&mic_mutex);
|
||||
}
|
||||
|
||||
static void mic_pre_enable(struct drm_bridge *bridge)
|
||||
static void mic_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct exynos_mic *mic = bridge->driver_private;
|
||||
int ret;
|
||||
|
|
@ -295,9 +298,12 @@ static void mic_pre_enable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs mic_bridge_funcs = {
|
||||
.post_disable = mic_post_disable,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_post_disable = mic_post_disable,
|
||||
.mode_set = mic_mode_set,
|
||||
.pre_enable = mic_pre_enable,
|
||||
.atomic_pre_enable = mic_pre_enable,
|
||||
};
|
||||
|
||||
static int exynos_mic_bind(struct device *dev, struct device *master,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "dc-drv.h"
|
||||
|
||||
#define USERINTERRUPTMASK(n) (0x8 + 4 * (n))
|
||||
#define INTERRUPTENABLE(n) (0x10 + 4 * (n))
|
||||
#define INTERRUPTPRESET(n) (0x18 + 4 * (n))
|
||||
|
|
@ -174,8 +176,8 @@ static int dc_ic_probe(struct platform_device *pdev)
|
|||
regmap_write(data->regs, USERINTERRUPTMASK(i), 0xffffffff);
|
||||
}
|
||||
|
||||
data->domain = irq_domain_add_linear(dev->of_node, IRQ_COUNT,
|
||||
&irq_generic_chip_ops, data);
|
||||
data->domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), IRQ_COUNT,
|
||||
&irq_generic_chip_ops, data);
|
||||
if (!data->domain) {
|
||||
dev_err(dev, "failed to create IRQ domain\n");
|
||||
pm_runtime_put(dev);
|
||||
|
|
|
|||
|
|
@ -1063,6 +1063,9 @@ static int mcde_dsi_bridge_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = mcde_dsi_bridge_attach,
|
||||
.mode_set = mcde_dsi_bridge_mode_set,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -850,7 +850,8 @@ static void mtk_dpi_bridge_mode_set(struct drm_bridge *bridge,
|
|||
drm_mode_copy(&dpi->mode, adjusted_mode);
|
||||
}
|
||||
|
||||
static void mtk_dpi_bridge_disable(struct drm_bridge *bridge)
|
||||
static void mtk_dpi_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
|
||||
|
||||
|
|
@ -860,7 +861,8 @@ static void mtk_dpi_bridge_disable(struct drm_bridge *bridge)
|
|||
pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio);
|
||||
}
|
||||
|
||||
static void mtk_dpi_bridge_enable(struct drm_bridge *bridge)
|
||||
static void mtk_dpi_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
|
||||
|
||||
|
|
@ -982,8 +984,8 @@ static const struct drm_bridge_funcs mtk_dpi_bridge_funcs = {
|
|||
.attach = mtk_dpi_bridge_attach,
|
||||
.mode_set = mtk_dpi_bridge_mode_set,
|
||||
.mode_valid = mtk_dpi_bridge_mode_valid,
|
||||
.disable = mtk_dpi_bridge_disable,
|
||||
.enable = mtk_dpi_bridge_enable,
|
||||
.atomic_disable = mtk_dpi_bridge_disable,
|
||||
.atomic_enable = mtk_dpi_bridge_enable,
|
||||
.atomic_check = mtk_dpi_bridge_atomic_check,
|
||||
.atomic_get_output_bus_fmts = mtk_dpi_bridge_atomic_get_output_bus_fmts,
|
||||
.atomic_get_input_bus_fmts = mtk_dpi_bridge_atomic_get_input_bus_fmts,
|
||||
|
|
|
|||
|
|
@ -275,7 +275,8 @@ static void dsi_mgr_bridge_power_off(struct drm_bridge *bridge)
|
|||
dsi_mgr_phy_disable(id);
|
||||
}
|
||||
|
||||
static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
int id = dsi_mgr_bridge_get_id(bridge);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
|
|
@ -331,7 +332,8 @@ void msm_dsi_manager_tpg_enable(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
|
||||
static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
int id = dsi_mgr_bridge_get_id(bridge);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
|
|
@ -445,9 +447,12 @@ static int dsi_mgr_bridge_attach(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = dsi_mgr_bridge_attach,
|
||||
.pre_enable = dsi_mgr_bridge_pre_enable,
|
||||
.post_disable = dsi_mgr_bridge_post_disable,
|
||||
.atomic_pre_enable = dsi_mgr_bridge_pre_enable,
|
||||
.atomic_post_disable = dsi_mgr_bridge_post_disable,
|
||||
.mode_set = dsi_mgr_bridge_mode_set,
|
||||
.mode_valid = dsi_mgr_bridge_mode_valid,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -297,6 +297,7 @@ r535_fbsr = {
|
|||
static void *
|
||||
r535_instmem_dtor(struct nvkm_instmem *imem)
|
||||
{
|
||||
nv50_instmem_dtor(imem);
|
||||
kfree(imem->func);
|
||||
return imem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,14 @@
|
|||
#include <subdev/gsp.h>
|
||||
#include <subdev/mmu.h>
|
||||
|
||||
#include <linux/io-mapping.h>
|
||||
|
||||
struct nv50_instmem {
|
||||
struct nvkm_instmem base;
|
||||
u64 addr;
|
||||
|
||||
struct io_mapping iomap;
|
||||
|
||||
/* Mappings that can be evicted when BAR2 space has been exhausted. */
|
||||
struct list_head lru;
|
||||
};
|
||||
|
|
@ -124,7 +128,6 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm)
|
|||
struct nv50_instobj *eobj;
|
||||
struct nvkm_memory *memory = &iobj->base.memory;
|
||||
struct nvkm_subdev *subdev = &imem->base.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
struct nvkm_vma *bar = NULL, *ebar;
|
||||
u64 size = nvkm_memory_size(memory);
|
||||
void *emap;
|
||||
|
|
@ -155,7 +158,7 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm)
|
|||
mutex_unlock(&imem->base.mutex);
|
||||
if (!eobj)
|
||||
break;
|
||||
iounmap(emap);
|
||||
io_mapping_unmap(emap);
|
||||
nvkm_vmm_put(vmm, &ebar);
|
||||
}
|
||||
|
||||
|
|
@ -172,8 +175,7 @@ nv50_instobj_kmap(struct nv50_instobj *iobj, struct nvkm_vmm *vmm)
|
|||
|
||||
/* Make the mapping visible to the host. */
|
||||
iobj->bar = bar;
|
||||
iobj->map = ioremap_wc(device->func->resource_addr(device, NVKM_BAR2_INST) +
|
||||
(u32)iobj->bar->addr, size);
|
||||
iobj->map = io_mapping_map_wc(&imem->iomap, (u32)iobj->bar->addr, size);
|
||||
if (!iobj->map) {
|
||||
nvkm_warn(subdev, "PRAMIN ioremap failed\n");
|
||||
nvkm_vmm_put(vmm, &iobj->bar);
|
||||
|
|
@ -188,6 +190,16 @@ nv50_instobj_map(struct nvkm_memory *memory, u64 offset, struct nvkm_vmm *vmm,
|
|||
return nvkm_memory_map(memory, offset, vmm, vma, argv, argc);
|
||||
}
|
||||
|
||||
static bool
|
||||
check_io_mapping(struct nv50_instmem *imem)
|
||||
{
|
||||
struct nvkm_device *device = imem->base.subdev.device;
|
||||
|
||||
return io_mapping_init_wc(&imem->iomap,
|
||||
device->func->resource_addr(device, NVKM_BAR2_INST),
|
||||
device->func->resource_size(device, NVKM_BAR2_INST)) != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_instobj_release(struct nvkm_memory *memory)
|
||||
{
|
||||
|
|
@ -239,7 +251,7 @@ nv50_instobj_acquire(struct nvkm_memory *memory)
|
|||
|
||||
/* Attempt to get a direct CPU mapping of the object. */
|
||||
if ((vmm = nvkm_bar_bar2_vmm(imem->subdev.device))) {
|
||||
if (!iobj->map)
|
||||
if (!iobj->map && iobj->imem->iomap.size)
|
||||
nv50_instobj_kmap(iobj, vmm);
|
||||
map = iobj->map;
|
||||
}
|
||||
|
|
@ -277,7 +289,12 @@ nv50_instobj_boot(struct nvkm_memory *memory, struct nvkm_vmm *vmm)
|
|||
iobj->lru.next = NULL;
|
||||
}
|
||||
|
||||
nv50_instobj_kmap(iobj, vmm);
|
||||
/*
|
||||
* boot is only called on BAR2, if we can't remap the complete
|
||||
* BAR it's unlikely things are functioning well.
|
||||
*/
|
||||
if (check_io_mapping(iobj->imem))
|
||||
nv50_instobj_kmap(iobj, vmm);
|
||||
nvkm_instmem_boot(imem);
|
||||
mutex_unlock(&imem->mutex);
|
||||
}
|
||||
|
|
@ -330,7 +347,7 @@ nv50_instobj_dtor(struct nvkm_memory *memory)
|
|||
|
||||
if (map) {
|
||||
struct nvkm_vmm *vmm = nvkm_bar_bar2_vmm(imem->subdev.device);
|
||||
iounmap(map);
|
||||
io_mapping_unmap(map);
|
||||
if (likely(vmm)) /* Can be NULL during BAR destructor. */
|
||||
nvkm_vmm_put(vmm, &bar);
|
||||
}
|
||||
|
|
@ -406,10 +423,14 @@ nv50_instmem_fini(struct nvkm_instmem *base)
|
|||
nv50_instmem(base)->addr = ~0ULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
void *
|
||||
nv50_instmem_dtor(struct nvkm_instmem *base)
|
||||
{
|
||||
return nv50_instmem(base);
|
||||
struct nv50_instmem *imem = nv50_instmem(base);
|
||||
|
||||
if (imem->iomap.size)
|
||||
io_mapping_fini(&imem->iomap);
|
||||
return imem;
|
||||
}
|
||||
|
||||
static const struct nvkm_instmem_func
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ int nv50_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero,
|
|||
struct nvkm_memory **);
|
||||
int nv50_instobj_wrap(struct nvkm_instmem *, struct nvkm_memory *vram,
|
||||
struct nvkm_memory **bar2);
|
||||
void *nv50_instmem_dtor(struct nvkm_instmem *base);
|
||||
|
||||
void nvkm_instmem_ctor(const struct nvkm_instmem_func *, struct nvkm_device *,
|
||||
enum nvkm_subdev_type, int, struct nvkm_instmem *);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
|
@ -482,7 +483,8 @@ static void dpi_bridge_mode_set(struct drm_bridge *bridge,
|
|||
dpi->pixelclock = adjusted_mode->clock * 1000;
|
||||
}
|
||||
|
||||
static void dpi_bridge_enable(struct drm_bridge *bridge)
|
||||
static void dpi_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
|
||||
int r;
|
||||
|
|
@ -533,7 +535,8 @@ static void dpi_bridge_enable(struct drm_bridge *bridge)
|
|||
regulator_disable(dpi->vdds_dsi_reg);
|
||||
}
|
||||
|
||||
static void dpi_bridge_disable(struct drm_bridge *bridge)
|
||||
static void dpi_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
|
||||
|
||||
|
|
@ -552,12 +555,15 @@ static void dpi_bridge_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs dpi_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = dpi_bridge_attach,
|
||||
.mode_valid = dpi_bridge_mode_valid,
|
||||
.mode_fixup = dpi_bridge_mode_fixup,
|
||||
.mode_set = dpi_bridge_mode_set,
|
||||
.enable = dpi_bridge_enable,
|
||||
.disable = dpi_bridge_disable,
|
||||
.atomic_enable = dpi_bridge_enable,
|
||||
.atomic_disable = dpi_bridge_disable,
|
||||
};
|
||||
|
||||
static void dpi_bridge_init(struct dpi_data *dpi)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/component.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
|
@ -4654,7 +4655,8 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
|
|||
dsi_set_config(&dsi->output, adjusted_mode);
|
||||
}
|
||||
|
||||
static void dsi_bridge_enable(struct drm_bridge *bridge)
|
||||
static void dsi_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct dsi_data *dsi = drm_bridge_to_dsi(bridge);
|
||||
struct omap_dss_device *dssdev = &dsi->output;
|
||||
|
|
@ -4673,7 +4675,8 @@ static void dsi_bridge_enable(struct drm_bridge *bridge)
|
|||
dsi_bus_unlock(dsi);
|
||||
}
|
||||
|
||||
static void dsi_bridge_disable(struct drm_bridge *bridge)
|
||||
static void dsi_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct dsi_data *dsi = drm_bridge_to_dsi(bridge);
|
||||
struct omap_dss_device *dssdev = &dsi->output;
|
||||
|
|
@ -4692,11 +4695,14 @@ static void dsi_bridge_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs dsi_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = dsi_bridge_attach,
|
||||
.mode_valid = dsi_bridge_mode_valid,
|
||||
.mode_set = dsi_bridge_mode_set,
|
||||
.enable = dsi_bridge_enable,
|
||||
.disable = dsi_bridge_disable,
|
||||
.atomic_enable = dsi_bridge_enable,
|
||||
.atomic_disable = dsi_bridge_disable,
|
||||
};
|
||||
|
||||
static void dsi_bridge_init(struct dsi_data *dsi)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
|
@ -197,7 +198,8 @@ static void sdi_bridge_mode_set(struct drm_bridge *bridge,
|
|||
sdi->pixelclock = adjusted_mode->clock * 1000;
|
||||
}
|
||||
|
||||
static void sdi_bridge_enable(struct drm_bridge *bridge)
|
||||
static void sdi_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
|
|
@ -260,7 +262,8 @@ static void sdi_bridge_enable(struct drm_bridge *bridge)
|
|||
regulator_disable(sdi->vdds_sdi_reg);
|
||||
}
|
||||
|
||||
static void sdi_bridge_disable(struct drm_bridge *bridge)
|
||||
static void sdi_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
|
||||
|
||||
|
|
@ -274,12 +277,15 @@ static void sdi_bridge_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs sdi_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = sdi_bridge_attach,
|
||||
.mode_valid = sdi_bridge_mode_valid,
|
||||
.mode_fixup = sdi_bridge_mode_fixup,
|
||||
.mode_set = sdi_bridge_mode_set,
|
||||
.enable = sdi_bridge_enable,
|
||||
.disable = sdi_bridge_disable,
|
||||
.atomic_enable = sdi_bridge_enable,
|
||||
.atomic_disable = sdi_bridge_disable,
|
||||
};
|
||||
|
||||
static void sdi_bridge_init(struct sdi_device *sdi)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/component.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include <drm/drm_atomic_state_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
|
|
@ -614,14 +615,16 @@ static void venc_bridge_mode_set(struct drm_bridge *bridge,
|
|||
dispc_set_tv_pclk(venc->dss->dispc, 13500000);
|
||||
}
|
||||
|
||||
static void venc_bridge_enable(struct drm_bridge *bridge)
|
||||
static void venc_bridge_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct venc_device *venc = drm_bridge_to_venc(bridge);
|
||||
|
||||
venc_power_on(venc);
|
||||
}
|
||||
|
||||
static void venc_bridge_disable(struct drm_bridge *bridge)
|
||||
static void venc_bridge_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct venc_device *venc = drm_bridge_to_venc(bridge);
|
||||
|
||||
|
|
@ -653,12 +656,15 @@ static int venc_bridge_get_modes(struct drm_bridge *bridge,
|
|||
}
|
||||
|
||||
static const struct drm_bridge_funcs venc_bridge_funcs = {
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.attach = venc_bridge_attach,
|
||||
.mode_valid = venc_bridge_mode_valid,
|
||||
.mode_fixup = venc_bridge_mode_fixup,
|
||||
.mode_set = venc_bridge_mode_set,
|
||||
.enable = venc_bridge_enable,
|
||||
.disable = venc_bridge_disable,
|
||||
.atomic_enable = venc_bridge_enable,
|
||||
.atomic_disable = venc_bridge_disable,
|
||||
.get_modes = venc_bridge_get_modes,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -51,61 +51,56 @@ static void novatek_nt37801_reset(struct novatek_nt37801 *ctx)
|
|||
mipi_dsi_dcs_write_seq_multi((dsi_ctx), NT37801_DCS_SWITCH_PAGE, \
|
||||
0x55, 0xaa, 0x52, 0x08, (page))
|
||||
|
||||
static int novatek_nt37801_on(struct novatek_nt37801 *ctx)
|
||||
static void novatek_nt37801_on(struct mipi_dsi_multi_context *dsi_ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
dsi_ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
novatek_nt37801_switch_page(&dsi_ctx, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc5, 0x0b, 0x0b, 0x0b);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf5, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x1b);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x55);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x18);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x19);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x0f);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfc, 0x00);
|
||||
mipi_dsi_dcs_set_column_address_multi(&dsi_ctx, 0x0000, 0x059f);
|
||||
mipi_dsi_dcs_set_page_address_multi(&dsi_ctx, 0x0000, 0x0c7f);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x03, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91,
|
||||
novatek_nt37801_switch_page(dsi_ctx, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc5, 0x0b, 0x0b, 0x0b);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf5, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x1b);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf4, 0x55);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x18);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf8, 0x19);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x0f);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfc, 0x00);
|
||||
mipi_dsi_dcs_set_column_address_multi(dsi_ctx, 0x0000, 0x059f);
|
||||
mipi_dsi_dcs_set_page_address_multi(dsi_ctx, 0x0000, 0x0c7f);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x90, 0x03, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x91,
|
||||
0x89, 0x28, 0x00, 0x28, 0xc2, 0x00, 0x02,
|
||||
0x68, 0x04, 0x6c, 0x00, 0x0a, 0x02, 0x77,
|
||||
0x01, 0xe9, 0x10, 0xf0);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x23);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfb,
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x81);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x23);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xfb,
|
||||
0x00, 0x01, 0x00, 0x11, 0x33, 0x33, 0x33,
|
||||
0x55, 0x57, 0xd0, 0x00, 0x00, 0x44, 0x56,
|
||||
0x77, 0x78, 0x9a, 0xbc, 0xdd, 0xf0);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0xdc);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00);
|
||||
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3b, 0x00, 0x18, 0x00, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x6f, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xf3, 0xdc);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_SET_GAMMA_CURVE, 0x00);
|
||||
mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x3b, 0x00, 0x18, 0x00, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
|
||||
0x20);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51,
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x51,
|
||||
0x07, 0xff, 0x07, 0xff, 0x0f, 0xff);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5a, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5f, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9c, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_MEMORY_START);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2f, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5a, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x5f, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x9c, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, MIPI_DCS_WRITE_MEMORY_START);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x2f, 0x00);
|
||||
|
||||
novatek_nt37801_switch_page(&dsi_ctx, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x55, 0x01, 0xff, 0x03);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
novatek_nt37801_switch_page(dsi_ctx, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x55, 0x01, 0xff, 0x03);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
|
||||
mipi_dsi_msleep(dsi_ctx, 120);
|
||||
mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
|
||||
mipi_dsi_msleep(dsi_ctx, 20);
|
||||
}
|
||||
|
||||
static int novatek_nt37801_off(struct novatek_nt37801 *ctx)
|
||||
|
|
@ -127,7 +122,8 @@ static int novatek_nt37801_off(struct novatek_nt37801 *ctx)
|
|||
static int novatek_nt37801_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct novatek_nt37801 *ctx = to_novatek_nt37801(panel);
|
||||
struct device *dev = &ctx->dsi->dev;
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
struct drm_dsc_picture_parameter_set pps;
|
||||
int ret;
|
||||
|
||||
|
|
@ -137,22 +133,12 @@ static int novatek_nt37801_prepare(struct drm_panel *panel)
|
|||
return ret;
|
||||
|
||||
novatek_nt37801_reset(ctx);
|
||||
|
||||
ret = novatek_nt37801_on(ctx);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
novatek_nt37801_on(&dsi_ctx);
|
||||
drm_dsc_pps_payload_pack(&pps, &ctx->dsc);
|
||||
|
||||
ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps);
|
||||
if (ret < 0) {
|
||||
dev_err(panel->dev, "failed to transmit PPS: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = mipi_dsi_compression_mode(ctx->dsi, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable compression mode: %d\n", ret);
|
||||
mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps);
|
||||
mipi_dsi_compression_mode_multi(&dsi_ctx, true);
|
||||
if (dsi_ctx.accum_err) {
|
||||
ret = dsi_ctx.accum_err;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,16 +88,22 @@ static int s6d16d0_prepare(struct drm_panel *panel)
|
|||
MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
if (ret) {
|
||||
dev_err(s6->dev, "failed to enable vblank TE (%d)\n", ret);
|
||||
return ret;
|
||||
goto err_power_off;
|
||||
}
|
||||
/* Exit sleep mode and power on */
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret) {
|
||||
dev_err(s6->dev, "failed to exit sleep mode (%d)\n", ret);
|
||||
return ret;
|
||||
goto err_power_off;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_off:
|
||||
gpiod_set_value_cansleep(s6->reset_gpio, 1);
|
||||
regulator_disable(s6->supply);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s6d16d0_enable(struct drm_panel *panel)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <drm/drm_utils.h>
|
||||
|
||||
#include "panfrost_device.h"
|
||||
#include "panfrost_drv.h"
|
||||
#include "panfrost_gem.h"
|
||||
#include "panfrost_mmu.h"
|
||||
#include "panfrost_job.h"
|
||||
|
|
|
|||
|
|
@ -3446,7 +3446,6 @@ queue_timedout_job(struct drm_sched_job *sched_job)
|
|||
|
||||
static void queue_free_job(struct drm_sched_job *sched_job)
|
||||
{
|
||||
drm_sched_job_cleanup(sched_job);
|
||||
panthor_job_put(sched_job);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@
|
|||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_vblank_helper.h>
|
||||
|
|
@ -1095,6 +1095,10 @@ static const struct drm_connector_helper_funcs qxl_connector_helper_funcs = {
|
|||
.best_encoder = qxl_best_encoder,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs qxl_encoder_funcs = {
|
||||
.destroy = drm_encoder_cleanup,
|
||||
};
|
||||
|
||||
static enum drm_connector_status qxl_conn_detect(
|
||||
struct drm_connector *connector,
|
||||
bool force)
|
||||
|
|
@ -1169,10 +1173,10 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
|
|||
drm_connector_init(dev, &qxl_output->base,
|
||||
&qxl_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
|
||||
|
||||
ret = drm_simple_encoder_init(dev, &qxl_output->enc,
|
||||
DRM_MODE_ENCODER_VIRTUAL);
|
||||
ret = drm_encoder_init(dev, &qxl_output->enc, &qxl_encoder_funcs,
|
||||
DRM_MODE_ENCODER_VIRTUAL, NULL);
|
||||
if (ret) {
|
||||
drm_err(dev, "drm_simple_encoder_init() failed, error %d\n",
|
||||
drm_err(dev, "drm_encoder_init() failed, error %d\n",
|
||||
ret);
|
||||
goto err_drm_connector_cleanup;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,7 +209,8 @@ static void dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor)
|
|||
minor->debugfs_root, minor);
|
||||
}
|
||||
|
||||
static void sti_dvo_disable(struct drm_bridge *bridge)
|
||||
static void sti_dvo_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sti_dvo *dvo = bridge->driver_private;
|
||||
|
||||
|
|
@ -232,7 +233,8 @@ static void sti_dvo_disable(struct drm_bridge *bridge)
|
|||
dvo->enabled = false;
|
||||
}
|
||||
|
||||
static void sti_dvo_pre_enable(struct drm_bridge *bridge)
|
||||
static void sti_dvo_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sti_dvo *dvo = bridge->driver_private;
|
||||
struct dvo_config *config = dvo->config;
|
||||
|
|
@ -320,16 +322,20 @@ static void sti_dvo_set_mode(struct drm_bridge *bridge,
|
|||
dvo->config = &rgb_24bit_de_cfg;
|
||||
}
|
||||
|
||||
static void sti_dvo_bridge_nope(struct drm_bridge *bridge)
|
||||
static void sti_dvo_bridge_nope(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs sti_dvo_bridge_funcs = {
|
||||
.pre_enable = sti_dvo_pre_enable,
|
||||
.enable = sti_dvo_bridge_nope,
|
||||
.disable = sti_dvo_disable,
|
||||
.post_disable = sti_dvo_bridge_nope,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_pre_enable = sti_dvo_pre_enable,
|
||||
.atomic_enable = sti_dvo_bridge_nope,
|
||||
.atomic_disable = sti_dvo_disable,
|
||||
.atomic_post_disable = sti_dvo_bridge_nope,
|
||||
.mode_set = sti_dvo_set_mode,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -404,7 +404,8 @@ static void sti_hda_configure_awg(struct sti_hda *hda, u32 *awg_instr, int nb)
|
|||
hda_write(hda, 0, HDA_SYNC_AWGI + i * 4);
|
||||
}
|
||||
|
||||
static void sti_hda_disable(struct drm_bridge *bridge)
|
||||
static void sti_hda_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sti_hda *hda = drm_bridge_to_sti_hda(bridge);
|
||||
u32 val;
|
||||
|
|
@ -429,7 +430,8 @@ static void sti_hda_disable(struct drm_bridge *bridge)
|
|||
hda->enabled = false;
|
||||
}
|
||||
|
||||
static void sti_hda_pre_enable(struct drm_bridge *bridge)
|
||||
static void sti_hda_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sti_hda *hda = drm_bridge_to_sti_hda(bridge);
|
||||
u32 val, i, mode_idx;
|
||||
|
|
@ -563,16 +565,20 @@ static void sti_hda_set_mode(struct drm_bridge *bridge,
|
|||
mode->clock * 1000);
|
||||
}
|
||||
|
||||
static void sti_hda_bridge_nope(struct drm_bridge *bridge)
|
||||
static void sti_hda_bridge_nope(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
|
||||
.pre_enable = sti_hda_pre_enable,
|
||||
.enable = sti_hda_bridge_nope,
|
||||
.disable = sti_hda_disable,
|
||||
.post_disable = sti_hda_bridge_nope,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_pre_enable = sti_hda_pre_enable,
|
||||
.atomic_enable = sti_hda_bridge_nope,
|
||||
.atomic_disable = sti_hda_disable,
|
||||
.atomic_post_disable = sti_hda_bridge_nope,
|
||||
.mode_set = sti_hda_set_mode,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -752,7 +752,8 @@ static void hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor)
|
|||
minor->debugfs_root, minor);
|
||||
}
|
||||
|
||||
static void sti_hdmi_disable(struct drm_bridge *bridge)
|
||||
static void sti_hdmi_disable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sti_hdmi *hdmi = drm_bridge_to_sti_hdmi(bridge);
|
||||
|
||||
|
|
@ -884,7 +885,8 @@ static int hdmi_audio_configure(struct sti_hdmi *hdmi)
|
|||
return hdmi_audio_infoframe_config(hdmi);
|
||||
}
|
||||
|
||||
static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
|
||||
static void sti_hdmi_pre_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
struct sti_hdmi *hdmi = drm_bridge_to_sti_hdmi(bridge);
|
||||
|
||||
|
|
@ -964,16 +966,20 @@ static void sti_hdmi_set_mode(struct drm_bridge *bridge,
|
|||
}
|
||||
}
|
||||
|
||||
static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
|
||||
static void sti_hdmi_bridge_nope(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *commit)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
|
||||
.pre_enable = sti_hdmi_pre_enable,
|
||||
.enable = sti_hdmi_bridge_nope,
|
||||
.disable = sti_hdmi_disable,
|
||||
.post_disable = sti_hdmi_bridge_nope,
|
||||
.atomic_create_state = drm_atomic_helper_bridge_create_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_pre_enable = sti_hdmi_pre_enable,
|
||||
.atomic_enable = sti_hdmi_bridge_nope,
|
||||
.atomic_disable = sti_hdmi_disable,
|
||||
.atomic_post_disable = sti_hdmi_bridge_nope,
|
||||
.mode_set = sti_hdmi_set_mode,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -74,26 +74,6 @@ static void drm_test_bridge_priv_destroy(struct drm_bridge *bridge)
|
|||
priv->destroyed = true;
|
||||
}
|
||||
|
||||
static void drm_test_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_bridge_priv *priv = bridge_to_priv(bridge);
|
||||
|
||||
priv->enable_count++;
|
||||
}
|
||||
|
||||
static void drm_test_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_bridge_priv *priv = bridge_to_priv(bridge);
|
||||
|
||||
priv->disable_count++;
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = {
|
||||
.destroy = drm_test_bridge_priv_destroy,
|
||||
.enable = drm_test_bridge_enable,
|
||||
.disable = drm_test_bridge_disable,
|
||||
};
|
||||
|
||||
static void drm_test_bridge_atomic_enable(struct drm_bridge *bridge,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
|
|
@ -695,35 +675,8 @@ static void drm_test_drm_bridge_get_current_state_atomic(struct kunit *test)
|
|||
drm_modeset_acquire_fini(&ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that drm_bridge_get_current_state() returns NULL for a
|
||||
* non-atomic bridge.
|
||||
*/
|
||||
static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test)
|
||||
{
|
||||
struct drm_bridge_init_priv *priv;
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
||||
|
||||
/*
|
||||
* NOTE: Strictly speaking, we should take the bridge->base.lock
|
||||
* before calling that function. However, bridge->base is only
|
||||
* initialized if the bridge is atomic, while we explicitly
|
||||
* initialize one that isn't there.
|
||||
*
|
||||
* In order to avoid unnecessary warnings, let's skip the
|
||||
* locking. The function would return NULL in all cases anyway,
|
||||
* so we don't really have any concurrency to worry about.
|
||||
*/
|
||||
bridge = &priv->test_bridge->bridge;
|
||||
KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge));
|
||||
}
|
||||
|
||||
static struct kunit_case drm_bridge_get_current_state_tests[] = {
|
||||
KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic),
|
||||
KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy),
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
@ -828,62 +781,6 @@ static void drm_test_drm_bridge_helper_reset_crtc_atomic_disabled(struct kunit *
|
|||
KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a non-atomic bridge is properly power-cycled when calling
|
||||
* drm_bridge_helper_reset_crtc().
|
||||
*/
|
||||
static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
|
||||
{
|
||||
struct drm_modeset_acquire_ctx ctx;
|
||||
struct drm_bridge_init_priv *priv;
|
||||
struct drm_display_mode *mode;
|
||||
struct drm_bridge_priv *bridge_priv;
|
||||
int ret;
|
||||
|
||||
priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
|
||||
|
||||
mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
retry_commit:
|
||||
ret = drm_kunit_helper_enable_crtc_connector(test,
|
||||
&priv->drm, priv->crtc,
|
||||
priv->connector,
|
||||
mode,
|
||||
&ctx);
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(&ctx);
|
||||
goto retry_commit;
|
||||
}
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
bridge_priv = priv->test_bridge;
|
||||
KUNIT_ASSERT_EQ(test, bridge_priv->enable_count, 1);
|
||||
KUNIT_ASSERT_EQ(test, bridge_priv->disable_count, 0);
|
||||
|
||||
drm_modeset_acquire_init(&ctx, 0);
|
||||
|
||||
retry_reset:
|
||||
ret = drm_bridge_helper_reset_crtc(&bridge_priv->bridge, &ctx);
|
||||
if (ret == -EDEADLK) {
|
||||
drm_modeset_backoff(&ctx);
|
||||
goto retry_reset;
|
||||
}
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
drm_modeset_drop_locks(&ctx);
|
||||
drm_modeset_acquire_fini(&ctx);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, bridge_priv->enable_count, 2);
|
||||
KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a bridge using the drm_atomic_helper_bridge_get_hdmi_output_bus_fmts()
|
||||
* function for &drm_bridge_funcs.atomic_get_output_bus_fmts behaves as expected
|
||||
|
|
@ -970,7 +867,6 @@ static void drm_test_drm_bridge_helper_hdmi_output_bus_fmts(struct kunit *test)
|
|||
static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
|
||||
KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
|
||||
KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
|
||||
KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
|
||||
KUNIT_CASE(drm_test_drm_bridge_helper_hdmi_output_bus_fmts),
|
||||
{ }
|
||||
};
|
||||
|
|
@ -1071,7 +967,7 @@ static void drm_test_bridge_chain_verify_fmt(struct kunit *test,
|
|||
struct drm_bridge_state *bstate;
|
||||
unsigned int i = 0;
|
||||
|
||||
drm_for_each_bridge_in_chain_scoped(&priv->encoder, bridge) {
|
||||
drm_for_each_bridge_in_chain(&priv->encoder, bridge) {
|
||||
KUNIT_ASSERT_LT(test, i, num_expected);
|
||||
|
||||
bstate = drm_bridge_get_current_state(bridge);
|
||||
|
|
|
|||
|
|
@ -760,7 +760,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
|
|||
return -EAGAIN;
|
||||
}
|
||||
if (xe_svm_range_has_dma_mapping(range)) {
|
||||
xe_res_first_dma(range->base.pages.dma_addr, 0,
|
||||
xe_res_first_dma(range->pages.dma_addr, 0,
|
||||
xe_svm_range_size(range),
|
||||
&curs);
|
||||
xe_svm_range_debug(range, "BIND PREPARE - MIXED");
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ static bool xe_svm_range_in_vram(struct xe_svm_range *range)
|
|||
|
||||
struct drm_gpusvm_pages_flags flags = {
|
||||
/* Pairs with WRITE_ONCE in drm_gpusvm.c */
|
||||
.__flags = READ_ONCE(range->base.pages.flags.__flags),
|
||||
.__flags = READ_ONCE(range->pages.flags.__flags),
|
||||
};
|
||||
|
||||
return flags.has_devmem_pages;
|
||||
|
|
@ -96,7 +96,7 @@ static struct xe_vm *range_to_vm(struct drm_gpusvm_range *r)
|
|||
(r__)->base.gpusvm, \
|
||||
xe_svm_range_in_vram((r__)) ? 1 : 0, \
|
||||
xe_svm_range_has_vram_binding((r__)) ? 1 : 0, \
|
||||
(r__)->base.pages.notifier_seq, \
|
||||
(r__)->pages.notifier_seq, \
|
||||
xe_svm_range_start((r__)), xe_svm_range_end((r__)), \
|
||||
xe_svm_range_size((r__)))
|
||||
|
||||
|
|
@ -115,6 +115,7 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm)
|
|||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&range->garbage_collector_link);
|
||||
drm_gpusvm_init_pages(&range->pages, &gpusvm_to_vm(gpusvm)->xe->drm);
|
||||
xe_vm_get(gpusvm_to_vm(gpusvm));
|
||||
|
||||
return &range->base;
|
||||
|
|
@ -122,8 +123,10 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm)
|
|||
|
||||
static void xe_svm_range_free(struct drm_gpusvm_range *range)
|
||||
{
|
||||
drm_gpusvm_free_pages(range->gpusvm, &(to_xe_range(range)->pages),
|
||||
drm_gpusvm_range_size(range) >> PAGE_SHIFT);
|
||||
xe_vm_put(range_to_vm(range));
|
||||
kfree(range);
|
||||
kfree(to_xe_range(range));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -134,7 +137,8 @@ xe_svm_garbage_collector_add_range(struct xe_vm *vm, struct xe_svm_range *range,
|
|||
|
||||
range_debug(range, "GARBAGE COLLECTOR ADD");
|
||||
|
||||
drm_gpusvm_range_set_unmapped(&range->base, mmu_range);
|
||||
drm_gpusvm_range_set_unmapped(&range->base, &range->pages, 1,
|
||||
mmu_range);
|
||||
|
||||
spin_lock(&vm->svm.garbage_collector.lock);
|
||||
if (list_empty(&range->garbage_collector_link))
|
||||
|
|
@ -166,7 +170,7 @@ xe_svm_range_notifier_event_begin(struct xe_vm *vm, struct drm_gpusvm_range *r,
|
|||
range_debug(range, "NOTIFIER");
|
||||
|
||||
/* Skip if already unmapped or if no binding exist */
|
||||
if (range->base.pages.flags.unmapped || !range->tile_present)
|
||||
if (range->base.flags.unmapped || !range->tile_present)
|
||||
return 0;
|
||||
|
||||
range_debug(range, "NOTIFIER - EXECUTE");
|
||||
|
|
@ -208,7 +212,8 @@ xe_svm_range_notifier_event_end(struct xe_vm *vm, struct drm_gpusvm_range *r,
|
|||
|
||||
xe_svm_assert_in_notifier(vm);
|
||||
|
||||
drm_gpusvm_range_unmap_pages(&vm->svm.gpusvm, r, &ctx);
|
||||
drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &(to_xe_range(r)->pages),
|
||||
drm_gpusvm_range_size(r) >> PAGE_SHIFT, &ctx);
|
||||
if (!xe_vm_is_closed(vm) && mmu_range->event == MMU_NOTIFY_UNMAP)
|
||||
xe_svm_garbage_collector_add_range(vm, to_xe_range(r),
|
||||
mmu_range);
|
||||
|
|
@ -299,6 +304,7 @@ static void xe_svm_invalidate(struct drm_gpusvm *gpusvm,
|
|||
static int __xe_svm_garbage_collector(struct xe_vm *vm,
|
||||
struct xe_svm_range *range)
|
||||
{
|
||||
struct drm_gpusvm_ctx ctx = { .in_notifier = false, };
|
||||
struct dma_fence *fence;
|
||||
|
||||
range_debug(range, "GARBAGE COLLECTOR");
|
||||
|
|
@ -310,6 +316,10 @@ static int __xe_svm_garbage_collector(struct xe_vm *vm,
|
|||
return PTR_ERR(fence);
|
||||
dma_fence_put(fence);
|
||||
|
||||
drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &range->pages,
|
||||
drm_gpusvm_range_size(&range->base) >> PAGE_SHIFT,
|
||||
&ctx);
|
||||
|
||||
drm_gpusvm_range_remove(&vm->svm.gpusvm, &range->base);
|
||||
|
||||
return 0;
|
||||
|
|
@ -901,7 +911,7 @@ int xe_svm_init(struct xe_vm *vm)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
|
||||
err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM",
|
||||
current->mm, 0, vm->size,
|
||||
xe_modparam.svm_notifier_size * SZ_1M,
|
||||
&gpusvm_ops, fault_chunk_sizes,
|
||||
|
|
@ -915,7 +925,7 @@ int xe_svm_init(struct xe_vm *vm)
|
|||
}
|
||||
} else {
|
||||
err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)",
|
||||
&vm->xe->drm, NULL, 0, 0, 0, NULL,
|
||||
NULL, 0, 0, 0, NULL,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
|
|
@ -944,15 +954,28 @@ void xe_svm_close(struct xe_vm *vm)
|
|||
*/
|
||||
void xe_svm_fini(struct xe_vm *vm)
|
||||
{
|
||||
struct drm_gpusvm_notifier *notifier, *next;
|
||||
struct drm_gpusvm_ctx ctx = { .in_notifier = false, };
|
||||
|
||||
xe_assert(vm->xe, xe_vm_is_closed(vm));
|
||||
|
||||
drm_gpusvm_for_each_notifier_safe(notifier, next, &vm->svm.gpusvm, 0, LONG_MAX) {
|
||||
struct drm_gpusvm_range *range, *__next;
|
||||
|
||||
drm_gpusvm_for_each_range_safe(range, __next, notifier, 0, LONG_MAX)
|
||||
drm_gpusvm_unmap_pages(&vm->svm.gpusvm,
|
||||
&(to_xe_range(range)->pages),
|
||||
drm_gpusvm_range_size(range) >> PAGE_SHIFT,
|
||||
&ctx);
|
||||
}
|
||||
|
||||
drm_gpusvm_fini(&vm->svm.gpusvm);
|
||||
}
|
||||
|
||||
static bool xe_svm_range_has_pagemap_locked(const struct xe_svm_range *range,
|
||||
const struct drm_pagemap *dpagemap)
|
||||
{
|
||||
return range->base.pages.dpagemap == dpagemap;
|
||||
return range->pages.dpagemap == dpagemap;
|
||||
}
|
||||
|
||||
static bool xe_svm_range_has_pagemap(struct xe_svm_range *range,
|
||||
|
|
@ -1017,7 +1040,7 @@ bool xe_svm_range_validate(struct xe_vm *vm,
|
|||
if (dpagemap)
|
||||
ret = ret && xe_svm_range_has_pagemap_locked(range, dpagemap);
|
||||
else
|
||||
ret = ret && !range->base.pages.dpagemap;
|
||||
ret = ret && !range->pages.dpagemap;
|
||||
|
||||
xe_svm_notifier_unlock(vm);
|
||||
|
||||
|
|
@ -1135,8 +1158,12 @@ bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, struct xe_vm
|
|||
{
|
||||
struct xe_vm *vm = range_to_vm(&range->base);
|
||||
u64 range_size = xe_svm_range_size(range);
|
||||
struct drm_gpusvm_range_flags flags = {
|
||||
/* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */
|
||||
.__flags = READ_ONCE(range->base.flags.__flags),
|
||||
};
|
||||
|
||||
if (!range->base.pages.flags.migrate_devmem || !dpagemap)
|
||||
if (!flags.migrate_devmem || !dpagemap)
|
||||
return false;
|
||||
|
||||
xe_assert(vm->xe, IS_DGFX(vm->xe));
|
||||
|
|
@ -1220,6 +1247,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
|
|||
struct xe_validation_ctx vctx;
|
||||
struct drm_exec exec;
|
||||
struct xe_svm_range *range;
|
||||
struct drm_gpusvm_range_flags range_flags;
|
||||
struct dma_fence *fence;
|
||||
struct drm_pagemap *dpagemap;
|
||||
struct xe_tile *tile = gt_to_tile(gt);
|
||||
|
|
@ -1248,7 +1276,9 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
|
|||
|
||||
xe_svm_range_fault_count_stats_incr(gt, range);
|
||||
|
||||
if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem)
|
||||
/* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */
|
||||
range_flags.__flags = READ_ONCE(range->base.flags.__flags);
|
||||
if (ctx.devmem_only && !range_flags.migrate_devmem)
|
||||
return -EACCES;
|
||||
|
||||
if (xe_svm_range_is_valid(range, tile, ctx.devmem_only, dpagemap)) {
|
||||
|
|
@ -1505,7 +1535,11 @@ int xe_svm_range_get_pages(struct xe_vm *vm, struct xe_svm_range *range,
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
err = drm_gpusvm_range_get_pages(&vm->svm.gpusvm, &range->base, ctx);
|
||||
err = drm_gpusvm_get_pages(&vm->svm.gpusvm, &range->pages,
|
||||
vm->svm.gpusvm.mm,
|
||||
&range->base.notifier->notifier,
|
||||
drm_gpusvm_range_start(&range->base),
|
||||
drm_gpusvm_range_end(&range->base), ctx);
|
||||
if (err == -EOPNOTSUPP) {
|
||||
range_debug(range, "PAGE FAULT - EVICT PAGES");
|
||||
drm_gpusvm_range_evict(&vm->svm.gpusvm, &range->base);
|
||||
|
|
@ -1620,8 +1654,12 @@ int xe_svm_alloc_vram(struct xe_svm_range *range, const struct drm_gpusvm_ctx *c
|
|||
struct xe_device *xe = vm->xe;
|
||||
int err, retries = 1;
|
||||
bool write_locked = false;
|
||||
struct drm_gpusvm_range_flags flags = {
|
||||
/* READ_ONCE pairs with WRITE_ONCE in drm_gpusvm_range_set_unmapped() */
|
||||
.__flags = READ_ONCE(range->base.flags.__flags),
|
||||
};
|
||||
|
||||
xe_assert(range_to_vm(&range->base)->xe, range->base.pages.flags.migrate_devmem);
|
||||
xe_assert(range_to_vm(&range->base)->xe, flags.migrate_devmem);
|
||||
range_debug(range, "ALLOCATE VRAM");
|
||||
|
||||
migration_state = drm_gpusvm_scan_mm(&range->base,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ struct xe_vram_region;
|
|||
struct xe_svm_range {
|
||||
/** @base: base drm_gpusvm_range */
|
||||
struct drm_gpusvm_range base;
|
||||
/** @pages: Page/DMA mapping state for this range (single drm_device). */
|
||||
struct drm_gpusvm_pages pages;
|
||||
/**
|
||||
* @garbage_collector_link: Link into VM's garbage collect SVM range
|
||||
* list. Protected by VM's garbage collect lock.
|
||||
|
|
@ -74,7 +76,7 @@ struct xe_pagemap {
|
|||
*/
|
||||
static inline bool xe_svm_range_pages_valid(struct xe_svm_range *range)
|
||||
{
|
||||
return drm_gpusvm_range_pages_valid(range->base.gpusvm, &range->base);
|
||||
return drm_gpusvm_pages_valid(range->base.gpusvm, &range->pages);
|
||||
}
|
||||
|
||||
int xe_devm_add(struct xe_tile *tile, struct xe_vram_region *vr);
|
||||
|
|
@ -132,7 +134,7 @@ void *xe_svm_private_page_owner(struct xe_vm *vm, bool force_smem);
|
|||
static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range)
|
||||
{
|
||||
lockdep_assert_held(&range->base.gpusvm->notifier_lock);
|
||||
return range->base.pages.flags.has_dma_mapping;
|
||||
return range->pages.flags.has_dma_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -210,10 +212,10 @@ struct xe_vram_region;
|
|||
struct xe_svm_range {
|
||||
struct {
|
||||
struct interval_tree_node itree;
|
||||
struct {
|
||||
const struct drm_pagemap_addr *dma_addr;
|
||||
} pages;
|
||||
} base;
|
||||
struct {
|
||||
const struct drm_pagemap_addr *dma_addr;
|
||||
} pages;
|
||||
u32 tile_present;
|
||||
u32 tile_invalidated;
|
||||
};
|
||||
|
|
@ -233,7 +235,7 @@ static inline
|
|||
int xe_svm_init(struct xe_vm *vm)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_DRM_GPUSVM)
|
||||
return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
|
||||
return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)",
|
||||
NULL, 0, 0, 0, NULL, NULL, 0);
|
||||
#else
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -390,19 +390,20 @@ int xe_userptr_setup(struct xe_userptr_vma *uvma, unsigned long start,
|
|||
unsigned long range)
|
||||
{
|
||||
struct xe_userptr *userptr = &uvma->userptr;
|
||||
struct xe_vm *vm = xe_vma_vm(&uvma->vma);
|
||||
int err;
|
||||
|
||||
INIT_LIST_HEAD(&userptr->invalidate_link);
|
||||
INIT_LIST_HEAD(&userptr->repin_link);
|
||||
|
||||
drm_gpusvm_init_pages(&userptr->pages, &vm->xe->drm);
|
||||
|
||||
err = mmu_interval_notifier_insert(&userptr->notifier, current->mm,
|
||||
start, range,
|
||||
&vma_userptr_notifier_ops);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
userptr->pages.notifier_seq = LONG_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -173,52 +173,6 @@ struct drm_bridge_funcs {
|
|||
bool (*mode_fixup)(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
/**
|
||||
* @disable:
|
||||
*
|
||||
* This callback should disable the bridge. It is called right before
|
||||
* the preceding element in the display pipe is disabled. If the
|
||||
* preceding element is a bridge this means it's called before that
|
||||
* bridge's @disable vfunc. If the preceding element is a &drm_encoder
|
||||
* it's called right before the &drm_encoder_helper_funcs.disable,
|
||||
* &drm_encoder_helper_funcs.prepare or &drm_encoder_helper_funcs.dpms
|
||||
* hook.
|
||||
*
|
||||
* The bridge can assume that the display pipe (i.e. clocks and timing
|
||||
* signals) feeding it is still running when this callback is called.
|
||||
*
|
||||
* The @disable callback is optional.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* This is deprecated, do not use!
|
||||
* New drivers shall use &drm_bridge_funcs.atomic_disable.
|
||||
*/
|
||||
void (*disable)(struct drm_bridge *bridge);
|
||||
|
||||
/**
|
||||
* @post_disable:
|
||||
*
|
||||
* This callback should disable the bridge. It is called right after the
|
||||
* preceding element in the display pipe is disabled. If the preceding
|
||||
* element is a bridge this means it's called after that bridge's
|
||||
* @post_disable function. If the preceding element is a &drm_encoder
|
||||
* it's called right after the encoder's
|
||||
* &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare
|
||||
* or &drm_encoder_helper_funcs.dpms hook.
|
||||
*
|
||||
* The bridge must assume that the display pipe (i.e. clocks and timing
|
||||
* signals) feeding it is no longer running when this callback is
|
||||
* called.
|
||||
*
|
||||
* The @post_disable callback is optional.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* This is deprecated, do not use!
|
||||
* New drivers shall use &drm_bridge_funcs.atomic_post_disable.
|
||||
*/
|
||||
void (*post_disable)(struct drm_bridge *bridge);
|
||||
|
||||
/**
|
||||
* @mode_set:
|
||||
|
|
@ -249,55 +203,6 @@ struct drm_bridge_funcs {
|
|||
void (*mode_set)(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adjusted_mode);
|
||||
/**
|
||||
* @pre_enable:
|
||||
*
|
||||
* This callback should enable the bridge. It is called right before
|
||||
* the preceding element in the display pipe is enabled. If the
|
||||
* preceding element is a bridge this means it's called before that
|
||||
* bridge's @pre_enable function. If the preceding element is a
|
||||
* &drm_encoder it's called right before the encoder's
|
||||
* &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
|
||||
* &drm_encoder_helper_funcs.dpms hook.
|
||||
*
|
||||
* The display pipe (i.e. clocks and timing signals) feeding this bridge
|
||||
* will not yet be running when this callback is called. The bridge must
|
||||
* not enable the display link feeding the next bridge in the chain (if
|
||||
* there is one) when this callback is called.
|
||||
*
|
||||
* The @pre_enable callback is optional.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* This is deprecated, do not use!
|
||||
* New drivers shall use &drm_bridge_funcs.atomic_pre_enable.
|
||||
*/
|
||||
void (*pre_enable)(struct drm_bridge *bridge);
|
||||
|
||||
/**
|
||||
* @enable:
|
||||
*
|
||||
* This callback should enable the bridge. It is called right after
|
||||
* the preceding element in the display pipe is enabled. If the
|
||||
* preceding element is a bridge this means it's called after that
|
||||
* bridge's @enable function. If the preceding element is a
|
||||
* &drm_encoder it's called right after the encoder's
|
||||
* &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
|
||||
* &drm_encoder_helper_funcs.dpms hook.
|
||||
*
|
||||
* The bridge can assume that the display pipe (i.e. clocks and timing
|
||||
* signals) feeding it is running when this callback is called. This
|
||||
* callback must enable the display link feeding the next bridge in the
|
||||
* chain if there is one.
|
||||
*
|
||||
* The @enable callback is optional.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* This is deprecated, do not use!
|
||||
* New drivers shall use &drm_bridge_funcs.atomic_enable.
|
||||
*/
|
||||
void (*enable)(struct drm_bridge *bridge);
|
||||
|
||||
/**
|
||||
* @atomic_pre_enable:
|
||||
|
|
@ -1359,14 +1264,6 @@ drm_bridge_get_current_state(struct drm_bridge *bridge)
|
|||
if (!bridge)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Only atomic bridges will have bridge->base initialized by
|
||||
* drm_atomic_private_obj_init(), so we need to make sure we're
|
||||
* working with one before we try to use the lock.
|
||||
*/
|
||||
if (!bridge->funcs || !bridge->funcs->atomic_create_state)
|
||||
return NULL;
|
||||
|
||||
drm_modeset_lock_assert_held(&bridge->base.lock);
|
||||
|
||||
if (!bridge->base.state)
|
||||
|
|
@ -1474,9 +1371,9 @@ static inline struct drm_bridge *__drm_for_each_bridge_in_chain_next(struct drm_
|
|||
DEFINE_FREE(__drm_for_each_bridge_in_chain_cleanup, struct drm_bridge *,
|
||||
if (_T) { mutex_unlock(&_T->encoder->bridge_chain_mutex); drm_bridge_put(_T); })
|
||||
|
||||
/* Internal to drm_for_each_bridge_in_chain_scoped() */
|
||||
/* Internal to drm_for_each_bridge_in_chain() */
|
||||
static inline struct drm_bridge *
|
||||
__drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder)
|
||||
__drm_for_each_bridge_in_chain_start(struct drm_encoder *encoder)
|
||||
{
|
||||
mutex_lock(&encoder->bridge_chain_mutex);
|
||||
|
||||
|
|
@ -1489,8 +1386,7 @@ __drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder)
|
|||
}
|
||||
|
||||
/**
|
||||
* drm_for_each_bridge_in_chain_scoped - iterate over all bridges attached
|
||||
* to an encoder
|
||||
* drm_for_each_bridge_in_chain - iterate over all bridges attached to an encoder
|
||||
* @encoder: the encoder to iterate bridges on
|
||||
* @bridge: a bridge pointer updated to point to the current bridge at each
|
||||
* iteration
|
||||
|
|
@ -1500,9 +1396,9 @@ __drm_for_each_bridge_in_chain_scoped_start(struct drm_encoder *encoder)
|
|||
* Automatically gets/puts the bridge reference while iterating and locks
|
||||
* the encoder chain mutex to prevent chain modifications while iterating.
|
||||
*/
|
||||
#define drm_for_each_bridge_in_chain_scoped(encoder, bridge) \
|
||||
#define drm_for_each_bridge_in_chain(encoder, bridge) \
|
||||
for (struct drm_bridge *bridge __free(__drm_for_each_bridge_in_chain_cleanup) = \
|
||||
__drm_for_each_bridge_in_chain_scoped_start((encoder)); \
|
||||
__drm_for_each_bridge_in_chain_start((encoder)); \
|
||||
bridge; \
|
||||
bridge = __drm_for_each_bridge_in_chain_next(bridge)) \
|
||||
|
||||
|
|
|
|||
|
|
@ -109,9 +109,7 @@ struct drm_gpusvm_notifier {
|
|||
/**
|
||||
* struct drm_gpusvm_pages_flags - Structure representing a GPU SVM pages flags
|
||||
*
|
||||
* @migrate_devmem: Flag indicating whether the pages can be migrated to device memory
|
||||
* @unmapped: Flag indicating if the pages has been unmapped
|
||||
* @partial_unmap: Flag indicating if the pages has been partially unmapped
|
||||
* @has_devmem_pages: Flag indicating if the pages has devmem pages
|
||||
* @has_dma_mapping: Flag indicating if the pages has a DMA mapping
|
||||
* @__flags: Flags for pages in u16 form (used for READ_ONCE)
|
||||
|
|
@ -119,11 +117,8 @@ struct drm_gpusvm_notifier {
|
|||
struct drm_gpusvm_pages_flags {
|
||||
union {
|
||||
struct {
|
||||
/* All flags below must be set upon creation */
|
||||
u16 migrate_devmem : 1;
|
||||
/* All flags below must be set / cleared under notifier lock */
|
||||
u16 unmapped : 1;
|
||||
u16 partial_unmap : 1;
|
||||
u16 has_devmem_pages : 1;
|
||||
u16 has_dma_mapping : 1;
|
||||
};
|
||||
|
|
@ -134,6 +129,7 @@ struct drm_gpusvm_pages_flags {
|
|||
/**
|
||||
* struct drm_gpusvm_pages - Structure representing a GPU SVM mapped pages
|
||||
*
|
||||
* @drm: The DRM device that owns the dma mappings
|
||||
* @dma_addr: Device address array
|
||||
* @dpagemap: The struct drm_pagemap of the device pages we're dma-mapping.
|
||||
* Note this is assuming only one drm_pagemap per range is allowed.
|
||||
|
|
@ -143,6 +139,7 @@ struct drm_gpusvm_pages_flags {
|
|||
* @flags: Flags for the range; see &struct drm_gpusvm_pages_flags
|
||||
*/
|
||||
struct drm_gpusvm_pages {
|
||||
struct drm_device *drm;
|
||||
struct drm_pagemap_addr *dma_addr;
|
||||
struct drm_pagemap *dpagemap;
|
||||
struct dma_iova_state state;
|
||||
|
|
@ -151,6 +148,27 @@ struct drm_gpusvm_pages {
|
|||
struct drm_gpusvm_pages_flags flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_gpusvm_range_flags - Range-level GPU SVM flags
|
||||
*
|
||||
* @migrate_devmem: Flag indicating whether the range can be migrated to device memory
|
||||
* @unmapped: Flag indicating if the range has been unmapped
|
||||
* @partial_unmap: Flag indicating if the range has been partially unmapped
|
||||
* @__flags: All flags in u16 form (used for READ_ONCE)
|
||||
*/
|
||||
struct drm_gpusvm_range_flags {
|
||||
union {
|
||||
struct {
|
||||
/* All flags below must be set upon creation */
|
||||
u16 migrate_devmem : 1;
|
||||
/* All flags below must be set / cleared under notifier lock */
|
||||
u16 unmapped : 1;
|
||||
u16 partial_unmap : 1;
|
||||
};
|
||||
u16 __flags;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_gpusvm_range - Structure representing a GPU SVM range
|
||||
*
|
||||
|
|
@ -159,7 +177,7 @@ struct drm_gpusvm_pages {
|
|||
* @refcount: Reference count for the range
|
||||
* @itree: Interval tree node for the range (inserted in GPU SVM notifier)
|
||||
* @entry: List entry to fast interval tree traversal
|
||||
* @pages: The pages for this range.
|
||||
* @flags: Flags for range see &struct drm_gpusvm_range_flags
|
||||
*
|
||||
* This structure represents a GPU SVM range used for tracking memory ranges
|
||||
* mapped in a DRM device.
|
||||
|
|
@ -170,14 +188,13 @@ struct drm_gpusvm_range {
|
|||
struct kref refcount;
|
||||
struct interval_tree_node itree;
|
||||
struct list_head entry;
|
||||
struct drm_gpusvm_pages pages;
|
||||
struct drm_gpusvm_range_flags flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_gpusvm - GPU SVM structure
|
||||
*
|
||||
* @name: Name of the GPU SVM
|
||||
* @drm: Pointer to the DRM device structure
|
||||
* @mm: Pointer to the mm_struct for the address space
|
||||
* @mm_start: Start address of GPU SVM
|
||||
* @mm_range: Range of the GPU SVM
|
||||
|
|
@ -201,7 +218,6 @@ struct drm_gpusvm_range {
|
|||
*/
|
||||
struct drm_gpusvm {
|
||||
const char *name;
|
||||
struct drm_device *drm;
|
||||
struct mm_struct *mm;
|
||||
unsigned long mm_start;
|
||||
unsigned long mm_range;
|
||||
|
|
@ -253,7 +269,7 @@ struct drm_gpusvm_ctx {
|
|||
};
|
||||
|
||||
int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
|
||||
const char *name, struct drm_device *drm,
|
||||
const char *name,
|
||||
struct mm_struct *mm,
|
||||
unsigned long mm_start, unsigned long mm_range,
|
||||
unsigned long notifier_size,
|
||||
|
|
@ -287,16 +303,8 @@ drm_gpusvm_range_get(struct drm_gpusvm_range *range);
|
|||
|
||||
void drm_gpusvm_range_put(struct drm_gpusvm_range *range);
|
||||
|
||||
bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range);
|
||||
|
||||
int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range,
|
||||
const struct drm_gpusvm_ctx *ctx);
|
||||
|
||||
void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_range *range,
|
||||
const struct drm_gpusvm_ctx *ctx);
|
||||
bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
|
||||
struct drm_gpusvm_pages *svm_pages);
|
||||
|
||||
bool drm_gpusvm_has_mapping(struct drm_gpusvm *gpusvm, unsigned long start,
|
||||
unsigned long end);
|
||||
|
|
@ -310,6 +318,8 @@ drm_gpusvm_range_find(struct drm_gpusvm_notifier *notifier, unsigned long start,
|
|||
unsigned long end);
|
||||
|
||||
void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
|
||||
struct drm_gpusvm_pages *pages,
|
||||
unsigned int pages_count,
|
||||
const struct mmu_notifier_range *mmu_range);
|
||||
|
||||
int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
|
||||
|
|
@ -328,6 +338,23 @@ void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
|
|||
struct drm_gpusvm_pages *svm_pages,
|
||||
unsigned long npages);
|
||||
|
||||
/**
|
||||
* drm_gpusvm_init_pages() - Initialize a freshly allocated drm_gpusvm_pages
|
||||
* @svm_pages: Pointer to the drm_gpusvm_pages to initialize.
|
||||
* @drm: The DRM device that will own DMA mappings for this pages object.
|
||||
*
|
||||
* Drivers that embed one or more drm_gpusvm_pages in their own range
|
||||
* structure must call this once on each pages instance after allocation,
|
||||
* before the first drm_gpusvm_get_pages() / unmap / free.
|
||||
*/
|
||||
static inline void drm_gpusvm_init_pages(struct drm_gpusvm_pages *svm_pages,
|
||||
struct drm_device *drm)
|
||||
{
|
||||
memset(svm_pages, 0, sizeof(*svm_pages));
|
||||
svm_pages->drm = drm;
|
||||
svm_pages->notifier_seq = LONG_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* enum drm_gpusvm_scan_result - Scan result from the drm_gpusvm_scan_mm() function.
|
||||
* @DRM_GPUSVM_SCAN_UNPOPULATED: At least one page was not present or inaccessible.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user