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:
Dave Airlie 2026-07-17 10:40:39 +10:00
commit 2e33bfe53c
63 changed files with 726 additions and 616 deletions

View File

@ -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'

View File

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

View File

@ -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)

View File

@ -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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -457,7 +457,8 @@ static void lt8912_bridge_mode_set(struct drm_bridge *bridge,
drm_display_mode_to_videomode(adj, &lt->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,
};

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

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

View File

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

View File

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

View File

@ -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))

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

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

View File

@ -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) {

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

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

View File

@ -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)

View File

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

View File

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

View File

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

View File

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

View File

@ -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,

View File

@ -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))

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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,

View File

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

View File

@ -297,6 +297,7 @@ r535_fbsr = {
static void *
r535_instmem_dtor(struct nvkm_instmem *imem)
{
nv50_instmem_dtor(imem);
kfree(imem->func);
return imem;
}

View File

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

View File

@ -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 *);

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

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

View File

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

View File

@ -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)

View File

@ -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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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)) \

View File

@ -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.