From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=209.85.221.47 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793887546; b=eLImyVpX8tS5kXOfh0DD1QClVktpLw3OTuBcD0PMybhUV2ZtOOvyckfFHxnSP7Z5Kbgh Z6CpwB+F34/muKypDwcA8OvwpKftw8ruI33ZbmtTSZY6X5KuVMVNF8uge/zitKS6lyS9z MUIhw2CVDDv07xN1t7LMxUYnWi7r6DG6pAgOD9TsnJ+Rh4jeafGkJCT+QUczrKQLTAnfp Tcr+PjIyKrSRvSxzGqR9AucwMaRKQ0mJEnHL7xcN+KZjnC7oTdo7GAKVAU2+60Y7rbCxU t7/u+cct+GjmcIVzmy8hWzzk1Z418VHIl6d3LnOf8LnMYpBfs5IYxSUYFct5gtXuzsQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793887546; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=EgDmwowbMyQC1eDfYYfisgkWF1YiN0LWR4L23OptHgY=; b=OuCUfogbyMXXKo2ymiGMdz3zpd5ppRbTYLJvxhf+QQVeqhKpGjan3YsQ6taQp8FL2+1A nmBq7cRRItHYWLYAsGdLaMm8N74v83Pze+jenlHbv9EWNA+XsuuzZlF6W/X6EjJ3JIoCh cfPOSgyXx61Am3jY8zsAdvmjXaknDeitT/hAgd7mUG/acJGYLCBUMip7BVJayGWMHlCxV Uproh4i1x5YcRs8BHX+t6hugktz3dxypyJ7zn1PzGyO4HNl5UwGMVL5ubQ1dYx2oN8USJ OwMG2XSx3Z2sUyG/2KD8AM1aGX7QbKjnq009G45ewTYGJBLfFgtE2K2wj4/YmSjveQQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=XYx7bcj6; arc=none smtp.remote-ip=209.85.221.47 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B56C606D802 for ; Thu, 5 Nov 2026 14:05:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 8B56C606D802 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=XYx7bcj6 Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-48e6eb21a8fso865183f8f.1 for ; Thu, 05 Nov 2026 06:05:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793887544; x=1794492344; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=EgDmwowbMyQC1eDfYYfisgkWF1YiN0LWR4L23OptHgY=; b=XYx7bcj6fo6wNFUMf9OEwKhjK2CP3kbCMiVX1hkUI4JID83LY7nZF2VsVQUY/dmqQz RTecTv+mW1/IKKDypKMrvhcFJp8RDzVBhBMyWUqFnmqoEqMZmu9bOLp+Pjs1+ZglRdVx qLdzlF7DHGMWGcjO4K2/Py+dYzuKbdULlCjLVX3+KilpzHpDczhghtXS3t3RV1WFuCaa +Hn7D+f168jO2cKajntMoKXCjqHFvYu4PbQYHWKfpJ351DH1J/yae6HsY2WM6GuJ645t 4+7anhaH4HGS5OXiEm4MNd/50W/yuPnjAw4UmKsfgLsZ0C6ZI90lkBY3nx9M7hINcsSj 76RA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793887544; x=1794492344; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=EgDmwowbMyQC1eDfYYfisgkWF1YiN0LWR4L23OptHgY=; b=lYVBQIXFou8O7Z5c/26OTilX9v/fkjzFhy5l0rhFitWeyLvtoX4iI33gx0SgjWEMjA cmWvSOmtK7VSqhFAE31gGNdbDdLnPcz1FdlOwdT8fDugqUkNF/8wSkKN/PMppWWuUDDy pDXCXaLROGAJvpiakqktNsAFc1wiY1O1n8+IfkAVChsY8W59+nxfLSQWJQNUTLB1NjsL Z6louHYNLQ2JGMugo6uWak8rCxkBnrcr+MDqf88aRM9vUnWYXtPHXCT4fkaj1yD4PaJz 9HNirEYulr5vHC93WwHAZcrSS1VicvXkGpQ0hIuh6t6AJiGza1p4qKJrUh53z03XvuYo Fwdw== X-Forwarded-Encrypted: i=1; AKwUvBzIHmgqmjgGmDX1HkhgCCyFtkWhihaph6orKNWo9CfTmkpmJXbqe9c5Vn2vtS+cQYUe6d455pKHFNWf@vger.kernel.org X-Gm-Message-State: APuU4Z8cYnuNGqVse+DX22/hFBr3usgu5asIkDiPoWHeV5SpbhRjnePM RensVt9KHihvsDho9lUB3yP2PbXy009yfSGRyQ+ZQti9JMQdvYKC+VDn X-Gm-Gg: AYBFou2nM7bET/EF9q31pqOmqWubEswFc8XZFn5oKvLAY7qMeOS42ufp4W4nnXP1loR qnkG+4zhspOhGJC7oXGoNe7+AXU9VIRa55CVVfYUzkXYJLofHy6D6ZmwyI/EgoWxm1uBCN+neaF mlrddYcn8QN+C+qm+YripCgzQnWvOgapw2wjN//o1rJqpRuBwoxiLaF9vJZI1r35wrxBHD9pIHX jrusuruD85Owczw2rxi5SatsZLh6/30K7R/PzWYKJuqvDATqEw2TobCKujSnCSFZC8H892/k8CG m4PVyyiEheu50fgDN8VpErNMIMNrWeCaYYIzbUi0ektFOVV1ih9wv1Df7MZTV7f43kgdWzkdr/c yO7HUNxJ8x7h4Zeb7UT5QlhgjPLhxZMUwP4v4tdTmVjZJ/IYwFGZt/w+bq/tV9cVG6XuQbrP9L7 e8NVPRUkVeS0Q/ZjTSkZfh52w2nulbOxIFFtoAsg6aC/BsXMs88GD+pwv36b+arXD+i16JrIdle 2Zuhh+SJ5CaauT0PNCUf5NvxAlmILkKImtbsSZpBjgsT1WbQ5uW68LNxrlVCelFCotRiWD6Vm5Z lZjIaXkCu1YEWIZsBQz5kQpZcvRZO4yWmTfFPMgm2MxCOZBj/3S/zM940ORzXLH/M1tEnyQ= X-Received: by 2002:a05:6000:1887:b0:48e:d36:77 with SMTP id ffacd0b85a97d-48e6e2bc062mr48347421f8f.4.1793887543748; Thu, 05 Nov 2026 06:05:43 -0800 (PST) Received: from xeon ([188.163.112.62]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-48fed92a753sm11454111f8f.45.2026.11.05.06.05.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Nov 2026 06:05:41 -0800 (PST) From: Svyatoslav Ryhel To: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thierry Reding , Jonathan Hunter , Neil Armstrong , Jessica Zhang , Mikko Perttunen , Svyatoslav Ryhel Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v6 01/10] drm: Add MIPI DBI bus support for MIPI DBI Type A and B Date: Thu, 5 Nov 2026 16:05:01 +0200 Message-ID: <20261105140510.165165-2-clamor95@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261105140510.165165-1-clamor95@gmail.com> References: <20261105140510.165165-1-clamor95@gmail.com> X-Mailing-List: devicetree@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The MIPI DBI bus allows modeling DBI hosts and peripherals using the Linux driver model. DBI hosts are registered by their respective drivers. During registration, DBI peripherals are created from the device tree nodes provided by the host. DBI hosts expose operations that can be used by peripheral drivers to access associated devices. This implementation adds support for MIPI DBI Type A and Type B only. Type C support existing in drm_mipi_dbi.c was not altered. The framework is modeled to closely resemble the existing MIPI DSI setup for seamless integration. Suggested-by: Mikko Perttunen # preliminary sketch Signed-off-by: Svyatoslav Ryhel --- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/drm_mipi_dbi_bus.c | 256 +++++++++++++++++++++++++++++ include/drm/drm_mipi_dbi_bus.h | 103 ++++++++++++ 3 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/drm_mipi_dbi_bus.c create mode 100644 include/drm/drm_mipi_dbi_bus.h diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 2c6bc093a923a..880f0dc930b85 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -166,7 +166,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o obj-y += tests/ -obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o +obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o drm_mipi_dbi_bus.o obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o obj-y += arm/ obj-y += clients/ diff --git a/drivers/gpu/drm/drm_mipi_dbi_bus.c b/drivers/gpu/drm/drm_mipi_dbi_bus.c new file mode 100644 index 0000000000000..11792c0e389f7 --- /dev/null +++ b/drivers/gpu/drm/drm_mipi_dbi_bus.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MIPI DBI devices with command transport through parallel interface + * + * Copyright 2026 Mikko Perttunen + * Copyright 2026 Svyatoslav Ryhel + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * DOC: overview + * + * There are three MIPI DBI implementation types: + * + * A. Motorola 6800-type parallel bus + * + * B. Intel 8080-type parallel bus + * + * C. SPI-type with three options: + * + * 1. 9-bit with the Data/Command signal as the ninth bit + * 2. Same as above, except it is sent as 16 bits + * 3. 8-bit with the Data/Command signal as a separate D/CX pin + * + * This library provides a framework for MIPI Display Bus Interface (DBI) + * compatible display controllers using Type A and Type B. This + * implementation closely matches existing DSI framework behavior to + * allow seamless integration. + * + * Type C options 1 and 3 are covered by drm_mipi_dbi.c with + * mipi_dbi_spi_init(). + */ + +static int mipi_dbi_match(struct device *dev, const struct device_driver *driver) +{ + return of_driver_match_device(dev, driver); +} + +static int mipi_dbi_uevent(const struct device *dev, struct kobj_uevent_env *env) +{ + return of_device_uevent_modalias(dev, env); +} + +static const struct dev_pm_ops mipi_dbi_device_pm_ops = { + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, +}; + +static const struct bus_type mipi_dbi_bus_type = { + .name = "mipi-dbi", + .match = mipi_dbi_match, + .uevent = mipi_dbi_uevent, + .pm = &mipi_dbi_device_pm_ops, +}; + +static void mipi_dbi_device_release(struct device *dev) +{ + of_node_put(dev->of_node); + kfree(to_mipi_dbi_device(dev)); +} + +static void mipi_dbi_device_unregister(void *data) +{ + struct device *dev = data; + + of_node_clear_flag(dev->of_node, OF_POPULATED); + device_unregister(dev); +} + +/** + * devm_mipi_dbi_device_register() - create a managed MIPI DBI device + * @dev: device to tie the MIPI-DBI device lifetime to + * @host: DBI host to which this device is connected + * @np: device tree node associated with the panel MIPI DBI device + * + * This function is called by DBI host driver to create panel device. + * It automatically calls mipi_dbi_device_unregister() when @dev is + * unbound. It does not automatically free passed device node pointer, + * it must be put manually. + * + * Returns: + * A pointer to the newly created MIPI DBI device, or, a pointer encoded + * with an error. + */ +struct mipi_dbi_device * +devm_mipi_dbi_device_register(struct device *dev, struct mipi_dbi_host *host, + struct device_node *np) +{ + struct mipi_dbi_device *dbidev; + int ret; + + if (!host || !host->dev || !host->dbi || !host->dbi->command || + !host->ops || !host->ops->attach || !host->ops->detach || !np) + return ERR_PTR(-EINVAL); + + if (!of_device_is_available(np)) + return ERR_PTR(-ENODEV); + + dbidev = kzalloc_obj(*dbidev); + if (!dbidev) + return ERR_PTR(-ENOMEM); + + if (of_node_test_and_set_flag(np, OF_POPULATED)) { + kfree(dbidev); + return ERR_PTR(-EBUSY); + } + + dbidev->host = host; + dbidev->dbi = host->dbi; + device_initialize(&dbidev->dev); + dbidev->dev.parent = host->dev; + dbidev->dev.bus = &mipi_dbi_bus_type; + dbidev->dev.release = mipi_dbi_device_release; + device_set_node(&dbidev->dev, of_fwnode_handle(of_node_get(np))); + + ret = dev_set_name(&dbidev->dev, "%s:%s", dev_name(host->dev), np->full_name); + if (ret) + goto put_device; + + ret = device_add(&dbidev->dev); + if (ret) + goto put_device; + + ret = devm_add_action_or_reset(dev, mipi_dbi_device_unregister, + &dbidev->dev); + if (ret) + return ERR_PTR(ret); + + return dbidev; + +put_device: + of_node_clear_flag(np, OF_POPULATED); + put_device(&dbidev->dev); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(devm_mipi_dbi_device_register); + +static void mipi_dbi_detach(void *data) +{ + struct mipi_dbi_device *dbidev = data; + + dbidev->host->ops->detach(dbidev->host, dbidev); + dbidev->attached = false; +} + +/** + * devm_mipi_dbi_attach() - managed attach of DBI device to its DBI host + * @dev: device to tie the MIPI-DBI device lifetime to + * @dbidev: DBI peripheral + */ +int devm_mipi_dbi_attach(struct device *dev, struct mipi_dbi_device *dbidev) +{ + int ret; + + if (dbidev->attached) + return -EBUSY; + + ret = dbidev->host->ops->attach(dbidev->host, dbidev); + if (ret) + return ret; + + dbidev->attached = true; + return devm_add_action_or_reset(dev, mipi_dbi_detach, dbidev); +} +EXPORT_SYMBOL_GPL(devm_mipi_dbi_attach); + +static int mipi_dbi_drv_probe(struct device *dev) +{ + struct mipi_dbi_driver *drv = to_mipi_dbi_driver(dev->driver); + struct mipi_dbi_device *dbidev = to_mipi_dbi_device(dev); + + return drv->probe(dbidev); +} + +static int mipi_dbi_drv_remove(struct device *dev) +{ + struct mipi_dbi_driver *drv = to_mipi_dbi_driver(dev->driver); + struct mipi_dbi_device *dbidev = to_mipi_dbi_device(dev); + + drv->remove(dbidev); + + return 0; +} + +static void mipi_dbi_drv_shutdown(struct device *dev) +{ + struct mipi_dbi_driver *drv = to_mipi_dbi_driver(dev->driver); + struct mipi_dbi_device *dbidev = to_mipi_dbi_device(dev); + + drv->shutdown(dbidev); +} + +/** + * __mipi_dbi_driver_register() - register a driver for DBI devices + * @drv: DBI driver structure + * @owner: owner module + * + * Return: 0 on success or a negative error code on failure. + */ +int __mipi_dbi_driver_register(struct mipi_dbi_driver *drv, struct module *owner) +{ + drv->driver.bus = &mipi_dbi_bus_type; + drv->driver.owner = owner; + + if (drv->probe) + drv->driver.probe = mipi_dbi_drv_probe; + if (drv->remove) + drv->driver.remove = mipi_dbi_drv_remove; + if (drv->shutdown) + drv->driver.shutdown = mipi_dbi_drv_shutdown; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_GPL(__mipi_dbi_driver_register); + +/** + * mipi_dbi_driver_unregister() - unregister a driver for DBI devices + * @drv: DBI driver structure + * + * Return: 0 on success or a negative error code on failure. + */ +void mipi_dbi_driver_unregister(struct mipi_dbi_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_GPL(mipi_dbi_driver_unregister); + +static int __init mipi_dbi_bus_init(void) +{ + return bus_register(&mipi_dbi_bus_type); +} +subsys_initcall(mipi_dbi_bus_init); + +static void __exit mipi_dbi_bus_exit(void) +{ + bus_unregister(&mipi_dbi_bus_type); +} +module_exit(mipi_dbi_bus_exit); + +MODULE_DESCRIPTION("MIPI DBI devices with command transport through parallel interface"); +MODULE_LICENSE("GPL"); diff --git a/include/drm/drm_mipi_dbi_bus.h b/include/drm/drm_mipi_dbi_bus.h new file mode 100644 index 0000000000000..2b8b59bffd0b8 --- /dev/null +++ b/include/drm/drm_mipi_dbi_bus.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * MIPI DBI devices with command transport through parallel interface + * + * Copyright 2026 Mikko Perttunen + * Copyright 2026 Svyatoslav Ryhel + */ + +#ifndef __DRM_MIPI_DBI_BUS_H__ +#define __DRM_MIPI_DBI_BUS_H__ + +#include +#include + +struct device_node; +struct mipi_dbi; +struct mipi_dbi_device; +struct mipi_dbi_host; + +/** + * struct mipi_dbi_host_ops - DBI bus operations + * @attach: attach DBI device to DBI host + * @detach: detach DBI device from DBI host + */ +struct mipi_dbi_host_ops { + int (*attach)(struct mipi_dbi_host *host, struct mipi_dbi_device *dev); + void (*detach)(struct mipi_dbi_host *host, struct mipi_dbi_device *dev); +}; + +/** + * struct mipi_dbi_host - DBI host device + * @dev: driver model device node for this DBI host + * @dbi: MIPI DBI interface + * @ops: DBI host operations + */ +struct mipi_dbi_host { + struct device *dev; + struct mipi_dbi *dbi; + const struct mipi_dbi_host_ops *ops; +}; + +/** + * struct mipi_dbi_device - DBI peripheral device + * @dev: driver model device node for this peripheral + * @dbi: MIPI DBI interface + * @host: DBI host for this peripheral + * @attached: the DBI device has been successfully attached + */ +struct mipi_dbi_device { + struct device dev; + struct mipi_dbi *dbi; + struct mipi_dbi_host *host; + bool attached; +}; + +#define to_mipi_dbi_device(__dev) container_of_const(__dev, struct mipi_dbi_device, dev) + +struct mipi_dbi_device * +devm_mipi_dbi_device_register(struct device *dev, struct mipi_dbi_host *host, + struct device_node *np); +int devm_mipi_dbi_attach(struct device *dev, struct mipi_dbi_device *dbidev); + +/** + * struct mipi_dbi_driver - DBI driver + * @driver: device driver model driver + * @probe: callback for device binding + * @remove: callback for device unbinding + * @shutdown: called at shutdown time to quiesce the device + */ +struct mipi_dbi_driver { + struct device_driver driver; + int (*probe)(struct mipi_dbi_device *dbi); + void (*remove)(struct mipi_dbi_device *dbi); + void (*shutdown)(struct mipi_dbi_device *dbi); +}; + +static inline struct mipi_dbi_driver * +to_mipi_dbi_driver(struct device_driver *driver) +{ + return container_of(driver, struct mipi_dbi_driver, driver); +} + +static inline void *mipi_dbi_get_drvdata(const struct mipi_dbi_device *dbi) +{ + return dev_get_drvdata(&dbi->dev); +} + +static inline void mipi_dbi_set_drvdata(struct mipi_dbi_device *dbi, void *data) +{ + dev_set_drvdata(&dbi->dev, data); +} + +int __mipi_dbi_driver_register(struct mipi_dbi_driver *drv, struct module *owner); +void mipi_dbi_driver_unregister(struct mipi_dbi_driver *drv); + +#define mipi_dbi_driver_register(driver) \ + __mipi_dbi_driver_register(driver, THIS_MODULE) + +#define module_mipi_dbi_driver(__mipi_dbi_driver) \ + module_driver(__mipi_dbi_driver, mipi_dbi_driver_register, \ + mipi_dbi_driver_unregister) + +#endif /* __DRM_MIPI_DBI_BUS__ */ -- 2.53.0