From 4350aa21cca48a5d951ba108290bad703fbc0630 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Tue, 12 Dec 2023 14:57:54 -0500 Subject: fbdev/simplefb: change loglevel when the power domains cannot be parsed When the power domains cannot be parsed, the message is incorrectly logged as an info message. Let's change this to an error since an error is returned. Fixes: 92a511a568e4 ("fbdev/simplefb: Add support for generic power-domains") Signed-off-by: Brian Masney Acked-by: Andrew Halaney Acked-by: Javier Martinez Canillas Acked-by: Thierry Reding Signed-off-by: Hans de Goede Link: https://patchwork.freedesktop.org/patch/msgid/20231212195754.232303-1-bmasney@redhat.com --- drivers/video/fbdev/simplefb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index 6f58ee276ad1..028a56525047 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -470,7 +470,7 @@ static int simplefb_attach_genpds(struct simplefb_par *par, if (err == -ENOENT) return 0; - dev_info(dev, "failed to parse power-domains: %d\n", err); + dev_err(dev, "failed to parse power-domains: %d\n", err); return err; } -- cgit v1.2.3 From 9afc1e0aa4851ef48482b03f6304047cf9b550ca Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:27 +0100 Subject: drm/ttm/tests: Add tests for ttm_resource and ttm_sys_man MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test initialization of ttm_resource using different memory domains. Add tests for a system memory manager and functions that can be tested without a fully-featured resource manager. Update ttm_bo_kunit_init() to initialize BO's kref and a genuine GEM drm object. Export ttm_resource_alloc for test purposes only. Signed-off-by: Karolina Stolarek Tested-by: Amaranath Somalapuram Reviewed-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/68b8b293b6bf5f1170d49a1a089ccce9172e2855.1701257386.git.karolina.stolarek@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/tests/Makefile | 1 + drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c | 22 +- drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h | 3 + drivers/gpu/drm/ttm/tests/ttm_resource_test.c | 335 ++++++++++++++++++++++++++ drivers/gpu/drm/ttm/ttm_resource.c | 3 + 5 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/ttm/tests/ttm_resource_test.c diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index ec87c4fc1ad5..c92fe2052ef6 100644 --- a/drivers/gpu/drm/ttm/tests/Makefile +++ b/drivers/gpu/drm/ttm/tests/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \ ttm_device_test.o \ ttm_pool_test.o \ + ttm_resource_test.o \ ttm_kunit_helpers.o diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c index 81661d8827aa..779fbc038f17 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c @@ -29,19 +29,39 @@ struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test, struct ttm_test_devices *devs, size_t size) { - struct drm_gem_object gem_obj = { .size = size }; + struct drm_gem_object gem_obj = { }; struct ttm_buffer_object *bo; + int err; bo = kunit_kzalloc(test, sizeof(*bo), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, bo); bo->base = gem_obj; + err = drm_gem_object_init(devs->drm, &bo->base, size); + KUNIT_ASSERT_EQ(test, err, 0); + bo->bdev = devs->ttm_dev; + kref_init(&bo->kref); return bo; } EXPORT_SYMBOL_GPL(ttm_bo_kunit_init); +struct ttm_place *ttm_place_kunit_init(struct kunit *test, + uint32_t mem_type, uint32_t flags) +{ + struct ttm_place *place; + + place = kunit_kzalloc(test, sizeof(*place), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, place); + + place->mem_type = mem_type; + place->flags = flags; + + return place; +} +EXPORT_SYMBOL_GPL(ttm_place_kunit_init); + struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test) { struct ttm_test_devices *devs; diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h index e261e3660d0b..2f51c833a536 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,8 @@ int ttm_device_kunit_init(struct ttm_test_devices *priv, struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test, struct ttm_test_devices *devs, size_t size); +struct ttm_place *ttm_place_kunit_init(struct kunit *test, + uint32_t mem_type, uint32_t flags); struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test); struct ttm_test_devices *ttm_test_devices_all(struct kunit *test); diff --git a/drivers/gpu/drm/ttm/tests/ttm_resource_test.c b/drivers/gpu/drm/ttm/tests/ttm_resource_test.c new file mode 100644 index 000000000000..029e1f094bb0 --- /dev/null +++ b/drivers/gpu/drm/ttm/tests/ttm_resource_test.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ +#include + +#include "ttm_kunit_helpers.h" + +#define RES_SIZE SZ_4K +#define TTM_PRIV_DUMMY_REG (TTM_NUM_MEM_TYPES - 1) + +struct ttm_resource_test_case { + const char *description; + uint32_t mem_type; + uint32_t flags; +}; + +struct ttm_resource_test_priv { + struct ttm_test_devices *devs; + struct ttm_buffer_object *bo; + struct ttm_place *place; +}; + +static const struct ttm_resource_manager_func ttm_resource_manager_mock_funcs = { }; + +static int ttm_resource_test_init(struct kunit *test) +{ + struct ttm_resource_test_priv *priv; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, priv); + + priv->devs = ttm_test_devices_all(test); + KUNIT_ASSERT_NOT_NULL(test, priv->devs); + + test->priv = priv; + + return 0; +} + +static void ttm_resource_test_fini(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + + ttm_test_devices_put(test, priv->devs); +} + +static void ttm_init_test_mocks(struct kunit *test, + struct ttm_resource_test_priv *priv, + uint32_t mem_type, uint32_t flags) +{ + size_t size = RES_SIZE; + + /* Make sure we have what we need for a good BO mock */ + KUNIT_ASSERT_NOT_NULL(test, priv->devs->ttm_dev); + + priv->bo = ttm_bo_kunit_init(test, priv->devs, size); + priv->place = ttm_place_kunit_init(test, mem_type, flags); +} + +static void ttm_init_test_manager(struct kunit *test, + struct ttm_resource_test_priv *priv, + uint32_t mem_type) +{ + struct ttm_device *ttm_dev = priv->devs->ttm_dev; + struct ttm_resource_manager *man; + size_t size = SZ_16K; + + man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, man); + + man->use_tt = false; + man->func = &ttm_resource_manager_mock_funcs; + + ttm_resource_manager_init(man, ttm_dev, size); + ttm_set_driver_manager(ttm_dev, mem_type, man); + ttm_resource_manager_set_used(man, true); +} + +static const struct ttm_resource_test_case ttm_resource_cases[] = { + { + .description = "Init resource in TTM_PL_SYSTEM", + .mem_type = TTM_PL_SYSTEM, + }, + { + .description = "Init resource in TTM_PL_VRAM", + .mem_type = TTM_PL_VRAM, + }, + { + .description = "Init resource in a private placement", + .mem_type = TTM_PRIV_DUMMY_REG, + }, + { + .description = "Init resource in TTM_PL_SYSTEM, set placement flags", + .mem_type = TTM_PL_SYSTEM, + .flags = TTM_PL_FLAG_TOPDOWN, + }, +}; + +static void ttm_resource_case_desc(const struct ttm_resource_test_case *t, char *desc) +{ + strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(ttm_resource, ttm_resource_cases, ttm_resource_case_desc); + +static void ttm_resource_init_basic(struct kunit *test) +{ + const struct ttm_resource_test_case *params = test->param_value; + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + uint64_t expected_usage; + + ttm_init_test_mocks(test, priv, params->mem_type, params->flags); + bo = priv->bo; + place = priv->place; + + if (params->mem_type > TTM_PL_SYSTEM) + ttm_init_test_manager(test, priv, params->mem_type); + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + expected_usage = man->usage + RES_SIZE; + + KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority])); + + ttm_resource_init(bo, place, res); + + KUNIT_ASSERT_EQ(test, res->start, 0); + KUNIT_ASSERT_EQ(test, res->size, RES_SIZE); + KUNIT_ASSERT_EQ(test, res->mem_type, place->mem_type); + KUNIT_ASSERT_EQ(test, res->placement, place->flags); + KUNIT_ASSERT_PTR_EQ(test, res->bo, bo); + + KUNIT_ASSERT_NULL(test, res->bus.addr); + KUNIT_ASSERT_EQ(test, res->bus.offset, 0); + KUNIT_ASSERT_FALSE(test, res->bus.is_iomem); + KUNIT_ASSERT_EQ(test, res->bus.caching, ttm_cached); + KUNIT_ASSERT_EQ(test, man->usage, expected_usage); + + KUNIT_ASSERT_TRUE(test, list_is_singular(&man->lru[bo->priority])); + + ttm_resource_fini(man, res); +} + +static void ttm_resource_init_pinned(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + + ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0); + bo = priv->bo; + place = priv->place; + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_pin(bo); + ttm_resource_init(bo, place, res); + KUNIT_ASSERT_TRUE(test, list_is_singular(&bo->bdev->pinned)); + + ttm_bo_unpin(bo); + ttm_resource_fini(man, res); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); +} + +static void ttm_resource_fini_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + + ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, 0); + bo = priv->bo; + place = priv->place; + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + ttm_resource_init(bo, place, res); + ttm_resource_fini(man, res); + + KUNIT_ASSERT_TRUE(test, list_empty(&res->lru)); + KUNIT_ASSERT_EQ(test, man->usage, 0); +} + +static void ttm_resource_manager_init_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + size_t size = SZ_16K; + + man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, man); + + ttm_resource_manager_init(man, priv->devs->ttm_dev, size); + + KUNIT_ASSERT_PTR_EQ(test, man->bdev, priv->devs->ttm_dev); + KUNIT_ASSERT_EQ(test, man->size, size); + KUNIT_ASSERT_EQ(test, man->usage, 0); + KUNIT_ASSERT_NULL(test, man->move); + KUNIT_ASSERT_NOT_NULL(test, &man->move_lock); + + for (int i = 0; i < TTM_MAX_BO_PRIORITY; ++i) + KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[i])); +} + +static void ttm_resource_manager_usage_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource *res; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource_manager *man; + uint64_t actual_usage; + + ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, TTM_PL_FLAG_TOPDOWN); + bo = priv->bo; + place = priv->place; + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); + + ttm_resource_init(bo, place, res); + actual_usage = ttm_resource_manager_usage(man); + + KUNIT_ASSERT_EQ(test, actual_usage, RES_SIZE); + + ttm_resource_fini(man, res); +} + +static void ttm_resource_manager_set_used_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + + man = ttm_manager_type(priv->devs->ttm_dev, TTM_PL_SYSTEM); + KUNIT_ASSERT_TRUE(test, man->use_type); + + ttm_resource_manager_set_used(man, false); + KUNIT_ASSERT_FALSE(test, man->use_type); +} + +static void ttm_sys_man_alloc_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource *res; + uint32_t mem_type = TTM_PL_SYSTEM; + int ret; + + ttm_init_test_mocks(test, priv, mem_type, 0); + bo = priv->bo; + place = priv->place; + + man = ttm_manager_type(priv->devs->ttm_dev, mem_type); + ret = man->func->alloc(man, bo, place, &res); + + KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_ASSERT_EQ(test, res->size, RES_SIZE); + KUNIT_ASSERT_EQ(test, res->mem_type, mem_type); + KUNIT_ASSERT_PTR_EQ(test, res->bo, bo); + + ttm_resource_fini(man, res); +} + +static void ttm_sys_man_free_basic(struct kunit *test) +{ + struct ttm_resource_test_priv *priv = test->priv; + struct ttm_resource_manager *man; + struct ttm_buffer_object *bo; + struct ttm_place *place; + struct ttm_resource *res; + uint32_t mem_type = TTM_PL_SYSTEM; + + ttm_init_test_mocks(test, priv, mem_type, 0); + bo = priv->bo; + place = priv->place; + + res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, res); + + ttm_resource_alloc(bo, place, &res); + + man = ttm_manager_type(priv->devs->ttm_dev, mem_type); + man->func->free(man, res); + + KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority])); + KUNIT_ASSERT_EQ(test, man->usage, 0); +} + +static struct kunit_case ttm_resource_test_cases[] = { + KUNIT_CASE_PARAM(ttm_resource_init_basic, ttm_resource_gen_params), + KUNIT_CASE(ttm_resource_init_pinned), + KUNIT_CASE(ttm_resource_fini_basic), + KUNIT_CASE(ttm_resource_manager_init_basic), + KUNIT_CASE(ttm_resource_manager_usage_basic), + KUNIT_CASE(ttm_resource_manager_set_used_basic), + KUNIT_CASE(ttm_sys_man_alloc_basic), + KUNIT_CASE(ttm_sys_man_free_basic), + {} +}; + +static struct kunit_suite ttm_resource_test_suite = { + .name = "ttm_resource", + .init = ttm_resource_test_init, + .exit = ttm_resource_test_fini, + .test_cases = ttm_resource_test_cases, +}; + +kunit_test_suites(&ttm_resource_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c index 46ff9c75bb12..02b96d23fdb9 100644 --- a/drivers/gpu/drm/ttm/ttm_resource.c +++ b/drivers/gpu/drm/ttm/ttm_resource.c @@ -30,6 +30,8 @@ #include #include +#include + /** * ttm_lru_bulk_move_init - initialize a bulk move structure * @bulk: the structure to init @@ -240,6 +242,7 @@ int ttm_resource_alloc(struct ttm_buffer_object *bo, spin_unlock(&bo->bdev->lru_lock); return 0; } +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_resource_alloc); void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res) { -- cgit v1.2.3 From e6f7c641fae339cd5df28186677de1741e0c40c7 Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:28 +0100 Subject: drm/ttm/tests: Add tests for ttm_tt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test initialization, creation and destruction of ttm_tt instances. Export ttm_tt_destroy and ttm_tt_create symbols for testing purposes. Signed-off-by: Karolina Stolarek Reviewed-by: Christian König Tested-by: Amaranath Somalapuram Link: https://patchwork.freedesktop.org/patch/msgid/4459cb89c666bfa377753ae18d0c8917131638e8.1701257386.git.karolina.stolarek@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/tests/Makefile | 1 + drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c | 20 ++ drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 295 ++++++++++++++++++++++++++ drivers/gpu/drm/ttm/ttm_tt.c | 3 + 4 files changed, 319 insertions(+) create mode 100644 drivers/gpu/drm/ttm/tests/ttm_tt_test.c diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index c92fe2052ef6..f570530bbb60 100644 --- a/drivers/gpu/drm/ttm/tests/Makefile +++ b/drivers/gpu/drm/ttm/tests/Makefile @@ -4,4 +4,5 @@ obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \ ttm_device_test.o \ ttm_pool_test.o \ ttm_resource_test.o \ + ttm_tt_test.o \ ttm_kunit_helpers.o diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c index 779fbc038f17..ba4e5c689164 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c @@ -2,9 +2,29 @@ /* * Copyright © 2023 Intel Corporation */ +#include + #include "ttm_kunit_helpers.h" +static struct ttm_tt *ttm_tt_simple_create(struct ttm_buffer_object *bo, + uint32_t page_flags) +{ + struct ttm_tt *tt; + + tt = kzalloc(sizeof(*tt), GFP_KERNEL); + ttm_tt_init(tt, bo, page_flags, ttm_cached, 0); + + return tt; +} + +static void ttm_tt_simple_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) +{ + kfree(ttm); +} + struct ttm_device_funcs ttm_dev_funcs = { + .ttm_tt_create = ttm_tt_simple_create, + .ttm_tt_destroy = ttm_tt_simple_destroy, }; EXPORT_SYMBOL_GPL(ttm_dev_funcs); diff --git a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c new file mode 100644 index 000000000000..fd4502c18de6 --- /dev/null +++ b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ +#include +#include + +#include "ttm_kunit_helpers.h" + +#define BO_SIZE SZ_4K + +struct ttm_tt_test_case { + const char *description; + uint32_t size; + uint32_t extra_pages_num; +}; + +static int ttm_tt_test_init(struct kunit *test) +{ + struct ttm_test_devices *priv; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, priv); + + priv = ttm_test_devices_all(test); + test->priv = priv; + + return 0; +} + +static const struct ttm_tt_test_case ttm_tt_init_basic_cases[] = { + { + .description = "Page-aligned size", + .size = SZ_4K, + }, + { + .description = "Extra pages requested", + .size = SZ_4K, + .extra_pages_num = 1, + }, +}; + +static void ttm_tt_init_case_desc(const struct ttm_tt_test_case *t, + char *desc) +{ + strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases, + ttm_tt_init_case_desc); + +static void ttm_tt_init_basic(struct kunit *test) +{ + const struct ttm_tt_test_case *params = test->param_value; + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + uint32_t page_flags = TTM_TT_FLAG_ZERO_ALLOC; + enum ttm_caching caching = ttm_cached; + uint32_t extra_pages = params->extra_pages_num; + int num_pages = params->size >> PAGE_SHIFT; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, params->size); + + err = ttm_tt_init(tt, bo, page_flags, caching, extra_pages); + KUNIT_ASSERT_EQ(test, err, 0); + + KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages + extra_pages); + + KUNIT_ASSERT_EQ(test, tt->page_flags, page_flags); + KUNIT_ASSERT_EQ(test, tt->caching, caching); + + KUNIT_ASSERT_NULL(test, tt->dma_address); + KUNIT_ASSERT_NULL(test, tt->swap_storage); +} + +static void ttm_tt_init_misaligned(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + uint32_t size = SZ_8K; + int num_pages = (size + SZ_4K) >> PAGE_SHIFT; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, size); + + /* Make the object size misaligned */ + bo->base.size += 1; + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + + KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages); +} + +static void ttm_tt_fini_basic(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_NOT_NULL(test, tt->pages); + + ttm_tt_fini(tt); + KUNIT_ASSERT_NULL(test, tt->pages); +} + +static void ttm_tt_fini_sg(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_sg_tt_init(tt, bo, 0, caching); + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_NOT_NULL(test, tt->dma_address); + + ttm_tt_fini(tt); + KUNIT_ASSERT_NULL(test, tt->dma_address); +} + +static void ttm_tt_fini_shmem(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + struct file *shmem; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + + shmem = shmem_file_setup("ttm swap", BO_SIZE, 0); + tt->swap_storage = shmem; + + ttm_tt_fini(tt); + KUNIT_ASSERT_NULL(test, tt->swap_storage); +} + +static void ttm_tt_create_basic(struct kunit *test) +{ + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_device; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_EXPECT_EQ(test, err, 0); + KUNIT_EXPECT_NOT_NULL(test, bo->ttm); + + /* Free manually, as it was allocated outside of KUnit */ + kfree(bo->ttm); +} + +static void ttm_tt_create_invalid_bo_type(struct kunit *test) +{ + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_sg + 1; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_EXPECT_EQ(test, err, -EINVAL); + KUNIT_EXPECT_NULL(test, bo->ttm); +} + +static void ttm_tt_create_ttm_exists(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ttm_tt *tt; + enum ttm_caching caching = ttm_cached; + int err; + + tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, tt); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_tt_init(tt, bo, 0, caching, 0); + KUNIT_ASSERT_EQ(test, err, 0); + bo->ttm = tt; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + /* Expect to keep the previous TTM */ + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_PTR_EQ(test, tt, bo->ttm); +} + +static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo, + uint32_t page_flags) +{ + return NULL; +} + +static struct ttm_device_funcs ttm_dev_empty_funcs = { + .ttm_tt_create = ttm_tt_null_create, +}; + +static void ttm_tt_create_failed(struct kunit *test) +{ + const struct ttm_test_devices *devs = test->priv; + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + /* Update ttm_device_funcs so we don't alloc ttm_tt */ + devs->ttm_dev->funcs = &ttm_dev_empty_funcs; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, err, -ENOMEM); +} + +static void ttm_tt_destroy_basic(struct kunit *test) +{ + const struct ttm_test_devices *devs = test->priv; + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_NOT_NULL(test, bo->ttm); + + ttm_tt_destroy(devs->ttm_dev, bo->ttm); +} + +static struct kunit_case ttm_tt_test_cases[] = { + KUNIT_CASE_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_gen_params), + KUNIT_CASE(ttm_tt_init_misaligned), + KUNIT_CASE(ttm_tt_fini_basic), + KUNIT_CASE(ttm_tt_fini_sg), + KUNIT_CASE(ttm_tt_fini_shmem), + KUNIT_CASE(ttm_tt_create_basic), + KUNIT_CASE(ttm_tt_create_invalid_bo_type), + KUNIT_CASE(ttm_tt_create_ttm_exists), + KUNIT_CASE(ttm_tt_create_failed), + KUNIT_CASE(ttm_tt_destroy_basic), + {} +}; + +static struct kunit_suite ttm_tt_test_suite = { + .name = "ttm_tt", + .init = ttm_tt_test_init, + .exit = ttm_test_devices_fini, + .test_cases = ttm_tt_test_cases, +}; + +kunit_test_suites(&ttm_tt_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index e0a77671edd6..d978dc539a9b 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -91,6 +92,7 @@ int ttm_tt_create(struct ttm_buffer_object *bo, bool zero_alloc) return 0; } +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_create); /* * Allocates storage for pointers to the pages that back the ttm. @@ -129,6 +131,7 @@ void ttm_tt_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) { bdev->funcs->ttm_tt_destroy(bdev, ttm); } +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_destroy); static void ttm_tt_init_fields(struct ttm_tt *ttm, struct ttm_buffer_object *bo, -- cgit v1.2.3 From 995279d280d1ef5cc349b6eafee4dccd720c99bf Mon Sep 17 00:00:00 2001 From: Karolina Stolarek Date: Wed, 29 Nov 2023 13:02:29 +0100 Subject: drm/ttm/tests: Add tests for ttm_bo functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test reservation and release of TTM buffer objects. Add tests to check pin and unpin operations. Signed-off-by: Karolina Stolarek Tested-by: Amaranath Somalapuram Reviewed-by: Andi Shyti Link: https://patchwork.freedesktop.org/patch/msgid/fcd53970f55ae4be8c738e03f9fcf45366d20b47.1701257386.git.karolina.stolarek@intel.com Signed-off-by: Christian König --- drivers/gpu/drm/ttm/tests/Makefile | 1 + drivers/gpu/drm/ttm/tests/ttm_bo_test.c | 622 ++++++++++++++++++++++++++ drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c | 6 + 3 files changed, 629 insertions(+) create mode 100644 drivers/gpu/drm/ttm/tests/ttm_bo_test.c diff --git a/drivers/gpu/drm/ttm/tests/Makefile b/drivers/gpu/drm/ttm/tests/Makefile index f570530bbb60..468535f7eed2 100644 --- a/drivers/gpu/drm/ttm/tests/Makefile +++ b/drivers/gpu/drm/ttm/tests/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \ ttm_pool_test.o \ ttm_resource_test.o \ ttm_tt_test.o \ + ttm_bo_test.o \ ttm_kunit_helpers.o diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c new file mode 100644 index 000000000000..1f8a4f8adc92 --- /dev/null +++ b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c @@ -0,0 +1,622 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2023 Intel Corporation + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ttm_kunit_helpers.h" + +#define BO_SIZE SZ_8K + +struct ttm_bo_test_case { + const char *description; + bool interruptible; + bool no_wait; +}; + +static const struct ttm_bo_test_case ttm_bo_reserved_cases[] = { + { + .description = "Cannot be interrupted and sleeps", + .interruptible = false, + .no_wait = false, + }, + { + .description = "Cannot be interrupted, locks straight away", + .interruptible = false, + .no_wait = true, + }, + { + .description = "Can be interrupted, sleeps", + .interruptible = true, + .no_wait = false, + }, +}; + +static void ttm_bo_init_case_desc(const struct ttm_bo_test_case *t, + char *desc) +{ + strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(ttm_bo_reserve, ttm_bo_reserved_cases, ttm_bo_init_case_desc); + +static void ttm_bo_reserve_optimistic_no_ticket(struct kunit *test) +{ + const struct ttm_bo_test_case *params = test->param_value; + struct ttm_buffer_object *bo; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_bo_reserve(bo, params->interruptible, params->no_wait, NULL); + KUNIT_ASSERT_EQ(test, err, 0); + + dma_resv_unlock(bo->base.resv); +} + +static void ttm_bo_reserve_locked_no_sleep(struct kunit *test) +{ + struct ttm_buffer_object *bo; + bool interruptible = false; + bool no_wait = true; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + /* Let's lock it beforehand */ + dma_resv_lock(bo->base.resv, NULL); + + err = ttm_bo_reserve(bo, interruptible, no_wait, NULL); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, err, -EBUSY); +} + +static void ttm_bo_reserve_no_wait_ticket(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ww_acquire_ctx ctx; + bool interruptible = false; + bool no_wait = true; + int err; + + ww_acquire_init(&ctx, &reservation_ww_class); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + KUNIT_ASSERT_EQ(test, err, -EBUSY); + + ww_acquire_fini(&ctx); +} + +static void ttm_bo_reserve_double_resv(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct ww_acquire_ctx ctx; + bool interruptible = false; + bool no_wait = false; + int err; + + ww_acquire_init(&ctx, &reservation_ww_class); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + KUNIT_ASSERT_EQ(test, err, 0); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + + dma_resv_unlock(bo->base.resv); + ww_acquire_fini(&ctx); + + KUNIT_ASSERT_EQ(test, err, -EALREADY); +} + +/* + * A test case heavily inspired by ww_test_edeadlk_normal(). It injects + * a deadlock by manipulating the sequence number of the context that holds + * dma_resv lock of bo2 so the other context is "wounded" and has to back off + * (indicated by -EDEADLK). The subtest checks if ttm_bo_reserve() properly + * propagates that error. + */ +static void ttm_bo_reserve_deadlock(struct kunit *test) +{ + struct ttm_buffer_object *bo1, *bo2; + struct ww_acquire_ctx ctx1, ctx2; + bool interruptible = false; + bool no_wait = false; + int err; + + bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + ww_acquire_init(&ctx1, &reservation_ww_class); + mutex_lock(&bo2->base.resv->lock.base); + + /* The deadlock will be caught by WW mutex, don't warn about it */ + lock_release(&bo2->base.resv->lock.base.dep_map, 1); + + bo2->base.resv->lock.ctx = &ctx2; + ctx2 = ctx1; + ctx2.stamp--; /* Make the context holding the lock younger */ + + err = ttm_bo_reserve(bo1, interruptible, no_wait, &ctx1); + KUNIT_ASSERT_EQ(test, err, 0); + + err = ttm_bo_reserve(bo2, interruptible, no_wait, &ctx1); + KUNIT_ASSERT_EQ(test, err, -EDEADLK); + + dma_resv_unlock(bo1->base.resv); + ww_acquire_fini(&ctx1); +} + +#if IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST) +struct signal_timer { + struct timer_list timer; + struct ww_acquire_ctx *ctx; +}; + +static void signal_for_ttm_bo_reserve(struct timer_list *t) +{ + struct signal_timer *s_timer = from_timer(s_timer, t, timer); + struct task_struct *task = s_timer->ctx->task; + + do_send_sig_info(SIGTERM, SEND_SIG_PRIV, task, PIDTYPE_PID); +} + +static int threaded_ttm_bo_reserve(void *arg) +{ + struct ttm_buffer_object *bo = arg; + struct signal_timer s_timer; + struct ww_acquire_ctx ctx; + bool interruptible = true; + bool no_wait = false; + int err; + + ww_acquire_init(&ctx, &reservation_ww_class); + + /* Prepare a signal that will interrupt the reservation attempt */ + timer_setup_on_stack(&s_timer.timer, &signal_for_ttm_bo_reserve, 0); + s_timer.ctx = &ctx; + + mod_timer(&s_timer.timer, msecs_to_jiffies(100)); + + err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx); + + timer_delete_sync(&s_timer.timer); + destroy_timer_on_stack(&s_timer.timer); + + ww_acquire_fini(&ctx); + + return err; +} + +static void ttm_bo_reserve_interrupted(struct kunit *test) +{ + struct ttm_buffer_object *bo; + struct task_struct *task; + int err; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + task = kthread_create(threaded_ttm_bo_reserve, bo, "ttm-bo-reserve"); + + if (IS_ERR(task)) + KUNIT_FAIL(test, "Couldn't create ttm bo reserve task\n"); + + /* Take a lock so the threaded reserve has to wait */ + mutex_lock(&bo->base.resv->lock.base); + + wake_up_process(task); + msleep(20); + err = kthread_stop(task); + + mutex_unlock(&bo->base.resv->lock.base); + + KUNIT_ASSERT_EQ(test, err, -ERESTARTSYS); +} +#endif /* IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST) */ + +static void ttm_bo_unreserve_basic(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_device *ttm_dev; + struct ttm_resource *res1, *res2; + struct ttm_place *place; + struct ttm_resource_manager *man; + unsigned int bo_prio = TTM_MAX_BO_PRIORITY - 1; + uint32_t mem_type = TTM_PL_SYSTEM; + int err; + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->priority = bo_prio; + + err = ttm_resource_alloc(bo, place, &res1); + KUNIT_ASSERT_EQ(test, err, 0); + + bo->resource = res1; + + /* Add a dummy resource to populate LRU */ + ttm_resource_alloc(bo, place, &res2); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unreserve(bo); + + man = ttm_manager_type(priv->ttm_dev, mem_type); + KUNIT_ASSERT_EQ(test, + list_is_last(&res1->lru, &man->lru[bo->priority]), 1); + + ttm_resource_free(bo, &res2); + ttm_resource_free(bo, &res1); +} + +static void ttm_bo_unreserve_pinned(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_device *ttm_dev; + struct ttm_resource *res1, *res2; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + int err; + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + place = ttm_place_kunit_init(test, mem_type, 0); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_pin(bo); + + err = ttm_resource_alloc(bo, place, &res1); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res1; + + /* Add a dummy resource to the pinned list */ + err = ttm_resource_alloc(bo, place, &res2); + KUNIT_ASSERT_EQ(test, err, 0); + KUNIT_ASSERT_EQ(test, + list_is_last(&res2->lru, &priv->ttm_dev->pinned), 1); + + ttm_bo_unreserve(bo); + KUNIT_ASSERT_EQ(test, + list_is_last(&res1->lru, &priv->ttm_dev->pinned), 1); + + ttm_resource_free(bo, &res1); + ttm_resource_free(bo, &res2); +} + +static void ttm_bo_unreserve_bulk(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_lru_bulk_move lru_bulk_move; + struct ttm_lru_bulk_move_pos *pos; + struct ttm_buffer_object *bo1, *bo2; + struct ttm_resource *res1, *res2; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + unsigned int bo_priority = 0; + int err; + + ttm_lru_bulk_move_init(&lru_bulk_move); + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + dma_resv_lock(bo1->base.resv, NULL); + ttm_bo_set_bulk_move(bo1, &lru_bulk_move); + dma_resv_unlock(bo1->base.resv); + + err = ttm_resource_alloc(bo1, place, &res1); + KUNIT_ASSERT_EQ(test, err, 0); + bo1->resource = res1; + + dma_resv_lock(bo2->base.resv, NULL); + ttm_bo_set_bulk_move(bo2, &lru_bulk_move); + dma_resv_unlock(bo2->base.resv); + + err = ttm_resource_alloc(bo2, place, &res2); + KUNIT_ASSERT_EQ(test, err, 0); + bo2->resource = res2; + + ttm_bo_reserve(bo1, false, false, NULL); + ttm_bo_unreserve(bo1); + + pos = &lru_bulk_move.pos[mem_type][bo_priority]; + KUNIT_ASSERT_PTR_EQ(test, res1, pos->last); + + ttm_resource_free(bo1, &res1); + ttm_resource_free(bo2, &res2); +} + +static void ttm_bo_put_basic(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_resource *res; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + int err; + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_device; + + err = ttm_resource_alloc(bo, place, &res); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res; + + dma_resv_lock(bo->base.resv, NULL); + err = ttm_tt_create(bo, false); + dma_resv_unlock(bo->base.resv); + KUNIT_EXPECT_EQ(test, err, 0); + + ttm_bo_put(bo); +} + +static const char *mock_name(struct dma_fence *f) +{ + return "kunit-ttm-bo-put"; +} + +static const struct dma_fence_ops mock_fence_ops = { + .get_driver_name = mock_name, + .get_timeline_name = mock_name, +}; + +static void ttm_bo_put_shared_resv(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct dma_resv *external_resv; + struct dma_fence *fence; + /* A dummy DMA fence lock */ + spinlock_t fence_lock; + struct ttm_device *ttm_dev; + int err; + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + external_resv = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, external_resv); + + dma_resv_init(external_resv); + + fence = kunit_kzalloc(test, sizeof(*fence), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fence); + + spin_lock_init(&fence_lock); + dma_fence_init(fence, &mock_fence_ops, &fence_lock, 0, 0); + + dma_resv_lock(external_resv, NULL); + dma_resv_reserve_fences(external_resv, 1); + dma_resv_add_fence(external_resv, fence, DMA_RESV_USAGE_BOOKKEEP); + dma_resv_unlock(external_resv); + + dma_fence_signal(fence); + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + bo->type = ttm_bo_type_device; + bo->base.resv = external_resv; + + ttm_bo_put(bo); +} + +static void ttm_bo_pin_basic(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_buffer_object *bo; + struct ttm_device *ttm_dev; + unsigned int no_pins = 3; + int err; + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + for (int i = 0; i < no_pins; i++) { + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_pin(bo); + dma_resv_unlock(bo->base.resv); + } + + KUNIT_ASSERT_EQ(test, bo->pin_count, no_pins); +} + +static void ttm_bo_pin_unpin_resource(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_lru_bulk_move lru_bulk_move; + struct ttm_lru_bulk_move_pos *pos; + struct ttm_buffer_object *bo; + struct ttm_resource *res; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + unsigned int bo_priority = 0; + int err; + + ttm_lru_bulk_move_init(&lru_bulk_move); + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_resource_alloc(bo, place, &res); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res; + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_set_bulk_move(bo, &lru_bulk_move); + ttm_bo_pin(bo); + dma_resv_unlock(bo->base.resv); + + pos = &lru_bulk_move.pos[mem_type][bo_priority]; + + KUNIT_ASSERT_EQ(test, bo->pin_count, 1); + KUNIT_ASSERT_NULL(test, pos->first); + KUNIT_ASSERT_NULL(test, pos->last); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unpin(bo); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_PTR_EQ(test, res, pos->last); + KUNIT_ASSERT_EQ(test, bo->pin_count, 0); + + ttm_resource_free(bo, &res); +} + +static void ttm_bo_multiple_pin_one_unpin(struct kunit *test) +{ + struct ttm_test_devices *priv = test->priv; + struct ttm_lru_bulk_move lru_bulk_move; + struct ttm_lru_bulk_move_pos *pos; + struct ttm_buffer_object *bo; + struct ttm_resource *res; + struct ttm_device *ttm_dev; + struct ttm_place *place; + uint32_t mem_type = TTM_PL_SYSTEM; + unsigned int bo_priority = 0; + int err; + + ttm_lru_bulk_move_init(&lru_bulk_move); + + place = ttm_place_kunit_init(test, mem_type, 0); + + ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ttm_dev); + + err = ttm_device_kunit_init(priv, ttm_dev, false, false); + KUNIT_ASSERT_EQ(test, err, 0); + priv->ttm_dev = ttm_dev; + + bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE); + + err = ttm_resource_alloc(bo, place, &res); + KUNIT_ASSERT_EQ(test, err, 0); + bo->resource = res; + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_set_bulk_move(bo, &lru_bulk_move); + + /* Multiple pins */ + ttm_bo_pin(bo); + ttm_bo_pin(bo); + + dma_resv_unlock(bo->base.resv); + + pos = &lru_bulk_move.pos[mem_type][bo_priority]; + + KUNIT_ASSERT_EQ(test, bo->pin_count, 2); + KUNIT_ASSERT_NULL(test, pos->first); + KUNIT_ASSERT_NULL(test, pos->last); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unpin(bo); + dma_resv_unlock(bo->base.resv); + + KUNIT_ASSERT_EQ(test, bo->pin_count, 1); + KUNIT_ASSERT_NULL(test, pos->first); + KUNIT_ASSERT_NULL(test, pos->last); + + dma_resv_lock(bo->base.resv, NULL); + ttm_bo_unpin(bo); + dma_resv_unlock(bo->base.resv); + + ttm_resource_free(bo, &res); +} + +static struct kunit_case ttm_bo_test_cases[] = { + KUNIT_CASE_PARAM(ttm_bo_reserve_optimistic_no_ticket, + ttm_bo_reserve_gen_params), + KUNIT_CASE(ttm_bo_reserve_locked_no_sleep), + KUNIT_CASE(ttm_bo_reserve_no_wait_ticket), + KUNIT_CASE(ttm_bo_reserve_double_resv), +#if IS_BUILTIN(CONFIG_DRM_TTM_KUNIT_TEST) + KUNIT_CASE(ttm_bo_reserve_interrupted), +#endif + KUNIT_CASE(ttm_bo_reserve_deadlock), + KUNIT_CASE(ttm_bo_unreserve_basic), + KUNIT_CASE(ttm_bo_unreserve_pinned), + KUNIT_CASE(ttm_bo_unreserve_bulk), + KUNIT_CASE(ttm_bo_put_basic), + KUNIT_CASE(ttm_bo_put_shared_resv), + KUNIT_CASE(ttm_bo_pin_basic), + KUNIT_CASE(ttm_bo_pin_unpin_resource), + KUNIT_CASE(ttm_bo_multiple_pin_one_unpin), + {} +}; + +static struct kunit_suite ttm_bo_test_suite = { + .name = "ttm_bo", + .init = ttm_test_devices_init, + .exit = ttm_test_devices_fini, + .test_cases = ttm_bo_test_cases, +}; + +kunit_test_suites(&ttm_bo_test_suite); + +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c index ba4e5c689164..7b7c1fa805fc 100644 --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c @@ -22,6 +22,10 @@ static void ttm_tt_simple_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) kfree(ttm); } +static void dummy_ttm_bo_destroy(struct ttm_buffer_object *bo) +{ +} + struct ttm_device_funcs ttm_dev_funcs = { .ttm_tt_create = ttm_tt_simple_create, .ttm_tt_destroy = ttm_tt_simple_destroy, @@ -61,6 +65,8 @@ struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test, KUNIT_ASSERT_EQ(test, err, 0); bo->bdev = devs->ttm_dev; + bo->destroy = dummy_ttm_bo_destroy; + kref_init(&bo->kref); return bo; -- cgit v1.2.3 From dd20946516b6dc567c733cc3e4538eb9223596cf Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 12 Dec 2023 15:25:56 +0200 Subject: drm/edid: replace __attribute__((packed)) with __packed __packed is preferred over __attribute__((packed)). Signed-off-by: Jani Nikula Reviewed-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20231212132557.3777281-1-jani.nikula@intel.com --- include/drm/drm_edid.h | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 518d1b8106c7..54cc6f04a708 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -46,7 +46,7 @@ struct est_timings { u8 t1; u8 t2; u8 mfg_rsvd; -} __attribute__((packed)); +} __packed; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ #define EDID_TIMING_ASPECT_SHIFT 6 @@ -59,7 +59,7 @@ struct est_timings { struct std_timing { u8 hsize; /* need to multiply by 8 then add 248 */ u8 vfreq_aspect; -} __attribute__((packed)); +} __packed; #define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1) #define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2) @@ -85,12 +85,12 @@ struct detailed_pixel_timing { u8 hborder; u8 vborder; u8 misc; -} __attribute__((packed)); +} __packed; /* If it's not pixel timing, it'll be one of the below */ struct detailed_data_string { u8 str[13]; -} __attribute__((packed)); +} __packed; #define DRM_EDID_RANGE_OFFSET_MIN_VFREQ (1 << 0) /* 1.4 */ #define DRM_EDID_RANGE_OFFSET_MAX_VFREQ (1 << 1) /* 1.4 */ @@ -120,7 +120,7 @@ struct detailed_data_monitor_range { __le16 m; u8 k; u8 j; /* need to divide by 2 */ - } __attribute__((packed)) gtf2; + } __packed gtf2; struct { u8 version; u8 data1; /* high 6 bits: extra clock resolution */ @@ -129,27 +129,27 @@ struct detailed_data_monitor_range { u8 flags; /* preferred aspect and blanking support */ u8 supported_scalings; u8 preferred_refresh; - } __attribute__((packed)) cvt; - } __attribute__((packed)) formula; -} __attribute__((packed)); + } __packed cvt; + } __packed formula; +} __packed; struct detailed_data_wpindex { u8 white_yx_lo; /* Lower 2 bits each */ u8 white_x_hi; u8 white_y_hi; u8 gamma; /* need to divide by 100 then add 1 */ -} __attribute__((packed)); +} __packed; struct detailed_data_color_point { u8 windex1; u8 wpindex1[3]; u8 windex2; u8 wpindex2[3]; -} __attribute__((packed)); +} __packed; struct cvt_timing { u8 code[3]; -} __attribute__((packed)); +} __packed; struct detailed_non_pixel { u8 pad1; @@ -163,8 +163,8 @@ struct detailed_non_pixel { struct detailed_data_wpindex color; struct std_timing timings[6]; struct cvt_timing cvt[4]; - } __attribute__((packed)) data; -} __attribute__((packed)); + } __packed data; +} __packed; #define EDID_DETAIL_EST_TIMINGS 0xf7 #define EDID_DETAIL_CVT_3BYTE 0xf8 @@ -181,8 +181,8 @@ struct detailed_timing { union { struct detailed_pixel_timing pixel_data; struct detailed_non_pixel other_data; - } __attribute__((packed)) data; -} __attribute__((packed)); + } __packed data; +} __packed; #define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 0) #define DRM_EDID_INPUT_SYNC_ON_GREEN (1 << 1) @@ -307,7 +307,7 @@ struct edid { u8 extensions; /* Checksum */ u8 checksum; -} __attribute__((packed)); +} __packed; #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) -- cgit v1.2.3 From 8acf543cc68cefb0b41011fd66d5e11fd8fcee56 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 12 Dec 2023 15:25:57 +0200 Subject: drm/ioc32: replace __attribute__((packed)) with __packed __packed is preferred over __attribute__((packed)). Signed-off-by: Jani Nikula Reviewed-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20231212132557.3777281-2-jani.nikula@intel.com --- drivers/gpu/drm/drm_ioc32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 129e2b91dbfe..e6b5b06de148 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -229,7 +229,7 @@ typedef struct drm_update_draw32 { unsigned int num; /* 64-bit version has a 32-bit pad here */ u64 data; /**< Pointer */ -} __attribute__((packed)) drm_update_draw32_t; +} __packed drm_update_draw32_t; static int compat_drm_update_draw(struct file *file, unsigned int cmd, unsigned long arg) @@ -296,7 +296,7 @@ typedef struct drm_mode_fb_cmd232 { u32 pitches[4]; u32 offsets[4]; u64 modifier[4]; -} __attribute__((packed)) drm_mode_fb_cmd232_t; +} __packed drm_mode_fb_cmd232_t; static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd, unsigned long arg) -- cgit v1.2.3 From 100035bf8677a57371cb9850fad6faf16a2c0c47 Mon Sep 17 00:00:00 2001 From: Donald Robson Date: Thu, 14 Dec 2023 10:33:53 +0000 Subject: MAINTAINERS: Remove Donald Robson from powervr driver maintainers I will be leaving Imagination Technologies on 2023-12-15 and will no longer be working on this driver. Signed-off-by: Donald Robson Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231214103353.122257-1-donald.robson@imgtec.com --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index f2cee321099f..9d959a6881f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10407,7 +10407,6 @@ F: drivers/media/rc/img-ir/ IMGTEC POWERVR DRM DRIVER M: Frank Binns -M: Donald Robson M: Matt Coster S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc -- cgit v1.2.3 From afe6fcb9775882230cd29b529203eabd5d2a638d Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Tue, 24 Oct 2023 08:07:38 +0000 Subject: drm/tegra: dsi: Add missing check for of_find_device_by_node Add check for the return value of of_find_device_by_node() and return the error if it fails in order to avoid NULL pointer dereference. Fixes: e94236cde4d5 ("drm/tegra: dsi: Add ganged mode support") Signed-off-by: Chen Ni Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20231024080738.825553-1-nichen@iscas.ac.cn --- drivers/gpu/drm/tegra/dsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index fbfe92a816d4..e419b76e57d3 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1544,9 +1544,11 @@ static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0); if (np) { struct platform_device *gangster = of_find_device_by_node(np); + of_node_put(np); + if (!gangster) + return -EPROBE_DEFER; dsi->slave = platform_get_drvdata(gangster); - of_node_put(np); if (!dsi->slave) { put_device(&gangster->dev); -- cgit v1.2.3 From 11aa6d78ab8b135bdeba0bdaa10e63527c837b89 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 13 Dec 2023 12:19:51 +0200 Subject: drm/tegra: include drm/drm_edid.h only where needed Reduce the need for rebuilds when drm_edid.h is modified by including it only where needed. v2: Fix build (kernel test robot ) Signed-off-by: Jani Nikula Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20231213101951.3932273-1-jani.nikula@intel.com --- drivers/gpu/drm/tegra/drm.h | 2 +- drivers/gpu/drm/tegra/output.c | 1 + drivers/gpu/drm/tegra/sor.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index ccb5d74fa227..682011166a8f 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -13,7 +13,6 @@ #include #include -#include #include #include #include @@ -26,6 +25,7 @@ /* XXX move to include/uapi/drm/drm_fourcc.h? */ #define DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT BIT_ULL(22) +struct edid; struct reset_control; struct tegra_drm { diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index dc2dcb5ca1c8..88af956ad0e7 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 83341576630d..bad3b8fcc726 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 0800880f4eb789b7d299db40f2e86e056bd33a4e Mon Sep 17 00:00:00 2001 From: Zhang Shurong Date: Wed, 4 Oct 2023 22:10:55 +0800 Subject: drm/tegra: dpaux: Fix PM disable depth imbalance in tegra_dpaux_probe The pm_runtime_enable function increases the power disable depth, which means that we must perform a matching decrement on the error handling path to maintain balance within the given context. Additionally, we need to address the same issue for pm_runtime_get_sync. We fix this by invoking pm_runtime_disable and pm_runtime_put_sync when error returns. Fixes: 82b81b3ec1a7 ("drm/tegra: dpaux: Implement runtime PM") Signed-off-by: Zhang Shurong Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/tencent_B13DB7F6C0023C46157250A524966F326A09@qq.com --- drivers/gpu/drm/tegra/dpaux.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index ef02d530f78d..ae12d001a04b 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -522,7 +522,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) if (err < 0) { dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", dpaux->irq, err); - return err; + goto err_pm_disable; } disable_irq(dpaux->irq); @@ -542,7 +542,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) */ err = tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_I2C); if (err < 0) - return err; + goto err_pm_disable; #ifdef CONFIG_GENERIC_PINCONF dpaux->desc.name = dev_name(&pdev->dev); @@ -555,7 +555,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev) dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux); if (IS_ERR(dpaux->pinctrl)) { dev_err(&pdev->dev, "failed to register pincontrol\n"); - return PTR_ERR(dpaux->pinctrl); + err = PTR_ERR(dpaux->pinctrl); + goto err_pm_disable; } #endif /* enable and clear all interrupts */ @@ -571,10 +572,15 @@ static int tegra_dpaux_probe(struct platform_device *pdev) err = devm_of_dp_aux_populate_ep_devices(&dpaux->aux); if (err < 0) { dev_err(dpaux->dev, "failed to populate AUX bus: %d\n", err); - return err; + goto err_pm_disable; } return 0; + +err_pm_disable: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return err; } static void tegra_dpaux_remove(struct platform_device *pdev) -- cgit v1.2.3 From 830c1ded356369cd1303e8bb87ce3fea6e744de8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:08 +0200 Subject: drm/tegra: dsi: Fix some error handling paths in tegra_dsi_probe() If an error occurs after calling tegra_output_probe(), tegra_output_remove() should be called as already done in the remove function. Fixes: dec727399a4b ("drm/tegra: Add DSI support") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/16820073278d031f6c474a08d5f22a255158585e.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/dsi.c | 54 +++++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index e419b76e57d3..0c8ad8ee5009 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1596,44 +1596,58 @@ static int tegra_dsi_probe(struct platform_device *pdev) if (!pdev->dev.pm_domain) { dsi->rst = devm_reset_control_get(&pdev->dev, "dsi"); - if (IS_ERR(dsi->rst)) - return PTR_ERR(dsi->rst); + if (IS_ERR(dsi->rst)) { + err = PTR_ERR(dsi->rst); + goto remove; + } } dsi->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(dsi->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk), - "cannot get DSI clock\n"); + if (IS_ERR(dsi->clk)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk), + "cannot get DSI clock\n"); + goto remove; + } dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); - if (IS_ERR(dsi->clk_lp)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp), - "cannot get low-power clock\n"); + if (IS_ERR(dsi->clk_lp)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp), + "cannot get low-power clock\n"); + goto remove; + } dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); - if (IS_ERR(dsi->clk_parent)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent), - "cannot get parent clock\n"); + if (IS_ERR(dsi->clk_parent)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent), + "cannot get parent clock\n"); + goto remove; + } dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi"); - if (IS_ERR(dsi->vdd)) - return dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd), - "cannot get VDD supply\n"); + if (IS_ERR(dsi->vdd)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd), + "cannot get VDD supply\n"); + goto remove; + } err = tegra_dsi_setup_clocks(dsi); if (err < 0) { dev_err(&pdev->dev, "cannot setup clocks\n"); - return err; + goto remove; } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); dsi->regs = devm_ioremap_resource(&pdev->dev, regs); - if (IS_ERR(dsi->regs)) - return PTR_ERR(dsi->regs); + if (IS_ERR(dsi->regs)) { + err = PTR_ERR(dsi->regs); + goto remove; + } dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node); - if (IS_ERR(dsi->mipi)) - return PTR_ERR(dsi->mipi); + if (IS_ERR(dsi->mipi)) { + err = PTR_ERR(dsi->mipi); + goto remove; + } dsi->host.ops = &tegra_dsi_host_ops; dsi->host.dev = &pdev->dev; @@ -1664,6 +1678,8 @@ unregister: mipi_dsi_host_unregister(&dsi->host); mipi_free: tegra_mipi_free(dsi->mipi); +remove: + tegra_output_remove(&dsi->output); return err; } -- cgit v1.2.3 From 5286a9fc280c45b6b307ee1b07f7a997e042252c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:09 +0200 Subject: drm/tegra: dsi: Fix missing pm_runtime_disable() in the error handling path of tegra_dsi_probe() If an error occurs after calling pm_runtime_enable(), pm_runtime_disable() should be called as already done in the remove function. Fixes: ef8187d75265 ("drm/tegra: dsi: Implement runtime PM") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/ee4a15c9cd4b574a55cd67c30d2411239ba2cee9.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/dsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 0c8ad8ee5009..db606e151afc 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1675,6 +1675,7 @@ static int tegra_dsi_probe(struct platform_device *pdev) return 0; unregister: + pm_runtime_disable(&pdev->dev); mipi_dsi_host_unregister(&dsi->host); mipi_free: tegra_mipi_free(dsi->mipi); -- cgit v1.2.3 From 643ae131b8598fb2940c92c7d23fe62823a119c8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:10 +0200 Subject: drm/tegra: hdmi: Fix some error handling paths in tegra_hdmi_probe() If an error occurs after calling tegra_output_probe(), tegra_output_remove() should be called as already done in the remove function. Fixes: 59d29c0ec93f ("drm/tegra: Allocate resources at probe time") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/9b7c564eb71977678b20abd73ee52001a51cf327.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/hdmi.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index a1fcee665023..417fb884240a 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -1856,12 +1856,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev) return err; hdmi->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(hdmi->regs)) - return PTR_ERR(hdmi->regs); + if (IS_ERR(hdmi->regs)) { + err = PTR_ERR(hdmi->regs); + goto remove; + } err = platform_get_irq(pdev, 0); if (err < 0) - return err; + goto remove; hdmi->irq = err; @@ -1870,18 +1872,18 @@ static int tegra_hdmi_probe(struct platform_device *pdev) if (err < 0) { dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", hdmi->irq, err); - return err; + goto remove; } platform_set_drvdata(pdev, hdmi); err = devm_pm_runtime_enable(&pdev->dev); if (err) - return err; + goto remove; err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev); if (err) - return err; + goto remove; INIT_LIST_HEAD(&hdmi->client.list); hdmi->client.ops = &hdmi_client_ops; @@ -1891,10 +1893,14 @@ static int tegra_hdmi_probe(struct platform_device *pdev) if (err < 0) { dev_err(&pdev->dev, "failed to register host1x client: %d\n", err); - return err; + goto remove; } return 0; + +remove: + tegra_output_remove(&hdmi->output); + return err; } static void tegra_hdmi_remove(struct platform_device *pdev) -- cgit v1.2.3 From bc456b5d93dbfdbd89f2a036f4f3d8026595f9e4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:11 +0200 Subject: drm/tegra: rgb: Fix some error handling paths in tegra_dc_rgb_probe() If an error occurs after calling tegra_output_probe(), tegra_output_remove() should be called as already done in the remove function. Fixes: 59d29c0ec93f ("drm/tegra: Allocate resources at probe time") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/0001f61eb89048bc36241629b564195689cf54b6.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/rgb.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index fc66bbd913b2..53c492b13d12 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -225,26 +225,28 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) rgb->clk = devm_clk_get(dc->dev, NULL); if (IS_ERR(rgb->clk)) { dev_err(dc->dev, "failed to get clock\n"); - return PTR_ERR(rgb->clk); + err = PTR_ERR(rgb->clk); + goto remove; } rgb->clk_parent = devm_clk_get(dc->dev, "parent"); if (IS_ERR(rgb->clk_parent)) { dev_err(dc->dev, "failed to get parent clock\n"); - return PTR_ERR(rgb->clk_parent); + err = PTR_ERR(rgb->clk_parent); + goto remove; } err = clk_set_parent(rgb->clk, rgb->clk_parent); if (err < 0) { dev_err(dc->dev, "failed to set parent clock: %d\n", err); - return err; + goto remove; } rgb->pll_d_out0 = clk_get_sys(NULL, "pll_d_out0"); if (IS_ERR(rgb->pll_d_out0)) { err = PTR_ERR(rgb->pll_d_out0); dev_err(dc->dev, "failed to get pll_d_out0: %d\n", err); - return err; + goto remove; } if (dc->soc->has_pll_d2_out0) { @@ -252,13 +254,17 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) if (IS_ERR(rgb->pll_d2_out0)) { err = PTR_ERR(rgb->pll_d2_out0); dev_err(dc->dev, "failed to get pll_d2_out0: %d\n", err); - return err; + goto remove; } } dc->rgb = &rgb->output; return 0; + +remove: + tegra_output_remove(&rgb->output); + return err; } void tegra_dc_rgb_remove(struct tegra_dc *dc) -- cgit v1.2.3 From 45c8034db47842b25a3ab6139d71e13b4e67b9b3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:12 +0200 Subject: drm/tegra: rgb: Fix missing clk_put() in the error handling paths of tegra_dc_rgb_probe() If clk_get_sys(..., "pll_d2_out0") fails, the clk_get_sys() call must be undone. Add the missing clk_put and a new 'put_pll_d_out0' label in the error handling path, and use it. Fixes: 0c921b6d4ba0 ("drm/tegra: dc: rgb: Allow changing PLLD rate on Tegra30+") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/0182895ead4e4730426616b0d9995954c960b634.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/rgb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 53c492b13d12..1e8ec50b759e 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -254,7 +254,7 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) if (IS_ERR(rgb->pll_d2_out0)) { err = PTR_ERR(rgb->pll_d2_out0); dev_err(dc->dev, "failed to get pll_d2_out0: %d\n", err); - goto remove; + goto put_pll; } } @@ -262,6 +262,8 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc) return 0; +put_pll: + clk_put(rgb->pll_d_out0); remove: tegra_output_remove(&rgb->output); return err; -- cgit v1.2.3 From 2db4578ef6ffb2b52115ca0ebf897b60ec559556 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 17:22:13 +0200 Subject: drm/tegra: output: Fix missing i2c_put_adapter() in the error handling paths of tegra_output_probe() If an error occurs after a successful of_get_i2c_adapter_by_node() call, it should be undone by a corresponding i2c_put_adapter(). Add the missing i2c_put_adapter() call. Fixes: 9be7d864cf07 ("drm/tegra: Implement panel support") Signed-off-by: Christophe JAILLET Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/b38604178991e1f08b2cda219103be266be2d680.1693667005.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/tegra/output.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 88af956ad0e7..4da3c3d1abbc 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -143,8 +143,10 @@ int tegra_output_probe(struct tegra_output *output) GPIOD_IN, "HDMI hotplug detect"); if (IS_ERR(output->hpd_gpio)) { - if (PTR_ERR(output->hpd_gpio) != -ENOENT) - return PTR_ERR(output->hpd_gpio); + if (PTR_ERR(output->hpd_gpio) != -ENOENT) { + err = PTR_ERR(output->hpd_gpio); + goto put_i2c; + } output->hpd_gpio = NULL; } @@ -153,7 +155,7 @@ int tegra_output_probe(struct tegra_output *output) err = gpiod_to_irq(output->hpd_gpio); if (err < 0) { dev_err(output->dev, "gpiod_to_irq(): %d\n", err); - return err; + goto put_i2c; } output->hpd_irq = err; @@ -166,7 +168,7 @@ int tegra_output_probe(struct tegra_output *output) if (err < 0) { dev_err(output->dev, "failed to request IRQ#%u: %d\n", output->hpd_irq, err); - return err; + goto put_i2c; } output->connector.polled = DRM_CONNECTOR_POLL_HPD; @@ -180,6 +182,12 @@ int tegra_output_probe(struct tegra_output *output) } return 0; + +put_i2c: + if (output->ddc) + i2c_put_adapter(output->ddc); + + return err; } void tegra_output_remove(struct tegra_output *output) -- cgit v1.2.3 From c3b78577462782e20c18cd30f8fe9b735746467b Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:51 +0100 Subject: drm/bridge: tc358767: Use regmap_access_table for writeable registers Using ranges it is easier to add more register where writing is not allowed, especially for sequences of registers. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-2-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 615cc8f950d7..b8b29b291b72 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1992,12 +1992,15 @@ static const struct regmap_access_table tc_volatile_table = { .n_yes_ranges = ARRAY_SIZE(tc_volatile_ranges), }; -static bool tc_writeable_reg(struct device *dev, unsigned int reg) -{ - return (reg != TC_IDREG) && - (reg != DP0_LTSTAT) && - (reg != DP0_SNKLTCHGREQ); -} +static const struct regmap_range tc_non_writeable_ranges[] = { + regmap_reg_range(TC_IDREG, TC_IDREG), + regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), +}; + +static const struct regmap_access_table tc_writeable_table = { + .no_ranges = tc_non_writeable_ranges, + .n_no_ranges = ARRAY_SIZE(tc_non_writeable_ranges), +}; static const struct regmap_config tc_regmap_config = { .name = "tc358767", @@ -2008,7 +2011,7 @@ static const struct regmap_config tc_regmap_config = { .cache_type = REGCACHE_MAPLE, .readable_reg = tc_readable_reg, .volatile_table = &tc_volatile_table, - .writeable_reg = tc_writeable_reg, + .wr_table = &tc_writeable_table, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_LITTLE, }; -- cgit v1.2.3 From 31094d3d2a5c67a9d47ea64eea38ba27335ff67f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:52 +0100 Subject: drm/bridge: tc358767: Fix order of register defines 0x0510 is bigger than 0x50c, order them accordingly. No functional change intended. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-3-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index b8b29b291b72..637d38ec7628 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -116,13 +116,6 @@ /* System */ #define TC_IDREG 0x0500 #define SYSSTAT 0x0508 -#define SYSCTRL 0x0510 -#define DP0_AUDSRC_NO_INPUT (0 << 3) -#define DP0_AUDSRC_I2S_RX (1 << 3) -#define DP0_VIDSRC_NO_INPUT (0 << 0) -#define DP0_VIDSRC_DSI_RX (1 << 0) -#define DP0_VIDSRC_DPI_RX (2 << 0) -#define DP0_VIDSRC_COLOR_BAR (3 << 0) #define SYSRSTENB 0x050c #define ENBI2C (1 << 0) #define ENBLCD0 (1 << 2) @@ -130,6 +123,13 @@ #define ENBDSIRX (1 << 4) #define ENBREG (1 << 5) #define ENBHDCP (1 << 8) +#define SYSCTRL 0x0510 /* System Control Register */ +#define DP0_AUDSRC_NO_INPUT (0 << 3) +#define DP0_AUDSRC_I2S_RX (1 << 3) +#define DP0_VIDSRC_NO_INPUT (0 << 0) +#define DP0_VIDSRC_DSI_RX (1 << 0) +#define DP0_VIDSRC_DPI_RX (2 << 0) +#define DP0_VIDSRC_COLOR_BAR (3 << 0) #define GPIOM 0x0540 #define GPIOC 0x0544 #define GPIOO 0x0548 -- cgit v1.2.3 From f8a4ac9e9e3c56047c3f92748c30fb90476015e4 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:53 +0100 Subject: drm/bridge: tc358767: Add more registers to non-writeable range While at it, also add missing register definitions. HDCP registers are skipped as they are not named, range 0x0980 - 0x09ac. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-4-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 87 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 637d38ec7628..e07b71d1ea8e 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -41,8 +41,24 @@ /* Registers */ +/* DSI D-PHY Layer registers */ +#define D0W_DPHYCONTTX 0x0004 +#define CLW_DPHYCONTTX 0x0020 +#define D0W_DPHYCONTRX 0x0024 +#define D1W_DPHYCONTRX 0x0028 +#define D2W_DPHYCONTRX 0x002c +#define D3W_DPHYCONTRX 0x0030 +#define COM_DPHYCONTRX 0x0038 +#define CLW_CNTRL 0x0040 +#define D0W_CNTRL 0x0044 +#define D1W_CNTRL 0x0048 +#define D2W_CNTRL 0x004c +#define D3W_CNTRL 0x0050 +#define TESTMODE_CNTRL 0x0054 + /* PPI layer registers */ #define PPI_STARTPPI 0x0104 /* START control bit */ +#define PPI_BUSYPPI 0x0108 /* PPI busy status */ #define PPI_LPTXTIMECNT 0x0114 /* LPTX timing signal */ #define LPX_PERIOD 3 #define PPI_LANEENABLE 0x0134 @@ -59,6 +75,7 @@ /* DSI layer registers */ #define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX */ +#define DSI_BUSYDSI 0x0208 /* DSI busy status */ #define DSI_LANEENABLE 0x0210 /* Enables each lane */ #define DSI_RX_START BIT(0) @@ -69,6 +86,20 @@ #define LANEENABLE_L2EN BIT(1) #define LANEENABLE_L3EN BIT(2) +#define DSI_LANESTATUS0 0x0214 /* DSI lane status 0 */ +#define DSI_LANESTATUS1 0x0218 /* DSI lane status 1 */ +#define DSI_INTSTATUS 0x0220 /* Interrupt Status */ +#define DSI_INTMASK 0x0224 /* Interrupt Mask */ +#define DSI_INTCLR 0x0228 /* Interrupt Clear */ +#define DSI_LPTXTO 0x0230 /* LPTX Time Out Counter */ + +/* DSI General Registers */ +#define DSIERRCNT 0x0300 /* DSI Error Count Register */ + +/* DSI Application Layer Registers */ +#define APLCTRL 0x0400 /* Application layer Control Register */ +#define RDPKTLN 0x0404 /* DSI Read packet Length Register */ + /* Display Parallel Input Interface */ #define DPIPXLFMT 0x0440 #define VS_POL_ACTIVE_LOW (1 << 10) @@ -117,6 +148,7 @@ #define TC_IDREG 0x0500 #define SYSSTAT 0x0508 #define SYSRSTENB 0x050c +#define SYSBOOT 0x0504 /* System BootStrap Status Register */ #define ENBI2C (1 << 0) #define ENBLCD0 (1 << 2) #define ENBBM (1 << 3) @@ -141,6 +173,9 @@ #define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10)) #define INT_GPIO_LC(x) (1 << (x == 0 ? 3 : 11)) +#define TEST_INT_C 0x0570 /* Test Interrupts Control Register */ +#define TEST_INT_S 0x0574 /* Test Interrupts Status Register */ + #define INT_GP0_LCNT 0x0584 #define INT_GP1_LCNT 0x0588 @@ -155,6 +190,9 @@ #define DP0_VIDMNGEN0 0x0610 #define DP0_VIDMNGEN1 0x0614 #define DP0_VMNGENSTATUS 0x0618 +#define DP0_AUDMNGEN0 0x0628 /* DP0 Audio Force M Value Register */ +#define DP0_AUDMNGEN1 0x062c /* DP0 Audio Force N Value Register */ +#define DP0_AMNGENSTATUS 0x0630 /* DP0 Audio Current M Value Register */ /* Main Channel */ #define DP0_SECSAMPLE 0x0640 @@ -224,6 +262,20 @@ #define DP0_SNKLTCHGREQ 0x06d4 #define DP0_LTLOOPCTRL 0x06d8 #define DP0_SNKLTCTRL 0x06e4 +#define DP0_TPATDAT0 0x06e8 /* DP0 Test Pattern bits 29 to 0 */ +#define DP0_TPATDAT1 0x06ec /* DP0 Test Pattern bits 59 to 30 */ +#define DP0_TPATDAT2 0x06f0 /* DP0 Test Pattern bits 89 to 60 */ +#define DP0_TPATDAT3 0x06f4 /* DP0 Test Pattern bits 119 to 90 */ + +#define AUDCFG0 0x0700 /* DP0 Audio Config0 Register */ +#define AUDCFG1 0x0704 /* DP0 Audio Config1 Register */ +#define AUDIFDATA0 0x0708 /* DP0 Audio Info Frame Bytes 3 to 0 */ +#define AUDIFDATA1 0x070c /* DP0 Audio Info Frame Bytes 7 to 4 */ +#define AUDIFDATA2 0x0710 /* DP0 Audio Info Frame Bytes 11 to 8 */ +#define AUDIFDATA3 0x0714 /* DP0 Audio Info Frame Bytes 15 to 12 */ +#define AUDIFDATA4 0x0718 /* DP0 Audio Info Frame Bytes 19 to 16 */ +#define AUDIFDATA5 0x071c /* DP0 Audio Info Frame Bytes 23 to 20 */ +#define AUDIFDATA6 0x0720 /* DP0 Audio Info Frame Bytes 27 to 24 */ #define DP1_SRCCTRL 0x07a0 @@ -238,6 +290,25 @@ #define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */ #define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */ #define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */ +#define DP_PHY_CFG_WR 0x0810 /* DP PHY Configuration Test Write Register */ +#define DP_PHY_CFG_RD 0x0814 /* DP PHY Configuration Test Read Register */ +#define DP0_AUX_PHY_CTRL 0x0820 /* DP0 AUX PHY Control Register */ +#define DP0_MAIN_PHY_DBG 0x0840 /* DP0 Main PHY Test Debug Register */ + +/* I2S */ +#define I2SCFG 0x0880 /* I2S Audio Config 0 Register */ +#define I2SCH0STAT0 0x0888 /* I2S Audio Channel 0 Status Bytes 3 to 0 */ +#define I2SCH0STAT1 0x088c /* I2S Audio Channel 0 Status Bytes 7 to 4 */ +#define I2SCH0STAT2 0x0890 /* I2S Audio Channel 0 Status Bytes 11 to 8 */ +#define I2SCH0STAT3 0x0894 /* I2S Audio Channel 0 Status Bytes 15 to 12 */ +#define I2SCH0STAT4 0x0898 /* I2S Audio Channel 0 Status Bytes 19 to 16 */ +#define I2SCH0STAT5 0x089c /* I2S Audio Channel 0 Status Bytes 23 to 20 */ +#define I2SCH1STAT0 0x08a0 /* I2S Audio Channel 1 Status Bytes 3 to 0 */ +#define I2SCH1STAT1 0x08a4 /* I2S Audio Channel 1 Status Bytes 7 to 4 */ +#define I2SCH1STAT2 0x08a8 /* I2S Audio Channel 1 Status Bytes 11 to 8 */ +#define I2SCH1STAT3 0x08ac /* I2S Audio Channel 1 Status Bytes 15 to 12 */ +#define I2SCH1STAT4 0x08b0 /* I2S Audio Channel 1 Status Bytes 19 to 16 */ +#define I2SCH1STAT5 0x08b4 /* I2S Audio Channel 1 Status Bytes 23 to 20 */ /* PLL */ #define DP0_PLLCTRL 0x0900 @@ -1833,16 +1904,16 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) case 0x1f4: /* DSI Protocol Layer */ case DSI_STARTDSI: - case 0x208: + case DSI_BUSYDSI: case DSI_LANEENABLE: - case 0x214: - case 0x218: - case 0x220: + case DSI_LANESTATUS0: + case DSI_LANESTATUS1: + case DSI_INTSTATUS: case 0x224: case 0x228: case 0x230: /* DSI General */ - case 0x300: + case DSIERRCNT: /* DSI Application Layer */ case 0x400: case 0x404: @@ -1993,7 +2064,11 @@ static const struct regmap_access_table tc_volatile_table = { }; static const struct regmap_range tc_non_writeable_ranges[] = { - regmap_reg_range(TC_IDREG, TC_IDREG), + regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), + regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), + regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS), + regmap_reg_range(TC_IDREG, SYSSTAT), + regmap_reg_range(GPIOI, GPIOI), regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), }; -- cgit v1.2.3 From b36bc498d1837398e5b355c019dc400201040811 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:54 +0100 Subject: drm/bridge: tc358767: Sort volatile registers according to address Sort the list by the starting address to ease adding new entries. No functional change intended. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-5-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index e07b71d1ea8e..45f8876210fe 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2049,13 +2049,13 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) } static const struct regmap_range tc_volatile_ranges[] = { + regmap_reg_range(VFUEN0, VFUEN0), + regmap_reg_range(GPIOI, GPIOI), + regmap_reg_range(INTSTS_G, INTSTS_G), regmap_reg_range(DP0_AUXWDATA(0), DP0_AUXSTATUS), regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL), regmap_reg_range(DP0_PLLCTRL, PXL_PLLCTRL), - regmap_reg_range(VFUEN0, VFUEN0), - regmap_reg_range(INTSTS_G, INTSTS_G), - regmap_reg_range(GPIOI, GPIOI), }; static const struct regmap_access_table tc_volatile_table = { -- cgit v1.2.3 From ef34c0eb0b58dfdd846093b1a26e63a08acaaf22 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:55 +0100 Subject: drm/bridge: tc358767: Add more volatile registers These registers might change their value without any host write operation. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-6-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 45f8876210fe..d1cde022cb5e 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2049,9 +2049,16 @@ static bool tc_readable_reg(struct device *dev, unsigned int reg) } static const struct regmap_range tc_volatile_ranges[] = { + regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), + regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), + regmap_reg_range(DSI_LANESTATUS0, DSI_INTSTATUS), + regmap_reg_range(DSIERRCNT, DSIERRCNT), regmap_reg_range(VFUEN0, VFUEN0), + regmap_reg_range(SYSSTAT, SYSSTAT), regmap_reg_range(GPIOI, GPIOI), regmap_reg_range(INTSTS_G, INTSTS_G), + regmap_reg_range(DP0_VMNGENSTATUS, DP0_VMNGENSTATUS), + regmap_reg_range(DP0_AMNGENSTATUS, DP0_AMNGENSTATUS), regmap_reg_range(DP0_AUXWDATA(0), DP0_AUXSTATUS), regmap_reg_range(DP0_LTSTAT, DP0_SNKLTCHGREQ), regmap_reg_range(DP_PHY_CTRL, DP_PHY_CTRL), -- cgit v1.2.3 From 230dae78d6d4531cd440daa782533d16ea3cfc33 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:56 +0100 Subject: drm/bridge: tc358767: Add precious register SYSSTAT This is the single register which clears its value upon read operation. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-7-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index d1cde022cb5e..10465398d4e6 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2070,6 +2070,15 @@ static const struct regmap_access_table tc_volatile_table = { .n_yes_ranges = ARRAY_SIZE(tc_volatile_ranges), }; +static const struct regmap_range tc_precious_ranges[] = { + regmap_reg_range(SYSSTAT, SYSSTAT), +}; + +static const struct regmap_access_table tc_precious_table = { + .yes_ranges = tc_precious_ranges, + .n_yes_ranges = ARRAY_SIZE(tc_precious_ranges), +}; + static const struct regmap_range tc_non_writeable_ranges[] = { regmap_reg_range(PPI_BUSYPPI, PPI_BUSYPPI), regmap_reg_range(DSI_BUSYDSI, DSI_BUSYDSI), @@ -2093,6 +2102,7 @@ static const struct regmap_config tc_regmap_config = { .cache_type = REGCACHE_MAPLE, .readable_reg = tc_readable_reg, .volatile_table = &tc_volatile_table, + .precious_table = &tc_precious_table, .wr_table = &tc_writeable_table, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_LITTLE, -- cgit v1.2.3 From 9203f67272531ee17d58966e51f086e9a5deb840 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 12 Dec 2023 08:52:57 +0100 Subject: drm/bridge: tc358767: Add descriptions to register definitions Use the register names from the datasheet. No functional change intended. Signed-off-by: Alexander Stein Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231212075257.75084-8-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/tc358767.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 10465398d4e6..eb0d82a91cb9 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -145,10 +145,10 @@ #define VFUEN BIT(0) /* Video Frame Timing Upload */ /* System */ -#define TC_IDREG 0x0500 -#define SYSSTAT 0x0508 -#define SYSRSTENB 0x050c +#define TC_IDREG 0x0500 /* Chip ID and Revision ID */ #define SYSBOOT 0x0504 /* System BootStrap Status Register */ +#define SYSSTAT 0x0508 /* System Status Register */ +#define SYSRSTENB 0x050c /* System Reset/Enable Register */ #define ENBI2C (1 << 0) #define ENBLCD0 (1 << 2) #define ENBBM (1 << 3) @@ -162,12 +162,12 @@ #define DP0_VIDSRC_DSI_RX (1 << 0) #define DP0_VIDSRC_DPI_RX (2 << 0) #define DP0_VIDSRC_COLOR_BAR (3 << 0) -#define GPIOM 0x0540 -#define GPIOC 0x0544 -#define GPIOO 0x0548 -#define GPIOI 0x054c -#define INTCTL_G 0x0560 -#define INTSTS_G 0x0564 +#define GPIOM 0x0540 /* GPIO Mode Control Register */ +#define GPIOC 0x0544 /* GPIO Direction Control Register */ +#define GPIOO 0x0548 /* GPIO Output Register */ +#define GPIOI 0x054c /* GPIO Input Register */ +#define INTCTL_G 0x0560 /* General Interrupts Control Register */ +#define INTSTS_G 0x0564 /* General Interrupts Status Register */ #define INT_SYSERR BIT(16) #define INT_GPIO_H(x) (1 << (x == 0 ? 2 : 10)) @@ -176,8 +176,8 @@ #define TEST_INT_C 0x0570 /* Test Interrupts Control Register */ #define TEST_INT_S 0x0574 /* Test Interrupts Status Register */ -#define INT_GP0_LCNT 0x0584 -#define INT_GP1_LCNT 0x0588 +#define INT_GP0_LCNT 0x0584 /* Interrupt GPIO0 Low Count Value Register */ +#define INT_GP1_LCNT 0x0588 /* Interrupt GPIO1 Low Count Value Register */ /* Control */ #define DP0CTL 0x0600 @@ -187,9 +187,9 @@ #define DP_EN BIT(0) /* Enable DPTX function */ /* Clocks */ -#define DP0_VIDMNGEN0 0x0610 -#define DP0_VIDMNGEN1 0x0614 -#define DP0_VMNGENSTATUS 0x0618 +#define DP0_VIDMNGEN0 0x0610 /* DP0 Video Force M Value Register */ +#define DP0_VIDMNGEN1 0x0614 /* DP0 Video Force N Value Register */ +#define DP0_VMNGENSTATUS 0x0618 /* DP0 Video Current M Value Register */ #define DP0_AUDMNGEN0 0x0628 /* DP0 Audio Force M Value Register */ #define DP0_AUDMNGEN1 0x062c /* DP0 Audio Force N Value Register */ #define DP0_AMNGENSTATUS 0x0630 /* DP0 Audio Current M Value Register */ @@ -277,7 +277,7 @@ #define AUDIFDATA5 0x071c /* DP0 Audio Info Frame Bytes 23 to 20 */ #define AUDIFDATA6 0x0720 /* DP0 Audio Info Frame Bytes 27 to 24 */ -#define DP1_SRCCTRL 0x07a0 +#define DP1_SRCCTRL 0x07a0 /* DP1 Control Register */ /* PHY */ #define DP_PHY_CTRL 0x0800 -- cgit v1.2.3 From 045159f5018eee5fd2b502dbbfdc31985ac8f516 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Thu, 7 Dec 2023 17:10:43 +0100 Subject: drm/bridge: samsung-dsim: check the return value only if necessary It was useless to check again the "ret" variable if the function register_host() was not called. Signed-off-by: Dario Binacchi Reviewed-by: Frieder Schrempf Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20231207161056.183442-1-dario.binacchi@amarulasolutions.com --- drivers/gpu/drm/bridge/samsung-dsim.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index be5914caa17d..98cd589e4427 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -2020,11 +2020,11 @@ int samsung_dsim_probe(struct platform_device *pdev) else dsi->bridge.timings = &samsung_dsim_bridge_timings_de_high; - if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) + if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->register_host) { ret = dsi->plat_data->host_ops->register_host(dsi); - - if (ret) - goto err_disable_runtime; + if (ret) + goto err_disable_runtime; + } return 0; -- cgit v1.2.3 From 216d86b9a430f3280e5b631c51e6fd1a7774cfa0 Mon Sep 17 00:00:00 2001 From: Huang Rui Date: Fri, 15 Sep 2023 18:59:18 +0800 Subject: drm/virtio: add definition for venus capset This Venus capset definition is used by Qemu, and Qemu imports the kernel protocol header file. Add Venus capset to the VirtIO-GPU protocol. Signed-off-by: Huang Rui [dmitry.osipenko@collabora.com: edit commit message] Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20230915105918.3763061-1-ray.huang@amd.com --- include/uapi/linux/virtio_gpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/virtio_gpu.h b/include/uapi/linux/virtio_gpu.h index f556fde07b76..0e21f3998108 100644 --- a/include/uapi/linux/virtio_gpu.h +++ b/include/uapi/linux/virtio_gpu.h @@ -309,6 +309,8 @@ struct virtio_gpu_cmd_submit { #define VIRTIO_GPU_CAPSET_VIRGL 1 #define VIRTIO_GPU_CAPSET_VIRGL2 2 +/* 3 is reserved for gfxstream */ +#define VIRTIO_GPU_CAPSET_VENUS 4 /* VIRTIO_GPU_CMD_GET_CAPSET_INFO */ struct virtio_gpu_get_capset_info { -- cgit v1.2.3 From 0808aef86dc2776f75c7961015ee0280b78d868d Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:51 -0700 Subject: accel/qaic: Deprecate ->size field from attach slice IOCTL structure ->size in struct qaic_attach_slice_hdr is redundant since we have BO handle and its size can be retrieved from base BO structure. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-2-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 17 ++++------------- include/uapi/drm/qaic_accel.h | 13 +------------ 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index cf2898eda7ae..0c6f1328df68 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -830,9 +830,6 @@ static int qaic_prepare_import_bo(struct qaic_bo *bo, struct qaic_attach_slice_h struct sg_table *sgt; int ret; - if (obj->import_attach->dmabuf->size < hdr->size) - return -EINVAL; - sgt = dma_buf_map_attachment(obj->import_attach, hdr->dir); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); @@ -849,9 +846,6 @@ static int qaic_prepare_export_bo(struct qaic_device *qdev, struct qaic_bo *bo, { int ret; - if (bo->base.size < hdr->size) - return -EINVAL; - ret = dma_map_sgtable(&qdev->pdev->dev, bo->sgt, hdr->dir, 0); if (ret) return -EFAULT; @@ -952,9 +946,6 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi if (arg_size / args->hdr.count != sizeof(*slice_ent)) return -EINVAL; - if (args->hdr.size == 0) - return -EINVAL; - if (!(args->hdr.dir == DMA_TO_DEVICE || args->hdr.dir == DMA_FROM_DEVICE)) return -EINVAL; @@ -994,16 +985,16 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi goto free_slice_ent; } - ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, args->hdr.size); - if (ret) - goto free_slice_ent; - obj = drm_gem_object_lookup(file_priv, args->hdr.handle); if (!obj) { ret = -ENOENT; goto free_slice_ent; } + ret = qaic_validate_req(qdev, slice_ent, args->hdr.count, obj->size); + if (ret) + goto put_bo; + bo = to_qaic_bo(obj); ret = mutex_lock_interruptible(&bo->lock); if (ret) diff --git a/include/uapi/drm/qaic_accel.h b/include/uapi/drm/qaic_accel.h index 9dab32316aee..d3ca876a08e9 100644 --- a/include/uapi/drm/qaic_accel.h +++ b/include/uapi/drm/qaic_accel.h @@ -242,18 +242,7 @@ struct qaic_attach_slice_entry { * @dbc_id: In. Associate the sliced BO with this DBC. * @handle: In. GEM handle of the BO to slice. * @dir: In. Direction of data flow. 1 = DMA_TO_DEVICE, 2 = DMA_FROM_DEVICE - * @size: In. Total length of BO being used. This should not exceed base - * size of BO (struct drm_gem_object.base) - * For BOs being allocated using DRM_IOCTL_QAIC_CREATE_BO, size of - * BO requested is PAGE_SIZE aligned then allocated hence allocated - * BO size maybe bigger. This size should not exceed the new - * PAGE_SIZE aligned BO size. - * @dev_addr: In. Device address this slice pushes to or pulls from. - * @db_addr: In. Address of the doorbell to ring. - * @db_data: In. Data to write to the doorbell. - * @db_len: In. Size of the doorbell data in bits - 32, 16, or 8. 0 is for - * inactive doorbells. - * @offset: In. Start of this slice as an offset from the start of the BO. + * @size: Deprecated. This value is ignored and size of @handle is used instead. */ struct qaic_attach_slice_hdr { __u32 count; -- cgit v1.2.3 From 401c005c16c954803850e9ee57486c385245bc73 Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:52 -0700 Subject: accel/qaic: Remove bo->queued field ->queued field is used to track whether the BO is submitted to hardware for DMA or not. Since same information can be retrieved using ->xfer_list field of same structure remove ->queued as it is redundant. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-3-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic.h | 2 -- drivers/accel/qaic/qaic_data.c | 23 +++++++++++------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 582836f9538f..2b3ef588b717 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -191,8 +191,6 @@ struct qaic_bo { u32 nr_slice; /* Number of slice that have been transferred by DMA engine */ u32 nr_slice_xfer_done; - /* true = BO is queued for execution, true = BO is not queued */ - bool queued; /* * If true then user has attached slicing information to this BO by * calling DRM_IOCTL_QAIC_ATTACH_SLICE_BO ioctl. diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 0c6f1328df68..89ab8fa19315 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -141,6 +141,11 @@ struct dbc_rsp { __le16 status; } __packed; +static inline bool bo_queued(struct qaic_bo *bo) +{ + return !list_empty(&bo->xfer_list); +} + inline int get_dbc_req_elem_size(void) { return sizeof(struct dbc_req); @@ -648,6 +653,7 @@ static void qaic_init_bo(struct qaic_bo *bo, bool reinit) } complete_all(&bo->xfer_done); INIT_LIST_HEAD(&bo->slices); + INIT_LIST_HEAD(&bo->xfer_list); } static struct qaic_bo *qaic_alloc_init_bo(void) @@ -1166,7 +1172,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil struct bo_slice *slice; unsigned long flags; struct qaic_bo *bo; - bool queued; int i, j; int ret; @@ -1198,9 +1203,7 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil } spin_lock_irqsave(&dbc->xfer_lock, flags); - queued = bo->queued; - bo->queued = true; - if (queued) { + if (bo_queued(bo)) { spin_unlock_irqrestore(&dbc->xfer_lock, flags); ret = -EINVAL; goto unlock_bo; @@ -1223,7 +1226,6 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil else ret = copy_exec_reqs(qdev, slice, dbc->id, head, tail); if (ret) { - bo->queued = false; spin_unlock_irqrestore(&dbc->xfer_lock, flags); goto unlock_bo; } @@ -1246,8 +1248,7 @@ failed_to_send_bo: spin_lock_irqsave(&dbc->xfer_lock, flags); bo = list_last_entry(&dbc->xfer_list, struct qaic_bo, xfer_list); obj = &bo->base; - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); spin_unlock_irqrestore(&dbc->xfer_lock, flags); dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir); drm_gem_object_put(obj); @@ -1608,8 +1609,7 @@ read_fifo: */ dma_sync_sgtable_for_cpu(&qdev->pdev->dev, bo->sgt, bo->dir); bo->nr_slice_xfer_done = 0; - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); bo->perf_stats.req_processed_ts = ktime_get_ns(); complete_all(&bo->xfer_done); drm_gem_object_put(&bo->base); @@ -1868,7 +1868,7 @@ int qaic_detach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi /* Check if BO is committed to H/W for DMA */ spin_lock_irqsave(&dbc->xfer_lock, flags); - if (bo->queued) { + if (bo_queued(bo)) { spin_unlock_irqrestore(&dbc->xfer_lock, flags); ret = -EBUSY; goto unlock_ch_srcu; @@ -1898,8 +1898,7 @@ static void empty_xfer_list(struct qaic_device *qdev, struct dma_bridge_chan *db spin_lock_irqsave(&dbc->xfer_lock, flags); while (!list_empty(&dbc->xfer_list)) { bo = list_first_entry(&dbc->xfer_list, typeof(*bo), xfer_list); - bo->queued = false; - list_del(&bo->xfer_list); + list_del_init(&bo->xfer_list); spin_unlock_irqrestore(&dbc->xfer_lock, flags); bo->nr_slice_xfer_done = 0; bo->req_id = 0; -- cgit v1.2.3 From fbd60a67f4975d6bad25d9d504055fae8c1c27b7 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 8 Dec 2023 09:34:53 -0700 Subject: accel/qaic: Fix MHI channel struct field order The timesync channels have their struct fields out of order with the rest of the channels. Fix them so there is a consistent style in the file. Signed-off-by: Jeffrey Hugo Reviewed-by: Carl Vanderlip Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-4-quic_jhugo@quicinc.com --- drivers/accel/qaic/mhi_controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 832464f2833a..364eede0ac02 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -358,8 +358,8 @@ static struct mhi_channel_config aic100_channels[] = { .wake_capable = false, }, { - .num = 21, .name = "QAIC_TIMESYNC", + .num = 21, .num_elements = 32, .local_elements = 0, .event_ring = 0, @@ -390,8 +390,8 @@ static struct mhi_channel_config aic100_channels[] = { .wake_capable = false, }, { - .num = 23, .name = "QAIC_TIMESYNC_PERIODIC", + .num = 23, .num_elements = 32, .local_elements = 0, .event_ring = 0, -- cgit v1.2.3 From ce5fed9aa0f6ff951bc1ef02f274875e67f070d2 Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:54 -0700 Subject: accel/qaic: Drop the reference to BO in error path of create BO IOCTL Do not free BO explicitly in error path, just drop its reference, cleanup will be taken care by DRM as we have registered for ->free() callback. This patch makes sure that there is only one code path for BO to be freed. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Carl Vanderlip Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-5-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 89ab8fa19315..7faa00705c1d 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -574,6 +574,9 @@ static void qaic_free_sgt(struct sg_table *sgt) { struct scatterlist *sg; + if (!sgt) + return; + for (sg = sgt->sgl; sg; sg = sg_next(sg)) if (sg_page(sg)) __free_pages(sg_page(sg), get_order(sg->length)); @@ -717,7 +720,7 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi ret = drm_gem_handle_create(file_priv, obj, &args->handle); if (ret) - goto free_sgt; + goto free_bo; bo->handle = args->handle; drm_gem_object_put(obj); @@ -726,10 +729,8 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi return 0; -free_sgt: - qaic_free_sgt(bo->sgt); free_bo: - kfree(bo); + drm_gem_object_put(obj); unlock_dev_srcu: srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id); unlock_usr_srcu: -- cgit v1.2.3 From 2f4494b34fe3f6fd810e3690a3cf66b551cef3da Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:55 -0700 Subject: accel/qaic: Call drm_gem_create_mmap_offset() once for each BO Every time QAIC_MMAP_BO ioctl is called for a BO, drm_gem_create_mmap_offset() is called. Calling drm_gem_create_mmap_offset() more then once for a BO seems redundant. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-6-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_data.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index 7faa00705c1d..f88d925c8001 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -718,6 +718,10 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi if (ret) goto free_bo; + ret = drm_gem_create_mmap_offset(obj); + if (ret) + goto free_bo; + ret = drm_gem_handle_create(file_priv, obj, &args->handle); if (ret) goto free_bo; @@ -745,7 +749,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file struct drm_gem_object *obj; struct qaic_device *qdev; struct qaic_user *usr; - int ret; + int ret = 0; usr = file_priv->driver_priv; usr_rcu_id = srcu_read_lock(&usr->qddev_lock); @@ -767,9 +771,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file goto unlock_dev_srcu; } - ret = drm_gem_create_mmap_offset(obj); - if (ret == 0) - args->offset = drm_vma_node_offset_addr(&obj->vma_node); + args->offset = drm_vma_node_offset_addr(&obj->vma_node); drm_gem_object_put(obj); -- cgit v1.2.3 From 8505e70821ade706f98f7114a2cbcd51326f7b82 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:26 +0100 Subject: fbdev/efifb: Replace references to global screen_info by local pointer Get the global screen_info's address once and access the data via this pointer. Limits the use of global state. v3: * use const screen_info in several places (Sui) * fix build for deferred takeover (kernel test robot) Signed-off-by: Thomas Zimmermann Tested-by: Sui Jingfeng Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-2-tzimmermann@suse.de --- drivers/video/fbdev/efifb.c | 124 +++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index f9b4ddd592ce..6b3b5cca1d41 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -108,7 +108,7 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, */ #if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ defined CONFIG_ACPI_BGRT -static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) +static void efifb_copy_bmp(u8 *src, u32 *dst, int width, const struct screen_info *si) { u8 r, g, b; @@ -130,7 +130,7 @@ static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) * resolution still fits, it will be displayed very close to the right edge of * the display looking quite bad. This function checks for this. */ -static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width) { /* * All x86 firmwares horizontally center the image (the yoffset @@ -141,16 +141,15 @@ static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) return bgrt_tab.image_offset_x == expected_xoffset; } #else -static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width) { return true; } #endif -static void efifb_show_boot_graphics(struct fb_info *info) +static void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si) { u32 bmp_width, bmp_height, bmp_pitch, dst_x, y, src_y; - struct screen_info *si = &screen_info; struct bmp_file_header *file_header; struct bmp_dib_header *dib_header; void *bgrt_image = NULL; @@ -247,7 +246,8 @@ error: pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n"); } #else -static inline void efifb_show_boot_graphics(struct fb_info *info) {} +static inline void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si) +{ } #endif /* @@ -282,7 +282,7 @@ static const struct fb_ops efifb_ops = { .fb_setcolreg = efifb_setcolreg, }; -static int efifb_setup(char *options) +static int efifb_setup(struct screen_info *si, char *options) { char *this_opt; @@ -290,16 +290,16 @@ static int efifb_setup(char *options) while ((this_opt = strsep(&options, ",")) != NULL) { if (!*this_opt) continue; - efifb_setup_from_dmi(&screen_info, this_opt); + efifb_setup_from_dmi(si, this_opt); if (!strncmp(this_opt, "base:", 5)) - screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0); + si->lfb_base = simple_strtoul(this_opt+5, NULL, 0); else if (!strncmp(this_opt, "stride:", 7)) - screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4; + si->lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4; else if (!strncmp(this_opt, "height:", 7)) - screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0); + si->lfb_height = simple_strtoul(this_opt+7, NULL, 0); else if (!strncmp(this_opt, "width:", 6)) - screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); + si->lfb_width = simple_strtoul(this_opt+6, NULL, 0); else if (!strcmp(this_opt, "nowc")) mem_flags &= ~EFI_MEMORY_WC; else if (!strcmp(this_opt, "nobgrt")) @@ -310,15 +310,15 @@ static int efifb_setup(char *options) return 0; } -static inline bool fb_base_is_valid(void) +static inline bool fb_base_is_valid(struct screen_info *si) { - if (screen_info.lfb_base) + if (si->lfb_base) return true; - if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)) + if (!(si->capabilities & VIDEO_CAPABILITY_64BIT_BASE)) return false; - if (screen_info.ext_lfb_base) + if (si->ext_lfb_base) return true; return false; @@ -329,7 +329,10 @@ static ssize_t name##_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - return sprintf(buf, fmt "\n", (screen_info.lfb_##name)); \ + struct screen_info *si = dev_get_platdata(dev); \ + if (!si) \ + return -ENODEV; \ + return sprintf(buf, fmt "\n", (si->lfb_##name)); \ } \ static DEVICE_ATTR_RO(name) @@ -356,6 +359,7 @@ static u64 bar_offset; static int efifb_probe(struct platform_device *dev) { + struct screen_info *si = &screen_info; struct fb_info *info; struct efifb_par *par; int err, orientation; @@ -365,48 +369,48 @@ static int efifb_probe(struct platform_device *dev) char *option = NULL; efi_memory_desc_t md; - if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) + if (si->orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; if (fb_get_options("efifb", &option)) return -ENODEV; - efifb_setup(option); + efifb_setup(si, option); /* We don't get linelength from UGA Draw Protocol, only from * EFI Graphics Protocol. So if it's not in DMI, and it's not * passed in from the user, we really can't use the framebuffer. */ - if (!screen_info.lfb_linelength) + if (!si->lfb_linelength) return -ENODEV; - if (!screen_info.lfb_depth) - screen_info.lfb_depth = 32; - if (!screen_info.pages) - screen_info.pages = 1; - if (!fb_base_is_valid()) { + if (!si->lfb_depth) + si->lfb_depth = 32; + if (!si->pages) + si->pages = 1; + if (!fb_base_is_valid(si)) { printk(KERN_DEBUG "efifb: invalid framebuffer address\n"); return -ENODEV; } printk(KERN_INFO "efifb: probing for efifb\n"); /* just assume they're all unset if any are */ - if (!screen_info.blue_size) { - screen_info.blue_size = 8; - screen_info.blue_pos = 0; - screen_info.green_size = 8; - screen_info.green_pos = 8; - screen_info.red_size = 8; - screen_info.red_pos = 16; - screen_info.rsvd_size = 8; - screen_info.rsvd_pos = 24; + if (!si->blue_size) { + si->blue_size = 8; + si->blue_pos = 0; + si->green_size = 8; + si->green_pos = 8; + si->red_size = 8; + si->red_pos = 16; + si->rsvd_size = 8; + si->rsvd_pos = 24; } - efifb_fix.smem_start = screen_info.lfb_base; + efifb_fix.smem_start = si->lfb_base; - if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) { + if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE) { u64 ext_lfb_base; - ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32; + ext_lfb_base = (u64)(unsigned long)si->ext_lfb_base << 32; efifb_fix.smem_start |= ext_lfb_base; } @@ -417,10 +421,10 @@ static int efifb_probe(struct platform_device *dev) efifb_fix.smem_start = bar_resource->start + bar_offset; } - efifb_defined.bits_per_pixel = screen_info.lfb_depth; - efifb_defined.xres = screen_info.lfb_width; - efifb_defined.yres = screen_info.lfb_height; - efifb_fix.line_length = screen_info.lfb_linelength; + efifb_defined.bits_per_pixel = si->lfb_depth; + efifb_defined.xres = si->lfb_width; + efifb_defined.yres = si->lfb_height; + efifb_fix.line_length = si->lfb_linelength; /* size_vmode -- that is the amount of memory needed for the * used video mode, i.e. the minimum amount of @@ -430,7 +434,7 @@ static int efifb_probe(struct platform_device *dev) /* size_total -- all video memory we have. Used for * entries, ressource allocation and bounds * checking. */ - size_total = screen_info.lfb_size; + size_total = si->lfb_size; if (size_total < size_vmode) size_total = size_vmode; @@ -505,14 +509,14 @@ static int efifb_probe(struct platform_device *dev) goto err_release_fb; } - efifb_show_boot_graphics(info); + efifb_show_boot_graphics(info, si); pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n", efifb_fix.smem_start, size_remap/1024, size_total/1024); pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", efifb_defined.xres, efifb_defined.yres, efifb_defined.bits_per_pixel, efifb_fix.line_length, - screen_info.pages); + si->pages); efifb_defined.xres_virtual = efifb_defined.xres; efifb_defined.yres_virtual = efifb_fix.smem_len / @@ -526,26 +530,26 @@ static int efifb_probe(struct platform_device *dev) efifb_defined.left_margin = (efifb_defined.xres / 8) & 0xf8; efifb_defined.hsync_len = (efifb_defined.xres / 8) & 0xf8; - efifb_defined.red.offset = screen_info.red_pos; - efifb_defined.red.length = screen_info.red_size; - efifb_defined.green.offset = screen_info.green_pos; - efifb_defined.green.length = screen_info.green_size; - efifb_defined.blue.offset = screen_info.blue_pos; - efifb_defined.blue.length = screen_info.blue_size; - efifb_defined.transp.offset = screen_info.rsvd_pos; - efifb_defined.transp.length = screen_info.rsvd_size; + efifb_defined.red.offset = si->red_pos; + efifb_defined.red.length = si->red_size; + efifb_defined.green.offset = si->green_pos; + efifb_defined.green.length = si->green_size; + efifb_defined.blue.offset = si->blue_pos; + efifb_defined.blue.length = si->blue_size; + efifb_defined.transp.offset = si->rsvd_pos; + efifb_defined.transp.length = si->rsvd_size; pr_info("efifb: %s: " "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", "Truecolor", - screen_info.rsvd_size, - screen_info.red_size, - screen_info.green_size, - screen_info.blue_size, - screen_info.rsvd_pos, - screen_info.red_pos, - screen_info.green_pos, - screen_info.blue_pos); + si->rsvd_size, + si->red_size, + si->green_size, + si->blue_size, + si->rsvd_pos, + si->red_pos, + si->green_pos, + si->blue_pos); efifb_fix.ypanstep = 0; efifb_fix.ywrapstep = 0; -- cgit v1.2.3 From b9cfd1d271ab51d677cd16b02b74267b5bac6508 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:27 +0100 Subject: fbdev/efifb: Use screen_info pointer from device Use the screen_info instance from the device instead of dereferencing the global screen_info state. Decouples the driver from per-architecture code. Duplicated the screen_info data, so that efifb can modify it at will. v2: * comment on devm_kmemdup() usage (Javier) Signed-off-by: Thomas Zimmermann Tested-by: Sui Jingfeng Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-3-tzimmermann@suse.de --- drivers/video/fbdev/efifb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 6b3b5cca1d41..10fc14ad5d12 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -359,7 +359,7 @@ static u64 bar_offset; static int efifb_probe(struct platform_device *dev) { - struct screen_info *si = &screen_info; + struct screen_info *si; struct fb_info *info; struct efifb_par *par; int err, orientation; @@ -369,6 +369,18 @@ static int efifb_probe(struct platform_device *dev) char *option = NULL; efi_memory_desc_t md; + /* + * If we fail probing the device, the kernel might try a different + * driver. We get a copy of the attached screen_info, so that we can + * modify its values without affecting later drivers. + */ + si = dev_get_platdata(&dev->dev); + if (!si) + return -ENODEV; + si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL); + if (!si) + return -ENOMEM; + if (si->orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; -- cgit v1.2.3 From 3218286bbb78cac3dde713514529e0480d678173 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:28 +0100 Subject: fbdev/vesafb: Replace references to global screen_info by local pointer Get the global screen_info's address once and access the data via this pointer. Limits the use of global state. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-4-tzimmermann@suse.de --- drivers/video/fbdev/vesafb.c | 66 +++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c index c0edceea0a79..ea89accbec38 100644 --- a/drivers/video/fbdev/vesafb.c +++ b/drivers/video/fbdev/vesafb.c @@ -243,6 +243,7 @@ static int vesafb_setup(char *options) static int vesafb_probe(struct platform_device *dev) { + struct screen_info *si = &screen_info; struct fb_info *info; struct vesafb_par *par; int i, err; @@ -255,17 +256,17 @@ static int vesafb_probe(struct platform_device *dev) fb_get_options("vesafb", &option); vesafb_setup(option); - if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) + if (si->orig_video_isVGA != VIDEO_TYPE_VLFB) return -ENODEV; - vga_compat = (screen_info.capabilities & 2) ? 0 : 1; - vesafb_fix.smem_start = screen_info.lfb_base; - vesafb_defined.bits_per_pixel = screen_info.lfb_depth; + vga_compat = (si->capabilities & 2) ? 0 : 1; + vesafb_fix.smem_start = si->lfb_base; + vesafb_defined.bits_per_pixel = si->lfb_depth; if (15 == vesafb_defined.bits_per_pixel) vesafb_defined.bits_per_pixel = 16; - vesafb_defined.xres = screen_info.lfb_width; - vesafb_defined.yres = screen_info.lfb_height; - vesafb_fix.line_length = screen_info.lfb_linelength; + vesafb_defined.xres = si->lfb_width; + vesafb_defined.yres = si->lfb_height; + vesafb_fix.line_length = si->lfb_linelength; vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; @@ -277,7 +278,7 @@ static int vesafb_probe(struct platform_device *dev) /* size_total -- all video memory we have. Used for mtrr * entries, resource allocation and bounds * checking. */ - size_total = screen_info.lfb_size * 65536; + size_total = si->lfb_size * 65536; if (vram_total) size_total = vram_total * 1024 * 1024; if (size_total < size_vmode) @@ -297,7 +298,7 @@ static int vesafb_probe(struct platform_device *dev) vesafb_fix.smem_len = size_remap; #ifndef __i386__ - screen_info.vesapm_seg = 0; + si->vesapm_seg = 0; #endif if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { @@ -317,23 +318,26 @@ static int vesafb_probe(struct platform_device *dev) par = info->par; info->pseudo_palette = par->pseudo_palette; - par->base = screen_info.lfb_base; + par->base = si->lfb_base; par->size = size_total; printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", - vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages); + vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, + vesafb_fix.line_length, si->pages); - if (screen_info.vesapm_seg) { + if (si->vesapm_seg) { printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", - screen_info.vesapm_seg,screen_info.vesapm_off); + si->vesapm_seg, si->vesapm_off); } - if (screen_info.vesapm_seg < 0xc000) + if (si->vesapm_seg < 0xc000) ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */ if (ypan || pmi_setpal) { + unsigned long pmi_phys; unsigned short *pmi_base; - pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); + pmi_phys = ((unsigned long)si->vesapm_seg << 4) + si->vesapm_off; + pmi_base = (unsigned short *)phys_to_virt(pmi_phys); pmi_start = (void*)((char*)pmi_base + pmi_base[1]); pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); @@ -377,14 +381,14 @@ static int vesafb_probe(struct platform_device *dev) vesafb_defined.left_margin = (vesafb_defined.xres / 8) & 0xf8; vesafb_defined.hsync_len = (vesafb_defined.xres / 8) & 0xf8; - vesafb_defined.red.offset = screen_info.red_pos; - vesafb_defined.red.length = screen_info.red_size; - vesafb_defined.green.offset = screen_info.green_pos; - vesafb_defined.green.length = screen_info.green_size; - vesafb_defined.blue.offset = screen_info.blue_pos; - vesafb_defined.blue.length = screen_info.blue_size; - vesafb_defined.transp.offset = screen_info.rsvd_pos; - vesafb_defined.transp.length = screen_info.rsvd_size; + vesafb_defined.red.offset = si->red_pos; + vesafb_defined.red.length = si->red_size; + vesafb_defined.green.offset = si->green_pos; + vesafb_defined.green.length = si->green_size; + vesafb_defined.blue.offset = si->blue_pos; + vesafb_defined.blue.length = si->blue_size; + vesafb_defined.transp.offset = si->rsvd_pos; + vesafb_defined.transp.length = si->rsvd_size; if (vesafb_defined.bits_per_pixel <= 8) { depth = vesafb_defined.green.length; @@ -399,14 +403,14 @@ static int vesafb_probe(struct platform_device *dev) (vesafb_defined.bits_per_pixel > 8) ? "Truecolor" : (vga_compat || pmi_setpal) ? "Pseudocolor" : "Static Pseudocolor", - screen_info.rsvd_size, - screen_info.red_size, - screen_info.green_size, - screen_info.blue_size, - screen_info.rsvd_pos, - screen_info.red_pos, - screen_info.green_pos, - screen_info.blue_pos); + si->rsvd_size, + si->red_size, + si->green_size, + si->blue_size, + si->rsvd_pos, + si->red_pos, + si->green_pos, + si->blue_pos); vesafb_fix.ypanstep = ypan ? 1 : 0; vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; -- cgit v1.2.3 From 0f7c246235a0639d90b5380277a43c853ba73681 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 6 Dec 2023 14:50:29 +0100 Subject: fbdev/vesafb: Use screen_info pointer from device Use the screen_info instance from the device instead of dereferencing the global screen_info state. Decouples the driver from per-architecture code. Duplicated the screen_info data, so that vesafb can modify it at will. v2: * comment on devm_kmemdup() usage (Javier) Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20231206135153.2599-5-tzimmermann@suse.de --- drivers/video/fbdev/vesafb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c index ea89accbec38..8ab64ae4cad3 100644 --- a/drivers/video/fbdev/vesafb.c +++ b/drivers/video/fbdev/vesafb.c @@ -243,7 +243,7 @@ static int vesafb_setup(char *options) static int vesafb_probe(struct platform_device *dev) { - struct screen_info *si = &screen_info; + struct screen_info *si; struct fb_info *info; struct vesafb_par *par; int i, err; @@ -252,6 +252,18 @@ static int vesafb_probe(struct platform_device *dev) unsigned int size_total; char *option = NULL; + /* + * If we fail probing the device, the kernel might try a different + * driver. We get a copy of the attached screen_info, so that we can + * modify its values without affecting later drivers. + */ + si = dev_get_platdata(&dev->dev); + if (!si) + return -ENODEV; + si = devm_kmemdup(&dev->dev, si, sizeof(*si), GFP_KERNEL); + if (!si) + return -ENOMEM; + /* ignore error return of fb_get_options */ fb_get_options("vesafb", &option); vesafb_setup(option); -- cgit v1.2.3 From 1c20d8b8e171b92194a4f9b45821c821606b8936 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:12 +0100 Subject: drm/atomic: Move the drm_atomic_state field doc inline Some fields of drm_atomic_state have been documented in-line, but some were documented in the main kerneldoc block before the structure. Since the former is the preferred option in DRM, let's move all the fields to an inline documentation. Acked-by: Sui Jingfeng Link: https://lore.kernel.org/r/20231214100917.277842-1-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 50 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index cf8e1220a4ac..2a08030fcd75 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -347,24 +347,22 @@ struct __drm_private_objs_state { /** * struct drm_atomic_state - the global state object for atomic updates - * @ref: count of all references to this state (will not be freed until zero) - * @dev: parent DRM device - * @async_update: hint for asynchronous plane update - * @planes: pointer to array of structures with per-plane data - * @crtcs: pointer to array of CRTC pointers - * @num_connector: size of the @connectors and @connector_states arrays - * @connectors: pointer to array of structures with per-connector data - * @num_private_objs: size of the @private_objs array - * @private_objs: pointer to array of private object pointers - * @acquire_ctx: acquire context for this atomic modeset state update * * States are added to an atomic update by calling drm_atomic_get_crtc_state(), * drm_atomic_get_plane_state(), drm_atomic_get_connector_state(), or for * private state structures, drm_atomic_get_private_obj_state(). */ struct drm_atomic_state { + /** + * @ref: + * + * Count of all references to this update (will not be freed until zero). + */ struct kref ref; + /** + * @dev: Parent DRM Device. + */ struct drm_device *dev; /** @@ -388,7 +386,12 @@ struct drm_atomic_state { * flag are not allowed. */ bool legacy_cursor_update : 1; + + /** + * @async_update: hint for asynchronous plane update + */ bool async_update : 1; + /** * @duplicated: * @@ -398,13 +401,40 @@ struct drm_atomic_state { * states. */ bool duplicated : 1; + + /** + * @planes: pointer to array of structures with per-plane data + */ struct __drm_planes_state *planes; + + /** + * @crtcs: pointer to array of CRTC pointers + */ struct __drm_crtcs_state *crtcs; + + /** + * @num_connector: size of the @connectors and @connector_states arrays + */ int num_connector; + + /** + * @connectors: pointer to array of structures with per-connector data + */ struct __drm_connnectors_state *connectors; + + /** + * @num_private_objs: size of the @private_objs array + */ int num_private_objs; + + /** + * @private_objs: pointer to array of private object pointers + */ struct __drm_private_objs_state *private_objs; + /** + * @acquire_ctx: acquire context for this atomic modeset state update + */ struct drm_modeset_acquire_ctx *acquire_ctx; /** -- cgit v1.2.3 From 786f6c2fa4ae3913f0fdcd371e871bd97aff8481 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:13 +0100 Subject: drm/atomic: Remove inexistent reference Commit 63e83c1dba54 ("drm: Consolidate connector arrays in drm_atomic_state") removed the connector_states field but didn't remove its mention in the num_connectors documentation. Acked-by: Sui Jingfeng Reviewed-by: Daniel Vetter Link: https://lore.kernel.org/r/20231214100917.277842-2-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 2a08030fcd75..13cecdc1257d 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -413,7 +413,7 @@ struct drm_atomic_state { struct __drm_crtcs_state *crtcs; /** - * @num_connector: size of the @connectors and @connector_states arrays + * @num_connector: size of the @connectors array */ int num_connector; -- cgit v1.2.3 From 17beda5e951aac35fee26703719c252bb216b56b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:14 +0100 Subject: drm/atomic: Rework the object doc a bit Commits 63e83c1dba54 ("drm: Consolidate connector arrays in drm_atomic_state"), b8b5342b699b ("drm: Consolidate plane arrays in drm_atomic_state") and 5d943aa6c0d4 ("drm: Consolidate crtc arrays in drm_atomic_state") moved the object pointer and their state pointer to an intermediate structure storing both. The CRTC commit didn't update the doc of the crtcs field to reflect that, and the doc for the planes and connectors fields mention that they are pointers to an array of structures with per-$OBJECT data. The private_objs field was added later on by commit b430c27a7de3 ("drm: Add driver-private objects to atomic state") reusing the same sentence than the crtcs field, probably due to copy and paste. While these fields are indeed pointers to an array, each item of that array contain a pointer to the object structure affected by the update, and its old and new state. There's no per-object data there, and there's more than just a pointer to the objects. Let's rephrase those fields a bit to better match the current situation. Acked-by: Sui Jingfeng Reviewed-by: Daniel Vetter Link: https://lore.kernel.org/r/20231214100917.277842-3-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 13cecdc1257d..914574b58ae7 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -403,12 +403,18 @@ struct drm_atomic_state { bool duplicated : 1; /** - * @planes: pointer to array of structures with per-plane data + * @planes: + * + * Pointer to array of @drm_plane and @drm_plane_state part of this + * update. */ struct __drm_planes_state *planes; /** - * @crtcs: pointer to array of CRTC pointers + * @crtcs: + * + * Pointer to array of @drm_crtc and @drm_crtc_state part of this + * update. */ struct __drm_crtcs_state *crtcs; @@ -418,7 +424,10 @@ struct drm_atomic_state { int num_connector; /** - * @connectors: pointer to array of structures with per-connector data + * @connectors: + * + * Pointer to array of @drm_connector and @drm_connector_state part of + * this update. */ struct __drm_connnectors_state *connectors; @@ -428,7 +437,10 @@ struct drm_atomic_state { int num_private_objs; /** - * @private_objs: pointer to array of private object pointers + * @private_objs: + * + * Pointer to array of @drm_private_obj and @drm_private_obj_state part + * of this update. */ struct __drm_private_objs_state *private_objs; -- cgit v1.2.3 From ab9fabeae4e71095d29216ff14f8a56e4fdda895 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:15 +0100 Subject: drm/atomic: Make the drm_atomic_state documentation less ambiguous The current documentation of drm_atomic_state says that it's the "global state object". This is confusing since, while it does contain all the objects affected by an update and their respective states, if an object isn't affected by this update it won't be part of it. Thus, it's not truly a "global state", unlike object state structures that do contain the entire state of a given object. Reviewed-by: Hamza Mahfooz Acked-by: Pekka Paalanen Link: https://lore.kernel.org/r/20231214100917.277842-4-mripard@kernel.org Signed-off-by: Maxime Ripard --- include/drm/drm_atomic.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 914574b58ae7..4d7f4c5f2001 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -346,7 +346,13 @@ struct __drm_private_objs_state { }; /** - * struct drm_atomic_state - the global state object for atomic updates + * struct drm_atomic_state - Atomic commit structure + * + * This structure is the kernel counterpart of @drm_mode_atomic and represents + * an atomic commit that transitions from an old to a new display state. It + * contains all the objects affected by the atomic commit and both the new + * state structures and pointers to the old state structures for + * these. * * States are added to an atomic update by calling drm_atomic_get_crtc_state(), * drm_atomic_get_plane_state(), drm_atomic_get_connector_state(), or for -- cgit v1.2.3 From d0ac5722dae5f4302bb4ef6df10d0afa718df80b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 14 Dec 2023 11:09:16 +0100 Subject: drm/todo: Add entry to rename drm_atomic_state The name of the structure drm_atomic_state is confusing. Let's add an entry to our todo list to rename it. Reviewed-by: Daniel Vetter Link: https://lore.kernel.org/r/20231214100917.277842-5-mripard@kernel.org Signed-off-by: Maxime Ripard --- Documentation/gpu/todo.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 41a264bf84ce..fb9ad120b141 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -120,6 +120,29 @@ Contact: Daniel Vetter, respective driver maintainers Level: Advanced +Rename drm_atomic_state +----------------------- + +The KMS framework uses two slightly different definitions for the ``state`` +concept. For a given object (plane, CRTC, encoder, etc., so +``drm_$OBJECT_state``), the state is the entire state of that object. However, +at the device level, ``drm_atomic_state`` refers to a state update for a +limited number of objects. + +The state isn't the entire device state, but only the full state of some +objects in that device. This is confusing to newcomers, and +``drm_atomic_state`` should be renamed to something clearer like +``drm_atomic_commit``. + +In addition to renaming the structure itself, it would also imply renaming some +related functions (``drm_atomic_state_alloc``, ``drm_atomic_state_get``, +``drm_atomic_state_put``, ``drm_atomic_state_init``, +``__drm_atomic_state_free``, etc.). + +Contact: Maxime Ripard + +Level: Advanced + Fallout from atomic KMS ----------------------- -- cgit v1.2.3 From 3a63826c720675f35144a444b9a8e506493f5166 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 15 Dec 2023 13:11:29 +0200 Subject: drm/mm: Allow CONFIG_DRM_MM_DEBUG with DRM=m MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original rationale for commit cd456f8d06d2 ("drm: Restrict stackdepot usage to builtin drm.ko") was that depot_save_stack() (which is what we used back then) wasn't exported. stack_depot_save() (which is what we use now) is exported however, so relax the dependency allow CONFIG_DRM_MM_DEBUG with DRM=m. Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231215111129.9559-1-ville.syrjala@linux.intel.com Acked-by: Javier Martinez Canillas --- drivers/gpu/drm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 31cfe2c2a2af..4b8b8f8a0e72 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -42,7 +42,7 @@ config DRM_MIPI_DSI config DRM_DEBUG_MM bool "Insert extra checks and debug info into the DRM range managers" default n - depends on DRM=y + depends on DRM depends on STACKTRACE_SUPPORT select STACKDEPOT help -- cgit v1.2.3 From 4464af92f276537716db87aa21828190b5e12463 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:50 +0800 Subject: drm/panel-edp: Add powered_on_to_enable delay Add the support of powered_on_to_enable delay as the minimum time that needs to have passed between the panel powered on and enable may begin. This delay is seen in BOE panels as the minimum delay of T3+T4+T5+T6+T8 in the eDP timing diagrams. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231214152817.2766280-2-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index a0b6f69b916f..44acf9cacaf7 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -70,6 +70,21 @@ struct panel_delay { */ unsigned int hpd_absent; + /** + * @powered_on_to_enable: Time between panel powered on and enable. + * + * The minimum time, in milliseconds, that needs to have passed + * between when panel powered on and enable may begin. + * + * This is (T3+T4+T5+T6+T8)-min on eDP timing diagrams or after the + * power supply enabled until we can turn the backlight on and see + * valid data. + * + * This doesn't normally need to be set if timings are already met by + * prepare_to_enable or enable. + */ + unsigned int powered_on_to_enable; + /** * @prepare_to_enable: Time between prepare and enable. * @@ -216,6 +231,7 @@ struct panel_edp { bool prepared; ktime_t prepared_time; + ktime_t powered_on_time; ktime_t unprepared_time; const struct panel_desc *desc; @@ -455,6 +471,8 @@ static int panel_edp_prepare_once(struct panel_edp *p) gpiod_set_value_cansleep(p->enable_gpio, 1); + p->powered_on_time = ktime_get_boottime(); + delay = p->desc->delay.hpd_reliable; if (p->no_hpd) delay = max(delay, p->desc->delay.hpd_absent); @@ -579,6 +597,8 @@ static int panel_edp_enable(struct drm_panel *panel) panel_edp_wait(p->prepared_time, p->desc->delay.prepare_to_enable); + panel_edp_wait(p->powered_on_time, p->desc->delay.powered_on_to_enable); + p->enabled = true; return 0; -- cgit v1.2.3 From f4ccd9fea227070497df29d68dcbcb55bdb3a9e3 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:51 +0800 Subject: drm/edp-panel: Add panels delay entries Add panels used by Mediatek MT8173 Chromebooks. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231214152817.2766280-3-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 44acf9cacaf7..b059f5895d3a 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1857,6 +1857,13 @@ static const struct panel_delay delay_200_500_p2e80 = { .prepare_to_enable = 80, }; +static const struct panel_delay delay_200_500_e50_p2e80 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .prepare_to_enable = 80, +}; + static const struct panel_delay delay_200_500_p2e100 = { .hpd_absent = 200, .unprepare = 500, @@ -1894,6 +1901,13 @@ static const struct panel_delay delay_200_500_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e200_d200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, + .disable = 200, +}; + static const struct panel_delay delay_200_500_e200_d10 = { .hpd_absent = 200, .unprepare = 500, @@ -1907,6 +1921,13 @@ static const struct panel_delay delay_200_150_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e50_po2e200 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .powered_on_to_enable = 200, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .name = _name, \ @@ -1932,6 +1953,7 @@ static const struct panel_delay delay_200_150_e200 = { * Sort first by vendor, then by product ID. */ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), @@ -1948,23 +1970,31 @@ static const struct edp_panel_entry edp_panels[] = { &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, "NV133FHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, "NT140WHM-N44 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x096e, &delay_200_500_e50_po2e200, "NV116WHM-T07 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0993, &delay_200_500_e80, "NV116WHM-T14 V8.0"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ad, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), @@ -1973,6 +2003,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), @@ -1985,6 +2016,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), @@ -2000,10 +2032,17 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, &delay_200_500_e50, "KD116N29-30NK-A005"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x044f, &delay_200_500_e50, "KD116N9-30NH-F3"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, &delay_200_500_e80_d50, "KD116N5-30NV-G7"), EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0497, &delay_200_500_e200_d200, "LP116WH7-SPB1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x052c, &delay_200_500_e200_d200, "LP133WF2-SPL7"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x054a, &delay_200_500_e200_d200, "LP116WH8-SPC1"), + EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), -- cgit v1.2.3 From 7c8690d8fc80e6149d9a8c85d22ba03f4d8dcc69 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Thu, 14 Dec 2023 23:27:52 +0800 Subject: drm/panel-edp: Add some panels with conservative timings These panels are used by Mediatek MT8173 Chromebooks, and they used to work with the downstream v4.19 kernel without any specified delay. Back in the v4.19 kernel, they used the "little white lie" approach, which is making the devicetree claim a specific panel's compatible string for many different panels. That was a common solution before the generic edp-panel driver. After we uprevved the device to a newer kernel and used the edp-panel driver, we saw multiple devices reporting warnings of using an unknown panel and falling back to the conservative timings, which means that they turn on/off much more slowly than they should. We tried to fill in the timings for those panels, but we failed to find all the data sheets for them. Therefore, instead of having them use the default conservative timings, update them with less-conservative timings from other panels of the same vendor. The panels should still work under those timings, and we can save some delays and suppress the warnings. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231214152817.2766280-4-treapking@chromium.org --- drivers/gpu/drm/panel/panel-edp.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index b059f5895d3a..e23737284f31 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1955,6 +1955,7 @@ static const struct panel_delay delay_200_500_e50_po2e200 = { static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), @@ -1965,6 +1966,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", &auo_b116xa3_mode), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1", &auo_b116xa3_mode), @@ -1974,18 +1976,34 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0607, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0608, &delay_200_500_e50, "NT116WHM-N11"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0668, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x068f, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x06e5, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0705, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0717, &delay_200_500_e50_po2e200, "NV133FHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0744, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x074c, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0751, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0754, &delay_200_500_e50_po2e200, "NV116WHM-N45"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0771, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0797, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d3, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f8, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0813, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0827, &delay_200_500_e50_p2e80, "NT140WHM-N44 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0843, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0848, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0849, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), @@ -1997,6 +2015,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ad, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), @@ -2007,11 +2026,14 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1141, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, &delay_200_500_e80_d50, "N116BCN-EB1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x114a, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1156, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), @@ -2023,6 +2045,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x048e, &delay_200_500_e200_d10, "M116NWR6 R5"), @@ -2031,6 +2055,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('I', 'V', 'O', 0x854b, &delay_200_500_p2e100, "R133NW4K-R0"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), + EDP_PANEL_ENTRY('K', 'D', 'B', 0x044f, &delay_200_500_e80_d50, "Unknown"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1118, &delay_200_500_e50, "KD116N29-30NK-A005"), EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), @@ -2039,9 +2064,15 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('K', 'D', 'C', 0x05f1, &delay_200_500_e80_d50, "KD116N5-30NV-G7"), EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0000, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x048d, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x0497, &delay_200_500_e200_d200, "LP116WH7-SPB1"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x052c, &delay_200_500_e200_d200, "LP133WF2-SPL7"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0537, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('L', 'G', 'D', 0x054a, &delay_200_500_e200_d200, "LP116WH8-SPC1"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x0567, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"), + EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"), EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), -- cgit v1.2.3 From 0547692ac14650d0574e065094891bed31e37007 Mon Sep 17 00:00:00 2001 From: Xuxin Xiong Date: Mon, 18 Dec 2023 17:59:33 +0800 Subject: drm/panel-edp: Add several generic edp panels Add support for the following 3 panels: 1. BOE NV116WHM-N49 V8.0 2. BOE NV122WUM-N41 3. CSO MNC207QS1-1 Signed-off-by: Xuxin Xiong Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20231218095933.2487360-1-xuxinxiong@huaqin.corp-partner.google.com --- drivers/gpu/drm/panel/panel-edp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index e23737284f31..cd05c76868e3 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -2016,8 +2016,10 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80, "NV116WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), @@ -2045,6 +2047,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50, "MNC207QS1-1"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), -- cgit v1.2.3 From 22ec9a3b73ddf5debf186a8041ad6c00a7b82b9c Mon Sep 17 00:00:00 2001 From: Pranjal Ramajor Asha Kanojiya Date: Fri, 8 Dec 2023 09:34:56 -0700 Subject: accel/qaic: Leverage DRM managed APIs to release resources Offload the balancing of init and destroy calls to DRM managed APIs. mutex destroy for ->cntl_mutex is not called during device release and destroy workqueue is not called in error path of create_qdev(). So, use DRM managed APIs to manage the release of resources and avoid such problems. Signed-off-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Jeffrey Hugo Signed-off-by: Jeffrey Hugo Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-7-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic.h | 1 + drivers/accel/qaic/qaic_drv.c | 138 +++++++++++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 50 deletions(-) diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index 2b3ef588b717..9256653b3036 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -30,6 +30,7 @@ #define to_qaic_drm_device(dev) container_of(dev, struct qaic_drm_device, drm) #define to_drm(qddev) (&(qddev)->drm) #define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */ +#define to_qaic_device(dev) (to_qaic_drm_device((dev))->qdev) enum __packed dev_states { /* Device is offline or will be very soon */ diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 2a313eb69b12..10a43d02844f 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -44,6 +44,53 @@ MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode"); static bool link_up; static DEFINE_IDA(qaic_usrs); +static void qaicm_wq_release(struct drm_device *dev, void *res) +{ + struct workqueue_struct *wq = res; + + destroy_workqueue(wq); +} + +static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *fmt) +{ + struct workqueue_struct *wq; + int ret; + + wq = alloc_workqueue(fmt, WQ_UNBOUND, 0); + if (!wq) + return ERR_PTR(-ENOMEM); + ret = drmm_add_action_or_reset(dev, qaicm_wq_release, wq); + if (ret) + return ERR_PTR(ret); + + return wq; +} + +static void qaicm_srcu_release(struct drm_device *dev, void *res) +{ + struct srcu_struct *lock = res; + + cleanup_srcu_struct(lock); +} + +static int qaicm_srcu_init(struct drm_device *dev, struct srcu_struct *lock) +{ + int ret; + + ret = init_srcu_struct(lock); + if (ret) + return ret; + + return drmm_add_action_or_reset(dev, qaicm_srcu_release, lock); +} + +static void qaicm_pci_release(struct drm_device *dev, void *res) +{ + struct qaic_device *qdev = to_qaic_device(dev); + + pci_set_drvdata(qdev->pdev, NULL); +} + static void free_usr(struct kref *kref) { struct qaic_user *usr = container_of(kref, struct qaic_user, ref_count); @@ -299,74 +346,73 @@ void qaic_dev_reset_clean_local_state(struct qaic_device *qdev) release_dbc(qdev, i); } -static void cleanup_qdev(struct qaic_device *qdev) -{ - int i; - - for (i = 0; i < qdev->num_dbc; ++i) - cleanup_srcu_struct(&qdev->dbc[i].ch_lock); - cleanup_srcu_struct(&qdev->dev_lock); - pci_set_drvdata(qdev->pdev, NULL); - destroy_workqueue(qdev->cntl_wq); - destroy_workqueue(qdev->qts_wq); -} - static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; struct qaic_drm_device *qddev; struct qaic_device *qdev; - int i; + struct drm_device *drm; + int i, ret; - qdev = devm_kzalloc(&pdev->dev, sizeof(*qdev), GFP_KERNEL); + qdev = devm_kzalloc(dev, sizeof(*qdev), GFP_KERNEL); if (!qdev) return NULL; qdev->dev_state = QAIC_OFFLINE; if (id->device == PCI_DEV_AIC100) { qdev->num_dbc = 16; - qdev->dbc = devm_kcalloc(&pdev->dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); + qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); if (!qdev->dbc) return NULL; } - qdev->cntl_wq = alloc_workqueue("qaic_cntl", WQ_UNBOUND, 0); - if (!qdev->cntl_wq) + qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm); + if (IS_ERR(qddev)) + return NULL; + + drm = to_drm(qddev); + pci_set_drvdata(pdev, qdev); + + ret = drmm_mutex_init(drm, &qddev->users_mutex); + if (ret) + return NULL; + ret = drmm_add_action_or_reset(drm, qaicm_pci_release, NULL); + if (ret) + return NULL; + ret = drmm_mutex_init(drm, &qdev->cntl_mutex); + if (ret) return NULL; - qdev->qts_wq = alloc_workqueue("qaic_ts", WQ_UNBOUND, 0); - if (!qdev->qts_wq) { - destroy_workqueue(qdev->cntl_wq); + qdev->cntl_wq = qaicm_wq_init(drm, "qaic_cntl"); + if (IS_ERR(qdev->cntl_wq)) + return NULL; + qdev->qts_wq = qaicm_wq_init(drm, "qaic_ts"); + if (IS_ERR(qdev->qts_wq)) return NULL; - } - pci_set_drvdata(pdev, qdev); + ret = qaicm_srcu_init(drm, &qdev->dev_lock); + if (ret) + return NULL; + + qdev->qddev = qddev; qdev->pdev = pdev; + qddev->qdev = qdev; - mutex_init(&qdev->cntl_mutex); INIT_LIST_HEAD(&qdev->cntl_xfer_list); - init_srcu_struct(&qdev->dev_lock); + INIT_LIST_HEAD(&qddev->users); for (i = 0; i < qdev->num_dbc; ++i) { spin_lock_init(&qdev->dbc[i].xfer_lock); qdev->dbc[i].qdev = qdev; qdev->dbc[i].id = i; INIT_LIST_HEAD(&qdev->dbc[i].xfer_list); - init_srcu_struct(&qdev->dbc[i].ch_lock); + ret = qaicm_srcu_init(drm, &qdev->dbc[i].ch_lock); + if (ret) + return NULL; init_waitqueue_head(&qdev->dbc[i].dbc_release); INIT_LIST_HEAD(&qdev->dbc[i].bo_lists); } - qddev = devm_drm_dev_alloc(&pdev->dev, &qaic_accel_driver, struct qaic_drm_device, drm); - if (IS_ERR(qddev)) { - cleanup_qdev(qdev); - return NULL; - } - - drmm_mutex_init(to_drm(qddev), &qddev->users_mutex); - INIT_LIST_HEAD(&qddev->users); - qddev->qdev = qdev; - qdev->qddev = qddev; - return qdev; } @@ -472,35 +518,28 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = init_pci(qdev, pdev); if (ret) - goto cleanup_qdev; + return ret; for (i = 0; i < qdev->num_dbc; ++i) qdev->dbc[i].dbc_base = qdev->bar_2 + QAIC_DBC_OFF(i); mhi_irq = init_msi(qdev, pdev); - if (mhi_irq < 0) { - ret = mhi_irq; - goto cleanup_qdev; - } + if (mhi_irq < 0) + return mhi_irq; ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION); if (ret) - goto cleanup_qdev; + return ret; qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq, qdev->single_msi); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); - goto cleanup_drm_dev; + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); + return ret; } return 0; - -cleanup_drm_dev: - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); -cleanup_qdev: - cleanup_qdev(qdev); - return ret; } static void qaic_pci_remove(struct pci_dev *pdev) @@ -513,7 +552,6 @@ static void qaic_pci_remove(struct pci_dev *pdev) qaic_dev_reset_clean_local_state(qdev); qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); qaic_mhi_free_controller(qdev->mhi_cntrl, link_up); - cleanup_qdev(qdev); } static void qaic_pci_shutdown(struct pci_dev *pdev) -- cgit v1.2.3 From 5202c721da4c96c137041b41c3d7caa57a329137 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 8 Dec 2023 09:34:57 -0700 Subject: accel/qaic: Order pci_remove() operations in reverse of probe() In probe() we create the drm_device, and then register the MHI controller. In remove(), we should unregister the controller first, then remove the drm_device. Update the remove() operations to match. Signed-off-by: Jeffrey Hugo Reviewed-by: Pranjal Ramajor Asha Kanojiya Reviewed-by: Carl Vanderlip Reviewed-by: Jacek Lawrynowicz Link: https://patchwork.freedesktop.org/patch/msgid/20231208163457.1295993-8-quic_jhugo@quicinc.com --- drivers/accel/qaic/qaic_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 10a43d02844f..d1a632dbaec6 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -550,8 +550,8 @@ static void qaic_pci_remove(struct pci_dev *pdev) return; qaic_dev_reset_clean_local_state(qdev); - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); qaic_mhi_free_controller(qdev->mhi_cntrl, link_up); + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); } static void qaic_pci_shutdown(struct pci_dev *pdev) -- cgit v1.2.3 From 021a81e7ac8f579b049e5bc76efabd9e67bd627c Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Thu, 21 Dec 2023 13:43:32 +0100 Subject: dt-bindings: panel: lvds: Append edt,etml0700z9ndha in panel-lvds List EDT ETML0700Z9NDHA in the LVDS panel enumeration. Signed-off-by: Raphael Gallais-Pou Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231221124339.420119-2-raphael.gallais-pou@foss.st.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231221124339.420119-2-raphael.gallais-pou@foss.st.com --- Documentation/devicetree/bindings/display/panel/panel-lvds.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml index 9f1016551e0b..3fb24393529c 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml @@ -42,6 +42,8 @@ properties: - auo,b101ew05 # Chunghwa Picture Tubes Ltd. 7" WXGA (800x1280) TFT LCD LVDS panel - chunghwa,claa070wp03xg + # EDT ETML0700Z9NDHA 7.0" WSVGA (1024x600) color TFT LCD LVDS panel + - edt,etml0700z9ndha # HannStar Display Corp. HSD101PWW2 10.1" WXGA (1280x800) LVDS panel - hannstar,hsd101pww2 # Hydis Technologies 7" WXGA (800x1280) TFT LCD LVDS panel -- cgit v1.2.3 From a196a5166e0812db267281c32fa0724fc5be6582 Mon Sep 17 00:00:00 2001 From: Philipp Stanner Date: Fri, 22 Dec 2023 12:52:17 +0100 Subject: drm/tilcdc: request and mapp iomem with devres tilcdc currently just ioremaps its iomem, without doing the (a bit more robust) request on the memory first. The devm_ functions provide a handy way to both request and ioremap the memory with automatic cleanup. Replace the manual ioremap with the devm_ version. Suggested-by: Thomas Zimmermann Signed-off-by: Philipp Stanner Reviewed-by: Jyri Sarha Tested-by: Jyri Sarha Signed-off-by: Jyri Sarha Link: https://patchwork.freedesktop.org/patch/msgid/20231222115216.19218-2-pstanner@redhat.com --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 23bf16f596f6..cd5eefa06060 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -182,9 +182,6 @@ static void tilcdc_fini(struct drm_device *dev) if (priv->clk) clk_put(priv->clk); - if (priv->mmio) - iounmap(priv->mmio); - if (priv->wq) destroy_workqueue(priv->wq); @@ -201,7 +198,6 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct device_node *node = dev->of_node; struct tilcdc_drm_private *priv; - struct resource *res; u32 bpp = 0; int ret; @@ -226,17 +222,10 @@ static int tilcdc_init(const struct drm_driver *ddrv, struct device *dev) goto init_failed; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to get memory resource\n"); - ret = -EINVAL; - goto init_failed; - } - - priv->mmio = ioremap(res->start, resource_size(res)); - if (!priv->mmio) { - dev_err(dev, "failed to ioremap\n"); - ret = -ENOMEM; + priv->mmio = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->mmio)) { + dev_err(dev, "failed to request / ioremap\n"); + ret = PTR_ERR(priv->mmio); goto init_failed; } -- cgit v1.2.3 From 407eaa4aa64a8429094fa75fac00fff5e471138d Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:41:53 +0100 Subject: drm/rockchip: vop: Add output selection registers for RK312x In contrast to RK3036, RK312x SoCs have multiple output channels such as RGB (i.e. LVDS TTL), LVDS, DSI and HDMI. In order to support that, this splits output from RK3036 and defines an separate one for RK3126 with the registers required to enable the appropriate output and setup the correct polarity. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-3-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 13 ++++++++++++- drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index c51ca82320cb..b9ee02061d5b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -227,11 +227,22 @@ static const struct vop_win_data rk3126_vop_win_data[] = { .type = DRM_PLANE_TYPE_CURSOR }, }; +static const struct vop_output rk3126_output = { + .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4), + .hdmi_pin_pol = VOP_REG(RK3126_INT_SCALER, 0x7, 4), + .hdmi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 22), + .hdmi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 23), + .rgb_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 24), + .rgb_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 25), + .mipi_en = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 28), + .mipi_dclk_pol = VOP_REG(RK3036_AXI_BUS_CTRL, 0x1, 29), +}; + static const struct vop_data rk3126_vop = { .intr = &rk3036_intr, .common = &rk3036_common, .modeset = &rk3036_modeset, - .output = &rk3036_output, + .output = &rk3126_output, .win = rk3126_vop_win_data, .win_size = ARRAY_SIZE(rk3126_vop_win_data), .max_output = { 1920, 1080 }, diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index 406e981c75bd..fbf1bcc68625 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -872,6 +872,9 @@ /* rk3036 register definition end */ /* rk3126 register definition */ +#define RK3126_INT_SCALER 0x0c + +/* win1 register */ #define RK3126_WIN1_MST 0x4c #define RK3126_WIN1_DSP_INFO 0x50 #define RK3126_WIN1_DSP_ST 0x54 -- cgit v1.2.3 From 47a145c03484d33e65d773169d5ca1b9fe2a492e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:41:54 +0100 Subject: drm/rockchip: inno_hdmi: Fix video timing The controller wants the difference between *total and *sync_start in the HDMI_VIDEO_EXT_*DELAY registers. Otherwise the signal is very unstable for certain non-VIC modes. See downstream commit [0]. [0] https://github.com/rockchip-linux/kernel/commit/8eb559f2502c Fixes: 412d4ae6b7a5 ("drm/rockchip: hdmi: add Innosilicon HDMI support") Co-developed-by: Zheng Yang Signed-off-by: Zheng Yang Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-4-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f6d819803c0e..50c984ac107d 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -411,7 +411,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF); hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF); - value = mode->hsync_start - mode->hdisplay; + value = mode->htotal - mode->hsync_start; hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF); hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF); @@ -426,7 +426,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, value = mode->vtotal - mode->vdisplay; hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF); - value = mode->vsync_start - mode->vdisplay; + value = mode->vtotal - mode->vsync_start; hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF); value = mode->vsync_end - mode->vsync_start; -- cgit v1.2.3 From 099be7b6718685ebafb417e74bb637abf992474a Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:55 +0100 Subject: drm/rockchip: inno_hdmi: Remove useless mode_fixup The mode_fixup implementation doesn't do anything, so we can simply remove it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-5-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 50c984ac107d..a50d1d7e9e06 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -516,13 +516,6 @@ static void inno_hdmi_encoder_disable(struct drm_encoder *encoder) inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); } -static bool inno_hdmi_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) -{ - return true; -} - static int inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -539,7 +532,6 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { .enable = inno_hdmi_encoder_enable, .disable = inno_hdmi_encoder_disable, - .mode_fixup = inno_hdmi_encoder_mode_fixup, .mode_set = inno_hdmi_encoder_mode_set, .atomic_check = inno_hdmi_encoder_atomic_check, }; -- cgit v1.2.3 From 8f0df2012b8a94aed0cc450016f7592c24e92cfb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:56 +0100 Subject: drm/rockchip: inno_hdmi: Remove useless copy of drm_display_mode The driver maintains a copy of the adjusted mode but doesn't use it anywhere. Remove it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-6-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index a50d1d7e9e06..0b16e449c17b 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -61,7 +61,6 @@ struct inno_hdmi { unsigned int tmds_rate; struct hdmi_data_info hdmi_data; - struct drm_display_mode previous_mode; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) @@ -497,9 +496,6 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); inno_hdmi_setup(hdmi, adj_mode); - - /* Store the display mode for plugin/DPMS poweron events */ - drm_mode_copy(&hdmi->previous_mode, adj_mode); } static void inno_hdmi_encoder_enable(struct drm_encoder *encoder) -- cgit v1.2.3 From ff4d4fa76fcc19f7d5d261f717121f0a88ec4e30 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:57 +0100 Subject: drm/rockchip: inno_hdmi: Switch encoder hooks to atomic The inno_hdmi encoder still uses the !atomic variants of enable, disable and modeset. Convert to their atomic equivalents. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-7-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 0b16e449c17b..4616ff8c22e7 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -490,22 +490,25 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, } static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { + struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode; struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); inno_hdmi_setup(hdmi, adj_mode); } -static void inno_hdmi_encoder_enable(struct drm_encoder *encoder) +static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); inno_hdmi_set_pwr_mode(hdmi, NORMAL); } -static void inno_hdmi_encoder_disable(struct drm_encoder *encoder) +static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); @@ -526,10 +529,10 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, } static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { - .enable = inno_hdmi_encoder_enable, - .disable = inno_hdmi_encoder_disable, - .mode_set = inno_hdmi_encoder_mode_set, - .atomic_check = inno_hdmi_encoder_atomic_check, + .atomic_check = inno_hdmi_encoder_atomic_check, + .atomic_enable = inno_hdmi_encoder_enable, + .atomic_disable = inno_hdmi_encoder_disable, + .atomic_mode_set = inno_hdmi_encoder_mode_set, }; static enum drm_connector_status -- cgit v1.2.3 From d3e040f450ec8e46ff42fa495a433b976ab47686 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:58 +0100 Subject: drm/rockchip: inno_hdmi: Get rid of mode_set We're not doing anything special in atomic_mode_set so we can simply merge it into atomic_enable. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-8-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 4616ff8c22e7..38990a13ee19 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -489,21 +489,22 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, return 0; } -static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode; - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - - inno_hdmi_setup(hdmi, adj_mode); -} - static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + + conn_state = drm_atomic_get_new_connector_state(state, &hdmi->connector); + if (WARN_ON(!conn_state)) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + if (WARN_ON(!crtc_state)) + return; + inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode); inno_hdmi_set_pwr_mode(hdmi, NORMAL); } @@ -532,7 +533,6 @@ static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { .atomic_check = inno_hdmi_encoder_atomic_check, .atomic_enable = inno_hdmi_encoder_enable, .atomic_disable = inno_hdmi_encoder_disable, - .atomic_mode_set = inno_hdmi_encoder_mode_set, }; static enum drm_connector_status -- cgit v1.2.3 From d7ba3d711cf537ef0ece14cd85d2113ca338a00b Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:41:59 +0100 Subject: drm/rockchip: inno_hdmi: no need to store vic The mode's VIC is only ever used in the inno_hdmi_setup() function so there's no need to store it in the main structure. Signed-off-by: Maxime Ripard Tested-by: Alex Bee [made checkpatch happy] Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-9-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 38990a13ee19..437c5dcbab0d 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -27,7 +27,6 @@ #include "inno_hdmi.h" struct hdmi_data_info { - int vic; bool sink_has_audio; unsigned int enc_in_format; unsigned int enc_out_format; @@ -442,16 +441,15 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { struct drm_display_info *display = &hdmi->connector.display_info; - - hdmi->hdmi_data.vic = drm_match_cea_mode(mode); + u8 vic = drm_match_cea_mode(mode); hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB; hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; - if ((hdmi->hdmi_data.vic == 6) || (hdmi->hdmi_data.vic == 7) || - (hdmi->hdmi_data.vic == 21) || (hdmi->hdmi_data.vic == 22) || - (hdmi->hdmi_data.vic == 2) || (hdmi->hdmi_data.vic == 3) || - (hdmi->hdmi_data.vic == 17) || (hdmi->hdmi_data.vic == 18)) + if (vic == 6 || vic == 7 || + vic == 21 || vic == 22 || + vic == 2 || vic == 3 || + vic == 17 || vic == 18) hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; else hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; -- cgit v1.2.3 From f8723484e045ff2d176124484907ec0199c55a0c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:00 +0100 Subject: drm/rockchip: inno_hdmi: Remove unneeded has audio flag The sink_has_audio flag is not used anywhere in the driver so let's get rid of it. It's redundant with drm_display_info.has_audio anyway. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-10-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 437c5dcbab0d..6120ab8dd8fd 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -27,7 +27,6 @@ #include "inno_hdmi.h" struct hdmi_data_info { - bool sink_has_audio; unsigned int enc_in_format; unsigned int enc_out_format; unsigned int colorimetry; @@ -553,7 +552,6 @@ static int inno_hdmi_connector_get_modes(struct drm_connector *connector) edid = drm_get_edid(connector, hdmi->ddc); if (edid) { - hdmi->hdmi_data.sink_has_audio = drm_detect_monitor_audio(edid); drm_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); kfree(edid); -- cgit v1.2.3 From c1ceee3248742149d1a602fd913bd88857da1d52 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:01 +0100 Subject: drm/rockchip: inno_hdmi: Remove useless input format The driver has a lot of logic to deal with multiple input formats, but hardcodes it to RGB. This means that most of that code has been dead code, so let's get rid of it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee [made checkpatch happy] Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-11-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 41 ++++++++++-------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 6120ab8dd8fd..3cb84943646f 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -27,7 +27,6 @@ #include "inno_hdmi.h" struct hdmi_data_info { - unsigned int enc_in_format; unsigned int enc_out_format; unsigned int colorimetry; }; @@ -327,47 +326,30 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) v_VIDEO_INPUT_CSP(0); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); - if (data->enc_in_format == data->enc_out_format) { - if ((data->enc_in_format == HDMI_COLORSPACE_RGB) || - (data->enc_in_format >= HDMI_COLORSPACE_YUV444)) { - value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); - - hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, - m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, - v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | - v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); - return 0; - } + if (data->enc_out_format == HDMI_COLORSPACE_RGB) { + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); + + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); + return 0; } if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if ((data->enc_in_format == HDMI_COLORSPACE_RGB) && - (data->enc_out_format == HDMI_COLORSPACE_YUV444)) { + if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; - } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) && - (data->enc_out_format == HDMI_COLORSPACE_RGB)) { - csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT; - auto_csc = AUTO_CSC_ENABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_DISABLE; } } else { - if ((data->enc_in_format == HDMI_COLORSPACE_RGB) && - (data->enc_out_format == HDMI_COLORSPACE_YUV444)) { + if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; - } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) && - (data->enc_out_format == HDMI_COLORSPACE_RGB)) { - csc_mode = CSC_ITU709_16_235_TO_RGB_0_255_8BIT; - auto_csc = AUTO_CSC_ENABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_DISABLE; } } @@ -442,7 +424,6 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_info *display = &hdmi->connector.display_info; u8 vic = drm_match_cea_mode(mode); - hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB; hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; if (vic == 6 || vic == 7 || -- cgit v1.2.3 From 139771b8239c43ad1bd6c2976aa12788096a5483 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:02 +0100 Subject: drm/rockchip: inno_hdmi: Remove YUV-based csc coefficents Now that the unneeded support for YUV based input formats is gone, the csc coefficients for those formats can be dropped as well. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-12-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 37 ------------------------------------ 1 file changed, 37 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 3cb84943646f..b5ba5fecbec9 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -73,49 +73,12 @@ static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) } enum { - CSC_ITU601_16_235_TO_RGB_0_255_8BIT, - CSC_ITU601_0_255_TO_RGB_0_255_8BIT, - CSC_ITU709_16_235_TO_RGB_0_255_8BIT, CSC_RGB_0_255_TO_ITU601_16_235_8BIT, CSC_RGB_0_255_TO_ITU709_16_235_8BIT, CSC_RGB_0_255_TO_RGB_16_235_8BIT, }; static const char coeff_csc[][24] = { - /* - * YUV2RGB:601 SD mode(Y[16:235], UV[16:240], RGB[0:255]): - * R = 1.164*Y + 1.596*V - 204 - * G = 1.164*Y - 0.391*U - 0.813*V + 154 - * B = 1.164*Y + 2.018*U - 258 - */ - { - 0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc, - 0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a, - 0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02 - }, - /* - * YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]): - * R = Y + 1.402*V - 248 - * G = Y - 0.344*U - 0.714*V + 135 - * B = Y + 1.772*U - 227 - */ - { - 0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8, - 0x04, 0x00, 0x11, 0x60, 0x12, 0xdb, 0x00, 0x87, - 0x04, 0x00, 0x07, 0x16, 0x00, 0x00, 0x02, 0xe3 - }, - /* - * YUV2RGB:709 HD mode(Y[16:235],UV[16:240],RGB[0:255]): - * R = 1.164*Y + 1.793*V - 248 - * G = 1.164*Y - 0.213*U - 0.534*V + 77 - * B = 1.164*Y + 2.115*U - 289 - */ - { - 0x04, 0xa7, 0x00, 0x00, 0x07, 0x2c, 0x02, 0xf8, - 0x04, 0xa7, 0x10, 0xda, 0x12, 0x22, 0x00, 0x4d, - 0x04, 0xa7, 0x08, 0x74, 0x00, 0x00, 0x03, 0x21 - }, - /* * RGB2YUV:601 SD mode: * Cb = -0.291G - 0.148R + 0.439B + 128 -- cgit v1.2.3 From 5f92474844a4fcb7997da20dd1de2031aed1d794 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:03 +0100 Subject: drm/rockchip: inno_hdmi: Remove tmds rate from structure The tmds_rate field in the inno_hdmi structure is used mostly to configure the internal i2c controller divider through a call to the inno_hdmi_i2c_init() function. We can simply make that rate an argument to that function, which also removes a workaround to initialize the divider at probe time when we don't have a mode yet. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-13-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index b5ba5fecbec9..682087275aeb 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -55,8 +55,6 @@ struct inno_hdmi { struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; - unsigned int tmds_rate; - struct hdmi_data_info hdmi_data; }; @@ -133,11 +131,11 @@ static inline void hdmi_modb(struct inno_hdmi *hdmi, u16 offset, hdmi_writeb(hdmi, offset, temp); } -static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi) +static void inno_hdmi_i2c_init(struct inno_hdmi *hdmi, unsigned long long rate) { - int ddc_bus_freq; + unsigned long long ddc_bus_freq = rate >> 2; - ddc_bus_freq = (hdmi->tmds_rate >> 2) / HDMI_SCL_RATE; + do_div(ddc_bus_freq, HDMI_SCL_RATE); hdmi_writeb(hdmi, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF); hdmi_writeb(hdmi, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF); @@ -420,8 +418,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, * DCLK_LCDC, so we need to init the TMDS rate to mode pixel * clock rate, and reconfigure the DDC clock. */ - hdmi->tmds_rate = mode->clock * 1000; - inno_hdmi_i2c_init(hdmi); + inno_hdmi_i2c_init(hdmi, mode->clock * 1000); /* Unmute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, @@ -799,8 +796,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, * and reconfigure the DDC clock. */ - hdmi->tmds_rate = clk_get_rate(hdmi->pclk); - inno_hdmi_i2c_init(hdmi); + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); ret = inno_hdmi_register(drm, hdmi); if (ret) -- cgit v1.2.3 From aa4f96e2de82f5e0dfc0102d08f66918c5e3637f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:04 +0100 Subject: drm/rockchip: inno_hdmi: Drop HDMI Vendor Infoframe support The HDMI vendor infoframe is only meant to be sent with 4k60 modes and higher, but the controller doesn't support them. Let's drop them from the kernel. Suggested-by: Johan Jonker Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-14-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 682087275aeb..08b5e4da4718 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -205,11 +205,15 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) } static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc, - union hdmi_infoframe *frame, u32 frame_index, - u32 mask, u32 disable, u32 enable) + union hdmi_infoframe *frame, u32 frame_index) { - if (mask) - hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, disable); + struct drm_connector *connector = &hdmi->connector; + + if (frame_index != INFOFRAME_AVI) { + drm_err(connector->dev, + "Unsupported infoframe type: %u\n", frame_index); + return 0; + } hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index); @@ -225,28 +229,11 @@ static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc, for (i = 0; i < rc; i++) hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, packed_frame[i]); - - if (mask) - hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, enable); } return setup_rc; } -static int inno_hdmi_config_video_vsi(struct inno_hdmi *hdmi, - struct drm_display_mode *mode) -{ - union hdmi_infoframe frame; - int rc; - - rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, - &hdmi->connector, - mode); - - return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI, - m_PACKET_VSI_EN, v_PACKET_VSI_EN(0), v_PACKET_VSI_EN(1)); -} - static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { @@ -264,7 +251,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; - return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0); + return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI); } static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) @@ -407,10 +394,8 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, inno_hdmi_config_video_csc(hdmi); - if (display->is_hdmi) { + if (display->is_hdmi) inno_hdmi_config_video_avi(hdmi, mode); - inno_hdmi_config_video_vsi(hdmi, mode); - } /* * When IP controller have configured to an accurate video -- cgit v1.2.3 From cc9ec38cb2cd32518fe02615d004e96ce2fd0348 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:05 +0100 Subject: drm/rockchip: inno_hdmi: Move infoframe disable to separate function The code to upload infoframes to the controller uses a weird construct which, based on the previous function call return code, will either disable or enable that infoframe. In order to get rid of that argument, let's split the function to disable the infoframe into a separate function and make it obvious what we are doing in the error path. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-15-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 46 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 08b5e4da4718..90a163029773 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -204,34 +204,44 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) inno_hdmi_set_pwr_mode(hdmi, NORMAL); } -static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc, - union hdmi_infoframe *frame, u32 frame_index) +static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, u32 frame_index) { struct drm_connector *connector = &hdmi->connector; if (frame_index != INFOFRAME_AVI) { drm_err(connector->dev, "Unsupported infoframe type: %u\n", frame_index); - return 0; + return; } hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index); +} - if (setup_rc >= 0) { - u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; - ssize_t rc, i; - - rc = hdmi_infoframe_pack(frame, packed_frame, - sizeof(packed_frame)); - if (rc < 0) - return rc; +static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, + union hdmi_infoframe *frame, u32 frame_index) +{ + struct drm_connector *connector = &hdmi->connector; + u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; + ssize_t rc, i; - for (i = 0; i < rc; i++) - hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, - packed_frame[i]); + if (frame_index != INFOFRAME_AVI) { + drm_err(connector->dev, + "Unsupported infoframe type: %u\n", frame_index); + return 0; } - return setup_rc; + inno_hdmi_disable_frame(hdmi, frame_index); + + rc = hdmi_infoframe_pack(frame, packed_frame, + sizeof(packed_frame)); + if (rc < 0) + return rc; + + for (i = 0; i < rc; i++) + hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, + packed_frame[i]); + + return 0; } static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, @@ -243,6 +253,10 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, &hdmi->connector, mode); + if (rc) { + inno_hdmi_disable_frame(hdmi, INFOFRAME_AVI); + return rc; + } if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) frame.avi.colorspace = HDMI_COLORSPACE_YUV444; @@ -251,7 +265,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; - return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI); + return inno_hdmi_upload_frame(hdmi, &frame, INFOFRAME_AVI); } static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) -- cgit v1.2.3 From 4278ff62b73936a9138b60cc0610381003132b77 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:06 +0100 Subject: drm/rockchip: inno_hdmi: Switch to infoframe type The inno_hdmi driver relies on its own internal infoframe type matching the hardware. This works fine, but in order to make further reworks easier, let's switch to the HDMI spec definition of those types. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-16-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 90a163029773..bec91a14965b 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -204,33 +204,34 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) inno_hdmi_set_pwr_mode(hdmi, NORMAL); } -static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, u32 frame_index) +static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, + enum hdmi_infoframe_type type) { struct drm_connector *connector = &hdmi->connector; - if (frame_index != INFOFRAME_AVI) { + if (type != HDMI_INFOFRAME_TYPE_AVI) { drm_err(connector->dev, - "Unsupported infoframe type: %u\n", frame_index); + "Unsupported infoframe type: %u\n", type); return; } - hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index); + hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); } static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, - union hdmi_infoframe *frame, u32 frame_index) + union hdmi_infoframe *frame, enum hdmi_infoframe_type type) { struct drm_connector *connector = &hdmi->connector; u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE]; ssize_t rc, i; - if (frame_index != INFOFRAME_AVI) { + if (type != HDMI_INFOFRAME_TYPE_AVI) { drm_err(connector->dev, - "Unsupported infoframe type: %u\n", frame_index); + "Unsupported infoframe type: %u\n", type); return 0; } - inno_hdmi_disable_frame(hdmi, frame_index); + inno_hdmi_disable_frame(hdmi, type); rc = hdmi_infoframe_pack(frame, packed_frame, sizeof(packed_frame)); @@ -254,7 +255,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, &hdmi->connector, mode); if (rc) { - inno_hdmi_disable_frame(hdmi, INFOFRAME_AVI); + inno_hdmi_disable_frame(hdmi, HDMI_INFOFRAME_TYPE_AVI); return rc; } @@ -265,7 +266,7 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; - return inno_hdmi_upload_frame(hdmi, &frame, INFOFRAME_AVI); + return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI); } static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) -- cgit v1.2.3 From 153fe8dbd866869846af3a359ecf82d5ad9fe247 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 22 Dec 2023 18:42:07 +0100 Subject: drm/rockchip: inno_hdmi: Remove unused drm device pointer The drm_dev field in the inno_hdmi struct stores a pointer to the DRM device but is never used anywhere in the driver. Let's remove it. Signed-off-by: Maxime Ripard Tested-by: Alex Bee Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-17-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index bec91a14965b..f17f0c4859d3 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -43,7 +43,6 @@ struct inno_hdmi_i2c { struct inno_hdmi { struct device *dev; - struct drm_device *drm_dev; int irq; struct clk *pclk; @@ -756,7 +755,6 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, return -ENOMEM; hdmi->dev = dev; - hdmi->drm_dev = drm; hdmi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hdmi->regs)) -- cgit v1.2.3 From 073aa696f8cbc170a2c3502c2165aeb835be0156 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:08 +0100 Subject: drm/rockchip: inno_hdmi: Drop irq struct member The struct member irq isn't used anywhere. Drop it. Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-18-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index f17f0c4859d3..610e7241e4f3 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -44,7 +44,6 @@ struct inno_hdmi_i2c { struct inno_hdmi { struct device *dev; - int irq; struct clk *pclk; void __iomem *regs; -- cgit v1.2.3 From f68a68fe9d9197ea6aa9cb461270685f370b165e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:09 +0100 Subject: drm/rockchip: inno_hdmi: Remove useless include The inclusion syscon.h isn't used anywhere. Remove it. Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-19-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 610e7241e4f3..9fb1e49bc909 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From ceeb0f0104a62c867656c2730a51df47e7350b8f Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:10 +0100 Subject: drm/rockchip: inno_hdmi: Subclass connector state The data which is currently hold in hdmi_data should not be part of device itself but of the connector state. Introduce a connector state subclass and move the data from hdmi_data in there. Suggested-by: Maxime Ripard Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-20-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 116 +++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 9fb1e49bc909..c6a4b228ea93 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -25,11 +25,6 @@ #include "inno_hdmi.h" -struct hdmi_data_info { - unsigned int enc_out_format; - unsigned int colorimetry; -}; - struct inno_hdmi_i2c { struct i2c_adapter adap; @@ -51,8 +46,12 @@ struct inno_hdmi { struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; +}; - struct hdmi_data_info hdmi_data; +struct inno_hdmi_connector_state { + struct drm_connector_state base; + unsigned int enc_out_format; + unsigned int colorimetry; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) @@ -67,6 +66,9 @@ static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) return container_of(connector, struct inno_hdmi, connector); } +#define to_inno_hdmi_conn_state(conn_state) \ + container_of_const(conn_state, struct inno_hdmi_connector_state, base) + enum { CSC_RGB_0_255_TO_ITU601_16_235_8BIT, CSC_RGB_0_255_TO_ITU709_16_235_8BIT, @@ -245,6 +247,10 @@ static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { + struct drm_connector *connector = &hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); union hdmi_infoframe frame; int rc; @@ -256,9 +262,9 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, return rc; } - if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444) + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) frame.avi.colorspace = HDMI_COLORSPACE_YUV444; - else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422) + else if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV422) frame.avi.colorspace = HDMI_COLORSPACE_YUV422; else frame.avi.colorspace = HDMI_COLORSPACE_RGB; @@ -268,7 +274,10 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) { - struct hdmi_data_info *data = &hdmi->hdmi_data; + struct drm_connector *connector = &hdmi->connector; + struct drm_connector_state *conn_state = connector->state; + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); int c0_c2_change = 0; int csc_enable = 0; int csc_mode = 0; @@ -286,7 +295,7 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) v_VIDEO_INPUT_CSP(0); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); - if (data->enc_out_format == HDMI_COLORSPACE_RGB) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); @@ -297,15 +306,15 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) return 0; } - if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; } } else { - if (data->enc_out_format == HDMI_COLORSPACE_YUV444) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; @@ -382,17 +391,6 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { struct drm_display_info *display = &hdmi->connector.display_info; - u8 vic = drm_match_cea_mode(mode); - - hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB; - - if (vic == 6 || vic == 7 || - vic == 21 || vic == 22 || - vic == 2 || vic == 3 || - vic == 17 || vic == 18) - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; - else - hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; /* Mute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, @@ -457,10 +455,24 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct drm_display_mode *mode = &crtc_state->adjusted_mode; + u8 vic = drm_match_cea_mode(mode); + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(conn_state); s->output_mode = ROCKCHIP_OUT_MODE_P888; s->output_type = DRM_MODE_CONNECTOR_HDMIA; + if (vic == 6 || vic == 7 || + vic == 21 || vic == 22 || + vic == 2 || vic == 3 || + vic == 17 || vic == 18) + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601; + else + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; + + inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + return 0; } @@ -518,13 +530,63 @@ static void inno_hdmi_connector_destroy(struct drm_connector *connector) drm_connector_cleanup(connector); } +static void +inno_hdmi_connector_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct inno_hdmi_connector_state *inno_conn_state = + to_inno_hdmi_conn_state(state); + + __drm_atomic_helper_connector_destroy_state(&inno_conn_state->base); + kfree(inno_conn_state); +} + +static void inno_hdmi_connector_reset(struct drm_connector *connector) +{ + struct inno_hdmi_connector_state *inno_conn_state; + + if (connector->state) { + inno_hdmi_connector_destroy_state(connector, connector->state); + connector->state = NULL; + } + + inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL); + if (!inno_conn_state) + return; + + __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base); + + inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; + inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; +} + +static struct drm_connector_state * +inno_hdmi_connector_duplicate_state(struct drm_connector *connector) +{ + struct inno_hdmi_connector_state *inno_conn_state; + + if (WARN_ON(!connector->state)) + return NULL; + + inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state), + sizeof(*inno_conn_state), GFP_KERNEL); + + if (!inno_conn_state) + return NULL; + + __drm_atomic_helper_connector_duplicate_state(connector, + &inno_conn_state->base); + + return &inno_conn_state->base; +} + static const struct drm_connector_funcs inno_hdmi_connector_funcs = { .fill_modes = inno_hdmi_probe_single_connector_modes, .detect = inno_hdmi_connector_detect, .destroy = inno_hdmi_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .reset = inno_hdmi_connector_reset, + .atomic_duplicate_state = inno_hdmi_connector_duplicate_state, + .atomic_destroy_state = inno_hdmi_connector_destroy_state, }; static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { -- cgit v1.2.3 From 164abbd2b7ef62aae6fc80450a2d085acdc3da3e Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:11 +0100 Subject: drm/rockchip: inno_hdmi: Correctly setup HDMI quantization range The display controller will always give full range RGB regardless of the mode set, but HDMI requires certain modes to be transmitted in limited range RGB. This is especially required for HDMI sinks which do not support non-standard quantization ranges. This enables color space conversion for those modes and sets the quantization range accordingly in the AVI infoframe. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-21-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 60 +++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index c6a4b228ea93..fbf73f6b99ca 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -52,6 +52,7 @@ struct inno_hdmi_connector_state { struct drm_connector_state base; unsigned int enc_out_format; unsigned int colorimetry; + bool rgb_limited_range; }; static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) @@ -269,6 +270,18 @@ static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi, else frame.avi.colorspace = HDMI_COLORSPACE_RGB; + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { + drm_hdmi_avi_infoframe_quant_range(&frame.avi, + connector, mode, + inno_conn_state->rgb_limited_range ? + HDMI_QUANTIZATION_RANGE_LIMITED : + HDMI_QUANTIZATION_RANGE_FULL); + } else { + frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; + frame.avi.ycc_quantization_range = + HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + } + return inno_hdmi_upload_frame(hdmi, &frame, HDMI_INFOFRAME_TYPE_AVI); } @@ -296,29 +309,37 @@ static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value); if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_RGB) { - value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); - hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); - - hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, - m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, - v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | - v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); - return 0; - } - - if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { - csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; + if (inno_conn_state->rgb_limited_range) { + csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT; auto_csc = AUTO_CSC_DISABLE; c0_c2_change = C0_C2_CHANGE_DISABLE; csc_enable = v_CSC_ENABLE; + + } else { + value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1); + hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); + + hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, + m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP, + v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) | + v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE)); + return 0; } } else { - if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { - csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; - auto_csc = AUTO_CSC_DISABLE; - c0_c2_change = C0_C2_CHANGE_DISABLE; - csc_enable = v_CSC_ENABLE; + if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; + auto_csc = AUTO_CSC_DISABLE; + c0_c2_change = C0_C2_CHANGE_DISABLE; + csc_enable = v_CSC_ENABLE; + } + } else { + if (inno_conn_state->enc_out_format == HDMI_COLORSPACE_YUV444) { + csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT; + auto_csc = AUTO_CSC_DISABLE; + c0_c2_change = C0_C2_CHANGE_DISABLE; + csc_enable = v_CSC_ENABLE; + } } } @@ -472,6 +493,8 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + inno_conn_state->rgb_limited_range = + drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; return 0; } @@ -558,6 +581,7 @@ static void inno_hdmi_connector_reset(struct drm_connector *connector) inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; inno_conn_state->enc_out_format = HDMI_COLORSPACE_RGB; + inno_conn_state->rgb_limited_range = false; } static struct drm_connector_state * -- cgit v1.2.3 From 71892cee6ceb3e1b88e0bb44b05c8397d8261a85 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:12 +0100 Subject: drm/rockchip: inno_hdmi: Don't power up the phy after resetting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit inno_hdmi_reset is only ever called when initializing the controller. At this point it’s completely uneccessary to power up the PHY, since all what has to work at this point is the DDC bus. The phy will be powered up correctly when a mode is set in inno_hdmi_encoder_enable and disabled in inno_hdmi_encoder_disable. Set it to LOWER_PWR after resetting the controller. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-22-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index fbf73f6b99ca..763d61704ee6 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -201,7 +201,7 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH; hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); - inno_hdmi_set_pwr_mode(hdmi, NORMAL); + inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); } static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, -- cgit v1.2.3 From f01e33cb586b5fd354cba73052f82c3b4246109d Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:13 +0100 Subject: drm/rockchip: inno_hdmi: Split power mode setting This splits setting the power mode of the controller / phy in two functions. It's done in preparation of setting up the phy based on the pixelclock. No functional changes intended. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-23-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 54 ++++++++++++++++-------------------- drivers/gpu/drm/rockchip/inno_hdmi.h | 5 ---- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 763d61704ee6..da77171b2b42 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -153,38 +153,31 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable) hdmi_modb(hdmi, HDMI_SYS_CTRL, m_POWER, v_PWR_OFF); } -static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) +static void inno_hdmi_standby(struct inno_hdmi *hdmi) { - switch (mode) { - case NORMAL: - inno_hdmi_sys_power(hdmi, false); + inno_hdmi_sys_power(hdmi, false); - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); - - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); - hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f); - hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01); - - inno_hdmi_sys_power(hdmi, true); - break; + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +}; - case LOWER_PWR: - inno_hdmi_sys_power(hdmi, false); - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x00); - hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); +static void inno_hdmi_power_up(struct inno_hdmi *hdmi) +{ + inno_hdmi_sys_power(hdmi, false); - break; + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); + hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); + hdmi_writeb(hdmi, HDMI_PHY_CHG_PWR, 0x0f); + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x00); + hdmi_writeb(hdmi, HDMI_PHY_SYNC, 0x01); - default: - DRM_DEV_ERROR(hdmi->dev, "Unknown power mode %d\n", mode); - } -} + inno_hdmi_sys_power(hdmi, true); +}; static void inno_hdmi_reset(struct inno_hdmi *hdmi) { @@ -201,7 +194,7 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi) val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH; hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val); - inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); + inno_hdmi_standby(hdmi); } static void inno_hdmi_disable_frame(struct inno_hdmi *hdmi, @@ -440,6 +433,8 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); + inno_hdmi_power_up(hdmi); + return 0; } @@ -459,7 +454,6 @@ static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, return; inno_hdmi_setup(hdmi, &crtc_state->adjusted_mode); - inno_hdmi_set_pwr_mode(hdmi, NORMAL); } static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, @@ -467,7 +461,7 @@ static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, { struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); - inno_hdmi_set_pwr_mode(hdmi, LOWER_PWR); + inno_hdmi_standby(hdmi); } static int diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.h b/drivers/gpu/drm/rockchip/inno_hdmi.h index 93245b55f967..a7edf3559e60 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.h +++ b/drivers/gpu/drm/rockchip/inno_hdmi.h @@ -10,11 +10,6 @@ #define DDC_SEGMENT_ADDR 0x30 -enum PWR_MODE { - NORMAL, - LOWER_PWR, -}; - #define HDMI_SCL_RATE (100*1000) #define DDC_BUS_FREQ_L 0x4b #define DDC_BUS_FREQ_H 0x4c -- cgit v1.2.3 From a72aa8985c41ec241263b802857d84f4c90a8694 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:18 +0100 Subject: dt-bindings: display: ssd1307fb: Add vendor prefix to width and height The commit 591825fba8a2 ("dt-bindings: display: ssd1307fb: Remove default width and height values") used the wrong properties for width and height, instead of the correct "solomon,width" and "solomon,height" properties. Fix this by adding the vendor prefix to the width and height properties. Fixes: 591825fba8a2 ("dt-bindings: display: ssd1307fb: Remove default width and height values") Reported-by: Conor Dooley Closes: https://lore.kernel.org/dri-devel/20231218-example-envision-b41ca8efa251@spud/ Signed-off-by: Javier Martinez Canillas Acked-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-2-javierm@redhat.com --- .../bindings/display/solomon,ssd1307fb.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml index 3afbb52d1b7f..153ff86fb405 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml @@ -131,9 +131,9 @@ allOf: const: sinowealth,sh1106 then: properties: - width: + solomon,width: default: 132 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -149,9 +149,9 @@ allOf: - solomon,ssd1305 then: properties: - width: + solomon,width: default: 132 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -167,9 +167,9 @@ allOf: - solomon,ssd1306 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 @@ -185,9 +185,9 @@ allOf: - solomon,ssd1307 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 39 solomon,dclk-div: default: 2 @@ -205,9 +205,9 @@ allOf: - solomon,ssd1309 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 64 solomon,dclk-div: default: 1 -- cgit v1.2.3 From 95ea83829e5f406b15175eb445b89000c2558168 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:19 +0100 Subject: dt-bindings: display: ssd132x: Add vendor prefix to width and height Commit 2d23e7d6bacb ("dt-bindings: display: Add SSD132x OLED controllers") used the wrong properties for width and height, instead of the correct "solomon,width" and "solomon,height" properties. Fix this by adding the vendor prefix to the width and height properties. Fixes: 2d23e7d6bacb ("dt-bindings: display: Add SSD132x OLED controllers") Reported-by: Conor Dooley Closes: https://lore.kernel.org/dri-devel/20231218-example-envision-b41ca8efa251@spud/ Signed-off-by: Javier Martinez Canillas Acked-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-3-javierm@redhat.com --- .../devicetree/bindings/display/solomon,ssd132x.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml index 37975ee61c5a..dd7939989cf4 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd132x.yaml @@ -30,9 +30,9 @@ allOf: const: solomon,ssd1322 then: properties: - width: + solomon,width: default: 480 - height: + solomon,height: default: 128 - if: @@ -42,9 +42,9 @@ allOf: const: solomon,ssd1325 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 80 - if: @@ -54,9 +54,9 @@ allOf: const: solomon,ssd1327 then: properties: - width: + solomon,width: default: 128 - height: + solomon,height: default: 128 unevaluatedProperties: false -- cgit v1.2.3 From e06b7373cfb96b73d05712fbd15b6d6a78ce9b9d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:20 +0100 Subject: dt-bindings: display: Add SSD133x OLED controllers Add a Device Tree binding schema for the OLED panels based on the Solomon SSD133x family of controllers. Signed-off-by: Javier Martinez Canillas Reviewed-by: Rob Herring Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-4-javierm@redhat.com --- .../bindings/display/solomon,ssd133x.yaml | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/solomon,ssd133x.yaml diff --git a/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml b/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml new file mode 100644 index 000000000000..b7780038a34b --- /dev/null +++ b/Documentation/devicetree/bindings/display/solomon,ssd133x.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/solomon,ssd133x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Solomon SSD133x OLED Display Controllers + +maintainers: + - Javier Martinez Canillas + +allOf: + - $ref: solomon,ssd-common.yaml# + +properties: + compatible: + enum: + - solomon,ssd1331 + + solomon,width: + default: 96 + + solomon,height: + default: 64 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + oled@0 { + compatible = "solomon,ssd1331"; + reg = <0x0>; + reset-gpios = <&gpio2 7>; + dc-gpios = <&gpio2 8>; + spi-max-frequency = <10000000>; + }; + }; -- cgit v1.2.3 From b4299c936d8fd62b75621cad8dbf8aa9178e7c0e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 29 Dec 2023 12:20:21 +0100 Subject: drm/ssd130x: Add support for the SSD133x OLED controller family The Solomon SSD133x controllers (such as the SSD1331) are used by RGB dot matrix OLED panels, add a modesetting pipeline to support the chip family. The SSD133x controllers support 256 (8-bit) and 65k (16-bit) color depths but only the 256-color mode (DRM_FORMAT_RGB332) is implemented for now. Signed-off-by: Javier Martinez Canillas Reviewed-by: Jocelyn Falempe Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-5-javierm@redhat.com --- drivers/gpu/drm/solomon/ssd130x-spi.c | 7 + drivers/gpu/drm/solomon/ssd130x.c | 370 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/solomon/ssd130x.h | 5 +- 3 files changed, 381 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/solomon/ssd130x-spi.c b/drivers/gpu/drm/solomon/ssd130x-spi.c index 84e035a7ab3f..84bfde31d172 100644 --- a/drivers/gpu/drm/solomon/ssd130x-spi.c +++ b/drivers/gpu/drm/solomon/ssd130x-spi.c @@ -142,6 +142,11 @@ static const struct of_device_id ssd130x_of_match[] = { .compatible = "solomon,ssd1327", .data = &ssd130x_variants[SSD1327_ID], }, + /* ssd133x family */ + { + .compatible = "solomon,ssd1331", + .data = &ssd130x_variants[SSD1331_ID], + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ssd130x_of_match); @@ -166,6 +171,8 @@ static const struct spi_device_id ssd130x_spi_table[] = { { "ssd1322", SSD1322_ID }, { "ssd1325", SSD1325_ID }, { "ssd1327", SSD1327_ID }, + /* ssd133x family */ + { "ssd1331", SSD1331_ID }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(spi, ssd130x_spi_table); diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index bef293922b98..447d0c7c88c6 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -119,6 +119,26 @@ #define SSD130X_SET_VCOMH_VOLTAGE 0xbe #define SSD132X_SET_FUNCTION_SELECT_B 0xd5 +/* ssd133x commands */ +#define SSD133X_SET_COL_RANGE 0x15 +#define SSD133X_SET_ROW_RANGE 0x75 +#define SSD133X_CONTRAST_A 0x81 +#define SSD133X_CONTRAST_B 0x82 +#define SSD133X_CONTRAST_C 0x83 +#define SSD133X_SET_MASTER_CURRENT 0x87 +#define SSD132X_SET_PRECHARGE_A 0x8a +#define SSD132X_SET_PRECHARGE_B 0x8b +#define SSD132X_SET_PRECHARGE_C 0x8c +#define SSD133X_SET_DISPLAY_START 0xa1 +#define SSD133X_SET_DISPLAY_OFFSET 0xa2 +#define SSD133X_SET_DISPLAY_NORMAL 0xa4 +#define SSD133X_SET_MASTER_CONFIG 0xad +#define SSD133X_POWER_SAVE_MODE 0xb0 +#define SSD133X_PHASES_PERIOD 0xb1 +#define SSD133X_SET_CLOCK_FREQ 0xb3 +#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb +#define SSD133X_SET_VCOMH_VOLTAGE 0xbe + #define MAX_CONTRAST 255 const struct ssd130x_deviceinfo ssd130x_variants[] = { @@ -180,6 +200,12 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = { .default_width = 128, .default_height = 128, .family_id = SSD132X_FAMILY, + }, + /* ssd133x family */ + [SSD1331_ID] = { + .default_width = 96, + .default_height = 64, + .family_id = SSD133X_FAMILY, } }; EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X); @@ -589,6 +615,117 @@ static int ssd132x_init(struct ssd130x_device *ssd130x) return 0; } +static int ssd133x_init(struct ssd130x_device *ssd130x) +{ + int ret; + + /* Set color A contrast */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_A, 0x91); + if (ret < 0) + return ret; + + /* Set color B contrast */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_B, 0x50); + if (ret < 0) + return ret; + + /* Set color C contrast */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_C, 0x7d); + if (ret < 0) + return ret; + + /* Set master current */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CURRENT, 0x06); + if (ret < 0) + return ret; + + /* Set column start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1); + if (ret < 0) + return ret; + + /* Set row start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1); + if (ret < 0) + return ret; + + /* + * Horizontal Address Increment + * Normal order SA,SB,SC (e.g. RGB) + * COM Split Odd Even + * 256 color format + */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_SEG_REMAP, 0x20); + if (ret < 0) + return ret; + + /* Set display start and offset */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_START, 0x00); + if (ret < 0) + return ret; + + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_OFFSET, 0x00); + if (ret < 0) + return ret; + + /* Set display mode normal */ + ret = ssd130x_write_cmd(ssd130x, 1, SSD133X_SET_DISPLAY_NORMAL); + if (ret < 0) + return ret; + + /* Set multiplex ratio value */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_MULTIPLEX_RATIO, ssd130x->height - 1); + if (ret < 0) + return ret; + + /* Set master configuration */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CONFIG, 0x8e); + if (ret < 0) + return ret; + + /* Set power mode */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_POWER_SAVE_MODE, 0x0b); + if (ret < 0) + return ret; + + /* Set Phase 1 and 2 period */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_PHASES_PERIOD, 0x31); + if (ret < 0) + return ret; + + /* Set clock divider */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_CLOCK_FREQ, 0xf0); + if (ret < 0) + return ret; + + /* Set pre-charge A */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_A, 0x64); + if (ret < 0) + return ret; + + /* Set pre-charge B */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_B, 0x78); + if (ret < 0) + return ret; + + /* Set pre-charge C */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_C, 0x64); + if (ret < 0) + return ret; + + /* Set pre-charge level */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_PRECHARGE_VOLTAGE, 0x3a); + if (ret < 0) + return ret; + + /* Set VCOMH voltage */ + ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_VCOMH_VOLTAGE, 0x3e); + if (ret < 0) + return ret; + + return 0; +} + static int ssd130x_update_rect(struct ssd130x_device *ssd130x, struct drm_rect *rect, u8 *buf, u8 *data_array) @@ -753,6 +890,47 @@ static int ssd132x_update_rect(struct ssd130x_device *ssd130x, return ret; } +static int ssd133x_update_rect(struct ssd130x_device *ssd130x, + struct drm_rect *rect, u8 *data_array, + unsigned int pitch) +{ + unsigned int x = rect->x1; + unsigned int y = rect->y1; + unsigned int columns = drm_rect_width(rect); + unsigned int rows = drm_rect_height(rect); + int ret; + + /* + * The screen is divided in Segment and Common outputs, where + * COM0 to COM[N - 1] are the rows and SEG0 to SEG[M - 1] are + * the columns. + * + * Each Segment has a 8-bit pixel and each Common output has a + * row of pixels. When using the (default) horizontal address + * increment mode, each byte of data sent to the controller has + * a Segment (e.g: SEG0). + * + * When using the 256 color depth format, each pixel contains 3 + * sub-pixels for color A, B and C. These have 3 bit, 3 bit and + * 2 bits respectively. + */ + + /* Set column start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, x, columns - 1); + if (ret < 0) + return ret; + + /* Set row start and end */ + ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, y, rows - 1); + if (ret < 0) + return ret; + + /* Write out update in one go since horizontal addressing mode is used */ + ret = ssd130x_write_data(ssd130x, data_array, pitch * rows); + + return ret; +} + static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) { unsigned int pages = DIV_ROUND_UP(ssd130x->height, SSD130X_PAGE_HEIGHT); @@ -805,6 +983,22 @@ static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) ssd130x_write_data(ssd130x, data_array, columns * height); } +static void ssd133x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array) +{ + const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332); + unsigned int pitch; + + if (!fi) + return; + + pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width); + + memset(data_array, 0, pitch * ssd130x->height); + + /* Write out update in one go since horizontal addressing mode is used */ + ssd130x_write_data(ssd130x, data_array, pitch * ssd130x->height); +} + static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *vmap, struct drm_rect *rect, @@ -866,6 +1060,36 @@ static int ssd132x_fb_blit_rect(struct drm_framebuffer *fb, return ret; } +static int ssd133x_fb_blit_rect(struct drm_framebuffer *fb, + const struct iosys_map *vmap, + struct drm_rect *rect, u8 *data_array, + struct drm_format_conv_state *fmtcnv_state) +{ + struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev); + const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332); + unsigned int dst_pitch; + struct iosys_map dst; + int ret = 0; + + if (!fi) + return -EINVAL; + + dst_pitch = drm_format_info_min_pitch(fi, 0, drm_rect_width(rect)); + + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return ret; + + iosys_map_set_vaddr(&dst, data_array); + drm_fb_xrgb8888_to_rgb332(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state); + + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); + + ssd133x_update_rect(ssd130x, rect, data_array, dst_pitch); + + return ret; +} + static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -964,6 +1188,29 @@ static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane, return 0; } +static int ssd133x_primary_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + else if (!plane_state->visible) + return 0; + + return 0; +} + static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -1034,6 +1281,39 @@ static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane, drm_dev_exit(idx); } +static void ssd133x_primary_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + struct ssd130x_crtc_state *ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state); + struct drm_framebuffer *fb = plane_state->fb; + struct drm_atomic_helper_damage_iter iter; + struct drm_device *drm = plane->dev; + struct drm_rect dst_clip; + struct drm_rect damage; + int idx; + + if (!drm_dev_enter(drm, &idx)) + return; + + drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); + drm_atomic_for_each_plane_damage(&iter, &damage) { + dst_clip = plane_state->dst; + + if (!drm_rect_intersect(&dst_clip, &damage)) + continue; + + ssd133x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip, + ssd130x_crtc_state->data_array, + &shadow_plane_state->fmtcnv_state); + } + + drm_dev_exit(idx); +} + static void ssd130x_primary_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) { @@ -1082,6 +1362,30 @@ static void ssd132x_primary_plane_atomic_disable(struct drm_plane *plane, drm_dev_exit(idx); } +static void ssd133x_primary_plane_atomic_disable(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_device *drm = plane->dev; + struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc_state *crtc_state; + struct ssd130x_crtc_state *ssd130x_crtc_state; + int idx; + + if (!plane_state->crtc) + return; + + crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc); + ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state); + + if (!drm_dev_enter(drm, &idx)) + return; + + ssd133x_clear_screen(ssd130x, ssd130x_crtc_state->data_array); + + drm_dev_exit(idx); +} + /* Called during init to allocate the plane's atomic state. */ static void ssd130x_primary_plane_reset(struct drm_plane *plane) { @@ -1144,6 +1448,12 @@ static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs[] .atomic_check = ssd132x_primary_plane_atomic_check, .atomic_update = ssd132x_primary_plane_atomic_update, .atomic_disable = ssd132x_primary_plane_atomic_disable, + }, + [SSD133X_FAMILY] = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = ssd133x_primary_plane_atomic_check, + .atomic_update = ssd133x_primary_plane_atomic_update, + .atomic_disable = ssd133x_primary_plane_atomic_disable, } }; @@ -1214,6 +1524,33 @@ static int ssd132x_crtc_atomic_check(struct drm_crtc *crtc, return 0; } +static int ssd133x_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_device *drm = crtc->dev; + struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state); + const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332); + unsigned int pitch; + int ret; + + if (!fi) + return -EINVAL; + + ret = drm_crtc_helper_atomic_check(crtc, state); + if (ret) + return ret; + + pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width); + + ssd130x_state->data_array = kmalloc(pitch * ssd130x->height, GFP_KERNEL); + if (!ssd130x_state->data_array) + return -ENOMEM; + + return 0; +} + /* Called during init to allocate the CRTC's atomic state. */ static void ssd130x_crtc_reset(struct drm_crtc *crtc) { @@ -1275,6 +1612,10 @@ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs[] = { .mode_valid = ssd130x_crtc_mode_valid, .atomic_check = ssd132x_crtc_atomic_check, }, + [SSD133X_FAMILY] = { + .mode_valid = ssd130x_crtc_mode_valid, + .atomic_check = ssd133x_crtc_atomic_check, + }, }; static const struct drm_crtc_funcs ssd130x_crtc_funcs = { @@ -1337,6 +1678,31 @@ power_off: ssd130x_power_off(ssd130x); } +static void ssd133x_encoder_atomic_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct drm_device *drm = encoder->dev; + struct ssd130x_device *ssd130x = drm_to_ssd130x(drm); + int ret; + + ret = ssd130x_power_on(ssd130x); + if (ret) + return; + + ret = ssd133x_init(ssd130x); + if (ret) + goto power_off; + + ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_ON); + + backlight_enable(ssd130x->bl_dev); + + return; + +power_off: + ssd130x_power_off(ssd130x); +} + static void ssd130x_encoder_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { @@ -1358,6 +1724,10 @@ static const struct drm_encoder_helper_funcs ssd130x_encoder_helper_funcs[] = { [SSD132X_FAMILY] = { .atomic_enable = ssd132x_encoder_atomic_enable, .atomic_disable = ssd130x_encoder_atomic_disable, + }, + [SSD133X_FAMILY] = { + .atomic_enable = ssd133x_encoder_atomic_enable, + .atomic_disable = ssd130x_encoder_atomic_disable, } }; diff --git a/drivers/gpu/drm/solomon/ssd130x.h b/drivers/gpu/drm/solomon/ssd130x.h index 075c5c3ee75a..a4554018bb2a 100644 --- a/drivers/gpu/drm/solomon/ssd130x.h +++ b/drivers/gpu/drm/solomon/ssd130x.h @@ -25,7 +25,8 @@ enum ssd130x_family_ids { SSD130X_FAMILY, - SSD132X_FAMILY + SSD132X_FAMILY, + SSD133X_FAMILY }; enum ssd130x_variants { @@ -39,6 +40,8 @@ enum ssd130x_variants { SSD1322_ID, SSD1325_ID, SSD1327_ID, + /* ssd133x family */ + SSD1331_ID, NR_SSD130X_VARIANTS }; -- cgit v1.2.3 From b8a5d1f4a08751031a18621ce1b59fc49d042494 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 16 Dec 2023 14:15:27 +0000 Subject: drm/vc4: plane: check drm_gem_plane_helper_prepare_fb() return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bubble up any error to the caller. Signed-off-by: Simon Ser Cc: Maxime Ripard Cc: Kees Cook Cc: Dave Stevenson Reviewed-by: Maíra Canal Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20231216141518.242811-1-contact@emersion.fr --- drivers/gpu/drm/vc4/vc4_plane.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 00e713faecd5..b8184374332c 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1497,13 +1497,16 @@ static int vc4_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) { struct vc4_bo *bo; + int ret; if (!state->fb) return 0; bo = to_vc4_bo(&drm_fb_dma_get_gem_obj(state->fb, 0)->base); - drm_gem_plane_helper_prepare_fb(plane, state); + ret = drm_gem_plane_helper_prepare_fb(plane, state); + if (ret) + return ret; if (plane->state->fb == state->fb) return 0; -- cgit v1.2.3 From cf8837d7204481026335461629b84ac7f4538fa5 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:20 -0500 Subject: drm: Don't treat 0 as -1 in drm_fixp2int_ceil Unit testing this in VKMS shows that passing 0 into this function returns -1, which is highly counter- intuitive. Fix it by checking whether the input is >= 0 instead of > 0. Fixes: 64566b5e767f ("drm: Add drm_fixp_from_fraction and drm_fixp2int_ceil") Signed-off-by: Harry Wentland Reviewed-by: Simon Ser Reviewed-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231108163647.106853-2-harry.wentland@amd.com --- include/drm/drm_fixed.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h index 6ea339d5de08..0c9f917a4d4b 100644 --- a/include/drm/drm_fixed.h +++ b/include/drm/drm_fixed.h @@ -95,7 +95,7 @@ static inline int drm_fixp2int_round(s64 a) static inline int drm_fixp2int_ceil(s64 a) { - if (a > 0) + if (a >= 0) return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE); else return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE); -- cgit v1.2.3 From ffcc67cd79ff2e93fd0bdb837c99cbab6c59d38c Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:22 -0500 Subject: drm/vkms: Create separate Kconfig file for VKMS This aligns with most other DRM drivers and will allow us to add new VKMS config options without polluting the DRM Kconfig. v3: - Change SPDX to GPL-2.0-only to match DRM KConfig SPDX (Simon) Signed-off-by: Harry Wentland Reviewed-by: Simon Ser Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231108163647.106853-4-harry.wentland@amd.com --- drivers/gpu/drm/Kconfig | 14 +------------- drivers/gpu/drm/vkms/Kconfig | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/vkms/Kconfig diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 4b8b8f8a0e72..628f90ed8a9b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -287,19 +287,7 @@ config DRM_VGEM as used by Mesa's software renderer for enhanced performance. If M is selected the module will be called vgem. -config DRM_VKMS - tristate "Virtual KMS (EXPERIMENTAL)" - depends on DRM && MMU - select DRM_KMS_HELPER - select DRM_GEM_SHMEM_HELPER - select CRC32 - default n - help - Virtual Kernel Mode-Setting (VKMS) is used for testing or for - running GPU in a headless machines. Choose this option to get - a VKMS. - - If M is selected the module will be called vkms. +source "drivers/gpu/drm/vkms/Kconfig" source "drivers/gpu/drm/exynos/Kconfig" diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig new file mode 100644 index 000000000000..b9ecdebecb0b --- /dev/null +++ b/drivers/gpu/drm/vkms/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config DRM_VKMS + tristate "Virtual KMS (EXPERIMENTAL)" + depends on DRM && MMU + select DRM_KMS_HELPER + select DRM_GEM_SHMEM_HELPER + select CRC32 + default n + help + Virtual Kernel Mode-Setting (VKMS) is used for testing or for + running GPU in a headless machines. Choose this option to get + a VKMS. + + If M is selected the module will be called vkms. -- cgit v1.2.3 From 2fee84030d12d9fddfa874e4562d71761a129277 Mon Sep 17 00:00:00 2001 From: Harry Wentland Date: Wed, 8 Nov 2023 11:36:24 -0500 Subject: drm/vkms: Avoid reading beyond LUT array When the floor LUT index (drm_fixp2int(lut_index) is the last index of the array the ceil LUT index will point to an entry beyond the array. Make sure we guard against it and use the value of the floor LUT index. v3: - Drop bits from commit description that didn't contribute anything of value Fixes: db1f254f2cfa ("drm/vkms: Add support to 1D gamma LUT") Signed-off-by: Harry Wentland Cc: Arthur Grillo Reviewed-by: Arthur Grillo Reviewed-by: Melissa Wen Signed-off-by: Melissa Wen Link: https://patchwork.freedesktop.org/patch/msgid/20231108163647.106853-6-harry.wentland@amd.com --- drivers/gpu/drm/vkms/vkms_composer.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index 3c99fb8b54e2..e7441b227b3c 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -123,6 +123,8 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan enum lut_channel channel) { s64 lut_index = get_lut_index(lut, channel_value); + u16 *floor_lut_value, *ceil_lut_value; + u16 floor_channel_value, ceil_channel_value; /* * This checks if `struct drm_color_lut` has any gap added by the compiler @@ -130,11 +132,15 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan */ static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4); - u16 *floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)]; - u16 *ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)]; + floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)]; + if (drm_fixp2int(lut_index) == (lut->lut_length - 1)) + /* We're at the end of the LUT array, use same value for ceil and floor */ + ceil_lut_value = floor_lut_value; + else + ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)]; - u16 floor_channel_value = floor_lut_value[channel]; - u16 ceil_channel_value = ceil_lut_value[channel]; + floor_channel_value = floor_lut_value[channel]; + ceil_channel_value = ceil_lut_value[channel]; return lerp_u16(floor_channel_value, ceil_channel_value, lut_index & DRM_FIXED_DECIMAL_MASK); -- cgit v1.2.3 From 0c75d52190b8bfa22cdb66e07148aea599c4535d Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sat, 23 Dec 2023 19:32:48 +0100 Subject: drm/debugfs: drop unneeded DEBUG_FS guard The Makefile enables/disables the file compilation depending on CONFIG_DEBUG_FS. Signed-off-by: Dario Binacchi Reviewed-by: Jani Nikula Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20231223183301.78332-1-dario.binacchi@amarulasolutions.com --- drivers/gpu/drm/drm_debugfs.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index f4715a67e340..08fcefd804bc 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -45,8 +45,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#if defined(CONFIG_DEBUG_FS) - /*************************************************** * Initialization, etc. **************************************************/ @@ -647,5 +645,3 @@ void drm_debugfs_encoder_remove(struct drm_encoder *encoder) debugfs_remove_recursive(encoder->debugfs_entry); encoder->debugfs_entry = NULL; } - -#endif /* CONFIG_DEBUG_FS */ -- cgit v1.2.3 From 09d015deddd6234430c04a1eddaa8a28fd621dec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Dec 2023 17:19:55 +0200 Subject: drm/virtio: Spelling fixes While making a spelling mistake myself for `git grep kvalloc` I found that the only file has such a typo. Fix it and update to the standard de facto of how we refer to the functions. Also spell usr-out as user-out, it seems this driver uses its own terminology nobody else can decypher, make it more readable. Signed-off-by: Andy Shevchenko Signed-off-by: Dmitry Osipenko Link: https://patchwork.freedesktop.org/patch/msgid/20231219151955.2477488-1-andriy.shevchenko@linux.intel.com --- drivers/gpu/drm/virtio/virtgpu_submit.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c index 5c514946bbad..1c7c7f61a222 100644 --- a/drivers/gpu/drm/virtio/virtgpu_submit.c +++ b/drivers/gpu/drm/virtio/virtgpu_submit.c @@ -99,8 +99,8 @@ virtio_gpu_parse_deps(struct virtio_gpu_submit *submit) return 0; /* - * kvalloc at first tries to allocate memory using kmalloc and - * falls back to vmalloc only on failure. It also uses __GFP_NOWARN + * kvmalloc() at first tries to allocate memory using kmalloc() and + * falls back to vmalloc() only on failure. It also uses __GFP_NOWARN * internally for allocations larger than a page size, preventing * storm of KMSG warnings. */ @@ -529,7 +529,7 @@ int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, virtio_gpu_submit(&submit); /* - * Set up usr-out data after submitting the job to optimize + * Set up user-out data after submitting the job to optimize * the job submission path. */ virtio_gpu_install_out_fence_fd(&submit); -- cgit v1.2.3 From ecc8271f56d317627b5875918f2ac7e94242ea6d Mon Sep 17 00:00:00 2001 From: Ghanshyam Agrawal Date: Fri, 15 Dec 2023 11:00:16 +0530 Subject: drm/vmwgfx: Fix typos in vmwgfx_execbuf.c Fix typos in vmwgfx_execbuf.c. Signed-off-by: Ghanshyam Agrawal Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231215053016.552019-1-ghanshyam1898@gmail.com --- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 36987ef3fc30..272141b6164c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -621,10 +621,10 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) * @sw_context: Pointer to the software context. * @res_type: Resource type. * @dirty: Whether to change dirty status. - * @converter: User-space visisble type specific information. + * @converter: User-space visible type specific information. * @id_loc: Pointer to the location in the command buffer currently being parsed * from where the user-space resource id handle is located. - * @p_res: Pointer to pointer to resource validalidation node. Populated on + * @p_res: Pointer to pointer to resource validation node. Populated on * exit. */ static int -- cgit v1.2.3 From 834b1d72051145e553222926b1a375f5441b24eb Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Dec 2023 15:41:02 -0800 Subject: drm/vmwgfx: fix all kernel-doc warnings in stdu kernel test robot reports one kernel-doc warning in stdu, but running scripts/kernel-doc in -Wall mode reports several more, so fix all of them at one time: vmwgfx_stdu.c:76: warning: Excess struct member 'transfer' description in 'vmw_stdu_dirty' vmwgfx_stdu.c:103: warning: missing initial short description on line: * struct vmw_screen_target_display_unit vmwgfx_stdu.c:215: warning: No description found for return value of 'vmw_stdu_bind_st' vmwgfx_stdu.c:320: warning: No description found for return value of 'vmw_stdu_destroy_st' vmwgfx_stdu.c:551: warning: No description found for return value of 'vmw_kms_stdu_readback' vmwgfx_stdu.c:719: warning: No description found for return value of 'vmw_kms_stdu_surface_dirty' vmwgfx_stdu.c:895: warning: No description found for return value of 'vmw_stdu_primary_plane_prepare_fb' vmwgfx_stdu.c:1470: warning: No description found for return value of 'vmw_stdu_init' Signed-off-by: Randy Dunlap Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312150347.5icezNlK-lkp@intel.com/ Cc: Zack Rusin Cc: VMware Graphics Reviewers Cc: dri-devel@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Reviewed-by: Zack Rusin Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231215234102.16574-1-rdunlap@infradead.org --- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index ba0c0e12cfe9..6bc23bdf32c2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -53,7 +53,6 @@ enum stdu_content_type { * struct vmw_stdu_dirty - closure structure for the update functions * * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). - * @transfer: Transfer direction for DMA command. * @left: Left side of bounding box. * @right: Right side of bounding box. * @top: Top side of bounding box. @@ -100,7 +99,7 @@ struct vmw_stdu_update_gb_image { }; /** - * struct vmw_screen_target_display_unit + * struct vmw_screen_target_display_unit - conglomerated STDU structure * * @base: VMW specific DU structure * @display_srf: surface to be displayed. The dimension of this will always @@ -208,6 +207,8 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, * @res: Buffer to bind to the screen target. Set to NULL to blank screen. * * Binding a surface to a Screen Target the same as flipping + * + * Returns: %0 on success or -errno code on failure */ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, struct vmw_screen_target_display_unit *stdu, @@ -314,6 +315,9 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, * * @dev_priv: VMW DRM device * @stdu: display unit to destroy + * + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. */ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, struct vmw_screen_target_display_unit *stdu) @@ -536,7 +540,8 @@ static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty) * If DMA-ing till the screen target system, the function will also notify * the screen target system that a bounding box of the cliprects has been * updated. - * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ int vmw_kms_stdu_readback(struct vmw_private *dev_priv, @@ -703,7 +708,7 @@ static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) * case the device has already synchronized. * @crtc: If crtc is passed, perform surface dirty on that crtc only. * - * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if * interrupted. */ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, @@ -887,7 +892,7 @@ vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, * backed by a buffer object. The display surface is pinned here, and it'll * be unpinned in .cleanup_fb() * - * Returns 0 on success + * Returns: %0 on success */ static int vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, @@ -1465,6 +1470,8 @@ static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { * This function is called once per CRTC, and allocates one Screen Target * display unit to represent that CRTC. Since the SVGA device does not separate * out encoder and connector, they are represented as part of the STDU as well. + * + * Returns: %0 on success or -errno code on failure */ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) { -- cgit v1.2.3 From 89709105a6091948ffb6ec2427954cbfe45358ce Mon Sep 17 00:00:00 2001 From: Zhipeng Lu Date: Mon, 4 Dec 2023 17:14:16 +0800 Subject: drm/vmwgfx: fix a memleak in vmw_gmrid_man_get_node When ida_alloc_max fails, resources allocated before should be freed, including *res allocated by kmalloc and ttm_resource_init. Fixes: d3bcb4b02fe9 ("drm/vmwgfx: switch the TTM backends to self alloc") Signed-off-by: Zhipeng Lu Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231204091416.3308430-1-alexious@zju.edu.cn --- drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c index ceb4d3d3b965..a0b47c9b33f5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c @@ -64,8 +64,11 @@ static int vmw_gmrid_man_get_node(struct ttm_resource_manager *man, ttm_resource_init(bo, place, *res); id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL); - if (id < 0) + if (id < 0) { + ttm_resource_fini(man, *res); + kfree(*res); return id; + } spin_lock(&gman->lock); -- cgit v1.2.3 From 85110d04688d7a12ff594f1152c0ae85f3b90bbe Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 15 Dec 2023 15:56:38 -0800 Subject: drm/vmwgfx: fix kernel-doc Excess struct member 'base' Fix a new kernel-doc warning reported by kernel test robot: vmwgfx_surface.c:55: warning: Excess struct member 'base' description in 'vmw_user_surface' The other warning is not correct: it is confused by "__counted_by". Kees has made a separate patch for that. In -Wall mode, kernel-doc still reports 20 warnings of this nature: vmwgfx_surface.c:198: warning: No description found for return value of 'vmw_surface_dma_size' but I am not addressing those. Signed-off-by: Randy Dunlap Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312150701.kNI9LuM3-lkp@intel.com/ Cc: Kees Cook Cc: Zack Rusin Cc: VMware Graphics Reviewers Cc: dri-devel@lists.freedesktop.org Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Signed-off-by: Zack Rusin Link: https://patchwork.freedesktop.org/patch/msgid/20231215235638.19189-1-rdunlap@infradead.org --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 680441bb1786..10498725034c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -44,7 +44,6 @@ * struct vmw_user_surface - User-space visible surface resource * * @prime: The TTM prime object. - * @base: The TTM base object handling user-space visibility. * @srf: The surface metadata. * @master: Master of the creating client. Used for security check. */ -- cgit v1.2.3 From 27571c64f1855881753e6f33c3186573afbab7ba Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Sun, 24 Dec 2023 00:25:40 -0500 Subject: drm/vmwgfx: Unmap the surface before resetting it on a plane state Switch to a new plane state requires unreferencing of all held surfaces. In the work required for mob cursors the mapped surfaces started being cached but the variable indicating whether the surface is currently mapped was not being reset. This leads to crashes as the duplicated state, incorrectly, indicates the that surface is mapped even when no surface is present. That's because after unreferencing the surface it's perfectly possible for the plane to be backed by a bo instead of a surface. Reset the surface mapped flag when unreferencing the plane state surface to fix null derefs in cleanup. Fixes crashes in KDE KWin 6.0 on Wayland: Oops: 0000 [#1] PREEMPT SMP PTI CPU: 4 PID: 2533 Comm: kwin_wayland Not tainted 6.7.0-rc3-vmwgfx #2 Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 11/12/2020 RIP: 0010:vmw_du_cursor_plane_cleanup_fb+0x124/0x140 [vmwgfx] Code: 00 00 00 75 3a 48 83 c4 10 5b 5d c3 cc cc cc cc 48 8b b3 a8 00 00 00 48 c7 c7 99 90 43 c0 e8 93 c5 db ca 48 8b 83 a8 00 00 00 <48> 8b 78 28 e8 e3 f> RSP: 0018:ffffb6b98216fa80 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff969d84cdcb00 RCX: 0000000000000027 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff969e75f21600 RBP: ffff969d4143dc50 R08: 0000000000000000 R09: ffffb6b98216f920 R10: 0000000000000003 R11: ffff969e7feb3b10 R12: 0000000000000000 R13: 0000000000000000 R14: 000000000000027b R15: ffff969d49c9fc00 FS: 00007f1e8f1b4180(0000) GS:ffff969e75f00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000028 CR3: 0000000104006004 CR4: 00000000003706f0 Call Trace: ? __die+0x23/0x70 ? page_fault_oops+0x171/0x4e0 ? exc_page_fault+0x7f/0x180 ? asm_exc_page_fault+0x26/0x30 ? vmw_du_cursor_plane_cleanup_fb+0x124/0x140 [vmwgfx] drm_atomic_helper_cleanup_planes+0x9b/0xc0 commit_tail+0xd1/0x130 drm_atomic_helper_commit+0x11a/0x140 drm_atomic_commit+0x97/0xd0 ? __pfx___drm_printfn_info+0x10/0x10 drm_atomic_helper_update_plane+0xf5/0x160 drm_mode_cursor_universal+0x10e/0x270 drm_mode_cursor_common+0x102/0x230 ? __pfx_drm_mode_cursor2_ioctl+0x10/0x10 drm_ioctl_kernel+0xb2/0x110 drm_ioctl+0x26d/0x4b0 ? __pfx_drm_mode_cursor2_ioctl+0x10/0x10 ? __pfx_drm_ioctl+0x10/0x10 vmw_generic_ioctl+0xa4/0x110 [vmwgfx] __x64_sys_ioctl+0x94/0xd0 do_syscall_64+0x61/0xe0 ? __x64_sys_ioctl+0xaf/0xd0 ? syscall_exit_to_user_mode+0x2b/0x40 ? do_syscall_64+0x70/0xe0 ? __x64_sys_ioctl+0xaf/0xd0 ? syscall_exit_to_user_mode+0x2b/0x40 ? do_syscall_64+0x70/0xe0 ? exc_page_fault+0x7f/0x180 entry_SYSCALL_64_after_hwframe+0x6e/0x76 RIP: 0033:0x7f1e93f279ed Code: 04 25 28 00 00 00 48 89 45 c8 31 c0 48 8d 45 10 c7 45 b0 10 00 00 00 48 89 45 b8 48 8d 45 d0 48 89 45 c0 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff f> RSP: 002b:00007ffca0faf600 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 000055db876ed2c0 RCX: 00007f1e93f279ed RDX: 00007ffca0faf6c0 RSI: 00000000c02464bb RDI: 0000000000000015 RBP: 00007ffca0faf650 R08: 000055db87184010 R09: 0000000000000007 R10: 000055db886471a0 R11: 0000000000000246 R12: 00007ffca0faf6c0 R13: 00000000c02464bb R14: 0000000000000015 R15: 00007ffca0faf790 Modules linked in: snd_seq_dummy snd_hrtimer nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_ine> CR2: 0000000000000028 ---[ end trace 0000000000000000 ]--- RIP: 0010:vmw_du_cursor_plane_cleanup_fb+0x124/0x140 [vmwgfx] Code: 00 00 00 75 3a 48 83 c4 10 5b 5d c3 cc cc cc cc 48 8b b3 a8 00 00 00 48 c7 c7 99 90 43 c0 e8 93 c5 db ca 48 8b 83 a8 00 00 00 <48> 8b 78 28 e8 e3 f> RSP: 0018:ffffb6b98216fa80 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff969d84cdcb00 RCX: 0000000000000027 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff969e75f21600 RBP: ffff969d4143dc50 R08: 0000000000000000 R09: ffffb6b98216f920 R10: 0000000000000003 R11: ffff969e7feb3b10 R12: 0000000000000000 R13: 0000000000000000 R14: 000000000000027b R15: ffff969d49c9fc00 FS: 00007f1e8f1b4180(0000) GS:ffff969e75f00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000028 CR3: 0000000104006004 CR4: 00000000003706f0 Signed-off-by: Zack Rusin Fixes: 485d98d472d5 ("drm/vmwgfx: Add support for CursorMob and CursorBypass 4") Reported-by: Stefan Hoffmeister Closes: https://gitlab.freedesktop.org/drm/misc/-/issues/34 Cc: Martin Krastev Cc: Maaz Mombasawala Cc: Ian Forbes Cc: Broadcom internal kernel review list Cc: dri-devel@lists.freedesktop.org Cc: # v5.19+ Acked-by: Javier Martinez Canillas Reviewed-by: Maaz Mombasawala Reviewed-by: Martin Krastev Link: https://patchwork.freedesktop.org/patch/msgid/20231224052540.605040-1-zack.rusin@broadcom.com --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5fd0ccaa0b41..8589a1c3cc36 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -694,6 +694,10 @@ vmw_du_cursor_plane_prepare_fb(struct drm_plane *plane, int ret = 0; if (vps->surf) { + if (vps->surf_mapped) { + vmw_bo_unmap(vps->surf->res.guest_memory_bo); + vps->surf_mapped = false; + } vmw_surface_unreference(&vps->surf); vps->surf = NULL; } -- cgit v1.2.3 From bb056046c2139c72e20a5b6fc39c9caaf9eac2b8 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 3 Jan 2024 19:13:01 +0100 Subject: drm/rockchip: analogix_dp: get encoder port ID from DT The VOP2 driver needs this port ID to properly configure the display data routing. Signed-off-by: Lucas Stach Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20240103181301.3339595-1-l.stach@pengutronix.de --- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index bd08d57486fe..7069a3d4d581 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -343,6 +343,9 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, return ret; } + rockchip_drm_encoder_set_crtc_endpoint_id(&dp->encoder, + dev->of_node, 0, 0); + dp->plat_data.encoder = &dp->encoder.encoder; ret = analogix_dp_bind(dp->adp, drm_dev); -- cgit v1.2.3 From 5f2e93e6719701a91307090f8f7696fd6b3bffdf Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:14 +0100 Subject: drm/rockchip: inno_hdmi: Add variant support In preparation to support RK3128's integration of the controller, this patch adds a simple variant implementation. They mainly differ in the phy configuration required, so those are part of the match_data. The values have been taken from downstream. The pixelclocks in there are meant to be max-inclusive. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-24-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 74 +++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index da77171b2b42..676c1cd73862 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -25,6 +25,17 @@ #include "inno_hdmi.h" +struct inno_hdmi_phy_config { + unsigned long pixelclock; + u8 pre_emphasis; + u8 voltage_level_control; +}; + +struct inno_hdmi_variant { + struct inno_hdmi_phy_config *phy_configs; + struct inno_hdmi_phy_config *default_phy_config; +}; + struct inno_hdmi_i2c { struct i2c_adapter adap; @@ -46,6 +57,8 @@ struct inno_hdmi { struct inno_hdmi_i2c *i2c; struct i2c_adapter *ddc; + + const struct inno_hdmi_variant *variant; }; struct inno_hdmi_connector_state { @@ -112,6 +125,30 @@ static const char coeff_csc[][24] = { }, }; +static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { + { 74250000, 0x3f, 0xbb }, + { 165000000, 0x6f, 0xbb }, + { ~0UL, 0x00, 0x00 } +}; + +static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi, + unsigned long pixelclk) +{ + const struct inno_hdmi_phy_config *phy_configs = + hdmi->variant->phy_configs; + int i; + + for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) { + if (pixelclk <= phy_configs[i].pixelclock) + return i; + } + + DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n", + pixelclk); + + return -EINVAL; +} + static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset) { return readl_relaxed(hdmi->regs + (offset) * 0x04); @@ -163,12 +200,25 @@ static void inno_hdmi_standby(struct inno_hdmi *hdmi) hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); }; -static void inno_hdmi_power_up(struct inno_hdmi *hdmi) +static void inno_hdmi_power_up(struct inno_hdmi *hdmi, + unsigned long mpixelclock) { + struct inno_hdmi_phy_config *phy_config; + int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock); + + if (ret < 0) { + phy_config = hdmi->variant->default_phy_config; + DRM_DEV_ERROR(hdmi->dev, + "Using default phy configuration for TMDS rate %lu", + mpixelclock); + } else { + phy_config = &hdmi->variant->phy_configs[ret]; + } + inno_hdmi_sys_power(hdmi, false); - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis); + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); @@ -405,6 +455,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_display_mode *mode) { struct drm_display_info *display = &hdmi->connector.display_info; + unsigned long mpixelclock = mode->clock * 1000; /* Mute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, @@ -427,13 +478,13 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, * DCLK_LCDC, so we need to init the TMDS rate to mode pixel * clock rate, and reconfigure the DDC clock. */ - inno_hdmi_i2c_init(hdmi, mode->clock * 1000); + inno_hdmi_i2c_init(hdmi, mpixelclock); /* Unmute video and audio output */ hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); - inno_hdmi_power_up(hdmi); + inno_hdmi_power_up(hdmi, mpixelclock); return 0; } @@ -825,6 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct inno_hdmi *hdmi; + const struct inno_hdmi_variant *variant; int irq; int ret; @@ -834,6 +886,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, hdmi->dev = dev; + variant = of_device_get_match_data(hdmi->dev); + if (!variant) + return -EINVAL; + + hdmi->variant = variant; + hdmi->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); @@ -927,8 +985,14 @@ static void inno_hdmi_remove(struct platform_device *pdev) component_del(&pdev->dev, &inno_hdmi_ops); } +static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { + .phy_configs = rk3036_hdmi_phy_configs, + .default_phy_config = &rk3036_hdmi_phy_configs[1], +}; + static const struct of_device_id inno_hdmi_dt_ids[] = { { .compatible = "rockchip,rk3036-inno-hdmi", + .data = &rk3036_inno_hdmi_variant, }, {}, }; -- cgit v1.2.3 From aa54f334c291effe321aa4b9ac0e67a895fd7b58 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:15 +0100 Subject: drm/rockchip: inno_hdmi: Add RK3128 support This variant requires the phy reference clock to be enabled before the DDC block can work and the (initial) DDC bus frequency is calculated based on the rate of this clock. Besides the only difference is phy configuration required to make the driver working for this variant as well. Signed-off-by: Alex Bee Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-25-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 46 ++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 676c1cd73862..5045836993b5 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -50,6 +50,7 @@ struct inno_hdmi { struct device *dev; struct clk *pclk; + struct clk *refclk; void __iomem *regs; struct drm_connector connector; @@ -131,6 +132,12 @@ static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { { ~0UL, 0x00, 0x00 } }; +static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = { + { 74250000, 0x3f, 0xaa }, + { 165000000, 0x5f, 0xaa }, + { ~0UL, 0x00, 0x00 } +}; + static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi, unsigned long pixelclk) { @@ -909,6 +916,20 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, return ret; } + hdmi->refclk = devm_clk_get_optional(hdmi->dev, "ref"); + if (IS_ERR(hdmi->refclk)) { + DRM_DEV_ERROR(hdmi->dev, "Unable to get HDMI reference clock\n"); + ret = PTR_ERR(hdmi->refclk); + goto err_disable_pclk; + } + + ret = clk_prepare_enable(hdmi->refclk); + if (ret) { + DRM_DEV_ERROR(hdmi->dev, + "Cannot enable HDMI reference clock: %d\n", ret); + goto err_disable_pclk; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = irq; @@ -925,12 +946,16 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, } /* - * When IP controller haven't configured to an accurate video - * timing, then the TMDS clock source would be switched to - * PCLK_HDMI, so we need to init the TMDS rate to PCLK rate, - * and reconfigure the DDC clock. + * When the controller isn't configured to an accurate + * video timing and there is no reference clock available, + * then the TMDS clock source would be switched to PCLK_HDMI, + * so we need to init the TMDS rate to PCLK rate, and + * reconfigure the DDC clock. */ - inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); + if (hdmi->refclk) + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->refclk)); + else + inno_hdmi_i2c_init(hdmi, clk_get_rate(hdmi->pclk)); ret = inno_hdmi_register(drm, hdmi); if (ret) @@ -954,6 +979,8 @@ err_cleanup_hdmi: err_put_adapter: i2c_put_adapter(hdmi->ddc); err_disable_clk: + clk_disable_unprepare(hdmi->refclk); +err_disable_pclk: clk_disable_unprepare(hdmi->pclk); return ret; } @@ -967,6 +994,7 @@ static void inno_hdmi_unbind(struct device *dev, struct device *master, hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); i2c_put_adapter(hdmi->ddc); + clk_disable_unprepare(hdmi->refclk); clk_disable_unprepare(hdmi->pclk); } @@ -990,10 +1018,18 @@ static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { .default_phy_config = &rk3036_hdmi_phy_configs[1], }; +static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = { + .phy_configs = rk3128_hdmi_phy_configs, + .default_phy_config = &rk3128_hdmi_phy_configs[1], +}; + static const struct of_device_id inno_hdmi_dt_ids[] = { { .compatible = "rockchip,rk3036-inno-hdmi", .data = &rk3036_inno_hdmi_variant, }, + { .compatible = "rockchip,rk3128-inno-hdmi", + .data = &rk3128_inno_hdmi_variant, + }, {}, }; MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); -- cgit v1.2.3 From 701029621d4141d0c9f8b81a88a37b95ec84ce65 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:16 +0100 Subject: drm/rockchip: inno_hdmi: Add basic mode validation As per TRM this controller supports pixelclocks starting from 25 MHz. The maximum supported pixelclocks are defined by the phy configurations we have. Also it can't support modes that require doubled clocks. If the variant has a phy reference clock we can additionally validate against VESA DMT'srecommendations. Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-26-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 42 ++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 5045836993b5..22697e714b23 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -25,6 +25,8 @@ #include "inno_hdmi.h" +#define INNO_HDMI_MIN_TMDS_CLOCK 25000000U + struct inno_hdmi_phy_config { unsigned long pixelclock; u8 pre_emphasis; @@ -496,6 +498,38 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, return 0; } +static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi, + struct drm_display_mode *mode) +{ + unsigned long mpixelclk, max_tolerance; + long rounded_refclk; + + /* No support for double-clock modes */ + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + return MODE_BAD; + + mpixelclk = mode->clock * 1000; + + if (mpixelclk < INNO_HDMI_MIN_TMDS_CLOCK) + return MODE_CLOCK_LOW; + + if (inno_hdmi_find_phy_config(hdmi, mpixelclk) < 0) + return MODE_CLOCK_HIGH; + + if (hdmi->refclk) { + rounded_refclk = clk_round_rate(hdmi->refclk, mpixelclk); + if (rounded_refclk < 0) + return MODE_BAD; + + /* Vesa DMT standard mentions +/- 0.5% max tolerance */ + max_tolerance = mpixelclk / 200; + if (abs_diff((unsigned long)rounded_refclk, mpixelclk) > max_tolerance) + return MODE_NOCLOCK; + } + + return MODE_OK; +} + static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { @@ -528,6 +562,7 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, struct drm_connector_state *conn_state) { struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); struct drm_display_mode *mode = &crtc_state->adjusted_mode; u8 vic = drm_match_cea_mode(mode); struct inno_hdmi_connector_state *inno_conn_state = @@ -548,7 +583,8 @@ inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, inno_conn_state->rgb_limited_range = drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED; - return 0; + return inno_hdmi_display_mode_valid(hdmi, + &crtc_state->adjusted_mode) == MODE_OK ? 0 : -EINVAL; } static struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { @@ -589,7 +625,9 @@ static enum drm_mode_status inno_hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - return MODE_OK; + struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); + + return inno_hdmi_display_mode_valid(hdmi, mode); } static int -- cgit v1.2.3 From 50a3c772bd927dd409c484832ddd9f6bf00b7389 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 22 Dec 2023 18:42:17 +0100 Subject: drm/rockchip: inno_hdmi: Drop custom fill_modes hook Now that we have proper pixelclock-based mode validation we can drop the custom fill_modes hook. CRTC size validation for the display controller has been added with Commit 8e140cb60270 ("drm/rockchip: vop: limit maximum resolution to hardware capabilities") Signed-off-by: Alex Bee Reviewed-by: Maxime Ripard Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-27-knaerzche@gmail.com --- drivers/gpu/drm/rockchip/inno_hdmi.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/inno_hdmi.c b/drivers/gpu/drm/rockchip/inno_hdmi.c index 22697e714b23..925320fef0a8 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi.c @@ -630,13 +630,6 @@ inno_hdmi_connector_mode_valid(struct drm_connector *connector, return inno_hdmi_display_mode_valid(hdmi, mode); } -static int -inno_hdmi_probe_single_connector_modes(struct drm_connector *connector, - uint32_t maxX, uint32_t maxY) -{ - return drm_helper_probe_single_connector_modes(connector, 1920, 1080); -} - static void inno_hdmi_connector_destroy(struct drm_connector *connector) { drm_connector_unregister(connector); @@ -695,7 +688,7 @@ inno_hdmi_connector_duplicate_state(struct drm_connector *connector) } static const struct drm_connector_funcs inno_hdmi_connector_funcs = { - .fill_modes = inno_hdmi_probe_single_connector_modes, + .fill_modes = drm_helper_probe_single_connector_modes, .detect = inno_hdmi_connector_detect, .destroy = inno_hdmi_connector_destroy, .reset = inno_hdmi_connector_reset, -- cgit v1.2.3 From 79b09453c4e369ca81cfb670d0136d089e3b92f0 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 20 Nov 2023 13:29:48 +0100 Subject: drm/rockchip: lvds: do not overwrite error code ret variable stores the return value of drm_of_find_panel_or_bridge which can return error codes different from EPROBE_DEFER. Therefore, let's just return that error code instead of forcing it to EPROBE_DEFER. Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS") Cc: Quentin Schulz Signed-off-by: Quentin Schulz Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231120-rk-lvds-defer-msg-v2-1-9c59a5779cf9@theobroma-systems.com --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 59341654ec32..6ecb6b8a1dcd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -577,7 +577,6 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, goto err_put_port; } else if (ret) { DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); - ret = -EPROBE_DEFER; goto err_put_port; } if (lvds->panel) -- cgit v1.2.3 From 52d11c863ac92e36a0365249f7f6d27ac48c78bc Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 20 Nov 2023 13:29:49 +0100 Subject: drm/rockchip: lvds: do not print scary message when probing defer This scary message can misled the user into thinking something bad has happened and needs to be fixed, however it could simply be part of a normal boot process where EPROBE_DEFER is taken into account. Therefore, let's use dev_err_probe so that this message doesn't get shown (by default) when the return code is EPROBE_DEFER. Fixes: 34cc0aa25456 ("drm/rockchip: Add support for Rockchip Soc LVDS") Cc: Quentin Schulz Signed-off-by: Quentin Schulz Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231120-rk-lvds-defer-msg-v2-2-9c59a5779cf9@theobroma-systems.com --- drivers/gpu/drm/rockchip/rockchip_lvds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 6ecb6b8a1dcd..77b76cff1adb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -576,7 +576,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master, ret = -EINVAL; goto err_put_port; } else if (ret) { - DRM_DEV_ERROR(dev, "failed to find panel and bridge node\n"); + dev_err_probe(dev, ret, "failed to find panel and bridge node\n"); goto err_put_port; } if (lvds->panel) -- cgit v1.2.3 From 65afd91e8d70e10c7f99126d61bf0045ef52d271 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Jan 2024 13:41:57 +0100 Subject: drm/panel: ltk050h3146w: only print message when GPIO getting is not EPROBE_DEFER devm_gpiod_get_optional may return EPROBE_DEFER in case the GPIO controller isn't yet probed when the panel driver is being probed. In that case, a spurious and confusing error message about not being able to get the reset GPIO is printed even though later on the device actually manages to get probed. Use dev_err_probe instead so that the message is only printed when it truly matters. Cc: Quentin Schulz Signed-off-by: Quentin Schulz Reviewed-by: Christophe JAILLET Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20240104-ltk-dev_err_probe-v1-1-8ef3c0b585d8@theobroma-systems.com --- drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 6e3670508e3a..69e4b4c97558 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -646,10 +646,8 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) return -EINVAL; ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ctx->reset_gpio)) { - dev_err(dev, "cannot get reset gpio\n"); - return PTR_ERR(ctx->reset_gpio); - } + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n"); ctx->vci = devm_regulator_get(dev, "vci"); if (IS_ERR(ctx->vci)) { -- cgit v1.2.3 From 056a9965e58e47928e8afd4dc017221f9221b3d3 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 4 Jan 2024 13:41:58 +0100 Subject: drm/panel: ltk050h3146w: use dev_err_probe wherever possible This is only a cosmetic change. This replaces a hand-crafted EPROBE_DEFER handling for deciding to print an error message with dev_err_probe. A side-effect is that dev_err_probe also adds a debug message when it's not EPROBE_DEFER, but this is seen as an improvement. Cc: Quentin Schulz Signed-off-by: Quentin Schulz Reviewed-by: Christophe JAILLET Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20240104-ltk-dev_err_probe-v1-2-8ef3c0b585d8@theobroma-systems.com --- drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index 69e4b4c97558..32ebedadbcdc 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -650,20 +650,13 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n"); ctx->vci = devm_regulator_get(dev, "vci"); - if (IS_ERR(ctx->vci)) { - ret = PTR_ERR(ctx->vci); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request vci regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->vci)) + return dev_err_probe(dev, PTR_ERR(ctx->vci), "Failed to request vci regulator\n"); ctx->iovcc = devm_regulator_get(dev, "iovcc"); - if (IS_ERR(ctx->iovcc)) { - ret = PTR_ERR(ctx->iovcc); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request iovcc regulator: %d\n", ret); - return ret; - } + if (IS_ERR(ctx->iovcc)) + return dev_err_probe(dev, PTR_ERR(ctx->iovcc), + "Failed to request iovcc regulator\n"); mipi_dsi_set_drvdata(dsi, ctx); -- cgit v1.2.3 From e130ba220da559a8eac60eb5ff60b0774ea17009 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 4 Jan 2024 23:10:28 +0200 Subject: drm/edid: prefer forward declarations over includes in drm_edid.h There's no need to include either linux/hdmi.h or drm/drm_mode.h. They can be removed by using forward declarations. While at it, group the forward declarations together, and remove the unnecessary ones. Signed-off-by: Jani Nikula Reviewed-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20240104211028.1129606-1-jani.nikula@intel.com --- include/drm/drm_edid.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 54cc6f04a708..86c1812a8034 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -24,11 +24,14 @@ #define __DRM_EDID_H__ #include -#include -#include +enum hdmi_quantization_range; +struct drm_connector; struct drm_device; +struct drm_display_mode; struct drm_edid; +struct hdmi_avi_infoframe; +struct hdmi_vendor_infoframe; struct i2c_adapter; #define EDID_LENGTH 128 @@ -319,11 +322,6 @@ struct cea_sad { u8 byte2; /* meaning depends on format */ }; -struct drm_encoder; -struct drm_connector; -struct drm_connector_state; -struct drm_display_mode; - int drm_edid_to_sad(const struct edid *edid, struct cea_sad **sads); int drm_edid_to_speaker_allocation(const struct edid *edid, u8 **sadb); int drm_av_sync_delay(struct drm_connector *connector, -- cgit v1.2.3 From 5343f29b3dc534be01b45cd3a3e43572996f96f8 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 2 Jan 2024 13:21:58 +0100 Subject: drm: Move drm_set_preferred_mode() helper from drm_edid to drm_modes The helper is generic, it doesn't use the opaque EDID type struct drm_edid and is also used by drivers that only support non-probeable displays such as fixed panels. These drivers add a list of modes using drm_mode_probed_add() and then set a preferred mode using the drm_set_preferred_mode() helper. It seems more logical to have the helper definition in drm_modes.o instead of drm_edid.o, since the former contains modes helper while the latter has helpers to manage the EDID information. Since both drm_edid.o and drm_modes.o object files are built-in the drm.o object, there are no functional changes. But besides being a more logical place for this helper, it could also allow to eventually make drm_edid.o optional and not included in drm.o if only fixed panels must be supported in a given system. Signed-off-by: Javier Martinez Canillas Reviewed-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20240102122208.3103597-1-javierm@redhat.com --- drivers/gpu/drm/drm_edid.c | 22 ---------------------- drivers/gpu/drm/drm_modes.c | 22 ++++++++++++++++++++++ include/drm/drm_edid.h | 2 -- include/drm/drm_modes.h | 2 ++ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index cb4031d5dcbb..e677dc8eb7a9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -6989,28 +6989,6 @@ int drm_add_modes_noedid(struct drm_connector *connector, } EXPORT_SYMBOL(drm_add_modes_noedid); -/** - * drm_set_preferred_mode - Sets the preferred mode of a connector - * @connector: connector whose mode list should be processed - * @hpref: horizontal resolution of preferred mode - * @vpref: vertical resolution of preferred mode - * - * Marks a mode as preferred if it matches the resolution specified by @hpref - * and @vpref. - */ -void drm_set_preferred_mode(struct drm_connector *connector, - int hpref, int vpref) -{ - struct drm_display_mode *mode; - - list_for_each_entry(mode, &connector->probed_modes, head) { - if (mode->hdisplay == hpref && - mode->vdisplay == vpref) - mode->type |= DRM_MODE_TYPE_PREFERRED; - } -} -EXPORT_SYMBOL(drm_set_preferred_mode); - static bool is_hdmi2_sink(const struct drm_connector *connector) { /* diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ac9a406250c5..45238ec5df1b 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2754,3 +2754,25 @@ bool drm_mode_is_420(const struct drm_display_info *display, drm_mode_is_420_also(display, mode); } EXPORT_SYMBOL(drm_mode_is_420); + +/** + * drm_set_preferred_mode - Sets the preferred mode of a connector + * @connector: connector whose mode list should be processed + * @hpref: horizontal resolution of preferred mode + * @vpref: vertical resolution of preferred mode + * + * Marks a mode as preferred if it matches the resolution specified by @hpref + * and @vpref. + */ +void drm_set_preferred_mode(struct drm_connector *connector, + int hpref, int vpref) +{ + struct drm_display_mode *mode; + + list_for_each_entry(mode, &connector->probed_modes, head) { + if (mode->hdisplay == hpref && + mode->vdisplay == vpref) + mode->type |= DRM_MODE_TYPE_PREFERRED; + } +} +EXPORT_SYMBOL(drm_set_preferred_mode); diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 86c1812a8034..7923bc00dc7a 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -424,8 +424,6 @@ enum hdmi_quantization_range drm_default_rgb_quant_range(const struct drm_display_mode *mode); int drm_add_modes_noedid(struct drm_connector *connector, int hdisplay, int vdisplay); -void drm_set_preferred_mode(struct drm_connector *connector, - int hpref, int vpref); int drm_edid_header_is_valid(const void *edid); bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index c613f0abe9dc..b9bb92e4b029 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -467,6 +467,8 @@ bool drm_mode_is_420_also(const struct drm_display_info *display, const struct drm_display_mode *mode); bool drm_mode_is_420(const struct drm_display_info *display, const struct drm_display_mode *mode); +void drm_set_preferred_mode(struct drm_connector *connector, + int hpref, int vpref); struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev, enum drm_connector_tv_mode mode, -- cgit v1.2.3 From 3bb45618061c0e1838e99ad246d7342727396451 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 26 Dec 2023 16:30:25 +0100 Subject: drm/sched: One function call less in drm_sched_init() after error detection The kfree() function was called in one case by the drm_sched_init() function during error handling even if the passed data structure member contained a null pointer. This issue was detected by using the Coccinelle software. Thus adjust a jump target. Signed-off-by: Markus Elfring Link: https://patchwork.freedesktop.org/patch/msgid/85066512-983d-480c-a44d-32405ab1b80e@web.de Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index 550492a7a031..b99d4e9ff109 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1289,7 +1289,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq), GFP_KERNEL | __GFP_ZERO); if (!sched->sched_rq) - goto Out_free; + goto Out_check_own; sched->num_rqs = num_rqs; for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) { sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL); @@ -1314,9 +1314,10 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, Out_unroll: for (--i ; i >= DRM_SCHED_PRIORITY_KERNEL; i--) kfree(sched->sched_rq[i]); -Out_free: + kfree(sched->sched_rq); sched->sched_rq = NULL; +Out_check_own: if (sched->own_submit_wq) destroy_workqueue(sched->submit_wq); drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__); -- cgit v1.2.3 From 26a4591b31916e1c53a7c64fa3ba3fc7cc5d549f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 26 Dec 2023 16:37:37 +0100 Subject: drm/sched: Return an error code only as a constant in drm_sched_init() Return an error code without storing it in an intermediate variable. Signed-off-by: Markus Elfring Link: https://patchwork.freedesktop.org/patch/msgid/85f8004e-f0c9-42d9-8c59-30f1b4e0b89e@web.de Reviewed-by: Luben Tuikov Signed-off-by: Luben Tuikov --- drivers/gpu/drm/scheduler/sched_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index b99d4e9ff109..1abbcdf38430 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -1249,7 +1249,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, long timeout, struct workqueue_struct *timeout_wq, atomic_t *score, const char *name, struct device *dev) { - int i, ret; + int i; sched->ops = ops; sched->credit_limit = credit_limit; @@ -1285,7 +1285,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched, sched->own_submit_wq = true; } - ret = -ENOMEM; + sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq), GFP_KERNEL | __GFP_ZERO); if (!sched->sched_rq) @@ -1321,7 +1321,7 @@ Out_check_own: if (sched->own_submit_wq) destroy_workqueue(sched->submit_wq); drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__); - return ret; + return -ENOMEM; } EXPORT_SYMBOL(drm_sched_init); -- cgit v1.2.3