Introduce the component framework to bind childs and siblings, for better
modularity and paper over the deferral probe problems if it need to attach
exterinal module someday. Hardware units come with PCI(e) are actually all
ready to drive, but there has some board specific modules will return
-EPROBE_DEFER. We need all other submodules ready to attach before we can
register the drm device to userspace.
The idea is to devide the exterinal module dependent part and exterinal
module independent part clearly, for example, the display controller and
the builtin GPIO-I2C just belong to exterinal module independent part.
While the output is belong to exterinal module dependent part.
Also for better reflecting the hardware, we intend to abstract the output
ports as child devices. The output ports may consists of encoder phy and
level shift, while the GPU and VPU are standalone siblings. As those units
are relative separate hardware units from display controller itself.
By design, the display controller PCI(e) is selected as the component
master, gpio-i2c go with master. The manually created virtual child device
are functional as agents for the master, it could return the -EPROBE_DEFER
back to the component core. This allows the master don't have to tear down
everything, the majority setups work can be preserved. The potential cyclic
dependency problem can be solved with such framework.
Sui Jingfeng (3):
drm/loongson: Add helpers for creating subdevice
drm/loongson: Introduce component framework support
drm/loongson: Refactor lsdc device initialize and the output port
drivers/gpu/drm/loongson/Makefile | 1 +
drivers/gpu/drm/loongson/loongson_device.c | 42 ++++
drivers/gpu/drm/loongson/loongson_module.c | 17 +-
drivers/gpu/drm/loongson/loongson_module.h | 1 +
drivers/gpu/drm/loongson/lsdc_drv.c | 208 +++++++++++-------
drivers/gpu/drm/loongson/lsdc_drv.h | 34 +--
drivers/gpu/drm/loongson/lsdc_output.c | 183 +++++++++++++++
drivers/gpu/drm/loongson/lsdc_output.h | 38 +++-
drivers/gpu/drm/loongson/lsdc_output_7a1000.c | 3 +-
drivers/gpu/drm/loongson/lsdc_output_7a2000.c | 15 +-
10 files changed, 422 insertions(+), 120 deletions(-)
create mode 100644 drivers/gpu/drm/loongson/lsdc_output.c
--
2.34.1
In some display subsystems, the functionality of a PCI(e) device may too
complex for a single driver to be managed by a monolithic driver. A split
of the functionality into child devices can helps to achieve better
modularity, eaiser for understand and maintain.
Add the loongson_create_platform_device() function to pove the way for the
mentioned goals. Pure software method, no hardware operations involved.
Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/loongson/loongson_device.c | 42 ++++++++++++++++++++++
drivers/gpu/drm/loongson/lsdc_drv.h | 6 ++++
2 files changed, 48 insertions(+)
diff --git a/drivers/gpu/drm/loongson/loongson_device.c b/drivers/gpu/drm/loongson/loongson_device.c
index 9986c8a2a255..b268549d643e 100644
--- a/drivers/gpu/drm/loongson/loongson_device.c
+++ b/drivers/gpu/drm/loongson/loongson_device.c
@@ -4,6 +4,7 @@
*/
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include "lsdc_drv.h"
@@ -100,3 +101,44 @@ lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip_id)
{
return __chip_id_desc_table[chip_id];
}
+
+int loongson_create_platform_device(struct device *parent,
+ const char *name, int id,
+ struct resource *pres,
+ void *data,
+ struct platform_device **ppdev)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = platform_device_alloc(name, id);
+ if (!pdev)
+ return -ENOMEM;
+
+ pdev->dev.parent = parent;
+
+ if (pres) {
+ ret = platform_device_add_resources(pdev, pres, 1);
+ if (ret) {
+ platform_device_put(pdev);
+ return ret;
+ }
+ }
+
+ if (data) {
+ void *pdata = kmalloc(sizeof(void *), GFP_KERNEL);
+
+ *(void **)pdata = data;
+ pdev->dev.platform_data = pdata;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ *ppdev = pdev;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.h b/drivers/gpu/drm/loongson/lsdc_drv.h
index fbf2d760ef27..a2c6b496a69f 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.h
+++ b/drivers/gpu/drm/loongson/lsdc_drv.h
@@ -47,6 +47,12 @@ enum loongson_chip_id {
const struct lsdc_desc *
lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip);
+int loongson_create_platform_device(struct device *parent,
+ const char *name, int id,
+ struct resource *pres,
+ void *data,
+ struct platform_device **ppdev);
+
struct lsdc_kms_funcs;
/* DC specific */
--
2.34.1
Introduce the component framework to bind childs and siblings, for better
modularity and paper over the deferral probe problems if it need to attach
exterinal module someday. Hardware units come with PCI(e) are actually all
ready to drive, but there has some board specific modules will return
-EPROBE_DEFER. We need all other submodules ready to attach before we can
register the drm device to userspace.
The idea is to devide the exterinal module dependent part and exterinal
module independent part clearly, for example, the display controller and
the builtin GPIO-I2C just belong to exterinal module independent part.
While the output is belong to exterinal module dependent part.
Also for better reflecting the hardware, we intend to abstract the output
ports as child devices. The output ports may consists of encoder phy and
level shift, while the GPU and VPU are standalone siblings. As those units
are relative separate hardware units from display controller itself.
By design, the display controller PCI(e) is selected as the component
master, gpio-i2c go with master. The manually created virtual child device
are functional as agents for the master, it could return the -EPROBE_DEFER
back to the component core. This allows the master don't have to tear down
everything, the majority setups work can be preserved. The potential cyclic
dependency problem can be solved with such framework.
Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/loongson/Makefile | 1 +
drivers/gpu/drm/loongson/loongson_module.c | 17 ++-
drivers/gpu/drm/loongson/loongson_module.h | 1 +
drivers/gpu/drm/loongson/lsdc_drv.c | 59 +++++++++
drivers/gpu/drm/loongson/lsdc_drv.h | 6 +-
drivers/gpu/drm/loongson/lsdc_output.c | 142 +++++++++++++++++++++
drivers/gpu/drm/loongson/lsdc_output.h | 22 +++-
7 files changed, 241 insertions(+), 7 deletions(-)
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..e15cb9bff378 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 \
diff --git a/drivers/gpu/drm/loongson/loongson_module.c b/drivers/gpu/drm/loongson/loongson_module.c
index d2a51bd395f6..037fa7ffe9c9 100644
--- a/drivers/gpu/drm/loongson/loongson_module.c
+++ b/drivers/gpu/drm/loongson/loongson_module.c
@@ -4,6 +4,7 @@
*/
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <video/nomodeset.h>
@@ -19,15 +20,29 @@ module_param_named(vblank, loongson_vblank, int, 0400);
static int __init loongson_module_init(void)
{
+ int ret;
+
if (!loongson_modeset || video_firmware_drivers_only())
return -ENODEV;
- return pci_register_driver(&lsdc_pci_driver);
+ ret = platform_driver_register(&lsdc_output_port_platform_driver);
+ if (ret)
+ return ret;
+
+ ret = pci_register_driver(&lsdc_pci_driver);
+ if (ret) {
+ platform_driver_unregister(&lsdc_output_port_platform_driver);
+ return ret;
+ }
+
+ return 0;
}
module_init(loongson_module_init);
static void __exit loongson_module_exit(void)
{
pci_unregister_driver(&lsdc_pci_driver);
+
+ platform_driver_unregister(&lsdc_output_port_platform_driver);
}
module_exit(loongson_module_exit);
diff --git a/drivers/gpu/drm/loongson/loongson_module.h b/drivers/gpu/drm/loongson/loongson_module.h
index 931c17521bf0..8dc71b98f5cc 100644
--- a/drivers/gpu/drm/loongson/loongson_module.h
+++ b/drivers/gpu/drm/loongson/loongson_module.h
@@ -8,5 +8,6 @@
extern int loongson_vblank;
extern struct pci_driver lsdc_pci_driver;
+extern struct platform_driver lsdc_output_port_platform_driver;
#endif
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index adc7344d2f80..45c30e3d178f 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -3,7 +3,9 @@
* Copyright (C) 2023 Loongson Technology Corporation Limited
*/
+#include <linux/component.h>
#include <linux/pci.h>
+#include <linux/platform_device.h>
#include <linux/vgaarb.h>
#include <drm/drm_aperture.h>
@@ -257,12 +259,39 @@ static unsigned int lsdc_vga_set_decode(struct pci_dev *pdev, bool state)
return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
}
+static int loongson_drm_master_bind(struct device *dev)
+{
+ int ret;
+
+ ret = component_bind_all(dev, NULL);
+ if (ret) {
+ dev_err(dev, "master bind all failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void loongson_drm_master_unbind(struct device *dev)
+{
+ component_unbind_all(dev, NULL);
+
+ return;
+}
+
+const struct component_master_ops loongson_drm_master_ops = {
+ .bind = loongson_drm_master_bind,
+ .unbind = loongson_drm_master_unbind,
+};
+
static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ struct component_match *matches = NULL;
const struct lsdc_desc *descp;
struct drm_device *ddev;
struct lsdc_device *ldev;
int ret;
+ int i;
descp = lsdc_device_probe(pdev, ent->driver_data);
if (IS_ERR_OR_NULL(descp))
@@ -285,6 +314,25 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (IS_ERR(ldev))
return PTR_ERR(ldev);
+ for (i = 0; i < descp->num_of_crtc; ++i) {
+ ret = lsdc_output_preinit(&pdev->dev, descp, i,
+ &ldev->childs[i]);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < descp->num_of_crtc; ++i) {
+ component_match_add(&pdev->dev, &matches,
+ component_compare_dev,
+ &ldev->childs[i]->dev);
+ }
+
+ ret = component_master_add_with_match(&pdev->dev,
+ &loongson_drm_master_ops,
+ matches);
+
+ dev_info(&pdev->dev, "loongson add component: %u\n", ret);
+
ddev = &ldev->base;
pci_set_drvdata(pdev, ddev);
@@ -322,9 +370,20 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static void lsdc_pci_remove(struct pci_dev *pdev)
{
struct drm_device *ddev = pci_get_drvdata(pdev);
+ struct lsdc_device *ldev = to_lsdc(ddev);
+ unsigned int i;
drm_dev_unregister(ddev);
drm_atomic_helper_shutdown(ddev);
+
+ component_master_del(&pdev->dev, &loongson_drm_master_ops);
+
+ for (i = 0; i < ldev->descp->num_of_crtc; ++i) {
+ if (ldev->childs[i]) {
+ platform_device_unregister(ldev->childs[i]);
+ ldev->childs[i] = NULL;
+ }
+ }
}
static void lsdc_pci_shutdown(struct pci_dev *pdev)
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.h b/drivers/gpu/drm/loongson/lsdc_drv.h
index a2c6b496a69f..86061207851d 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.h
+++ b/drivers/gpu/drm/loongson/lsdc_drv.h
@@ -173,11 +173,6 @@ struct lsdc_cursor {
struct lsdc_device *ldev;
};
-struct lsdc_output {
- struct drm_encoder encoder;
- struct drm_connector connector;
-};
-
static inline struct lsdc_output *
connector_to_lsdc_output(struct drm_connector *connector)
{
@@ -290,6 +285,7 @@ struct lsdc_device {
resource_size_t gtt_size;
struct lsdc_display_pipe dispipe[LSDC_NUM_CRTC];
+ struct platform_device *childs[LSDC_NUM_CRTC];
struct lsdc_gem gem;
diff --git a/drivers/gpu/drm/loongson/lsdc_output.c b/drivers/gpu/drm/loongson/lsdc_output.c
new file mode 100644
index 000000000000..b1a9c6123615
--- /dev/null
+++ b/drivers/gpu/drm/loongson/lsdc_output.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/delay.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "lsdc_drv.h"
+#include "lsdc_output.h"
+
+static struct lsdc_output_desc ls7a1000_output_port_desc[2] = {
+ {
+ .pipe = 0,
+ .type = "DVO-0",
+ },
+ {
+ .pipe = 1,
+ .type = "DVO-1",
+ },
+};
+
+static struct lsdc_output_desc ls7a2000_output_port_desc[2] = {
+ {
+ .pipe = 0,
+ .type = "HDMI-or-VGA-0",
+ },
+ {
+ .pipe = 1,
+ .type = "HDMI-1",
+ },
+};
+
+int lsdc_output_preinit(struct device *parent,
+ const struct lsdc_desc *descp,
+ unsigned int index,
+ struct platform_device **ppdev)
+{
+ struct lsdc_output_desc *output_port_info;
+ int ret;
+
+ switch (to_loongson_gfx(descp)->chip_id) {
+ case CHIP_LS7A1000:
+ output_port_info = &ls7a1000_output_port_desc[index];
+ break;
+ case CHIP_LS7A2000:
+ output_port_info = &ls7a2000_output_port_desc[index];
+ break;
+ default:
+ output_port_info = NULL;
+ break;
+ };
+
+ ret = loongson_create_platform_device(parent,
+ "lsdc-output-port",
+ index,
+ NULL,
+ (void *)output_port_info,
+ ppdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * dev stand for the port@0, port@1, ..., port@n of the dispplay controller
+ */
+static int lsdc_output_port_bind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+ return 0;
+}
+
+static void lsdc_output_port_unbind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+}
+
+static const struct component_ops lsdc_output_port_component_ops = {
+ .bind = lsdc_output_port_bind,
+ .unbind = lsdc_output_port_unbind,
+};
+
+static int lsdc_output_port_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lsdc_output *output;
+ struct lsdc_output_desc *descp;
+ int ret;
+
+ descp = *(void **)dev->platform_data;
+ if (!descp) {
+ dev_err(dev, "No platform specific data for output port\n");
+ return -ENODEV;
+ }
+
+ output = devm_kzalloc(dev, sizeof(*output), GFP_KERNEL);
+ if (!output)
+ return -ENOMEM;
+
+ output->dev = dev;
+ output->descp = descp;
+
+ ret = component_add(dev, &lsdc_output_port_component_ops);
+ if (ret) {
+ devm_kfree(dev, output);
+ dev_err(dev, "failed to register component: %d\n", ret);
+ return ret;
+ }
+
+ dev_set_drvdata(dev, output);
+
+ return 0;
+}
+
+static void lsdc_output_port_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lsdc_output *output;
+
+ component_del(dev, &lsdc_output_port_component_ops);
+
+ output = dev_get_drvdata(dev);
+ if (output)
+ devm_kfree(dev, output);
+}
+
+static const struct platform_device_id lsdc_output_port_ids[] = {
+ { .name = "lsdc-output-port" },
+ { },
+};
+
+struct platform_driver lsdc_output_port_platform_driver = {
+ .driver = {
+ .name = "lsdc-output-port",
+ },
+ .probe = lsdc_output_port_probe,
+ .remove_new = lsdc_output_port_remove,
+ .id_table = lsdc_output_port_ids,
+};
diff --git a/drivers/gpu/drm/loongson/lsdc_output.h b/drivers/gpu/drm/loongson/lsdc_output.h
index 097789051a1d..195b74da194d 100644
--- a/drivers/gpu/drm/loongson/lsdc_output.h
+++ b/drivers/gpu/drm/loongson/lsdc_output.h
@@ -6,7 +6,22 @@
#ifndef __LSDC_OUTPUT_H__
#define __LSDC_OUTPUT_H__
-#include "lsdc_drv.h"
+#include <drm/drm_encoder.h>
+#include <drm/drm_connector.h>
+
+struct lsdc_desc;
+
+struct lsdc_output_desc {
+ u32 pipe;
+ const char type[32];
+};
+
+struct lsdc_output {
+ struct device *dev;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+ struct lsdc_output_desc *descp;
+};
int ls7a1000_output_init(struct drm_device *ddev,
struct lsdc_display_pipe *dispipe,
@@ -18,4 +33,9 @@ int ls7a2000_output_init(struct drm_device *ldev,
struct i2c_adapter *ddc,
unsigned int index);
+int lsdc_output_preinit(struct device *parent,
+ const struct lsdc_desc *descp,
+ unsigned int index,
+ struct platform_device **ppdev);
+
#endif
--
2.34.1
Move drm related device initialization into loongson_drm_master_bind(),
As we need to wait all other submodules ready before we could register
the drm device to userspace. Move output related things into subdriver,
fullfill the implement under the new framework.
Signed-off-by: Sui Jingfeng <[email protected]>
---
drivers/gpu/drm/loongson/lsdc_drv.c | 187 +++++++++---------
drivers/gpu/drm/loongson/lsdc_drv.h | 22 +--
drivers/gpu/drm/loongson/lsdc_output.c | 41 ++++
drivers/gpu/drm/loongson/lsdc_output.h | 16 +-
drivers/gpu/drm/loongson/lsdc_output_7a1000.c | 3 +-
drivers/gpu/drm/loongson/lsdc_output_7a2000.c | 15 +-
6 files changed, 152 insertions(+), 132 deletions(-)
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.c b/drivers/gpu/drm/loongson/lsdc_drv.c
index 45c30e3d178f..796da5c3c2ee 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.c
+++ b/drivers/gpu/drm/loongson/lsdc_drv.c
@@ -69,31 +69,6 @@ static int lsdc_modeset_init(struct lsdc_device *ldev,
unsigned int i;
int ret;
- for (i = 0; i < num_crtc; i++) {
- dispipe = &ldev->dispipe[i];
-
- /* We need an index before crtc is initialized */
- dispipe->index = i;
-
- ret = funcs->create_i2c(ddev, dispipe, i);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < num_crtc; i++) {
- struct i2c_adapter *ddc = NULL;
-
- dispipe = &ldev->dispipe[i];
- if (dispipe->li2c)
- ddc = &dispipe->li2c->adapter;
-
- ret = funcs->output_init(ddev, dispipe, ddc, i);
- if (ret)
- return ret;
-
- ldev->num_output++;
- }
-
for (i = 0; i < num_crtc; i++) {
dispipe = &ldev->dispipe[i];
@@ -189,30 +164,17 @@ static int lsdc_get_dedicated_vram(struct lsdc_device *ldev,
return (size > SZ_1M) ? 0 : -ENODEV;
}
-static struct lsdc_device *
-lsdc_create_device(struct pci_dev *pdev,
- const struct lsdc_desc *descp,
- const struct drm_driver *driver)
+static int lsdc_device_init(struct lsdc_device *ldev,
+ const struct lsdc_desc *descp,
+ const struct drm_driver *driver)
{
- struct lsdc_device *ldev;
- struct drm_device *ddev;
+ struct drm_device *ddev = &ldev->base;
int ret;
- ldev = devm_drm_dev_alloc(&pdev->dev, driver, struct lsdc_device, base);
- if (IS_ERR(ldev))
- return ldev;
-
- ldev->dc = pdev;
- ldev->descp = descp;
-
- ddev = &ldev->base;
-
- loongson_gfxpll_create(ddev, &ldev->gfxpll);
-
- ret = lsdc_get_dedicated_vram(ldev, pdev, descp);
+ ret = lsdc_get_dedicated_vram(ldev, ldev->dc, ldev->descp);
if (ret) {
drm_err(ddev, "Init VRAM failed: %d\n", ret);
- return ERR_PTR(ret);
+ return ret;
}
ret = drm_aperture_remove_conflicting_framebuffers(ldev->vram_base,
@@ -220,36 +182,25 @@ lsdc_create_device(struct pci_dev *pdev,
driver);
if (ret) {
drm_err(ddev, "Remove firmware framebuffers failed: %d\n", ret);
- return ERR_PTR(ret);
+ return ret;
}
ret = lsdc_ttm_init(ldev);
if (ret) {
drm_err(ddev, "Memory manager init failed: %d\n", ret);
- return ERR_PTR(ret);
+ return ret;
}
lsdc_gem_init(ddev);
/* Bar 0 of the DC device contains the MMIO register's base address */
- ldev->reg_base = pcim_iomap(pdev, 0, 0);
+ ldev->reg_base = pcim_iomap(ldev->dc, 0, 0);
if (!ldev->reg_base)
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
spin_lock_init(&ldev->reglock);
- ret = lsdc_mode_config_init(ddev, descp);
- if (ret)
- return ERR_PTR(ret);
-
- ret = lsdc_modeset_init(ldev, descp->num_of_crtc, descp->funcs,
- loongson_vblank);
- if (ret)
- return ERR_PTR(ret);
-
- drm_mode_config_reset(ddev);
-
- return ldev;
+ return 0;
}
/* For multiple GPU driver instance co-exixt in the system */
@@ -261,20 +212,64 @@ static unsigned int lsdc_vga_set_decode(struct pci_dev *pdev, bool state)
static int loongson_drm_master_bind(struct device *dev)
{
+ struct lsdc_device *ldev = dev_get_drvdata(dev);
+ const struct lsdc_desc *descp = ldev->descp;
+ struct drm_device *ddev = &ldev->base;
int ret;
- ret = component_bind_all(dev, NULL);
+ if (loongson_vblank) {
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ ret = drm_vblank_init(ddev, descp->num_of_crtc);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(dev, pdev->irq,
+ descp->funcs->irq_handler,
+ IRQF_SHARED,
+ dev_name(dev), ddev);
+ if (ret) {
+ drm_err(ddev, "Failed to register interrupt: %d\n", ret);
+ return ret;
+ }
+
+ drm_info(ddev, "registered irq: %u\n", pdev->irq);
+ }
+
+ ret = lsdc_mode_config_init(ddev, descp);
+ if (ret)
+ return ret;
+
+ ret = component_bind_all(dev, ddev);
if (ret) {
dev_err(dev, "master bind all failed: %d\n", ret);
return ret;
}
+ ret = lsdc_modeset_init(ldev, descp->num_of_crtc, descp->funcs,
+ loongson_vblank);
+ if (ret)
+ return ret;
+
+ drm_mode_config_reset(ddev);
+
+ drm_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)
{
- component_unbind_all(dev, NULL);
+ struct lsdc_device *ldev = dev_get_drvdata(dev);
+ struct drm_device *ddev = &ldev->base;
+
+ component_unbind_all(dev, ddev);
return;
}
@@ -288,7 +283,6 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct component_match *matches = NULL;
const struct lsdc_desc *descp;
- struct drm_device *ddev;
struct lsdc_device *ldev;
int ret;
int i;
@@ -310,10 +304,31 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev, "Found %s, revision: %u",
to_loongson_gfx(descp)->model, pdev->revision);
- ldev = lsdc_create_device(pdev, descp, &lsdc_drm_driver);
+ ldev = devm_drm_dev_alloc(&pdev->dev, &lsdc_drm_driver,
+ struct lsdc_device, base);
if (IS_ERR(ldev))
return PTR_ERR(ldev);
+ pci_set_drvdata(pdev, ldev);
+
+ ldev->dc = pdev;
+ ldev->descp = descp;
+
+ loongson_gfxpll_create(&ldev->base, &ldev->gfxpll);
+
+ ret = lsdc_device_init(ldev, descp, &lsdc_drm_driver);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < descp->num_of_crtc; ++i) {
+ struct lsdc_display_pipe *dispipe = &ldev->dispipe[i];
+ const struct lsdc_kms_funcs *funcs = descp->funcs;
+
+ ret = funcs->create_i2c(&ldev->base, dispipe, i);
+ if (ret)
+ return ret;
+ }
+
for (i = 0; i < descp->num_of_crtc; ++i) {
ret = lsdc_output_preinit(&pdev->dev, descp, i,
&ldev->childs[i]);
@@ -333,44 +348,15 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev, "loongson add component: %u\n", ret);
- ddev = &ldev->base;
-
- pci_set_drvdata(pdev, ddev);
-
vga_client_register(pdev, lsdc_vga_set_decode);
- drm_kms_helper_poll_init(ddev);
-
- if (loongson_vblank) {
- ret = drm_vblank_init(ddev, descp->num_of_crtc);
- if (ret)
- return ret;
-
- ret = devm_request_irq(&pdev->dev, pdev->irq,
- descp->funcs->irq_handler,
- IRQF_SHARED,
- dev_name(&pdev->dev), ddev);
- if (ret) {
- drm_err(ddev, "Failed to register interrupt: %d\n", ret);
- return ret;
- }
-
- drm_info(ddev, "registered irq: %u\n", pdev->irq);
- }
-
- ret = drm_dev_register(ddev, 0);
- if (ret)
- return ret;
-
- drm_fbdev_ttm_setup(ddev, 32);
-
return 0;
}
static void lsdc_pci_remove(struct pci_dev *pdev)
{
- struct drm_device *ddev = pci_get_drvdata(pdev);
- struct lsdc_device *ldev = to_lsdc(ddev);
+ struct lsdc_device *ldev = pci_get_drvdata(pdev);
+ struct drm_device *ddev = &ldev->base;
unsigned int i;
drm_dev_unregister(ddev);
@@ -388,7 +374,10 @@ static void lsdc_pci_remove(struct pci_dev *pdev)
static void lsdc_pci_shutdown(struct pci_dev *pdev)
{
- drm_atomic_helper_shutdown(pci_get_drvdata(pdev));
+ struct lsdc_device *ldev = pci_get_drvdata(pdev);
+ struct drm_device *ddev = &ldev->base;
+
+ drm_atomic_helper_shutdown(ddev);
}
static int lsdc_drm_freeze(struct drm_device *ddev)
@@ -442,7 +431,8 @@ static int lsdc_drm_freeze(struct drm_device *ddev)
static int lsdc_drm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *ddev = pci_get_drvdata(pdev);
+ struct lsdc_device *ldev = pci_get_drvdata(pdev);
+ struct drm_device *ddev = &ldev->base;
return drm_mode_config_helper_resume(ddev);
}
@@ -450,7 +440,8 @@ static int lsdc_drm_resume(struct device *dev)
static int lsdc_pm_freeze(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *ddev = pci_get_drvdata(pdev);
+ struct lsdc_device *ldev = pci_get_drvdata(pdev);
+ struct drm_device *ddev = &ldev->base;
return lsdc_drm_freeze(ddev);
}
diff --git a/drivers/gpu/drm/loongson/lsdc_drv.h b/drivers/gpu/drm/loongson/lsdc_drv.h
index 86061207851d..2a291a4a0827 100644
--- a/drivers/gpu/drm/loongson/lsdc_drv.h
+++ b/drivers/gpu/drm/loongson/lsdc_drv.h
@@ -173,33 +173,15 @@ struct lsdc_cursor {
struct lsdc_device *ldev;
};
-static inline struct lsdc_output *
-connector_to_lsdc_output(struct drm_connector *connector)
-{
- return container_of(connector, struct lsdc_output, connector);
-}
-
-static inline struct lsdc_output *
-encoder_to_lsdc_output(struct drm_encoder *encoder)
-{
- return container_of(encoder, struct lsdc_output, encoder);
-}
-
struct lsdc_display_pipe {
struct lsdc_crtc crtc;
struct lsdc_primary primary;
struct lsdc_cursor cursor;
- struct lsdc_output output;
+ struct lsdc_output *output;
struct lsdc_i2c *li2c;
unsigned int index;
};
-static inline struct lsdc_display_pipe *
-output_to_display_pipe(struct lsdc_output *output)
-{
- return container_of(output, struct lsdc_display_pipe, output);
-}
-
struct lsdc_kms_funcs {
irqreturn_t (*irq_handler)(int irq, void *arg);
@@ -208,7 +190,7 @@ struct lsdc_kms_funcs {
unsigned int index);
int (*output_init)(struct drm_device *ddev,
- struct lsdc_display_pipe *dispipe,
+ struct lsdc_output *output,
struct i2c_adapter *ddc,
unsigned int index);
diff --git a/drivers/gpu/drm/loongson/lsdc_output.c b/drivers/gpu/drm/loongson/lsdc_output.c
index b1a9c6123615..28639a1e4407 100644
--- a/drivers/gpu/drm/loongson/lsdc_output.c
+++ b/drivers/gpu/drm/loongson/lsdc_output.c
@@ -62,6 +62,30 @@ int lsdc_output_preinit(struct device *parent,
return 0;
}
+static int lsdc_output_postinit(struct lsdc_output *output,
+ struct drm_device *ddev,
+ struct lsdc_display_pipe *dispipe,
+ unsigned int pipe)
+{
+ struct lsdc_device *ldev = to_lsdc(ddev);
+ const struct lsdc_kms_funcs *kms_funcs = ldev->descp->funcs;
+ struct i2c_adapter *ddc = NULL;
+ int ret;
+
+ if (dispipe->li2c)
+ ddc = &dispipe->li2c->adapter;
+
+ pipe = output->descp->pipe;
+
+ ret = kms_funcs->output_init(&ldev->base, output, ddc, pipe);
+ if (ret)
+ return ret;
+
+ dispipe->output = output;
+
+ return 0;
+}
+
/*
* dev stand for the port@0, port@1, ..., port@n of the dispplay controller
*/
@@ -69,6 +93,23 @@ static int lsdc_output_port_bind(struct device *dev,
struct device *master,
void *data)
{
+ struct lsdc_output *output = dev_get_drvdata(dev);
+ struct drm_device *ddev = data;
+ struct lsdc_device *ldev = to_lsdc(ddev);
+ unsigned int pipe;
+ int ret;
+
+ pipe = output->descp->pipe;
+
+ ret = lsdc_output_postinit(output, ddev, &ldev->dispipe[pipe], pipe);
+ if (ret)
+ return ret;
+
+ ldev->num_output++;
+
+ drm_info(ddev, "Output port-%d bound, type: %s\n",
+ pipe, output->descp->type);
+
return 0;
}
diff --git a/drivers/gpu/drm/loongson/lsdc_output.h b/drivers/gpu/drm/loongson/lsdc_output.h
index 195b74da194d..684a5b19bc70 100644
--- a/drivers/gpu/drm/loongson/lsdc_output.h
+++ b/drivers/gpu/drm/loongson/lsdc_output.h
@@ -23,13 +23,25 @@ struct lsdc_output {
struct lsdc_output_desc *descp;
};
+static inline struct lsdc_output *
+connector_to_lsdc_output(struct drm_connector *connector)
+{
+ return container_of(connector, struct lsdc_output, connector);
+}
+
+static inline struct lsdc_output *
+encoder_to_lsdc_output(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct lsdc_output, encoder);
+}
+
int ls7a1000_output_init(struct drm_device *ddev,
- struct lsdc_display_pipe *dispipe,
+ struct lsdc_output *output,
struct i2c_adapter *ddc,
unsigned int index);
int ls7a2000_output_init(struct drm_device *ldev,
- struct lsdc_display_pipe *dispipe,
+ struct lsdc_output *output,
struct i2c_adapter *ddc,
unsigned int index);
diff --git a/drivers/gpu/drm/loongson/lsdc_output_7a1000.c b/drivers/gpu/drm/loongson/lsdc_output_7a1000.c
index 6fc8dd1c7d9a..f331c198e3d4 100644
--- a/drivers/gpu/drm/loongson/lsdc_output_7a1000.c
+++ b/drivers/gpu/drm/loongson/lsdc_output_7a1000.c
@@ -140,11 +140,10 @@ static const struct drm_encoder_funcs ls7a1000_encoder_funcs[2] = {
};
int ls7a1000_output_init(struct drm_device *ddev,
- struct lsdc_display_pipe *dispipe,
+ struct lsdc_output *output,
struct i2c_adapter *ddc,
unsigned int index)
{
- struct lsdc_output *output = &dispipe->output;
struct drm_encoder *encoder = &output->encoder;
struct drm_connector *connector = &output->connector;
int ret;
diff --git a/drivers/gpu/drm/loongson/lsdc_output_7a2000.c b/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
index ce3dabec887e..a81852939d23 100644
--- a/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
+++ b/drivers/gpu/drm/loongson/lsdc_output_7a2000.c
@@ -284,8 +284,7 @@ static int ls7a2000_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
struct drm_display_mode *mode)
{
struct lsdc_output *output = encoder_to_lsdc_output(encoder);
- struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
- unsigned int index = dispipe->index;
+ unsigned int index = output->descp->pipe;
struct drm_device *ddev = encoder->dev;
struct lsdc_device *ldev = to_lsdc(ddev);
struct hdmi_avi_infoframe infoframe;
@@ -335,8 +334,7 @@ static void ls7a2000_hdmi_atomic_disable(struct drm_encoder *encoder,
struct drm_atomic_state *state)
{
struct lsdc_output *output = encoder_to_lsdc_output(encoder);
- struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
- unsigned int index = dispipe->index;
+ unsigned int index = output->descp->pipe;
struct drm_device *ddev = encoder->dev;
struct lsdc_device *ldev = to_lsdc(ddev);
u32 val;
@@ -360,8 +358,7 @@ static void ls7a2000_hdmi_atomic_enable(struct drm_encoder *encoder,
struct drm_device *ddev = encoder->dev;
struct lsdc_device *ldev = to_lsdc(ddev);
struct lsdc_output *output = encoder_to_lsdc_output(encoder);
- struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
- unsigned int index = dispipe->index;
+ unsigned int index = output->descp->pipe;
u32 val;
/* datasheet say it should larger than 48 */
@@ -482,8 +479,7 @@ static void ls7a2000_hdmi_atomic_mode_set(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct lsdc_output *output = encoder_to_lsdc_output(encoder);
- struct lsdc_display_pipe *dispipe = output_to_display_pipe(output);
- unsigned int index = dispipe->index;
+ unsigned int index = output->descp->pipe;
struct drm_device *ddev = encoder->dev;
struct lsdc_device *ldev = to_lsdc(ddev);
struct drm_display_mode *mode = &crtc_state->mode;
@@ -512,11 +508,10 @@ static const struct drm_encoder_helper_funcs ls7a2000_encoder_helper_funcs = {
* writing hdmi register do no harms.
*/
int ls7a2000_output_init(struct drm_device *ddev,
- struct lsdc_display_pipe *dispipe,
+ struct lsdc_output *output,
struct i2c_adapter *ddc,
unsigned int pipe)
{
- struct lsdc_output *output = &dispipe->output;
struct drm_encoder *encoder = &output->encoder;
struct drm_connector *connector = &output->connector;
int ret;
--
2.34.1
Hi Sui,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on linus/master v6.9 next-20240515]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Sui-Jingfeng/drm-loongson-Add-helpers-for-creating-subdevice/20240513-081653
base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link: https://lore.kernel.org/r/20240513001243.1739336-3-sui.jingfeng%40linux.dev
patch subject: [PATCH 2/3] drm/loongson: Introduce component framework support
config: alpha-randconfig-r133-20240515 (https://download.01.org/0day-ci/archive/20240516/[email protected]/config)
compiler: alpha-linux-gcc (GCC) 13.2.0
reproduce: (https://download.01.org/0day-ci/archive/20240516/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
sparse warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/loongson/lsdc_drv.c:282:35: sparse: sparse: symbol 'loongson_drm_master_ops' was not declared. Should it be static?
vim +/loongson_drm_master_ops +282 drivers/gpu/drm/loongson/lsdc_drv.c
281
> 282 const struct component_master_ops loongson_drm_master_ops = {
283 .bind = loongson_drm_master_bind,
284 .unbind = loongson_drm_master_unbind,
285 };
286
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
> In some display subsystems, the functionality of a PCI(e) device may too
…
> of the functionality into child devices can helps to achieve better
> modularity, eaiser for understand and maintain.
>
> Add the loongson_create_platform_device() function to pove the way …
Please avoid typos in such a change description.
Regards,
Markus
Hi,
On 5/16/24 04:30, Markus Elfring wrote:
>> In some display subsystems, the functionality of a PCI(e) device may too
> …
>> of the functionality into child devices can helps to achieve better
>> modularity, eaiser for understand and maintain.
>>
>> Add the loongson_create_platform_device() function to pove the way …
>
> Please avoid typos in such a change description.
I was too hurry, sorry, my bad.
Will be fixed at the next version.
> Regards,
> Markus
--
Best regards
Sui
…
> The idea is to devide the exterinal module dependent part …
divide | separate the external?
Please avoid typos in such a change description.
Regards,
Markus
…
> fullfill the implement under the new framework.
fulfil the implementation?
Please improve your change descriptions another bit.
Regards,
Markus
Hi,
On 5/16/24 14:26, Markus Elfring wrote:
> …
>> fullfill the implement under the new framework.
>
> fulfil the implementation?
>
> Please improve your change descriptions another bit.
I'll accept you suggestions, with pleasure. Thanks.
> Regards,
> Markus
--
Best regards
Sui
Hi,
On 5/16/24 14:26, Markus Elfring wrote:
> …
>> fullfill the implement under the new framework.
>
> fulfil the implementation?
>
> Please improve your change descriptions another bit.
OK, despite has a few typos. but the quality of the patch itself
can be guaranteed. The first version is mainly for preview purpose.
I'll fix the problem you mentioned at the next version, thanks for
reviewing.
I have tested this series before posting on ls3a6000+ls7a2000 PC:
$ dmesg | grep loongson:
[ 4.125926] loongson 0000:00:06.1: Found LS7A2000 bridge chipset,
revision: 2
[ 4.133035] loongson 0000:00:06.1: [drm] dc: 400MHz, gmc: 1200MHz,
gpu: 480MHz
[ 4.140215] loongson 0000:00:06.1: [drm] Dedicated vram start:
0xe0030000000, size: 256MiB
[ 4.148538] loongson 0000:00:06.1: [drm] VRAM: 16384 pages ready
[ 4.154506] loongson 0000:00:06.1: [drm] GTT: 32768 pages ready
[ 4.160410] loongson 0000:00:06.1: [drm] lsdc-i2c0(sda pin mask=1,
scl pin mask=2) created
[ 4.168638] loongson 0000:00:06.1: [drm] lsdc-i2c1(sda pin mask=4,
scl pin mask=8) created
[ 4.176938] loongson 0000:00:06.1: [drm] registered irq: 54
[ 4.189404] loongson 0000:00:06.1: [drm] Output port-0 bound, type:
HDMI-or-VGA-0
[ 4.196839] loongson 0000:00:06.1: bound lsdc-output-port.0 (ops
lsdc_output_port_component_ops)
[ 4.211629] loongson 0000:00:06.1: [drm] Output port-1 bound, type:
HDMI-1
[ 4.218459] loongson 0000:00:06.1: bound lsdc-output-port.1 (ops
lsdc_output_port_component_ops)
[ 4.227203] loongson 0000:00:06.1: [drm] Total 2 outputs
[ 4.272617] [drm] Initialized loongson 1.0.0 for 0000:00:06.1 on minor 0
[ 4.341588] loongson 0000:00:06.1: [drm] fb0: loongsondrmfb frame
buffer device
[ 4.348867] loongson 0000:00:06.1: loongson add component: 0
> Regards,
> Markus
--
Best regards
Sui