From fef6d35d82c22d7451bdaccc346f993c6d922cd9 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Thu, 16 Dec 2021 17:55:36 +0800 Subject: drm/tilcdc: add const to of_device_id struct of_device_id should normally be const. Signed-off-by: Xiang wangx Reviewed-by: Jyri Sarha Signed-off-by: Jyri Sarha Link: https://patchwork.freedesktop.org/patch/msgid/20211216095536.58577-1-wangxiang@cdjrlc.com --- drivers/gpu/drm/tilcdc/tilcdc_drv.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 3ddb7c710a3d..cc567c87057d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -60,8 +60,6 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) list_del(&mod->list); } -static struct of_device_id tilcdc_of_match[]; - static int tilcdc_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { @@ -587,7 +585,7 @@ static int tilcdc_pdev_remove(struct platform_device *pdev) return 0; } -static struct of_device_id tilcdc_of_match[] = { +static const struct of_device_id tilcdc_of_match[] = { { .compatible = "ti,am33xx-tilcdc", }, { .compatible = "ti,da850-tilcdc", }, { }, -- cgit v1.2.3 From ef2f5d0aa1214940f123721794f244f7287633ba Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Thu, 2 Dec 2021 19:39:46 +0100 Subject: drm/ingenic: prepare ingenic drm for later addition of JZ4780 This changes the way the regmap is allocated to prepare for the later addition of the JZ4780 which has more registers and bits than the others. Therefore we make the regmap as big as the reg property in the device tree tells. Suggested-by: Paul Cercueil Signed-off-by: H. Nikolaus Schaller Signed-off-by: Paul Cercueil Link: https://patchwork.freedesktop.org/patch/msgid/ee65e70e91268b3963f8a6581c8aa6c3b643c53e.1638470392.git.hns@goldelico.com --- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index b4943a56be09..9c60fc4605e4 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -173,7 +173,6 @@ static const struct regmap_config ingenic_drm_regmap_config = { .val_bits = 32, .reg_stride = 4, - .max_register = JZ_REG_LCD_SIZE1, .writeable_reg = ingenic_drm_writeable_reg, }; @@ -1011,6 +1010,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) struct ingenic_drm_bridge *ib; struct drm_device *drm; void __iomem *base; + struct resource *res; + struct regmap_config regmap_config; long parent_rate; unsigned int i, clone_mask = 0; int ret, irq; @@ -1056,14 +1057,16 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; - base = devm_platform_ioremap_resource(pdev, 0); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) { dev_err(dev, "Failed to get memory resource\n"); return PTR_ERR(base); } + regmap_config = ingenic_drm_regmap_config; + regmap_config.max_register = res->end - res->start; priv->map = devm_regmap_init_mmio(dev, base, - &ingenic_drm_regmap_config); + ®map_config); if (IS_ERR(priv->map)) { dev_err(dev, "Failed to create regmap\n"); return PTR_ERR(priv->map); -- cgit v1.2.3 From b807fd2c43fe008eb6f4083e196ea38dadad9680 Mon Sep 17 00:00:00 2001 From: Paul Boddie Date: Thu, 2 Dec 2021 19:39:47 +0100 Subject: drm/ingenic: Add support for JZ4780 and HDMI output Add support for the LCD controller present on JZ4780 SoCs. This SoC uses 8-byte descriptors which extend the current 4-byte descriptors used for other Ingenic SoCs. Tested on MIPS Creator CI20 board. Signed-off-by: Paul Boddie Signed-off-by: Ezequiel Garcia Signed-off-by: H. Nikolaus Schaller Signed-off-by: Paul Cercueil Link: https://patchwork.freedesktop.org/patch/msgid/caf9e56b64b0717563e03172b30fa03736e92e15.1638470392.git.hns@goldelico.com --- drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 53 +++++++++++++++++++++++++++++++ drivers/gpu/drm/ingenic/ingenic-drm.h | 38 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index 9c60fc4605e4..542c4af70661 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -6,6 +6,7 @@ #include "ingenic-drm.h" +#include #include #include #include @@ -49,6 +50,11 @@ struct ingenic_dma_hwdesc { u32 addr; u32 id; u32 cmd; + /* extended hw descriptor for jz4780 */ + u32 offsize; + u32 pagewidth; + u32 cpos; + u32 dessize; } __aligned(16); struct ingenic_dma_hwdescs { @@ -60,6 +66,7 @@ struct jz_soc_info { bool needs_dev_clk; bool has_osd; bool map_noncoherent; + bool use_extended_hwdesc; unsigned int max_width, max_height; const u32 *formats_f0, *formats_f1; unsigned int num_formats_f0, num_formats_f1; @@ -446,6 +453,9 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0; + if (plane == &priv->f0) + return -EINVAL; + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); if (WARN_ON(!crtc_state)) @@ -662,6 +672,33 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); hwdesc->next = dma_hwdesc_addr(priv, next_id); + if (priv->soc_info->use_extended_hwdesc) { + hwdesc->cmd |= JZ_LCD_CMD_FRM_ENABLE; + + /* Extended 8-byte descriptor */ + hwdesc->cpos = 0; + hwdesc->offsize = 0; + hwdesc->pagewidth = 0; + + switch (newstate->fb->format->format) { + case DRM_FORMAT_XRGB1555: + hwdesc->cpos |= JZ_LCD_CPOS_RGB555; + fallthrough; + case DRM_FORMAT_RGB565: + hwdesc->cpos |= JZ_LCD_CPOS_BPP_15_16; + break; + case DRM_FORMAT_XRGB8888: + hwdesc->cpos |= JZ_LCD_CPOS_BPP_18_24; + break; + } + hwdesc->cpos |= (JZ_LCD_CPOS_COEFFICIENT_1 << + JZ_LCD_CPOS_COEFFICIENT_OFFSET); + hwdesc->dessize = + (0xff << JZ_LCD_DESSIZE_ALPHA_OFFSET) | + FIELD_PREP(JZ_LCD_DESSIZE_HEIGHT_MASK, height - 1) | + FIELD_PREP(JZ_LCD_DESSIZE_WIDTH_MASK, width - 1); + } + if (drm_atomic_crtc_needs_modeset(crtc_state)) { fourcc = newstate->fb->format->format; @@ -693,6 +730,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, | JZ_LCD_CFG_SPL_DISABLE | JZ_LCD_CFG_REV_DISABLE; } + if (priv->soc_info->use_extended_hwdesc) + cfg |= JZ_LCD_CFG_DESCRIPTOR_8; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; if (mode->flags & DRM_MODE_FLAG_NVSYNC) @@ -1468,10 +1508,23 @@ static const struct jz_soc_info jz4770_soc_info = { .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), }; +static const struct jz_soc_info jz4780_soc_info = { + .needs_dev_clk = true, + .has_osd = true, + .use_extended_hwdesc = true, + .max_width = 4096, + .max_height = 2048, + .formats_f1 = jz4770_formats_f1, + .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1), + .formats_f0 = jz4770_formats_f0, + .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), +}; + static const struct of_device_id ingenic_drm_of_match[] = { { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, + { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.h b/drivers/gpu/drm/ingenic/ingenic-drm.h index 22654ac1dde1..cb1d09b62588 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm.h +++ b/drivers/gpu/drm/ingenic/ingenic-drm.h @@ -44,8 +44,11 @@ #define JZ_REG_LCD_XYP1 0x124 #define JZ_REG_LCD_SIZE0 0x128 #define JZ_REG_LCD_SIZE1 0x12c +#define JZ_REG_LCD_PCFG 0x2c0 #define JZ_LCD_CFG_SLCD BIT(31) +#define JZ_LCD_CFG_DESCRIPTOR_8 BIT(28) +#define JZ_LCD_CFG_RECOVER_FIFO_UNDERRUN BIT(25) #define JZ_LCD_CFG_PS_DISABLE BIT(23) #define JZ_LCD_CFG_CLS_DISABLE BIT(22) #define JZ_LCD_CFG_SPL_DISABLE BIT(21) @@ -63,6 +66,7 @@ #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) #define JZ_LCD_CFG_18_BIT BIT(7) +#define JZ_LCD_CFG_24_BIT BIT(6) #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) #define JZ_LCD_CFG_MODE_GENERIC_16BIT 0 @@ -132,6 +136,7 @@ #define JZ_LCD_CMD_SOF_IRQ BIT(31) #define JZ_LCD_CMD_EOF_IRQ BIT(30) #define JZ_LCD_CMD_ENABLE_PAL BIT(28) +#define JZ_LCD_CMD_FRM_ENABLE BIT(26) #define JZ_LCD_SYNC_MASK 0x3ff @@ -153,6 +158,7 @@ #define JZ_LCD_RGBC_EVEN_BGR (0x5 << 0) #define JZ_LCD_OSDC_OSDEN BIT(0) +#define JZ_LCD_OSDC_ALPHAEN BIT(2) #define JZ_LCD_OSDC_F0EN BIT(3) #define JZ_LCD_OSDC_F1EN BIT(4) @@ -176,6 +182,38 @@ #define JZ_LCD_SIZE01_WIDTH_LSB 0 #define JZ_LCD_SIZE01_HEIGHT_LSB 16 +#define JZ_LCD_DESSIZE_ALPHA_OFFSET 24 +#define JZ_LCD_DESSIZE_HEIGHT_MASK GENMASK(23, 12) +#define JZ_LCD_DESSIZE_WIDTH_MASK GENMASK(11, 0) + +#define JZ_LCD_CPOS_BPP_15_16 (4 << 27) +#define JZ_LCD_CPOS_BPP_18_24 (5 << 27) +#define JZ_LCD_CPOS_BPP_30 (7 << 27) +#define JZ_LCD_CPOS_RGB555 BIT(30) +#define JZ_LCD_CPOS_PREMULTIPLY_LCD BIT(26) +#define JZ_LCD_CPOS_COEFFICIENT_OFFSET 24 +#define JZ_LCD_CPOS_COEFFICIENT_0 0 +#define JZ_LCD_CPOS_COEFFICIENT_1 1 +#define JZ_LCD_CPOS_COEFFICIENT_ALPHA1 2 +#define JZ_LCD_CPOS_COEFFICIENT_1_ALPHA1 3 + +#define JZ_LCD_RGBC_RGB_PADDING BIT(15) +#define JZ_LCD_RGBC_RGB_PADDING_FIRST BIT(14) +#define JZ_LCD_RGBC_422 BIT(8) +#define JZ_LCD_RGBC_RGB_FORMAT_ENABLE BIT(7) + +#define JZ_LCD_PCFG_PRI_MODE BIT(31) +#define JZ_LCD_PCFG_HP_BST_4 (0 << 28) +#define JZ_LCD_PCFG_HP_BST_8 (1 << 28) +#define JZ_LCD_PCFG_HP_BST_16 (2 << 28) +#define JZ_LCD_PCFG_HP_BST_32 (3 << 28) +#define JZ_LCD_PCFG_HP_BST_64 (4 << 28) +#define JZ_LCD_PCFG_HP_BST_16_CONT (5 << 28) +#define JZ_LCD_PCFG_HP_BST_DISABLE (7 << 28) +#define JZ_LCD_PCFG_THRESHOLD2_OFFSET 18 +#define JZ_LCD_PCFG_THRESHOLD1_OFFSET 9 +#define JZ_LCD_PCFG_THRESHOLD0_OFFSET 0 + struct device; struct drm_plane; struct drm_plane_state; -- cgit v1.2.3 From 72345114c96b8211ec693b1ce59f95a83a613f1d Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Wed, 15 Dec 2021 13:41:45 -0500 Subject: drm/vmwgfx: Fix a size_t/long int format specifier mismatch On i386 size_t is of course 32bits and using long int throws warnings, trivially fix it by using the dedicated size_t format. This is enough to fix the following warning found by the kernel test robot: drivers/gpu/drm/vmwgfx/vmwgfx_gem.c: In function 'vmw_bo_print_info': >> drivers/gpu/drm/vmwgfx/vmwgfx_gem.c:230:33: warning: format '%ld' expects argument of type 'long int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Wformat=] 230 | seq_printf(m, "\t\t0x%08x: %12ld bytes %s, type = %s", | ~~~~^ | | | long int | %12d 231 | id, bo->base.base.size, placement, type); | ~~~~~~~~~~~~~~~~~~ | | Reported-by: kernel test robot Signed-off-by: Zack Rusin Fixes: 8afa13a0583f ("drm/vmwgfx: Implement DRIVER_GEM") Reviewed-by: Martin Krastev Reviewed-by: Maaz Mombasawala Link: https://patchwork.freedesktop.org/patch/msgid/20211215184147.3688785-1-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c index c016c434b6cb..ce609e7d758f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c @@ -227,7 +227,7 @@ static void vmw_bo_print_info(int id, struct vmw_buffer_object *bo, struct seq_f break; } - seq_printf(m, "\t\t0x%08x: %12ld bytes %s, type = %s", + seq_printf(m, "\t\t0x%08x: %12zu bytes %s, type = %s", id, bo->base.base.size, placement, type); seq_printf(m, ", priority = %u, pin_count = %u, GEM refs = %d, TTM refs = %d", bo->base.priority, -- cgit v1.2.3 From 49d535d64d52945e2c874f380705675e20a02b6a Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Wed, 15 Dec 2021 13:41:46 -0500 Subject: drm/vmwgfx: Remove explicit transparent hugepages support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Old versions of the svga device used to export virtual vram, handling of which was optimized on top of transparent hugepages support. Only very old devices (OpenGL 2.1 support and earlier) used this code and at this point performance differences are negligible. Because the code requires very old hardware versions to run it has been largely untested and unused for a long time. Furthermore removal of the ttm hugepages support in: commit 0d979509539e ("drm/ttm: remove ttm_bo_vm_insert_huge()") broke the coherency mode in vmwgfx when running with hugepages. Fixes: 0d979509539e ("drm/ttm: remove ttm_bo_vm_insert_huge()") Signed-off-by: Zack Rusin Cc: Jason Gunthorpe Cc: Thomas Hellström Cc: Christian König Cc: Daniel Vetter Reviewed-by: Martin Krastev Reviewed-by: Maaz Mombasawala Link: https://patchwork.freedesktop.org/patch/msgid/20211215184147.3688785-2-zack@kde.org --- drivers/gpu/drm/vmwgfx/Makefile | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 8 -- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 - drivers/gpu/drm/vmwgfx/vmwgfx_thp.c | 184 ------------------------------------ 4 files changed, 198 deletions(-) delete mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_thp.c diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index e9d13f155d8c..eee73b9aa404 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -13,6 +13,5 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d vmwgfx_gem.o vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o -vmwgfx-$(CONFIG_TRANSPARENT_HUGEPAGE) += vmwgfx_thp.o obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 2d59bdad0373..fe36efdb7ff5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -701,23 +701,15 @@ static int vmw_dma_masks(struct vmw_private *dev_priv) static int vmw_vram_manager_init(struct vmw_private *dev_priv) { int ret; -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - ret = vmw_thp_init(dev_priv); -#else ret = ttm_range_man_init(&dev_priv->bdev, TTM_PL_VRAM, false, dev_priv->vram_size >> PAGE_SHIFT); -#endif ttm_resource_manager_set_used(ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM), false); return ret; } static void vmw_vram_manager_fini(struct vmw_private *dev_priv) { -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - vmw_thp_fini(dev_priv); -#else ttm_range_man_fini(&dev_priv->bdev, TTM_PL_VRAM); -#endif } static int vmw_setup_pci_resources(struct vmw_private *dev, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 4ec2b99351cf..e2baca9a55f8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1564,11 +1564,6 @@ void vmw_bo_dirty_unmap(struct vmw_buffer_object *vbo, vm_fault_t vmw_bo_vm_fault(struct vm_fault *vmf); vm_fault_t vmw_bo_vm_mkwrite(struct vm_fault *vmf); -/* Transparent hugepage support - vmwgfx_thp.c */ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern int vmw_thp_init(struct vmw_private *dev_priv); -void vmw_thp_fini(struct vmw_private *dev_priv); -#endif /** * VMW_DEBUG_KMS - Debug output for kernel mode-setting diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c b/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c deleted file mode 100644 index 2a3d3468e4e0..000000000000 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_thp.c +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* - * Huge page-table-entry support for IO memory. - * - * Copyright (C) 2007-2019 Vmware, Inc. All rights reservedd. - */ -#include "vmwgfx_drv.h" -#include -#include -#include - -/** - * struct vmw_thp_manager - Range manager implementing huge page alignment - * - * @manager: TTM resource manager. - * @mm: The underlying range manager. Protected by @lock. - * @lock: Manager lock. - */ -struct vmw_thp_manager { - struct ttm_resource_manager manager; - struct drm_mm mm; - spinlock_t lock; -}; - -static struct vmw_thp_manager *to_thp_manager(struct ttm_resource_manager *man) -{ - return container_of(man, struct vmw_thp_manager, manager); -} - -static const struct ttm_resource_manager_func vmw_thp_func; - -static int vmw_thp_insert_aligned(struct ttm_buffer_object *bo, - struct drm_mm *mm, struct drm_mm_node *node, - unsigned long align_pages, - const struct ttm_place *place, - struct ttm_resource *mem, - unsigned long lpfn, - enum drm_mm_insert_mode mode) -{ - if (align_pages >= bo->page_alignment && - (!bo->page_alignment || align_pages % bo->page_alignment == 0)) { - return drm_mm_insert_node_in_range(mm, node, - mem->num_pages, - align_pages, 0, - place->fpfn, lpfn, mode); - } - - return -ENOSPC; -} - -static int vmw_thp_get_node(struct ttm_resource_manager *man, - struct ttm_buffer_object *bo, - const struct ttm_place *place, - struct ttm_resource **res) -{ - struct vmw_thp_manager *rman = to_thp_manager(man); - struct drm_mm *mm = &rman->mm; - struct ttm_range_mgr_node *node; - unsigned long align_pages; - unsigned long lpfn; - enum drm_mm_insert_mode mode = DRM_MM_INSERT_BEST; - int ret; - - node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL); - if (!node) - return -ENOMEM; - - ttm_resource_init(bo, place, &node->base); - - lpfn = place->lpfn; - if (!lpfn) - lpfn = man->size; - - mode = DRM_MM_INSERT_BEST; - if (place->flags & TTM_PL_FLAG_TOPDOWN) - mode = DRM_MM_INSERT_HIGH; - - spin_lock(&rman->lock); - if (IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)) { - align_pages = (HPAGE_PUD_SIZE >> PAGE_SHIFT); - if (node->base.num_pages >= align_pages) { - ret = vmw_thp_insert_aligned(bo, mm, &node->mm_nodes[0], - align_pages, place, - &node->base, lpfn, mode); - if (!ret) - goto found_unlock; - } - } - - align_pages = (HPAGE_PMD_SIZE >> PAGE_SHIFT); - if (node->base.num_pages >= align_pages) { - ret = vmw_thp_insert_aligned(bo, mm, &node->mm_nodes[0], - align_pages, place, &node->base, - lpfn, mode); - if (!ret) - goto found_unlock; - } - - ret = drm_mm_insert_node_in_range(mm, &node->mm_nodes[0], - node->base.num_pages, - bo->page_alignment, 0, - place->fpfn, lpfn, mode); -found_unlock: - spin_unlock(&rman->lock); - - if (unlikely(ret)) { - kfree(node); - } else { - node->base.start = node->mm_nodes[0].start; - *res = &node->base; - } - - return ret; -} - -static void vmw_thp_put_node(struct ttm_resource_manager *man, - struct ttm_resource *res) -{ - struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res); - struct vmw_thp_manager *rman = to_thp_manager(man); - - spin_lock(&rman->lock); - drm_mm_remove_node(&node->mm_nodes[0]); - spin_unlock(&rman->lock); - - kfree(node); -} - -int vmw_thp_init(struct vmw_private *dev_priv) -{ - struct vmw_thp_manager *rman; - - rman = kzalloc(sizeof(*rman), GFP_KERNEL); - if (!rman) - return -ENOMEM; - - ttm_resource_manager_init(&rman->manager, - dev_priv->vram_size >> PAGE_SHIFT); - - rman->manager.func = &vmw_thp_func; - drm_mm_init(&rman->mm, 0, rman->manager.size); - spin_lock_init(&rman->lock); - - ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, &rman->manager); - ttm_resource_manager_set_used(&rman->manager, true); - return 0; -} - -void vmw_thp_fini(struct vmw_private *dev_priv) -{ - struct ttm_resource_manager *man = ttm_manager_type(&dev_priv->bdev, TTM_PL_VRAM); - struct vmw_thp_manager *rman = to_thp_manager(man); - struct drm_mm *mm = &rman->mm; - int ret; - - ttm_resource_manager_set_used(man, false); - - ret = ttm_resource_manager_evict_all(&dev_priv->bdev, man); - if (ret) - return; - spin_lock(&rman->lock); - drm_mm_clean(mm); - drm_mm_takedown(mm); - spin_unlock(&rman->lock); - ttm_resource_manager_cleanup(man); - ttm_set_driver_manager(&dev_priv->bdev, TTM_PL_VRAM, NULL); - kfree(rman); -} - -static void vmw_thp_debug(struct ttm_resource_manager *man, - struct drm_printer *printer) -{ - struct vmw_thp_manager *rman = to_thp_manager(man); - - spin_lock(&rman->lock); - drm_mm_print(&rman->mm, printer); - spin_unlock(&rman->lock); -} - -static const struct ttm_resource_manager_func vmw_thp_func = { - .alloc = vmw_thp_get_node, - .free = vmw_thp_put_node, - .debug = vmw_thp_debug -}; -- cgit v1.2.3 From 11343099d5ae6c7411da1425b6b162c89fb5bf10 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Wed, 15 Dec 2021 13:41:47 -0500 Subject: drm/vmwgfx: Remove unused compile options Before the driver had screen targets support we had to disable explicit bringup of its infrastructure because it was breaking screen objects support. Since the implementation of screen targets landed there hasn't been a reason to explicitly disable it and the options were never used. Remove of all that unused code. Signed-off-by: Zack Rusin Fixes: d80efd5cb3de ("drm/vmwgfx: Initial DX support") Reviewed-by: Martin Krastev Link: https://patchwork.freedesktop.org/patch/msgid/20211215184147.3688785-3-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 3 --- drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 12 +++--------- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 4 ++-- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index e2baca9a55f8..d6b66636a19b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -59,11 +59,8 @@ #define VMWGFX_DRIVER_MINOR 20 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) -#define VMWGFX_MAX_RELOCATIONS 2048 -#define VMWGFX_MAX_VALIDATIONS 2048 #define VMWGFX_MAX_DISPLAYS 16 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768 -#define VMWGFX_ENABLE_SCREEN_TARGET_OTABLE 1 #define VMWGFX_PCI_ID_SVGA2 0x0405 #define VMWGFX_PCI_ID_SVGA3 0x0406 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index 2d91a44a3b22..0a8cc28d6606 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /************************************************************************** * - * Copyright 2012-2015 VMware, Inc., Palo Alto, CA., USA + * Copyright 2012-2021 VMware, Inc., Palo Alto, CA., USA * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -29,12 +29,6 @@ #include "vmwgfx_drv.h" -/* - * If we set up the screen target otable, screen objects stop working. - */ - -#define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE ? 0 : 1)) - #ifdef CONFIG_64BIT #define VMW_PPN_SIZE 8 #define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PT64_0 @@ -75,7 +69,7 @@ static const struct vmw_otable pre_dx_tables[] = { {VMWGFX_NUM_GB_CONTEXT * sizeof(SVGAOTableContextEntry), NULL, true}, {VMWGFX_NUM_GB_SHADER * sizeof(SVGAOTableShaderEntry), NULL, true}, {VMWGFX_NUM_GB_SCREEN_TARGET * sizeof(SVGAOTableScreenTargetEntry), - NULL, VMWGFX_ENABLE_SCREEN_TARGET_OTABLE} + NULL, true} }; static const struct vmw_otable dx_tables[] = { @@ -84,7 +78,7 @@ static const struct vmw_otable dx_tables[] = { {VMWGFX_NUM_GB_CONTEXT * sizeof(SVGAOTableContextEntry), NULL, true}, {VMWGFX_NUM_GB_SHADER * sizeof(SVGAOTableShaderEntry), NULL, true}, {VMWGFX_NUM_GB_SCREEN_TARGET * sizeof(SVGAOTableScreenTargetEntry), - NULL, VMWGFX_ENABLE_SCREEN_TARGET_OTABLE}, + NULL, true}, {VMWGFX_NUM_DXCONTEXT * sizeof(SVGAOTableDXContextEntry), NULL, true}, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 8f0d651d0144..ae9a6044d448 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1872,8 +1872,8 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) int i, ret; - /* Do nothing if Screen Target support is turned off */ - if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE || !dev_priv->has_mob) + /* Do nothing if there's no support for MOBs */ + if (!dev_priv->has_mob) return -ENOSYS; if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) -- cgit v1.2.3 From 60c9ecd705be3a28f79d70ea21c3939db668bf46 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Wed, 15 Dec 2021 15:02:24 -0500 Subject: drm/vmwgfx: Fix possible usage of an uninitialized variable vmw_user_bo_lookup can fail to lookup user buffers, especially because the buffer handles come from the userspace. The return value has to be checked before the buffers are put back. This was spotted by Dan's Smatch statick checker: drivers/gpu/drm/vmwgfx/vmwgfx_bo.c:574 vmw_user_bo_synccpu_release() error: uninitialized symbol 'vmw_bo'. Signed-off-by: Zack Rusin Reported-by: Dan Carpenter Fixes: 8afa13a0583f ("drm/vmwgfx: Implement DRIVER_GEM") Reviewed-by: Martin Krastev Link: https://patchwork.freedesktop.org/patch/msgid/20211215200224.3693345-1-zack@kde.org --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index 15fead85450c..31aecc46624b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -568,10 +568,12 @@ static int vmw_user_bo_synccpu_release(struct drm_file *filp, struct vmw_buffer_object *vmw_bo; int ret = vmw_user_bo_lookup(filp, handle, &vmw_bo); - if (!(flags & drm_vmw_synccpu_allow_cs)) { - atomic_dec(&vmw_bo->cpu_writers); + if (!ret) { + if (!(flags & drm_vmw_synccpu_allow_cs)) { + atomic_dec(&vmw_bo->cpu_writers); + } + ttm_bo_put(&vmw_bo->base); } - ttm_bo_put(&vmw_bo->base); return ret; } -- cgit v1.2.3 From 007354597d5c12a8d44a34c66a2e1a089bc7d3d8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:17:43 +1000 Subject: drm/nouveau/disp: remove some remnant of a rework Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index e484d0c3b0d4..7653d80b4076 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -9,10 +9,7 @@ #include struct nvkm_dp { - union { - struct nvkm_outp base; - struct nvkm_outp outp; - }; + struct nvkm_outp outp; struct nvbios_dpout info; u8 version; -- cgit v1.2.3 From be5b6985fbbe6ba9580351b3c9168c84e51bee5c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:17:49 +1000 Subject: drm/nouveau/disp/dp: explicitly control scrambling when setting pattern TPS1/2/3 require scrambling to be disabled. The IED scripts on earlier boards used to handle this, but appear not to anymore. TPS4 support will also require scrambling to remain enabled. Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 5 +++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 13 ++++++++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 14 +++++++++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c | 17 ++++++++++++++--- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 9669472a2749..3c0554a60ba9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -154,6 +154,11 @@ nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp |= pattern; + + if (pattern != 0) + sink_tp |= DPCD_LC02_SCRAMBLING_DISABLE; + else + sink_tp &= ~DPCD_LC02_SCRAMBLING_DISABLE; nvkm_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 7653d80b4076..9ce91f79ca35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -49,6 +49,7 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); #define DPCD_LC01_LANE_COUNT_SET 0x1f #define DPCD_LC02 0x00102 #define DPCD_LC02_TRAINING_PATTERN_SET 0x03 +#define DPCD_LC02_SCRAMBLING_DISABLE 0x20 #define DPCD_LC03(l) ((l) + 0x00103) #define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20 #define DPCD_LC03_PRE_EMPHASIS_SET 0x18 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 4d59d02525d9..56b8f4411988 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -77,7 +77,18 @@ g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern) { struct nvkm_device *device = sor->disp->engine.subdev.device; const u32 loff = nv50_sor_link(sor); - nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); + u32 data; + + switch (pattern) { + case 0: data = 0x00001000; break; + case 1: data = 0x01000000; break; + case 2: data = 0x02000000; break; + default: + WARN_ON(1); + return; + } + + nvkm_mask(device, 0x61c10c + loff, 0x0f001000, data); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 3b3643fb1019..c431e0b9fc11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -92,7 +92,19 @@ gf119_sor_dp_pattern(struct nvkm_ior *sor, int pattern) { struct nvkm_device *device = sor->disp->engine.subdev.device; const u32 soff = nv50_ior_base(sor); - nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); + u32 data; + + switch (pattern) { + case 0: data = 0x10101010; break; + case 1: data = 0x01010101; break; + case 2: data = 0x02020202; break; + case 3: data = 0x03030303; break; + default: + WARN_ON(1); + return; + } + + nvkm_mask(device, 0x61c110 + soff, 0x1f1f1f1f, data); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 38045c92197f..5aa7138f3472 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -28,11 +28,22 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) { struct nvkm_device *device = sor->disp->engine.subdev.device; const u32 soff = nv50_ior_base(sor); - const u32 data = 0x01010101 * pattern; + u32 mask = 0x1f1f1f1f, data; + + switch (pattern) { + case 0: data = 0x10101010; break; + case 1: data = 0x01010101; break; + case 2: data = 0x02020202; break; + case 3: data = 0x03030303; break; + default: + WARN_ON(1); + return; + } + if (sor->asy.link & 1) - nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); + nvkm_mask(device, 0x61c110 + soff, mask, data); else - nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); + nvkm_mask(device, 0x61c12c + soff, mask, data); } static const struct nvkm_ior_func -- cgit v1.2.3 From b96a1d8c5189452d80551f2c38ef50c533c19669 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:17:52 +1000 Subject: drm/nouveau/disp/dp: generate supported link rates table at detect time Replaces the static list used during link training with a table built dynamically from the union of source and sink capabilities. Preparation for adding support for HBR3, LTTPR and eDP 1.4 link rates. Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 108 ++++++++++---------------- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 6 ++ 2 files changed, 45 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 3c0554a60ba9..8b49398a91c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -350,63 +350,13 @@ nvkm_dp_train_init(struct nvkm_dp *dp) } } -static const struct dp_rates { - u32 rate; - u8 bw; - u8 nr; -} nvkm_dp_rates[] = { - { 2160000, 0x14, 4 }, - { 1080000, 0x0a, 4 }, - { 1080000, 0x14, 2 }, - { 648000, 0x06, 4 }, - { 540000, 0x0a, 2 }, - { 540000, 0x14, 1 }, - { 324000, 0x06, 2 }, - { 270000, 0x0a, 1 }, - { 162000, 0x06, 1 }, - {} -}; - static int nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) { struct nvkm_ior *ior = dp->outp.ior; - const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; - const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; - const u8 outp_nr = dp->outp.info.dpconf.link_nr; - const u8 outp_bw = dp->outp.info.dpconf.link_bw; - const struct dp_rates *failsafe = NULL, *cfg; - int ret = -EINVAL; + int ret = -EINVAL, nr, rate; u8 pwr; - /* Find the lowest configuration of the OR that can support - * the required link rate. - * - * We will refuse to program the OR to lower rates, even if - * link training fails at higher rates (or even if the sink - * can't support the rate at all, though the DD is supposed - * to prevent such situations from happening). - * - * Attempting to do so can cause the entire display to hang, - * and it's better to have a failed modeset than that. - */ - for (cfg = nvkm_dp_rates; cfg->rate; cfg++) { - if (cfg->nr <= outp_nr && cfg->bw <= outp_bw) { - /* Try to respect sink limits too when selecting - * lowest link configuration. - */ - if (!failsafe || - (cfg->nr <= sink_nr && cfg->bw <= sink_bw)) - failsafe = cfg; - } - - if (failsafe && cfg[1].rate < dataKBps) - break; - } - - if (WARN_ON(!failsafe)) - return ret; - /* Ensure sink is not in a low-power state. */ if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) { if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { @@ -416,25 +366,22 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) } } + ior->dp.mst = dp->lt.mst; + ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; + ior->dp.nr = 0; + /* Link training. */ - OUTP_DBG(&dp->outp, "training (min: %d x %d MB/s)", - failsafe->nr, failsafe->bw * 27); + OUTP_DBG(&dp->outp, "training"); nvkm_dp_train_init(dp); - for (cfg = nvkm_dp_rates; ret < 0 && cfg <= failsafe; cfg++) { - /* Skip configurations not supported by both OR and sink. */ - if ((cfg->nr > outp_nr || cfg->bw > outp_bw || - cfg->nr > sink_nr || cfg->bw > sink_bw)) { - if (cfg != failsafe) - continue; - OUTP_ERR(&dp->outp, "link rate unsupported by sink"); + for (nr = dp->links; ret < 0 && nr; nr >>= 1) { + for (rate = 0; ret < 0 && rate < dp->rates; rate++) { + if (dp->rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) { + /* Program selected link configuration. */ + ior->dp.bw = dp->rate[rate].rate / 27000; + ior->dp.nr = nr; + ret = nvkm_dp_train_links(dp); + } } - ior->dp.mst = dp->lt.mst; - ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; - ior->dp.bw = cfg->bw; - ior->dp.nr = cfg->nr; - - /* Program selected link configuration. */ - ret = nvkm_dp_train_links(dp); } nvkm_dp_train_fini(dp); if (ret < 0) @@ -543,9 +490,32 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) dp->present = true; } - if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, - sizeof(dp->dpcd))) + if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, sizeof(dp->dpcd))) { + const u8 rates[] = { 0x14, 0x0a, 0x06, 0 }; + const u8 *rate; + int rate_max; + + dp->rates = 0; + dp->links = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; + dp->links = min(dp->links, dp->outp.info.dpconf.link_nr); + + rate_max = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; + rate_max = min(rate_max, dp->outp.info.dpconf.link_bw); + + if (1) { + for (rate = rates; *rate; rate++) { + if (*rate <= rate_max) { + if (WARN_ON(dp->rates == ARRAY_SIZE(dp->rate))) + break; + + dp->rate[dp->rates].rate = *rate * 27000; + dp->rates++; + } + } + } + return true; + } } if (dp->present) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 9ce91f79ca35..8a8d0da58277 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -20,6 +20,12 @@ struct nvkm_dp { bool present; u8 dpcd[16]; + struct { + u32 rate; + } rate[3]; + int rates; + int links; + struct mutex mutex; struct { atomic_t done; -- cgit v1.2.3 From 3edcd504077c02c9e6e7b687a43849eacbb8088d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:17:54 +1000 Subject: drm/nouveau/disp/dp: add support for tps4 Required for HBR3 and LTTPR. Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 19 ++++++++++++++----- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 3 ++- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 8b49398a91c5..565ee63c0f1d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -153,7 +153,7 @@ nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; - sink_tp |= pattern; + sink_tp |= (pattern != 4) ? pattern : 7; if (pattern != 0) sink_tp |= DPCD_LC02_SCRAMBLING_DISABLE; @@ -168,10 +168,17 @@ nvkm_dp_train_eq(struct lt_state *lt) bool eq_done = false, cr_done = true; int tries = 0, i; - if (lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED) - nvkm_dp_train_pattern(lt, 3); - else - nvkm_dp_train_pattern(lt, 2); + { + if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x14 && + lt->dp->dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED) + nvkm_dp_train_pattern(lt, 4); + else + if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x12 && + lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED) + nvkm_dp_train_pattern(lt, 3); + else + nvkm_dp_train_pattern(lt, 2); + } do { if ((tries && @@ -245,6 +252,8 @@ nvkm_dp_train_links(struct nvkm_dp *dp) ior->dp.nr, ior->dp.bw * 27); /* Intersect misc. capabilities of the OR and sink. */ + if (disp->engine.subdev.device->chipset < 0x110) + dp->dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED; if (disp->engine.subdev.device->chipset < 0xd0) dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED; lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 8a8d0da58277..1becf9da3ed7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -45,6 +45,7 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); #define DPCD_RC02_TPS3_SUPPORTED 0x40 #define DPCD_RC02_MAX_LANE_COUNT 0x1f #define DPCD_RC03 0x00003 +#define DPCD_RC03_TPS4_SUPPORTED 0x80 #define DPCD_RC03_MAX_DOWNSPREAD 0x01 #define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e @@ -54,7 +55,7 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); #define DPCD_LC01_ENHANCED_FRAME_EN 0x80 #define DPCD_LC01_LANE_COUNT_SET 0x1f #define DPCD_LC02 0x00102 -#define DPCD_LC02_TRAINING_PATTERN_SET 0x03 +#define DPCD_LC02_TRAINING_PATTERN_SET 0x0f #define DPCD_LC02_SCRAMBLING_DISABLE 0x20 #define DPCD_LC03(l) ((l) + 0x00103) #define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 5aa7138f3472..3696bfd3bfd7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -35,6 +35,7 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) case 1: data = 0x01010101; break; case 2: data = 0x02020202; break; case 3: data = 0x03030303; break; + case 4: data = 0x1b1b1b1b; break; default: WARN_ON(1); return; -- cgit v1.2.3 From 9543e3c0511da64a77b1af3ab1f7199c39226e1b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:17:56 +1000 Subject: drm/nouveau/disp/dp: fixup cr/eq delays for 1.4 Also use usleep_range() instead of [um]delay() to be a bit nicer. Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 18 ++++++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 3 ++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 565ee63c0f1d..eee2451123c9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -54,10 +54,7 @@ nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) struct nvkm_dp *dp = lt->dp; int ret; - if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) - mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); - else - udelay(delay); + usleep_range(delay, delay * 2); ret = nvkm_rdaux(dp->aux, DPCD_LS02, lt->stat, 6); if (ret) @@ -166,7 +163,7 @@ static int nvkm_dp_train_eq(struct lt_state *lt) { bool eq_done = false, cr_done = true; - int tries = 0, i; + int tries = 0, usec = 0, i; { if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x14 && @@ -178,12 +175,14 @@ nvkm_dp_train_eq(struct lt_state *lt) nvkm_dp_train_pattern(lt, 3); else nvkm_dp_train_pattern(lt, 2); + + usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; } do { if ((tries && nvkm_dp_train_drive(lt, lt->pc2)) || - nvkm_dp_train_sense(lt, lt->pc2, 400)) + nvkm_dp_train_sense(lt, lt->pc2, usec ? usec : 400)) break; eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); @@ -205,13 +204,16 @@ nvkm_dp_train_cr(struct lt_state *lt) { bool cr_done = false, abort = false; int voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; - int tries = 0, i; + int tries = 0, usec = 0, i; nvkm_dp_train_pattern(lt, 1); + if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] < 0x14) + usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; + do { if (nvkm_dp_train_drive(lt, false) || - nvkm_dp_train_sense(lt, false, 100)) + nvkm_dp_train_sense(lt, false, usec ? usec : 100)) break; cr_done = true; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 1becf9da3ed7..104f847b5abf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -47,7 +47,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); #define DPCD_RC03 0x00003 #define DPCD_RC03_TPS4_SUPPORTED 0x80 #define DPCD_RC03_MAX_DOWNSPREAD 0x01 -#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e +#define DPCD_RC0E 0x0000e +#define DPCD_RC0E_AUX_RD_INTERVAL 0x7f /* DPCD Link Configuration */ #define DPCD_LC00_LINK_BW_SET 0x00100 -- cgit v1.2.3 From f21e5fa191be05616e3250723c5c4cadc9baf84a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:18:00 +1000 Subject: drm/nouveau/disp/dp: add support for lttprs Add support for Link-Training Tunable PHY Repeaters, required to support higher bit rates on longer cables, as well as USB-C on certain docks and laptops. Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 114 +++++++++++++++++++++++--- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 12 +++ 2 files changed, 114 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index eee2451123c9..b0dfa08f799a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -41,6 +41,10 @@ struct lt_state { struct nvkm_dp *dp; + + int repeaters; + int repeater; + u8 stat[6]; u8 conf[4]; bool pc2; @@ -52,11 +56,26 @@ static int nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) { struct nvkm_dp *dp = lt->dp; + u32 addr; int ret; usleep_range(delay, delay * 2); - ret = nvkm_rdaux(dp->aux, DPCD_LS02, lt->stat, 6); + if (lt->repeater) + addr = DPCD_LTTPR_LANE0_1_STATUS(lt->repeater); + else + addr = DPCD_LS02; + + ret = nvkm_rdaux(dp->aux, addr, <->stat[0], 3); + if (ret) + return ret; + + if (lt->repeater) + addr = DPCD_LTTPR_LANE0_1_ADJUST(lt->repeater); + else + addr = DPCD_LS06; + + ret = nvkm_rdaux(dp->aux, addr, <->stat[4], 2); if (ret) return ret; @@ -82,6 +101,7 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) struct nvbios_dpout info; struct nvbios_dpcfg ocfg; u8 ver, hdr, cnt, len; + u32 addr; u32 data; int ret, i; @@ -110,6 +130,9 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) OUTP_TRACE(&dp->outp, "config lane %d %02x %02x", i, lt->conf[i], lpc2); + if (lt->repeater != lt->repeaters) + continue; + data = nvbios_dpout_match(bios, dp->outp.info.hasht, dp->outp.info.hashm, &ver, &hdr, &cnt, &len, &info); @@ -126,7 +149,12 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) ocfg.pe, ocfg.tx_pu); } - ret = nvkm_wraux(dp->aux, DPCD_LC03(0), lt->conf, 4); + if (lt->repeater) + addr = DPCD_LTTPR_LANE0_SET(lt->repeater); + else + addr = DPCD_LC03(0); + + ret = nvkm_wraux(dp->aux, addr, lt->conf, 4); if (ret) return ret; @@ -143,12 +171,18 @@ static void nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) { struct nvkm_dp *dp = lt->dp; + u32 addr; u8 sink_tp; OUTP_TRACE(&dp->outp, "training pattern %d", pattern); dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern); - nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); + if (lt->repeater) + addr = DPCD_LTTPR_PATTERN_SET(lt->repeater); + else + addr = DPCD_LC02; + + nvkm_rdaux(dp->aux, addr, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp |= (pattern != 4) ? pattern : 7; @@ -156,16 +190,23 @@ nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) sink_tp |= DPCD_LC02_SCRAMBLING_DISABLE; else sink_tp &= ~DPCD_LC02_SCRAMBLING_DISABLE; - nvkm_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); + nvkm_wraux(dp->aux, addr, &sink_tp, 1); } static int nvkm_dp_train_eq(struct lt_state *lt) { + struct nvkm_i2c_aux *aux = lt->dp->aux; bool eq_done = false, cr_done = true; int tries = 0, usec = 0, i; + u8 data; - { + if (lt->repeater) { + if (!nvkm_rdaux(aux, DPCD_LTTPR_AUX_RD_INTERVAL(lt->repeater), &data, sizeof(data))) + usec = (data & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; + + nvkm_dp_train_pattern(lt, 4); + } else { if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x14 && lt->dp->dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED) nvkm_dp_train_pattern(lt, 4); @@ -208,7 +249,7 @@ nvkm_dp_train_cr(struct lt_state *lt) nvkm_dp_train_pattern(lt, 1); - if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] < 0x14) + if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] < 0x14 && !lt->repeater) usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; do { @@ -247,7 +288,7 @@ nvkm_dp_train_links(struct nvkm_dp *dp) .dp = dp, }; u32 lnkcmp; - u8 sink[2]; + u8 sink[2], data; int ret; OUTP_DBG(&dp->outp, "training %d x %d MB/s", @@ -303,6 +344,20 @@ nvkm_dp_train_links(struct nvkm_dp *dp) ior->func->dp.power(ior, ior->dp.nr); + /* Select LTTPR non-transparent mode if we have a valid configuration, + * use transparent mode otherwise. + */ + if (dp->lttpr[0] >= 0x14) { + data = DPCD_LTTPR_MODE_TRANSPARENT; + nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data)); + + if (dp->lttprs) { + data = DPCD_LTTPR_MODE_NON_TRANSPARENT; + nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data)); + lt.repeaters = dp->lttprs; + } + } + /* Set desired link configuration on the sink. */ sink[0] = ior->dp.bw; sink[1] = ior->dp.nr; @@ -314,11 +369,19 @@ nvkm_dp_train_links(struct nvkm_dp *dp) return ret; /* Attempt to train the link in this configuration. */ - memset(lt.stat, 0x00, sizeof(lt.stat)); - ret = nvkm_dp_train_cr(<); - if (ret == 0) - ret = nvkm_dp_train_eq(<); - nvkm_dp_train_pattern(<, 0); + for (lt.repeater = lt.repeaters; lt.repeater >= 0; lt.repeater--) { + if (lt.repeater) + OUTP_DBG(&dp->outp, "training LTTPR%d", lt.repeater); + else + OUTP_DBG(&dp->outp, "training sink"); + + memset(lt.stat, 0x00, sizeof(lt.stat)); + ret = nvkm_dp_train_cr(<); + if (ret == 0) + ret = nvkm_dp_train_eq(<); + nvkm_dp_train_pattern(<, 0); + } + return ret; } @@ -501,6 +564,29 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) dp->present = true; } + /* Detect any LTTPRs before reading DPCD receiver caps. */ + if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, dp->lttpr, sizeof(dp->lttpr)) && + dp->lttpr[0] >= 0x14 && dp->lttpr[2]) { + switch (dp->lttpr[2]) { + case 0x80: dp->lttprs = 1; break; + case 0x40: dp->lttprs = 2; break; + case 0x20: dp->lttprs = 3; break; + case 0x10: dp->lttprs = 4; break; + case 0x08: dp->lttprs = 5; break; + case 0x04: dp->lttprs = 6; break; + case 0x02: dp->lttprs = 7; break; + case 0x01: dp->lttprs = 8; break; + default: + /* Unknown LTTPR count, we'll switch to transparent mode. */ + WARN_ON(1); + dp->lttprs = 0; + break; + } + } else { + /* No LTTPR support, or zero LTTPR count - don't touch it at all. */ + memset(dp->lttpr, 0x00, sizeof(dp->lttpr)); + } + if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, sizeof(dp->dpcd))) { const u8 rates[] = { 0x14, 0x0a, 0x06, 0 }; const u8 *rate; @@ -509,9 +595,13 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) dp->rates = 0; dp->links = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; dp->links = min(dp->links, dp->outp.info.dpconf.link_nr); + if (dp->lttprs && dp->lttpr[4]) + dp->links = min_t(int, dp->links, dp->lttpr[4]); rate_max = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; rate_max = min(rate_max, dp->outp.info.dpconf.link_bw); + if (dp->lttprs && dp->lttpr[1]) + rate_max = min_t(int, rate_max, dp->lttpr[1]); if (1) { for (rate = rates; *rate; rate++) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 104f847b5abf..8728d5e0fb8a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -18,6 +18,8 @@ struct nvkm_dp { struct nvkm_notify hpd; bool present; + u8 lttpr[6]; + u8 lttprs; u8 dpcd[16]; struct { @@ -114,4 +116,14 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); #define DPCD_SC00_SET_POWER 0x03 #define DPCD_SC00_SET_POWER_D0 0x01 #define DPCD_SC00_SET_POWER_D3 0x03 + +#define DPCD_LTTPR_REV 0xf0000 +#define DPCD_LTTPR_MODE 0xf0003 +#define DPCD_LTTPR_MODE_TRANSPARENT 0x55 +#define DPCD_LTTPR_MODE_NON_TRANSPARENT 0xaa +#define DPCD_LTTPR_PATTERN_SET(i) ((i - 1) * 0x50 + 0xf0010) +#define DPCD_LTTPR_LANE0_SET(i) ((i - 1) * 0x50 + 0xf0011) +#define DPCD_LTTPR_AUX_RD_INTERVAL(i) ((i - 1) * 0x50 + 0xf0020) +#define DPCD_LTTPR_LANE0_1_STATUS(i) ((i - 1) * 0x50 + 0xf0030) +#define DPCD_LTTPR_LANE0_1_ADJUST(i) ((i - 1) * 0x50 + 0xf0033) #endif -- cgit v1.2.3 From 405d5382ba083e6e54df354909b1583f1e3cb0db Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:18:03 +1000 Subject: drm/nouveau/disp/dp: add support for hbr3 Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index b0dfa08f799a..ab78842371e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -588,7 +588,7 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) } if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, sizeof(dp->dpcd))) { - const u8 rates[] = { 0x14, 0x0a, 0x06, 0 }; + const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 }; const u8 *rate; int rate_max; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 8728d5e0fb8a..3b751cd09a16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -24,7 +24,7 @@ struct nvkm_dp { struct { u32 rate; - } rate[3]; + } rate[4]; int rates; int links; -- cgit v1.2.3 From 70704fbf67ddc07ffc81073a3af1f7b2171697eb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 23 Nov 2021 18:18:06 +1000 Subject: drm/nouveau/disp/dp: add support for eDP link rates eDP 1.4 adds a table of link rates supported by the sink to DPCD, as well as a LINK_RATE_SET register to select between the entries in it. If present, we will use this data to generate our internal link rate table rather than using the standard list based on MAX_LINK_RATE. Some recent laptops report MAX_LINK_RATE=0, and require this support. Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul Signed-off-by: Karol Herbst Link: https://gitlab.freedesktop.org/drm/nouveau/-/merge_requests/17 --- drivers/gpu/drm/nouveau/nouveau_dp.c | 15 ++++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 63 ++++++++++++++++++++-- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 7 ++- .../gpu/drm/nouveau/nvkm/engine/disp/sorga102.c | 4 ++ 4 files changed, 84 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index 040ed88d362d..3a288d0b848f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -147,6 +147,21 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, nv_encoder->dp.link_nr = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) { + struct drm_dp_aux *aux = &nv_connector->aux; + int ret, i; + u8 sink_rates[16]; + + ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates)); + if (ret == sizeof(sink_rates)) { + for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { + int val = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; + if (val && (i == 0 || val > nv_encoder->dp.link_bw)) + nv_encoder->dp.link_bw = val; + } + } + } + NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n", nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[DP_DPCD_REV]); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index ab78842371e8..8e09315b8fb3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -278,7 +278,7 @@ nvkm_dp_train_cr(struct lt_state *lt) } static int -nvkm_dp_train_links(struct nvkm_dp *dp) +nvkm_dp_train_links(struct nvkm_dp *dp, int rate) { struct nvkm_ior *ior = dp->outp.ior; struct nvkm_disp *disp = dp->outp.disp; @@ -359,7 +359,7 @@ nvkm_dp_train_links(struct nvkm_dp *dp) } /* Set desired link configuration on the sink. */ - sink[0] = ior->dp.bw; + sink[0] = (dp->rate[rate].dpcd < 0) ? ior->dp.bw : 0; sink[1] = ior->dp.nr; if (ior->dp.ef) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; @@ -368,6 +368,19 @@ nvkm_dp_train_links(struct nvkm_dp *dp) if (ret) return ret; + if (dp->rate[rate].dpcd >= 0) { + ret = nvkm_rdaux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0])); + if (ret) + return ret; + + sink[0] &= ~DPCD_LC15_LINK_RATE_SET_MASK; + sink[0] |= dp->rate[rate].dpcd; + + ret = nvkm_wraux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0])); + if (ret) + return ret; + } + /* Attempt to train the link in this configuration. */ for (lt.repeater = lt.repeaters; lt.repeater >= 0; lt.repeater--) { if (lt.repeater) @@ -453,7 +466,7 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) /* Program selected link configuration. */ ior->dp.bw = dp->rate[rate].rate / 27000; ior->dp.nr = nr; - ret = nvkm_dp_train_links(dp); + ret = nvkm_dp_train_links(dp, rate); } } } @@ -552,6 +565,47 @@ done: return ret; } +static bool +nvkm_dp_enable_supported_link_rates(struct nvkm_dp *dp) +{ + u8 sink_rates[DPCD_RC10_SUPPORTED_LINK_RATES__SIZE]; + int i, j, k; + + if (dp->outp.conn->info.type != DCB_CONNECTOR_eDP || + dp->dpcd[DPCD_RC00_DPCD_REV] < 0x13 || + nvkm_rdaux(dp->aux, DPCD_RC10_SUPPORTED_LINK_RATES(0), sink_rates, sizeof(sink_rates))) + return false; + + for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { + const u32 rate = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; + + if (!rate || WARN_ON(dp->rates == ARRAY_SIZE(dp->rate))) + break; + + if (rate > dp->outp.info.dpconf.link_bw * 27000) { + OUTP_DBG(&dp->outp, "rate %d !outp", rate); + continue; + } + + for (j = 0; j < dp->rates; j++) { + if (rate > dp->rate[j].rate) { + for (k = dp->rates; k > j; k--) + dp->rate[k] = dp->rate[k - 1]; + break; + } + } + + dp->rate[j].dpcd = i / 2; + dp->rate[j].rate = rate; + dp->rates++; + } + + for (i = 0; i < dp->rates; i++) + OUTP_DBG(&dp->outp, "link_rate[%d] = %d", dp->rate[i].dpcd, dp->rate[i].rate); + + return dp->rates != 0; +} + static bool nvkm_dp_enable(struct nvkm_dp *dp, bool enable) { @@ -603,12 +657,13 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) if (dp->lttprs && dp->lttpr[1]) rate_max = min_t(int, rate_max, dp->lttpr[1]); - if (1) { + if (!nvkm_dp_enable_supported_link_rates(dp)) { for (rate = rates; *rate; rate++) { if (*rate <= rate_max) { if (WARN_ON(dp->rates == ARRAY_SIZE(dp->rate))) break; + dp->rate[dp->rates].dpcd = -1; dp->rate[dp->rates].rate = *rate * 27000; dp->rates++; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 3b751cd09a16..8e59dd469da6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -23,8 +23,9 @@ struct nvkm_dp { u8 dpcd[16]; struct { + int dpcd; /* -1, or index into SUPPORTED_LINK_RATES table */ u32 rate; - } rate[4]; + } rate[8]; int rates; int links; @@ -51,6 +52,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); #define DPCD_RC03_MAX_DOWNSPREAD 0x01 #define DPCD_RC0E 0x0000e #define DPCD_RC0E_AUX_RD_INTERVAL 0x7f +#define DPCD_RC10_SUPPORTED_LINK_RATES(i) 0x00010 +#define DPCD_RC10_SUPPORTED_LINK_RATES__SIZE 16 /* DPCD Link Configuration */ #define DPCD_LC00_LINK_BW_SET 0x00100 @@ -75,6 +78,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); #define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30 #define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04 #define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03 +#define DPCD_LC15_LINK_RATE_SET 0x00115 +#define DPCD_LC15_LINK_RATE_SET_MASK 0x07 /* DPCD Link/Sink Status */ #define DPCD_LS02 0x00202 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c index 033827de9116..d2c05f5c4aa0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c @@ -37,6 +37,10 @@ ga102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) case 0x0a: clksor |= 0x00040000; break; case 0x14: clksor |= 0x00080000; break; case 0x1e: clksor |= 0x000c0000; break; + case 0x08: clksor |= 0x00100000; break; + case 0x09: clksor |= 0x00140000; break; + case 0x0c: clksor |= 0x00180000; break; + case 0x10: clksor |= 0x001c0000; break; default: WARN_ON(1); return -EINVAL; -- cgit v1.2.3 From 943e6a8beeac1b676265f2dd81a69d7bede5e41d Mon Sep 17 00:00:00 2001 From: Claudio Suarez Date: Thu, 2 Dec 2021 10:49:49 +0100 Subject: mock a drm_plane in igt_check_plane_state to make the test more robust igt_check_plane_state test crashes in drm_atomic_helper_check_plane_state when trying to de-reference drm_plane_state->plane->dev due to the lack of a struct drm_plane in the mock struct drm_plane_state. Since drm_plane_state always should contain a plane, the mock also needs a plane to be the test more robust and realistic. Add it. Signed-off-by: Claudio Suarez Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/YaiWvQESctDMipjh@gineta.localdomain --- drivers/gpu/drm/selftests/test-drm_plane_helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/selftests/test-drm_plane_helper.c index 0a9553f51796..ceebeede55ea 100644 --- a/drivers/gpu/drm/selftests/test-drm_plane_helper.c +++ b/drivers/gpu/drm/selftests/test-drm_plane_helper.c @@ -87,11 +87,15 @@ int igt_check_plane_state(void *ignored) DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, }; + struct drm_plane plane = { + .dev = NULL + }; struct drm_framebuffer fb = { .width = 2048, .height = 2048 }; struct drm_plane_state plane_state = { + .plane = &plane, .crtc = ZERO_SIZE_PTR, .fb = &fb, .rotation = DRM_MODE_ROTATE_0 -- cgit v1.2.3 From 521d459b1935628a7caa0753429f880dae2dbfc9 Mon Sep 17 00:00:00 2001 From: Claudio Suarez Date: Thu, 2 Dec 2021 10:51:12 +0100 Subject: drm: fix error found in some cases after the patch d1af5cd86997 The patch d1af5cd86997 ("drm: get rid of DRM_DEBUG_* log calls in drm core, files drm_a*.c") fails when the drm_device cannot be found in the parameter plane_state->crtc. Fix it using plane_state->plane. Reported-by: kernel test robot Fixes: 6e22dc358377 ("drm: get rid of DRM_DEBUG_* log calls in drm core, files drm_a*.c") Signed-off-by: Claudio Suarez [danvet: fix Fixes: line] Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/YaiXEARd8z2C463h@gineta.localdomain --- drivers/gpu/drm/drm_atomic_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aef2fbd676e5..a7a05e1e26bb 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -828,8 +828,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, } if (!crtc_state->enable && !can_update_disabled) { - drm_dbg_kms(plane_state->crtc->dev, - "Cannot update plane of a disabled CRTC.\n"); + drm_dbg_kms(plane_state->plane->dev, + "Cannot update plane of a disabled CRTC.\n"); return -EINVAL; } @@ -839,8 +839,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); if (hscale < 0 || vscale < 0) { - drm_dbg_kms(plane_state->crtc->dev, - "Invalid scaling of plane\n"); + drm_dbg_kms(plane_state->plane->dev, + "Invalid scaling of plane\n"); drm_rect_debug_print("src: ", &plane_state->src, true); drm_rect_debug_print("dst: ", &plane_state->dst, false); return -ERANGE; @@ -864,8 +864,8 @@ int drm_atomic_helper_check_plane_state(struct drm_plane_state *plane_state, return 0; if (!can_position && !drm_rect_equals(dst, &clip)) { - drm_dbg_kms(plane_state->crtc->dev, - "Plane must cover entire CRTC\n"); + drm_dbg_kms(plane_state->plane->dev, + "Plane must cover entire CRTC\n"); drm_rect_debug_print("dst: ", dst, false); drm_rect_debug_print("clip: ", &clip, false); return -EINVAL; -- cgit v1.2.3 From f2165301c3cc2ee70b5c2ac9be4d0e3c76aa0985 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 13 Dec 2021 14:36:23 +0100 Subject: dt-bindings: display: bridge: sn65dsi83: Make enable GPIO optional The SN65DSI8x EN signal may be tied to VCC, or otherwise controlled by means not available to the kernel. Make the GPIO optional. Signed-off-by: Laurent Pinchart Acked-by: Rob Herring Signed-off-by: Alexander Stein Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211213133626.2498056-2-alexander.stein@ew.tq-group.com --- Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml index b446d0f0f1b4..c3f3e73f740a 100644 --- a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml +++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml @@ -91,7 +91,6 @@ properties: required: - compatible - reg - - enable-gpios - ports allOf: -- cgit v1.2.3 From 5995aef006698bb639547a439f47492de5c37f05 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 13 Dec 2021 14:36:24 +0100 Subject: drm/bridge: ti-sn65dsi83: Make enable GPIO optional The enable signal may not be controllable by the kernel. Make it optional. This is a similar to commit bbda1704fc15 ("drm/bridge: ti-sn65dsi86: Make enable GPIO optional") Reviewed-by: Laurent Pinchart Reviewed-by: Sam Ravnborg Signed-off-by: Alexander Stein Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211213133626.2498056-3-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 945f08de45f1..065610edc37a 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -662,7 +662,8 @@ static int sn65dsi83_probe(struct i2c_client *client, } /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ - ctx->enable_gpio = devm_gpiod_get(ctx->dev, "enable", GPIOD_OUT_LOW); + ctx->enable_gpio = devm_gpiod_get_optional(ctx->dev, "enable", + GPIOD_OUT_LOW); if (IS_ERR(ctx->enable_gpio)) return PTR_ERR(ctx->enable_gpio); -- cgit v1.2.3 From e6ba217381955587cb18b9f32d29b75f03550846 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 13 Dec 2021 14:36:25 +0100 Subject: dt-bindings: drm/bridge: ti-sn65dsi83: Add vcc supply bindings Add a VCC regulator which needs to be enabled before the EN pin is released. Reviewed-by: Sam Ravnborg Acked-by: Rob Herring Reviewed-by: Jagan Teki Signed-off-by: Alexander Stein Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211213133626.2498056-4-alexander.stein@ew.tq-group.com --- Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml index c3f3e73f740a..48a97bb3e2e0 100644 --- a/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml +++ b/Documentation/devicetree/bindings/display/bridge/ti,sn65dsi83.yaml @@ -32,6 +32,9 @@ properties: maxItems: 1 description: GPIO specifier for bridge_en pin (active high). + vcc-supply: + description: A 1.8V power supply (see regulator/regulator.yaml). + ports: $ref: /schemas/graph.yaml#/properties/ports @@ -132,6 +135,7 @@ examples: reg = <0x2d>; enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; + vcc-supply = <®_sn65dsi83_1v8>; ports { #address-cells = <1>; -- cgit v1.2.3 From 5664e3c907e20523cda622268716867e77648d0c Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 13 Dec 2021 14:36:26 +0100 Subject: drm/bridge: ti-sn65dsi83: Add vcc supply regulator support VCC needs to be enabled before releasing the enable GPIO. Reviewed-by: Laurent Pinchart Signed-off-by: Alexander Stein Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211213133626.2498056-5-alexander.stein@ew.tq-group.com --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 065610edc37a..5650a793db81 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -143,6 +144,7 @@ struct sn65dsi83 { struct mipi_dsi_device *dsi; struct drm_bridge *panel_bridge; struct gpio_desc *enable_gpio; + struct regulator *vcc; int dsi_lanes; bool lvds_dual_link; bool lvds_dual_link_even_odd_swap; @@ -337,6 +339,12 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, u16 val; int ret; + ret = regulator_enable(ctx->vcc); + if (ret) { + dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret); + return; + } + /* Deassert reset */ gpiod_set_value(ctx->enable_gpio, 1); usleep_range(1000, 1100); @@ -486,11 +494,16 @@ static void sn65dsi83_atomic_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); + int ret; /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ gpiod_set_value(ctx->enable_gpio, 0); usleep_range(10000, 11000); + ret = regulator_disable(ctx->vcc); + if (ret) + dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret); + regcache_mark_dirty(ctx->regmap); } @@ -599,6 +612,11 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) ctx->panel_bridge = panel_bridge; + ctx->vcc = devm_regulator_get(dev, "vcc"); + if (IS_ERR(ctx->vcc)) + return dev_err_probe(dev, PTR_ERR(ctx->vcc), + "Failed to get supply 'vcc'\n"); + return 0; } -- cgit v1.2.3 From 6844a28885183a5a2af92a8d315a59f7a0e668b9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 21 Dec 2021 21:37:54 +0200 Subject: drm/dbi: Use a static inline stub for mipi_dbi_debugfs_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the slightly odd "#define NULL" thing with a standard static inline stub. Cc: Noralf Trønnes Cc: Sam Ravnborg Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20211221193754.12287-2-ville.syrjala@linux.intel.com Reviewed-by: Jani Nikula --- include/drm/drm_mipi_dbi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_mipi_dbi.h b/include/drm/drm_mipi_dbi.h index 05e194958265..6fe13cce2670 100644 --- a/include/drm/drm_mipi_dbi.h +++ b/include/drm/drm_mipi_dbi.h @@ -194,7 +194,7 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, #ifdef CONFIG_DEBUG_FS void mipi_dbi_debugfs_init(struct drm_minor *minor); #else -#define mipi_dbi_debugfs_init NULL +static inline void mipi_dbi_debugfs_init(struct drm_minor *minor) {} #endif #endif /* __LINUX_MIPI_DBI_H */ -- cgit v1.2.3 From 6edf615618b8259f16eeb1df98f0ba0d2312c22e Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 29 Dec 2021 09:58:44 +0100 Subject: drm/bridge: sn65dsi83: Fix an error handling path in sn65dsi83_probe() sn65dsi83_parse_dt() takes a reference on 'ctx->host_node' that must be released in the error handling path of this function and of the probe. This is only done in the remove function up to now. Fixes: ceb515ba29ba ("drm/bridge: ti-sn65dsi83: Add TI SN65DSI83 and SN65DSI84 driver") Signed-off-by: Christophe JAILLET Reviewed-by: Laurent Pinchart Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/4bc21aed4b60d3d5ac4b28d8b07a6fdd8da6a536.1640768126.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 5650a793db81..19daaddd29a4 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -573,10 +573,14 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) ctx->host_node = of_graph_get_remote_port_parent(endpoint); of_node_put(endpoint); - if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) - return -EINVAL; - if (!ctx->host_node) - return -ENODEV; + if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) { + ret = -EINVAL; + goto err_put_node; + } + if (!ctx->host_node) { + ret = -ENODEV; + goto err_put_node; + } ctx->lvds_dual_link = false; ctx->lvds_dual_link_even_odd_swap = false; @@ -603,11 +607,13 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge); if (ret < 0) - return ret; + goto err_put_node; if (panel) { panel_bridge = devm_drm_panel_bridge_add(dev, panel); - if (IS_ERR(panel_bridge)) - return PTR_ERR(panel_bridge); + if (IS_ERR(panel_bridge)) { + ret = PTR_ERR(panel_bridge); + goto err_put_node; + } } ctx->panel_bridge = panel_bridge; @@ -618,6 +624,10 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) "Failed to get supply 'vcc'\n"); return 0; + +err_put_node: + of_node_put(ctx->host_node); + return ret; } static int sn65dsi83_host_attach(struct sn65dsi83 *ctx) @@ -692,8 +702,10 @@ static int sn65dsi83_probe(struct i2c_client *client, return ret; ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config); - if (IS_ERR(ctx->regmap)) - return PTR_ERR(ctx->regmap); + if (IS_ERR(ctx->regmap)) { + ret = PTR_ERR(ctx->regmap); + goto err_put_node; + } dev_set_drvdata(dev, ctx); i2c_set_clientdata(client, ctx); @@ -710,6 +722,8 @@ static int sn65dsi83_probe(struct i2c_client *client, err_remove_bridge: drm_bridge_remove(&ctx->bridge); +err_put_node: + of_node_put(ctx->host_node); return ret; } -- cgit v1.2.3 From 04b8a5d9cfd171f65df75f444b5617a372649edd Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 31 Dec 2021 00:55:14 +0100 Subject: drm/meson: osd_afbcd: Add an exit callback to struct meson_afbcd_ops Use this to simplify the driver shutdown. It will also come handy when fixing the error handling in meson_drv_bind_master(). Signed-off-by: Martin Blumenstingl Fixes: d1b5e41e13a7e9 ("drm/meson: Add AFBCD module driver") Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20211230235515.1627522-2-martin.blumenstingl@googlemail.com --- drivers/gpu/drm/meson/meson_drv.c | 6 ++--- drivers/gpu/drm/meson/meson_osd_afbcd.c | 41 ++++++++++++++++++++++----------- drivers/gpu/drm/meson/meson_osd_afbcd.h | 1 + 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 80f1d439841a..b919271a6e50 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -385,10 +385,8 @@ static void meson_drv_unbind(struct device *dev) free_irq(priv->vsync_irq, drm); drm_dev_put(drm); - if (priv->afbcd.ops) { - priv->afbcd.ops->reset(priv); - meson_rdma_free(priv); - } + if (priv->afbcd.ops) + priv->afbcd.ops->exit(priv); } static const struct component_master_ops meson_drv_master_ops = { diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.c b/drivers/gpu/drm/meson/meson_osd_afbcd.c index ffc6b584dbf8..0cdbe899402f 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.c +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.c @@ -79,11 +79,6 @@ static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format) return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0; } -static int meson_gxm_afbcd_init(struct meson_drm *priv) -{ - return 0; -} - static int meson_gxm_afbcd_reset(struct meson_drm *priv) { writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, @@ -93,6 +88,16 @@ static int meson_gxm_afbcd_reset(struct meson_drm *priv) return 0; } +static int meson_gxm_afbcd_init(struct meson_drm *priv) +{ + return 0; +} + +static void meson_gxm_afbcd_exit(struct meson_drm *priv) +{ + meson_gxm_afbcd_reset(priv); +} + static int meson_gxm_afbcd_enable(struct meson_drm *priv) { writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | @@ -172,6 +177,7 @@ static int meson_gxm_afbcd_setup(struct meson_drm *priv) struct meson_afbcd_ops meson_afbcd_gxm_ops = { .init = meson_gxm_afbcd_init, + .exit = meson_gxm_afbcd_exit, .reset = meson_gxm_afbcd_reset, .enable = meson_gxm_afbcd_enable, .disable = meson_gxm_afbcd_disable, @@ -269,6 +275,18 @@ static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format) return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0; } +static int meson_g12a_afbcd_reset(struct meson_drm *priv) +{ + meson_rdma_reset(priv); + + meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | + VIU_SW_RESET_G12A_OSD1_AFBCD, + VIU_SW_RESET); + meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); + + return 0; +} + static int meson_g12a_afbcd_init(struct meson_drm *priv) { int ret; @@ -286,16 +304,10 @@ static int meson_g12a_afbcd_init(struct meson_drm *priv) return 0; } -static int meson_g12a_afbcd_reset(struct meson_drm *priv) +static void meson_g12a_afbcd_exit(struct meson_drm *priv) { - meson_rdma_reset(priv); - - meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | - VIU_SW_RESET_G12A_OSD1_AFBCD, - VIU_SW_RESET); - meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); - - return 0; + meson_g12a_afbcd_reset(priv); + meson_rdma_free(priv); } static int meson_g12a_afbcd_enable(struct meson_drm *priv) @@ -380,6 +392,7 @@ static int meson_g12a_afbcd_setup(struct meson_drm *priv) struct meson_afbcd_ops meson_afbcd_g12a_ops = { .init = meson_g12a_afbcd_init, + .exit = meson_g12a_afbcd_exit, .reset = meson_g12a_afbcd_reset, .enable = meson_g12a_afbcd_enable, .disable = meson_g12a_afbcd_disable, diff --git a/drivers/gpu/drm/meson/meson_osd_afbcd.h b/drivers/gpu/drm/meson/meson_osd_afbcd.h index 5e5523304f42..e77ddeb6416f 100644 --- a/drivers/gpu/drm/meson/meson_osd_afbcd.h +++ b/drivers/gpu/drm/meson/meson_osd_afbcd.h @@ -14,6 +14,7 @@ struct meson_afbcd_ops { int (*init)(struct meson_drm *priv); + void (*exit)(struct meson_drm *priv); int (*reset)(struct meson_drm *priv); int (*enable)(struct meson_drm *priv); int (*disable)(struct meson_drm *priv); -- cgit v1.2.3 From fa747d75f65d1b1cbc3f4691fa67b695e8a399c8 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Fri, 31 Dec 2021 00:55:15 +0100 Subject: drm/meson: Fix error handling when afbcd.ops->init fails When afbcd.ops->init fails we need to free the struct drm_device. Also all errors which come after afbcd.ops->init was successful need to exit the AFBCD, just like meson_drv_unbind() does. Fixes: d1b5e41e13a7e9 ("drm/meson: Add AFBCD module driver") Signed-off-by: Martin Blumenstingl Acked-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20211230235515.1627522-3-martin.blumenstingl@googlemail.com --- drivers/gpu/drm/meson/meson_drv.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index b919271a6e50..26aeaf0ab86e 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -302,42 +302,42 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) if (priv->afbcd.ops) { ret = priv->afbcd.ops->init(priv); if (ret) - return ret; + goto free_drm; } /* Encoder Initialization */ ret = meson_encoder_cvbs_init(priv); if (ret) - goto free_drm; + goto exit_afbcd; if (has_components) { ret = component_bind_all(drm->dev, drm); if (ret) { dev_err(drm->dev, "Couldn't bind all components\n"); - goto free_drm; + goto exit_afbcd; } } ret = meson_encoder_hdmi_init(priv); if (ret) - goto free_drm; + goto exit_afbcd; ret = meson_plane_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; ret = meson_overlay_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; ret = meson_crtc_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); if (ret) - goto free_drm; + goto exit_afbcd; drm_mode_config_reset(drm); @@ -355,6 +355,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) uninstall_irq: free_irq(priv->vsync_irq, drm); +exit_afbcd: + if (priv->afbcd.ops) + priv->afbcd.ops->exit(priv); free_drm: drm_dev_put(drm); -- cgit v1.2.3 From 22f99f2db44771cf9569fc2e8c547ad3153d9384 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 18 Dec 2021 22:50:52 +0100 Subject: drm/stm: dsi: move lane capability detection in probe() There is no need to re-compute the dsi lane capability because it only depends on dsi hw version. Since dsi hw version is detected at probe(), move there also the assignment of dsi lane capability. Signed-off-by: Antonio Borneo Acked-by: Philippe Cornu Reviewed-by: Philippe Cornu Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211218215055.212421-1-antonio.borneo@foss.st.com --- drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 32cb41b2202f..480fdf256f01 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -247,14 +247,6 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, int ret, bpp; u32 val; - /* Update lane capabilities according to hw version */ - dsi->lane_min_kbps = LANE_MIN_KBPS; - dsi->lane_max_kbps = LANE_MAX_KBPS; - if (dsi->hw_version == HWVER_131) { - dsi->lane_min_kbps *= 2; - dsi->lane_max_kbps *= 2; - } - pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); /* Compute requested pll out */ @@ -417,6 +409,14 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) goto err_dsi_probe; } + /* set lane capabilities according to hw version */ + dsi->lane_min_kbps = LANE_MIN_KBPS; + dsi->lane_max_kbps = LANE_MAX_KBPS; + if (dsi->hw_version == HWVER_131) { + dsi->lane_min_kbps *= 2; + dsi->lane_max_kbps *= 2; + } + dw_mipi_dsi_stm_plat_data.base = dsi->base; dw_mipi_dsi_stm_plat_data.priv_data = dsi; -- cgit v1.2.3 From 5f4f958a0d9dfd7a569c56e76840e39b0c434378 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 18 Dec 2021 22:50:53 +0100 Subject: drm/bridge/synopsys: dsi: extend the prototype of mode_valid() To evaluate the validity of a video mode, some additional internal value has to be passed to the platform implementation. Extend the prototype of mode_valid(). Signed-off-by: Antonio Borneo Reviewed-by: Philippe Cornu Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211218215055.212421-2-antonio.borneo@foss.st.com --- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 5 ++++- include/drm/bridge/dw_mipi_dsi.h | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index e44e18a0112a..3f6564762e24 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -998,7 +998,10 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, enum drm_mode_status mode_status = MODE_OK; if (pdata->mode_valid) - mode_status = pdata->mode_valid(pdata->priv_data, mode); + mode_status = pdata->mode_valid(pdata->priv_data, mode, + dsi->mode_flags, + dw_mipi_dsi_get_lanes(dsi), + dsi->format); return mode_status; } diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index bda8aa7c2280..5286a53a1875 100644 --- a/include/drm/bridge/dw_mipi_dsi.h +++ b/include/drm/bridge/dw_mipi_dsi.h @@ -51,7 +51,9 @@ struct dw_mipi_dsi_plat_data { unsigned int max_data_lanes; enum drm_mode_status (*mode_valid)(void *priv_data, - const struct drm_display_mode *mode); + const struct drm_display_mode *mode, + unsigned long mode_flags, + u32 lanes, u32 format); const struct dw_mipi_dsi_phy_ops *phy_ops; const struct dw_mipi_dsi_host_ops *host_ops; -- cgit v1.2.3 From e01356d18273bd52bc88179f907b9d12978ebddd Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 18 Dec 2021 22:50:54 +0100 Subject: drm/stm: dsi: provide the implementation of mode_valid() The dsi has several constraints on the video modes it can support, mainly due to the frequencies that can be generated by the PLL integrated in the DSI device. Verify that the required HS clock can be generated by the PLL. The dsi clock from the dsi PLL and the ltdc pixel clock are asynchronous. The dsi needs to return in LP mode during HFP or HBP to re-synchronize at each video line. Verify that the duration of HFP and HBP allows the dsi to enter in LP mode. Signed-off-by: Antonio Borneo Acked-by: Philippe Cornu Reviewed-by: Philippe Cornu Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211218215055.212421-3-antonio.borneo@foss.st.com --- drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 98 +++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 480fdf256f01..89897d5f5c72 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -322,6 +322,103 @@ dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, return 0; } +#define CLK_TOLERANCE_HZ 50 + +static enum drm_mode_status +dw_mipi_dsi_stm_mode_valid(void *priv_data, + const struct drm_display_mode *mode, + unsigned long mode_flags, u32 lanes, u32 format) +{ + struct dw_mipi_dsi_stm *dsi = priv_data; + unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz; + int ret, bpp; + + bpp = mipi_dsi_pixel_format_to_bpp(format); + if (bpp < 0) + return MODE_BAD; + + /* Compute requested pll out */ + pll_out_khz = mode->clock * bpp / lanes; + + if (pll_out_khz > dsi->lane_max_kbps) + return MODE_CLOCK_HIGH; + + if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { + /* Add 20% to pll out to be higher than pixel bw */ + pll_out_khz = (pll_out_khz * 12) / 10; + } else { + if (pll_out_khz < dsi->lane_min_kbps) + return MODE_CLOCK_LOW; + } + + /* Compute best pll parameters */ + idf = 0; + ndiv = 0; + odf = 0; + pll_in_khz = clk_get_rate(dsi->pllref_clk) / 1000; + ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, &idf, &ndiv, &odf); + if (ret) { + DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); + return MODE_ERROR; + } + + if (!(mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) { + unsigned int px_clock_hz, target_px_clock_hz, lane_mbps; + int dsi_short_packet_size_px, hfp, hsync, hbp, delay_to_lp; + struct dw_mipi_dsi_dphy_timing dphy_timing; + + /* Get the adjusted pll out value */ + pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf); + + px_clock_hz = DIV_ROUND_CLOSEST_ULL(1000ULL * pll_out_khz * lanes, bpp); + target_px_clock_hz = mode->clock * 1000; + /* + * Filter modes according to the clock value, particularly useful for + * hdmi modes that require precise pixel clocks. + */ + if (px_clock_hz < target_px_clock_hz - CLK_TOLERANCE_HZ || + px_clock_hz > target_px_clock_hz + CLK_TOLERANCE_HZ) + return MODE_CLOCK_RANGE; + + /* sync packets are codes as DSI short packets (4 bytes) */ + dsi_short_packet_size_px = DIV_ROUND_UP(4 * BITS_PER_BYTE, bpp); + + hfp = mode->hsync_start - mode->hdisplay; + hsync = mode->hsync_end - mode->hsync_start; + hbp = mode->htotal - mode->hsync_end; + + /* hsync must be longer than 4 bytes HSS packets */ + if (hsync < dsi_short_packet_size_px) + return MODE_HSYNC_NARROW; + + if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { + /* HBP must be longer than 4 bytes HSE packets */ + if (hbp < dsi_short_packet_size_px) + return MODE_HSYNC_NARROW; + hbp -= dsi_short_packet_size_px; + } else { + /* With sync events HBP extends in the hsync */ + hbp += hsync - dsi_short_packet_size_px; + } + + lane_mbps = pll_out_khz / 1000; + ret = dw_mipi_dsi_phy_get_timing(priv_data, lane_mbps, &dphy_timing); + if (ret) + return MODE_ERROR; + /* + * In non-burst mode DSI has to enter in LP during HFP + * (horizontal front porch) or HBP (horizontal back porch) to + * resync with LTDC pixel clock. + */ + delay_to_lp = DIV_ROUND_UP((dphy_timing.data_hs2lp + dphy_timing.data_lp2hs) * + lanes * BITS_PER_BYTE, bpp); + if (hfp < delay_to_lp && hbp < delay_to_lp) + return MODE_HSYNC; + } + + return MODE_OK; +} + static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { .init = dw_mipi_dsi_phy_init, .power_on = dw_mipi_dsi_phy_power_on, @@ -332,6 +429,7 @@ static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = { .max_data_lanes = 2, + .mode_valid = dw_mipi_dsi_stm_mode_valid, .phy_ops = &dw_mipi_dsi_stm_phy_ops, }; -- cgit v1.2.3 From 3b26a2916844cf2680de10206e193e1d13f0eb88 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Fri, 19 Nov 2021 20:23:24 +0530 Subject: drm/bridge: chipone-icn6211: Switch to atomic operations Replace atomic version of the pre_enable/enable/post_disable operations to continue the transition to the atomic API. Also added default drm atomic operations for duplicate, destroy and reset state API's in order to have smooth transition on atomic API's. Tested on Allwinner R16/R40 DSI. Signed-off-by: Jagan Teki Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211119145325.1775046-1-jagan@amarulasolutions.com --- drivers/gpu/drm/bridge/chipone-icn6211.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index a6151db95586..77b3e2c29461 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -4,6 +4,7 @@ * Author: Jagan Teki */ +#include #include #include #include @@ -61,7 +62,8 @@ static inline int chipone_dsi_write(struct chipone *icn, const void *seq, chipone_dsi_write(icn, d, ARRAY_SIZE(d)); \ } -static void chipone_enable(struct drm_bridge *bridge) +static void chipone_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct chipone *icn = bridge_to_chipone(bridge); struct drm_display_mode *mode = bridge_to_mode(bridge); @@ -114,7 +116,8 @@ static void chipone_enable(struct drm_bridge *bridge) usleep_range(10000, 11000); } -static void chipone_pre_enable(struct drm_bridge *bridge) +static void chipone_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct chipone *icn = bridge_to_chipone(bridge); int ret; @@ -145,7 +148,8 @@ static void chipone_pre_enable(struct drm_bridge *bridge) usleep_range(10000, 11000); } -static void chipone_post_disable(struct drm_bridge *bridge) +static void chipone_atomic_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct chipone *icn = bridge_to_chipone(bridge); @@ -169,10 +173,13 @@ static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flag } static const struct drm_bridge_funcs chipone_bridge_funcs = { - .attach = chipone_attach, - .post_disable = chipone_post_disable, - .pre_enable = chipone_pre_enable, - .enable = chipone_enable, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_pre_enable = chipone_atomic_pre_enable, + .atomic_enable = chipone_atomic_enable, + .atomic_post_disable = chipone_atomic_post_disable, + .attach = chipone_attach, }; static int chipone_parse_dt(struct chipone *icn) -- cgit v1.2.3 From 50d76e3d3ec0c18dbe2c801af676f7e7cbedbff0 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Fri, 19 Nov 2021 20:23:25 +0530 Subject: drm/bridge: chipone-icn6211: Add mode_set API Get the display mode settings via mode_set bridge function instead of explicitly de-reference. Signed-off-by: Jagan Teki Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211119145325.1775046-2-jagan@amarulasolutions.com Reviewed-by: Robert Foss --- drivers/gpu/drm/bridge/chipone-icn6211.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index 77b3e2c29461..e8f36dca56b3 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -31,6 +31,7 @@ struct chipone { struct device *dev; struct drm_bridge bridge; + struct drm_display_mode mode; struct drm_bridge *panel_bridge; struct gpio_desc *enable_gpio; struct regulator *vdd1; @@ -43,11 +44,6 @@ static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge) return container_of(bridge, struct chipone, bridge); } -static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge) -{ - return &bridge->encoder->crtc->state->adjusted_mode; -} - static inline int chipone_dsi_write(struct chipone *icn, const void *seq, size_t len) { @@ -66,7 +62,7 @@ static void chipone_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct chipone *icn = bridge_to_chipone(bridge); - struct drm_display_mode *mode = bridge_to_mode(bridge); + struct drm_display_mode *mode = &icn->mode; ICN6211_DSI(icn, 0x7a, 0xc1); @@ -165,6 +161,15 @@ static void chipone_atomic_post_disable(struct drm_bridge *bridge, gpiod_set_value(icn->enable_gpio, 0); } +static void chipone_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct chipone *icn = bridge_to_chipone(bridge); + + drm_mode_copy(&icn->mode, adjusted_mode); +} + static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { struct chipone *icn = bridge_to_chipone(bridge); @@ -179,6 +184,7 @@ static const struct drm_bridge_funcs chipone_bridge_funcs = { .atomic_pre_enable = chipone_atomic_pre_enable, .atomic_enable = chipone_atomic_enable, .atomic_post_disable = chipone_atomic_post_disable, + .mode_set = chipone_mode_set, .attach = chipone_attach, }; -- cgit v1.2.3 From 7c442e76c06cb1bef16a6c523487438175584eea Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Mon, 27 Dec 2021 09:25:22 +0000 Subject: drm/bridge: Fix free wrong object in sii8620_init_rcp_input_dev rc_dev is allocated by rc_allocate_device(), and doesn't assigned to ctx->rc_dev before calling rc_free_device(ctx->rc_dev). So it should call rc_free_device(rc_dev); Fixes: e25f1f7c94e1 ("drm/bridge/sii8620: add remote control support") Signed-off-by: Miaoqian Lin Reviewed-by: Robert Foss Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211227092522.21755-1-linmq006@gmail.com --- drivers/gpu/drm/bridge/sil-sii8620.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 843265d7f1b1..ec7745c31da0 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) if (ret) { dev_err(ctx->dev, "Failed to register RC device\n"); ctx->error = ret; - rc_free_device(ctx->rc_dev); + rc_free_device(rc_dev); return; } ctx->rc_dev = rc_dev; -- cgit v1.2.3 From 77177c934c9a90002dbfead4067ba1f4ae0b5182 Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Mon, 6 Dec 2021 14:47:35 +0100 Subject: drm/stm: remove conflicting framebuffers In case of using simplefb or another conflicting framebuffer, call drm_aperture_remove_framebuffers() to remove memory allocated. Signed-off-by: Yannick Fertre Reviewed-by: Thomas Zimmermann Acked-by: Philippe Cornu Signed-off-by: Philippe Cornu Link: https://patchwork.freedesktop.org/patch/msgid/20211206134735.13537-1-yannick.fertre@foss.st.com --- drivers/gpu/drm/stm/drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 222869b232ae..9f441aadf2d5 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -183,6 +184,10 @@ static int stm_drm_platform_probe(struct platform_device *pdev) DRM_DEBUG("%s\n", __func__); + ret = drm_aperture_remove_framebuffers(false, &drv_driver); + if (ret) + return ret; + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); ddev = drm_dev_alloc(&drv_driver, dev); -- cgit v1.2.3 From 1726cee3d0537baa58dc58cf0a1630aa7ce93af7 Mon Sep 17 00:00:00 2001 From: Yannick Fertre Date: Fri, 3 Dec 2021 09:56:18 +0100 Subject: drm/stm: ltdc: support of new hardware version Add support of new hardware version 0x40100. Signed-off-by: Yannick Fertre Reviewed-by: Raphael Gallais-Pou Tested-by: Raphael Gallais-Pou Acked-by: Philippe Cornu Signed-off-by: Philippe Cornu Link: https://patchwork.freedesktop.org/patch/msgid/20211203085618.11314-1-yannick.fertre@foss.st.com --- drivers/gpu/drm/stm/ltdc.c | 172 +++++++++++++++++++++++++++++++++++++-------- drivers/gpu/drm/stm/ltdc.h | 3 +- 2 files changed, 145 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index dbdee954692a..c0619f372630 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -46,15 +46,15 @@ #define HWVER_10200 0x010200 #define HWVER_10300 0x010300 #define HWVER_20101 0x020101 +#define HWVER_40100 0x040100 /* * The address of some registers depends on the HW version: such registers have - * an extra offset specified with reg_ofs. + * an extra offset specified with layer_ofs. */ -#define REG_OFS_NONE 0 -#define REG_OFS_4 4 /* Insertion of "Layer Conf. 2" reg */ -#define REG_OFS (ldev->caps.reg_ofs) -#define LAY_OFS 0x80 /* Register Offset between 2 layers */ +#define LAY_OFS_0 0x80 +#define LAY_OFS_1 0x100 +#define LAY_OFS (ldev->caps.layer_ofs) /* Global register offsets */ #define LTDC_IDR 0x0000 /* IDentification */ @@ -75,29 +75,34 @@ #define LTDC_LIPCR 0x0040 /* Line Interrupt Position Conf. */ #define LTDC_CPSR 0x0044 /* Current Position Status */ #define LTDC_CDSR 0x0048 /* Current Display Status */ +#define LTDC_FUT 0x0090 /* Fifo underrun Threshold */ /* Layer register offsets */ -#define LTDC_L1LC1R (0x80) /* L1 Layer Configuration 1 */ -#define LTDC_L1LC2R (0x84) /* L1 Layer Configuration 2 */ -#define LTDC_L1CR (0x84 + REG_OFS)/* L1 Control */ -#define LTDC_L1WHPCR (0x88 + REG_OFS)/* L1 Window Hor Position Config */ -#define LTDC_L1WVPCR (0x8C + REG_OFS)/* L1 Window Vert Position Config */ -#define LTDC_L1CKCR (0x90 + REG_OFS)/* L1 Color Keying Configuration */ -#define LTDC_L1PFCR (0x94 + REG_OFS)/* L1 Pixel Format Configuration */ -#define LTDC_L1CACR (0x98 + REG_OFS)/* L1 Constant Alpha Config */ -#define LTDC_L1DCCR (0x9C + REG_OFS)/* L1 Default Color Configuration */ -#define LTDC_L1BFCR (0xA0 + REG_OFS)/* L1 Blend Factors Configuration */ -#define LTDC_L1FBBCR (0xA4 + REG_OFS)/* L1 FrameBuffer Bus Control */ -#define LTDC_L1AFBCR (0xA8 + REG_OFS)/* L1 AuxFB Control */ -#define LTDC_L1CFBAR (0xAC + REG_OFS)/* L1 Color FrameBuffer Address */ -#define LTDC_L1CFBLR (0xB0 + REG_OFS)/* L1 Color FrameBuffer Length */ -#define LTDC_L1CFBLNR (0xB4 + REG_OFS)/* L1 Color FrameBuffer Line Nb */ -#define LTDC_L1AFBAR (0xB8 + REG_OFS)/* L1 AuxFB Address */ -#define LTDC_L1AFBLR (0xBC + REG_OFS)/* L1 AuxFB Length */ -#define LTDC_L1AFBLNR (0xC0 + REG_OFS)/* L1 AuxFB Line Number */ -#define LTDC_L1CLUTWR (0xC4 + REG_OFS)/* L1 CLUT Write */ -#define LTDC_L1YS1R (0xE0 + REG_OFS)/* L1 YCbCr Scale 1 */ -#define LTDC_L1YS2R (0xE4 + REG_OFS)/* L1 YCbCr Scale 2 */ +#define LTDC_L1C0R (ldev->caps.layer_regs[0]) /* L1 configuration 0 */ +#define LTDC_L1C1R (ldev->caps.layer_regs[1]) /* L1 configuration 1 */ +#define LTDC_L1RCR (ldev->caps.layer_regs[2]) /* L1 reload control */ +#define LTDC_L1CR (ldev->caps.layer_regs[3]) /* L1 control register */ +#define LTDC_L1WHPCR (ldev->caps.layer_regs[4]) /* L1 window horizontal position configuration */ +#define LTDC_L1WVPCR (ldev->caps.layer_regs[5]) /* L1 window vertical position configuration */ +#define LTDC_L1CKCR (ldev->caps.layer_regs[6]) /* L1 color keying configuration */ +#define LTDC_L1PFCR (ldev->caps.layer_regs[7]) /* L1 pixel format configuration */ +#define LTDC_L1CACR (ldev->caps.layer_regs[8]) /* L1 constant alpha configuration */ +#define LTDC_L1DCCR (ldev->caps.layer_regs[9]) /* L1 default color configuration */ +#define LTDC_L1BFCR (ldev->caps.layer_regs[10]) /* L1 blending factors configuration */ +#define LTDC_L1BLCR (ldev->caps.layer_regs[11]) /* L1 burst length configuration */ +#define LTDC_L1PCR (ldev->caps.layer_regs[12]) /* L1 planar configuration */ +#define LTDC_L1CFBAR (ldev->caps.layer_regs[13]) /* L1 color frame buffer address */ +#define LTDC_L1CFBLR (ldev->caps.layer_regs[14]) /* L1 color frame buffer length */ +#define LTDC_L1CFBLNR (ldev->caps.layer_regs[15]) /* L1 color frame buffer line number */ +#define LTDC_L1AFBA0R (ldev->caps.layer_regs[16]) /* L1 auxiliary frame buffer address 0 */ +#define LTDC_L1AFBA1R (ldev->caps.layer_regs[17]) /* L1 auxiliary frame buffer address 1 */ +#define LTDC_L1AFBLR (ldev->caps.layer_regs[18]) /* L1 auxiliary frame buffer length */ +#define LTDC_L1AFBLNR (ldev->caps.layer_regs[19]) /* L1 auxiliary frame buffer line number */ +#define LTDC_L1CLUTWR (ldev->caps.layer_regs[20]) /* L1 CLUT write */ +#define LTDC_L1CYR0R (ldev->caps.layer_regs[21]) /* L1 Conversion YCbCr RGB 0 */ +#define LTDC_L1CYR1R (ldev->caps.layer_regs[22]) /* L1 Conversion YCbCr RGB 1 */ +#define LTDC_L1FPF0R (ldev->caps.layer_regs[23]) /* L1 Flexible Pixel Format 0 */ +#define LTDC_L1FPF1R (ldev->caps.layer_regs[24]) /* L1 Flexible Pixel Format 1 */ /* Bit definitions */ #define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */ @@ -208,7 +213,10 @@ enum ltdc_pix_fmt { /* Indexed formats */ PF_L8, /* Indexed 8 bits [8 bits] */ PF_AL44, /* Alpha:4 bits + indexed 4 bits [8 bits] */ - PF_AL88 /* Alpha:8 bits + indexed 8 bits [16 bits] */ + PF_AL88, /* Alpha:8 bits + indexed 8 bits [16 bits] */ + PF_ABGR8888, /* ABGR [32 bits] */ + PF_BGRA8888, /* BGRA [32 bits] */ + PF_BGR565 /* RGB [16 bits] */ }; /* The index gives the encoding of the pixel format for an HW version */ @@ -234,6 +242,102 @@ static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = { PF_ARGB4444 /* 0x07 */ }; +static const enum ltdc_pix_fmt ltdc_pix_fmt_a2[NB_PF] = { + PF_ARGB8888, /* 0x00 */ + PF_ABGR8888, /* 0x01 */ + PF_RGBA8888, /* 0x02 */ + PF_BGRA8888, /* 0x03 */ + PF_RGB565, /* 0x04 */ + PF_BGR565, /* 0x05 */ + PF_RGB888, /* 0x06 */ + PF_ARGB1555 /* 0x07 */ +}; + +/* Layer register offsets */ +static const u32 ltdc_layer_regs_a0[] = { + 0x80, /* L1 configuration 0 */ + 0x00, /* not available */ + 0x00, /* not available */ + 0x84, /* L1 control register */ + 0x88, /* L1 window horizontal position configuration */ + 0x8c, /* L1 window vertical position configuration */ + 0x90, /* L1 color keying configuration */ + 0x94, /* L1 pixel format configuration */ + 0x98, /* L1 constant alpha configuration */ + 0x9c, /* L1 default color configuration */ + 0xa0, /* L1 blending factors configuration */ + 0x00, /* not available */ + 0x00, /* not available */ + 0xac, /* L1 color frame buffer address */ + 0xb0, /* L1 color frame buffer length */ + 0xb4, /* L1 color frame buffer line number */ + 0x00, /* not available */ + 0x00, /* not available */ + 0x00, /* not available */ + 0x00, /* not available */ + 0xc4, /* L1 CLUT write */ + 0x00, /* not available */ + 0x00, /* not available */ + 0x00, /* not available */ + 0x00 /* not available */ +}; + +static const u32 ltdc_layer_regs_a1[] = { + 0x80, /* L1 configuration 0 */ + 0x84, /* L1 configuration 1 */ + 0x00, /* L1 reload control */ + 0x88, /* L1 control register */ + 0x8c, /* L1 window horizontal position configuration */ + 0x90, /* L1 window vertical position configuration */ + 0x94, /* L1 color keying configuration */ + 0x98, /* L1 pixel format configuration */ + 0x9c, /* L1 constant alpha configuration */ + 0xa0, /* L1 default color configuration */ + 0xa4, /* L1 blending factors configuration */ + 0xa8, /* L1 burst length configuration */ + 0x00, /* not available */ + 0xac, /* L1 color frame buffer address */ + 0xb0, /* L1 color frame buffer length */ + 0xb4, /* L1 color frame buffer line number */ + 0xb8, /* L1 auxiliary frame buffer address 0 */ + 0xbc, /* L1 auxiliary frame buffer address 1 */ + 0xc0, /* L1 auxiliary frame buffer length */ + 0xc4, /* L1 auxiliary frame buffer line number */ + 0xc8, /* L1 CLUT write */ + 0x00, /* not available */ + 0x00, /* not available */ + 0x00, /* not available */ + 0x00 /* not available */ +}; + +static const u32 ltdc_layer_regs_a2[] = { + 0x100, /* L1 configuration 0 */ + 0x104, /* L1 configuration 1 */ + 0x108, /* L1 reload control */ + 0x10c, /* L1 control register */ + 0x110, /* L1 window horizontal position configuration */ + 0x114, /* L1 window vertical position configuration */ + 0x118, /* L1 color keying configuration */ + 0x11c, /* L1 pixel format configuration */ + 0x120, /* L1 constant alpha configuration */ + 0x124, /* L1 default color configuration */ + 0x128, /* L1 blending factors configuration */ + 0x12c, /* L1 burst length configuration */ + 0x130, /* L1 planar configuration */ + 0x134, /* L1 color frame buffer address */ + 0x138, /* L1 color frame buffer length */ + 0x13c, /* L1 color frame buffer line number */ + 0x140, /* L1 auxiliary frame buffer address 0 */ + 0x144, /* L1 auxiliary frame buffer address 1 */ + 0x148, /* L1 auxiliary frame buffer length */ + 0x14c, /* L1 auxiliary frame buffer line number */ + 0x150, /* L1 CLUT write */ + 0x16c, /* L1 Conversion YCbCr RGB 0 */ + 0x170, /* L1 Conversion YCbCr RGB 1 */ + 0x174, /* L1 Flexible Pixel Format 0 */ + 0x178 /* L1 Flexible Pixel Format 1 */ +}; + static const u64 ltdc_format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID @@ -1158,7 +1262,8 @@ static int ltdc_get_caps(struct drm_device *ddev) switch (ldev->caps.hw_version) { case HWVER_10200: case HWVER_10300: - ldev->caps.reg_ofs = REG_OFS_NONE; + ldev->caps.layer_ofs = LAY_OFS_0; + ldev->caps.layer_regs = ltdc_layer_regs_a0; ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; /* * Hw older versions support non-alpha color formats derived @@ -1174,12 +1279,21 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.nb_irq = 2; break; case HWVER_20101: - ldev->caps.reg_ofs = REG_OFS_4; + ldev->caps.layer_ofs = LAY_OFS_0; + ldev->caps.layer_regs = ltdc_layer_regs_a1; ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; ldev->caps.non_alpha_only_l1 = false; ldev->caps.pad_max_freq_hz = 150000000; ldev->caps.nb_irq = 4; break; + case HWVER_40100: + ldev->caps.layer_ofs = LAY_OFS_1; + ldev->caps.layer_regs = ltdc_layer_regs_a2; + ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a2; + ldev->caps.non_alpha_only_l1 = false; + ldev->caps.pad_max_freq_hz = 90000000; + ldev->caps.nb_irq = 2; + break; default: return -ENODEV; } diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index f153b908c70e..55a125f89af6 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -14,7 +14,8 @@ struct ltdc_caps { u32 hw_version; /* hardware version */ u32 nb_layers; /* number of supported layers */ - u32 reg_ofs; /* register offset for applicable regs */ + u32 layer_ofs; /* layer offset for applicable regs */ + const u32 *layer_regs; /* layer register offset */ u32 bus_width; /* bus width (32 or 64 bits) */ const u32 *pix_fmt_hw; /* supported pixel formats */ bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ -- cgit v1.2.3 From 7020449b8f5ac0f7444a584645edec02f7168f1a Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Fri, 19 Nov 2021 09:58:04 +0800 Subject: drm/bridge: anx7625: Check GPIO description to avoid crash As GPIO probe function "devm_gpiod_get_optional()" may return error code, driver should identify GPIO desc as NULL to avoid crash. Acked-by: Tzung-Bi Shih Signed-off-by: Xin Ji Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211119015804.3824027-1-xji@analogixsemi.com Reviewed-by: Robert Foss --- drivers/gpu/drm/bridge/analogix/anx7625.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 2346dbcc505f..9765ac07f46d 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1098,9 +1098,18 @@ static void anx7625_init_gpio(struct anx7625_data *platform) /* Gpio for chip power enable */ platform->pdata.gpio_p_on = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR_OR_NULL(platform->pdata.gpio_p_on)) { + DRM_DEV_DEBUG_DRIVER(dev, "no enable gpio found\n"); + platform->pdata.gpio_p_on = NULL; + } + /* Gpio for chip reset */ platform->pdata.gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR_OR_NULL(platform->pdata.gpio_reset)) { + DRM_DEV_DEBUG_DRIVER(dev, "no reset gpio found\n"); + platform->pdata.gpio_reset = NULL; + } if (platform->pdata.gpio_p_on && platform->pdata.gpio_reset) { platform->pdata.low_power_mode = 1; -- cgit v1.2.3 From f5f05ddc37e0445567e4a2369b73ecf9ee2e187d Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 22 Dec 2021 08:33:48 +0000 Subject: drm/bridge: anx7625: Fix null vs IS_ERR() checking in anx7625_register_i2c_dummy_clients Since i2c_new_client_device() function return error pointers. The i2c_new_dummy_device() function does not return NULL, It returns error pointers too. Using IS_ERR() to check the return value to fix this. Fixes: 8bdfc5dae4e3("drm/bridge: anx7625: Add anx7625 MIPI DSI/DPI to DP") Signed-off-by: Miaoqian Lin Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211222083350.18514-1-linmq006@gmail.com Reviewed-by: Robert Foss --- drivers/gpu/drm/bridge/analogix/anx7625.c | 32 ++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 9765ac07f46d..7b24213f7b13 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1971,40 +1971,54 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, struct i2c_client *client) { + int err = 0; + ctx->i2c.tx_p0_client = i2c_new_dummy_device(client->adapter, TX_P0_ADDR >> 1); - if (!ctx->i2c.tx_p0_client) - return -ENOMEM; + if (IS_ERR(ctx->i2c.tx_p0_client)) + return PTR_ERR(ctx->i2c.tx_p0_client); ctx->i2c.tx_p1_client = i2c_new_dummy_device(client->adapter, TX_P1_ADDR >> 1); - if (!ctx->i2c.tx_p1_client) + if (IS_ERR(ctx->i2c.tx_p1_client)) { + err = PTR_ERR(ctx->i2c.tx_p1_client); goto free_tx_p0; + } ctx->i2c.tx_p2_client = i2c_new_dummy_device(client->adapter, TX_P2_ADDR >> 1); - if (!ctx->i2c.tx_p2_client) + if (IS_ERR(ctx->i2c.tx_p2_client)) { + err = PTR_ERR(ctx->i2c.tx_p2_client); goto free_tx_p1; + } ctx->i2c.rx_p0_client = i2c_new_dummy_device(client->adapter, RX_P0_ADDR >> 1); - if (!ctx->i2c.rx_p0_client) + if (IS_ERR(ctx->i2c.rx_p0_client)) { + err = PTR_ERR(ctx->i2c.rx_p0_client); goto free_tx_p2; + } ctx->i2c.rx_p1_client = i2c_new_dummy_device(client->adapter, RX_P1_ADDR >> 1); - if (!ctx->i2c.rx_p1_client) + if (IS_ERR(ctx->i2c.rx_p1_client)) { + err = PTR_ERR(ctx->i2c.rx_p1_client); goto free_rx_p0; + } ctx->i2c.rx_p2_client = i2c_new_dummy_device(client->adapter, RX_P2_ADDR >> 1); - if (!ctx->i2c.rx_p2_client) + if (IS_ERR(ctx->i2c.rx_p2_client)) { + err = PTR_ERR(ctx->i2c.rx_p2_client); goto free_rx_p1; + } ctx->i2c.tcpc_client = i2c_new_dummy_device(client->adapter, TCPC_INTERFACE_ADDR >> 1); - if (!ctx->i2c.tcpc_client) + if (IS_ERR(ctx->i2c.tcpc_client)) { + err = PTR_ERR(ctx->i2c.tcpc_client); goto free_rx_p2; + } return 0; @@ -2021,7 +2035,7 @@ free_tx_p1: free_tx_p0: i2c_unregister_device(ctx->i2c.tx_p0_client); - return -ENOMEM; + return err; } static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx) -- cgit v1.2.3 From 92e794fab87af0793403d5e4a547f0be94a0e656 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 22 Nov 2021 12:36:32 +0530 Subject: drm: exynos: dsi: Convert to bridge driver Some display panels would come up with a non-DSI output, those can have an option to connect the DSI host by means of interface bridge converter. This DSI to non-DSI interface bridge converter would requires DSI Host to handle drm bridge functionalities in order to DSI Host to Interface bridge. This patch convert the existing to a drm bridge driver with a built-in encoder support for compatibility with existing component drivers. Signed-off-by: Jagan Teki Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211122070633.89219-2-jagan@amarulasolutions.com --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 73 +++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 8d137857818c..174590f543c3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -257,6 +257,7 @@ struct exynos_dsi { struct drm_connector connector; struct drm_panel *panel; struct list_head bridge_chain; + struct drm_bridge bridge; struct drm_bridge *out_bridge; struct device *dev; @@ -287,9 +288,9 @@ struct exynos_dsi { #define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) #define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) -static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e) +static inline struct exynos_dsi *bridge_to_dsi(struct drm_bridge *b) { - return container_of(e, struct exynos_dsi, encoder); + return container_of(b, struct exynos_dsi, bridge); } enum reg_idx { @@ -1374,9 +1375,10 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) } } -static void exynos_dsi_enable(struct drm_encoder *encoder) +static void exynos_dsi_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { - struct exynos_dsi *dsi = encoder_to_dsi(encoder); + struct exynos_dsi *dsi = bridge_to_dsi(bridge); struct drm_bridge *iter; int ret; @@ -1399,7 +1401,8 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) { if (iter->funcs->pre_enable) - iter->funcs->pre_enable(iter); + iter->funcs->atomic_pre_enable(iter, + old_bridge_state); } } @@ -1413,7 +1416,7 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) } else { list_for_each_entry(iter, &dsi->bridge_chain, chain_node) { if (iter->funcs->enable) - iter->funcs->enable(iter); + iter->funcs->atomic_enable(iter, old_bridge_state); } } @@ -1429,9 +1432,10 @@ err_put_sync: pm_runtime_put(dsi->dev); } -static void exynos_dsi_disable(struct drm_encoder *encoder) +static void exynos_dsi_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { - struct exynos_dsi *dsi = encoder_to_dsi(encoder); + struct exynos_dsi *dsi = bridge_to_dsi(bridge); struct drm_bridge *iter; if (!(dsi->state & DSIM_STATE_ENABLED)) @@ -1443,7 +1447,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) list_for_each_entry_reverse(iter, &dsi->bridge_chain, chain_node) { if (iter->funcs->disable) - iter->funcs->disable(iter); + iter->funcs->atomic_disable(iter, old_bridge_state); } exynos_dsi_set_display_enable(dsi, false); @@ -1451,7 +1455,7 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) list_for_each_entry(iter, &dsi->bridge_chain, chain_node) { if (iter->funcs->post_disable) - iter->funcs->post_disable(iter); + iter->funcs->atomic_post_disable(iter, old_bridge_state); } dsi->state &= ~DSIM_STATE_ENABLED; @@ -1494,9 +1498,9 @@ static const struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs .get_modes = exynos_dsi_get_modes, }; -static int exynos_dsi_create_connector(struct drm_encoder *encoder) +static int exynos_dsi_create_connector(struct exynos_dsi *dsi) { - struct exynos_dsi *dsi = encoder_to_dsi(encoder); + struct drm_encoder *encoder = &dsi->encoder; struct drm_connector *connector = &dsi->connector; struct drm_device *drm = encoder->dev; int ret; @@ -1522,9 +1526,21 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) return 0; } -static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { - .enable = exynos_dsi_enable, - .disable = exynos_dsi_disable, +static int exynos_dsi_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct exynos_dsi *dsi = bridge_to_dsi(bridge); + + return drm_bridge_attach(bridge->encoder, dsi->out_bridge, NULL, 0); +} + +static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_enable = exynos_dsi_atomic_enable, + .atomic_disable = exynos_dsi_atomic_disable, + .attach = exynos_dsi_attach, }; MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); @@ -1543,7 +1559,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, dsi->out_bridge = out_bridge; list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain); } else { - int ret = exynos_dsi_create_connector(encoder); + int ret = exynos_dsi_create_connector(dsi); if (ret) { DRM_DEV_ERROR(dsi->dev, @@ -1596,7 +1612,7 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, if (dsi->panel) { mutex_lock(&drm->mode_config.mutex); - exynos_dsi_disable(&dsi->encoder); + exynos_dsi_atomic_disable(&dsi->bridge, NULL); dsi->panel = NULL; dsi->connector.status = connector_status_disconnected; mutex_unlock(&drm->mode_config.mutex); @@ -1702,12 +1718,16 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs); - ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); if (ret < 0) return ret; + ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, 0); + if (ret) { + drm_encoder_cleanup(&dsi->encoder); + return ret; + } + in_bridge_node = of_graph_get_remote_node(dev->of_node, DSI_PORT_IN, 0); if (in_bridge_node) { in_bridge = of_drm_find_bridge(in_bridge_node); @@ -1723,10 +1743,9 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master, void *data) { struct exynos_dsi *dsi = dev_get_drvdata(dev); - struct drm_encoder *encoder = &dsi->encoder; - - exynos_dsi_disable(encoder); + exynos_dsi_atomic_disable(&dsi->bridge, NULL); + drm_encoder_cleanup(&dsi->encoder); mipi_dsi_host_unregister(&dsi->dsi_host); } @@ -1819,6 +1838,12 @@ static int exynos_dsi_probe(struct platform_device *pdev) pm_runtime_enable(dev); + dsi->bridge.funcs = &exynos_dsi_bridge_funcs; + dsi->bridge.of_node = dev->of_node; + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; + + drm_bridge_add(&dsi->bridge); + ret = component_add(dev, &exynos_dsi_component_ops); if (ret) goto err_disable_runtime; @@ -1833,6 +1858,10 @@ err_disable_runtime: static int exynos_dsi_remove(struct platform_device *pdev) { + struct exynos_dsi *dsi = platform_get_drvdata(pdev); + + drm_bridge_remove(&dsi->bridge); + pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &exynos_dsi_component_ops); -- cgit v1.2.3 From aee039e66035b66f0c587cc1b0dd32fb04c9a892 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 22 Nov 2021 12:36:33 +0530 Subject: drm: exynos: dsi: Add mode_set function Get the display mode settings via mode_set bridge function instead of explicitly de-reference. Signed-off-by: Jagan Teki Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20211122070633.89219-3-jagan@amarulasolutions.com --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 174590f543c3..3d4713346949 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -260,6 +260,7 @@ struct exynos_dsi { struct drm_bridge bridge; struct drm_bridge *out_bridge; struct device *dev; + struct drm_display_mode mode; void __iomem *reg_base; struct phy *phy; @@ -883,7 +884,7 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) { - struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode; + struct drm_display_mode *m = &dsi->mode; unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; u32 reg; @@ -1526,6 +1527,15 @@ static int exynos_dsi_create_connector(struct exynos_dsi *dsi) return 0; } +static void exynos_dsi_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) +{ + struct exynos_dsi *dsi = bridge_to_dsi(bridge); + + drm_mode_copy(&dsi->mode, adjusted_mode); +} + static int exynos_dsi_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -1540,6 +1550,7 @@ static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = { .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_enable = exynos_dsi_atomic_enable, .atomic_disable = exynos_dsi_atomic_disable, + .mode_set = exynos_dsi_mode_set, .attach = exynos_dsi_attach, }; -- cgit v1.2.3 From 9294914dd5507eca56566c470c56327f46dfd4fa Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 5 Jan 2022 10:08:02 +0100 Subject: drm/bridge: parade-ps8640: Link device to ensure suspend/resume order Entering suspend while the display attached to this bridge is still on makes the resume sequence to resume the bridge first, display last: when this happens, we get a timeout while resuming the bridge, as its MCU will get stuck due to the display being unpowered. On the other hand, on mt8173-elm, closing the lid makes the display to get powered off first, bridge last, so at resume time the sequence is swapped (compared to the first example) and everything just works as expected. Add a stateless device link to the DRM device that this bridge belongs to, ensuring a correct resume sequence and solving the unability to correctly resume bridge operation in the first mentioned example. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220105090802.73564-1-angelogioacchino.delregno@collabora.com Reviewed-by: Robert Foss --- drivers/gpu/drm/bridge/parade-ps8640.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 818704bf5e86..54723f068884 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -102,6 +102,7 @@ struct ps8640 { struct regulator_bulk_data supplies[2]; struct gpio_desc *gpio_reset; struct gpio_desc *gpio_powerdown; + struct device_link *link; bool pre_enabled; }; @@ -456,14 +457,36 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, return ret; } + ps_bridge->link = device_link_add(bridge->dev->dev, dev, DL_FLAG_STATELESS); + if (!ps_bridge->link) { + dev_err(dev, "failed to create device link"); + ret = -EINVAL; + goto err_devlink; + } + /* Attach the panel-bridge to the dsi bridge */ - return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, - &ps_bridge->bridge, flags); + ret = drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, + &ps_bridge->bridge, flags); + if (ret) + goto err_bridge_attach; + + return 0; + +err_bridge_attach: + device_link_del(ps_bridge->link); +err_devlink: + drm_dp_aux_unregister(&ps_bridge->aux); + + return ret; } static void ps8640_bridge_detach(struct drm_bridge *bridge) { - drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux); + struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); + + drm_dp_aux_unregister(&ps_bridge->aux); + if (ps_bridge->link) + device_link_del(ps_bridge->link); } static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, -- cgit v1.2.3 From 96211b7c56b109a52768e6cc5e23a1f79316eca0 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 5 Jan 2022 10:41:09 +0000 Subject: drm/bridge: Add missing pm_runtime_disable() in __dw_mipi_dsi_probe If the probe fails, we should use pm_runtime_disable() to balance pm_runtime_enable(). Add missing pm_runtime_disable() for __dw_mipi_dsi_probe. Fixes: 46fc51546d44 ("drm/bridge/synopsys: Add MIPI DSI host controller bridge") Signed-off-by: Miaoqian Lin Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220105104113.31415-1-linmq006@gmail.com Reviewed-by: Robert Foss --- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c index 3f6564762e24..2a58b0b7ace5 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -1202,6 +1202,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, ret = mipi_dsi_host_register(&dsi->dsi_host); if (ret) { dev_err(dev, "Failed to register MIPI host: %d\n", ret); + pm_runtime_disable(dev); dw_mipi_dsi_debugfs_remove(dsi); return ERR_PTR(ret); } -- cgit v1.2.3 From b146e343a9e05605b491b1bf4a2b62a39d5638d8 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 5 Jan 2022 10:48:26 +0000 Subject: drm/bridge: nwl-dsi: Fix PM disable depth imbalance in nwl_dsi_probe The pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced according to context. Fixes: 44cfc6233447 ("drm/bridge: Add NWL MIPI DSI host controller support") Signed-off-by: Miaoqian Lin Signed-off-by: Robert Foss Link: https://patchwork.freedesktop.org/patch/msgid/20220105104826.1418-1-linmq006@gmail.com Reviewed-by: Robert Foss --- drivers/gpu/drm/bridge/nwl-dsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c index a7389a0facfb..fc3ad9fab867 100644 --- a/drivers/gpu/drm/bridge/nwl-dsi.c +++ b/drivers/gpu/drm/bridge/nwl-dsi.c @@ -1206,6 +1206,7 @@ static int nwl_dsi_probe(struct platform_device *pdev) ret = nwl_dsi_select_input(dsi); if (ret < 0) { + pm_runtime_disable(dev); mipi_dsi_host_unregister(&dsi->dsi_host); return ret; } -- cgit v1.2.3 From d14f0c205302648df29c494a1a81ec3d897a2552 Mon Sep 17 00:00:00 2001 From: José Expósito Date: Sun, 26 Dec 2021 12:24:58 +0100 Subject: drm/plane: Make format_mod_supported truly optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation for "drm_plane_funcs.format_mod_supported" reads: This *optional* hook is used for the DRM to determine if the given format/modifier combination is valid for the plane. This allows the DRM to generate the correct format bitmask (which formats apply to which modifier), and to validate modifiers at atomic_check time. *If not present*, then any modifier in the plane's modifier list is allowed with any of the plane's formats. However, where the function is not present, an invalid IN_FORMATS blob property with modifiers but no formats is exposed to user-space. This breaks the latest Weston [1]. For testing purposes, I extracted the affected code to a standalone program [2]. Make "create_in_format_blob" behave as documented. [1] https://gitlab.freedesktop.org/wayland/weston/-/blob/9.0/libweston/backend-drm/kms.c#L431 [2] https://github.com/JoseExposito/drm-sandbox/blob/main/in_formats.c Signed-off-by: José Expósito Reviewed-by: Simon Ser Signed-off-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20211226112503.31771-2-jose.exposito89@gmail.com --- drivers/gpu/drm/drm_plane.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 82afb854141b..deeec60a3315 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -202,17 +202,13 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane memcpy(formats_ptr(blob_data), plane->format_types, formats_size); - /* If we can't determine support, just bail */ - if (!plane->funcs->format_mod_supported) - goto done; - mod = modifiers_ptr(blob_data); for (i = 0; i < plane->modifier_count; i++) { for (j = 0; j < plane->format_count; j++) { - if (plane->funcs->format_mod_supported(plane, + if (!plane->funcs->format_mod_supported || + plane->funcs->format_mod_supported(plane, plane->format_types[j], plane->modifiers[i])) { - mod->formats |= 1ULL << j; } } @@ -223,7 +219,6 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane mod++; } -done: drm_object_attach_property(&plane->base, config->modifiers_property, blob->base.id); -- cgit v1.2.3 From 91d8531393be96b4a088290cc67233b2e6ab072f Mon Sep 17 00:00:00 2001 From: José Expósito Date: Sun, 26 Dec 2021 12:24:59 +0100 Subject: drm/plane: Fix typo in format_mod_supported documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix minor typo: "valdiate" -> "validate". Signed-off-by: José Expósito Reviewed-by: Simon Ser Signed-off-by: Simon Ser Link: https://patchwork.freedesktop.org/patch/msgid/20211226112503.31771-3-jose.exposito89@gmail.com --- include/drm/drm_plane.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index 0c1102dc4d88..06759badf99f 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -516,7 +516,7 @@ struct drm_plane_funcs { * This optional hook is used for the DRM to determine if the given * format/modifier combination is valid for the plane. This allows the * DRM to generate the correct format bitmask (which formats apply to - * which modifier), and to valdiate modifiers at atomic_check time. + * which modifier), and to validate modifiers at atomic_check time. * * If not present, then any modifier in the plane's modifier * list is allowed with any of the plane's formats. -- cgit v1.2.3 From 506d9d7414cfbdce02b7126fc8644f04ef234680 Mon Sep 17 00:00:00 2001 From: yangcong Date: Fri, 31 Dec 2021 12:50:56 +0800 Subject: drm/panel: Update Boe-tv110c9m initial code Optimize two problems a)Turn off low voltage detection register.During the esd test, the low-voltage detection ic may be triggered to enter the slpin state, so a black screen occurs on the panel. b)Optimize CMD2 page1 gamma. Signed-off-by: yangcong Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://patchwork.freedesktop.org/patch/msgid/20211231045056.118640-1-yangcong5@huaqin.corp-partner.google.com --- drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c index 5fcbde789ddb..1be150ac758f 100644 --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c @@ -86,7 +86,7 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = { _INIT_DCS_CMD(0x0F, 0x73), _INIT_DCS_CMD(0x95, 0xE6), _INIT_DCS_CMD(0x96, 0xF0), - _INIT_DCS_CMD(0x30, 0x11), + _INIT_DCS_CMD(0x30, 0x00), _INIT_DCS_CMD(0x6D, 0x66), _INIT_DCS_CMD(0x75, 0xA2), _INIT_DCS_CMD(0x77, 0x3B), @@ -112,17 +112,17 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = { _INIT_DCS_CMD(0xB1, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), _INIT_DCS_CMD(0xB2, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), - _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), + _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), _INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), _INIT_DCS_CMD(0xB5, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), _INIT_DCS_CMD(0xB6, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), - _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), + _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), _INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), _INIT_DCS_CMD(0xB9, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), _INIT_DCS_CMD(0xBA, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), - _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), + _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), _INIT_DCS_CMD(0xFF, 0x24), _INIT_DCS_CMD(0xFB, 0x01), -- cgit v1.2.3