summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/vc4
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vc4')
-rw-r--r--drivers/gpu/drm/vc4/Kconfig2
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock.h4
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_mock_output.c66
-rw-r--r--drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c200
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c19
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c49
-rw-r--r--drivers/gpu/drm/vc4/vc4_debugfs.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_dpi.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c5
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h60
-rw-r--r--drivers/gpu/drm/vc4/vc4_dsi.c47
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c220
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c436
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.h10
-rw-r--r--drivers/gpu/drm/vc4/vc4_hvs.c11
-rw-r--r--drivers/gpu/drm/vc4/vc4_irq.c34
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c105
-rw-r--r--drivers/gpu/drm/vc4/vc4_perfmon.c56
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c21
-rw-r--r--drivers/gpu/drm/vc4/vc4_render_cl.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_txp.c14
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c3
-rw-r--r--drivers/gpu/drm/vc4/vc4_validate.c14
-rw-r--r--drivers/gpu/drm/vc4/vc4_validate_shaders.c17
-rw-r--r--drivers/gpu/drm/vc4/vc4_vec.c17
25 files changed, 744 insertions, 672 deletions
diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
index 6cc7b7e6294a..bb8c40be3250 100644
--- a/drivers/gpu/drm/vc4/Kconfig
+++ b/drivers/gpu/drm/vc4/Kconfig
@@ -14,6 +14,7 @@ config DRM_VC4
select DRM_DISPLAY_HDMI_HELPER
select DRM_DISPLAY_HDMI_STATE_HELPER
select DRM_DISPLAY_HELPER
+ select DRM_EXEC
select DRM_KMS_HELPER
select DRM_GEM_DMA_HELPER
select DRM_PANEL_BRIDGE
@@ -34,6 +35,7 @@ config DRM_VC4_HDMI_CEC
bool "Broadcom VC4 HDMI CEC Support"
depends on DRM_VC4
select CEC_CORE
+ select DRM_DISPLAY_HDMI_CEC_HELPER
help
Choose this option if you have a Broadcom VC4 GPU
and want to use CEC.
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
index 002b6218960c..3cc4b4a0feed 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
@@ -52,10 +52,10 @@ struct vc4_dev *vc4_mock_device(struct kunit *test);
struct vc4_dev *vc5_mock_device(struct kunit *test);
int vc4_mock_atomic_add_output(struct kunit *test,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
enum vc4_encoder_type type);
int vc4_mock_atomic_del_output(struct kunit *test,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
enum vc4_encoder_type type);
#endif // VC4_MOCK_H_
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
index e70d7c3076ac..b53c3635ce67 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
@@ -61,8 +61,21 @@ static const struct drm_display_mode default_mode = {
DRM_SIMPLE_MODE(640, 480, 64, 48)
};
+/**
+ * vc4_mock_atomic_add_output() - Enables an output in a state
+ * @test: The test context object
+ * @state: Atomic state to enable the output in.
+ * @type: Type of the output encoder
+ *
+ * Adds an output CRTC and connector to a state, and enables them.
+ *
+ * Returns:
+ * 0 on success, a negative error code on failure. If the error is
+ * EDEADLK, the entire atomic sequence must be restarted. All other
+ * errors are fatal.
+ */
int vc4_mock_atomic_add_output(struct kunit *test,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
enum vc4_encoder_type type)
{
struct drm_device *drm = state->dev;
@@ -75,32 +88,51 @@ int vc4_mock_atomic_add_output(struct kunit *test,
int ret;
encoder = vc4_find_encoder_by_type(drm, type);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+ if (!encoder)
+ return -ENODEV;
crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ if (!crtc)
+ return -ENODEV;
output = encoder_to_vc4_dummy_output(encoder);
conn = &output->connector;
conn_state = drm_atomic_get_connector_state(state, conn);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+ if (IS_ERR(conn_state))
+ return PTR_ERR(conn_state);
ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
- KUNIT_EXPECT_EQ(test, ret, 0);
+ if (ret)
+ return ret;
crtc_state = drm_atomic_get_crtc_state(state, crtc);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
ret = drm_atomic_set_mode_for_crtc(crtc_state, &default_mode);
- KUNIT_EXPECT_EQ(test, ret, 0);
+ if (ret)
+ return ret;
crtc_state->active = true;
return 0;
}
+/**
+ * vc4_mock_atomic_del_output() - Disables an output in a state
+ * @test: The test context object
+ * @state: Atomic state to disable the output in.
+ * @type: Type of the output encoder
+ *
+ * Adds an output CRTC and connector to a state, and disables them.
+ *
+ * Returns:
+ * 0 on success, a negative error code on failure. If the error is
+ * EDEADLK, the entire atomic sequence must be restarted. All other
+ * errors are fatal.
+ */
int vc4_mock_atomic_del_output(struct kunit *test,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
enum vc4_encoder_type type)
{
struct drm_device *drm = state->dev;
@@ -113,26 +145,32 @@ int vc4_mock_atomic_del_output(struct kunit *test,
int ret;
encoder = vc4_find_encoder_by_type(drm, type);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+ if (!encoder)
+ return -ENODEV;
crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+ if (!crtc)
+ return -ENODEV;
crtc_state = drm_atomic_get_crtc_state(state, crtc);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
crtc_state->active = false;
ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
- KUNIT_ASSERT_EQ(test, ret, 0);
+ if (ret)
+ return ret;
output = encoder_to_vc4_dummy_output(encoder);
conn = &output->connector;
conn_state = drm_atomic_get_connector_state(state, conn);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+ if (IS_ERR(conn_state))
+ return PTR_ERR(conn_state);
ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
- KUNIT_ASSERT_EQ(test, ret, 0);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
index 40a05869a50e..7a54f46acff9 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
@@ -20,11 +20,10 @@
struct pv_muxing_priv {
struct vc4_dev *vc4;
- struct drm_atomic_state *state;
};
static bool check_fifo_conflict(struct kunit *test,
- const struct drm_atomic_state *state)
+ const struct drm_atomic_commit *state)
{
struct vc4_hvs_state *hvs_state;
unsigned int used_fifos = 0;
@@ -120,7 +119,7 @@ static bool check_vc5_encoder_constraints(enum vc4_encoder_type type, unsigned i
static struct vc4_crtc_state *
get_vc4_crtc_state_for_encoder(struct kunit *test,
- const struct drm_atomic_state *state,
+ const struct drm_atomic_commit *state,
enum vc4_encoder_type type)
{
struct drm_device *drm = state->dev;
@@ -142,7 +141,7 @@ get_vc4_crtc_state_for_encoder(struct kunit *test,
}
static bool check_channel_for_encoder(struct kunit *test,
- const struct drm_atomic_state *state,
+ const struct drm_atomic_commit *state,
enum vc4_encoder_type type,
bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel))
{
@@ -677,18 +676,41 @@ static void drm_vc4_test_pv_muxing(struct kunit *test)
{
const struct pv_muxing_param *params = test->param_value;
const struct pv_muxing_priv *priv = test->priv;
- struct drm_atomic_state *state = priv->state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
unsigned int i;
int ret;
+ drm_modeset_acquire_init(&ctx, 0);
+
+ vc4 = priv->vc4;
+ drm = &vc4->base;
+
+retry:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
for (i = 0; i < params->nencoders; i++) {
enum vc4_encoder_type enc_type = params->encoders[i];
ret = vc4_mock_atomic_add_output(test, state, enc_type);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
}
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_TRUE(test,
@@ -700,33 +722,61 @@ static void drm_vc4_test_pv_muxing(struct kunit *test)
KUNIT_EXPECT_TRUE(test, check_channel_for_encoder(test, state, enc_type,
params->check_fn));
}
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
}
static void drm_vc4_test_pv_muxing_invalid(struct kunit *test)
{
const struct pv_muxing_param *params = test->param_value;
const struct pv_muxing_priv *priv = test->priv;
- struct drm_atomic_state *state = priv->state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
unsigned int i;
int ret;
+ drm_modeset_acquire_init(&ctx, 0);
+
+ vc4 = priv->vc4;
+ drm = &vc4->base;
+
+retry:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
for (i = 0; i < params->nencoders; i++) {
enum vc4_encoder_type enc_type = params->encoders[i];
ret = vc4_mock_atomic_add_output(test, state, enc_type);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
}
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry;
+ }
KUNIT_EXPECT_LT(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
}
static int vc4_pv_muxing_test_init(struct kunit *test)
{
const struct pv_muxing_param *params = test->param_value;
- struct drm_modeset_acquire_ctx *ctx;
struct pv_muxing_priv *priv;
- struct drm_device *drm;
struct vc4_dev *vc4;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
@@ -737,13 +787,6 @@ static int vc4_pv_muxing_test_init(struct kunit *test)
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
priv->vc4 = vc4;
- ctx = drm_kunit_helper_acquire_ctx_alloc(test);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
-
- drm = &vc4->base;
- priv->state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->state);
-
return 0;
}
@@ -782,8 +825,8 @@ static struct kunit_suite vc5_pv_muxing_test_suite = {
*/
static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *test)
{
- struct drm_modeset_acquire_ctx *ctx;
- struct drm_atomic_state *state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
struct vc4_crtc_state *new_vc4_crtc_state;
struct vc4_hvs_state *new_hvs_state;
unsigned int hdmi0_channel;
@@ -795,17 +838,29 @@ static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *tes
vc4 = vc5_mock_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
- ctx = drm_kunit_helper_acquire_ctx_alloc(test);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ drm_modeset_acquire_init(&ctx, 0);
drm = &vc4->base;
- state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+retry_first:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
new_hvs_state = vc4_hvs_get_new_global_state(state);
@@ -822,13 +877,26 @@ static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *tes
ret = drm_atomic_helper_swap_state(state, false);
KUNIT_ASSERT_EQ(test, ret, 0);
- state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+retry_second:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
new_hvs_state = vc4_hvs_get_new_global_state(state);
@@ -843,6 +911,9 @@ static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *tes
KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
KUNIT_EXPECT_NE(test, hdmi0_channel, hdmi1_channel);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
}
/*
@@ -854,8 +925,8 @@ static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *tes
*/
static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
{
- struct drm_modeset_acquire_ctx *ctx;
- struct drm_atomic_state *state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
struct vc4_crtc_state *new_vc4_crtc_state;
struct vc4_hvs_state *new_hvs_state;
unsigned int old_hdmi0_channel;
@@ -867,20 +938,38 @@ static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
vc4 = vc5_mock_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
- ctx = drm_kunit_helper_acquire_ctx_alloc(test);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ drm_modeset_acquire_init(&ctx, 0);
drm = &vc4->base;
- state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+retry_first:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
new_hvs_state = vc4_hvs_get_new_global_state(state);
@@ -905,13 +994,26 @@ static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
ret = drm_atomic_helper_swap_state(state, false);
KUNIT_ASSERT_EQ(test, ret, 0);
- state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+retry_second:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
ret = vc4_mock_atomic_del_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
new_hvs_state = vc4_hvs_get_new_global_state(state);
@@ -929,6 +1031,9 @@ static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
KUNIT_EXPECT_EQ(test, old_hdmi1_channel, hdmi1_channel);
}
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
}
/*
@@ -949,8 +1054,8 @@ static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
static void
drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct kunit *test)
{
- struct drm_modeset_acquire_ctx *ctx;
- struct drm_atomic_state *state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_commit *state;
struct vc4_crtc_state *new_vc4_crtc_state;
struct drm_device *drm;
struct vc4_dev *vc4;
@@ -959,34 +1064,61 @@ drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct ku
vc4 = vc5_mock_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
- ctx = drm_kunit_helper_acquire_ctx_alloc(test);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
+ drm_modeset_acquire_init(&ctx, 0);
drm = &vc4->base;
- state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+retry_first:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_first;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
-
ret = drm_atomic_helper_swap_state(state, false);
KUNIT_ASSERT_EQ(test, ret, 0);
- state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+retry_second:
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
ret = drm_atomic_check_only(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_commit_clear(state);
+ ret = drm_modeset_backoff(&ctx);
+ if (!ret)
+ goto retry_second;
+ }
KUNIT_ASSERT_EQ(test, ret, 0);
new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
VC4_ENCODER_TYPE_HDMI0);
KUNIT_EXPECT_NULL(test, new_vc4_crtc_state);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
}
static struct kunit_case vc5_pv_muxing_bugs_tests[] = {
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index fb450b6a4d44..2161761b1f22 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -19,9 +19,9 @@
#include <linux/dma-buf.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_print.h>
#include "vc4_drv.h"
-#include "uapi/drm/vc4_drm.h"
static const struct drm_gem_object_funcs vc4_gem_object_funcs;
@@ -204,8 +204,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct drm_device *dev,
struct list_head *new_list;
uint32_t i;
- new_list = kmalloc_array(new_size, sizeof(struct list_head),
- GFP_KERNEL);
+ new_list = kmalloc_objs(struct list_head, new_size);
if (!new_list)
return NULL;
@@ -399,7 +398,7 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size)
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return ERR_PTR(-ENODEV);
- bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+ bo = kzalloc_obj(*bo);
if (!bo)
return ERR_PTR(-ENOMEM);
@@ -556,7 +555,7 @@ static void vc4_free_object(struct drm_gem_object *gem_bo)
mutex_lock(&vc4->bo_lock);
/* If the object references someone else's memory, we can't cache it.
*/
- if (gem_bo->import_attach) {
+ if (drm_gem_is_imported(gem_bo)) {
vc4_bo_destroy(bo);
goto out;
}
@@ -679,7 +678,7 @@ void vc4_bo_dec_usecnt(struct vc4_bo *bo)
static void vc4_bo_cache_time_timer(struct timer_list *t)
{
- struct vc4_dev *vc4 = from_timer(vc4, t, bo_cache.time_timer);
+ struct vc4_dev *vc4 = timer_container_of(vc4, t, bo_cache.time_timer);
schedule_work(&vc4->bo_cache.time_work);
}
@@ -738,12 +737,15 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
return -EINVAL;
}
+ mutex_lock(&bo->madv_lock);
if (bo->madv != VC4_MADV_WILLNEED) {
DRM_DEBUG("mmapping of %s BO not allowed\n",
bo->madv == VC4_MADV_DONTNEED ?
"purgeable" : "purged");
+ mutex_unlock(&bo->madv_lock);
return -EINVAL;
}
+ mutex_unlock(&bo->madv_lock);
return drm_gem_dma_mmap(&bo->base, vma);
}
@@ -1014,8 +1016,7 @@ int vc4_bo_cache_init(struct drm_device *dev)
* use. This lets us avoid a bunch of string reallocation in
* the kernel's draw and BO allocation paths.
*/
- vc4->bo_labels = kcalloc(VC4_BO_TYPE_COUNT, sizeof(*vc4->bo_labels),
- GFP_KERNEL);
+ vc4->bo_labels = kzalloc_objs(*vc4->bo_labels, VC4_BO_TYPE_COUNT);
if (!vc4->bo_labels)
return -ENOMEM;
vc4->num_labels = VC4_BO_TYPE_COUNT;
@@ -1043,7 +1044,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, void *unused)
struct vc4_dev *vc4 = to_vc4_dev(dev);
int i;
- del_timer(&vc4->bo_cache.time_timer);
+ timer_delete(&vc4->bo_cache.time_timer);
cancel_work_sync(&vc4->bo_cache.time_work);
vc4_bo_cache_purge(dev);
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index cf40a53ad42e..4572b0b9bae1 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -343,7 +343,7 @@ static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc)
}
static void vc4_crtc_config_pv(struct drm_crtc *crtc, struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -497,7 +497,7 @@ static void require_hvs_enabled(struct drm_device *dev)
static int vc4_crtc_disable(struct drm_crtc *crtc,
struct drm_encoder *encoder,
- struct drm_atomic_state *state,
+ struct drm_atomic_commit *state,
unsigned int channel)
{
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
@@ -622,7 +622,7 @@ void vc4_crtc_send_vblank(struct drm_crtc *crtc)
}
static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
crtc);
@@ -648,7 +648,7 @@ static void vc4_crtc_atomic_disable(struct drm_crtc *crtc,
}
static void vc4_crtc_atomic_enable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_crtc_state *new_state = drm_atomic_get_new_crtc_state(state,
crtc);
@@ -740,7 +740,7 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state,
}
int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc);
@@ -884,11 +884,7 @@ struct vc4_async_flip_state {
struct drm_framebuffer *fb;
struct drm_framebuffer *old_fb;
struct drm_pending_vblank_event *event;
-
- union {
- struct dma_fence_cb fence;
- struct vc4_seqno_cb seqno;
- } cb;
+ struct dma_fence_cb cb;
};
/* Called when the V3D execution for the BO being flipped to is done, so that
@@ -919,10 +915,11 @@ vc4_async_page_flip_complete(struct vc4_async_flip_state *flip_state)
kfree(flip_state);
}
-static void vc4_async_page_flip_seqno_complete(struct vc4_seqno_cb *cb)
+static void vc4_async_page_flip_complete_with_cleanup(struct dma_fence *fence,
+ struct dma_fence_cb *cb)
{
struct vc4_async_flip_state *flip_state =
- container_of(cb, struct vc4_async_flip_state, cb.seqno);
+ container_of(cb, struct vc4_async_flip_state, cb);
struct vc4_bo *bo = NULL;
if (flip_state->old_fb) {
@@ -932,6 +929,7 @@ static void vc4_async_page_flip_seqno_complete(struct vc4_seqno_cb *cb)
}
vc4_async_page_flip_complete(flip_state);
+ dma_fence_put(fence);
/*
* Decrement the BO usecnt in order to keep the inc/dec
@@ -950,7 +948,7 @@ static void vc4_async_page_flip_fence_complete(struct dma_fence *fence,
struct dma_fence_cb *cb)
{
struct vc4_async_flip_state *flip_state =
- container_of(cb, struct vc4_async_flip_state, cb.fence);
+ container_of(cb, struct vc4_async_flip_state, cb);
vc4_async_page_flip_complete(flip_state);
dma_fence_put(fence);
@@ -961,16 +959,15 @@ static int vc4_async_set_fence_cb(struct drm_device *dev,
{
struct drm_framebuffer *fb = flip_state->fb;
struct drm_gem_dma_object *dma_bo = drm_fb_dma_get_gem_obj(fb, 0);
+ dma_fence_func_t async_page_flip_complete_function;
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct dma_fence *fence;
int ret;
- if (vc4->gen == VC4_GEN_4) {
- struct vc4_bo *bo = to_vc4_bo(&dma_bo->base);
-
- return vc4_queue_seqno_cb(dev, &flip_state->cb.seqno, bo->seqno,
- vc4_async_page_flip_seqno_complete);
- }
+ if (vc4->gen == VC4_GEN_4)
+ async_page_flip_complete_function = vc4_async_page_flip_complete_with_cleanup;
+ else
+ async_page_flip_complete_function = vc4_async_page_flip_fence_complete;
ret = dma_resv_get_singleton(dma_bo->base.resv, DMA_RESV_USAGE_READ, &fence);
if (ret)
@@ -978,14 +975,14 @@ static int vc4_async_set_fence_cb(struct drm_device *dev,
/* If there's no fence, complete the page flip immediately */
if (!fence) {
- vc4_async_page_flip_fence_complete(fence, &flip_state->cb.fence);
+ async_page_flip_complete_function(fence, &flip_state->cb);
return 0;
}
/* If the fence has already been completed, complete the page flip */
- if (dma_fence_add_callback(fence, &flip_state->cb.fence,
- vc4_async_page_flip_fence_complete))
- vc4_async_page_flip_fence_complete(fence, &flip_state->cb.fence);
+ if (dma_fence_add_callback(fence, &flip_state->cb,
+ async_page_flip_complete_function))
+ async_page_flip_complete_function(fence, &flip_state->cb);
return 0;
}
@@ -1000,7 +997,7 @@ vc4_async_page_flip_common(struct drm_crtc *crtc,
struct drm_plane *plane = crtc->primary;
struct vc4_async_flip_state *flip_state;
- flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL);
+ flip_state = kzalloc_obj(*flip_state);
if (!flip_state)
return -ENOMEM;
@@ -1108,7 +1105,7 @@ struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct vc4_crtc_state *vc4_state, *old_vc4_state;
- vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
+ vc4_state = kzalloc_obj(*vc4_state);
if (!vc4_state)
return NULL;
@@ -1145,7 +1142,7 @@ void vc4_crtc_reset(struct drm_crtc *crtc)
if (crtc->state)
vc4_crtc_destroy_state(crtc, crtc->state);
- vc4_crtc_state = kzalloc(sizeof(*vc4_crtc_state), GFP_KERNEL);
+ vc4_crtc_state = kzalloc_obj(*vc4_crtc_state);
if (!vc4_crtc_state) {
crtc->state = NULL;
return;
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index fac624a663ea..e765904e13f3 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -4,6 +4,7 @@
*/
#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
#include <linux/seq_file.h>
#include <linux/circ_buf.h>
diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
index 960550c166d9..53f36626a50d 100644
--- a/drivers/gpu/drm/vc4/vc4_dpi.c
+++ b/drivers/gpu/drm/vc4/vc4_dpi.c
@@ -17,12 +17,12 @@
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/media-bus-format.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include "vc4_drv.h"
#include "vc4_regs.h"
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index c7cb1e3a6434..616caf9d9915 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -36,12 +36,11 @@
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_dma.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
-#include "uapi/drm/vc4_drm.h"
-
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -151,7 +150,7 @@ static int vc4_open(struct drm_device *dev, struct drm_file *file)
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return -ENODEV;
- vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL);
+ vc4file = kzalloc_obj(*vc4file);
if (!vc4file)
return -ENOMEM;
vc4file->dev = vc4;
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 4a078ffd9f82..0f5958c1e6b6 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -186,11 +186,6 @@ struct vc4_dev {
*/
struct vc4_perfmon *active_perfmon;
- /* List of struct vc4_seqno_cb for callbacks to be made from a
- * workqueue when the given seqno is passed.
- */
- struct list_head seqno_cb_list;
-
/* The memory used for storing binner tile alloc, tile state,
* and overflow memory allocations. This is freed when V3D
* powers down.
@@ -247,16 +242,6 @@ struct vc4_dev {
struct vc4_bo {
struct drm_gem_dma_object base;
- /* seqno of the last job to render using this BO. */
- uint64_t seqno;
-
- /* seqno of the last job to use the RCL to write to this BO.
- *
- * Note that this doesn't include binner overflow memory
- * writes.
- */
- uint64_t write_seqno;
-
bool t_format;
/* List entry for the BO's position in either
@@ -304,12 +289,6 @@ struct vc4_fence {
#define to_vc4_fence(_fence) \
container_of_const(_fence, struct vc4_fence, base)
-struct vc4_seqno_cb {
- struct work_struct work;
- uint64_t seqno;
- void (*func)(struct vc4_seqno_cb *cb);
-};
-
struct vc4_v3d {
struct vc4_dev *vc4;
struct platform_device *pdev;
@@ -396,9 +375,9 @@ struct vc4_hvs_state {
#define to_vc4_hvs_state(_state) \
container_of_const(_state, struct vc4_hvs_state, base)
-struct vc4_hvs_state *vc4_hvs_get_global_state(struct drm_atomic_state *state);
-struct vc4_hvs_state *vc4_hvs_get_old_global_state(const struct drm_atomic_state *state);
-struct vc4_hvs_state *vc4_hvs_get_new_global_state(const struct drm_atomic_state *state);
+struct vc4_hvs_state *vc4_hvs_get_global_state(struct drm_atomic_commit *state);
+struct vc4_hvs_state *vc4_hvs_get_old_global_state(const struct drm_atomic_commit *state);
+struct vc4_hvs_state *vc4_hvs_get_new_global_state(const struct drm_atomic_commit *state);
struct vc4_plane {
struct drm_plane base;
@@ -499,12 +478,12 @@ struct vc4_encoder {
enum vc4_encoder_type type;
u32 clock_select;
- void (*pre_crtc_configure)(struct drm_encoder *encoder, struct drm_atomic_state *state);
- void (*pre_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_state *state);
- void (*post_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_state *state);
+ void (*pre_crtc_configure)(struct drm_encoder *encoder, struct drm_atomic_commit *state);
+ void (*pre_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_commit *state);
+ void (*post_crtc_enable)(struct drm_encoder *encoder, struct drm_atomic_commit *state);
- void (*post_crtc_disable)(struct drm_encoder *encoder, struct drm_atomic_state *state);
- void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state);
+ void (*post_crtc_disable)(struct drm_encoder *encoder, struct drm_atomic_commit *state);
+ void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_commit *state);
};
#define to_vc4_encoder(_encoder) \
@@ -695,9 +674,6 @@ struct vc4_exec_info {
/* Sequence number for this bin/render job. */
uint64_t seqno;
- /* Latest write_seqno of any BO that binning depends on. */
- uint64_t bin_dep_seqno;
-
struct dma_fence *fence;
/* Last current addresses the hardware was processing when the
@@ -815,10 +791,7 @@ struct vc4_exec_info {
struct vc4_file {
struct vc4_dev *dev;
- struct {
- struct idr idr;
- struct mutex lock;
- } perfmon;
+ struct xarray perfmons;
bool bin_bo_used;
};
@@ -972,7 +945,7 @@ int vc4_page_flip(struct drm_crtc *crtc,
uint32_t flags,
struct drm_modeset_acquire_ctx *ctx);
int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *state);
+ struct drm_atomic_commit *state);
struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc);
void vc4_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
@@ -1025,9 +998,6 @@ void vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec);
int vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno,
uint64_t timeout_ns, bool interruptible);
void vc4_job_handle_completed(struct vc4_dev *vc4);
-int vc4_queue_seqno_cb(struct drm_device *dev,
- struct vc4_seqno_cb *cb, uint64_t seqno,
- void (*func)(struct vc4_seqno_cb *cb));
int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -1055,11 +1025,11 @@ struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4,
void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output);
int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output);
u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo);
-int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state);
-void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state);
-void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state);
-void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state);
-void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state);
+int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *state);
+void vc4_hvs_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_commit *state);
+void vc4_hvs_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_commit *state);
+void vc4_hvs_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_commit *state);
+void vc4_hvs_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_commit *state);
void vc4_hvs_dump_state(struct vc4_hvs *hvs);
void vc4_hvs_unmask_underrun(struct vc4_hvs *hvs, int channel);
void vc4_hvs_mask_underrun(struct vc4_hvs *hvs, int channel);
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 5eb293bdb363..fc76018b044c 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -36,6 +36,7 @@
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -552,8 +553,6 @@ struct vc4_dsi {
struct vc4_encoder encoder;
struct mipi_dsi_host dsi_host;
- struct kref kref;
-
struct platform_device *pdev;
struct drm_bridge *out_bridge;
@@ -800,7 +799,7 @@ dsi_esc_timing(u32 ns)
}
static void vc4_dsi_bridge_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
u32 disp0_ctrl;
@@ -811,7 +810,7 @@ static void vc4_dsi_bridge_disable(struct drm_bridge *bridge,
}
static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
struct device *dev = &dsi->pdev->dev;
@@ -873,9 +872,8 @@ static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
}
static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_state)
+ struct drm_atomic_commit *state)
{
- struct drm_atomic_state *state = old_state->base.state;
struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
const struct drm_crtc_state *crtc_state;
struct device *dev = &dsi->pdev->dev;
@@ -1143,7 +1141,7 @@ static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge,
}
static void vc4_dsi_bridge_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *old_state)
+ struct drm_atomic_commit *state)
{
struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
bool debug_dump_regs = false;
@@ -1161,12 +1159,13 @@ static void vc4_dsi_bridge_enable(struct drm_bridge *bridge,
}
static int vc4_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
/* Attach the panel or bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, dsi->out_bridge,
+ return drm_bridge_attach(encoder, dsi->out_bridge,
&dsi->bridge, flags);
}
@@ -1622,29 +1621,11 @@ static void vc4_dsi_dma_chan_release(void *ptr)
dsi->reg_dma_chan = NULL;
}
-static void vc4_dsi_release(struct kref *kref)
-{
- struct vc4_dsi *dsi =
- container_of(kref, struct vc4_dsi, kref);
-
- kfree(dsi);
-}
-
-static void vc4_dsi_get(struct vc4_dsi *dsi)
-{
- kref_get(&dsi->kref);
-}
-
-static void vc4_dsi_put(struct vc4_dsi *dsi)
-{
- kref_put(&dsi->kref, &vc4_dsi_release);
-}
-
static void vc4_dsi_release_action(struct drm_device *drm, void *ptr)
{
struct vc4_dsi *dsi = ptr;
- vc4_dsi_put(dsi);
+ drm_bridge_put(&dsi->bridge);
}
static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
@@ -1655,7 +1636,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data)
struct drm_encoder *encoder = &dsi->encoder.base;
int ret;
- vc4_dsi_get(dsi);
+ drm_bridge_get(&dsi->bridge);
ret = drmm_add_action_or_reset(drm, vc4_dsi_release_action, dsi);
if (ret)
@@ -1810,15 +1791,12 @@ static int vc4_dsi_dev_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct vc4_dsi *dsi;
- dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
- if (!dsi)
- return -ENOMEM;
+ dsi = devm_drm_bridge_alloc(&pdev->dev, struct vc4_dsi, bridge, &vc4_dsi_bridge_funcs);
+ if (IS_ERR(dsi))
+ return PTR_ERR(dsi);
dev_set_drvdata(dev, dsi);
- kref_init(&dsi->kref);
-
dsi->pdev = pdev;
- dsi->bridge.funcs = &vc4_dsi_bridge_funcs;
#ifdef CONFIG_OF
dsi->bridge.of_node = dev->of_node;
#endif
@@ -1836,7 +1814,6 @@ static void vc4_dsi_dev_remove(struct platform_device *pdev)
struct vc4_dsi *dsi = dev_get_drvdata(dev);
mipi_dsi_host_unregister(&dsi->dsi_host);
- vc4_dsi_put(dsi);
}
struct platform_driver vc4_dsi_driver = {
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 22bccd69eb62..e231c906709c 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -29,9 +29,10 @@
#include <linux/sched/signal.h>
#include <linux/dma-fence-array.h>
+#include <drm/drm_exec.h>
+#include <drm/drm_print.h>
#include <drm/drm_syncobj.h>
-#include "uapi/drm/vc4_drm.h"
#include "vc4_drv.h"
#include "vc4_regs.h"
#include "vc4_trace.h"
@@ -60,6 +61,7 @@ vc4_free_hang_state(struct drm_device *dev, struct vc4_hang_state *state)
for (i = 0; i < state->user_state.bo_count; i++)
drm_gem_object_put(state->bo[i]);
+ kfree(state->bo);
kfree(state);
}
@@ -108,7 +110,7 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
state->bo = get_state->bo;
memcpy(get_state, state, sizeof(*state));
- bo_state = kcalloc(state->bo_count, sizeof(*bo_state), GFP_KERNEL);
+ bo_state = kzalloc_objs(*bo_state, state->bo_count);
if (!bo_state) {
ret = -ENOMEM;
goto err_free;
@@ -159,7 +161,7 @@ vc4_save_hang_state(struct drm_device *dev)
unsigned long irqflags;
unsigned int i, j, k, unref_list_count;
- kernel_state = kcalloc(1, sizeof(*kernel_state), GFP_KERNEL);
+ kernel_state = kzalloc_objs(*kernel_state, 1);
if (!kernel_state)
return;
@@ -168,10 +170,8 @@ vc4_save_hang_state(struct drm_device *dev)
spin_lock_irqsave(&vc4->job_lock, irqflags);
exec[0] = vc4_first_bin_job(vc4);
exec[1] = vc4_first_render_job(vc4);
- if (!exec[0] && !exec[1]) {
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
- return;
- }
+ if (!exec[0] && !exec[1])
+ goto err_free_state;
/* Get the bos from both binner and renderer into hang state. */
state->bo_count = 0;
@@ -185,13 +185,11 @@ vc4_save_hang_state(struct drm_device *dev)
state->bo_count += exec[i]->bo_count + unref_list_count;
}
- kernel_state->bo = kcalloc(state->bo_count,
- sizeof(*kernel_state->bo), GFP_ATOMIC);
+ kernel_state->bo = kzalloc_objs(*kernel_state->bo, state->bo_count,
+ GFP_ATOMIC);
- if (!kernel_state->bo) {
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
- return;
- }
+ if (!kernel_state->bo)
+ goto err_free_state;
k = 0;
for (i = 0; i < 2; i++) {
@@ -283,6 +281,12 @@ vc4_save_hang_state(struct drm_device *dev)
vc4->hang_state = kernel_state;
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
}
+
+ return;
+
+err_free_state:
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+ kfree(kernel_state);
}
static void
@@ -325,7 +329,7 @@ vc4_reset_work(struct work_struct *work)
static void
vc4_hangcheck_elapsed(struct timer_list *t)
{
- struct vc4_dev *vc4 = from_timer(vc4, t, hangcheck.timer);
+ struct vc4_dev *vc4 = timer_container_of(vc4, t, hangcheck.timer);
struct drm_device *dev = &vc4->base;
uint32_t ct0ca, ct1ca;
unsigned long irqflags;
@@ -552,45 +556,24 @@ vc4_move_job_to_render(struct drm_device *dev, struct vc4_exec_info *exec)
}
static void
-vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
+vc4_attach_fences(struct vc4_exec_info *exec)
{
struct vc4_bo *bo;
unsigned i;
for (i = 0; i < exec->bo_count; i++) {
bo = to_vc4_bo(exec->bo[i]);
- bo->seqno = seqno;
-
dma_resv_add_fence(bo->base.base.resv, exec->fence,
DMA_RESV_USAGE_READ);
}
- list_for_each_entry(bo, &exec->unref_list, unref_head) {
- bo->seqno = seqno;
- }
-
for (i = 0; i < exec->rcl_write_bo_count; i++) {
bo = to_vc4_bo(&exec->rcl_write_bo[i]->base);
- bo->write_seqno = seqno;
-
dma_resv_add_fence(bo->base.base.resv, exec->fence,
DMA_RESV_USAGE_WRITE);
}
}
-static void
-vc4_unlock_bo_reservations(struct drm_device *dev,
- struct vc4_exec_info *exec,
- struct ww_acquire_ctx *acquire_ctx)
-{
- int i;
-
- for (i = 0; i < exec->bo_count; i++)
- dma_resv_unlock(exec->bo[i]->resv);
-
- ww_acquire_fini(acquire_ctx);
-}
-
/* Takes the reservation lock on all the BOs being referenced, so that
* at queue submit time we can update the reservations.
*
@@ -599,70 +582,23 @@ vc4_unlock_bo_reservations(struct drm_device *dev,
* to vc4, so we don't attach dma-buf fences to them.
*/
static int
-vc4_lock_bo_reservations(struct drm_device *dev,
- struct vc4_exec_info *exec,
- struct ww_acquire_ctx *acquire_ctx)
+vc4_lock_bo_reservations(struct vc4_exec_info *exec,
+ struct drm_exec *exec_ctx)
{
- int contended_lock = -1;
- int i, ret;
- struct drm_gem_object *bo;
-
- ww_acquire_init(acquire_ctx, &reservation_ww_class);
-
-retry:
- if (contended_lock != -1) {
- bo = exec->bo[contended_lock];
- ret = dma_resv_lock_slow_interruptible(bo->resv, acquire_ctx);
- if (ret) {
- ww_acquire_done(acquire_ctx);
- return ret;
- }
- }
-
- for (i = 0; i < exec->bo_count; i++) {
- if (i == contended_lock)
- continue;
-
- bo = exec->bo[i];
-
- ret = dma_resv_lock_interruptible(bo->resv, acquire_ctx);
- if (ret) {
- int j;
-
- for (j = 0; j < i; j++) {
- bo = exec->bo[j];
- dma_resv_unlock(bo->resv);
- }
-
- if (contended_lock != -1 && contended_lock >= i) {
- bo = exec->bo[contended_lock];
-
- dma_resv_unlock(bo->resv);
- }
-
- if (ret == -EDEADLK) {
- contended_lock = i;
- goto retry;
- }
-
- ww_acquire_done(acquire_ctx);
- return ret;
- }
- }
-
- ww_acquire_done(acquire_ctx);
+ int ret;
/* Reserve space for our shared (read-only) fence references,
* before we commit the CL to the hardware.
*/
- for (i = 0; i < exec->bo_count; i++) {
- bo = exec->bo[i];
+ drm_exec_init(exec_ctx, DRM_EXEC_INTERRUPTIBLE_WAIT, exec->bo_count);
+ drm_exec_until_all_locked(exec_ctx) {
+ ret = drm_exec_prepare_array(exec_ctx, exec->bo,
+ exec->bo_count, 1);
+ }
- ret = dma_resv_reserve_fences(bo->resv, 1);
- if (ret) {
- vc4_unlock_bo_reservations(dev, exec, acquire_ctx);
- return ret;
- }
+ if (ret) {
+ drm_exec_fini(exec_ctx);
+ return ret;
}
return 0;
@@ -679,7 +615,7 @@ retry:
*/
static int
vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
- struct ww_acquire_ctx *acquire_ctx,
+ struct drm_exec *exec_ctx,
struct drm_syncobj *out_sync)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -688,7 +624,7 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
unsigned long irqflags;
struct vc4_fence *fence;
- fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+ fence = kzalloc_obj(*fence);
if (!fence)
return -ENOMEM;
fence->dev = dev;
@@ -706,9 +642,9 @@ vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec,
if (out_sync)
drm_syncobj_replace_fence(out_sync, exec->fence);
- vc4_update_bo_seqnos(exec, seqno);
+ vc4_attach_fences(exec);
- vc4_unlock_bo_reservations(dev, exec, acquire_ctx);
+ drm_exec_fini(exec_ctx);
list_add_tail(&exec->head, &vc4->bin_job_list);
@@ -904,12 +840,6 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
goto fail;
}
- /* Block waiting on any previous rendering into the CS's VBO,
- * IB, or textures, so that pixels are actually written by the
- * time we try to read them.
- */
- ret = vc4_wait_for_seqno(dev, exec->bin_dep_seqno, ~0ull, true);
-
fail:
kvfree(temp);
return ret;
@@ -968,7 +898,6 @@ void
vc4_job_handle_completed(struct vc4_dev *vc4)
{
unsigned long irqflags;
- struct vc4_seqno_cb *cb, *cb_temp;
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return;
@@ -985,48 +914,9 @@ vc4_job_handle_completed(struct vc4_dev *vc4)
spin_lock_irqsave(&vc4->job_lock, irqflags);
}
- list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) {
- if (cb->seqno <= vc4->finished_seqno) {
- list_del_init(&cb->work.entry);
- schedule_work(&cb->work);
- }
- }
-
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
}
-static void vc4_seqno_cb_work(struct work_struct *work)
-{
- struct vc4_seqno_cb *cb = container_of(work, struct vc4_seqno_cb, work);
-
- cb->func(cb);
-}
-
-int vc4_queue_seqno_cb(struct drm_device *dev,
- struct vc4_seqno_cb *cb, uint64_t seqno,
- void (*func)(struct vc4_seqno_cb *cb))
-{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
- unsigned long irqflags;
-
- if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
- return -ENODEV;
-
- cb->func = func;
- INIT_WORK(&cb->work, vc4_seqno_cb_work);
-
- spin_lock_irqsave(&vc4->job_lock, irqflags);
- if (seqno > vc4->finished_seqno) {
- cb->seqno = seqno;
- list_add_tail(&cb->work.entry, &vc4->seqno_cb_list);
- } else {
- schedule_work(&cb->work);
- }
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
-
- return 0;
-}
-
/* Scheduled when any job has been completed, this walks the list of
* jobs that had completed and unrefs their BOs and frees their exec
* structs.
@@ -1079,8 +969,10 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
struct vc4_dev *vc4 = to_vc4_dev(dev);
int ret;
struct drm_vc4_wait_bo *args = data;
- struct drm_gem_object *gem_obj;
- struct vc4_bo *bo;
+ unsigned long timeout_jiffies =
+ usecs_to_jiffies(div_u64(args->timeout_ns, 1000));
+ ktime_t start = ktime_get();
+ u64 delta_ns;
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return -ENODEV;
@@ -1088,17 +980,18 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
if (args->pad != 0)
return -EINVAL;
- gem_obj = drm_gem_object_lookup(file_priv, args->handle);
- if (!gem_obj) {
- DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
- return -EINVAL;
- }
- bo = to_vc4_bo(gem_obj);
+ ret = drm_gem_dma_resv_wait(file_priv, args->handle,
+ true, timeout_jiffies);
- ret = vc4_wait_for_seqno_ioctl_helper(dev, bo->seqno,
- &args->timeout_ns);
+ /* Decrement the user's timeout, in case we got interrupted
+ * such that the ioctl will be restarted.
+ */
+ delta_ns = ktime_to_ns(ktime_sub(ktime_get(), start));
+ if (delta_ns < args->timeout_ns)
+ args->timeout_ns -= delta_ns;
+ else
+ args->timeout_ns = 0;
- drm_gem_object_put(gem_obj);
return ret;
}
@@ -1123,7 +1016,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
struct drm_vc4_submit_cl *args = data;
struct drm_syncobj *out_sync = NULL;
struct vc4_exec_info *exec;
- struct ww_acquire_ctx acquire_ctx;
+ struct drm_exec exec_ctx;
struct dma_fence *in_fence;
int ret = 0;
@@ -1152,7 +1045,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
- exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);
+ exec = kzalloc_objs(*exec, 1);
if (!exec)
return -ENOMEM;
@@ -1216,7 +1109,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
if (ret)
goto fail;
- ret = vc4_lock_bo_reservations(dev, exec, &acquire_ctx);
+ ret = vc4_lock_bo_reservations(exec, &exec_ctx);
if (ret)
goto fail;
@@ -1224,7 +1117,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
out_sync = drm_syncobj_find(file_priv, args->out_sync);
if (!out_sync) {
ret = -EINVAL;
- goto fail;
+ goto fail_unreserve;
}
/* We replace the fence in out_sync in vc4_queue_submit since
@@ -1239,7 +1132,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
*/
exec->args = NULL;
- ret = vc4_queue_submit(dev, exec, &acquire_ctx, out_sync);
+ ret = vc4_queue_submit(dev, exec, &exec_ctx, out_sync);
/* The syncobj isn't part of the exec data and we need to free our
* reference even if job submission failed.
@@ -1248,13 +1141,15 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
drm_syncobj_put(out_sync);
if (ret)
- goto fail;
+ goto fail_unreserve;
/* Return the seqno for our job. */
args->seqno = vc4->emit_seqno;
return 0;
+fail_unreserve:
+ drm_exec_fini(&exec_ctx);
fail:
vc4_complete_exec(&vc4->base, exec);
@@ -1275,7 +1170,6 @@ int vc4_gem_init(struct drm_device *dev)
INIT_LIST_HEAD(&vc4->bin_job_list);
INIT_LIST_HEAD(&vc4->render_job_list);
INIT_LIST_HEAD(&vc4->job_done_list);
- INIT_LIST_HEAD(&vc4->seqno_cb_list);
spin_lock_init(&vc4->job_lock);
INIT_WORK(&vc4->hangcheck.reset_work, vc4_reset_work);
@@ -1358,7 +1252,7 @@ int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data,
/* Not sure it's safe to purge imported BOs. Let's just assume it's
* not until proven otherwise.
*/
- if (gem_obj->import_attach) {
+ if (drm_gem_is_imported(gem_obj)) {
DRM_DEBUG("madvise not supported on imported BOs\n");
ret = -EINVAL;
goto out_put_gem;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 47d9ada98430..a161d3b00a25 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -32,12 +32,14 @@
*/
#include <drm/display/drm_hdmi_audio_helper.h>
+#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <linux/clk.h>
@@ -51,6 +53,7 @@
#include <linux/reset.h>
#include <sound/dmaengine_pcm.h>
#include <sound/hdmi-codec.h>
+#include <sound/jack.h>
#include <sound/pcm_drm_eld.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -130,7 +133,7 @@ static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
unsigned int bpc,
- enum hdmi_colorspace fmt)
+ enum drm_output_color_format fmt)
{
unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
@@ -270,34 +273,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
#endif
-static int reset_pipe(struct drm_crtc *crtc,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_atomic_state *state;
- struct drm_crtc_state *crtc_state;
- int ret;
-
- state = drm_atomic_state_alloc(crtc->dev);
- if (!state)
- return -ENOMEM;
-
- state->acquire_ctx = ctx;
-
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state)) {
- ret = PTR_ERR(crtc_state);
- goto out;
- }
-
- crtc_state->connectors_changed = true;
-
- ret = drm_atomic_commit(state);
-out:
- drm_atomic_state_put(state);
-
- return ret;
-}
-
static int vc4_hdmi_reset_link(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx)
{
@@ -376,7 +351,7 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
* would be perfectly happy if were to just reconfigure
* the SCDC settings on the fly.
*/
- return reset_pipe(crtc, ctx);
+ return drm_atomic_helper_reset_crtc(crtc, ctx);
}
static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
@@ -400,16 +375,8 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
* the lock for now.
*/
- if (status == connector_status_disconnected) {
- cec_phys_addr_invalidate(vc4_hdmi->cec_adap);
- return;
- }
-
drm_atomic_helper_connector_hdmi_hotplug(connector, status);
- cec_s_phys_addr(vc4_hdmi->cec_adap,
- connector->display_info.source_physical_address, false);
-
if (status != connector_status_connected)
return;
@@ -477,7 +444,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
const struct drm_display_mode *mode;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode, 8, HDMI_COLORSPACE_RGB)) {
+ if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
}
@@ -488,7 +455,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
}
static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_connector_state *old_state =
drm_atomic_get_old_connector_state(state, connector);
@@ -580,16 +547,16 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
&vc4_hdmi_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA,
vc4_hdmi->ddc,
- BIT(HDMI_COLORSPACE_RGB) |
- BIT(HDMI_COLORSPACE_YUV422) |
- BIT(HDMI_COLORSPACE_YUV444),
+ BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
max_bpc);
if (ret)
return ret;
ret = drm_connector_hdmi_audio_init(connector, dev->dev,
&vc4_hdmi_audio_funcs,
- 8, false, -1);
+ 8, 0, false, -1);
if (ret)
return ret;
@@ -657,6 +624,30 @@ static int vc4_hdmi_stop_packet(struct vc4_hdmi *vc4_hdmi,
return ret;
}
+static int vc4_hdmi_clear_infoframe(struct drm_connector *connector,
+ enum hdmi_infoframe_type type)
+{
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
+ struct drm_device *drm = connector->dev;
+ int ret;
+ int idx;
+
+ if (!drm_dev_enter(drm, &idx))
+ return 0;
+
+ WARN_ONCE(!(HDMI_READ(HDMI_RAM_PACKET_CONFIG) &
+ VC4_HDMI_RAM_PACKET_ENABLE),
+ "Packet RAM has to be on to store the packet.");
+
+ ret = vc4_hdmi_stop_packet(vc4_hdmi, type, true);
+ if (ret)
+ drm_err(drm, "Failed to wait for infoframe to go idle: %d\n", ret);
+
+ drm_dev_exit(idx);
+
+ return ret;
+}
+
static int vc4_hdmi_write_infoframe(struct drm_connector *connector,
enum hdmi_infoframe_type type,
const u8 *infoframe, size_t len)
@@ -736,6 +727,66 @@ out:
return ret;
}
+static int vc4_hdmi_clear_avi_infoframe(struct drm_connector *connector)
+{
+ return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_AVI);
+}
+
+static int vc4_hdmi_clear_hdmi_infoframe(struct drm_connector *connector)
+{
+ return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_VENDOR);
+}
+
+static int vc4_hdmi_clear_audio_infoframe(struct drm_connector *connector)
+{
+ return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_AUDIO);
+}
+
+static int vc4_hdmi_clear_hdr_drm_infoframe(struct drm_connector *connector)
+{
+ return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_DRM);
+}
+
+static int vc4_hdmi_clear_spd_infoframe(struct drm_connector *connector)
+{
+ return vc4_hdmi_clear_infoframe(connector, HDMI_INFOFRAME_TYPE_SPD);
+}
+
+static int vc4_hdmi_write_avi_infoframe(struct drm_connector *connector,
+ const u8 *buffer, size_t len)
+{
+ return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_AVI,
+ buffer, len);
+}
+
+static int vc4_hdmi_write_hdmi_infoframe(struct drm_connector *connector,
+ const u8 *buffer, size_t len)
+{
+ return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_VENDOR,
+ buffer, len);
+}
+
+static int vc4_hdmi_write_audio_infoframe(struct drm_connector *connector,
+ const u8 *buffer, size_t len)
+{
+ return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_AUDIO,
+ buffer, len);
+}
+
+static int vc4_hdmi_write_hdr_drm_infoframe(struct drm_connector *connector,
+ const u8 *buffer, size_t len)
+{
+ return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_DRM,
+ buffer, len);
+}
+
+static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
+ const u8 *buffer, size_t len)
+{
+ return vc4_hdmi_write_infoframe(connector, HDMI_INFOFRAME_TYPE_SPD,
+ buffer, len);
+}
+
#define SCRAMBLING_POLLING_DELAY_MS 1000
static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
@@ -772,7 +823,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
vc4_hdmi->scdc_enabled = true;
- queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
+ queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
}
@@ -821,12 +872,12 @@ static void vc4_hdmi_scrambling_wq(struct work_struct *work)
drm_scdc_set_high_tmds_clock_ratio(connector, true);
drm_scdc_set_scrambling(connector, true);
- queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
+ queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
}
static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_device *drm = vc4_hdmi->connector.dev;
@@ -876,12 +927,11 @@ out:
}
static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_device *drm = vc4_hdmi->connector.dev;
unsigned long flags;
- int ret;
int idx;
mutex_lock(&vc4_hdmi->mutex);
@@ -900,9 +950,7 @@ static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
clk_disable_unprepare(vc4_hdmi->pixel_bvb_clock);
clk_disable_unprepare(vc4_hdmi->pixel_clock);
- ret = pm_runtime_put(&vc4_hdmi->pdev->dev);
- if (ret < 0)
- drm_err(drm, "Failed to release power domain: %d\n", ret);
+ pm_runtime_put(&vc4_hdmi->pdev->dev);
drm_dev_exit(idx);
@@ -1166,13 +1214,13 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
switch (state->hdmi.output_format) {
- case HDMI_COLORSPACE_YUV444:
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range);
vc5_hdmi_set_csc_coeffs_swap(vc4_hdmi, csc);
break;
- case HDMI_COLORSPACE_YUV422:
+ case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range);
csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
@@ -1189,7 +1237,7 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
vc5_hdmi_set_csc_coeffs(vc4_hdmi, csc);
break;
- case HDMI_COLORSPACE_RGB:
+ case DRM_OUTPUT_COLOR_FORMAT_RGB444:
if_xbar = 0x354021;
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_rgb[lim_range]);
@@ -1346,7 +1394,7 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
* YCC422 is always 36-bit and not considered deep colour so
* doesn't signal in GCP.
*/
- if (state->hdmi.output_format == HDMI_COLORSPACE_YUV422) {
+ if (state->hdmi.output_format == DRM_OUTPUT_COLOR_FORMAT_YCBCR422) {
gcp = 0;
}
@@ -1423,7 +1471,7 @@ static void vc4_hdmi_recenter_fifo(struct vc4_hdmi *vc4_hdmi)
}
static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_device *drm = vc4_hdmi->connector.dev;
@@ -1539,7 +1587,7 @@ out:
}
static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_device *drm = vc4_hdmi->connector.dev;
@@ -1569,7 +1617,7 @@ out:
}
static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_connector *connector = &vc4_hdmi->connector;
@@ -1693,7 +1741,26 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
.tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
- .write_infoframe = vc4_hdmi_write_infoframe,
+ .avi = {
+ .clear_infoframe = vc4_hdmi_clear_avi_infoframe,
+ .write_infoframe = vc4_hdmi_write_avi_infoframe,
+ },
+ .hdmi = {
+ .clear_infoframe = vc4_hdmi_clear_hdmi_infoframe,
+ .write_infoframe = vc4_hdmi_write_hdmi_infoframe,
+ },
+ .audio = {
+ .clear_infoframe = vc4_hdmi_clear_audio_infoframe,
+ .write_infoframe = vc4_hdmi_write_audio_infoframe,
+ },
+ .hdr_drm = {
+ .clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe,
+ .write_infoframe = vc4_hdmi_write_hdr_drm_infoframe,
+ },
+ .spd = {
+ .clear_infoframe = vc4_hdmi_clear_spd_infoframe,
+ .write_infoframe = vc4_hdmi_write_spd_infoframe,
+ },
};
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
@@ -2203,6 +2270,22 @@ static const struct drm_connector_hdmi_audio_funcs vc4_hdmi_audio_funcs = {
.shutdown = vc4_hdmi_audio_shutdown,
};
+static int vc4_hdmi_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct vc4_hdmi *vc4_hdmi = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
+ int ret;
+
+ ret = snd_soc_card_jack_new(rtd->card, "HDMI Jack", SND_JACK_LINEOUT,
+ &vc4_hdmi->hdmi_jack);
+ if (ret) {
+ dev_err(rtd->dev, "HDMI Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_component_set_jack(component, &vc4_hdmi->hdmi_jack, NULL);
+}
+
static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
{
const struct vc4_hdmi_register *mai_data =
@@ -2302,6 +2385,12 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
return ret;
}
+ ret = drm_connector_hdmi_audio_init(&vc4_hdmi->connector, dev,
+ &vc4_hdmi_audio_funcs, 8, 0, false,
+ -1);
+ if (ret)
+ return ret;
+
dai_link->cpus = &vc4_hdmi->audio.cpu;
dai_link->codecs = &vc4_hdmi->audio.codec;
dai_link->platforms = &vc4_hdmi->audio.platform;
@@ -2316,6 +2405,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
dai_link->cpus->dai_name = dev_name(dev);
dai_link->codecs->name = dev_name(&vc4_hdmi->connector.hdmi_audio.codec_pdev->dev);
dai_link->platforms->name = dev_name(dev);
+ dai_link->init = vc4_hdmi_codec_init;
card->dai_link = dai_link;
card->num_links = 1;
@@ -2359,17 +2449,23 @@ static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
int ret;
if (vc4_hdmi->variant->external_irq_controller) {
- unsigned int hpd_con = platform_get_irq_byname(pdev, "hpd-connected");
- unsigned int hpd_rm = platform_get_irq_byname(pdev, "hpd-removed");
+ int hpd = platform_get_irq_byname(pdev, "hpd-connected");
+
+ if (hpd < 0)
+ return hpd;
- ret = devm_request_threaded_irq(&pdev->dev, hpd_con,
+ ret = devm_request_threaded_irq(&pdev->dev, hpd,
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd connected", vc4_hdmi);
if (ret)
return ret;
- ret = devm_request_threaded_irq(&pdev->dev, hpd_rm,
+ hpd = platform_get_irq_byname(pdev, "hpd-removed");
+ if (hpd < 0)
+ return hpd;
+
+ ret = devm_request_threaded_irq(&pdev->dev, hpd,
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd disconnected", vc4_hdmi);
@@ -2388,8 +2484,8 @@ static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
struct vc4_hdmi *vc4_hdmi = priv;
if (vc4_hdmi->cec_rx_msg.len)
- cec_received_msg(vc4_hdmi->cec_adap,
- &vc4_hdmi->cec_rx_msg);
+ drm_connector_hdmi_cec_received_msg(&vc4_hdmi->connector,
+ &vc4_hdmi->cec_rx_msg);
return IRQ_HANDLED;
}
@@ -2399,15 +2495,17 @@ static irqreturn_t vc4_cec_irq_handler_tx_thread(int irq, void *priv)
struct vc4_hdmi *vc4_hdmi = priv;
if (vc4_hdmi->cec_tx_ok) {
- cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK,
- 0, 0, 0, 0);
+ drm_connector_hdmi_cec_transmit_done(&vc4_hdmi->connector,
+ CEC_TX_STATUS_OK,
+ 0, 0, 0, 0);
} else {
/*
* This CEC implementation makes 1 retry, so if we
* get a NACK, then that means it made 2 attempts.
*/
- cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_NACK,
- 0, 2, 0, 0);
+ drm_connector_hdmi_cec_transmit_done(&vc4_hdmi->connector,
+ CEC_TX_STATUS_NACK,
+ 0, 2, 0, 0);
}
return IRQ_HANDLED;
}
@@ -2564,9 +2662,9 @@ static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
return ret;
}
-static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
+static int vc4_hdmi_cec_enable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = vc4_hdmi->connector.dev;
/* clock period in microseconds */
const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
@@ -2631,9 +2729,9 @@ static int vc4_hdmi_cec_enable(struct cec_adapter *adap)
return 0;
}
-static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
+static int vc4_hdmi_cec_disable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = vc4_hdmi->connector.dev;
unsigned long flags;
int idx;
@@ -2667,17 +2765,17 @@ static int vc4_hdmi_cec_disable(struct cec_adapter *adap)
return 0;
}
-static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
+static int vc4_hdmi_cec_adap_enable(struct drm_connector *connector, bool enable)
{
if (enable)
- return vc4_hdmi_cec_enable(adap);
+ return vc4_hdmi_cec_enable(connector);
else
- return vc4_hdmi_cec_disable(adap);
+ return vc4_hdmi_cec_disable(connector);
}
-static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
+static int vc4_hdmi_cec_adap_log_addr(struct drm_connector *connector, u8 log_addr)
{
- struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = vc4_hdmi->connector.dev;
unsigned long flags;
int idx;
@@ -2703,10 +2801,10 @@ static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
return 0;
}
-static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+static int vc4_hdmi_cec_adap_transmit(struct drm_connector *connector, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
- struct vc4_hdmi *vc4_hdmi = cec_get_drvdata(adap);
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *dev = vc4_hdmi->connector.dev;
unsigned long flags;
u32 val;
@@ -2749,84 +2847,65 @@ static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
return 0;
}
-static const struct cec_adap_ops vc4_hdmi_cec_adap_ops = {
- .adap_enable = vc4_hdmi_cec_adap_enable,
- .adap_log_addr = vc4_hdmi_cec_adap_log_addr,
- .adap_transmit = vc4_hdmi_cec_adap_transmit,
-};
-
-static void vc4_hdmi_cec_release(void *ptr)
-{
- struct vc4_hdmi *vc4_hdmi = ptr;
-
- cec_unregister_adapter(vc4_hdmi->cec_adap);
- vc4_hdmi->cec_adap = NULL;
-}
-
-static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
+static int vc4_hdmi_cec_init(struct drm_connector *connector)
{
- struct cec_connector_info conn_info;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct platform_device *pdev = vc4_hdmi->pdev;
struct device *dev = &pdev->dev;
int ret;
- if (!of_property_present(dev->of_node, "interrupts")) {
- dev_warn(dev, "'interrupts' DT property is missing, no CEC\n");
- return 0;
- }
-
- vc4_hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
- vc4_hdmi,
- vc4_hdmi->variant->card_name,
- CEC_CAP_DEFAULTS |
- CEC_CAP_CONNECTOR_INFO, 1);
- ret = PTR_ERR_OR_ZERO(vc4_hdmi->cec_adap);
- if (ret < 0)
- return ret;
-
- cec_fill_conn_info_from_drm(&conn_info, &vc4_hdmi->connector);
- cec_s_conn_info(vc4_hdmi->cec_adap, &conn_info);
-
if (vc4_hdmi->variant->external_irq_controller) {
ret = devm_request_threaded_irq(dev, platform_get_irq_byname(pdev, "cec-rx"),
vc4_cec_irq_handler_rx_bare,
vc4_cec_irq_handler_rx_thread, 0,
"vc4 hdmi cec rx", vc4_hdmi);
if (ret)
- goto err_delete_cec_adap;
+ return ret;
ret = devm_request_threaded_irq(dev, platform_get_irq_byname(pdev, "cec-tx"),
vc4_cec_irq_handler_tx_bare,
vc4_cec_irq_handler_tx_thread, 0,
"vc4 hdmi cec tx", vc4_hdmi);
if (ret)
- goto err_delete_cec_adap;
+ return ret;
} else {
ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
vc4_cec_irq_handler,
vc4_cec_irq_handler_thread, 0,
"vc4 hdmi cec", vc4_hdmi);
if (ret)
- goto err_delete_cec_adap;
+ return ret;
}
- ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
- if (ret < 0)
- goto err_delete_cec_adap;
+ return 0;
+}
+
+static const struct drm_connector_hdmi_cec_funcs vc4_hdmi_cec_funcs = {
+ .init = vc4_hdmi_cec_init,
+ .enable = vc4_hdmi_cec_adap_enable,
+ .log_addr = vc4_hdmi_cec_adap_log_addr,
+ .transmit = vc4_hdmi_cec_adap_transmit,
+};
+
+static int vc4_hdmi_cec_register(struct vc4_hdmi *vc4_hdmi)
+{
+ struct platform_device *pdev = vc4_hdmi->pdev;
+ struct device *dev = &pdev->dev;
+
+ if (!of_property_present(dev->of_node, "interrupts")) {
+ dev_warn(dev, "'interrupts' DT property is missing, no CEC\n");
+ return 0;
+ }
/*
- * NOTE: Strictly speaking, we should probably use a DRM-managed
- * registration there to avoid removing the CEC adapter by the
- * time the DRM driver doesn't have any user anymore.
+ * NOTE: the CEC adapter will be unregistered by drmm cleanup from
+ * drm_managed_release(), which is called from drm_dev_release()
+ * during device unbind.
*
* However, the CEC framework already cleans up the CEC adapter
* only when the last user has closed its file descriptor, so we
* don't need to handle it in DRM.
*
- * By the time the device-managed hook is executed, we will give
- * up our reference to the CEC adapter and therefore don't
- * really care when it's actually freed.
- *
* There's still a problematic sequence: if we unregister our
* CEC adapter, but the userspace keeps a handle on the CEC
* adapter but not the DRM device for some reason. In such a
@@ -2837,19 +2916,14 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
* the CEC framework already handles this too, by calling
* cec_is_registered() in cec_ioctl() and cec_poll().
*/
- ret = devm_add_action_or_reset(dev, vc4_hdmi_cec_release, vc4_hdmi);
- if (ret)
- return ret;
-
- return 0;
-
-err_delete_cec_adap:
- cec_delete_adapter(vc4_hdmi->cec_adap);
-
- return ret;
+ return drmm_connector_hdmi_cec_register(&vc4_hdmi->connector,
+ &vc4_hdmi_cec_funcs,
+ vc4_hdmi->variant->card_name,
+ 1,
+ &pdev->dev);
}
#else
-static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
+static int vc4_hdmi_cec_register(struct vc4_hdmi *vc4_hdmi)
{
return 0;
}
@@ -2873,8 +2947,7 @@ static int vc4_hdmi_build_regset(struct drm_device *drm,
unsigned int i;
int ret;
- regs = kcalloc(variant->num_registers, sizeof(*regs),
- GFP_KERNEL);
+ regs = kzalloc_objs(*regs, variant->num_registers);
if (!regs)
return -ENOMEM;
@@ -2954,15 +3027,16 @@ static int vc5_hdmi_init_resources(struct drm_device *drm,
struct resource *res;
int ret;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi");
- if (!res)
- return -ENODEV;
-
- vc4_hdmi->hdmicore_regs = devm_ioremap(dev, res->start,
- resource_size(res));
- if (!vc4_hdmi->hdmicore_regs)
- return -ENOMEM;
+ vc4_hdmi->hdmicore_regs = devm_platform_ioremap_resource_byname(pdev,
+ "hdmi");
+ if (IS_ERR(vc4_hdmi->hdmicore_regs))
+ return PTR_ERR(vc4_hdmi->hdmicore_regs);
+ /* This is shared between both HDMI controllers. Cannot
+ * claim for both instances. Lets not convert to using
+ * devm_platform_ioremap_resource_byname() like
+ * the rest
+ */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hd");
if (!res)
return -ENODEV;
@@ -2971,53 +3045,35 @@ static int vc5_hdmi_init_resources(struct drm_device *drm,
if (!vc4_hdmi->hd_regs)
return -ENOMEM;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cec");
- if (!res)
- return -ENODEV;
-
- vc4_hdmi->cec_regs = devm_ioremap(dev, res->start, resource_size(res));
- if (!vc4_hdmi->cec_regs)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csc");
- if (!res)
- return -ENODEV;
+ vc4_hdmi->cec_regs = devm_platform_ioremap_resource_byname(pdev,
+ "cec");
+ if (IS_ERR(vc4_hdmi->cec_regs))
+ return PTR_ERR(vc4_hdmi->cec_regs);
- vc4_hdmi->csc_regs = devm_ioremap(dev, res->start, resource_size(res));
- if (!vc4_hdmi->csc_regs)
- return -ENOMEM;
+ vc4_hdmi->csc_regs = devm_platform_ioremap_resource_byname(pdev,
+ "csc");
+ if (IS_ERR(vc4_hdmi->csc_regs))
+ return PTR_ERR(vc4_hdmi->csc_regs);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvp");
- if (!res)
- return -ENODEV;
+ vc4_hdmi->dvp_regs = devm_platform_ioremap_resource_byname(pdev,
+ "dvp");
+ if (IS_ERR(vc4_hdmi->dvp_regs))
+ return PTR_ERR(vc4_hdmi->dvp_regs);
- vc4_hdmi->dvp_regs = devm_ioremap(dev, res->start, resource_size(res));
- if (!vc4_hdmi->dvp_regs)
- return -ENOMEM;
+ vc4_hdmi->phy_regs = devm_platform_ioremap_resource_byname(pdev,
+ "phy");
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
- if (!res)
- return -ENODEV;
+ if (IS_ERR(vc4_hdmi->phy_regs))
+ return PTR_ERR(vc4_hdmi->phy_regs);
- vc4_hdmi->phy_regs = devm_ioremap(dev, res->start, resource_size(res));
- if (!vc4_hdmi->phy_regs)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "packet");
- if (!res)
- return -ENODEV;
-
- vc4_hdmi->ram_regs = devm_ioremap(dev, res->start, resource_size(res));
- if (!vc4_hdmi->ram_regs)
- return -ENOMEM;
+ vc4_hdmi->ram_regs = devm_platform_ioremap_resource_byname(pdev,
+ "packet");
+ if (IS_ERR(vc4_hdmi->ram_regs))
+ return PTR_ERR(vc4_hdmi->ram_regs);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rm");
- if (!res)
- return -ENODEV;
-
- vc4_hdmi->rm_regs = devm_ioremap(dev, res->start, resource_size(res));
- if (!vc4_hdmi->rm_regs)
- return -ENOMEM;
+ vc4_hdmi->rm_regs = devm_platform_ioremap_resource_byname(pdev, "rm");
+ if (IS_ERR(vc4_hdmi->rm_regs))
+ return PTR_ERR(vc4_hdmi->rm_regs);
vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi");
if (IS_ERR(vc4_hdmi->hsm_clock)) {
@@ -3271,7 +3327,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
if (ret)
goto err_put_runtime_pm;
- ret = vc4_hdmi_cec_init(vc4_hdmi);
+ ret = vc4_hdmi_cec_register(vc4_hdmi);
if (ret)
goto err_put_runtime_pm;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index e3d989ca302b..29d461d4ee49 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -4,6 +4,7 @@
#include <drm/drm_connector.h>
#include <media/cec.h>
#include <sound/dmaengine_pcm.h>
+#include <sound/hdmi-codec.h>
#include <sound/soc.h>
#include "vc4_drv.h"
@@ -146,7 +147,6 @@ struct vc4_hdmi {
*/
bool disable_wifi_frequencies;
- struct cec_adapter *cec_adap;
struct cec_msg cec_rx_msg;
bool cec_tx_ok;
bool cec_irq_was_rx;
@@ -210,7 +210,13 @@ struct vc4_hdmi {
* @drm_connector_state.hdmi.output_format for use outside of
* KMS hooks. Protected by @mutex.
*/
- enum hdmi_colorspace output_format;
+ enum drm_output_color_format output_format;
+
+ /**
+ * @hdmi_jack: Represents the connection state of the HDMI plug, for
+ * ALSA jack detection.
+ */
+ struct snd_soc_jack hdmi_jack;
};
#define connector_to_vc4_hdmi(_connector) \
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index 4811d794001f..184d51ea3fa5 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -26,6 +26,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
@@ -786,7 +787,7 @@ void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
__vc4_hvs_stop_channel(hvs, chan);
}
-int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
+int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *state)
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
@@ -881,7 +882,7 @@ static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
}
void vc4_hvs_atomic_begin(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
@@ -893,7 +894,7 @@ void vc4_hvs_atomic_begin(struct drm_crtc *crtc,
}
void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -911,7 +912,7 @@ void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
}
void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_device *dev = crtc->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -923,7 +924,7 @@ void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
}
void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state,
crtc);
diff --git a/drivers/gpu/drm/vc4/vc4_irq.c b/drivers/gpu/drm/vc4/vc4_irq.c
index 69b399f3b802..8e5141bb5075 100644
--- a/drivers/gpu/drm/vc4/vc4_irq.c
+++ b/drivers/gpu/drm/vc4/vc4_irq.c
@@ -47,7 +47,7 @@
#include <linux/platform_device.h>
-#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -241,23 +241,6 @@ vc4_irq(int irq, void *arg)
return status;
}
-static void
-vc4_irq_prepare(struct drm_device *dev)
-{
- struct vc4_dev *vc4 = to_vc4_dev(dev);
-
- if (!vc4->v3d)
- return;
-
- init_waitqueue_head(&vc4->job_wait_queue);
- INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
-
- /* Clear any pending interrupts someone might have left around
- * for us.
- */
- V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
-}
-
void
vc4_irq_enable(struct drm_device *dev)
{
@@ -306,12 +289,22 @@ int vc4_irq_install(struct drm_device *dev, int irq)
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return -ENODEV;
+ if (!vc4->v3d)
+ return -ENODEV;
+
if (irq == IRQ_NOTCONNECTED)
return -ENOTCONN;
- vc4_irq_prepare(dev);
+ init_waitqueue_head(&vc4->job_wait_queue);
+ INIT_WORK(&vc4->overflow_mem_work, vc4_overflow_mem_work);
+
+ /* Clear any pending interrupts someone might have left around
+ * for us.
+ */
+ V3D_WRITE(V3D_INTCTL, V3D_DRIVER_IRQS);
- ret = request_irq(irq, vc4_irq, 0, dev->driver->name, dev);
+ ret = devm_request_irq(dev->dev, irq, vc4_irq, 0,
+ dev_name(dev->dev), dev);
if (ret)
return ret;
@@ -328,7 +321,6 @@ void vc4_irq_uninstall(struct drm_device *dev)
return;
vc4_irq_disable(dev);
- free_irq(vc4->irq, dev);
}
/** Reinitializes interrupt registers when a GPU reset is performed. */
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index f5b167417428..b17e73bce384 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -19,6 +19,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
@@ -43,7 +44,7 @@ struct vc4_load_tracker_state {
#define to_vc4_load_tracker_state(_state) \
container_of_const(_state, struct vc4_load_tracker_state, base)
-static struct vc4_ctm_state *vc4_get_ctm_state(struct drm_atomic_state *state,
+static struct vc4_ctm_state *vc4_get_ctm_state(struct drm_atomic_commit *state,
struct drm_private_obj *manager)
{
struct drm_device *dev = state->dev;
@@ -84,7 +85,22 @@ static void vc4_ctm_destroy_state(struct drm_private_obj *obj,
kfree(ctm_state);
}
+static struct drm_private_state *
+vc4_ctm_create_state(struct drm_private_obj *obj)
+{
+ struct vc4_ctm_state *ctm_state;
+
+ ctm_state = kzalloc_obj(*ctm_state);
+ if (!ctm_state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_private_obj_create_state(obj, &ctm_state->base);
+
+ return &ctm_state->base;
+}
+
static const struct drm_private_state_funcs vc4_ctm_state_funcs = {
+ .atomic_create_state = vc4_ctm_create_state,
.atomic_duplicate_state = vc4_ctm_duplicate_state,
.atomic_destroy_state = vc4_ctm_destroy_state,
};
@@ -98,15 +114,9 @@ static void vc4_ctm_obj_fini(struct drm_device *dev, void *unused)
static int vc4_ctm_obj_init(struct vc4_dev *vc4)
{
- struct vc4_ctm_state *ctm_state;
-
drm_modeset_lock_init(&vc4->ctm_state_lock);
- ctm_state = kzalloc(sizeof(*ctm_state), GFP_KERNEL);
- if (!ctm_state)
- return -ENOMEM;
-
- drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager, &ctm_state->base,
+ drm_atomic_private_obj_init(&vc4->base, &vc4->ctm_manager,
&vc4_ctm_state_funcs);
return drmm_add_action_or_reset(&vc4->base, vc4_ctm_obj_fini, NULL);
@@ -132,7 +142,7 @@ static u16 vc4_ctm_s31_32_to_s0_9(u64 in)
}
static void
-vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
+vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_commit *state)
{
struct vc4_hvs *hvs = vc4->hvs;
struct vc4_ctm_state *ctm_state = to_vc4_ctm_state(vc4->ctm_manager.state);
@@ -169,7 +179,7 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
}
struct vc4_hvs_state *
-vc4_hvs_get_new_global_state(const struct drm_atomic_state *state)
+vc4_hvs_get_new_global_state(const struct drm_atomic_commit *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
struct drm_private_state *priv_state;
@@ -182,7 +192,7 @@ vc4_hvs_get_new_global_state(const struct drm_atomic_state *state)
}
struct vc4_hvs_state *
-vc4_hvs_get_old_global_state(const struct drm_atomic_state *state)
+vc4_hvs_get_old_global_state(const struct drm_atomic_commit *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
struct drm_private_state *priv_state;
@@ -195,7 +205,7 @@ vc4_hvs_get_old_global_state(const struct drm_atomic_state *state)
}
struct vc4_hvs_state *
-vc4_hvs_get_global_state(struct drm_atomic_state *state)
+vc4_hvs_get_global_state(struct drm_atomic_commit *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
struct drm_private_state *priv_state;
@@ -208,7 +218,7 @@ vc4_hvs_get_global_state(struct drm_atomic_state *state)
}
static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hvs *hvs = vc4->hvs;
struct drm_crtc_state *crtc_state;
@@ -251,7 +261,7 @@ static void vc4_hvs_pv_muxing_commit(struct vc4_dev *vc4,
}
static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hvs *hvs = vc4->hvs;
struct drm_crtc_state *crtc_state;
@@ -327,7 +337,7 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4,
}
static void vc6_hvs_pv_muxing_commit(struct vc4_dev *vc4,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hvs *hvs = vc4->hvs;
struct drm_crtc_state *crtc_state;
@@ -374,7 +384,7 @@ static void vc6_hvs_pv_muxing_commit(struct vc4_dev *vc4,
}
}
-static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
+static void vc4_atomic_commit_tail(struct drm_atomic_commit *state)
{
struct drm_device *dev = state->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -498,7 +508,7 @@ static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
}
}
-static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
+static int vc4_atomic_commit_setup(struct drm_atomic_commit *state)
{
struct drm_crtc_state *crtc_state;
struct vc4_hvs_state *hvs_state;
@@ -530,6 +540,7 @@ static int vc4_atomic_commit_setup(struct drm_atomic_state *state)
static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev,
struct drm_file *file_priv,
+ const struct drm_format_info *info,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -568,7 +579,7 @@ static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev,
mode_cmd = &mode_cmd_local;
}
- return drm_gem_fb_create(dev, file_priv, mode_cmd);
+ return drm_gem_fb_create(dev, file_priv, info, mode_cmd);
}
/* Our CTM has some peculiar limitations: we can only enable it for one CRTC
@@ -576,7 +587,7 @@ static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev,
* we don't allow userland to set a CTM that we have no hope of approximating.
*/
static int
-vc4_ctm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
+vc4_ctm_atomic_check(struct drm_device *dev, struct drm_atomic_commit *state)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
struct vc4_ctm_state *ctm_state = NULL;
@@ -642,7 +653,7 @@ vc4_ctm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
return 0;
}
-static int vc4_load_tracker_atomic_check(struct drm_atomic_state *state)
+static int vc4_load_tracker_atomic_check(struct drm_atomic_commit *state)
{
struct drm_plane_state *old_plane_state, *new_plane_state;
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
@@ -716,7 +727,22 @@ static void vc4_load_tracker_destroy_state(struct drm_private_obj *obj,
kfree(load_state);
}
+static struct drm_private_state *
+vc4_load_tracker_create_state(struct drm_private_obj *obj)
+{
+ struct vc4_load_tracker_state *load_state;
+
+ load_state = kzalloc_obj(*load_state);
+ if (!load_state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_private_obj_create_state(obj, &load_state->base);
+
+ return &load_state->base;
+}
+
static const struct drm_private_state_funcs vc4_load_tracker_state_funcs = {
+ .atomic_create_state = vc4_load_tracker_create_state,
.atomic_duplicate_state = vc4_load_tracker_duplicate_state,
.atomic_destroy_state = vc4_load_tracker_destroy_state,
};
@@ -730,14 +756,7 @@ static void vc4_load_tracker_obj_fini(struct drm_device *dev, void *unused)
static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
{
- struct vc4_load_tracker_state *load_state;
-
- load_state = kzalloc(sizeof(*load_state), GFP_KERNEL);
- if (!load_state)
- return -ENOMEM;
-
drm_atomic_private_obj_init(&vc4->base, &vc4->load_tracker,
- &load_state->base,
&vc4_load_tracker_state_funcs);
return drmm_add_action_or_reset(&vc4->base, vc4_load_tracker_obj_fini, NULL);
@@ -750,7 +769,7 @@ vc4_hvs_channels_duplicate_state(struct drm_private_obj *obj)
struct vc4_hvs_state *state;
unsigned int i;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
+ state = kzalloc_obj(*state);
if (!state)
return NULL;
@@ -798,7 +817,22 @@ static void vc4_hvs_channels_print_state(struct drm_printer *p,
}
}
+static struct drm_private_state *
+vc4_hvs_channels_create_state(struct drm_private_obj *obj)
+{
+ struct vc4_hvs_state *hvs_state;
+
+ hvs_state = kzalloc_obj(*hvs_state);
+ if (!hvs_state)
+ return ERR_PTR(-ENOMEM);
+
+ __drm_atomic_helper_private_obj_create_state(obj, &hvs_state->base);
+
+ return &hvs_state->base;
+}
+
static const struct drm_private_state_funcs vc4_hvs_state_funcs = {
+ .atomic_create_state = vc4_hvs_channels_create_state,
.atomic_duplicate_state = vc4_hvs_channels_duplicate_state,
.atomic_destroy_state = vc4_hvs_channels_destroy_state,
.atomic_print_state = vc4_hvs_channels_print_state,
@@ -813,14 +847,7 @@ static void vc4_hvs_channels_obj_fini(struct drm_device *dev, void *unused)
static int vc4_hvs_channels_obj_init(struct vc4_dev *vc4)
{
- struct vc4_hvs_state *state;
-
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
-
drm_atomic_private_obj_init(&vc4->base, &vc4->hvs_channels,
- &state->base,
&vc4_hvs_state_funcs);
return drmm_add_action_or_reset(&vc4->base, vc4_hvs_channels_obj_fini, NULL);
@@ -871,7 +898,7 @@ static int cmp_vc4_crtc_hvs_output(const void *a, const void *b)
* single display, and changing the resolution down and then back up.
*/
static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_hvs_state *hvs_new_state;
struct drm_crtc **sorted_crtcs;
@@ -909,7 +936,7 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
* If the layout changes and doesn't give us that in the future,
* we will need to have something smarter, but it works so far.
*/
- sorted_crtcs = kmalloc_array(dev->num_crtcs, sizeof(*sorted_crtcs), GFP_KERNEL);
+ sorted_crtcs = kmalloc_objs(*sorted_crtcs, dev->num_crtcs);
if (!sorted_crtcs)
return -ENOMEM;
@@ -992,7 +1019,7 @@ err_free_crtc_array:
}
static int
-vc4_core_clock_atomic_check(struct drm_atomic_state *state)
+vc4_core_clock_atomic_check(struct drm_atomic_commit *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
struct drm_private_state *priv_state;
@@ -1064,7 +1091,7 @@ vc4_core_clock_atomic_check(struct drm_atomic_state *state)
static int
-vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
+vc4_atomic_check(struct drm_device *dev, struct drm_atomic_commit *state)
{
int ret;
diff --git a/drivers/gpu/drm/vc4/vc4_perfmon.c b/drivers/gpu/drm/vc4/vc4_perfmon.c
index f1342f917cf7..f75dfd156756 100644
--- a/drivers/gpu/drm/vc4/vc4_perfmon.c
+++ b/drivers/gpu/drm/vc4/vc4_perfmon.c
@@ -9,12 +9,11 @@
* The V3D block provides 16 hardware counters which can count various events.
*/
+#include <drm/drm_print.h>
+
#include "vc4_drv.h"
#include "vc4_regs.h"
-#define VC4_PERFMONID_MIN 1
-#define VC4_PERFMONID_MAX U32_MAX
-
void vc4_perfmon_get(struct vc4_perfmon *perfmon)
{
struct vc4_dev *vc4;
@@ -93,10 +92,10 @@ struct vc4_perfmon *vc4_perfmon_find(struct vc4_file *vc4file, int id)
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return NULL;
- mutex_lock(&vc4file->perfmon.lock);
- perfmon = idr_find(&vc4file->perfmon.idr, id);
+ xa_lock(&vc4file->perfmons);
+ perfmon = xa_load(&vc4file->perfmons, id);
vc4_perfmon_get(perfmon);
- mutex_unlock(&vc4file->perfmon.lock);
+ xa_unlock(&vc4file->perfmons);
return perfmon;
}
@@ -108,37 +107,34 @@ void vc4_perfmon_open_file(struct vc4_file *vc4file)
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return;
- mutex_init(&vc4file->perfmon.lock);
- idr_init_base(&vc4file->perfmon.idr, VC4_PERFMONID_MIN);
- vc4file->dev = vc4;
+ xa_init_flags(&vc4file->perfmons, XA_FLAGS_ALLOC1);
}
-static int vc4_perfmon_idr_del(int id, void *elem, void *data)
+static void vc4_perfmon_delete(struct vc4_file *vc4file,
+ struct vc4_perfmon *perfmon)
{
- struct vc4_perfmon *perfmon = elem;
- struct vc4_dev *vc4 = (struct vc4_dev *)data;
+ struct vc4_dev *vc4 = vc4file->dev;
/* If the active perfmon is being destroyed, stop it first */
if (perfmon == vc4->active_perfmon)
vc4_perfmon_stop(vc4, perfmon, false);
vc4_perfmon_put(perfmon);
-
- return 0;
}
void vc4_perfmon_close_file(struct vc4_file *vc4file)
{
struct vc4_dev *vc4 = vc4file->dev;
+ struct vc4_perfmon *perfmon;
+ unsigned long id;
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return;
- mutex_lock(&vc4file->perfmon.lock);
- idr_for_each(&vc4file->perfmon.idr, vc4_perfmon_idr_del, vc4);
- idr_destroy(&vc4file->perfmon.idr);
- mutex_unlock(&vc4file->perfmon.lock);
- mutex_destroy(&vc4file->perfmon.lock);
+ xa_for_each(&vc4file->perfmons, id, perfmon)
+ vc4_perfmon_delete(vc4file, perfmon);
+
+ xa_destroy(&vc4file->perfmons);
}
int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
@@ -150,6 +146,7 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
struct vc4_perfmon *perfmon;
unsigned int i;
int ret;
+ u32 id;
if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
return -ENODEV;
@@ -170,8 +167,7 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
- perfmon = kzalloc(struct_size(perfmon, counters, req->ncounters),
- GFP_KERNEL);
+ perfmon = kzalloc_flex(*perfmon, counters, req->ncounters);
if (!perfmon)
return -ENOMEM;
perfmon->dev = vc4;
@@ -183,17 +179,15 @@ int vc4_perfmon_create_ioctl(struct drm_device *dev, void *data,
refcount_set(&perfmon->refcnt, 1);
- mutex_lock(&vc4file->perfmon.lock);
- ret = idr_alloc(&vc4file->perfmon.idr, perfmon, VC4_PERFMONID_MIN,
- VC4_PERFMONID_MAX, GFP_KERNEL);
- mutex_unlock(&vc4file->perfmon.lock);
-
+ ret = xa_alloc(&vc4file->perfmons, &id, perfmon, xa_limit_32b,
+ GFP_KERNEL);
if (ret < 0) {
kfree(perfmon);
return ret;
}
- req->id = ret;
+ req->id = id;
+
return 0;
}
@@ -213,14 +207,12 @@ int vc4_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
return -ENODEV;
}
- mutex_lock(&vc4file->perfmon.lock);
- perfmon = idr_remove(&vc4file->perfmon.idr, req->id);
- mutex_unlock(&vc4file->perfmon.lock);
-
+ perfmon = xa_erase(&vc4file->perfmons, req->id);
if (!perfmon)
return -EINVAL;
- vc4_perfmon_put(perfmon);
+ vc4_perfmon_delete(vc4file, perfmon);
+
return 0;
}
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index d608860d525f..6c433270214d 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -24,8 +24,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
-
-#include "uapi/drm/vc4_drm.h"
+#include <drm/drm_print.h>
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -373,7 +372,7 @@ static void vc4_plane_reset(struct drm_plane *plane)
kfree(plane->state);
- vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
+ vc4_state = kzalloc_obj(*vc4_state);
if (!vc4_state)
return;
@@ -497,8 +496,7 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
u32 v_subsample = fb->format->vsub;
int ret;
- crtc_state = drm_atomic_get_existing_crtc_state(state->state,
- state->crtc);
+ crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
if (!crtc_state) {
DRM_DEBUG_KMS("Invalid crtc state\n");
return -EINVAL;
@@ -875,8 +873,7 @@ static void vc4_plane_calc_load(struct drm_plane_state *state)
unsigned int vscale_factor;
vc4_state = to_vc4_plane_state(state);
- crtc_state = drm_atomic_get_existing_crtc_state(state->state,
- state->crtc);
+ crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
vrefresh = drm_mode_vrefresh(&crtc_state->adjusted_mode);
/* The HVS is able to process 2 pixels/cycle when scaling the source,
@@ -2080,7 +2077,7 @@ static int vc6_plane_mode_set(struct drm_plane *plane,
/* HPPF plane 1 */
vc4_dlist_write(vc4_state, kernel);
/* VPPF plane 1 */
- vc4_dlist_write(vc4_state, kernel);
+ vc4_dlist_write(vc4_state, kernel);
}
}
@@ -2126,7 +2123,7 @@ static int vc6_plane_mode_set(struct drm_plane *plane,
* in the CRTC's flush.
*/
static int vc4_plane_atomic_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
@@ -2172,7 +2169,7 @@ static int vc4_plane_atomic_check(struct drm_plane *plane,
}
static void vc4_plane_atomic_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
/* No contents here. Since we don't know where in the CRTC's
* dlist we should be stored, our dlist is uploaded to the
@@ -2264,7 +2261,7 @@ void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
}
static void vc4_plane_atomic_async_update(struct drm_plane *plane,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
plane);
@@ -2338,7 +2335,7 @@ static void vc4_plane_atomic_async_update(struct drm_plane *plane,
}
static int vc4_plane_atomic_async_check(struct drm_plane *plane,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state, bool flip)
{
struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c
index 14079853338e..c264d21bc3fe 100644
--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
@@ -35,7 +35,8 @@
* actually fairly low.
*/
-#include "uapi/drm/vc4_drm.h"
+#include <drm/drm_print.h>
+
#include "vc4_drv.h"
#include "vc4_packet.h"
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index 4eab069cda75..bc3f366fc3e6 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -9,7 +9,6 @@
#include <linux/clk.h>
#include <linux/component.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -21,6 +20,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include <drm/drm_writeback.h>
@@ -196,7 +196,7 @@ static int vc4_txp_connector_get_modes(struct drm_connector *connector)
static enum drm_mode_status
vc4_txp_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *mode)
{
struct drm_device *dev = connector->dev;
struct drm_mode_config *mode_config = &dev->mode_config;
@@ -245,7 +245,7 @@ static void vc4_txp_armed(struct drm_crtc_state *state)
}
static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
@@ -284,7 +284,7 @@ static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
}
static void vc4_txp_connector_atomic_commit(struct drm_connector *conn,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_device *drm = conn->dev;
struct drm_connector_state *conn_state = drm_atomic_get_new_connector_state(state,
@@ -434,7 +434,7 @@ static const struct drm_crtc_funcs vc4_txp_crtc_funcs = {
};
static int vc4_txp_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc);
@@ -450,14 +450,14 @@ static int vc4_txp_atomic_check(struct drm_crtc *crtc,
}
static void vc4_txp_atomic_enable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
drm_crtc_vblank_on(crtc);
vc4_hvs_atomic_enable(crtc, state);
}
static void vc4_txp_atomic_disable(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_device *dev = crtc->dev;
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index bb09df5000bd..d31b906cb8e7 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -10,6 +10,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <drm/drm_print.h>
+
#include "vc4_drv.h"
#include "vc4_regs.h"
@@ -479,6 +481,7 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, 40); /* a little over 2 frames. */
+ pm_runtime_put_autosuspend(dev);
return 0;
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
index 5bf134968ade..7f2fadfde7a8 100644
--- a/drivers/gpu/drm/vc4/vc4_validate.c
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
@@ -43,7 +43,8 @@
* to use) happens.
*/
-#include "uapi/drm/vc4_drm.h"
+#include <drm/drm_print.h>
+
#include "vc4_drv.h"
#include "vc4_packet.h"
@@ -284,9 +285,6 @@ validate_indexed_prim_list(VALIDATE_ARGS)
if (!ib)
return -EINVAL;
- exec->bin_dep_seqno = max(exec->bin_dep_seqno,
- to_vc4_bo(&ib->base)->write_seqno);
-
if (offset > ib->base.size ||
(ib->base.size - offset) / index_size < length) {
DRM_DEBUG("IB access overflow (%d + %d*%d > %zd)\n",
@@ -738,11 +736,6 @@ reloc_tex(struct vc4_exec_info *exec,
*validated_p0 = tex->dma_addr + p0;
- if (is_cs) {
- exec->bin_dep_seqno = max(exec->bin_dep_seqno,
- to_vc4_bo(&tex->base)->write_seqno);
- }
-
return true;
fail:
DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);
@@ -904,9 +897,6 @@ validate_gl_shader_rec(struct drm_device *dev,
uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
uint32_t max_index;
- exec->bin_dep_seqno = max(exec->bin_dep_seqno,
- to_vc4_bo(&vbo->base)->write_seqno);
-
if (state->addr & 0x8)
stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
diff --git a/drivers/gpu/drm/vc4/vc4_validate_shaders.c b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
index 2d74e786914c..66502a6a4a8e 100644
--- a/drivers/gpu/drm/vc4/vc4_validate_shaders.c
+++ b/drivers/gpu/drm/vc4/vc4_validate_shaders.c
@@ -41,6 +41,8 @@
* this validation is only performed at BO creation time.
*/
+#include <drm/drm_print.h>
+
#include "vc4_drv.h"
#include "vc4_qpu_defines.h"
@@ -288,15 +290,16 @@ static bool require_uniform_address_uniform(struct vc4_validated_shader_info *va
{
uint32_t o = validated_shader->num_uniform_addr_offsets;
uint32_t num_uniforms = validated_shader->uniforms_size / 4;
+ u32 *offsets;
- validated_shader->uniform_addr_offsets =
- krealloc(validated_shader->uniform_addr_offsets,
- (o + 1) *
- sizeof(*validated_shader->uniform_addr_offsets),
- GFP_KERNEL);
- if (!validated_shader->uniform_addr_offsets)
+ offsets = krealloc_array(validated_shader->uniform_addr_offsets,
+ o + 1,
+ sizeof(*validated_shader->uniform_addr_offsets),
+ GFP_KERNEL);
+ if (!offsets)
return false;
+ validated_shader->uniform_addr_offsets = offsets;
validated_shader->uniform_addr_offsets[o] = num_uniforms;
validated_shader->num_uniform_addr_offsets++;
@@ -801,7 +804,7 @@ vc4_validate_shader(struct drm_gem_dma_object *shader_obj)
if (!validation_state.branch_targets)
goto fail;
- validated_shader = kcalloc(1, sizeof(*validated_shader), GFP_KERNEL);
+ validated_shader = kzalloc_objs(*validated_shader, 1);
if (!validated_shader)
goto fail;
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 06d702e879b0..792b7b39be59 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -17,6 +17,7 @@
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include <linux/clk.h>
@@ -537,11 +538,11 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
}
static void vc4_vec_encoder_disable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_device *drm = encoder->dev;
struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
- int idx, ret;
+ int idx;
if (!drm_dev_enter(drm, &idx))
return;
@@ -555,21 +556,13 @@ static void vc4_vec_encoder_disable(struct drm_encoder *encoder,
clk_disable_unprepare(vec->clock);
- ret = pm_runtime_put(&vec->pdev->dev);
- if (ret < 0) {
- drm_err(drm, "Failed to release power domain: %d\n", ret);
- goto err_dev_exit;
- }
-
- drm_dev_exit(idx);
- return;
+ pm_runtime_put(&vec->pdev->dev);
-err_dev_exit:
drm_dev_exit(idx);
}
static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
- struct drm_atomic_state *state)
+ struct drm_atomic_commit *state)
{
struct drm_device *drm = encoder->dev;
struct vc4_vec *vec = encoder_to_vc4_vec(encoder);