From patchwork Sun Jul 28 15:28:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sui Jingfeng X-Patchwork-Id: 13744023 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E9C7BC3DA64 for ; Sun, 28 Jul 2024 15:29:36 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 477D210E1C3; Sun, 28 Jul 2024 15:29:36 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (1024-bit key; unprotected) header.d=linux.dev header.i=@linux.dev header.b="rQ5oVq1R"; dkim-atps=neutral Received: from out-175.mta1.migadu.com (out-175.mta1.migadu.com [95.215.58.175]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3D17310E1C3 for ; Sun, 28 Jul 2024 15:29:34 +0000 (UTC) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1722180572; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7Ge3pIaIRPzq6VNH/YpsfcqmBBYmbPxb13YHFRTFevg=; b=rQ5oVq1R54ExIbgLG/ZnFRpEGc/QWecl2Rkz/yHQU5rdwvo0WL0sB3auU1fB5v3d+N7vxb UwaNEQk5ndQGwbzrSdckG8AVLdh0OWzfUZ4nhB4A+HNDb0t5AQyt5049w1/VJXze19uBVl 7keETwSKHjPa1PL0Aqdpf+ryhZlnE64= From: Sui Jingfeng To: Markus Elfring Cc: Maxime Ripard , Thomas Zimmermann , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, Sui Jingfeng Subject: [PATCH v5 1/2] drm/loongson: Introduce component framework support Date: Sun, 28 Jul 2024 23:28:57 +0800 Message-ID: <20240728152858.346211-2-sui.jingfeng@linux.dev> In-Reply-To: <20240728152858.346211-1-sui.jingfeng@linux.dev> References: <20240728152858.346211-1-sui.jingfeng@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" In some display subsystems, the functionality of a PCIe device might be too complex to manage with a single driver. A split of the functionality into child devices can help to achieve better modularity. For example, KMS drivers who have dependencies on external modules will suffer from the deferral probe problem. The problem is that the DRM driver has to tear down everything when it receives '-EPROBE_DEFER', even though the independent part of the driver is not related to this error. The idea is to migrate (offload) the dependency to submodules, creating submodule by creating platform devices manually during driver load time. Submodules are functional as agents, which will be responsible for attaching needed external modules for the main body of the whole KMS driver. Submodules are also responsible for returning '-EPROBE_DEFER' to the driver core if it needs to do so. Make LSDC PCI driver as a subcomponent and creating a platform device as a DRM proxy, which will attach the common DRM routines to our hardware after all submodules bound. The proxy is a fake master which is working at the foreground. Move DRM-related codes into the loongson_drm_master_bind(), move output related things into the submodule, because the output hardware units are relatively standalone IPs. Initialize the GPIO-I2Cs in the driver probe() of the LSDC PCIe device, tie its lifetime to the LSDC. Assign GFX PLL, TTM memory manager part, and power management part to the DRM proxy, as those entities do not belong to the LSDC itself. They are common resources. Signed-off-by: Sui Jingfeng --- drivers/gpu/drm/loongson/Makefile | 2 + drivers/gpu/drm/loongson/loongson_device.c | 30 ++ drivers/gpu/drm/loongson/loongson_drv.c | 298 +++++++++++++++ drivers/gpu/drm/loongson/loongson_drv.h | 108 ++++++ drivers/gpu/drm/loongson/loongson_module.c | 80 +++- drivers/gpu/drm/loongson/loongson_module.h | 31 ++ drivers/gpu/drm/loongson/lsdc_benchmark.c | 12 +- drivers/gpu/drm/loongson/lsdc_benchmark.h | 2 +- drivers/gpu/drm/loongson/lsdc_crtc.c | 4 +- drivers/gpu/drm/loongson/lsdc_debugfs.c | 41 +-- drivers/gpu/drm/loongson/lsdc_drv.c | 346 +++++------------- drivers/gpu/drm/loongson/lsdc_drv.h | 89 +---- drivers/gpu/drm/loongson/lsdc_gem.c | 42 ++- drivers/gpu/drm/loongson/lsdc_gem.h | 13 + drivers/gpu/drm/loongson/lsdc_gfxpll.c | 33 +- drivers/gpu/drm/loongson/lsdc_gfxpll.h | 3 +- drivers/gpu/drm/loongson/lsdc_i2c.c | 55 ++- drivers/gpu/drm/loongson/lsdc_i2c.h | 21 +- drivers/gpu/drm/loongson/lsdc_output.c | 183 +++++++++ drivers/gpu/drm/loongson/lsdc_output.h | 33 +- drivers/gpu/drm/loongson/lsdc_output_7a1000.c | 6 +- drivers/gpu/drm/loongson/lsdc_output_7a2000.c | 20 +- drivers/gpu/drm/loongson/lsdc_pixpll.c | 4 +- drivers/gpu/drm/loongson/lsdc_plane.c | 4 +- drivers/gpu/drm/loongson/lsdc_ttm.c | 70 ++-- drivers/gpu/drm/loongson/lsdc_ttm.h | 4 +- 26 files changed, 1026 insertions(+), 508 deletions(-) create mode 100644 drivers/gpu/drm/loongson/loongson_drv.c create mode 100644 drivers/gpu/drm/loongson/loongson_drv.h create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile index 91e72bd900c1..90c6239bd77d 100644 --- a/drivers/gpu/drm/loongson/Makefile +++ b/drivers/gpu/drm/loongson/Makefile @@ -9,6 +9,7 @@ loongson-y := \ lsdc_gfxpll.o \ lsdc_i2c.o \ lsdc_irq.o \ + lsdc_output.o \ lsdc_output_7a1000.o \ lsdc_output_7a2000.o \ lsdc_plane.o \ @@ -17,6 +18,7 @@ loongson-y := \ lsdc_ttm.o loongson-y += loongson_device.o \ + loongson_drv.o \ loongson_module.o obj-$(CONFIG_DRM_LOONGSON) += loongson.o diff --git a/drivers/gpu/drm/loongson/loongson_device.c b/drivers/gpu/drm/loongson/loongson_device.c index 9986c8a2a255..51de71a9b692 100644 --- a/drivers/gpu/drm/loongson/loongson_device.c +++ b/drivers/gpu/drm/loongson/loongson_device.c @@ -4,6 +4,7 @@ */ #include +#include #include "lsdc_drv.h" @@ -100,3 +101,32 @@ lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip_id) { return __chip_id_desc_table[chip_id]; } + +static void loongson_device_postfini(void *data) +{ + struct platform_device *proxy = data; + + platform_device_unregister(proxy); +} + +int loongson_device_preinit(struct device *parent) +{ + struct platform_device *proxy; + int ret; + + proxy = platform_device_register_resndata(parent, + "loongson.drm.proxy", + PLATFORM_DEVID_NONE, + NULL, 0, + NULL, 0); + if (IS_ERR(proxy)) { + dev_err(parent, "failed to register loongson proxy device\n"); + return PTR_ERR(proxy); + } + + ret = devm_add_action_or_reset(parent, loongson_device_postfini, proxy); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/loongson/loongson_drv.c b/drivers/gpu/drm/loongson/loongson_drv.c new file mode 100644 index 000000000000..1d7735cd1b89 --- /dev/null +++ b/drivers/gpu/drm/loongson/loongson_drv.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Authors: + * Sui Jingfeng + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "loongson_drv.h" +#include "loongson_module.h" +#include "lsdc_drv.h" +#include "lsdc_gem.h" +#include "lsdc_output.h" +#include "lsdc_ttm.h" + +DEFINE_DRM_GEM_FOPS(loongson_gem_fops); + +static const struct drm_driver loongson_drm_driver = { + .driver_features = DRIVER_MODESET | DRIVER_RENDER | DRIVER_GEM | + DRIVER_ATOMIC, + .fops = &loongson_gem_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, + .debugfs_init = loongson_debugfs_init, + .dumb_create = lsdc_dumb_create, + .dumb_map_offset = lsdc_dumb_map_offset, + .gem_prime_import_sg_table = lsdc_prime_import_sg_table, +}; + +/* + * The GPU and display controller in the LS7A1000/LS7A2000/LS2K2000 are + * separated PCIE devices. They are two devices, not one. Bar 2 of the GPU + * device contains the base address and size of the VRAM, both the GPU and + * the DC could access the on-board VRAM. + */ +static int loongson_drm_get_dedicated_vram(struct drm_device *drm) +{ + struct loongson_drm *ldrm = to_loongson_drm(drm); + struct pci_dev *pdev_gpu; + resource_size_t base, size; + + /* + * The GPU has 00:06.0 as its BDF, this is true at least for + * LS7A1000, LS7A2000 and LS2K2000. + */ + pdev_gpu = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(6, 0)); + if (!pdev_gpu) { + drm_err(drm, "No GPU device, then no VRAM\n"); + return -ENODEV; + } + + base = pci_resource_start(pdev_gpu, 2); + size = pci_resource_len(pdev_gpu, 2); + + pci_dev_put(pdev_gpu); + + ldrm->vram_base = base; + ldrm->vram_size = size; + + drm_info(drm, "Dedicated vram start: 0x%llx, size: %uMiB\n", + (u64)base, (u32)(size >> 20)); + + return (size > SZ_1M) ? 0 : -ENODEV; +} + +static int loongson_drm_master_bind(struct device *dev) +{ + struct loongson_drm *ldrm = dev_get_drvdata(dev); + struct drm_device *ddev = &ldrm->ddev; + int ret; + + loongson_drm_get_dedicated_vram(ddev); + + loongson_gfxpll_preinit(ddev); + + ret = drmm_mode_config_init(ddev); + if (ret) + return ret; + + ret = component_bind_all(dev, ddev); + if (ret) { + dev_err(dev, "master bind all failed: %d\n", ret); + return ret; + } + + drm_mode_config_reset(ddev); + + lsdc_gem_init(ddev); + + ret = lsdc_ttm_init(ddev); + if (ret) { + drm_err(ddev, "Memory manager init failed: %d\n", ret); + return ret; + } + + drmm_kms_helper_poll_init(ddev); + + ret = drm_dev_register(ddev, 0); + if (ret) + return ret; + + drm_fbdev_ttm_setup(ddev, 32); + + return 0; +} + +static void loongson_drm_master_unbind(struct device *dev) +{ + struct loongson_drm *ldrm = dev_get_drvdata(dev); + struct drm_device *ddev = &ldrm->ddev; + + drm_atomic_helper_shutdown(ddev); + + drm_dev_unregister(ddev); + + component_unbind_all(dev, ddev); +} + +static const struct component_master_ops loongson_drm_master_ops = { + .bind = loongson_drm_master_bind, + .unbind = loongson_drm_master_unbind, +}; + +static int loongson_drm_freeze(struct drm_device *ddev) +{ + struct loongson_drm *ldrm = to_loongson_drm(ddev); + struct lsdc_bo *lbo; + int ret; + + /* unpin all of buffers in the VRAM */ + mutex_lock(&ldrm->gem.mutex); + list_for_each_entry(lbo, &ldrm->gem.objects, list) { + struct ttm_buffer_object *tbo = &lbo->tbo; + struct ttm_resource *resource = tbo->resource; + unsigned int pin_count = tbo->pin_count; + + drm_dbg(ddev, "bo[%p], size: %zuKiB, type: %s, pin count: %u\n", + lbo, lsdc_bo_size(lbo) >> 10, + lsdc_mem_type_to_str(resource->mem_type), pin_count); + + if (!pin_count) + continue; + + if (resource->mem_type == TTM_PL_VRAM) { + ret = lsdc_bo_reserve(lbo); + if (unlikely(ret)) { + drm_err(ddev, "bo reserve failed: %d\n", ret); + continue; + } + + do { + lsdc_bo_unpin(lbo); + --pin_count; + } while (pin_count); + + lsdc_bo_unreserve(lbo); + } + } + mutex_unlock(&ldrm->gem.mutex); + + lsdc_bo_evict_vram(ddev); + + ret = drm_mode_config_helper_suspend(ddev); + if (unlikely(ret)) { + drm_err(ddev, "Freeze error: %d", ret); + return ret; + } + + return 0; +} + +static int loongson_drm_pm_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct loongson_drm *ldrm = platform_get_drvdata(pdev); + + return loongson_drm_freeze(&ldrm->ddev); +} + +static int loongson_drm_pm_resume(struct platform_device *pdev) +{ + struct loongson_drm *ldrm = platform_get_drvdata(pdev); + + return drm_mode_config_helper_resume(&ldrm->ddev); +} + +static void loongson_add_pci_match(struct device *master, + struct device_driver *driver, + struct component_match **matchptr) +{ + struct pci_driver *pdriver = to_pci_driver(driver); + const struct pci_device_id *id_table = pdriver->id_table; + unsigned int i = 0; + struct pci_dev *pdev; + + while (id_table[i].vendor == PCI_VENDOR_ID_LOONGSON) { + pdev = pci_get_device(PCI_VENDOR_ID_LOONGSON, + id_table[i].device, + NULL); + if (!pdev) { + ++i; + continue; + } + + component_match_add(master, matchptr, component_compare_dev, + &pdev->dev); + pci_dev_put(pdev); + return; + } +} + +static void loongson_add_platform_match(struct device *master, + struct device_driver *driver, + struct component_match **matchptr) +{ + struct device *dev = NULL; + + while ((dev = platform_find_device_by_driver(dev, driver))) { + component_match_add(master, matchptr, component_compare_dev, dev); + put_device(dev); + } +} + +static void loongson_matches_add(struct device *master, + struct component_match **pptr) +{ + const struct loongson_driver_info *ldi; + + ldi = loongson_get_driver_info_array(NULL); + while (ldi->driver) { + switch (ldi->type) { + case LOONGSON_DRIVER_FLAG_PCI: + loongson_add_pci_match(master, ldi->driver, pptr); + break; + case LOONGSON_DRIVER_FLAG_PLATFORM: + loongson_add_platform_match(master, ldi->driver, pptr); + break; + default: + break; + } + + ++ldi; + } +} + +static int loongson_drm_driver_probe(struct platform_device *pdev) +{ + struct lsdc_device *lsdc = dev_get_drvdata(pdev->dev.parent); + struct component_match *matches = NULL; + struct loongson_drm *ldrm; + + ldrm = devm_drm_dev_alloc(pdev->dev.parent, + &loongson_drm_driver, + struct loongson_drm, ddev); + if (IS_ERR(ldrm)) + return PTR_ERR(ldrm); + + ldrm->lsdc = lsdc; + ldrm->gfxinfo = to_loongson_gfx(lsdc->descp); + platform_set_drvdata(pdev, ldrm); + + loongson_matches_add(&pdev->dev, &matches); + + dev_info(&pdev->dev, "probed\n"); + + return component_master_add_with_match(&pdev->dev, + &loongson_drm_master_ops, + matches); +} + +static void loongson_drm_driver_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &loongson_drm_master_ops); +} + +struct platform_driver loongson_drm_platform_driver = { + .driver = { + .name = "loongson.drm.proxy", + }, + .probe = loongson_drm_driver_probe, + .remove_new = loongson_drm_driver_remove, + .suspend = loongson_drm_pm_suspend, + .resume = loongson_drm_pm_resume, +}; diff --git a/drivers/gpu/drm/loongson/loongson_drv.h b/drivers/gpu/drm/loongson/loongson_drv.h new file mode 100644 index 000000000000..896440c973c7 --- /dev/null +++ b/drivers/gpu/drm/loongson/loongson_drv.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Authors: + * Sui Jingfeng + */ + +#ifndef __LOONGSON_DRV_H__ +#define __LOONGSON_DRV_H__ + +#include +#include +#include + +#include "loongson_module.h" +#include "lsdc_gem.h" +#include "lsdc_gfxpll.h" + +struct loongson_drm { + struct drm_device ddev; + + struct device *dev; + + /* submodules */ + struct lsdc_device *lsdc; + struct loonggpu_device *loonggpu; + + const struct loongson_gfx_desc *gfxinfo; + + struct loongson_gfxpll gfxpll; + + /* memory manager */ + struct ttm_device bdev; + resource_size_t vram_base; + resource_size_t vram_size; + resource_size_t gtt_base; + resource_size_t gtt_size; + + /* tracking pinned memory */ + size_t vram_pinned_size; + size_t gtt_pinned_size; + + struct loongson_gem gem; +}; + +static inline struct loongson_drm * +to_loongson_drm(struct drm_device *drm) +{ + return container_of(drm, struct loongson_drm, ddev); +} + +static inline struct lsdc_device * +to_lsdc(struct drm_device *drm) +{ + return to_loongson_drm(drm)->lsdc; +} + +static inline struct loonggpu_device * +to_loongpu(struct drm_device *drm) +{ + return to_loongson_drm(drm)->loonggpu; +} + +static inline const struct loongson_gfx_desc * +to_loongson_gfxinfo(struct drm_device *drm) +{ + return to_loongson_drm(drm)->gfxinfo; +} + +static inline struct loongson_gem * +to_loongson_gem(struct drm_device *drm) +{ + return &(to_loongson_drm(drm)->gem); +} + +static inline struct loongson_gfxpll * +to_loongson_gfxpll(struct drm_device *drm) +{ + return &(to_loongson_drm(drm)->gfxpll); +} + +static inline struct ttm_device * +to_tdev(struct drm_device *drm) +{ + return &(to_loongson_drm(drm)->bdev); +} + +static inline struct loongson_drm * +tdev_to_ldrm(struct ttm_device *tdev) +{ + return container_of(tdev, struct loongson_drm, bdev); +} + +static inline resource_size_t +loongson_drm_vram_base(struct drm_device *drm) +{ + return to_loongson_drm(drm)->vram_base; +} + +static inline resource_size_t +loongson_drm_vram_size(struct drm_device *drm) +{ + return to_loongson_drm(drm)->vram_size; +} + +int loongson_device_preinit(struct device *parent); +void loongson_debugfs_init(struct drm_minor *minor); + +#endif diff --git a/drivers/gpu/drm/loongson/loongson_module.c b/drivers/gpu/drm/loongson/loongson_module.c index d2a51bd395f6..918c1cfbac6f 100644 --- a/drivers/gpu/drm/loongson/loongson_module.c +++ b/drivers/gpu/drm/loongson/loongson_module.c @@ -4,6 +4,7 @@ */ #include +#include #include