2018-12-21 16:04:45

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 0/9] Overview of Arm komeda display driver

This is the first patchset of ARM new komeda display driver, this patchset
added all basic structure of komeda, relationship of DRM-KMS with komeda,
for tring to give a brife overview of komeda-driver.

komeda is for supporting the ARM display processor D71 and later IPs, Since from
D71, Arm display IP begins to adopt a flexible and modularized architecture:
A display pipeline is made up of multiple individual and functional pipeline
stages called components, and every component has some specific capabilities
that can give the flowed pipeline pixel data a specific data processing.

The typical components like:

- Layer:
Layer is the first pipeline stage, It fetches the pixel from memory and
prepare the source pixel data for the next stage, like rotation, format,
color-space handling.

- Scaler:
As its name, scaler is for scaling and image enhancement.

- Compositor (compiz)
Compositor is for blending multiple layers or pixel data flows into one
single display frame.

- Writeback Layer (wb_layer)
Writeback layer do the opposite things of Layer, Which connect to compiz
for writing the composition result to memory.

- Post image processor (improc)
Post image processor is for adjusting frame data like gamma and color space
to fit the requirements of the monitor.

- Timing controller (timing_ctrlr)
Final stage of display pipeline, Timing controller is not for the pixel
handling, but only for controlling the display timing.

Benefitting from the modularized architecture, D71 pipelines can be easily
adjusted to fit different usages. And D71 has two pipelines, which support two
types of working mode:

- Dual display mode
Two pipelines work independently and separately to drive two display outputs.

- Single pipeline data flow

Layer_0 -> (scaler) ->\
Layer_1 -> (scaler) ->\ /-> (scaler) -> wb_layer -> memory
compiz ->
Layer_2 -> (scaler) ->/ \-> improc ->timing_ctrlr ->monitor
Layer_3 -> (scaler) ->/

- Single display mode
Two pipelines work together to drive only one display output.

On this mode, pipeline_B doesn't work indenpendently, but outputs its
composition result into pipeline_A, and its pixel timing also derived from
pipeline_A.timing_ctrlr. The pipeline_B works just like a "slave" of
pipeline_A(master)

- Slave enabled data flow

Layer_0 -> (scaler) ->\
Layer_1 -> (scaler) ->\
compiz_B -> compiz_A
Layer_2 -> (scaler) ->/
Layer_3 -> (scaler) ->/

compiz_B ->\
Layer_4 -> (scaler) ->\
Layer_5 -> (scaler) ->\ /-> (scaler) -> wb_layer -> memory
compiz_A ->
Layer_6 -> (scaler) ->/ \-> improc ->timing_ctrlr ->monitor
Layer_7 -> (scaler) ->/

To fully utilize and easily access/configure the HW, komeda use a similar
architecture: Pipeline/Component to describe the HW features and capabilities.
Add the DRM-KMS consideration. then:

A Komeda driver is comprised of two layers of data structures:

1. komeda_dev/pipeline/component
Which are used by komeda driver to describe and abstract a display HW.
- komeda_layer/scaler/compiz/improc/timing_ctrlr
for describing a specific pipeline component stage.
- komeda_pipeline
for abstracting a display pipeline and the pipeline is composed of multiple
components.
- komeda_dev
for the whole view of the device, manage the pipeline, irq, and the other
control-abilites of device.

2. komeda_kms_dev/crtc/plane:
Which connect Komeda-dev to DRM-KMS, basically it collects and organizes
komeda_dev's capabilities and resurces by DRM-KMS's way (crtc/plane/connector),
and convert the DRM-KMS's requirement to the real komeda_dev's configuration.

So generally, the komeda_dev is like a resource collection, and the komeda_kms
is a group of users (crtc/plane/wb_connector), the drm_state defined or
described the resource requirement of user, and every KMS-OBJ maps or represents
to a specific komeda data pipeline:

- Plane: Layer -> (Scaler) -> Compiz
- Wb_connector: Compiz-> (scaler) -> Wb_layer -> memory
- Crtc: Compiz -> Improc -> Timing_Ctrlr -> Monitor

The features and properties of KMS-OBJ based on the mapping pipeline, and the
komeda_kms level function (crtc/plane/wb_connector->atomic_check) actually
is for pickuping suitable pipeline and component resources, configure them to
a specific state and build these input/output pipeline of komeda to fit the
requirement.

Furthermore, To support multiple IPs, komeda_dev has been split into two layers:

- Komeda-CORE or common layer.
for the common feature validation and handling
- Komeda-CHIP.
for reporting and exposing the HW resource by CORE's way, the HW register
programming and updating.

With this two Layer's device abstraction, the most operations are handled in
Komeda-CORE, the Komeda-CHIP is only for CHIP-specific stuff, easy for adding
new chipset or IP in future.

v3:
- Fixed style problem found by checkpatch.pl --strict.
- Updated DT binding document according to Rob Herring's comments.

v2:
- Use "pipe" (to replace "ppl") as the short form of "pipeline".
- Some editing changes for document according to Randy Dunlap's comments.
- Adjusted the position of KOMEDA by alphabetical order.

James (Qian) Wang (9):
drm/komeda: komeda_dev/pipeline/component definition and initialzation
dt/bindings: drm/komeda: Add DT bindings for ARM display processor D71
drm/komeda: Build komeda to be a platform module
drm/komeda: Add DT parsing
drm/komeda: Add komeda_format_caps for format handling
drm/komeda: Add komeda_framebuffer
drm/komeda: Attach komeda_dev to DRM-KMS
drm/doc: Add initial komeda driver documentation
MAINTAINERS: Add maintainer for arm komeda driver

.../bindings/display/arm/arm,komeda.txt | 79 +++
Documentation/gpu/drivers.rst | 1 +
Documentation/gpu/komeda-kms.rst | 488 ++++++++++++++++++
MAINTAINERS | 9 +
drivers/gpu/drm/arm/Kconfig | 2 +
drivers/gpu/drm/arm/Makefile | 1 +
drivers/gpu/drm/arm/display/Kbuild | 3 +
drivers/gpu/drm/arm/display/Kconfig | 14 +
.../gpu/drm/arm/display/include/malidp_io.h | 42 ++
.../drm/arm/display/include/malidp_product.h | 23 +
.../drm/arm/display/include/malidp_utils.h | 16 +
drivers/gpu/drm/arm/display/komeda/Makefile | 21 +
.../gpu/drm/arm/display/komeda/d71/d71_dev.c | 111 ++++
.../gpu/drm/arm/display/komeda/komeda_crtc.c | 106 ++++
.../gpu/drm/arm/display/komeda/komeda_dev.c | 195 +++++++
.../gpu/drm/arm/display/komeda/komeda_dev.h | 113 ++++
.../gpu/drm/arm/display/komeda/komeda_drv.c | 143 +++++
.../arm/display/komeda/komeda_format_caps.c | 75 +++
.../arm/display/komeda/komeda_format_caps.h | 89 ++++
.../arm/display/komeda/komeda_framebuffer.c | 165 ++++++
.../arm/display/komeda/komeda_framebuffer.h | 31 ++
.../gpu/drm/arm/display/komeda/komeda_kms.c | 169 ++++++
.../gpu/drm/arm/display/komeda/komeda_kms.h | 113 ++++
.../drm/arm/display/komeda/komeda_pipeline.c | 202 ++++++++
.../drm/arm/display/komeda/komeda_pipeline.h | 361 +++++++++++++
.../gpu/drm/arm/display/komeda/komeda_plane.c | 109 ++++
.../arm/display/komeda/komeda_private_obj.c | 88 ++++
27 files changed, 2769 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/arm/arm,komeda.txt
create mode 100644 Documentation/gpu/komeda-kms.rst
create mode 100644 drivers/gpu/drm/arm/display/Kbuild
create mode 100644 drivers/gpu/drm/arm/display/Kconfig
create mode 100644 drivers/gpu/drm/arm/display/include/malidp_io.h
create mode 100644 drivers/gpu/drm/arm/display/include/malidp_product.h
create mode 100644 drivers/gpu/drm/arm/display/include/malidp_utils.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/Makefile
create mode 100644 drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_drv.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_plane.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c

--
2.17.1



2018-12-21 16:05:00

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 2/9] dt/bindings: drm/komeda: Add DT bindings for ARM display processor D71

Add DT bindings documentation for the ARM display processor D71 and later
IPs.

Signed-off-by: James (Qian) Wang <[email protected]>

Changes in v3:
- Deleted unnecessary property: interrupt-names.
- Dropped 'ports' and moving 'port' up a level.
---
.../bindings/display/arm/arm,komeda.txt | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/arm/arm,komeda.txt

diff --git a/Documentation/devicetree/bindings/display/arm/arm,komeda.txt b/Documentation/devicetree/bindings/display/arm/arm,komeda.txt
new file mode 100644
index 000000000000..b4e450243c7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/arm/arm,komeda.txt
@@ -0,0 +1,79 @@
+Device Tree bindings for ARM Komeda display driver
+
+Required properties:
+- compatible: Should be "arm,mali-d71"
+- reg: Physical base address and length of the registers in the system
+- interrupts: the interrupt line number of the device in the system
+- clocks: A list of phandle + clock-specifier pairs, one for each entry
+ in 'clock-names'
+- clock-names: A list of clock names. It should contain:
+ - "mclk": for the main processor clock
+ - "pclk": for the APB interface clock
+- #address-cells: Must be 1
+- #size-cells: Must be 0
+
+Required properties for sub-node: pipeline@nq
+Each device contains one or two pipeline sub-nodes (at least one), each
+pipeline node should provide properties:
+- reg: Zero-indexed identifier for the pipeline
+- clocks: A list of phandle + clock-specifier pairs, one for each entry
+ in 'clock-names'
+- clock-names: should contain:
+ - "pxclk": pixel clock
+ - "aclk": AXI interface clock
+
+- port: each pipeline connect to an encoder input port. The connection is
+ modeled using the OF graph bindings specified in
+ Documentation/devicetree/bindings/graph.txt
+
+Optional properties:
+ - memory-region: phandle to a node describing memory (see
+ Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt)
+ to be used for the framebuffer; if not present, the framebuffer may
+ be located anywhere in memory.
+
+Example:
+/ {
+ ...
+
+ dp0: display@c00000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "arm,mali-d71";
+ reg = <0xc00000 0x20000>;
+ interrupts = <0 168 4>;
+ clocks = <&dpu_mclk>, <&dpu_aclk>;
+ clock-names = "mclk", "pclk";
+
+ dp0_pipe0: pipeline@0 {
+ clocks = <&fpgaosc2>, <&dpu_aclk>;
+ clock-names = "pxclk", "aclk";
+ reg = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ dp0_pipe0_out: endpoint {
+ remote-endpoint = <&db_dvi0_in>;
+ };
+ };
+ };
+
+ dp0_pipe1: pipeline@1 {
+ clocks = <&fpgaosc2>, <&dpu_aclk>;
+ clock-names = "pxclk", "aclk";
+ reg = <1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ dp0_pipe1_out: endpoint {
+ remote-endpoint = <&db_dvi1_in>;
+ };
+ };
+ };
+ };
+ ...
+};
--
2.17.1


2018-12-21 16:05:22

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 3/9] drm/komeda: Build komeda to be a platform module

Implement a simple wrapper for platform module to build komeda to module,
Also add a very simple D71 layer code to show how to discover a product.
Komeda driver direct bind the product ENTRY function xxx_identity to DT
compatible name like:

d71_product = {
.product_id = MALIDP_D71_PRODUCT_ID,
.identify = d71_identify,
},

const struct of_device_id komeda_of_match[] = {
{ .compatible = "arm,mali-d71", .data = &d71_product, },
{},
};

Then when linux found a matched DT node and call driver to probe, we can
easily get the of data, and call into the product to do the identify:

komeda_bind()
{
...
product = of_device_get_match_data(dev);

product->identify();
...
}

Changes in v3:
- Fixed style problem found by checkpatch.pl --strict.

Signed-off-by: James (Qian) Wang <[email protected]>
---
.../gpu/drm/arm/display/include/malidp_io.h | 42 ++++++
drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
.../gpu/drm/arm/display/komeda/d71/d71_dev.c | 33 +++++
.../gpu/drm/arm/display/komeda/komeda_dev.h | 3 +
.../gpu/drm/arm/display/komeda/komeda_drv.c | 132 ++++++++++++++++++
5 files changed, 215 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/arm/display/include/malidp_io.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_drv.c

diff --git a/drivers/gpu/drm/arm/display/include/malidp_io.h b/drivers/gpu/drm/arm/display/include/malidp_io.h
new file mode 100644
index 000000000000..4fb3caf864ce
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_io.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#ifndef _MALIDP_IO_H_
+#define _MALIDP_IO_H_
+
+#include <linux/io.h>
+
+static inline u32
+malidp_read32(u32 __iomem *base, u32 offset)
+{
+ return readl((base + (offset >> 2)));
+}
+
+static inline void
+malidp_write32(u32 __iomem *base, u32 offset, u32 v)
+{
+ writel(v, (base + (offset >> 2)));
+}
+
+static inline void
+malidp_write32_mask(u32 __iomem *base, u32 offset, u32 m, u32 v)
+{
+ u32 tmp = malidp_read32(base, offset);
+
+ tmp &= (~m);
+ malidp_write32(base, offset, v | tmp);
+}
+
+static inline void
+malidp_write_group(u32 __iomem *base, u32 offset, int num, const u32 *values)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ malidp_write32(base, offset + i * 4, values[i]);
+}
+
+#endif /*_MALIDP_IO_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
index 5b44e36509b1..c03d6876ef75 100644
--- a/drivers/gpu/drm/arm/display/komeda/Makefile
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -5,7 +5,11 @@ ccflags-y := \
-I$(src)

komeda-y := \
+ komeda_drv.o \
komeda_dev.o \
- komeda_pipeline.o \
+ komeda_pipeline.o
+
+komeda-y += \
+ d71/d71_dev.o

obj-$(CONFIG_DRM_KOMEDA) += komeda.o
diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
new file mode 100644
index 000000000000..af3dabb499cd
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include "malidp_io.h"
+#include "komeda_dev.h"
+
+static int d71_enum_resources(struct komeda_dev *mdev)
+{
+ /* TODO add enum resources */
+ return -1;
+}
+
+static struct komeda_dev_funcs d71_chip_funcs = {
+ .enum_resources = d71_enum_resources,
+ .cleanup = NULL,
+};
+
+#define GLB_ARCH_ID 0x000
+#define GLB_CORE_ID 0x004
+#define GLB_CORE_INFO 0x008
+
+struct komeda_dev_funcs *
+d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)
+{
+ chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID);
+ chip->core_id = malidp_read32(reg_base, GLB_CORE_ID);
+ chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO);
+
+ return &d71_chip_funcs;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
index ad8fa160eff9..680e3e2cf100 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -92,6 +92,9 @@ komeda_product_match(struct komeda_dev *mdev, u32 target)
return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
}

+struct komeda_dev_funcs *
+d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip);
+
struct komeda_dev *komeda_dev_create(struct device *dev);
void komeda_dev_destroy(struct komeda_dev *mdev);

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
new file mode 100644
index 000000000000..a2657b3d09d7
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <drm/drm_of.h>
+#include "komeda_dev.h"
+
+struct komeda_drv {
+ struct komeda_dev *mdev;
+};
+
+static void komeda_unbind(struct device *dev)
+{
+ struct komeda_drv *mdrv = dev_get_drvdata(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+ if (!mdrv)
+ return;
+
+ komeda_dev_destroy(mdrv->mdev);
+ kfree(mdrv);
+}
+
+static int komeda_bind(struct device *dev)
+{
+ struct komeda_drv *mdrv;
+ int err;
+
+ mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
+ if (!mdrv)
+ return -ENOMEM;
+
+ mdrv->mdev = komeda_dev_create(dev);
+ if (IS_ERR(mdrv->mdev)) {
+ err = PTR_ERR(mdrv->mdev);
+ goto free_mdrv;
+ }
+
+ dev_set_drvdata(dev, mdrv);
+
+ return 0;
+
+free_mdrv:
+ kfree(mdrv);
+ return err;
+}
+
+static const struct component_master_ops komeda_master_ops = {
+ .bind = komeda_bind,
+ .unbind = komeda_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static void komeda_add_slave(struct device *master,
+ struct component_match **match,
+ struct device_node *np, int port)
+{
+ struct device_node *remote;
+
+ remote = of_graph_get_remote_node(np, port, 0);
+ if (!remote) {
+ drm_of_component_match_add(master, match, compare_of, remote);
+ of_node_put(remote);
+ }
+}
+
+static int komeda_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct component_match *match = NULL;
+ struct device_node *child;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ for_each_available_child_of_node(dev->of_node, child) {
+ if (of_node_cmp(child->name, "pipeline") != 0)
+ continue;
+
+ /* add connector */
+ komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
+ }
+
+ return component_master_add_with_match(dev, &komeda_master_ops, match);
+}
+
+static int komeda_platform_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &komeda_master_ops);
+ return 0;
+}
+
+static const struct komeda_product_data komeda_products[] = {
+ [MALI_D71] = {
+ .product_id = MALIDP_D71_PRODUCT_ID,
+ .identify = d71_identify,
+ },
+};
+
+const struct of_device_id komeda_of_match[] = {
+ { .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, komeda_of_match);
+
+static struct platform_driver komeda_platform_driver = {
+ .probe = komeda_platform_probe,
+ .remove = komeda_platform_remove,
+ .driver = {
+ .name = "komeda",
+ .of_match_table = komeda_of_match,
+ .pm = NULL,
+ },
+};
+
+module_platform_driver(komeda_platform_driver);
+
+MODULE_AUTHOR("James.Qian.Wang <[email protected]>");
+MODULE_DESCRIPTION("Komeda KMS driver");
+MODULE_LICENSE("GPL v2");
--
2.17.1


2018-12-21 16:05:59

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 5/9] drm/komeda: Add komeda_format_caps for format handling

komeda_format_caps is for describing ARM display specific features and
limitations of a specific format, and format_caps will be linked into
&komeda_framebuffer like a extension of &drm_format_info.
And komed_format_caps_table will be initialized before the enum_resources,
since the layer features description depend on this format_caps table, so
we'd better initialize the table first.

Changes in v3:
- Fixed style problem found by checkpatch.pl --strict.

Signed-off-by: James (Qian) Wang <[email protected]>
---
drivers/gpu/drm/arm/display/komeda/Makefile | 1 +
.../gpu/drm/arm/display/komeda/d71/d71_dev.c | 78 ++++++++++++++++
.../gpu/drm/arm/display/komeda/komeda_dev.c | 2 +
.../gpu/drm/arm/display/komeda/komeda_dev.h | 11 ++-
.../arm/display/komeda/komeda_format_caps.c | 75 ++++++++++++++++
.../arm/display/komeda/komeda_format_caps.h | 89 +++++++++++++++++++
.../drm/arm/display/komeda/komeda_pipeline.h | 1 +
7 files changed, 256 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h

diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
index c03d6876ef75..394fc2aa434a 100644
--- a/drivers/gpu/drm/arm/display/komeda/Makefile
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -7,6 +7,7 @@ ccflags-y := \
komeda-y := \
komeda_drv.o \
komeda_dev.o \
+ komeda_format_caps.o \
komeda_pipeline.o

komeda-y += \
diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
index af3dabb499cd..edbf9daa1545 100644
--- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
@@ -13,7 +13,85 @@ static int d71_enum_resources(struct komeda_dev *mdev)
return -1;
}

+#define __HW_ID(__group, __format) \
+ ((((__group) & 0x7) << 3) | ((__format) & 0x7))
+
+#define RICH KOMEDA_FMT_RICH_LAYER
+#define SIMPLE KOMEDA_FMT_SIMPLE_LAYER
+#define RICH_SIMPLE (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_SIMPLE_LAYER)
+#define RICH_WB (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_WB_LAYER)
+#define RICH_SIMPLE_WB (RICH_SIMPLE | KOMEDA_FMT_WB_LAYER)
+
+#define Rot_0 DRM_MODE_ROTATE_0
+#define Flip_H_V (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | Rot_0)
+#define Rot_ALL_H_V (DRM_MODE_ROTATE_MASK | Flip_H_V)
+
+#define LYT_NM BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)
+#define LYT_WB BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
+#define LYT_NM_WB (LYT_NM | LYT_WB)
+
+#define AFB_TH AFBC(_TILED | _SPARSE)
+#define AFB_TH_SC_YTR AFBC(_TILED | _SC | _SPARSE | _YTR)
+#define AFB_TH_SC_YTR_BS AFBC(_TILED | _SC | _SPARSE | _YTR | _SPLIT)
+
+static struct komeda_format_caps d71_format_caps_table[] = {
+ /* HW_ID | fourcc | tile_sz | layer_types | rots | afbc_layouts | afbc_features */
+ /* ABGR_2101010*/
+ {__HW_ID(0, 0), DRM_FORMAT_ARGB2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
+ {__HW_ID(0, 2), DRM_FORMAT_RGBA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(0, 3), DRM_FORMAT_BGRA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ /* ABGR_8888*/
+ {__HW_ID(1, 0), DRM_FORMAT_ARGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
+ {__HW_ID(1, 2), DRM_FORMAT_RGBA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(1, 3), DRM_FORMAT_BGRA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ /* XBGB_8888 */
+ {__HW_ID(2, 0), DRM_FORMAT_XRGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(2, 1), DRM_FORMAT_XBGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(2, 2), DRM_FORMAT_RGBX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ {__HW_ID(2, 3), DRM_FORMAT_BGRX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
+ /* BGR_888 */ /* none-afbc RGB888 doesn't support rotation and flip */
+ {__HW_ID(3, 0), DRM_FORMAT_RGB888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
+ {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
+ {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
+ /* BGR 16bpp */
+ {__HW_ID(4, 0), DRM_FORMAT_RGBA5551, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
+ {__HW_ID(4, 2), DRM_FORMAT_RGB565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
+ {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
+ {__HW_ID(4, 4), DRM_FORMAT_R8, 1, SIMPLE, Rot_0, 0, 0},
+ /* YUV 444/422/420 8bit */
+ {__HW_ID(5, 0), 0 /*XYUV8888*/, 1, 0, 0, 0, 0},
+ /* XYUV unsupported*/
+ {__HW_ID(5, 1), DRM_FORMAT_YUYV, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
+ {__HW_ID(5, 2), DRM_FORMAT_YUYV, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(5, 3), DRM_FORMAT_UYVY, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(5, 4), 0, /*X0L0 */ 2, 0, 0, 0}, /* Y0L0 unsupported */
+ {__HW_ID(5, 6), DRM_FORMAT_NV12, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(5, 6), 0/*DRM_FORMAT_YUV420_8BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
+ {__HW_ID(5, 7), DRM_FORMAT_YUV420, 1, RICH, Flip_H_V, 0, 0},
+ /* YUV 10bit*/
+ {__HW_ID(6, 0), 0,/*XVYU2101010*/ 1, 0, 0, 0, 0},/* VYV30 unsupported */
+ {__HW_ID(6, 6), 0/*DRM_FORMAT_X0L2*/, 2, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(6, 7), 0/*DRM_FORMAT_P010*/, 1, RICH, Flip_H_V, 0, 0},
+ {__HW_ID(6, 7), 0/*DRM_FORMAT_YUV420_10BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH},
+};
+
+static void d71_init_fmt_tbl(struct komeda_dev *mdev)
+{
+ struct komeda_format_caps_table *table = &mdev->fmt_tbl;
+
+ table->format_caps = d71_format_caps_table;
+ table->n_formats = ARRAY_SIZE(d71_format_caps_table);
+}
+
static struct komeda_dev_funcs d71_chip_funcs = {
+ .init_format_table = d71_init_fmt_tbl,
.enum_resources = d71_enum_resources,
.cleanup = NULL,
};
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
index d0cc4f758077..2f8f4685eb62 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -138,6 +138,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
MALIDP_CORE_ID_MINOR(mdev->chip.core_id));

+ mdev->funcs->init_format_table(mdev);
+
err = mdev->funcs->enum_resources(mdev);
if (err) {
DRM_ERROR("enumerate display resource failed.\n");
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
index 4a27a44e2ec6..555510be66f1 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include "komeda_pipeline.h"
#include "malidp_product.h"
+#include "komeda_format_caps.h"

/* malidp device id */
enum {
@@ -44,6 +45,13 @@ struct komeda_dev;
* Supplied by chip level and returned by the chip entry function xxx_identify,
*/
struct komeda_dev_funcs {
+ /**
+ * @init_format_table:
+ *
+ * initialize &komeda_dev->format_table, this function should be called
+ * before the &enum_resource
+ */
+ void (*init_format_table)(struct komeda_dev *mdev);
/**
* @enum_resources:
*
@@ -66,7 +74,8 @@ struct komeda_dev {
u32 __iomem *reg_base;

struct komeda_chip_info chip;
-
+ /** @fmt_tbl: initialized by &komeda_dev_funcs->init_format_table */
+ struct komeda_format_caps_table fmt_tbl;
/** @pclk: APB clock for register access */
struct clk *pclk;
/** @mck: HW main engine clk */
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
new file mode 100644
index 000000000000..1e17bd6107a4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+
+#include <linux/slab.h>
+#include "komeda_format_caps.h"
+#include "malidp_utils.h"
+
+const struct komeda_format_caps *
+komeda_get_format_caps(struct komeda_format_caps_table *table,
+ u32 fourcc, u64 modifier)
+{
+ const struct komeda_format_caps *caps;
+ u64 afbc_features = modifier & ~(AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
+ u32 afbc_layout = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
+ int id;
+
+ for (id = 0; id < table->n_formats; id++) {
+ caps = &table->format_caps[id];
+
+ if (fourcc != caps->fourcc)
+ continue;
+
+ if ((modifier == 0ULL) && (caps->supported_afbc_layouts == 0))
+ return caps;
+
+ if (has_bits(afbc_features, caps->supported_afbc_features) &&
+ has_bit(afbc_layout, caps->supported_afbc_layouts))
+ return caps;
+ }
+
+ return NULL;
+}
+
+u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
+ u32 layer_type, u32 *n_fmts)
+{
+ const struct komeda_format_caps *cap;
+ u32 *fmts;
+ int i, j, n = 0;
+
+ fmts = kcalloc(table->n_formats, sizeof(u32), GFP_KERNEL);
+ if (!fmts)
+ return NULL;
+
+ for (i = 0; i < table->n_formats; i++) {
+ cap = &table->format_caps[i];
+ if (!(layer_type & cap->supported_layer_types) ||
+ (cap->fourcc == 0))
+ continue;
+
+ /* one fourcc may has two caps items in table (afbc/none-afbc),
+ * so check the existing list to avoid adding a duplicated one.
+ */
+ for (j = n - 1; j >= 0; j--)
+ if (fmts[j] == cap->fourcc)
+ break;
+
+ if (j < 0)
+ fmts[n++] = cap->fourcc;
+ }
+
+ if (n_fmts)
+ *n_fmts = n;
+
+ return fmts;
+}
+
+void komeda_put_fourcc_list(u32 *fourcc_list)
+{
+ kfree(fourcc_list);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
new file mode 100644
index 000000000000..60f39e77b098
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+
+#ifndef _KOMEDA_FORMAT_CAPS_H_
+#define _KOMEDA_FORMAT_CAPS_H_
+
+#include <linux/types.h>
+#include <uapi/drm/drm_fourcc.h>
+#include <drm/drm_fourcc.h>
+
+#define AFBC(x) DRM_FORMAT_MOD_ARM_AFBC(x)
+
+/* afbc layerout */
+#define AFBC_16x16(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | (x))
+#define AFBC_32x8(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | (x))
+
+/* afbc features */
+#define _YTR AFBC_FORMAT_MOD_YTR
+#define _SPLIT AFBC_FORMAT_MOD_SPLIT
+#define _SPARSE AFBC_FORMAT_MOD_SPARSE
+#define _CBR AFBC_FORMAT_MOD_CBR
+#define _TILED AFBC_FORMAT_MOD_TILED
+#define _SC AFBC_FORMAT_MOD_SC
+
+/* layer_type */
+#define KOMEDA_FMT_RICH_LAYER BIT(0)
+#define KOMEDA_FMT_SIMPLE_LAYER BIT(1)
+#define KOMEDA_FMT_WB_LAYER BIT(2)
+
+#define AFBC_TH_LAYOUT_ALIGNMENT 8
+#define AFBC_HEADER_SIZE 16
+#define AFBC_SUPERBLK_ALIGNMENT 128
+#define AFBC_SUPERBLK_PIXELS 256
+#define AFBC_BODY_START_ALIGNMENT 1024
+#define AFBC_TH_BODY_START_ALIGNMENT 4096
+
+/**
+ * struct komeda_format_caps
+ *
+ * komeda_format_caps is for describing ARM display specific features and
+ * limitations for a specific format, and format_caps will be linked into
+ * &komeda_framebuffer like a extension of &drm_format_info.
+ *
+ * NOTE: one fourcc may has two different format_caps items for fourcc and
+ * fourcc+modifier
+ *
+ * @hw_id: hw format id, hw specific value.
+ * @fourcc: drm fourcc format.
+ * @tile_size: format tiled size, used by ARM format X0L0/X0L2
+ * @supported_layer_types: indicate which layer supports this format
+ * @supported_rots: allowed rotations for this format
+ * @supported_afbc_layouts: supported afbc layerout
+ * @supported_afbc_features: supported afbc features
+ */
+struct komeda_format_caps {
+ u32 hw_id;
+ u32 fourcc;
+ u32 tile_size;
+ u32 supported_layer_types;
+ u32 supported_rots;
+ u32 supported_afbc_layouts;
+ u64 supported_afbc_features;
+};
+
+/**
+ * struct komeda_format_caps_table - format_caps mananger
+ *
+ * @n_formats: the size of format_caps list.
+ * @format_caps: format_caps list.
+ */
+struct komeda_format_caps_table {
+ u32 n_formats;
+ const struct komeda_format_caps *format_caps;
+};
+
+const struct komeda_format_caps *
+komeda_get_format_caps(struct komeda_format_caps_table *table,
+ u32 fourcc, u64 modifier);
+
+u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
+ u32 layer_type, u32 *n_fmts);
+
+void komeda_put_fourcc_list(u32 *fourcc_list);
+
+#endif
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index d1e0c1140273..2d68ffeae25d 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -213,6 +213,7 @@ static inline u16 component_changed_inputs(struct komeda_component_state *st)
struct komeda_layer {
struct komeda_component base;
/* layer specific features and caps */
+ int layer_type; /* RICH, SIMPLE or WB */
};

struct komeda_layer_state {
--
2.17.1


2018-12-21 16:06:46

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 4/9] drm/komeda: Add DT parsing

Parse DT and initialize corresponding dev/pipeline attributes.

Changes in v3:
- Fixed style problem found by checkpatch.pl --strict.

Changes in v2:
- Unified abbreviation of "pipeline" to "pipe".

Signed-off-by: James (Qian) Wang <[email protected]>
---
.../gpu/drm/arm/display/komeda/komeda_dev.c | 76 +++++++++++++++++++
.../gpu/drm/arm/display/komeda/komeda_dev.h | 3 +
.../drm/arm/display/komeda/komeda_pipeline.c | 4 +
.../drm/arm/display/komeda/komeda_pipeline.h | 7 ++
4 files changed, 90 insertions(+)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
index 887a17005367..d0cc4f758077 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -12,6 +12,76 @@
#include <linux/version.h>
#include "komeda_dev.h"

+static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
+{
+ struct komeda_pipeline *pipe;
+ struct clk *clk;
+ u32 pipe_id;
+ int ret = 0;
+
+ ret = of_property_read_u32(np, "reg", &pipe_id);
+ if (ret != 0 || pipe_id >= mdev->n_pipelines)
+ return -EINVAL;
+
+ pipe = mdev->pipelines[pipe_id];
+
+ clk = of_clk_get_by_name(np, "aclk");
+ if (IS_ERR(clk)) {
+ DRM_ERROR("get aclk for pipeline %d failed!\n", pipe_id);
+ return PTR_ERR(clk);
+ }
+ pipe->aclk = clk;
+
+ clk = of_clk_get_by_name(np, "pxclk");
+ if (IS_ERR(clk)) {
+ DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id);
+ return PTR_ERR(clk);
+ }
+ pipe->pxlclk = clk;
+
+ /* enum ports */
+ pipe->of_output_dev =
+ of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
+ pipe->of_output_port =
+ of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
+
+ pipe->of_node = np;
+
+ return 0;
+}
+
+static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *child, *np = dev->of_node;
+ struct clk *clk;
+ int ret;
+
+ clk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ mdev->mclk = clk;
+ mdev->irq = platform_get_irq(pdev, 0);
+ if (mdev->irq < 0) {
+ DRM_ERROR("could not get IRQ number.\n");
+ return mdev->irq;
+ }
+
+ for_each_available_child_of_node(np, child) {
+ if (of_node_cmp(child->name, "pipeline") == 0) {
+ ret = komeda_parse_pipe_dt(mdev, child);
+ if (ret) {
+ DRM_ERROR("parse pipeline dt error!\n");
+ of_node_put(child);
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
struct komeda_dev *komeda_dev_create(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -74,6 +144,12 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
goto err_cleanup;
}

+ err = komeda_parse_dt(dev, mdev);
+ if (err) {
+ DRM_ERROR("parse device tree failed.\n");
+ goto err_cleanup;
+ }
+
return mdev;

err_cleanup:
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
index 680e3e2cf100..4a27a44e2ec6 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -72,6 +72,9 @@ struct komeda_dev {
/** @mck: HW main engine clk */
struct clk *mclk;

+ /** @irq: irq number */
+ u32 irq;
+
int n_pipelines;
struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
index 9293598b0533..e731b2a85c3a 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -55,6 +55,10 @@ void komeda_pipeline_destroy(struct komeda_dev *mdev,
clk_put(pipe->pxlclk);
clk_put(pipe->aclk);

+ of_node_put(pipe->of_output_dev);
+ of_node_put(pipe->of_output_port);
+ of_node_put(pipe->of_node);
+
devm_kfree(mdev->dev, pipe);
}

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 2174796d47c5..d1e0c1140273 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -290,6 +290,13 @@ struct komeda_pipeline {
struct komeda_improc *improc;
struct komeda_timing_ctrlr *ctrlr;
struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
+
+ /** @of_node: pipeline dt node */
+ struct device_node *of_node;
+ /** @of_output_port: pipeline output port */
+ struct device_node *of_output_port;
+ /** @of_output_dev: output connector device node */
+ struct device_node *of_output_dev;
};

/**
--
2.17.1


2018-12-21 16:06:56

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 1/9] drm/komeda: komeda_dev/pipeline/component definition and initialzation

1. Added a brief definition of komeda_dev/pipeline/component, this change
didn't add the detailed component features and capabilities, which will
be added in the following changes.
2. Corresponding resources discovery and initialzation functions.

Signed-off-by: James (Qian) Wang <[email protected]>

Changes in v3:
- Fixed style problem found by checkpatch.pl --strict.

Changes in v2:
- Unified abbreviation of "pipeline" to "pipe".
---
drivers/gpu/drm/arm/Kconfig | 2 +
drivers/gpu/drm/arm/Makefile | 1 +
drivers/gpu/drm/arm/display/Kbuild | 3 +
drivers/gpu/drm/arm/display/Kconfig | 14 +
.../drm/arm/display/include/malidp_product.h | 23 ++
.../drm/arm/display/include/malidp_utils.h | 16 +
drivers/gpu/drm/arm/display/komeda/Makefile | 11 +
.../gpu/drm/arm/display/komeda/komeda_dev.c | 117 ++++++
.../gpu/drm/arm/display/komeda/komeda_dev.h | 98 +++++
.../drm/arm/display/komeda/komeda_pipeline.c | 198 ++++++++++
.../drm/arm/display/komeda/komeda_pipeline.h | 350 ++++++++++++++++++
11 files changed, 833 insertions(+)
create mode 100644 drivers/gpu/drm/arm/display/Kbuild
create mode 100644 drivers/gpu/drm/arm/display/Kconfig
create mode 100644 drivers/gpu/drm/arm/display/include/malidp_product.h
create mode 100644 drivers/gpu/drm/arm/display/include/malidp_utils.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/Makefile
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h

diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index f9f7761cb2f4..a204103b3efb 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -37,4 +37,6 @@ config DRM_MALI_DISPLAY

If compiled as a module it will be called mali-dp.

+source "drivers/gpu/drm/arm/display/Kconfig"
+
endmenu
diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
index 3bf31d1a4722..120bef801fcf 100644
--- a/drivers/gpu/drm/arm/Makefile
+++ b/drivers/gpu/drm/arm/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
mali-dp-y += malidp_mw.o
obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
+obj-$(CONFIG_DRM_KOMEDA) += display/
diff --git a/drivers/gpu/drm/arm/display/Kbuild b/drivers/gpu/drm/arm/display/Kbuild
new file mode 100644
index 000000000000..382f1ca831e4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/Kbuild
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_DRM_KOMEDA) += komeda/
diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig
new file mode 100644
index 000000000000..cec0639e3aa1
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+config DRM_KOMEDA
+ tristate "ARM Komeda display driver"
+ depends on DRM && OF
+ depends on COMMON_CLK
+ select DRM_KMS_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_GEM_CMA_HELPER
+ select VIDEOMODE_HELPERS
+ help
+ Choose this option if you want to compile the ARM Komeda display
+ Processor driver. It supports the D71 variants of the hardware.
+
+ If compiled as a module it will be called komeda.
diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h
new file mode 100644
index 000000000000..b35fc5db866b
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_product.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#ifndef _MALIDP_PRODUCT_H_
+#define _MALIDP_PRODUCT_H_
+
+/* Product identification */
+#define MALIDP_CORE_ID(__product, __major, __minor, __status) \
+ ((((__product) & 0xFFFF) << 16) | (((__major) & 0xF) << 12) | \
+ (((__minor) & 0xF) << 8) | ((__status) & 0xFF))
+
+#define MALIDP_CORE_ID_PRODUCT_ID(__core_id) ((__u32)(__core_id) >> 16)
+#define MALIDP_CORE_ID_MAJOR(__core_id) (((__u32)(__core_id) >> 12) & 0xF)
+#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 8) & 0xF)
+#define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF)
+
+/* Mali-display product IDs */
+#define MALIDP_D71_PRODUCT_ID 0x0071
+
+#endif /* _MALIDP_PRODUCT_H_ */
diff --git a/drivers/gpu/drm/arm/display/include/malidp_utils.h b/drivers/gpu/drm/arm/display/include/malidp_utils.h
new file mode 100644
index 000000000000..63cc47cefcf8
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/include/malidp_utils.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#ifndef _MALIDP_UTILS_
+#define _MALIDP_UTILS_
+
+#define has_bit(nr, mask) (BIT(nr) & (mask))
+#define has_bits(bits, mask) (((bits) & (mask)) == (bits))
+
+#define dp_for_each_set_bit(bit, mask) \
+ for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8)
+
+#endif /* _MALIDP_UTILS_ */
diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
new file mode 100644
index 000000000000..5b44e36509b1
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-y := \
+ -I$(src)/../include \
+ -I$(src)
+
+komeda-y := \
+ komeda_dev.o \
+ komeda_pipeline.o \
+
+obj-$(CONFIG_DRM_KOMEDA) += komeda.o
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
new file mode 100644
index 000000000000..887a17005367
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/version.h>
+#include "komeda_dev.h"
+
+struct komeda_dev *komeda_dev_create(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct komeda_product_data *product;
+ struct komeda_dev *mdev;
+ struct resource *io_res;
+ int err = 0;
+
+ product = of_device_get_match_data(dev);
+ if (!product)
+ return ERR_PTR(-ENODEV);
+
+ io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!io_res) {
+ DRM_ERROR("No registers defined.\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return ERR_PTR(-ENOMEM);
+
+ mdev->dev = dev;
+ mdev->reg_base = devm_ioremap_resource(dev, io_res);
+ if (IS_ERR(mdev->reg_base)) {
+ DRM_ERROR("Map register space failed.\n");
+ err = PTR_ERR(mdev->reg_base);
+ mdev->reg_base = NULL;
+ goto err_cleanup;
+ }
+
+ mdev->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(mdev->pclk)) {
+ DRM_ERROR("Get APB clk failed.\n");
+ err = PTR_ERR(mdev->pclk);
+ mdev->pclk = NULL;
+ goto err_cleanup;
+ }
+
+ /* Enable APB clock to access the registers */
+ clk_prepare_enable(mdev->pclk);
+
+ mdev->funcs = product->identify(mdev->reg_base, &mdev->chip);
+ if (!komeda_product_match(mdev, product->product_id)) {
+ DRM_ERROR("DT configured %x mismatch with real HW %x.\n",
+ product->product_id,
+ MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
+ err = -ENODEV;
+ goto err_cleanup;
+ }
+
+ DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
+ MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),
+ MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
+ MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
+
+ err = mdev->funcs->enum_resources(mdev);
+ if (err) {
+ DRM_ERROR("enumerate display resource failed.\n");
+ goto err_cleanup;
+ }
+
+ return mdev;
+
+err_cleanup:
+ komeda_dev_destroy(mdev);
+ return ERR_PTR(err);
+}
+
+void komeda_dev_destroy(struct komeda_dev *mdev)
+{
+ struct device *dev = mdev->dev;
+ struct komeda_dev_funcs *funcs = mdev->funcs;
+ int i;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
+ mdev->pipelines[i] = NULL;
+ }
+
+ mdev->n_pipelines = 0;
+
+ if (funcs && funcs->cleanup)
+ funcs->cleanup(mdev);
+
+ if (mdev->reg_base) {
+ devm_iounmap(dev, mdev->reg_base);
+ mdev->reg_base = NULL;
+ }
+
+ if (mdev->mclk) {
+ devm_clk_put(dev, mdev->mclk);
+ mdev->mclk = NULL;
+ }
+
+ if (mdev->pclk) {
+ clk_disable_unprepare(mdev->pclk);
+ devm_clk_put(dev, mdev->pclk);
+ mdev->pclk = NULL;
+ }
+
+ devm_kfree(dev, mdev);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
new file mode 100644
index 000000000000..ad8fa160eff9
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#ifndef _KOMEDA_DEV_H_
+#define _KOMEDA_DEV_H_
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include "komeda_pipeline.h"
+#include "malidp_product.h"
+
+/* malidp device id */
+enum {
+ MALI_D71 = 0,
+};
+
+/* pipeline DT ports */
+enum {
+ KOMEDA_OF_PORT_OUTPUT = 0,
+ KOMEDA_OF_PORT_COPROC = 1,
+};
+
+struct komeda_chip_info {
+ u32 arch_id;
+ u32 core_id;
+ u32 core_info;
+ u32 bus_width;
+};
+
+struct komeda_product_data {
+ u32 product_id;
+ struct komeda_dev_funcs *(*identify)(u32 __iomem *reg,
+ struct komeda_chip_info *info);
+};
+
+struct komeda_dev;
+
+/**
+ * struct komeda_dev_funcs
+ *
+ * Supplied by chip level and returned by the chip entry function xxx_identify,
+ */
+struct komeda_dev_funcs {
+ /**
+ * @enum_resources:
+ *
+ * for CHIP to report or add pipeline and component resources to CORE
+ */
+ int (*enum_resources)(struct komeda_dev *mdev);
+ /** @cleanup: call to chip to cleanup komeda_dev->chip data */
+ void (*cleanup)(struct komeda_dev *mdev);
+};
+
+/**
+ * struct komeda_dev
+ *
+ * Pipeline and component are used to describe how to handle the pixel data.
+ * komeda_device is for describing the whole view of the device, and the
+ * control-abilites of device.
+ */
+struct komeda_dev {
+ struct device *dev;
+ u32 __iomem *reg_base;
+
+ struct komeda_chip_info chip;
+
+ /** @pclk: APB clock for register access */
+ struct clk *pclk;
+ /** @mck: HW main engine clk */
+ struct clk *mclk;
+
+ int n_pipelines;
+ struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
+
+ /** @funcs: chip funcs to access to HW */
+ struct komeda_dev_funcs *funcs;
+ /**
+ * @chip_data:
+ *
+ * chip data will be added by &komeda_dev_funcs.enum_resources() and
+ * destroyed by &komeda_dev_funcs.cleanup()
+ */
+ void *chip_data;
+};
+
+static inline bool
+komeda_product_match(struct komeda_dev *mdev, u32 target)
+{
+ return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
+}
+
+struct komeda_dev *komeda_dev_create(struct device *dev);
+void komeda_dev_destroy(struct komeda_dev *mdev);
+
+#endif /*_KOMEDA_DEV_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
new file mode 100644
index 000000000000..9293598b0533
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include <linux/clk.h>
+#include "komeda_dev.h"
+#include "komeda_pipeline.h"
+
+/** komeda_pipeline_add - Add a pipeline to &komeda_dev */
+struct komeda_pipeline *
+komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
+ struct komeda_pipeline_funcs *funcs)
+{
+ struct komeda_pipeline *pipe;
+
+ if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
+ DRM_ERROR("Exceed max support %d pipelines.\n",
+ KOMEDA_MAX_PIPELINES);
+ return NULL;
+ }
+
+ if (size < sizeof(*pipe)) {
+ DRM_ERROR("Request pipeline size too small.\n");
+ return NULL;
+ }
+
+ pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
+ if (!pipe)
+ return NULL;
+
+ pipe->mdev = mdev;
+ pipe->id = mdev->n_pipelines;
+ pipe->funcs = funcs;
+
+ mdev->pipelines[mdev->n_pipelines] = pipe;
+ mdev->n_pipelines++;
+
+ return pipe;
+}
+
+void komeda_pipeline_destroy(struct komeda_dev *mdev,
+ struct komeda_pipeline *pipe)
+{
+ struct komeda_component *c;
+ int i;
+
+ dp_for_each_set_bit(i, pipe->avail_comps) {
+ c = komeda_pipeline_get_component(pipe, i);
+
+ komeda_component_destroy(mdev, c);
+ }
+
+ clk_put(pipe->pxlclk);
+ clk_put(pipe->aclk);
+
+ devm_kfree(mdev->dev, pipe);
+}
+
+struct komeda_component **
+komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
+{
+ struct komeda_dev *mdev = pipe->mdev;
+ struct komeda_pipeline *temp = NULL;
+ struct komeda_component **pos = NULL;
+
+ switch (id) {
+ case KOMEDA_COMPONENT_LAYER0:
+ case KOMEDA_COMPONENT_LAYER1:
+ case KOMEDA_COMPONENT_LAYER2:
+ case KOMEDA_COMPONENT_LAYER3:
+ pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
+ break;
+ case KOMEDA_COMPONENT_WB_LAYER:
+ pos = to_cpos(pipe->wb_layer);
+ break;
+ case KOMEDA_COMPONENT_COMPIZ0:
+ case KOMEDA_COMPONENT_COMPIZ1:
+ temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
+ if (!temp) {
+ DRM_ERROR("compiz-%d doesn't exist.\n", id);
+ return NULL;
+ }
+ pos = to_cpos(temp->compiz);
+ break;
+ case KOMEDA_COMPONENT_SCALER0:
+ case KOMEDA_COMPONENT_SCALER1:
+ pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
+ break;
+ case KOMEDA_COMPONENT_IPS0:
+ case KOMEDA_COMPONENT_IPS1:
+ temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
+ if (!temp) {
+ DRM_ERROR("ips-%d doesn't exist.\n", id);
+ return NULL;
+ }
+ pos = to_cpos(temp->improc);
+ break;
+ case KOMEDA_COMPONENT_TIMING_CTRLR:
+ pos = to_cpos(pipe->ctrlr);
+ break;
+ default:
+ pos = NULL;
+ DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
+ break;
+ }
+
+ return pos;
+}
+
+struct komeda_component *
+komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
+{
+ struct komeda_component **pos = NULL;
+ struct komeda_component *c = NULL;
+
+ pos = komeda_pipeline_get_component_pos(pipe, id);
+ if (pos)
+ c = *pos;
+
+ return c;
+}
+
+/** komeda_component_add - Add a component to &komeda_pipeline */
+struct komeda_component *
+komeda_component_add(struct komeda_pipeline *pipe,
+ size_t comp_sz, u32 id, u32 hw_id,
+ struct komeda_component_funcs *funcs,
+ u8 max_active_inputs, u32 supported_inputs,
+ u8 max_active_outputs, u32 __iomem *reg,
+ const char *name_fmt, ...)
+{
+ struct komeda_component **pos;
+ struct komeda_component *c;
+ int idx, *num = NULL;
+
+ if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
+ WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
+ max_active_inputs);
+ return NULL;
+ }
+
+ pos = komeda_pipeline_get_component_pos(pipe, id);
+ if (!pos || !(*pos))
+ return NULL;
+
+ if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
+ idx = id - KOMEDA_COMPONENT_LAYER0;
+ num = &pipe->n_layers;
+ if (idx != pipe->n_layers) {
+ DRM_ERROR("please add Layer by id sequence.\n");
+ return NULL;
+ }
+ } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) {
+ idx = id - KOMEDA_COMPONENT_SCALER0;
+ num = &pipe->n_scalers;
+ if (idx != pipe->n_scalers) {
+ DRM_ERROR("please add Scaler by id sequence.\n");
+ return NULL;
+ }
+ }
+
+ c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
+ if (!c)
+ return NULL;
+
+ c->id = id;
+ c->hw_id = hw_id;
+ c->reg = reg;
+ c->pipeline = pipe;
+ c->max_active_inputs = max_active_inputs;
+ c->max_active_outputs = max_active_outputs;
+ c->supported_inputs = supported_inputs;
+ c->funcs = funcs;
+
+ if (name_fmt) {
+ va_list args;
+
+ va_start(args, name_fmt);
+ vsnprintf(c->name, sizeof(c->name), name_fmt, args);
+ va_end(args);
+ }
+
+ if (num)
+ *num = *num + 1;
+
+ pipe->avail_comps |= BIT(c->id);
+ *pos = c;
+
+ return c;
+}
+
+void komeda_component_destroy(struct komeda_dev *mdev,
+ struct komeda_component *c)
+{
+ devm_kfree(mdev->dev, c);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
new file mode 100644
index 000000000000..2174796d47c5
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -0,0 +1,350 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#ifndef _KOMEDA_PIPELINE_H_
+#define _KOMEDA_PIPELINE_H_
+
+#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/bitops.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include "malidp_utils.h"
+
+#define KOMEDA_MAX_PIPELINES 2
+#define KOMEDA_PIPELINE_MAX_LAYERS 4
+#define KOMEDA_PIPELINE_MAX_SCALERS 2
+#define KOMEDA_COMPONENT_N_INPUTS 5
+
+/* pipeline component IDs */
+enum {
+ KOMEDA_COMPONENT_LAYER0 = 0,
+ KOMEDA_COMPONENT_LAYER1 = 1,
+ KOMEDA_COMPONENT_LAYER2 = 2,
+ KOMEDA_COMPONENT_LAYER3 = 3,
+ KOMEDA_COMPONENT_WB_LAYER = 7, /* write back layer */
+ KOMEDA_COMPONENT_SCALER0 = 8,
+ KOMEDA_COMPONENT_SCALER1 = 9,
+ KOMEDA_COMPONENT_SPLITTER = 12,
+ KOMEDA_COMPONENT_MERGER = 14,
+ KOMEDA_COMPONENT_COMPIZ0 = 16, /* compositor */
+ KOMEDA_COMPONENT_COMPIZ1 = 17,
+ KOMEDA_COMPONENT_IPS0 = 20, /* post image processor */
+ KOMEDA_COMPONENT_IPS1 = 21,
+ KOMEDA_COMPONENT_TIMING_CTRLR = 22, /* timing controller */
+};
+
+#define KOMEDA_PIPELINE_LAYERS (BIT(KOMEDA_COMPONENT_LAYER0) |\
+ BIT(KOMEDA_COMPONENT_LAYER1) |\
+ BIT(KOMEDA_COMPONENT_LAYER2) |\
+ BIT(KOMEDA_COMPONENT_LAYER3))
+
+#define KOMEDA_PIPELINE_SCALERS (BIT(KOMEDA_COMPONENT_SCALER0) |\
+ BIT(KOMEDA_COMPONENT_SCALER1))
+
+#define KOMEDA_PIPELINE_COMPIZS (BIT(KOMEDA_COMPONENT_COMPIZ0) |\
+ BIT(KOMEDA_COMPONENT_COMPIZ1))
+
+#define KOMEDA_PIPELINE_IMPROCS (BIT(KOMEDA_COMPONENT_IPS0) |\
+ BIT(KOMEDA_COMPONENT_IPS1))
+struct komeda_component;
+struct komeda_component_state;
+
+/** komeda_component_funcs - component control functions */
+struct komeda_component_funcs {
+ /** @validate: optional,
+ * component may has special requirements or limitations, this function
+ * supply HW the ability to do the further HW specific check.
+ */
+ int (*validate)(struct komeda_component *c,
+ struct komeda_component_state *state);
+ /** @update: update is a active update */
+ void (*update)(struct komeda_component *c,
+ struct komeda_component_state *state);
+ /** @disable: disable component */
+ void (*disable)(struct komeda_component *c);
+ /** @dump_register: Optional, dump registers to seq_file */
+ void (*dump_register)(struct komeda_component *c, struct seq_file *seq);
+};
+
+/**
+ * struct komeda_component
+ *
+ * struct komeda_component describe the data flow capabilities for how to link a
+ * component into the display pipeline.
+ * all specified components are subclass of this structure.
+ */
+struct komeda_component {
+ /** @obj: treat component as private obj */
+ struct drm_private_obj obj;
+ /** @pipeline: the komeda pipeline this component belongs to */
+ struct komeda_pipeline *pipeline;
+ /** @name: component name */
+ char name[32];
+ /**
+ * @reg:
+ * component register base,
+ * which is initialized by chip and used by chip only
+ */
+ u32 __iomem *reg;
+ /** @id: component id */
+ u32 id;
+ /** @hw_ic: component hw id,
+ * which is initialized by chip and used by chip only
+ */
+ u32 hw_id;
+
+ /**
+ * @max_active_inputs:
+ * @max_active_outpus:
+ *
+ * maximum number of inputs/outputs that can be active in the same time
+ * Note:
+ * the number isn't the bit number of @supported_inputs or
+ * @supported_outputs, but may be less than it, since component may not
+ * support enabling all @supported_inputs/outputs at the same time.
+ */
+ u8 max_active_inputs;
+ u8 max_active_outputs;
+ /**
+ * @supported_inputs:
+ * @supported_outputs:
+ *
+ * bitmask of BIT(component->id) for the supported inputs/outputs
+ * describes the possibilities of how a component is linked into a
+ * pipeline.
+ */
+ u32 supported_inputs;
+ u32 supported_outputs;
+
+ /**
+ * @funcs: chip functions to access HW
+ */
+ struct komeda_component_funcs *funcs;
+};
+
+/**
+ * struct komeda_component_output
+ *
+ * a component has multiple outputs, if want to know where the data
+ * comes from, only know the component is not enough, we still need to know
+ * its output port
+ */
+struct komeda_component_output {
+ /** @component: indicate which component the data comes from */
+ struct komeda_component *component;
+ /** @output_port:
+ * the output port of the &komeda_component_output.component
+ */
+ u8 output_port;
+};
+
+/**
+ * struct komeda_component_state
+ *
+ * component_state is the data flow configuration of the component, and it's
+ * the superclass of all specific component_state like @komeda_layer_state,
+ * @komeda_scaler_state
+ */
+struct komeda_component_state {
+ /** @obj: tracking component_state by drm_atomic_state */
+ struct drm_private_state obj;
+ struct komeda_component *component;
+ /**
+ * @binding_user:
+ * currently bound user, the user can be crtc/plane/wb_conn, which is
+ * valid decided by @component and @inputs
+ *
+ * - Layer: its user always is plane.
+ * - compiz/improc/timing_ctrlr: the user is crtc.
+ * - wb_layer: wb_conn;
+ * - scaler: plane when input is layer, wb_conn if input is compiz.
+ */
+ union {
+ struct drm_crtc *crtc;
+ struct drm_plane *plane;
+ struct drm_connector *wb_conn;
+ void *binding_user;
+ };
+ /**
+ * @active_inputs:
+ *
+ * active_inputs is bitmask of @inputs index
+ *
+ * - active_inputs = changed_active_inputs + unchanged_active_inputs
+ * - affected_inputs = old->active_inputs + new->active_inputs;
+ * - disabling_inputs = affected_inputs ^ active_inputs;
+ * - changed_inputs = disabling_inputs + changed_active_inputs;
+ *
+ * NOTE:
+ * changed_inputs doesn't include all active_input but only
+ * @changed_active_inputs, and this bitmask can be used in chip
+ * level for dirty update.
+ */
+ u16 active_inputs;
+ u16 changed_active_inputs;
+ u16 affected_inputs;
+ /**
+ * @inputs:
+ *
+ * the specific inputs[i] only valid on BIT(i) has been set in
+ * @active_inputs, if not the inputs[i] is undefined.
+ */
+ struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];
+};
+
+static inline u16 component_disabling_inputs(struct komeda_component_state *st)
+{
+ return st->affected_inputs ^ st->active_inputs;
+}
+
+static inline u16 component_changed_inputs(struct komeda_component_state *st)
+{
+ return component_disabling_inputs(st) | st->changed_active_inputs;
+}
+
+#define to_comp(__c) (((__c) == NULL) ? NULL : &((__c)->base))
+#define to_cpos(__c) ((struct komeda_component **)&(__c))
+
+/* these structures are going to be filled in in uture patches */
+struct komeda_layer {
+ struct komeda_component base;
+ /* layer specific features and caps */
+};
+
+struct komeda_layer_state {
+ struct komeda_component_state base;
+ /* layer specific configuration state */
+};
+
+struct komeda_compiz {
+ struct komeda_component base;
+ /* compiz specific features and caps */
+};
+
+struct komeda_compiz_state {
+ struct komeda_component_state base;
+ /* compiz specific configuration state */
+};
+
+struct komeda_scaler {
+ struct komeda_component base;
+ /* scaler features and caps */
+};
+
+struct komeda_scaler_state {
+ struct komeda_component_state base;
+};
+
+struct komeda_improc {
+ struct komeda_component base;
+};
+
+struct komeda_improc_state {
+ struct komeda_component_state base;
+};
+
+/* display timing controller */
+struct komeda_timing_ctrlr {
+ struct komeda_component base;
+};
+
+struct komeda_timing_ctrlr_state {
+ struct komeda_component_state base;
+};
+
+/** struct komeda_pipeline_funcs */
+struct komeda_pipeline_funcs {
+ /* dump_register: Optional, dump registers to seq_file */
+ void (*dump_register)(struct komeda_pipeline *pipe,
+ struct seq_file *sf);
+};
+
+/**
+ * struct komeda_pipeline
+ *
+ * Represent a complete display pipeline and hold all functional components.
+ */
+struct komeda_pipeline {
+ /** @obj: link pipeline as private obj of drm_atomic_state */
+ struct drm_private_obj obj;
+ /** @mdev: the parent komeda_dev */
+ struct komeda_dev *mdev;
+ /** @pxlclk: pixel clock */
+ struct clk *pxlclk;
+ /** @aclk: AXI clock */
+ struct clk *aclk;
+ /** @id: pipeline id */
+ int id;
+ /** @avail_comps: available components mask of pipeline */
+ u32 avail_comps;
+ int n_layers;
+ struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
+ int n_scalers;
+ struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
+ struct komeda_compiz *compiz;
+ struct komeda_layer *wb_layer;
+ struct komeda_improc *improc;
+ struct komeda_timing_ctrlr *ctrlr;
+ struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
+};
+
+/**
+ * struct komeda_pipeline_state
+ *
+ * NOTE:
+ * Unlike the pipeline, pipeline_state doesn’t gather any component_state
+ * into it. It because all component will be managed by drm_atomic_state.
+ */
+struct komeda_pipeline_state {
+ /** @obj: tracking pipeline_state by drm_atomic_state */
+ struct drm_private_state obj;
+ struct komeda_pipeline *pipe;
+ /** @crtc: currently bound crtc */
+ struct drm_crtc *crtc;
+ /**
+ * @active_comps:
+ *
+ * bitmask - BIT(component->id) of active components
+ */
+ u32 active_comps;
+};
+
+#define to_layer(c) container_of(c, struct komeda_layer, base)
+#define to_compiz(c) container_of(c, struct komeda_compiz, base)
+#define to_scaler(c) container_of(c, struct komeda_scaler, base)
+#define to_improc(c) container_of(c, struct komeda_improc, base)
+#define to_ctrlr(c) container_of(c, struct komeda_timing_ctrlr, base)
+
+#define to_layer_st(c) container_of(c, struct komeda_layer_state, base)
+#define to_compiz_st(c) container_of(c, struct komeda_compiz_state, base)
+#define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
+#define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
+#define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
+
+/* pipeline APIs */
+struct komeda_pipeline *
+komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
+ struct komeda_pipeline_funcs *funcs);
+void komeda_pipeline_destroy(struct komeda_dev *mdev,
+ struct komeda_pipeline *pipe);
+
+struct komeda_component *
+komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
+
+/* component APIs */
+struct komeda_component *
+komeda_component_add(struct komeda_pipeline *pipe,
+ size_t comp_sz, u32 id, u32 hw_id,
+ struct komeda_component_funcs *funcs,
+ u8 max_active_inputs, u32 supported_inputs,
+ u8 max_active_outputs, u32 __iomem *reg,
+ const char *name_fmt, ...);
+
+void komeda_component_destroy(struct komeda_dev *mdev,
+ struct komeda_component *c);
+
+#endif /* _KOMEDA_PIPELINE_H_*/
--
2.17.1

2018-12-21 16:07:04

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 6/9] drm/komeda: Add komeda_framebuffer

komeda_framebuffer is for extending drm_framebuffer to add komeda own
attributes and komeda specific fb handling.

Changes in v3:
- Fixed style problem found by checkpatch.pl --strict.

Signed-off-by: James (Qian) Wang <[email protected]>
---
drivers/gpu/drm/arm/display/komeda/Makefile | 3 +-
.../arm/display/komeda/komeda_framebuffer.c | 165 ++++++++++++++++++
.../arm/display/komeda/komeda_framebuffer.h | 31 ++++
3 files changed, 198 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h

diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
index 394fc2aa434a..25beae900ed2 100644
--- a/drivers/gpu/drm/arm/display/komeda/Makefile
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -8,7 +8,8 @@ komeda-y := \
komeda_drv.o \
komeda_dev.o \
komeda_format_caps.o \
- komeda_pipeline.o
+ komeda_pipeline.o \
+ komeda_framebuffer.o

komeda-y += \
d71/d71_dev.o
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
new file mode 100644
index 000000000000..4ddd5314ca23
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include <drm/drm_gem.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include "komeda_framebuffer.h"
+#include "komeda_dev.h"
+
+static void komeda_fb_destroy(struct drm_framebuffer *fb)
+{
+ struct komeda_fb *kfb = to_kfb(fb);
+ u32 i;
+
+ for (i = 0; i < fb->format->num_planes; i++)
+ drm_gem_object_put_unlocked(fb->obj[i]);
+
+ drm_framebuffer_cleanup(fb);
+ kfree(kfb);
+}
+
+static int komeda_fb_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file, u32 *handle)
+{
+ return drm_gem_handle_create(file, fb->obj[0], handle);
+}
+
+static const struct drm_framebuffer_funcs komeda_fb_funcs = {
+ .destroy = komeda_fb_destroy,
+ .create_handle = komeda_fb_create_handle,
+};
+
+static int
+komeda_fb_none_afbc_size_check(struct komeda_dev *mdev, struct komeda_fb *kfb,
+ struct drm_file *file,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_framebuffer *fb = &kfb->base;
+ struct drm_gem_object *obj;
+ u32 min_size = 0;
+ u32 i;
+
+ for (i = 0; i < fb->format->num_planes; i++) {
+ obj = drm_gem_object_lookup(file, mode_cmd->handles[i]);
+ if (!obj) {
+ DRM_DEBUG_KMS("Failed to lookup GEM object\n");
+ fb->obj[i] = NULL;
+
+ return -ENOENT;
+ }
+
+ kfb->aligned_w = fb->width / (i ? fb->format->hsub : 1);
+ kfb->aligned_h = fb->height / (i ? fb->format->vsub : 1);
+
+ if (fb->pitches[i] % mdev->chip.bus_width) {
+ DRM_DEBUG_KMS("Pitch[%d]: 0x%x doesn't align to 0x%x\n",
+ i, fb->pitches[i], mdev->chip.bus_width);
+ drm_gem_object_put_unlocked(obj);
+ fb->obj[i] = NULL;
+
+ return -EINVAL;
+ }
+
+ min_size = ((kfb->aligned_h / kfb->format_caps->tile_size - 1)
+ * fb->pitches[i])
+ + (kfb->aligned_w * fb->format->cpp[i]
+ * kfb->format_caps->tile_size)
+ + fb->offsets[i];
+
+ if (obj->size < min_size) {
+ DRM_DEBUG_KMS("Fail to check none afbc fb size.\n");
+ drm_gem_object_put_unlocked(obj);
+ fb->obj[i] = NULL;
+
+ return -EINVAL;
+ }
+
+ fb->obj[i] = obj;
+ }
+
+ if (fb->format->num_planes == 3) {
+ if (fb->pitches[1] != fb->pitches[2]) {
+ DRM_DEBUG_KMS("The pitch[1] and [2] are not same\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+struct drm_framebuffer *
+komeda_fb_create(struct drm_device *dev, struct drm_file *file,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct komeda_dev *mdev = dev->dev_private;
+ struct komeda_fb *kfb;
+ int ret = 0, i;
+
+ kfb = kzalloc(sizeof(*kfb), GFP_KERNEL);
+ if (!kfb)
+ return ERR_PTR(-ENOMEM);
+
+ kfb->format_caps = komeda_get_format_caps(&mdev->fmt_tbl,
+ mode_cmd->pixel_format,
+ mode_cmd->modifier[0]);
+ if (!kfb->format_caps) {
+ DRM_DEBUG_KMS("FMT %x is not supported.\n",
+ mode_cmd->pixel_format);
+ kfree(kfb);
+ return ERR_PTR(-EINVAL);
+ }
+
+ drm_helper_mode_fill_fb_struct(dev, &kfb->base, mode_cmd);
+
+ ret = komeda_fb_none_afbc_size_check(mdev, kfb, file, mode_cmd);
+ if (ret < 0)
+ goto err_cleanup;
+
+ ret = drm_framebuffer_init(dev, &kfb->base, &komeda_fb_funcs);
+ if (ret < 0) {
+ DRM_DEBUG_KMS("failed to initialize fb\n");
+
+ goto err_cleanup;
+ }
+
+ return &kfb->base;
+
+err_cleanup:
+ for (i = 0; i < kfb->base.format->num_planes; i++)
+ drm_gem_object_put_unlocked(kfb->base.obj[i]);
+
+ kfree(kfb);
+ return ERR_PTR(ret);
+}
+
+dma_addr_t
+komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane)
+{
+ struct drm_framebuffer *fb = &kfb->base;
+ const struct drm_gem_cma_object *obj;
+ u32 plane_x, plane_y, cpp, pitch, offset;
+
+ if (plane > fb->format->num_planes) {
+ DRM_DEBUG_KMS("Out of max plane num.\n");
+ return -EINVAL;
+ }
+
+ obj = drm_fb_cma_get_gem_obj(fb, plane);
+
+ offset = fb->offsets[plane];
+ if (!fb->modifier) {
+ plane_x = x / (plane ? fb->format->hsub : 1);
+ plane_y = y / (plane ? fb->format->vsub : 1);
+ cpp = fb->format->cpp[plane];
+ pitch = fb->pitches[plane];
+ offset += plane_x * cpp * kfb->format_caps->tile_size +
+ (plane_y * pitch) / kfb->format_caps->tile_size;
+ }
+
+ return obj->paddr + offset;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
new file mode 100644
index 000000000000..383780013bb9
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#ifndef _KOMEDA_FRAMEBUFFER_H_
+#define _KOMEDA_FRAMEBUFFER_H_
+
+/** struct komeda_fb - entend drm_framebuffer with komeda attribute */
+struct komeda_fb {
+ /** @base: &drm_framebuffer */
+ struct drm_framebuffer base;
+ /* @format_caps: &komeda_format_caps */
+ const struct komeda_format_caps *format_caps;
+ /** @aligned_w: aligned frame buffer width */
+ u32 aligned_w;
+ /** @aligned_h: aligned frame buffer height */
+ u32 aligned_h;
+};
+
+#define to_kfb(dfb) container_of(dfb, struct komeda_fb, base)
+
+struct drm_framebuffer *
+komeda_fb_create(struct drm_device *dev, struct drm_file *file,
+ const struct drm_mode_fb_cmd2 *mode_cmd);
+dma_addr_t
+komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane);
+bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type);
+
+#endif
--
2.17.1


2018-12-21 16:07:28

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 8/9] drm/doc: Add initial komeda driver documentation

v2: Some editing changes according to Randy Dunlap's comments

Signed-off-by: James (Qian) Wang <[email protected]>
---
Documentation/gpu/drivers.rst | 1 +
Documentation/gpu/komeda-kms.rst | 488 +++++++++++++++++++++++++++++++
2 files changed, 489 insertions(+)
create mode 100644 Documentation/gpu/komeda-kms.rst

diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
index 7c1672118a73..978e6da9bbff 100644
--- a/Documentation/gpu/drivers.rst
+++ b/Documentation/gpu/drivers.rst
@@ -17,6 +17,7 @@ GPU Driver Documentation
vkms
bridge/dw-hdmi
xen-front
+ komeda-kms

.. only:: subproject and html

diff --git a/Documentation/gpu/komeda-kms.rst b/Documentation/gpu/komeda-kms.rst
new file mode 100644
index 000000000000..b08da1cffecc
--- /dev/null
+++ b/Documentation/gpu/komeda-kms.rst
@@ -0,0 +1,488 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============================
+ drm/komeda Arm display driver
+==============================
+
+The drm/komeda driver supports the Arm display processor D71 and later products,
+this document gives a brief overview of driver design: how it works and why
+design it like that.
+
+Overview of D71 like display IPs
+================================
+
+From D71, Arm display IP begins to adopt a flexible and modularized
+architecture. A display pipeline is made up of multiple individual and
+functional pipeline stages called components, and every component has some
+specific capabilities that can give the flowed pipeline pixel data a
+particular processing.
+
+Typical D71 components:
+
+Layer
+-----
+Layer is the first pipeline stage, which prepares the pixel data for the next
+stage. It fetches the pixel from memory, decodes it if it's AFBC, rotates the
+source image, unpacks or converts YUV pixels to the device internal RGB pixels,
+then adjusts the color_space of pixels if needed.
+
+Scaler
+------
+As its name suggests, scaler takes responsibility for scaling, and D71 also
+supports image enhancements by scaler.
+The usage of scaler is very flexible and can be connected to layer output
+for layer scaling, or connected to compositor and scale the whole display
+frame and then feed the output data into wb_layer which will then write it
+into memory.
+
+Compositor (compiz)
+-------------------
+Compositor blends multiple layers or pixel data flows into one single display
+frame. its output frame can be fed into post image processor for showing it on
+the monitor or fed into wb_layer and written to memory at the same time.
+user can also insert a scaler between compositor and wb_layer to down scale
+the display frame first and and then write to memory.
+
+Writeback Layer (wb_layer)
+--------------------------
+Writeback layer does the opposite things of Layer, which connects to compiz
+and writes the composition result to memory.
+
+Post image processor (improc)
+-----------------------------
+Post image processor adjusts frame data like gamma and color space to fit the
+requirements of the monitor.
+
+Timing controller (timing_ctrlr)
+--------------------------------
+Final stage of display pipeline, Timing controller is not for the pixel
+handling, but only for controlling the display timing.
+
+Merger
+------
+D71 scaler mostly only has the half horizontal input/output capabilities
+compared with Layer, like if Layer supports 4K input size, the scaler only can
+support 2K input/output in the same time. To achieve the ful frame scaling, D71
+introduces Layer Split, which splits the whole image to two half parts and feeds
+them to two Layers A and B, and does the scaling independently. After scaling
+the result need to be fed to merger to merge two part images together, and then
+output merged result to compiz.
+
+Splitter
+--------
+Similar to Layer Split, but Splitter is used for writeback, which splits the
+compiz result to two parts and then feed them to two scalers.
+
+Possible D71 Pipeline usage
+===========================
+
+Benefitting from the modularized architecture, D71 pipelines can be easily
+adjusted to fit different usages. And D71 has two pipelines, which support two
+types of working mode:
+
+- Dual display mode
+ Two pipelines work independently and separately to drive two display outputs.
+
+- Single display mode
+ Two pipelines work together to drive only one display output.
+
+ On this mode, pipeline_B doesn't work indenpendently, but outputs its
+ composition result into pipeline_A, and its pixel timing also derived from
+ pipeline_A.timing_ctrlr. The pipeline_B works just like a "slave" of
+ pipeline_A(master)
+
+Single pipeline data flow
+-------------------------
+
+.. kernel-render:: DOT
+ :alt: Single pipeline digraph
+ :caption: Single pipeline data flow
+
+ digraph single_ppl {
+ rankdir=LR;
+
+ subgraph {
+ "Memory";
+ "Monitor";
+ }
+
+ subgraph cluster_pipeline {
+ style=dashed
+ node [shape=box]
+ {
+ node [bgcolor=grey style=dashed]
+ "Scaler-0";
+ "Scaler-1";
+ "Scaler-0/1"
+ }
+
+ node [bgcolor=grey style=filled]
+ "Layer-0" -> "Scaler-0"
+ "Layer-1" -> "Scaler-0"
+ "Layer-2" -> "Scaler-1"
+ "Layer-3" -> "Scaler-1"
+
+ "Layer-0" -> "Compiz"
+ "Layer-1" -> "Compiz"
+ "Layer-2" -> "Compiz"
+ "Layer-3" -> "Compiz"
+ "Scaler-0" -> "Compiz"
+ "Scaler-1" -> "Compiz"
+
+ "Compiz" -> "Scaler-0/1" -> "Wb_layer"
+ "Compiz" -> "Improc" -> "Timing Controller"
+ }
+
+ "Wb_layer" -> "Memory"
+ "Timing Controller" -> "Monitor"
+ }
+
+Dual pipeline with Slave enabled
+--------------------------------
+
+.. kernel-render:: DOT
+ :alt: Slave pipeline digraph
+ :caption: Slave pipeline enabled data flow
+
+ digraph slave_ppl {
+ rankdir=LR;
+
+ subgraph {
+ "Memory";
+ "Monitor";
+ }
+ node [shape=box]
+ subgraph cluster_pipeline_slave {
+ style=dashed
+ label="Slave Pipeline_B"
+ node [shape=box]
+ {
+ node [bgcolor=grey style=dashed]
+ "Slave.Scaler-0";
+ "Slave.Scaler-1";
+ }
+
+ node [bgcolor=grey style=filled]
+ "Slave.Layer-0" -> "Slave.Scaler-0"
+ "Slave.Layer-1" -> "Slave.Scaler-0"
+ "Slave.Layer-2" -> "Slave.Scaler-1"
+ "Slave.Layer-3" -> "Slave.Scaler-1"
+
+ "Slave.Layer-0" -> "Slave.Compiz"
+ "Slave.Layer-1" -> "Slave.Compiz"
+ "Slave.Layer-2" -> "Slave.Compiz"
+ "Slave.Layer-3" -> "Slave.Compiz"
+ "Slave.Scaler-0" -> "Slave.Compiz"
+ "Slave.Scaler-1" -> "Slave.Compiz"
+ }
+
+ subgraph cluster_pipeline_master {
+ style=dashed
+ label="Master Pipeline_A"
+ node [shape=box]
+ {
+ node [bgcolor=grey style=dashed]
+ "Scaler-0";
+ "Scaler-1";
+ "Scaler-0/1"
+ }
+
+ node [bgcolor=grey style=filled]
+ "Layer-0" -> "Scaler-0"
+ "Layer-1" -> "Scaler-0"
+ "Layer-2" -> "Scaler-1"
+ "Layer-3" -> "Scaler-1"
+
+ "Slave.Compiz" -> "Compiz"
+ "Layer-0" -> "Compiz"
+ "Layer-1" -> "Compiz"
+ "Layer-2" -> "Compiz"
+ "Layer-3" -> "Compiz"
+ "Scaler-0" -> "Compiz"
+ "Scaler-1" -> "Compiz"
+
+ "Compiz" -> "Scaler-0/1" -> "Wb_layer"
+ "Compiz" -> "Improc" -> "Timing Controller"
+ }
+
+ "Wb_layer" -> "Memory"
+ "Timing Controller" -> "Monitor"
+ }
+
+Sub-pipelines for input and output
+----------------------------------
+
+A complete display pipeline can be easily divided into three sub-pipelines
+according to the in/out usage.
+
+Layer(input) pipeline
+~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-render:: DOT
+ :alt: Layer data digraph
+ :caption: Layer (input) data flow
+
+ digraph layer_data_flow {
+ rankdir=LR;
+ node [shape=box]
+
+ {
+ node [bgcolor=grey style=dashed]
+ "Scaler-n";
+ }
+
+ "Layer-n" -> "Scaler-n" -> "Compiz"
+ }
+
+.. kernel-render:: DOT
+ :alt: Layer Split digraph
+ :caption: Layer Split pipeline
+
+ digraph layer_data_flow {
+ rankdir=LR;
+ node [shape=box]
+
+ "Layer-0/1" -> "Scaler-0" -> "Merger"
+ "Layer-2/3" -> "Scaler-1" -> "Merger"
+ "Merger" -> "Compiz"
+ }
+
+Writeback(output) pipeline
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. kernel-render:: DOT
+ :alt: writeback digraph
+ :caption: Writeback(output) data flow
+
+ digraph writeback_data_flow {
+ rankdir=LR;
+ node [shape=box]
+
+ {
+ node [bgcolor=grey style=dashed]
+ "Scaler-n";
+ }
+
+ "Compiz" -> "Scaler-n" -> "Wb_layer"
+ }
+
+.. kernel-render:: DOT
+ :alt: split writeback digraph
+ :caption: Writeback(output) Split data flow
+
+ digraph writeback_data_flow {
+ rankdir=LR;
+ node [shape=box]
+
+ "Compiz" -> "Splitter"
+ "Splitter" -> "Scaler-0" -> "Merger"
+ "Splitter" -> "Scaler-1" -> "Merger"
+ "Merger" -> "Wb_layer"
+ }
+
+Display output pipeline
+~~~~~~~~~~~~~~~~~~~~~~~
+.. kernel-render:: DOT
+ :alt: display digraph
+ :caption: display output data flow
+
+ digraph single_ppl {
+ rankdir=LR;
+ node [shape=box]
+
+ "Compiz" -> "Improc" -> "Timing Controller"
+ }
+
+In the following section we'll see these three sub-pipelines will be handled
+by KMS-plane/wb_conn/crtc respectively.
+
+Komeda Resource abstraction
+===========================
+
+struct komeda_pipeline/component
+--------------------------------
+
+To fully utilize and easily access/configure the HW, the driver side also uses
+a similar architecture: Pipeline/Component to describe the HW features and
+capabilities, and a specific component includes two parts:
+
+- Data flow controlling.
+- Specific component capabilities and features.
+
+So the driver defines a common header struct komeda_component to describe the
+data flow control and all specific components are a subclass of this base
+structure.
+
+.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+ :internal:
+
+Resource discovery and initialization
+=====================================
+
+Pipeline and component are used to describe how to handle the pixel data. We
+still need a @struct komeda_dev to describe the whole view of the device, and
+the control-abilites of device.
+
+We have &komeda_dev, &komeda_pipeline, &komeda_component. Now fill devices with
+pipelines. Since komeda is not for D71 only but also intended for later products,
+of course we’d better share as much as possible between different products. To
+achieve this, split the komeda device into two layers: CORE and CHIP.
+
+- CORE: for common features and capabilities handling.
+- CHIP: for register programing and HW specific feature (limitation) handling.
+
+CORE can access CHIP by three chip function structures:
+
+- struct komeda_dev_funcs
+- struct komeda_pipeline_funcs
+- struct komeda_component_funcs
+
+.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_dev.h
+ :internal:
+
+Format handling
+===============
+
+.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
+ :internal:
+.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
+ :internal:
+
+Attach komeda_dev to DRM-KMS
+============================
+
+Komeda abstracts resources by pipeline/component, but DRM-KMS uses
+crtc/plane/connector. One KMS-obj cannot represent only one single component,
+since the requirements of a single KMS object cannot simply be achieved by a
+single component, usually that needs multiple components to fit the requirement.
+Like set mode, gamma, ctm for KMS all target on CRTC-obj, but komeda needs
+compiz, improc and timing_ctrlr to work together to fit these requirements.
+And a KMS-Plane may require multiple komeda resources: layer/scaler/compiz.
+
+So, one KMS-Obj represents a sub-pipeline of komeda resources.
+
+- Plane: `Layer(input) pipeline`_
+- Wb_connector: `Writeback(output) pipeline`_
+- Crtc: `Display output pipeline`_
+
+So, for komeda, we treat KMS crtc/plane/connector as users of pipeline and
+component, and at any one time a pipeline/component only can be used by one
+user. And pipeline/component will be treated as private object of DRM-KMS; the
+state will be managed by drm_atomic_state as well.
+
+How to map plane to Layer(input) pipeline
+-----------------------------------------
+
+Komeda has multiple Layer input pipelines, see:
+- `Single pipeline data flow`_
+- `Dual pipeline with Slave enabled`_
+
+The easiest way is binding a plane to a fixed Layer pipeline, but consider the
+komeda capabilities:
+
+- Layer Split, See `Layer(input) pipeline`_
+
+ Layer_Split is quite complicated feature, which splits a big image into two
+ parts and handles it by two layers and two scalers individually. But it
+ imports an edge problem or effect in the middle of the image after the split.
+ To avoid such a problem, it needs a complicated Split calculation and some
+ special configurations to the layer and scaler. We'd better hide such HW
+ related complexity to user mode.
+
+- Slave pipeline, See `Dual pipeline with Slave enabled`_
+
+ Since the compiz component doesn't output alpha value, the slave pipeline
+ only can be used for bottom layers composition. The komeda driver wants to
+ hide this limitation to the user. The way to do this is to pick a suitable
+ Layer according to plane_state->zpos.
+
+So for komeda, the KMS-plane doesn't represent a fixed komeda layer pipeline,
+but multiple Layers with same capabilities. Komeda will select one or more
+Layers to fit the requirement of one KMS-plane.
+
+Make component/pipeline to be drm_private_obj
+---------------------------------------------
+
+Add :c:type:`drm_private_obj` to :c:type:`komeda_component`, :c:type:`komeda_pipeline`
+
+.. code-block:: c
+
+ struct komeda_component {
+ struct drm_private_obj obj;
+ ...
+ }
+
+ struct komeda_pipeline {
+ struct drm_private_obj obj;
+ ...
+ }
+
+Tracking component_state/pipeline_state by drm_atomic_state
+-----------------------------------------------------------
+
+Add :c:type:`drm_private_state` and user to :c:type:`komeda_component_state`,
+:c:type:`komeda_pipeline_state`
+
+.. code-block:: c
+
+ struct komeda_component_state {
+ struct drm_private_state obj;
+ void *binding_user;
+ ...
+ }
+
+ struct komeda_pipeline_state {
+ struct drm_private_state obj;
+ struct drm_crtc *crtc;
+ ...
+ }
+
+komeda component validation
+---------------------------
+
+Komeda has multiple types of components, but the process of validation are
+similar, usually including the following steps:
+
+.. code-block:: c
+
+ int komeda_xxxx_validate(struct komeda_component_xxx xxx_comp,
+ struct komeda_component_output *input_dflow,
+ struct drm_plane/crtc/connector *user,
+ struct drm_plane/crtc/connector_state, *user_state)
+ {
+ setup 1: check if component is needed, like the scaler is optional depending
+ on the user_state; if unneeded, just return, and the caller will
+ put the data flow into next stage.
+ Setup 2: check user_state with component features and capabilities to see
+ if requirements can be met; if not, return fail.
+ Setup 3: get component_state from drm_atomic_state, and try set to set
+ user to component; fail if component has been assigned to another
+ user already.
+ Setup 3: configure the component_state, like set its input component,
+ convert user_state to component specific state.
+ Setup 4: adjust the input_dflow and prepare it for the next stage.
+ }
+
+komeda_kms Abstraction
+----------------------
+
+.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_kms.h
+ :internal:
+
+komde_kms Functions
+-------------------
+.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
+ :internal:
+.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_plane.c
+ :internal:
+
+Build komeda to be a Linux module driver
+========================================
+
+Now we have two level devices:
+
+- komeda_dev: describes the real display hardware.
+- komeda_kms_dev: attachs or connects komeda_dev to DRM-KMS.
+
+All komeda operations are supplied or operated by komeda_dev or komeda_kms_dev,
+the module driver is only a simple wrapper to pass the Linux command
+(probe/remove/pm) into komeda_dev or komeda_kms_dev.
--
2.17.1

2018-12-21 16:08:03

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 7/9] drm/komeda: Attach komeda_dev to DRM-KMS

Add komeda_kms abstracton to attach komeda_dev to DRM-KMS
CRTC: according to the komeda_pipeline
PLANE: according to komeda_layer (layer input pipeline)
PRIVATE_OBJS: komeda_pipeline/component all will be treat as private_objs

komeda_kms is for connecting DRM-KMS and komeda_dev, like reporting the
kms object properties according to the komeda_dev, and pass/convert KMS's
requirement to komeda_dev.

Changes in v3:
- Fixed style problem found by checkpatch.pl --strict.

Changes in v2:
- Unified abbreviation of "pipeline" to "pipe".

Signed-off-by: James (Qian) Wang <[email protected]>
---
drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
.../gpu/drm/arm/display/komeda/komeda_crtc.c | 106 +++++++++++
.../gpu/drm/arm/display/komeda/komeda_drv.c | 19 +-
.../gpu/drm/arm/display/komeda/komeda_kms.c | 169 ++++++++++++++++++
.../gpu/drm/arm/display/komeda/komeda_kms.h | 113 ++++++++++++
.../drm/arm/display/komeda/komeda_pipeline.h | 3 +
.../gpu/drm/arm/display/komeda/komeda_plane.c | 109 +++++++++++
.../arm/display/komeda/komeda_private_obj.c | 88 +++++++++
8 files changed, 608 insertions(+), 5 deletions(-)
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.h
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_plane.c
create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c

diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
index 25beae900ed2..1b875e5dc0f6 100644
--- a/drivers/gpu/drm/arm/display/komeda/Makefile
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -9,7 +9,11 @@ komeda-y := \
komeda_dev.o \
komeda_format_caps.o \
komeda_pipeline.o \
- komeda_framebuffer.o
+ komeda_framebuffer.o \
+ komeda_kms.o \
+ komeda_crtc.o \
+ komeda_plane.o \
+ komeda_private_obj.o

komeda-y += \
d71/d71_dev.o
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
new file mode 100644
index 000000000000..5bb5a55f6b31
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/pm_runtime.h>
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+
+struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
+};
+
+static const struct drm_crtc_funcs komeda_crtc_funcs = {
+};
+
+int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev)
+{
+ struct komeda_crtc *crtc;
+ struct komeda_pipeline *master;
+ char str[16];
+ int i;
+
+ kms->n_crtcs = 0;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ crtc = &kms->crtcs[kms->n_crtcs];
+ master = mdev->pipelines[i];
+
+ crtc->master = master;
+ crtc->slave = NULL;
+
+ if (crtc->slave)
+ sprintf(str, "pipe-%d", crtc->slave->id);
+ else
+ sprintf(str, "None");
+
+ DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
+ kms->n_crtcs, master->id, str,
+ master->of_output_dev ?
+ master->of_output_dev->full_name : "None");
+
+ kms->n_crtcs++;
+ }
+
+ return 0;
+}
+
+static struct drm_plane *
+get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
+{
+ struct komeda_plane *kplane;
+ struct drm_plane *plane;
+
+ drm_for_each_plane(plane, &kms->base) {
+ if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+ continue;
+
+ kplane = to_kplane(plane);
+ /* only master can be primary */
+ if (kplane->layer->base.pipeline == crtc->master)
+ return plane;
+ }
+
+ return NULL;
+}
+
+static int komeda_crtc_add(struct komeda_kms_dev *kms,
+ struct komeda_crtc *kcrtc)
+{
+ struct drm_crtc *crtc = &kcrtc->base;
+ int err;
+
+ err = drm_crtc_init_with_planes(&kms->base, crtc,
+ get_crtc_primary(kms, kcrtc), NULL,
+ &komeda_crtc_funcs, NULL);
+ if (err)
+ return err;
+
+ drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
+ drm_crtc_vblank_reset(crtc);
+
+ crtc->port = kcrtc->master->of_output_port;
+
+ return 0;
+}
+
+int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
+{
+ int i, err;
+
+ for (i = 0; i < kms->n_crtcs; i++) {
+ err = komeda_crtc_add(kms, &kms->crtcs[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
index a2657b3d09d7..4b8ce717a71c 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -13,18 +13,21 @@

struct komeda_drv {
struct komeda_dev *mdev;
+ struct komeda_kms_dev *kms;
};

static void komeda_unbind(struct device *dev)
{
struct komeda_drv *mdrv = dev_get_drvdata(dev);

- dev_set_drvdata(dev, NULL);
-
if (!mdrv)
return;

+ komeda_kms_detach(mdrv->kms);
+
komeda_dev_destroy(mdrv->mdev);
+
+ dev_set_drvdata(dev, NULL);
kfree(mdrv);
}

@@ -33,7 +36,7 @@ static int komeda_bind(struct device *dev)
struct komeda_drv *mdrv;
int err;

- mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
+ mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
if (!mdrv)
return -ENOMEM;

@@ -45,10 +48,18 @@ static int komeda_bind(struct device *dev)

dev_set_drvdata(dev, mdrv);

+ mdrv->kms = komeda_kms_attach(mdrv->mdev);
+ if (IS_ERR(mdrv->kms)) {
+ err = PTR_ERR(mdrv->kms);
+ goto destroy_mdev;
+ }
+
return 0;

+destroy_mdev:
+ komeda_dev_destroy(mdrv->mdev);
free_mdrv:
- kfree(mdrv);
+ devm_kfree(dev, mdrv);
return err;
}

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
new file mode 100644
index 000000000000..fd48360ca524
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include <linux/component.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <linux/interrupt.h>
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+#include "komeda_framebuffer.h"
+
+DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
+
+static int komeda_gem_cma_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ u32 alignment = 16; /* TODO get alignment from dev */
+
+ args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
+ alignment);
+
+ return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static struct drm_driver komeda_kms_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
+ DRIVER_PRIME,
+ .lastclose = drm_fb_helper_lastclose,
+ .gem_free_object_unlocked = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = komeda_gem_cma_dumb_create,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .fops = &komeda_cma_fops,
+ .name = "komeda",
+ .desc = "ARM Mali Komeda Display Processor driver",
+ .date = "20181101",
+ .major = 0,
+ .minor = 1,
+};
+
+static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = old_state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, old_state);
+
+ drm_atomic_helper_commit_planes(dev, old_state, 0);
+
+ drm_atomic_helper_commit_modeset_enables(dev, old_state);
+
+ drm_atomic_helper_wait_for_flip_done(dev, old_state);
+
+ drm_atomic_helper_commit_hw_done(old_state);
+
+ drm_atomic_helper_cleanup_planes(dev, old_state);
+}
+
+static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
+ .atomic_commit_tail = komeda_kms_commit_tail,
+};
+
+static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
+ .fb_create = komeda_fb_create,
+ .atomic_check = NULL,/*komeda_kms_check*/
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev)
+{
+ struct drm_mode_config *config = &kms->base.mode_config;
+
+ drm_mode_config_init(&kms->base);
+
+ komeda_kms_setup_crtcs(kms, mdev);
+
+ /* Get value from dev */
+ config->min_width = 0;
+ config->min_height = 0;
+ config->max_width = 4096;
+ config->max_height = 4096;
+ config->allow_fb_modifiers = true;
+
+ config->funcs = &komeda_mode_config_funcs;
+ config->helper_private = &komeda_mode_config_helpers;
+}
+
+struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
+{
+ struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
+ struct drm_device *drm;
+ int err;
+
+ if (!kms)
+ return ERR_PTR(-ENOMEM);
+
+ drm = &kms->base;
+ err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
+ if (err)
+ goto free_kms;
+
+ drm->dev_private = mdev;
+
+ komeda_kms_mode_config_init(kms, mdev);
+
+ err = komeda_kms_add_private_objs(kms, mdev);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = komeda_kms_add_planes(kms, mdev);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = drm_vblank_init(drm, kms->n_crtcs);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = komeda_kms_add_crtcs(kms, mdev);
+ if (err)
+ goto cleanup_mode_config;
+
+ err = component_bind_all(mdev->dev, kms);
+ if (err)
+ goto cleanup_mode_config;
+
+ drm_mode_config_reset(drm);
+
+ err = drm_dev_register(drm, 0);
+ if (err)
+ goto uninstall_irq;
+
+ return kms;
+
+uninstall_irq:
+ drm_irq_uninstall(drm);
+cleanup_mode_config:
+ drm_mode_config_cleanup(drm);
+free_kms:
+ kfree(kms);
+ return ERR_PTR(err);
+}
+
+void komeda_kms_detach(struct komeda_kms_dev *kms)
+{
+ struct drm_device *drm = &kms->base;
+ struct komeda_dev *mdev = drm->dev_private;
+
+ drm_dev_unregister(drm);
+ component_unbind_all(mdev->dev, drm);
+ komeda_kms_cleanup_private_objs(mdev);
+ drm_mode_config_cleanup(drm);
+ drm->dev_private = NULL;
+ drm_dev_put(drm);
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
new file mode 100644
index 000000000000..f13666004a42
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#ifndef _KOMEDA_KMS_H_
+#define _KOMEDA_KMS_H_
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_writeback.h>
+
+/** struct komeda_plane - komeda instance of drm_plane */
+struct komeda_plane {
+ /** @base: &drm_plane */
+ struct drm_plane base;
+ /**
+ * @layer:
+ *
+ * represents available layer input pipelines for this plane.
+ *
+ * NOTE:
+ * the layer is not for a specific Layer, but indicate a group of
+ * Layers with same capabilities.
+ */
+ struct komeda_layer *layer;
+};
+
+/**
+ * struct komeda_plane_state
+ *
+ * The plane_state can be split into two data flow (left/right) and handled
+ * by two layers &komeda_plane.layer and &komeda_plane.layer.right
+ */
+struct komeda_plane_state {
+ /** @base: &drm_plane_state */
+ struct drm_plane_state base;
+
+ /* private properties */
+};
+
+/**
+ * struct komeda_wb_connector
+ */
+struct komeda_wb_connector {
+ /** @base: &drm_writeback_connector */
+ struct drm_writeback_connector base;
+
+ /** @wb_layer: represents associated writeback pipeline of komeda */
+ struct komeda_layer *wb_layer;
+};
+
+/**
+ * struct komeda_crtc
+ */
+struct komeda_crtc {
+ /** @base: &drm_crtc */
+ struct drm_crtc base;
+ /** @master: only master has display output */
+ struct komeda_pipeline *master;
+ /**
+ * @slave: optional
+ *
+ * Doesn't have its own display output, the handled data flow will
+ * merge into the master.
+ */
+ struct komeda_pipeline *slave;
+};
+
+/** struct komeda_crtc_state */
+struct komeda_crtc_state {
+ /** @base: &drm_crtc_state */
+ struct drm_crtc_state base;
+
+ /* private properties */
+
+ /* computed state which are used by validate/check */
+ u32 affected_pipes;
+ u32 active_pipes;
+};
+
+/** struct komeda_kms_dev - for gather KMS related things */
+struct komeda_kms_dev {
+ /** @base: &drm_device */
+ struct drm_device base;
+
+ /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
+ int n_crtcs;
+ /** @crtcs: crtcs list */
+ struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
+};
+
+#define to_kplane(p) container_of(p, struct komeda_plane, base)
+#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
+#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
+#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
+#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
+#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
+
+int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
+
+int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
+int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
+int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev);
+void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
+
+struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
+void komeda_kms_detach(struct komeda_kms_dev *kms);
+
+#endif /*_KOMEDA_KMS_H_*/
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
index 2d68ffeae25d..114129d96851 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -333,6 +333,9 @@ struct komeda_pipeline_state {
#define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
#define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)

+#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
+#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
+
/* pipeline APIs */
struct komeda_pipeline *
komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
new file mode 100644
index 000000000000..0a4953a9a909
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+
+static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
+};
+
+static void komeda_plane_destroy(struct drm_plane *plane)
+{
+ drm_plane_cleanup(plane);
+
+ kfree(to_kplane(plane));
+}
+
+static const struct drm_plane_funcs komeda_plane_funcs = {
+};
+
+/* for komeda, which is pipeline can be share between crtcs */
+static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
+ struct komeda_pipeline *pipe)
+{
+ struct komeda_crtc *crtc;
+ u32 possible_crtcs = 0;
+ int i;
+
+ for (i = 0; i < kms->n_crtcs; i++) {
+ crtc = &kms->crtcs[i];
+
+ if ((pipe == crtc->master) || (pipe == crtc->slave))
+ possible_crtcs |= BIT(i);
+ }
+
+ return possible_crtcs;
+}
+
+/* use Layer0 as primary */
+static u32 get_plane_type(struct komeda_kms_dev *kms,
+ struct komeda_component *c)
+{
+ bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
+
+ return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+}
+
+static int komeda_plane_add(struct komeda_kms_dev *kms,
+ struct komeda_layer *layer)
+{
+ struct komeda_dev *mdev = kms->base.dev_private;
+ struct komeda_component *c = &layer->base;
+ struct komeda_plane *kplane;
+ struct drm_plane *plane;
+ u32 *formats, n_formats = 0;
+ int err;
+
+ kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
+ if (!kplane)
+ return -ENOMEM;
+
+ plane = &kplane->base;
+ kplane->layer = layer;
+
+ formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
+ layer->layer_type, &n_formats);
+
+ err = drm_universal_plane_init(&kms->base, plane,
+ get_possible_crtcs(kms, c->pipeline),
+ &komeda_plane_funcs,
+ formats, n_formats, NULL,
+ get_plane_type(kms, c),
+ "%s", c->name);
+
+ komeda_put_fourcc_list(formats);
+
+ if (err)
+ goto cleanup;
+
+ drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
+
+ return 0;
+cleanup:
+ komeda_plane_destroy(plane);
+ return err;
+}
+
+int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
+{
+ struct komeda_pipeline *pipe;
+ int i, j, err;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ pipe = mdev->pipelines[i];
+
+ for (j = 0; j < pipe->n_layers; j++) {
+ err = komeda_plane_add(kms, pipe->layers[j]);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
new file mode 100644
index 000000000000..9edfd6ab0c12
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
+ * Author: James.Qian.Wang <[email protected]>
+ *
+ */
+#include "komeda_dev.h"
+#include "komeda_kms.h"
+
+static struct drm_private_state *
+komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
+{
+ struct komeda_pipeline_state *st;
+
+ st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return NULL;
+
+ st->active_comps = 0;
+
+ __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
+
+ return &st->obj;
+}
+
+static void
+komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ kfree(priv_to_pipe_st(state));
+}
+
+static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
+ .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
+ .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
+};
+
+static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
+ struct komeda_pipeline *pipe)
+{
+ struct komeda_pipeline_state *st;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->pipe = pipe;
+ drm_atomic_private_obj_init(&pipe->obj, &st->obj,
+ &komeda_pipeline_obj_funcs);
+
+ return 0;
+}
+
+int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
+ struct komeda_dev *mdev)
+{
+ struct komeda_pipeline *pipe;
+ int i, err;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ pipe = mdev->pipelines[i];
+
+ err = komeda_pipeline_obj_add(kms, pipe);
+ if (err)
+ return err;
+
+ /* Add component */
+ }
+
+ return 0;
+}
+
+void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
+{
+ struct komeda_pipeline *pipe;
+ struct komeda_component *c;
+ int i, id;
+
+ for (i = 0; i < mdev->n_pipelines; i++) {
+ pipe = mdev->pipelines[i];
+ dp_for_each_set_bit(id, pipe->avail_comps) {
+ c = komeda_pipeline_get_component(pipe, id);
+
+ drm_atomic_private_obj_fini(&c->obj);
+ }
+ drm_atomic_private_obj_fini(&pipe->obj);
+ }
+}
--
2.17.1


2018-12-21 16:09:02

by James Qian Wang

[permalink] [raw]
Subject: [PATCH v3 9/9] MAINTAINERS: Add maintainer for arm komeda driver

v2: Adjusted the position of KOMEDA by alphabetical order

Signed-off-by: James (Qian) Wang <[email protected]>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 254b7b267731..e48c2e5fd29f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1124,6 +1124,15 @@ S: Supported
F: drivers/gpu/drm/arm/hdlcd_*
F: Documentation/devicetree/bindings/display/arm,hdlcd.txt

+ARM KOMEDA DRM-KMS DRIVER
+M: James (Qian) Wang <[email protected]>
+M: Mali DP Maintainers <[email protected]>
+S: Supported
+F: drivers/gpu/drm/arm/display/include/
+F: drivers/gpu/drm/arm/display/komeda/
+F: Documentation/devicetree/bindings/display/arm/arm,komeda.txt
+F: Documentation/gpu/komeda-kms.rst
+
ARM MALI-DP DRM DRIVER
M: Liviu Dudau <[email protected]>
M: Brian Starkey <[email protected]>
--
2.17.1


2018-12-24 12:00:02

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 1/9] drm/komeda: komeda_dev/pipeline/component definition and initialzation

On Fri, Dec 21, 2018 at 09:58:55AM +0000, james qian wang (Arm Technology China) wrote:
> 1. Added a brief definition of komeda_dev/pipeline/component, this change
> didn't add the detailed component features and capabilities, which will
> be added in the following changes.
> 2. Corresponding resources discovery and initialzation functions.
>
> Signed-off-by: James (Qian) Wang <[email protected]>
>
> Changes in v3:
> - Fixed style problem found by checkpatch.pl --strict.
>
> Changes in v2:
> - Unified abbreviation of "pipeline" to "pipe".
> ---
> drivers/gpu/drm/arm/Kconfig | 2 +
> drivers/gpu/drm/arm/Makefile | 1 +
> drivers/gpu/drm/arm/display/Kbuild | 3 +
> drivers/gpu/drm/arm/display/Kconfig | 14 +
> .../drm/arm/display/include/malidp_product.h | 23 ++
> .../drm/arm/display/include/malidp_utils.h | 16 +
> drivers/gpu/drm/arm/display/komeda/Makefile | 11 +
> .../gpu/drm/arm/display/komeda/komeda_dev.c | 117 ++++++
> .../gpu/drm/arm/display/komeda/komeda_dev.h | 98 +++++
> .../drm/arm/display/komeda/komeda_pipeline.c | 198 ++++++++++
> .../drm/arm/display/komeda/komeda_pipeline.h | 350 ++++++++++++++++++
> 11 files changed, 833 insertions(+)
> create mode 100644 drivers/gpu/drm/arm/display/Kbuild
> create mode 100644 drivers/gpu/drm/arm/display/Kconfig
> create mode 100644 drivers/gpu/drm/arm/display/include/malidp_product.h
> create mode 100644 drivers/gpu/drm/arm/display/include/malidp_utils.h
> create mode 100644 drivers/gpu/drm/arm/display/komeda/Makefile
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
>
> diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> index f9f7761cb2f4..a204103b3efb 100644
> --- a/drivers/gpu/drm/arm/Kconfig
> +++ b/drivers/gpu/drm/arm/Kconfig
> @@ -37,4 +37,6 @@ config DRM_MALI_DISPLAY
>
> If compiled as a module it will be called mali-dp.
>
> +source "drivers/gpu/drm/arm/display/Kconfig"
> +
> endmenu
> diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
> index 3bf31d1a4722..120bef801fcf 100644
> --- a/drivers/gpu/drm/arm/Makefile
> +++ b/drivers/gpu/drm/arm/Makefile
> @@ -3,3 +3,4 @@ obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
> mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
> mali-dp-y += malidp_mw.o
> obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
> +obj-$(CONFIG_DRM_KOMEDA) += display/
> diff --git a/drivers/gpu/drm/arm/display/Kbuild b/drivers/gpu/drm/arm/display/Kbuild
> new file mode 100644
> index 000000000000..382f1ca831e4
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/Kbuild
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_DRM_KOMEDA) += komeda/
> diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig
> new file mode 100644
> index 000000000000..cec0639e3aa1
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/Kconfig
> @@ -0,0 +1,14 @@
> +# SPDX-License-Identifier: GPL-2.0
> +config DRM_KOMEDA
> + tristate "ARM Komeda display driver"
> + depends on DRM && OF
> + depends on COMMON_CLK
> + select DRM_KMS_HELPER
> + select DRM_KMS_CMA_HELPER
> + select DRM_GEM_CMA_HELPER
> + select VIDEOMODE_HELPERS
> + help
> + Choose this option if you want to compile the ARM Komeda display
> + Processor driver. It supports the D71 variants of the hardware.
> +
> + If compiled as a module it will be called komeda.
> diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h
> new file mode 100644
> index 000000000000..b35fc5db866b
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/include/malidp_product.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#ifndef _MALIDP_PRODUCT_H_
> +#define _MALIDP_PRODUCT_H_
> +
> +/* Product identification */
> +#define MALIDP_CORE_ID(__product, __major, __minor, __status) \
> + ((((__product) & 0xFFFF) << 16) | (((__major) & 0xF) << 12) | \
> + (((__minor) & 0xF) << 8) | ((__status) & 0xFF))
> +
> +#define MALIDP_CORE_ID_PRODUCT_ID(__core_id) ((__u32)(__core_id) >> 16)
> +#define MALIDP_CORE_ID_MAJOR(__core_id) (((__u32)(__core_id) >> 12) & 0xF)
> +#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 8) & 0xF)
> +#define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF)
> +
> +/* Mali-display product IDs */
> +#define MALIDP_D71_PRODUCT_ID 0x0071
> +
> +#endif /* _MALIDP_PRODUCT_H_ */
> diff --git a/drivers/gpu/drm/arm/display/include/malidp_utils.h b/drivers/gpu/drm/arm/display/include/malidp_utils.h
> new file mode 100644
> index 000000000000..63cc47cefcf8
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/include/malidp_utils.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#ifndef _MALIDP_UTILS_
> +#define _MALIDP_UTILS_
> +
> +#define has_bit(nr, mask) (BIT(nr) & (mask))
> +#define has_bits(bits, mask) (((bits) & (mask)) == (bits))
> +
> +#define dp_for_each_set_bit(bit, mask) \
> + for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8)

Given that most of our registers (and masks, by extension) are 32bit, I
think it might be better to use 32 instead of sizeof(mask) * 8 as we
don't want to introduce subtle bugs in the future. And I don't think you
need the (unsigned long *) cast either.

> +
> +#endif /* _MALIDP_UTILS_ */
> diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> new file mode 100644
> index 000000000000..5b44e36509b1
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> @@ -0,0 +1,11 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +ccflags-y := \
> + -I$(src)/../include \
> + -I$(src)
> +
> +komeda-y := \
> + komeda_dev.o \
> + komeda_pipeline.o \
> +
> +obj-$(CONFIG_DRM_KOMEDA) += komeda.o
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> new file mode 100644
> index 000000000000..887a17005367
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> @@ -0,0 +1,117 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/of_device.h>
> +#include <linux/of_graph.h>
> +#include <linux/version.h>
> +#include "komeda_dev.h"
> +
> +struct komeda_dev *komeda_dev_create(struct device *dev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + const struct komeda_product_data *product;
> + struct komeda_dev *mdev;
> + struct resource *io_res;
> + int err = 0;
> +
> + product = of_device_get_match_data(dev);
> + if (!product)
> + return ERR_PTR(-ENODEV);
> +
> + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!io_res) {
> + DRM_ERROR("No registers defined.\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);
> + if (!mdev)
> + return ERR_PTR(-ENOMEM);
> +
> + mdev->dev = dev;
> + mdev->reg_base = devm_ioremap_resource(dev, io_res);
> + if (IS_ERR(mdev->reg_base)) {
> + DRM_ERROR("Map register space failed.\n");
> + err = PTR_ERR(mdev->reg_base);
> + mdev->reg_base = NULL;
> + goto err_cleanup;
> + }
> +
> + mdev->pclk = devm_clk_get(dev, "pclk");
> + if (IS_ERR(mdev->pclk)) {
> + DRM_ERROR("Get APB clk failed.\n");
> + err = PTR_ERR(mdev->pclk);
> + mdev->pclk = NULL;
> + goto err_cleanup;
> + }
> +
> + /* Enable APB clock to access the registers */
> + clk_prepare_enable(mdev->pclk);
> +
> + mdev->funcs = product->identify(mdev->reg_base, &mdev->chip);
> + if (!komeda_product_match(mdev, product->product_id)) {
> + DRM_ERROR("DT configured %x mismatch with real HW %x.\n",
> + product->product_id,
> + MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
> + err = -ENODEV;
> + goto err_cleanup;
> + }
> +
> + DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
> + MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),
> + MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
> + MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
> +
> + err = mdev->funcs->enum_resources(mdev);
> + if (err) {
> + DRM_ERROR("enumerate display resource failed.\n");
> + goto err_cleanup;
> + }
> +
> + return mdev;
> +
> +err_cleanup:
> + komeda_dev_destroy(mdev);
> + return ERR_PTR(err);
> +}
> +
> +void komeda_dev_destroy(struct komeda_dev *mdev)
> +{
> + struct device *dev = mdev->dev;
> + struct komeda_dev_funcs *funcs = mdev->funcs;
> + int i;
> +
> + for (i = 0; i < mdev->n_pipelines; i++) {
> + komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
> + mdev->pipelines[i] = NULL;
> + }
> +
> + mdev->n_pipelines = 0;
> +
> + if (funcs && funcs->cleanup)
> + funcs->cleanup(mdev);
> +
> + if (mdev->reg_base) {
> + devm_iounmap(dev, mdev->reg_base);
> + mdev->reg_base = NULL;
> + }
> +
> + if (mdev->mclk) {
> + devm_clk_put(dev, mdev->mclk);
> + mdev->mclk = NULL;
> + }
> +
> + if (mdev->pclk) {
> + clk_disable_unprepare(mdev->pclk);
> + devm_clk_put(dev, mdev->pclk);
> + mdev->pclk = NULL;
> + }
> +
> + devm_kfree(dev, mdev);
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> new file mode 100644
> index 000000000000..ad8fa160eff9
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> @@ -0,0 +1,98 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#ifndef _KOMEDA_DEV_H_
> +#define _KOMEDA_DEV_H_
> +
> +#include <linux/device.h>
> +#include <linux/interrupt.h>

You don't need this header to be included here.

> +#include "komeda_pipeline.h"
> +#include "malidp_product.h"
> +
> +/* malidp device id */
> +enum {
> + MALI_D71 = 0,
> +};
> +
> +/* pipeline DT ports */
> +enum {
> + KOMEDA_OF_PORT_OUTPUT = 0,
> + KOMEDA_OF_PORT_COPROC = 1,
> +};
> +
> +struct komeda_chip_info {
> + u32 arch_id;
> + u32 core_id;
> + u32 core_info;
> + u32 bus_width;
> +};
> +
> +struct komeda_product_data {
> + u32 product_id;
> + struct komeda_dev_funcs *(*identify)(u32 __iomem *reg,
> + struct komeda_chip_info *info);
> +};
> +
> +struct komeda_dev;
> +
> +/**
> + * struct komeda_dev_funcs
> + *
> + * Supplied by chip level and returned by the chip entry function xxx_identify,
> + */
> +struct komeda_dev_funcs {
> + /**
> + * @enum_resources:
> + *
> + * for CHIP to report or add pipeline and component resources to CORE
> + */
> + int (*enum_resources)(struct komeda_dev *mdev);
> + /** @cleanup: call to chip to cleanup komeda_dev->chip data */
> + void (*cleanup)(struct komeda_dev *mdev);
> +};
> +
> +/**
> + * struct komeda_dev
> + *
> + * Pipeline and component are used to describe how to handle the pixel data.
> + * komeda_device is for describing the whole view of the device, and the
> + * control-abilites of device.
> + */
> +struct komeda_dev {
> + struct device *dev;
> + u32 __iomem *reg_base;
> +
> + struct komeda_chip_info chip;
> +
> + /** @pclk: APB clock for register access */
> + struct clk *pclk;
> + /** @mck: HW main engine clk */
> + struct clk *mclk;
> +
> + int n_pipelines;
> + struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
> +
> + /** @funcs: chip funcs to access to HW */
> + struct komeda_dev_funcs *funcs;
> + /**
> + * @chip_data:
> + *
> + * chip data will be added by &komeda_dev_funcs.enum_resources() and
> + * destroyed by &komeda_dev_funcs.cleanup()
> + */
> + void *chip_data;
> +};
> +
> +static inline bool
> +komeda_product_match(struct komeda_dev *mdev, u32 target)
> +{
> + return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
> +}
> +
> +struct komeda_dev *komeda_dev_create(struct device *dev);
> +void komeda_dev_destroy(struct komeda_dev *mdev);
> +
> +#endif /*_KOMEDA_DEV_H_*/
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> new file mode 100644
> index 000000000000..9293598b0533
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> @@ -0,0 +1,198 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include <linux/clk.h>
> +#include "komeda_dev.h"
> +#include "komeda_pipeline.h"
> +
> +/** komeda_pipeline_add - Add a pipeline to &komeda_dev */
> +struct komeda_pipeline *
> +komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> + struct komeda_pipeline_funcs *funcs)
> +{
> + struct komeda_pipeline *pipe;
> +
> + if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
> + DRM_ERROR("Exceed max support %d pipelines.\n",
> + KOMEDA_MAX_PIPELINES);
> + return NULL;
> + }
> +
> + if (size < sizeof(*pipe)) {
> + DRM_ERROR("Request pipeline size too small.\n");
> + return NULL;
> + }
> +
> + pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
> + if (!pipe)
> + return NULL;
> +
> + pipe->mdev = mdev;
> + pipe->id = mdev->n_pipelines;
> + pipe->funcs = funcs;
> +
> + mdev->pipelines[mdev->n_pipelines] = pipe;
> + mdev->n_pipelines++;
> +
> + return pipe;
> +}
> +
> +void komeda_pipeline_destroy(struct komeda_dev *mdev,
> + struct komeda_pipeline *pipe)
> +{
> + struct komeda_component *c;
> + int i;
> +
> + dp_for_each_set_bit(i, pipe->avail_comps) {
> + c = komeda_pipeline_get_component(pipe, i);
> +

Unnecessary empty line.

> + komeda_component_destroy(mdev, c);
> + }
> +
> + clk_put(pipe->pxlclk);
> + clk_put(pipe->aclk);
> +
> + devm_kfree(mdev->dev, pipe);
> +}
> +
> +struct komeda_component **
> +komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
> +{
> + struct komeda_dev *mdev = pipe->mdev;
> + struct komeda_pipeline *temp = NULL;
> + struct komeda_component **pos = NULL;
> +
> + switch (id) {
> + case KOMEDA_COMPONENT_LAYER0:
> + case KOMEDA_COMPONENT_LAYER1:
> + case KOMEDA_COMPONENT_LAYER2:
> + case KOMEDA_COMPONENT_LAYER3:
> + pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
> + break;
> + case KOMEDA_COMPONENT_WB_LAYER:
> + pos = to_cpos(pipe->wb_layer);
> + break;
> + case KOMEDA_COMPONENT_COMPIZ0:
> + case KOMEDA_COMPONENT_COMPIZ1:
> + temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
> + if (!temp) {
> + DRM_ERROR("compiz-%d doesn't exist.\n", id);
> + return NULL;
> + }
> + pos = to_cpos(temp->compiz);
> + break;
> + case KOMEDA_COMPONENT_SCALER0:
> + case KOMEDA_COMPONENT_SCALER1:
> + pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
> + break;
> + case KOMEDA_COMPONENT_IPS0:
> + case KOMEDA_COMPONENT_IPS1:
> + temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
> + if (!temp) {
> + DRM_ERROR("ips-%d doesn't exist.\n", id);
> + return NULL;
> + }
> + pos = to_cpos(temp->improc);
> + break;
> + case KOMEDA_COMPONENT_TIMING_CTRLR:
> + pos = to_cpos(pipe->ctrlr);
> + break;
> + default:
> + pos = NULL;
> + DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
> + break;
> + }
> +
> + return pos;
> +}
> +
> +struct komeda_component *
> +komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
> +{
> + struct komeda_component **pos = NULL;
> + struct komeda_component *c = NULL;
> +
> + pos = komeda_pipeline_get_component_pos(pipe, id);
> + if (pos)
> + c = *pos;
> +
> + return c;
> +}
> +
> +/** komeda_component_add - Add a component to &komeda_pipeline */
> +struct komeda_component *
> +komeda_component_add(struct komeda_pipeline *pipe,
> + size_t comp_sz, u32 id, u32 hw_id,
> + struct komeda_component_funcs *funcs,
> + u8 max_active_inputs, u32 supported_inputs,
> + u8 max_active_outputs, u32 __iomem *reg,
> + const char *name_fmt, ...)
> +{
> + struct komeda_component **pos;
> + struct komeda_component *c;
> + int idx, *num = NULL;
> +
> + if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
> + WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
> + max_active_inputs);
> + return NULL;
> + }
> +
> + pos = komeda_pipeline_get_component_pos(pipe, id);
> + if (!pos || !(*pos))
> + return NULL;
> +
> + if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
> + idx = id - KOMEDA_COMPONENT_LAYER0;
> + num = &pipe->n_layers;
> + if (idx != pipe->n_layers) {
> + DRM_ERROR("please add Layer by id sequence.\n");
> + return NULL;
> + }
> + } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) {
> + idx = id - KOMEDA_COMPONENT_SCALER0;
> + num = &pipe->n_scalers;
> + if (idx != pipe->n_scalers) {
> + DRM_ERROR("please add Scaler by id sequence.\n");
> + return NULL;
> + }
> + }
> +
> + c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
> + if (!c)
> + return NULL;
> +
> + c->id = id;
> + c->hw_id = hw_id;
> + c->reg = reg;
> + c->pipeline = pipe;
> + c->max_active_inputs = max_active_inputs;
> + c->max_active_outputs = max_active_outputs;
> + c->supported_inputs = supported_inputs;
> + c->funcs = funcs;
> +
> + if (name_fmt) {
> + va_list args;
> +
> + va_start(args, name_fmt);
> + vsnprintf(c->name, sizeof(c->name), name_fmt, args);
> + va_end(args);
> + }
> +
> + if (num)
> + *num = *num + 1;
> +
> + pipe->avail_comps |= BIT(c->id);
> + *pos = c;
> +
> + return c;
> +}
> +
> +void komeda_component_destroy(struct komeda_dev *mdev,
> + struct komeda_component *c)
> +{
> + devm_kfree(mdev->dev, c);
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> new file mode 100644
> index 000000000000..2174796d47c5
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> @@ -0,0 +1,350 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#ifndef _KOMEDA_PIPELINE_H_
> +#define _KOMEDA_PIPELINE_H_
> +
> +#include <linux/types.h>
> +#include <linux/of.h>
> +#include <linux/bitops.h>

of.h and bitops.h are unnecessary in this header file.

> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include "malidp_utils.h"
> +
> +#define KOMEDA_MAX_PIPELINES 2
> +#define KOMEDA_PIPELINE_MAX_LAYERS 4
> +#define KOMEDA_PIPELINE_MAX_SCALERS 2
> +#define KOMEDA_COMPONENT_N_INPUTS 5
> +
> +/* pipeline component IDs */
> +enum {
> + KOMEDA_COMPONENT_LAYER0 = 0,
> + KOMEDA_COMPONENT_LAYER1 = 1,
> + KOMEDA_COMPONENT_LAYER2 = 2,
> + KOMEDA_COMPONENT_LAYER3 = 3,
> + KOMEDA_COMPONENT_WB_LAYER = 7, /* write back layer */
> + KOMEDA_COMPONENT_SCALER0 = 8,
> + KOMEDA_COMPONENT_SCALER1 = 9,
> + KOMEDA_COMPONENT_SPLITTER = 12,
> + KOMEDA_COMPONENT_MERGER = 14,
> + KOMEDA_COMPONENT_COMPIZ0 = 16, /* compositor */
> + KOMEDA_COMPONENT_COMPIZ1 = 17,
> + KOMEDA_COMPONENT_IPS0 = 20, /* post image processor */
> + KOMEDA_COMPONENT_IPS1 = 21,
> + KOMEDA_COMPONENT_TIMING_CTRLR = 22, /* timing controller */
> +};
> +
> +#define KOMEDA_PIPELINE_LAYERS (BIT(KOMEDA_COMPONENT_LAYER0) |\
> + BIT(KOMEDA_COMPONENT_LAYER1) |\
> + BIT(KOMEDA_COMPONENT_LAYER2) |\
> + BIT(KOMEDA_COMPONENT_LAYER3))
> +
> +#define KOMEDA_PIPELINE_SCALERS (BIT(KOMEDA_COMPONENT_SCALER0) |\
> + BIT(KOMEDA_COMPONENT_SCALER1))
> +
> +#define KOMEDA_PIPELINE_COMPIZS (BIT(KOMEDA_COMPONENT_COMPIZ0) |\
> + BIT(KOMEDA_COMPONENT_COMPIZ1))
> +
> +#define KOMEDA_PIPELINE_IMPROCS (BIT(KOMEDA_COMPONENT_IPS0) |\
> + BIT(KOMEDA_COMPONENT_IPS1))
> +struct komeda_component;
> +struct komeda_component_state;
> +
> +/** komeda_component_funcs - component control functions */
> +struct komeda_component_funcs {
> + /** @validate: optional,
> + * component may has special requirements or limitations, this function
> + * supply HW the ability to do the further HW specific check.
> + */
> + int (*validate)(struct komeda_component *c,
> + struct komeda_component_state *state);
> + /** @update: update is a active update */
> + void (*update)(struct komeda_component *c,
> + struct komeda_component_state *state);
> + /** @disable: disable component */
> + void (*disable)(struct komeda_component *c);
> + /** @dump_register: Optional, dump registers to seq_file */
> + void (*dump_register)(struct komeda_component *c, struct seq_file *seq);
> +};
> +
> +/**
> + * struct komeda_component
> + *
> + * struct komeda_component describe the data flow capabilities for how to link a
> + * component into the display pipeline.
> + * all specified components are subclass of this structure.
> + */
> +struct komeda_component {
> + /** @obj: treat component as private obj */
> + struct drm_private_obj obj;
> + /** @pipeline: the komeda pipeline this component belongs to */
> + struct komeda_pipeline *pipeline;
> + /** @name: component name */
> + char name[32];
> + /**
> + * @reg:
> + * component register base,
> + * which is initialized by chip and used by chip only
> + */
> + u32 __iomem *reg;
> + /** @id: component id */
> + u32 id;
> + /** @hw_ic: component hw id,
> + * which is initialized by chip and used by chip only
> + */
> + u32 hw_id;
> +
> + /**
> + * @max_active_inputs:
> + * @max_active_outpus:
> + *
> + * maximum number of inputs/outputs that can be active in the same time
> + * Note:
> + * the number isn't the bit number of @supported_inputs or
> + * @supported_outputs, but may be less than it, since component may not
> + * support enabling all @supported_inputs/outputs at the same time.
> + */
> + u8 max_active_inputs;
> + u8 max_active_outputs;
> + /**
> + * @supported_inputs:
> + * @supported_outputs:
> + *
> + * bitmask of BIT(component->id) for the supported inputs/outputs
> + * describes the possibilities of how a component is linked into a
> + * pipeline.
> + */
> + u32 supported_inputs;
> + u32 supported_outputs;
> +
> + /**
> + * @funcs: chip functions to access HW
> + */
> + struct komeda_component_funcs *funcs;
> +};
> +
> +/**
> + * struct komeda_component_output
> + *
> + * a component has multiple outputs, if want to know where the data
> + * comes from, only know the component is not enough, we still need to know
> + * its output port
> + */
> +struct komeda_component_output {
> + /** @component: indicate which component the data comes from */
> + struct komeda_component *component;
> + /** @output_port:
> + * the output port of the &komeda_component_output.component
> + */
> + u8 output_port;
> +};
> +
> +/**
> + * struct komeda_component_state
> + *
> + * component_state is the data flow configuration of the component, and it's
> + * the superclass of all specific component_state like @komeda_layer_state,
> + * @komeda_scaler_state
> + */
> +struct komeda_component_state {
> + /** @obj: tracking component_state by drm_atomic_state */
> + struct drm_private_state obj;
> + struct komeda_component *component;
> + /**
> + * @binding_user:
> + * currently bound user, the user can be crtc/plane/wb_conn, which is
> + * valid decided by @component and @inputs
> + *
> + * - Layer: its user always is plane.
> + * - compiz/improc/timing_ctrlr: the user is crtc.
> + * - wb_layer: wb_conn;
> + * - scaler: plane when input is layer, wb_conn if input is compiz.
> + */
> + union {
> + struct drm_crtc *crtc;
> + struct drm_plane *plane;
> + struct drm_connector *wb_conn;
> + void *binding_user;
> + };
> + /**
> + * @active_inputs:
> + *
> + * active_inputs is bitmask of @inputs index
> + *
> + * - active_inputs = changed_active_inputs + unchanged_active_inputs
> + * - affected_inputs = old->active_inputs + new->active_inputs;
> + * - disabling_inputs = affected_inputs ^ active_inputs;
> + * - changed_inputs = disabling_inputs + changed_active_inputs;
> + *
> + * NOTE:
> + * changed_inputs doesn't include all active_input but only
> + * @changed_active_inputs, and this bitmask can be used in chip
> + * level for dirty update.
> + */
> + u16 active_inputs;
> + u16 changed_active_inputs;
> + u16 affected_inputs;
> + /**
> + * @inputs:
> + *
> + * the specific inputs[i] only valid on BIT(i) has been set in
> + * @active_inputs, if not the inputs[i] is undefined.
> + */
> + struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];
> +};
> +
> +static inline u16 component_disabling_inputs(struct komeda_component_state *st)
> +{
> + return st->affected_inputs ^ st->active_inputs;
> +}
> +
> +static inline u16 component_changed_inputs(struct komeda_component_state *st)
> +{
> + return component_disabling_inputs(st) | st->changed_active_inputs;
> +}
> +
> +#define to_comp(__c) (((__c) == NULL) ? NULL : &((__c)->base))
> +#define to_cpos(__c) ((struct komeda_component **)&(__c))
> +
> +/* these structures are going to be filled in in uture patches */
> +struct komeda_layer {
> + struct komeda_component base;
> + /* layer specific features and caps */
> +};
> +
> +struct komeda_layer_state {
> + struct komeda_component_state base;
> + /* layer specific configuration state */
> +};
> +
> +struct komeda_compiz {
> + struct komeda_component base;
> + /* compiz specific features and caps */
> +};
> +
> +struct komeda_compiz_state {
> + struct komeda_component_state base;
> + /* compiz specific configuration state */
> +};
> +
> +struct komeda_scaler {
> + struct komeda_component base;
> + /* scaler features and caps */
> +};
> +
> +struct komeda_scaler_state {
> + struct komeda_component_state base;
> +};
> +
> +struct komeda_improc {
> + struct komeda_component base;
> +};
> +
> +struct komeda_improc_state {
> + struct komeda_component_state base;
> +};
> +
> +/* display timing controller */
> +struct komeda_timing_ctrlr {
> + struct komeda_component base;
> +};
> +
> +struct komeda_timing_ctrlr_state {
> + struct komeda_component_state base;
> +};
> +
> +/** struct komeda_pipeline_funcs */
> +struct komeda_pipeline_funcs {
> + /* dump_register: Optional, dump registers to seq_file */
> + void (*dump_register)(struct komeda_pipeline *pipe,
> + struct seq_file *sf);
> +};
> +
> +/**
> + * struct komeda_pipeline
> + *
> + * Represent a complete display pipeline and hold all functional components.
> + */
> +struct komeda_pipeline {
> + /** @obj: link pipeline as private obj of drm_atomic_state */
> + struct drm_private_obj obj;
> + /** @mdev: the parent komeda_dev */
> + struct komeda_dev *mdev;
> + /** @pxlclk: pixel clock */
> + struct clk *pxlclk;
> + /** @aclk: AXI clock */
> + struct clk *aclk;
> + /** @id: pipeline id */
> + int id;
> + /** @avail_comps: available components mask of pipeline */
> + u32 avail_comps;
> + int n_layers;
> + struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
> + int n_scalers;
> + struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
> + struct komeda_compiz *compiz;
> + struct komeda_layer *wb_layer;
> + struct komeda_improc *improc;
> + struct komeda_timing_ctrlr *ctrlr;
> + struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
> +};
> +
> +/**
> + * struct komeda_pipeline_state
> + *
> + * NOTE:
> + * Unlike the pipeline, pipeline_state doesn’t gather any component_state
> + * into it. It because all component will be managed by drm_atomic_state.
> + */
> +struct komeda_pipeline_state {
> + /** @obj: tracking pipeline_state by drm_atomic_state */
> + struct drm_private_state obj;
> + struct komeda_pipeline *pipe;
> + /** @crtc: currently bound crtc */
> + struct drm_crtc *crtc;
> + /**
> + * @active_comps:
> + *
> + * bitmask - BIT(component->id) of active components
> + */
> + u32 active_comps;
> +};
> +
> +#define to_layer(c) container_of(c, struct komeda_layer, base)
> +#define to_compiz(c) container_of(c, struct komeda_compiz, base)
> +#define to_scaler(c) container_of(c, struct komeda_scaler, base)
> +#define to_improc(c) container_of(c, struct komeda_improc, base)
> +#define to_ctrlr(c) container_of(c, struct komeda_timing_ctrlr, base)
> +
> +#define to_layer_st(c) container_of(c, struct komeda_layer_state, base)
> +#define to_compiz_st(c) container_of(c, struct komeda_compiz_state, base)
> +#define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
> +#define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
> +#define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
> +
> +/* pipeline APIs */
> +struct komeda_pipeline *
> +komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> + struct komeda_pipeline_funcs *funcs);
> +void komeda_pipeline_destroy(struct komeda_dev *mdev,
> + struct komeda_pipeline *pipe);
> +
> +struct komeda_component *
> +komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
> +
> +/* component APIs */
> +struct komeda_component *
> +komeda_component_add(struct komeda_pipeline *pipe,
> + size_t comp_sz, u32 id, u32 hw_id,
> + struct komeda_component_funcs *funcs,
> + u8 max_active_inputs, u32 supported_inputs,
> + u8 max_active_outputs, u32 __iomem *reg,
> + const char *name_fmt, ...);
> +
> +void komeda_component_destroy(struct komeda_dev *mdev,
> + struct komeda_component *c);
> +
> +#endif /* _KOMEDA_PIPELINE_H_*/
> --
> 2.17.1
>

With these small changes:

Reviewed-by: Liviu Dudau <[email protected]>

Best regards,
Liviu


--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:01:58

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 2/9] dt/bindings: drm/komeda: Add DT bindings for ARM display processor D71

On Fri, Dec 21, 2018 at 09:59:12AM +0000, james qian wang (Arm Technology China) wrote:
> Add DT bindings documentation for the ARM display processor D71 and later
> IPs.
>
> Signed-off-by: James (Qian) Wang <[email protected]>
>
> Changes in v3:
> - Deleted unnecessary property: interrupt-names.
> - Dropped 'ports' and moving 'port' up a level.
> ---
> .../bindings/display/arm/arm,komeda.txt | 79 +++++++++++++++++++
> 1 file changed, 79 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/arm/arm,komeda.txt
>
> diff --git a/Documentation/devicetree/bindings/display/arm/arm,komeda.txt b/Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> new file mode 100644
> index 000000000000..b4e450243c7d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> @@ -0,0 +1,79 @@
> +Device Tree bindings for ARM Komeda display driver
> +
> +Required properties:
> +- compatible: Should be "arm,mali-d71"
> +- reg: Physical base address and length of the registers in the system
> +- interrupts: the interrupt line number of the device in the system
> +- clocks: A list of phandle + clock-specifier pairs, one for each entry
> + in 'clock-names'
> +- clock-names: A list of clock names. It should contain:
> + - "mclk": for the main processor clock
> + - "pclk": for the APB interface clock
> +- #address-cells: Must be 1
> +- #size-cells: Must be 0
> +
> +Required properties for sub-node: pipeline@nq
> +Each device contains one or two pipeline sub-nodes (at least one), each
> +pipeline node should provide properties:
> +- reg: Zero-indexed identifier for the pipeline
> +- clocks: A list of phandle + clock-specifier pairs, one for each entry
> + in 'clock-names'
> +- clock-names: should contain:
> + - "pxclk": pixel clock
> + - "aclk": AXI interface clock
> +
> +- port: each pipeline connect to an encoder input port. The connection is
> + modeled using the OF graph bindings specified in
> + Documentation/devicetree/bindings/graph.txt
> +
> +Optional properties:
> + - memory-region: phandle to a node describing memory (see
> + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt)
> + to be used for the framebuffer; if not present, the framebuffer may
> + be located anywhere in memory.
> +
> +Example:
> +/ {
> + ...
> +
> + dp0: display@c00000 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + compatible = "arm,mali-d71";
> + reg = <0xc00000 0x20000>;
> + interrupts = <0 168 4>;
> + clocks = <&dpu_mclk>, <&dpu_aclk>;
> + clock-names = "mclk", "pclk";
> +
> + dp0_pipe0: pipeline@0 {
> + clocks = <&fpgaosc2>, <&dpu_aclk>;
> + clock-names = "pxclk", "aclk";
> + reg = <0>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;

These are undocumented and not necessary anyway, as the pipelines will
inherit display's attributes.

> +
> + port@0 {
> + dp0_pipe0_out: endpoint {
> + remote-endpoint = <&db_dvi0_in>;
> + };
> + };
> + };
> +
> + dp0_pipe1: pipeline@1 {
> + clocks = <&fpgaosc2>, <&dpu_aclk>;
> + clock-names = "pxclk", "aclk";
> + reg = <1>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;

same here.

> +
> + port@0 {
> + dp0_pipe1_out: endpoint {
> + remote-endpoint = <&db_dvi1_in>;
> + };
> + };
> + };
> + };
> + ...
> +};
> --
> 2.17.1
>

With these changes:

Reviewed-by: Liviu Dudau <[email protected]>

Best regards,
Liviu


--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:03:40

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 3/9] drm/komeda: Build komeda to be a platform module

On Fri, Dec 21, 2018 at 09:59:28AM +0000, james qian wang (Arm Technology China) wrote:
> Implement a simple wrapper for platform module to build komeda to module,
> Also add a very simple D71 layer code to show how to discover a product.
> Komeda driver direct bind the product ENTRY function xxx_identity to DT
> compatible name like:
>
> d71_product = {
> .product_id = MALIDP_D71_PRODUCT_ID,
> .identify = d71_identify,
> },
>
> const struct of_device_id komeda_of_match[] = {
> { .compatible = "arm,mali-d71", .data = &d71_product, },
> {},
> };
>
> Then when linux found a matched DT node and call driver to probe, we can
> easily get the of data, and call into the product to do the identify:
>
> komeda_bind()
> {
> ...
> product = of_device_get_match_data(dev);
>
> product->identify();
> ...
> }
>
> Changes in v3:
> - Fixed style problem found by checkpatch.pl --strict.
>
> Signed-off-by: James (Qian) Wang <[email protected]>

Acked-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> .../gpu/drm/arm/display/include/malidp_io.h | 42 ++++++
> drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
> .../gpu/drm/arm/display/komeda/d71/d71_dev.c | 33 +++++
> .../gpu/drm/arm/display/komeda/komeda_dev.h | 3 +
> .../gpu/drm/arm/display/komeda/komeda_drv.c | 132 ++++++++++++++++++
> 5 files changed, 215 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/arm/display/include/malidp_io.h
> create mode 100644 drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_drv.c
>
> diff --git a/drivers/gpu/drm/arm/display/include/malidp_io.h b/drivers/gpu/drm/arm/display/include/malidp_io.h
> new file mode 100644
> index 000000000000..4fb3caf864ce
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/include/malidp_io.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#ifndef _MALIDP_IO_H_
> +#define _MALIDP_IO_H_
> +
> +#include <linux/io.h>
> +
> +static inline u32
> +malidp_read32(u32 __iomem *base, u32 offset)
> +{
> + return readl((base + (offset >> 2)));
> +}
> +
> +static inline void
> +malidp_write32(u32 __iomem *base, u32 offset, u32 v)
> +{
> + writel(v, (base + (offset >> 2)));
> +}
> +
> +static inline void
> +malidp_write32_mask(u32 __iomem *base, u32 offset, u32 m, u32 v)
> +{
> + u32 tmp = malidp_read32(base, offset);
> +
> + tmp &= (~m);
> + malidp_write32(base, offset, v | tmp);
> +}
> +
> +static inline void
> +malidp_write_group(u32 __iomem *base, u32 offset, int num, const u32 *values)
> +{
> + int i;
> +
> + for (i = 0; i < num; i++)
> + malidp_write32(base, offset + i * 4, values[i]);
> +}
> +
> +#endif /*_MALIDP_IO_H_*/
> diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> index 5b44e36509b1..c03d6876ef75 100644
> --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> @@ -5,7 +5,11 @@ ccflags-y := \
> -I$(src)
>
> komeda-y := \
> + komeda_drv.o \
> komeda_dev.o \
> - komeda_pipeline.o \
> + komeda_pipeline.o
> +
> +komeda-y += \
> + d71/d71_dev.o
>
> obj-$(CONFIG_DRM_KOMEDA) += komeda.o
> diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
> new file mode 100644
> index 000000000000..af3dabb499cd
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
> @@ -0,0 +1,33 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include "malidp_io.h"
> +#include "komeda_dev.h"
> +
> +static int d71_enum_resources(struct komeda_dev *mdev)
> +{
> + /* TODO add enum resources */
> + return -1;
> +}
> +
> +static struct komeda_dev_funcs d71_chip_funcs = {
> + .enum_resources = d71_enum_resources,
> + .cleanup = NULL,
> +};
> +
> +#define GLB_ARCH_ID 0x000
> +#define GLB_CORE_ID 0x004
> +#define GLB_CORE_INFO 0x008
> +
> +struct komeda_dev_funcs *
> +d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)
> +{
> + chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID);
> + chip->core_id = malidp_read32(reg_base, GLB_CORE_ID);
> + chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO);
> +
> + return &d71_chip_funcs;
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> index ad8fa160eff9..680e3e2cf100 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> @@ -92,6 +92,9 @@ komeda_product_match(struct komeda_dev *mdev, u32 target)
> return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
> }
>
> +struct komeda_dev_funcs *
> +d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip);
> +
> struct komeda_dev *komeda_dev_create(struct device *dev);
> void komeda_dev_destroy(struct komeda_dev *mdev);
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> new file mode 100644
> index 000000000000..a2657b3d09d7
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> @@ -0,0 +1,132 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/component.h>
> +#include <drm/drm_of.h>
> +#include "komeda_dev.h"
> +
> +struct komeda_drv {
> + struct komeda_dev *mdev;
> +};
> +
> +static void komeda_unbind(struct device *dev)
> +{
> + struct komeda_drv *mdrv = dev_get_drvdata(dev);
> +
> + dev_set_drvdata(dev, NULL);
> +
> + if (!mdrv)
> + return;
> +
> + komeda_dev_destroy(mdrv->mdev);
> + kfree(mdrv);
> +}
> +
> +static int komeda_bind(struct device *dev)
> +{
> + struct komeda_drv *mdrv;
> + int err;
> +
> + mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
> + if (!mdrv)
> + return -ENOMEM;
> +
> + mdrv->mdev = komeda_dev_create(dev);
> + if (IS_ERR(mdrv->mdev)) {
> + err = PTR_ERR(mdrv->mdev);
> + goto free_mdrv;
> + }
> +
> + dev_set_drvdata(dev, mdrv);
> +
> + return 0;
> +
> +free_mdrv:
> + kfree(mdrv);
> + return err;
> +}
> +
> +static const struct component_master_ops komeda_master_ops = {
> + .bind = komeda_bind,
> + .unbind = komeda_unbind,
> +};
> +
> +static int compare_of(struct device *dev, void *data)
> +{
> + return dev->of_node == data;
> +}
> +
> +static void komeda_add_slave(struct device *master,
> + struct component_match **match,
> + struct device_node *np, int port)
> +{
> + struct device_node *remote;
> +
> + remote = of_graph_get_remote_node(np, port, 0);
> + if (!remote) {
> + drm_of_component_match_add(master, match, compare_of, remote);
> + of_node_put(remote);
> + }
> +}
> +
> +static int komeda_platform_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct component_match *match = NULL;
> + struct device_node *child;
> +
> + if (!dev->of_node)
> + return -ENODEV;
> +
> + for_each_available_child_of_node(dev->of_node, child) {
> + if (of_node_cmp(child->name, "pipeline") != 0)
> + continue;
> +
> + /* add connector */
> + komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
> + }
> +
> + return component_master_add_with_match(dev, &komeda_master_ops, match);
> +}
> +
> +static int komeda_platform_remove(struct platform_device *pdev)
> +{
> + component_master_del(&pdev->dev, &komeda_master_ops);
> + return 0;
> +}
> +
> +static const struct komeda_product_data komeda_products[] = {
> + [MALI_D71] = {
> + .product_id = MALIDP_D71_PRODUCT_ID,
> + .identify = d71_identify,
> + },
> +};
> +
> +const struct of_device_id komeda_of_match[] = {
> + { .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], },
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(of, komeda_of_match);
> +
> +static struct platform_driver komeda_platform_driver = {
> + .probe = komeda_platform_probe,
> + .remove = komeda_platform_remove,
> + .driver = {
> + .name = "komeda",
> + .of_match_table = komeda_of_match,
> + .pm = NULL,
> + },
> +};
> +
> +module_platform_driver(komeda_platform_driver);
> +
> +MODULE_AUTHOR("James.Qian.Wang <[email protected]>");
> +MODULE_DESCRIPTION("Komeda KMS driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.17.1
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:05:38

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 4/9] drm/komeda: Add DT parsing

On Fri, Dec 21, 2018 at 09:59:44AM +0000, james qian wang (Arm Technology China) wrote:
> Parse DT and initialize corresponding dev/pipeline attributes.
>
> Changes in v3:
> - Fixed style problem found by checkpatch.pl --strict.
>
> Changes in v2:
> - Unified abbreviation of "pipeline" to "pipe".
>
> Signed-off-by: James (Qian) Wang <[email protected]>

Acked-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> .../gpu/drm/arm/display/komeda/komeda_dev.c | 76 +++++++++++++++++++
> .../gpu/drm/arm/display/komeda/komeda_dev.h | 3 +
> .../drm/arm/display/komeda/komeda_pipeline.c | 4 +
> .../drm/arm/display/komeda/komeda_pipeline.h | 7 ++
> 4 files changed, 90 insertions(+)
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> index 887a17005367..d0cc4f758077 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> @@ -12,6 +12,76 @@
> #include <linux/version.h>
> #include "komeda_dev.h"
>
> +static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
> +{
> + struct komeda_pipeline *pipe;
> + struct clk *clk;
> + u32 pipe_id;
> + int ret = 0;
> +
> + ret = of_property_read_u32(np, "reg", &pipe_id);
> + if (ret != 0 || pipe_id >= mdev->n_pipelines)
> + return -EINVAL;
> +
> + pipe = mdev->pipelines[pipe_id];
> +
> + clk = of_clk_get_by_name(np, "aclk");
> + if (IS_ERR(clk)) {
> + DRM_ERROR("get aclk for pipeline %d failed!\n", pipe_id);
> + return PTR_ERR(clk);
> + }
> + pipe->aclk = clk;
> +
> + clk = of_clk_get_by_name(np, "pxclk");
> + if (IS_ERR(clk)) {
> + DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id);
> + return PTR_ERR(clk);
> + }
> + pipe->pxlclk = clk;
> +
> + /* enum ports */
> + pipe->of_output_dev =
> + of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
> + pipe->of_output_port =
> + of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
> +
> + pipe->of_node = np;
> +
> + return 0;
> +}
> +
> +static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct device_node *child, *np = dev->of_node;
> + struct clk *clk;
> + int ret;
> +
> + clk = devm_clk_get(dev, "mclk");
> + if (IS_ERR(clk))
> + return PTR_ERR(clk);
> +
> + mdev->mclk = clk;
> + mdev->irq = platform_get_irq(pdev, 0);
> + if (mdev->irq < 0) {
> + DRM_ERROR("could not get IRQ number.\n");
> + return mdev->irq;
> + }
> +
> + for_each_available_child_of_node(np, child) {
> + if (of_node_cmp(child->name, "pipeline") == 0) {
> + ret = komeda_parse_pipe_dt(mdev, child);
> + if (ret) {
> + DRM_ERROR("parse pipeline dt error!\n");
> + of_node_put(child);
> + break;
> + }
> + }
> + }
> +
> + return ret;
> +}
> +
> struct komeda_dev *komeda_dev_create(struct device *dev)
> {
> struct platform_device *pdev = to_platform_device(dev);
> @@ -74,6 +144,12 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
> goto err_cleanup;
> }
>
> + err = komeda_parse_dt(dev, mdev);
> + if (err) {
> + DRM_ERROR("parse device tree failed.\n");
> + goto err_cleanup;
> + }
> +
> return mdev;
>
> err_cleanup:
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> index 680e3e2cf100..4a27a44e2ec6 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> @@ -72,6 +72,9 @@ struct komeda_dev {
> /** @mck: HW main engine clk */
> struct clk *mclk;
>
> + /** @irq: irq number */
> + u32 irq;
> +
> int n_pipelines;
> struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> index 9293598b0533..e731b2a85c3a 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> @@ -55,6 +55,10 @@ void komeda_pipeline_destroy(struct komeda_dev *mdev,
> clk_put(pipe->pxlclk);
> clk_put(pipe->aclk);
>
> + of_node_put(pipe->of_output_dev);
> + of_node_put(pipe->of_output_port);
> + of_node_put(pipe->of_node);
> +
> devm_kfree(mdev->dev, pipe);
> }
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> index 2174796d47c5..d1e0c1140273 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> @@ -290,6 +290,13 @@ struct komeda_pipeline {
> struct komeda_improc *improc;
> struct komeda_timing_ctrlr *ctrlr;
> struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
> +
> + /** @of_node: pipeline dt node */
> + struct device_node *of_node;
> + /** @of_output_port: pipeline output port */
> + struct device_node *of_output_port;
> + /** @of_output_dev: output connector device node */
> + struct device_node *of_output_dev;
> };
>
> /**
> --
> 2.17.1
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:06:53

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 5/9] drm/komeda: Add komeda_format_caps for format handling

On Fri, Dec 21, 2018 at 10:00:01AM +0000, james qian wang (Arm Technology China) wrote:
> komeda_format_caps is for describing ARM display specific features and
> limitations of a specific format, and format_caps will be linked into
> &komeda_framebuffer like a extension of &drm_format_info.
> And komed_format_caps_table will be initialized before the enum_resources,
> since the layer features description depend on this format_caps table, so
> we'd better initialize the table first.
>
> Changes in v3:
> - Fixed style problem found by checkpatch.pl --strict.
>
> Signed-off-by: James (Qian) Wang <[email protected]>

Acked-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> drivers/gpu/drm/arm/display/komeda/Makefile | 1 +
> .../gpu/drm/arm/display/komeda/d71/d71_dev.c | 78 ++++++++++++++++
> .../gpu/drm/arm/display/komeda/komeda_dev.c | 2 +
> .../gpu/drm/arm/display/komeda/komeda_dev.h | 11 ++-
> .../arm/display/komeda/komeda_format_caps.c | 75 ++++++++++++++++
> .../arm/display/komeda/komeda_format_caps.h | 89 +++++++++++++++++++
> .../drm/arm/display/komeda/komeda_pipeline.h | 1 +
> 7 files changed, 256 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> index c03d6876ef75..394fc2aa434a 100644
> --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> @@ -7,6 +7,7 @@ ccflags-y := \
> komeda-y := \
> komeda_drv.o \
> komeda_dev.o \
> + komeda_format_caps.o \
> komeda_pipeline.o
>
> komeda-y += \
> diff --git a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
> index af3dabb499cd..edbf9daa1545 100644
> --- a/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
> +++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
> @@ -13,7 +13,85 @@ static int d71_enum_resources(struct komeda_dev *mdev)
> return -1;
> }
>
> +#define __HW_ID(__group, __format) \
> + ((((__group) & 0x7) << 3) | ((__format) & 0x7))
> +
> +#define RICH KOMEDA_FMT_RICH_LAYER
> +#define SIMPLE KOMEDA_FMT_SIMPLE_LAYER
> +#define RICH_SIMPLE (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_SIMPLE_LAYER)
> +#define RICH_WB (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_WB_LAYER)
> +#define RICH_SIMPLE_WB (RICH_SIMPLE | KOMEDA_FMT_WB_LAYER)
> +
> +#define Rot_0 DRM_MODE_ROTATE_0
> +#define Flip_H_V (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | Rot_0)
> +#define Rot_ALL_H_V (DRM_MODE_ROTATE_MASK | Flip_H_V)
> +
> +#define LYT_NM BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)
> +#define LYT_WB BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
> +#define LYT_NM_WB (LYT_NM | LYT_WB)
> +
> +#define AFB_TH AFBC(_TILED | _SPARSE)
> +#define AFB_TH_SC_YTR AFBC(_TILED | _SC | _SPARSE | _YTR)
> +#define AFB_TH_SC_YTR_BS AFBC(_TILED | _SC | _SPARSE | _YTR | _SPLIT)
> +
> +static struct komeda_format_caps d71_format_caps_table[] = {
> + /* HW_ID | fourcc | tile_sz | layer_types | rots | afbc_layouts | afbc_features */
> + /* ABGR_2101010*/
> + {__HW_ID(0, 0), DRM_FORMAT_ARGB2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
> + {__HW_ID(0, 2), DRM_FORMAT_RGBA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(0, 3), DRM_FORMAT_BGRA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + /* ABGR_8888*/
> + {__HW_ID(1, 0), DRM_FORMAT_ARGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
> + {__HW_ID(1, 2), DRM_FORMAT_RGBA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(1, 3), DRM_FORMAT_BGRA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + /* XBGB_8888 */
> + {__HW_ID(2, 0), DRM_FORMAT_XRGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(2, 1), DRM_FORMAT_XBGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(2, 2), DRM_FORMAT_RGBX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + {__HW_ID(2, 3), DRM_FORMAT_BGRX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
> + /* BGR_888 */ /* none-afbc RGB888 doesn't support rotation and flip */
> + {__HW_ID(3, 0), DRM_FORMAT_RGB888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
> + {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
> + {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
> + /* BGR 16bpp */
> + {__HW_ID(4, 0), DRM_FORMAT_RGBA5551, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
> + {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
> + {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
> + {__HW_ID(4, 2), DRM_FORMAT_RGB565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
> + {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
> + {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
> + {__HW_ID(4, 4), DRM_FORMAT_R8, 1, SIMPLE, Rot_0, 0, 0},
> + /* YUV 444/422/420 8bit */
> + {__HW_ID(5, 0), 0 /*XYUV8888*/, 1, 0, 0, 0, 0},
> + /* XYUV unsupported*/
> + {__HW_ID(5, 1), DRM_FORMAT_YUYV, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
> + {__HW_ID(5, 2), DRM_FORMAT_YUYV, 1, RICH, Flip_H_V, 0, 0},
> + {__HW_ID(5, 3), DRM_FORMAT_UYVY, 1, RICH, Flip_H_V, 0, 0},
> + {__HW_ID(5, 4), 0, /*X0L0 */ 2, 0, 0, 0}, /* Y0L0 unsupported */
> + {__HW_ID(5, 6), DRM_FORMAT_NV12, 1, RICH, Flip_H_V, 0, 0},
> + {__HW_ID(5, 6), 0/*DRM_FORMAT_YUV420_8BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
> + {__HW_ID(5, 7), DRM_FORMAT_YUV420, 1, RICH, Flip_H_V, 0, 0},
> + /* YUV 10bit*/
> + {__HW_ID(6, 0), 0,/*XVYU2101010*/ 1, 0, 0, 0, 0},/* VYV30 unsupported */
> + {__HW_ID(6, 6), 0/*DRM_FORMAT_X0L2*/, 2, RICH, Flip_H_V, 0, 0},
> + {__HW_ID(6, 7), 0/*DRM_FORMAT_P010*/, 1, RICH, Flip_H_V, 0, 0},
> + {__HW_ID(6, 7), 0/*DRM_FORMAT_YUV420_10BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH},
> +};
> +
> +static void d71_init_fmt_tbl(struct komeda_dev *mdev)
> +{
> + struct komeda_format_caps_table *table = &mdev->fmt_tbl;
> +
> + table->format_caps = d71_format_caps_table;
> + table->n_formats = ARRAY_SIZE(d71_format_caps_table);
> +}
> +
> static struct komeda_dev_funcs d71_chip_funcs = {
> + .init_format_table = d71_init_fmt_tbl,
> .enum_resources = d71_enum_resources,
> .cleanup = NULL,
> };
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> index d0cc4f758077..2f8f4685eb62 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> @@ -138,6 +138,8 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
> MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
> MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
>
> + mdev->funcs->init_format_table(mdev);
> +
> err = mdev->funcs->enum_resources(mdev);
> if (err) {
> DRM_ERROR("enumerate display resource failed.\n");
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> index 4a27a44e2ec6..555510be66f1 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> @@ -11,6 +11,7 @@
> #include <linux/interrupt.h>
> #include "komeda_pipeline.h"
> #include "malidp_product.h"
> +#include "komeda_format_caps.h"
>
> /* malidp device id */
> enum {
> @@ -44,6 +45,13 @@ struct komeda_dev;
> * Supplied by chip level and returned by the chip entry function xxx_identify,
> */
> struct komeda_dev_funcs {
> + /**
> + * @init_format_table:
> + *
> + * initialize &komeda_dev->format_table, this function should be called
> + * before the &enum_resource
> + */
> + void (*init_format_table)(struct komeda_dev *mdev);
> /**
> * @enum_resources:
> *
> @@ -66,7 +74,8 @@ struct komeda_dev {
> u32 __iomem *reg_base;
>
> struct komeda_chip_info chip;
> -
> + /** @fmt_tbl: initialized by &komeda_dev_funcs->init_format_table */
> + struct komeda_format_caps_table fmt_tbl;
> /** @pclk: APB clock for register access */
> struct clk *pclk;
> /** @mck: HW main engine clk */
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
> new file mode 100644
> index 000000000000..1e17bd6107a4
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c
> @@ -0,0 +1,75 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +
> +#include <linux/slab.h>
> +#include "komeda_format_caps.h"
> +#include "malidp_utils.h"
> +
> +const struct komeda_format_caps *
> +komeda_get_format_caps(struct komeda_format_caps_table *table,
> + u32 fourcc, u64 modifier)
> +{
> + const struct komeda_format_caps *caps;
> + u64 afbc_features = modifier & ~(AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
> + u32 afbc_layout = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
> + int id;
> +
> + for (id = 0; id < table->n_formats; id++) {
> + caps = &table->format_caps[id];
> +
> + if (fourcc != caps->fourcc)
> + continue;
> +
> + if ((modifier == 0ULL) && (caps->supported_afbc_layouts == 0))
> + return caps;
> +
> + if (has_bits(afbc_features, caps->supported_afbc_features) &&
> + has_bit(afbc_layout, caps->supported_afbc_layouts))
> + return caps;
> + }
> +
> + return NULL;
> +}
> +
> +u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
> + u32 layer_type, u32 *n_fmts)
> +{
> + const struct komeda_format_caps *cap;
> + u32 *fmts;
> + int i, j, n = 0;
> +
> + fmts = kcalloc(table->n_formats, sizeof(u32), GFP_KERNEL);
> + if (!fmts)
> + return NULL;
> +
> + for (i = 0; i < table->n_formats; i++) {
> + cap = &table->format_caps[i];
> + if (!(layer_type & cap->supported_layer_types) ||
> + (cap->fourcc == 0))
> + continue;
> +
> + /* one fourcc may has two caps items in table (afbc/none-afbc),
> + * so check the existing list to avoid adding a duplicated one.
> + */
> + for (j = n - 1; j >= 0; j--)
> + if (fmts[j] == cap->fourcc)
> + break;
> +
> + if (j < 0)
> + fmts[n++] = cap->fourcc;
> + }
> +
> + if (n_fmts)
> + *n_fmts = n;
> +
> + return fmts;
> +}
> +
> +void komeda_put_fourcc_list(u32 *fourcc_list)
> +{
> + kfree(fourcc_list);
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> new file mode 100644
> index 000000000000..60f39e77b098
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> @@ -0,0 +1,89 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +
> +#ifndef _KOMEDA_FORMAT_CAPS_H_
> +#define _KOMEDA_FORMAT_CAPS_H_
> +
> +#include <linux/types.h>
> +#include <uapi/drm/drm_fourcc.h>
> +#include <drm/drm_fourcc.h>
> +
> +#define AFBC(x) DRM_FORMAT_MOD_ARM_AFBC(x)
> +
> +/* afbc layerout */
> +#define AFBC_16x16(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | (x))
> +#define AFBC_32x8(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | (x))
> +
> +/* afbc features */
> +#define _YTR AFBC_FORMAT_MOD_YTR
> +#define _SPLIT AFBC_FORMAT_MOD_SPLIT
> +#define _SPARSE AFBC_FORMAT_MOD_SPARSE
> +#define _CBR AFBC_FORMAT_MOD_CBR
> +#define _TILED AFBC_FORMAT_MOD_TILED
> +#define _SC AFBC_FORMAT_MOD_SC
> +
> +/* layer_type */
> +#define KOMEDA_FMT_RICH_LAYER BIT(0)
> +#define KOMEDA_FMT_SIMPLE_LAYER BIT(1)
> +#define KOMEDA_FMT_WB_LAYER BIT(2)
> +
> +#define AFBC_TH_LAYOUT_ALIGNMENT 8
> +#define AFBC_HEADER_SIZE 16
> +#define AFBC_SUPERBLK_ALIGNMENT 128
> +#define AFBC_SUPERBLK_PIXELS 256
> +#define AFBC_BODY_START_ALIGNMENT 1024
> +#define AFBC_TH_BODY_START_ALIGNMENT 4096
> +
> +/**
> + * struct komeda_format_caps
> + *
> + * komeda_format_caps is for describing ARM display specific features and
> + * limitations for a specific format, and format_caps will be linked into
> + * &komeda_framebuffer like a extension of &drm_format_info.
> + *
> + * NOTE: one fourcc may has two different format_caps items for fourcc and
> + * fourcc+modifier
> + *
> + * @hw_id: hw format id, hw specific value.
> + * @fourcc: drm fourcc format.
> + * @tile_size: format tiled size, used by ARM format X0L0/X0L2
> + * @supported_layer_types: indicate which layer supports this format
> + * @supported_rots: allowed rotations for this format
> + * @supported_afbc_layouts: supported afbc layerout
> + * @supported_afbc_features: supported afbc features
> + */
> +struct komeda_format_caps {
> + u32 hw_id;
> + u32 fourcc;
> + u32 tile_size;
> + u32 supported_layer_types;
> + u32 supported_rots;
> + u32 supported_afbc_layouts;
> + u64 supported_afbc_features;
> +};
> +
> +/**
> + * struct komeda_format_caps_table - format_caps mananger
> + *
> + * @n_formats: the size of format_caps list.
> + * @format_caps: format_caps list.
> + */
> +struct komeda_format_caps_table {
> + u32 n_formats;
> + const struct komeda_format_caps *format_caps;
> +};
> +
> +const struct komeda_format_caps *
> +komeda_get_format_caps(struct komeda_format_caps_table *table,
> + u32 fourcc, u64 modifier);
> +
> +u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
> + u32 layer_type, u32 *n_fmts);
> +
> +void komeda_put_fourcc_list(u32 *fourcc_list);
> +
> +#endif
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> index d1e0c1140273..2d68ffeae25d 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> @@ -213,6 +213,7 @@ static inline u16 component_changed_inputs(struct komeda_component_state *st)
> struct komeda_layer {
> struct komeda_component base;
> /* layer specific features and caps */
> + int layer_type; /* RICH, SIMPLE or WB */
> };
>
> struct komeda_layer_state {
> --
> 2.17.1
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:17:13

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 6/9] drm/komeda: Add komeda_framebuffer

On Fri, Dec 21, 2018 at 10:00:17AM +0000, james qian wang (Arm Technology China) wrote:
> komeda_framebuffer is for extending drm_framebuffer to add komeda own
> attributes and komeda specific fb handling.
>
> Changes in v3:
> - Fixed style problem found by checkpatch.pl --strict.
>
> Signed-off-by: James (Qian) Wang <[email protected]>
> ---
> drivers/gpu/drm/arm/display/komeda/Makefile | 3 +-
> .../arm/display/komeda/komeda_framebuffer.c | 165 ++++++++++++++++++
> .../arm/display/komeda/komeda_framebuffer.h | 31 ++++
> 3 files changed, 198 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> index 394fc2aa434a..25beae900ed2 100644
> --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> @@ -8,7 +8,8 @@ komeda-y := \
> komeda_drv.o \
> komeda_dev.o \
> komeda_format_caps.o \
> - komeda_pipeline.o
> + komeda_pipeline.o \
> + komeda_framebuffer.o
>
> komeda-y += \
> d71/d71_dev.o
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> new file mode 100644
> index 000000000000..4ddd5314ca23
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
> @@ -0,0 +1,165 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include <drm/drm_gem.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include "komeda_framebuffer.h"
> +#include "komeda_dev.h"
> +
> +static void komeda_fb_destroy(struct drm_framebuffer *fb)
> +{
> + struct komeda_fb *kfb = to_kfb(fb);
> + u32 i;
> +
> + for (i = 0; i < fb->format->num_planes; i++)
> + drm_gem_object_put_unlocked(fb->obj[i]);
> +
> + drm_framebuffer_cleanup(fb);
> + kfree(kfb);
> +}
> +
> +static int komeda_fb_create_handle(struct drm_framebuffer *fb,
> + struct drm_file *file, u32 *handle)
> +{
> + return drm_gem_handle_create(file, fb->obj[0], handle);
> +}
> +
> +static const struct drm_framebuffer_funcs komeda_fb_funcs = {
> + .destroy = komeda_fb_destroy,
> + .create_handle = komeda_fb_create_handle,
> +};
> +
> +static int
> +komeda_fb_none_afbc_size_check(struct komeda_dev *mdev, struct komeda_fb *kfb,
> + struct drm_file *file,
> + const struct drm_mode_fb_cmd2 *mode_cmd)

Not sure what _none stands for here, but otherwise:

Acked-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> +{
> + struct drm_framebuffer *fb = &kfb->base;
> + struct drm_gem_object *obj;
> + u32 min_size = 0;
> + u32 i;
> +
> + for (i = 0; i < fb->format->num_planes; i++) {
> + obj = drm_gem_object_lookup(file, mode_cmd->handles[i]);
> + if (!obj) {
> + DRM_DEBUG_KMS("Failed to lookup GEM object\n");
> + fb->obj[i] = NULL;
> +
> + return -ENOENT;
> + }
> +
> + kfb->aligned_w = fb->width / (i ? fb->format->hsub : 1);
> + kfb->aligned_h = fb->height / (i ? fb->format->vsub : 1);
> +
> + if (fb->pitches[i] % mdev->chip.bus_width) {
> + DRM_DEBUG_KMS("Pitch[%d]: 0x%x doesn't align to 0x%x\n",
> + i, fb->pitches[i], mdev->chip.bus_width);
> + drm_gem_object_put_unlocked(obj);
> + fb->obj[i] = NULL;
> +
> + return -EINVAL;
> + }
> +
> + min_size = ((kfb->aligned_h / kfb->format_caps->tile_size - 1)
> + * fb->pitches[i])
> + + (kfb->aligned_w * fb->format->cpp[i]
> + * kfb->format_caps->tile_size)
> + + fb->offsets[i];
> +
> + if (obj->size < min_size) {
> + DRM_DEBUG_KMS("Fail to check none afbc fb size.\n");
> + drm_gem_object_put_unlocked(obj);
> + fb->obj[i] = NULL;
> +
> + return -EINVAL;
> + }
> +
> + fb->obj[i] = obj;
> + }
> +
> + if (fb->format->num_planes == 3) {
> + if (fb->pitches[1] != fb->pitches[2]) {
> + DRM_DEBUG_KMS("The pitch[1] and [2] are not same\n");
> + return -EINVAL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +struct drm_framebuffer *
> +komeda_fb_create(struct drm_device *dev, struct drm_file *file,
> + const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> + struct komeda_dev *mdev = dev->dev_private;
> + struct komeda_fb *kfb;
> + int ret = 0, i;
> +
> + kfb = kzalloc(sizeof(*kfb), GFP_KERNEL);
> + if (!kfb)
> + return ERR_PTR(-ENOMEM);
> +
> + kfb->format_caps = komeda_get_format_caps(&mdev->fmt_tbl,
> + mode_cmd->pixel_format,
> + mode_cmd->modifier[0]);
> + if (!kfb->format_caps) {
> + DRM_DEBUG_KMS("FMT %x is not supported.\n",
> + mode_cmd->pixel_format);
> + kfree(kfb);
> + return ERR_PTR(-EINVAL);
> + }
> +
> + drm_helper_mode_fill_fb_struct(dev, &kfb->base, mode_cmd);
> +
> + ret = komeda_fb_none_afbc_size_check(mdev, kfb, file, mode_cmd);
> + if (ret < 0)
> + goto err_cleanup;
> +
> + ret = drm_framebuffer_init(dev, &kfb->base, &komeda_fb_funcs);
> + if (ret < 0) {
> + DRM_DEBUG_KMS("failed to initialize fb\n");
> +
> + goto err_cleanup;
> + }
> +
> + return &kfb->base;
> +
> +err_cleanup:
> + for (i = 0; i < kfb->base.format->num_planes; i++)
> + drm_gem_object_put_unlocked(kfb->base.obj[i]);
> +
> + kfree(kfb);
> + return ERR_PTR(ret);
> +}
> +
> +dma_addr_t
> +komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane)
> +{
> + struct drm_framebuffer *fb = &kfb->base;
> + const struct drm_gem_cma_object *obj;
> + u32 plane_x, plane_y, cpp, pitch, offset;
> +
> + if (plane > fb->format->num_planes) {
> + DRM_DEBUG_KMS("Out of max plane num.\n");
> + return -EINVAL;
> + }
> +
> + obj = drm_fb_cma_get_gem_obj(fb, plane);
> +
> + offset = fb->offsets[plane];
> + if (!fb->modifier) {
> + plane_x = x / (plane ? fb->format->hsub : 1);
> + plane_y = y / (plane ? fb->format->vsub : 1);
> + cpp = fb->format->cpp[plane];
> + pitch = fb->pitches[plane];
> + offset += plane_x * cpp * kfb->format_caps->tile_size +
> + (plane_y * pitch) / kfb->format_caps->tile_size;
> + }
> +
> + return obj->paddr + offset;
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
> new file mode 100644
> index 000000000000..383780013bb9
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
> @@ -0,0 +1,31 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#ifndef _KOMEDA_FRAMEBUFFER_H_
> +#define _KOMEDA_FRAMEBUFFER_H_
> +
> +/** struct komeda_fb - entend drm_framebuffer with komeda attribute */
> +struct komeda_fb {
> + /** @base: &drm_framebuffer */
> + struct drm_framebuffer base;
> + /* @format_caps: &komeda_format_caps */
> + const struct komeda_format_caps *format_caps;
> + /** @aligned_w: aligned frame buffer width */
> + u32 aligned_w;
> + /** @aligned_h: aligned frame buffer height */
> + u32 aligned_h;
> +};
> +
> +#define to_kfb(dfb) container_of(dfb, struct komeda_fb, base)
> +
> +struct drm_framebuffer *
> +komeda_fb_create(struct drm_device *dev, struct drm_file *file,
> + const struct drm_mode_fb_cmd2 *mode_cmd);
> +dma_addr_t
> +komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane);
> +bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type);
> +
> +#endif
> --
> 2.17.1
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:33:22

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 7/9] drm/komeda: Attach komeda_dev to DRM-KMS

On Fri, Dec 21, 2018 at 10:00:33AM +0000, james qian wang (Arm Technology China) wrote:
> Add komeda_kms abstracton to attach komeda_dev to DRM-KMS
> CRTC: according to the komeda_pipeline
> PLANE: according to komeda_layer (layer input pipeline)
> PRIVATE_OBJS: komeda_pipeline/component all will be treat as private_objs
>
> komeda_kms is for connecting DRM-KMS and komeda_dev, like reporting the
> kms object properties according to the komeda_dev, and pass/convert KMS's
> requirement to komeda_dev.
>
> Changes in v3:
> - Fixed style problem found by checkpatch.pl --strict.
>
> Changes in v2:
> - Unified abbreviation of "pipeline" to "pipe".
>
> Signed-off-by: James (Qian) Wang <[email protected]>
> ---
> drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
> .../gpu/drm/arm/display/komeda/komeda_crtc.c | 106 +++++++++++
> .../gpu/drm/arm/display/komeda/komeda_drv.c | 19 +-
> .../gpu/drm/arm/display/komeda/komeda_kms.c | 169 ++++++++++++++++++
> .../gpu/drm/arm/display/komeda/komeda_kms.h | 113 ++++++++++++
> .../drm/arm/display/komeda/komeda_pipeline.h | 3 +
> .../gpu/drm/arm/display/komeda/komeda_plane.c | 109 +++++++++++
> .../arm/display/komeda/komeda_private_obj.c | 88 +++++++++
> 8 files changed, 608 insertions(+), 5 deletions(-)
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> index 25beae900ed2..1b875e5dc0f6 100644
> --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> @@ -9,7 +9,11 @@ komeda-y := \
> komeda_dev.o \
> komeda_format_caps.o \
> komeda_pipeline.o \
> - komeda_framebuffer.o
> + komeda_framebuffer.o \
> + komeda_kms.o \
> + komeda_crtc.o \
> + komeda_plane.o \
> + komeda_private_obj.o
>
> komeda-y += \
> d71/d71_dev.o
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> new file mode 100644
> index 000000000000..5bb5a55f6b31
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> @@ -0,0 +1,106 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include <linux/clk.h>
> +#include <linux/spinlock.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <linux/pm_runtime.h>
> +#include "komeda_dev.h"
> +#include "komeda_kms.h"
> +
> +struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
> +};
> +
> +static const struct drm_crtc_funcs komeda_crtc_funcs = {
> +};
> +
> +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
> + struct komeda_dev *mdev)
> +{
> + struct komeda_crtc *crtc;
> + struct komeda_pipeline *master;
> + char str[16];
> + int i;
> +
> + kms->n_crtcs = 0;
> +
> + for (i = 0; i < mdev->n_pipelines; i++) {
> + crtc = &kms->crtcs[kms->n_crtcs];
> + master = mdev->pipelines[i];
> +
> + crtc->master = master;
> + crtc->slave = NULL;
> +
> + if (crtc->slave)
> + sprintf(str, "pipe-%d", crtc->slave->id);
> + else
> + sprintf(str, "None");
> +
> + DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
> + kms->n_crtcs, master->id, str,
> + master->of_output_dev ?
> + master->of_output_dev->full_name : "None");
> +
> + kms->n_crtcs++;
> + }
> +
> + return 0;
> +}
> +
> +static struct drm_plane *
> +get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
> +{
> + struct komeda_plane *kplane;
> + struct drm_plane *plane;
> +
> + drm_for_each_plane(plane, &kms->base) {
> + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> + continue;
> +
> + kplane = to_kplane(plane);
> + /* only master can be primary */
> + if (kplane->layer->base.pipeline == crtc->master)
> + return plane;
> + }
> +
> + return NULL;
> +}
> +
> +static int komeda_crtc_add(struct komeda_kms_dev *kms,
> + struct komeda_crtc *kcrtc)
> +{
> + struct drm_crtc *crtc = &kcrtc->base;
> + int err;
> +
> + err = drm_crtc_init_with_planes(&kms->base, crtc,
> + get_crtc_primary(kms, kcrtc), NULL,
> + &komeda_crtc_funcs, NULL);
> + if (err)
> + return err;
> +
> + drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
> + drm_crtc_vblank_reset(crtc);
> +
> + crtc->port = kcrtc->master->of_output_port;
> +
> + return 0;
> +}
> +
> +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> +{
> + int i, err;
> +
> + for (i = 0; i < kms->n_crtcs; i++) {
> + err = komeda_crtc_add(kms, &kms->crtcs[i]);
> + if (err)
> + return err;
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> index a2657b3d09d7..4b8ce717a71c 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> @@ -13,18 +13,21 @@
>
> struct komeda_drv {
> struct komeda_dev *mdev;
> + struct komeda_kms_dev *kms;
> };
>
> static void komeda_unbind(struct device *dev)
> {
> struct komeda_drv *mdrv = dev_get_drvdata(dev);
>
> - dev_set_drvdata(dev, NULL);
> -

I would argue that you're fixing a bug here that was introduced in an
earlier patch, and that you should fix that patch rather than this
change.

> if (!mdrv)
> return;
>
> + komeda_kms_detach(mdrv->kms);
> +
> komeda_dev_destroy(mdrv->mdev);
> +
> + dev_set_drvdata(dev, NULL);
> kfree(mdrv);
> }
>
> @@ -33,7 +36,7 @@ static int komeda_bind(struct device *dev)
> struct komeda_drv *mdrv;
> int err;
>
> - mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
> + mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
> if (!mdrv)
> return -ENOMEM;
>
> @@ -45,10 +48,18 @@ static int komeda_bind(struct device *dev)
>
> dev_set_drvdata(dev, mdrv);
>
> + mdrv->kms = komeda_kms_attach(mdrv->mdev);
> + if (IS_ERR(mdrv->kms)) {
> + err = PTR_ERR(mdrv->kms);

does mdrv->kms needs to be set to NULL here?

> + goto destroy_mdev;
> + }
> +
> return 0;
>
> +destroy_mdev:
> + komeda_dev_destroy(mdrv->mdev);
> free_mdrv:
> - kfree(mdrv);
> + devm_kfree(dev, mdrv);
> return err;
> }
>
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> new file mode 100644
> index 000000000000..fd48360ca524
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> @@ -0,0 +1,169 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include <linux/component.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <linux/interrupt.h>
> +#include "komeda_dev.h"
> +#include "komeda_kms.h"
> +#include "komeda_framebuffer.h"
> +
> +DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
> +
> +static int komeda_gem_cma_dumb_create(struct drm_file *file,
> + struct drm_device *dev,
> + struct drm_mode_create_dumb *args)
> +{
> + u32 alignment = 16; /* TODO get alignment from dev */
> +
> + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
> + alignment);
> +
> + return drm_gem_cma_dumb_create_internal(file, dev, args);
> +}
> +
> +static struct drm_driver komeda_kms_driver = {
> + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
> + DRIVER_PRIME,
> + .lastclose = drm_fb_helper_lastclose,
> + .gem_free_object_unlocked = drm_gem_cma_free_object,
> + .gem_vm_ops = &drm_gem_cma_vm_ops,
> + .dumb_create = komeda_gem_cma_dumb_create,
> + .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> + .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> + .gem_prime_export = drm_gem_prime_export,
> + .gem_prime_import = drm_gem_prime_import,
> + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> + .gem_prime_vmap = drm_gem_cma_prime_vmap,
> + .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> + .gem_prime_mmap = drm_gem_cma_prime_mmap,
> + .fops = &komeda_cma_fops,
> + .name = "komeda",
> + .desc = "ARM Mali Komeda Display Processor driver",
> + .date = "20181101",
> + .major = 0,
> + .minor = 1,
> +};
> +
> +static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
> +{
> + struct drm_device *dev = old_state->dev;
> +
> + drm_atomic_helper_commit_modeset_disables(dev, old_state);
> +
> + drm_atomic_helper_commit_planes(dev, old_state, 0);
> +
> + drm_atomic_helper_commit_modeset_enables(dev, old_state);

Mainline has also introduced the drm_atomic_helper_fake_vblank(old_state) call
to help with writebacks on CRTCs that might be otherwise disabled. Do we need
to have it here too?

> +
> + drm_atomic_helper_wait_for_flip_done(dev, old_state);
> +
> + drm_atomic_helper_commit_hw_done(old_state);
> +
> + drm_atomic_helper_cleanup_planes(dev, old_state);
> +}
> +
> +static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
> + .atomic_commit_tail = komeda_kms_commit_tail,
> +};
> +
> +static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
> + .fb_create = komeda_fb_create,
> + .atomic_check = NULL,/*komeda_kms_check*/

I would argue that you should at least use drm_atomic_helper_check here,
rather than set it to NULL, even if later you will replace it with a
komeda function.

> + .atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
> + struct komeda_dev *mdev)
> +{
> + struct drm_mode_config *config = &kms->base.mode_config;
> +
> + drm_mode_config_init(&kms->base);
> +
> + komeda_kms_setup_crtcs(kms, mdev);
> +
> + /* Get value from dev */
> + config->min_width = 0;
> + config->min_height = 0;
> + config->max_width = 4096;
> + config->max_height = 4096;
> + config->allow_fb_modifiers = true;
> +
> + config->funcs = &komeda_mode_config_funcs;
> + config->helper_private = &komeda_mode_config_helpers;
> +}
> +
> +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
> +{
> + struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
> + struct drm_device *drm;
> + int err;
> +
> + if (!kms)
> + return ERR_PTR(-ENOMEM);
> +
> + drm = &kms->base;
> + err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
> + if (err)
> + goto free_kms;
> +
> + drm->dev_private = mdev;
> +
> + komeda_kms_mode_config_init(kms, mdev);
> +
> + err = komeda_kms_add_private_objs(kms, mdev);
> + if (err)
> + goto cleanup_mode_config;
> +
> + err = komeda_kms_add_planes(kms, mdev);
> + if (err)
> + goto cleanup_mode_config;
> +
> + err = drm_vblank_init(drm, kms->n_crtcs);
> + if (err)
> + goto cleanup_mode_config;
> +
> + err = komeda_kms_add_crtcs(kms, mdev);
> + if (err)
> + goto cleanup_mode_config;
> +
> + err = component_bind_all(mdev->dev, kms);
> + if (err)
> + goto cleanup_mode_config;
> +
> + drm_mode_config_reset(drm);
> +
> + err = drm_dev_register(drm, 0);
> + if (err)
> + goto uninstall_irq;
> +
> + return kms;
> +
> +uninstall_irq:
> + drm_irq_uninstall(drm);
> +cleanup_mode_config:
> + drm_mode_config_cleanup(drm);
> +free_kms:
> + kfree(kms);
> + return ERR_PTR(err);
> +}
> +
> +void komeda_kms_detach(struct komeda_kms_dev *kms)
> +{
> + struct drm_device *drm = &kms->base;
> + struct komeda_dev *mdev = drm->dev_private;
> +
> + drm_dev_unregister(drm);
> + component_unbind_all(mdev->dev, drm);
> + komeda_kms_cleanup_private_objs(mdev);
> + drm_mode_config_cleanup(drm);
> + drm->dev_private = NULL;
> + drm_dev_put(drm);
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> new file mode 100644
> index 000000000000..f13666004a42
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> @@ -0,0 +1,113 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#ifndef _KOMEDA_KMS_H_
> +#define _KOMEDA_KMS_H_
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_writeback.h>
> +
> +/** struct komeda_plane - komeda instance of drm_plane */
> +struct komeda_plane {
> + /** @base: &drm_plane */
> + struct drm_plane base;
> + /**
> + * @layer:
> + *
> + * represents available layer input pipelines for this plane.
> + *
> + * NOTE:
> + * the layer is not for a specific Layer, but indicate a group of
> + * Layers with same capabilities.
> + */
> + struct komeda_layer *layer;
> +};
> +
> +/**
> + * struct komeda_plane_state
> + *
> + * The plane_state can be split into two data flow (left/right) and handled
> + * by two layers &komeda_plane.layer and &komeda_plane.layer.right
> + */
> +struct komeda_plane_state {
> + /** @base: &drm_plane_state */
> + struct drm_plane_state base;
> +
> + /* private properties */
> +};
> +
> +/**
> + * struct komeda_wb_connector
> + */
> +struct komeda_wb_connector {
> + /** @base: &drm_writeback_connector */
> + struct drm_writeback_connector base;
> +
> + /** @wb_layer: represents associated writeback pipeline of komeda */
> + struct komeda_layer *wb_layer;
> +};
> +
> +/**
> + * struct komeda_crtc
> + */
> +struct komeda_crtc {
> + /** @base: &drm_crtc */
> + struct drm_crtc base;
> + /** @master: only master has display output */
> + struct komeda_pipeline *master;
> + /**
> + * @slave: optional
> + *
> + * Doesn't have its own display output, the handled data flow will
> + * merge into the master.
> + */
> + struct komeda_pipeline *slave;
> +};
> +
> +/** struct komeda_crtc_state */
> +struct komeda_crtc_state {
> + /** @base: &drm_crtc_state */
> + struct drm_crtc_state base;
> +
> + /* private properties */
> +
> + /* computed state which are used by validate/check */
> + u32 affected_pipes;
> + u32 active_pipes;
> +};
> +
> +/** struct komeda_kms_dev - for gather KMS related things */
> +struct komeda_kms_dev {
> + /** @base: &drm_device */
> + struct drm_device base;
> +
> + /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
> + int n_crtcs;
> + /** @crtcs: crtcs list */
> + struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
> +};
> +
> +#define to_kplane(p) container_of(p, struct komeda_plane, base)
> +#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
> +#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
> +#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
> +#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
> +#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
> +
> +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> +
> +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> + struct komeda_dev *mdev);
> +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
> +
> +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
> +void komeda_kms_detach(struct komeda_kms_dev *kms);
> +
> +#endif /*_KOMEDA_KMS_H_*/
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> index 2d68ffeae25d..114129d96851 100644
> --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> @@ -333,6 +333,9 @@ struct komeda_pipeline_state {
> #define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
> #define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
>
> +#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
> +#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
> +
> /* pipeline APIs */
> struct komeda_pipeline *
> komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> new file mode 100644
> index 000000000000..0a4953a9a909
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> @@ -0,0 +1,109 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_plane_helper.h>
> +#include "komeda_dev.h"
> +#include "komeda_kms.h"
> +
> +static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
> +};
> +
> +static void komeda_plane_destroy(struct drm_plane *plane)
> +{
> + drm_plane_cleanup(plane);
> +
> + kfree(to_kplane(plane));
> +}
> +
> +static const struct drm_plane_funcs komeda_plane_funcs = {
> +};
> +
> +/* for komeda, which is pipeline can be share between crtcs */
> +static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
> + struct komeda_pipeline *pipe)
> +{
> + struct komeda_crtc *crtc;
> + u32 possible_crtcs = 0;
> + int i;
> +
> + for (i = 0; i < kms->n_crtcs; i++) {
> + crtc = &kms->crtcs[i];
> +
> + if ((pipe == crtc->master) || (pipe == crtc->slave))
> + possible_crtcs |= BIT(i);
> + }
> +
> + return possible_crtcs;
> +}
> +
> +/* use Layer0 as primary */
> +static u32 get_plane_type(struct komeda_kms_dev *kms,
> + struct komeda_component *c)
> +{
> + bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
> +
> + return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
> +}
> +
> +static int komeda_plane_add(struct komeda_kms_dev *kms,
> + struct komeda_layer *layer)
> +{
> + struct komeda_dev *mdev = kms->base.dev_private;
> + struct komeda_component *c = &layer->base;
> + struct komeda_plane *kplane;
> + struct drm_plane *plane;
> + u32 *formats, n_formats = 0;
> + int err;
> +
> + kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
> + if (!kplane)
> + return -ENOMEM;
> +
> + plane = &kplane->base;
> + kplane->layer = layer;
> +
> + formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
> + layer->layer_type, &n_formats);
> +
> + err = drm_universal_plane_init(&kms->base, plane,
> + get_possible_crtcs(kms, c->pipeline),
> + &komeda_plane_funcs,
> + formats, n_formats, NULL,
> + get_plane_type(kms, c),
> + "%s", c->name);
> +
> + komeda_put_fourcc_list(formats);
> +
> + if (err)
> + goto cleanup;
> +
> + drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
> +
> + return 0;
> +cleanup:
> + komeda_plane_destroy(plane);
> + return err;
> +}
> +
> +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> +{
> + struct komeda_pipeline *pipe;
> + int i, j, err;
> +
> + for (i = 0; i < mdev->n_pipelines; i++) {
> + pipe = mdev->pipelines[i];
> +
> + for (j = 0; j < pipe->n_layers; j++) {
> + err = komeda_plane_add(kms, pipe->layers[j]);
> + if (err)
> + return err;
> + }
> + }
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> new file mode 100644
> index 000000000000..9edfd6ab0c12
> --- /dev/null
> +++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> @@ -0,0 +1,88 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> + * Author: James.Qian.Wang <[email protected]>
> + *
> + */
> +#include "komeda_dev.h"
> +#include "komeda_kms.h"
> +
> +static struct drm_private_state *
> +komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
> +{
> + struct komeda_pipeline_state *st;
> +
> + st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
> + if (!st)
> + return NULL;
> +
> + st->active_comps = 0;
> +
> + __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
> +
> + return &st->obj;
> +}
> +
> +static void
> +komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
> + struct drm_private_state *state)
> +{
> + kfree(priv_to_pipe_st(state));
> +}
> +
> +static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
> + .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
> + .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
> +};
> +
> +static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
> + struct komeda_pipeline *pipe)
> +{
> + struct komeda_pipeline_state *st;
> +
> + st = kzalloc(sizeof(*st), GFP_KERNEL);
> + if (!st)
> + return -ENOMEM;
> +
> + st->pipe = pipe;
> + drm_atomic_private_obj_init(&pipe->obj, &st->obj,
> + &komeda_pipeline_obj_funcs);
> +
> + return 0;
> +}
> +
> +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> + struct komeda_dev *mdev)
> +{
> + struct komeda_pipeline *pipe;
> + int i, err;
> +
> + for (i = 0; i < mdev->n_pipelines; i++) {
> + pipe = mdev->pipelines[i];
> +
> + err = komeda_pipeline_obj_add(kms, pipe);
> + if (err)
> + return err;
> +
> + /* Add component */
> + }
> +
> + return 0;
> +}
> +
> +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
> +{
> + struct komeda_pipeline *pipe;
> + struct komeda_component *c;
> + int i, id;
> +
> + for (i = 0; i < mdev->n_pipelines; i++) {
> + pipe = mdev->pipelines[i];
> + dp_for_each_set_bit(id, pipe->avail_comps) {
> + c = komeda_pipeline_get_component(pipe, id);
> +
> + drm_atomic_private_obj_fini(&c->obj);
> + }
> + drm_atomic_private_obj_fini(&pipe->obj);
> + }
> +}
> --
> 2.17.1
>

Reviewed-by: Liviu Dudau <[email protected]>

Best regards,
Liviu


--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:34:07

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 8/9] drm/doc: Add initial komeda driver documentation

On Fri, Dec 21, 2018 at 10:00:49AM +0000, james qian wang (Arm Technology China) wrote:
> v2: Some editing changes according to Randy Dunlap's comments
>
> Signed-off-by: James (Qian) Wang <[email protected]>

Reviewed-by: Liviu Dudau <[email protected]>

> ---
> Documentation/gpu/drivers.rst | 1 +
> Documentation/gpu/komeda-kms.rst | 488 +++++++++++++++++++++++++++++++
> 2 files changed, 489 insertions(+)
> create mode 100644 Documentation/gpu/komeda-kms.rst
>
> diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
> index 7c1672118a73..978e6da9bbff 100644
> --- a/Documentation/gpu/drivers.rst
> +++ b/Documentation/gpu/drivers.rst
> @@ -17,6 +17,7 @@ GPU Driver Documentation
> vkms
> bridge/dw-hdmi
> xen-front
> + komeda-kms
>
> .. only:: subproject and html
>
> diff --git a/Documentation/gpu/komeda-kms.rst b/Documentation/gpu/komeda-kms.rst
> new file mode 100644
> index 000000000000..b08da1cffecc
> --- /dev/null
> +++ b/Documentation/gpu/komeda-kms.rst
> @@ -0,0 +1,488 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +==============================
> + drm/komeda Arm display driver
> +==============================
> +
> +The drm/komeda driver supports the Arm display processor D71 and later products,
> +this document gives a brief overview of driver design: how it works and why
> +design it like that.
> +
> +Overview of D71 like display IPs
> +================================
> +
> +From D71, Arm display IP begins to adopt a flexible and modularized
> +architecture. A display pipeline is made up of multiple individual and
> +functional pipeline stages called components, and every component has some
> +specific capabilities that can give the flowed pipeline pixel data a
> +particular processing.
> +
> +Typical D71 components:
> +
> +Layer
> +-----
> +Layer is the first pipeline stage, which prepares the pixel data for the next
> +stage. It fetches the pixel from memory, decodes it if it's AFBC, rotates the
> +source image, unpacks or converts YUV pixels to the device internal RGB pixels,
> +then adjusts the color_space of pixels if needed.
> +
> +Scaler
> +------
> +As its name suggests, scaler takes responsibility for scaling, and D71 also
> +supports image enhancements by scaler.
> +The usage of scaler is very flexible and can be connected to layer output
> +for layer scaling, or connected to compositor and scale the whole display
> +frame and then feed the output data into wb_layer which will then write it
> +into memory.
> +
> +Compositor (compiz)
> +-------------------
> +Compositor blends multiple layers or pixel data flows into one single display
> +frame. its output frame can be fed into post image processor for showing it on
> +the monitor or fed into wb_layer and written to memory at the same time.
> +user can also insert a scaler between compositor and wb_layer to down scale
> +the display frame first and and then write to memory.
> +
> +Writeback Layer (wb_layer)
> +--------------------------
> +Writeback layer does the opposite things of Layer, which connects to compiz
> +and writes the composition result to memory.
> +
> +Post image processor (improc)
> +-----------------------------
> +Post image processor adjusts frame data like gamma and color space to fit the
> +requirements of the monitor.
> +
> +Timing controller (timing_ctrlr)
> +--------------------------------
> +Final stage of display pipeline, Timing controller is not for the pixel
> +handling, but only for controlling the display timing.
> +
> +Merger
> +------
> +D71 scaler mostly only has the half horizontal input/output capabilities
> +compared with Layer, like if Layer supports 4K input size, the scaler only can
> +support 2K input/output in the same time. To achieve the ful frame scaling, D71
> +introduces Layer Split, which splits the whole image to two half parts and feeds
> +them to two Layers A and B, and does the scaling independently. After scaling
> +the result need to be fed to merger to merge two part images together, and then
> +output merged result to compiz.
> +
> +Splitter
> +--------
> +Similar to Layer Split, but Splitter is used for writeback, which splits the
> +compiz result to two parts and then feed them to two scalers.
> +
> +Possible D71 Pipeline usage
> +===========================
> +
> +Benefitting from the modularized architecture, D71 pipelines can be easily
> +adjusted to fit different usages. And D71 has two pipelines, which support two
> +types of working mode:
> +
> +- Dual display mode
> + Two pipelines work independently and separately to drive two display outputs.
> +
> +- Single display mode
> + Two pipelines work together to drive only one display output.
> +
> + On this mode, pipeline_B doesn't work indenpendently, but outputs its
> + composition result into pipeline_A, and its pixel timing also derived from
> + pipeline_A.timing_ctrlr. The pipeline_B works just like a "slave" of
> + pipeline_A(master)
> +
> +Single pipeline data flow
> +-------------------------
> +
> +.. kernel-render:: DOT
> + :alt: Single pipeline digraph
> + :caption: Single pipeline data flow
> +
> + digraph single_ppl {
> + rankdir=LR;
> +
> + subgraph {
> + "Memory";
> + "Monitor";
> + }
> +
> + subgraph cluster_pipeline {
> + style=dashed
> + node [shape=box]
> + {
> + node [bgcolor=grey style=dashed]
> + "Scaler-0";
> + "Scaler-1";
> + "Scaler-0/1"
> + }
> +
> + node [bgcolor=grey style=filled]
> + "Layer-0" -> "Scaler-0"
> + "Layer-1" -> "Scaler-0"
> + "Layer-2" -> "Scaler-1"
> + "Layer-3" -> "Scaler-1"
> +
> + "Layer-0" -> "Compiz"
> + "Layer-1" -> "Compiz"
> + "Layer-2" -> "Compiz"
> + "Layer-3" -> "Compiz"
> + "Scaler-0" -> "Compiz"
> + "Scaler-1" -> "Compiz"
> +
> + "Compiz" -> "Scaler-0/1" -> "Wb_layer"
> + "Compiz" -> "Improc" -> "Timing Controller"
> + }
> +
> + "Wb_layer" -> "Memory"
> + "Timing Controller" -> "Monitor"
> + }
> +
> +Dual pipeline with Slave enabled
> +--------------------------------
> +
> +.. kernel-render:: DOT
> + :alt: Slave pipeline digraph
> + :caption: Slave pipeline enabled data flow
> +
> + digraph slave_ppl {
> + rankdir=LR;
> +
> + subgraph {
> + "Memory";
> + "Monitor";
> + }
> + node [shape=box]
> + subgraph cluster_pipeline_slave {
> + style=dashed
> + label="Slave Pipeline_B"
> + node [shape=box]
> + {
> + node [bgcolor=grey style=dashed]
> + "Slave.Scaler-0";
> + "Slave.Scaler-1";
> + }
> +
> + node [bgcolor=grey style=filled]
> + "Slave.Layer-0" -> "Slave.Scaler-0"
> + "Slave.Layer-1" -> "Slave.Scaler-0"
> + "Slave.Layer-2" -> "Slave.Scaler-1"
> + "Slave.Layer-3" -> "Slave.Scaler-1"
> +
> + "Slave.Layer-0" -> "Slave.Compiz"
> + "Slave.Layer-1" -> "Slave.Compiz"
> + "Slave.Layer-2" -> "Slave.Compiz"
> + "Slave.Layer-3" -> "Slave.Compiz"
> + "Slave.Scaler-0" -> "Slave.Compiz"
> + "Slave.Scaler-1" -> "Slave.Compiz"
> + }
> +
> + subgraph cluster_pipeline_master {
> + style=dashed
> + label="Master Pipeline_A"
> + node [shape=box]
> + {
> + node [bgcolor=grey style=dashed]
> + "Scaler-0";
> + "Scaler-1";
> + "Scaler-0/1"
> + }
> +
> + node [bgcolor=grey style=filled]
> + "Layer-0" -> "Scaler-0"
> + "Layer-1" -> "Scaler-0"
> + "Layer-2" -> "Scaler-1"
> + "Layer-3" -> "Scaler-1"
> +
> + "Slave.Compiz" -> "Compiz"
> + "Layer-0" -> "Compiz"
> + "Layer-1" -> "Compiz"
> + "Layer-2" -> "Compiz"
> + "Layer-3" -> "Compiz"
> + "Scaler-0" -> "Compiz"
> + "Scaler-1" -> "Compiz"
> +
> + "Compiz" -> "Scaler-0/1" -> "Wb_layer"
> + "Compiz" -> "Improc" -> "Timing Controller"
> + }
> +
> + "Wb_layer" -> "Memory"
> + "Timing Controller" -> "Monitor"
> + }
> +
> +Sub-pipelines for input and output
> +----------------------------------
> +
> +A complete display pipeline can be easily divided into three sub-pipelines
> +according to the in/out usage.
> +
> +Layer(input) pipeline
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +.. kernel-render:: DOT
> + :alt: Layer data digraph
> + :caption: Layer (input) data flow
> +
> + digraph layer_data_flow {
> + rankdir=LR;
> + node [shape=box]
> +
> + {
> + node [bgcolor=grey style=dashed]
> + "Scaler-n";
> + }
> +
> + "Layer-n" -> "Scaler-n" -> "Compiz"
> + }
> +
> +.. kernel-render:: DOT
> + :alt: Layer Split digraph
> + :caption: Layer Split pipeline
> +
> + digraph layer_data_flow {
> + rankdir=LR;
> + node [shape=box]
> +
> + "Layer-0/1" -> "Scaler-0" -> "Merger"
> + "Layer-2/3" -> "Scaler-1" -> "Merger"
> + "Merger" -> "Compiz"
> + }
> +
> +Writeback(output) pipeline
> +~~~~~~~~~~~~~~~~~~~~~~~~~~
> +.. kernel-render:: DOT
> + :alt: writeback digraph
> + :caption: Writeback(output) data flow
> +
> + digraph writeback_data_flow {
> + rankdir=LR;
> + node [shape=box]
> +
> + {
> + node [bgcolor=grey style=dashed]
> + "Scaler-n";
> + }
> +
> + "Compiz" -> "Scaler-n" -> "Wb_layer"
> + }
> +
> +.. kernel-render:: DOT
> + :alt: split writeback digraph
> + :caption: Writeback(output) Split data flow
> +
> + digraph writeback_data_flow {
> + rankdir=LR;
> + node [shape=box]
> +
> + "Compiz" -> "Splitter"
> + "Splitter" -> "Scaler-0" -> "Merger"
> + "Splitter" -> "Scaler-1" -> "Merger"
> + "Merger" -> "Wb_layer"
> + }
> +
> +Display output pipeline
> +~~~~~~~~~~~~~~~~~~~~~~~
> +.. kernel-render:: DOT
> + :alt: display digraph
> + :caption: display output data flow
> +
> + digraph single_ppl {
> + rankdir=LR;
> + node [shape=box]
> +
> + "Compiz" -> "Improc" -> "Timing Controller"
> + }
> +
> +In the following section we'll see these three sub-pipelines will be handled
> +by KMS-plane/wb_conn/crtc respectively.
> +
> +Komeda Resource abstraction
> +===========================
> +
> +struct komeda_pipeline/component
> +--------------------------------
> +
> +To fully utilize and easily access/configure the HW, the driver side also uses
> +a similar architecture: Pipeline/Component to describe the HW features and
> +capabilities, and a specific component includes two parts:
> +
> +- Data flow controlling.
> +- Specific component capabilities and features.
> +
> +So the driver defines a common header struct komeda_component to describe the
> +data flow control and all specific components are a subclass of this base
> +structure.
> +
> +.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> + :internal:
> +
> +Resource discovery and initialization
> +=====================================
> +
> +Pipeline and component are used to describe how to handle the pixel data. We
> +still need a @struct komeda_dev to describe the whole view of the device, and
> +the control-abilites of device.
> +
> +We have &komeda_dev, &komeda_pipeline, &komeda_component. Now fill devices with
> +pipelines. Since komeda is not for D71 only but also intended for later products,
> +of course we’d better share as much as possible between different products. To
> +achieve this, split the komeda device into two layers: CORE and CHIP.
> +
> +- CORE: for common features and capabilities handling.
> +- CHIP: for register programing and HW specific feature (limitation) handling.
> +
> +CORE can access CHIP by three chip function structures:
> +
> +- struct komeda_dev_funcs
> +- struct komeda_pipeline_funcs
> +- struct komeda_component_funcs
> +
> +.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> + :internal:
> +
> +Format handling
> +===============
> +
> +.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h
> + :internal:
> +.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
> + :internal:
> +
> +Attach komeda_dev to DRM-KMS
> +============================
> +
> +Komeda abstracts resources by pipeline/component, but DRM-KMS uses
> +crtc/plane/connector. One KMS-obj cannot represent only one single component,
> +since the requirements of a single KMS object cannot simply be achieved by a
> +single component, usually that needs multiple components to fit the requirement.
> +Like set mode, gamma, ctm for KMS all target on CRTC-obj, but komeda needs
> +compiz, improc and timing_ctrlr to work together to fit these requirements.
> +And a KMS-Plane may require multiple komeda resources: layer/scaler/compiz.
> +
> +So, one KMS-Obj represents a sub-pipeline of komeda resources.
> +
> +- Plane: `Layer(input) pipeline`_
> +- Wb_connector: `Writeback(output) pipeline`_
> +- Crtc: `Display output pipeline`_
> +
> +So, for komeda, we treat KMS crtc/plane/connector as users of pipeline and
> +component, and at any one time a pipeline/component only can be used by one
> +user. And pipeline/component will be treated as private object of DRM-KMS; the
> +state will be managed by drm_atomic_state as well.
> +
> +How to map plane to Layer(input) pipeline
> +-----------------------------------------
> +
> +Komeda has multiple Layer input pipelines, see:
> +- `Single pipeline data flow`_
> +- `Dual pipeline with Slave enabled`_
> +
> +The easiest way is binding a plane to a fixed Layer pipeline, but consider the
> +komeda capabilities:
> +
> +- Layer Split, See `Layer(input) pipeline`_
> +
> + Layer_Split is quite complicated feature, which splits a big image into two
> + parts and handles it by two layers and two scalers individually. But it
> + imports an edge problem or effect in the middle of the image after the split.
> + To avoid such a problem, it needs a complicated Split calculation and some
> + special configurations to the layer and scaler. We'd better hide such HW
> + related complexity to user mode.
> +
> +- Slave pipeline, See `Dual pipeline with Slave enabled`_
> +
> + Since the compiz component doesn't output alpha value, the slave pipeline
> + only can be used for bottom layers composition. The komeda driver wants to
> + hide this limitation to the user. The way to do this is to pick a suitable
> + Layer according to plane_state->zpos.
> +
> +So for komeda, the KMS-plane doesn't represent a fixed komeda layer pipeline,
> +but multiple Layers with same capabilities. Komeda will select one or more
> +Layers to fit the requirement of one KMS-plane.
> +
> +Make component/pipeline to be drm_private_obj
> +---------------------------------------------
> +
> +Add :c:type:`drm_private_obj` to :c:type:`komeda_component`, :c:type:`komeda_pipeline`
> +
> +.. code-block:: c
> +
> + struct komeda_component {
> + struct drm_private_obj obj;
> + ...
> + }
> +
> + struct komeda_pipeline {
> + struct drm_private_obj obj;
> + ...
> + }
> +
> +Tracking component_state/pipeline_state by drm_atomic_state
> +-----------------------------------------------------------
> +
> +Add :c:type:`drm_private_state` and user to :c:type:`komeda_component_state`,
> +:c:type:`komeda_pipeline_state`
> +
> +.. code-block:: c
> +
> + struct komeda_component_state {
> + struct drm_private_state obj;
> + void *binding_user;
> + ...
> + }
> +
> + struct komeda_pipeline_state {
> + struct drm_private_state obj;
> + struct drm_crtc *crtc;
> + ...
> + }
> +
> +komeda component validation
> +---------------------------
> +
> +Komeda has multiple types of components, but the process of validation are
> +similar, usually including the following steps:
> +
> +.. code-block:: c
> +
> + int komeda_xxxx_validate(struct komeda_component_xxx xxx_comp,
> + struct komeda_component_output *input_dflow,
> + struct drm_plane/crtc/connector *user,
> + struct drm_plane/crtc/connector_state, *user_state)
> + {
> + setup 1: check if component is needed, like the scaler is optional depending
> + on the user_state; if unneeded, just return, and the caller will
> + put the data flow into next stage.
> + Setup 2: check user_state with component features and capabilities to see
> + if requirements can be met; if not, return fail.
> + Setup 3: get component_state from drm_atomic_state, and try set to set
> + user to component; fail if component has been assigned to another
> + user already.
> + Setup 3: configure the component_state, like set its input component,
> + convert user_state to component specific state.
> + Setup 4: adjust the input_dflow and prepare it for the next stage.
> + }
> +
> +komeda_kms Abstraction
> +----------------------
> +
> +.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> + :internal:
> +
> +komde_kms Functions
> +-------------------
> +.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> + :internal:
> +.. kernel-doc:: drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> + :internal:
> +
> +Build komeda to be a Linux module driver
> +========================================
> +
> +Now we have two level devices:
> +
> +- komeda_dev: describes the real display hardware.
> +- komeda_kms_dev: attachs or connects komeda_dev to DRM-KMS.
> +
> +All komeda operations are supplied or operated by komeda_dev or komeda_kms_dev,
> +the module driver is only a simple wrapper to pass the Linux command
> +(probe/remove/pm) into komeda_dev or komeda_kms_dev.
> --
> 2.17.1
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 12:35:54

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 9/9] MAINTAINERS: Add maintainer for arm komeda driver

On Fri, Dec 21, 2018 at 10:01:06AM +0000, james qian wang (Arm Technology China) wrote:
> v2: Adjusted the position of KOMEDA by alphabetical order
>
> Signed-off-by: James (Qian) Wang <[email protected]>

Acked-by: Liviu Dudau <[email protected]>

Best regards,
Liviu

> ---
> MAINTAINERS | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 254b7b267731..e48c2e5fd29f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1124,6 +1124,15 @@ S: Supported
> F: drivers/gpu/drm/arm/hdlcd_*
> F: Documentation/devicetree/bindings/display/arm,hdlcd.txt
>
> +ARM KOMEDA DRM-KMS DRIVER
> +M: James (Qian) Wang <[email protected]>
> +M: Mali DP Maintainers <[email protected]>
> +S: Supported
> +F: drivers/gpu/drm/arm/display/include/
> +F: drivers/gpu/drm/arm/display/komeda/
> +F: Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> +F: Documentation/gpu/komeda-kms.rst
> +
> ARM MALI-DP DRM DRIVER
> M: Liviu Dudau <[email protected]>
> M: Brian Starkey <[email protected]>
> --
> 2.17.1
>

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-24 13:07:02

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH v3 9/9] MAINTAINERS: Add maintainer for arm komeda driver

On Mon, Dec 24, 2018 at 1:33 PM Liviu Dudau <[email protected]> wrote:
>
> On Fri, Dec 21, 2018 at 10:01:06AM +0000, james qian wang (Arm Technology China) wrote:
> > v2: Adjusted the position of KOMEDA by alphabetical order
> >
> > Signed-off-by: James (Qian) Wang <[email protected]>
>
> Acked-by: Liviu Dudau <[email protected]>
>
> Best regards,
> Liviu
>
> > ---
> > MAINTAINERS | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 254b7b267731..e48c2e5fd29f 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1124,6 +1124,15 @@ S: Supported
> > F: drivers/gpu/drm/arm/hdlcd_*
> > F: Documentation/devicetree/bindings/display/arm,hdlcd.txt
> >
> > +ARM KOMEDA DRM-KMS DRIVER
> > +M: James (Qian) Wang <[email protected]>
> > +M: Mali DP Maintainers <[email protected]>
> > +S: Supported
> > +F: drivers/gpu/drm/arm/display/include/
> > +F: drivers/gpu/drm/arm/display/komeda/
> > +F: Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> > +F: Documentation/gpu/komeda-kms.rst

Mentioning the git tree would be good. And I guess you'll do some kind
of group maintainership? Probably still good if you send out a
dedicated/topic pull request for this new driver, but from then on
it's all in the same git repo.
-Daniel

> > +
> > ARM MALI-DP DRM DRIVER
> > M: Liviu Dudau <[email protected]>
> > M: Brian Starkey <[email protected]>
> > --
> > 2.17.1
> >
>
> --
> ====================
> | I would like to |
> | fix the world, |
> | but they're not |
> | giving me the |
> \ source code! /
> ---------------
> ¯\_(ツ)_/¯



--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

2018-12-27 18:16:43

by James Qian Wang

[permalink] [raw]
Subject: Re: [PATCH v3 2/9] dt/bindings: drm/komeda: Add DT bindings for ARM display processor D71

On Mon, Dec 24, 2018 at 08:00:51PM +0800, Liviu Dudau wrote:
> On Fri, Dec 21, 2018 at 09:59:12AM +0000, james qian wang (Arm Technology China) wrote:
> > Add DT bindings documentation for the ARM display processor D71 and later
> > IPs.
> >
> > Signed-off-by: James (Qian) Wang <[email protected]>
> >
> > Changes in v3:
> > - Deleted unnecessary property: interrupt-names.
> > - Dropped 'ports' and moving 'port' up a level.
> > ---
> > .../bindings/display/arm/arm,komeda.txt | 79 +++++++++++++++++++
> > 1 file changed, 79 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> >
> > diff --git a/Documentation/devicetree/bindings/display/arm/arm,komeda.txt b/Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> > new file mode 100644
> > index 000000000000..b4e450243c7d
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> > @@ -0,0 +1,79 @@
> > +Device Tree bindings for ARM Komeda display driver
> > +
> > +Required properties:
> > +- compatible: Should be "arm,mali-d71"
> > +- reg: Physical base address and length of the registers in the system
> > +- interrupts: the interrupt line number of the device in the system
> > +- clocks: A list of phandle + clock-specifier pairs, one for each entry
> > + in 'clock-names'
> > +- clock-names: A list of clock names. It should contain:
> > + - "mclk": for the main processor clock
> > + - "pclk": for the APB interface clock
> > +- #address-cells: Must be 1
> > +- #size-cells: Must be 0
> > +
> > +Required properties for sub-node: pipeline@nq
> > +Each device contains one or two pipeline sub-nodes (at least one), each
> > +pipeline node should provide properties:
> > +- reg: Zero-indexed identifier for the pipeline
> > +- clocks: A list of phandle + clock-specifier pairs, one for each entry
> > + in 'clock-names'
> > +- clock-names: should contain:
> > + - "pxclk": pixel clock
> > + - "aclk": AXI interface clock
> > +
> > +- port: each pipeline connect to an encoder input port. The connection is
> > + modeled using the OF graph bindings specified in
> > + Documentation/devicetree/bindings/graph.txt
> > +
> > +Optional properties:
> > + - memory-region: phandle to a node describing memory (see
> > + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt)
> > + to be used for the framebuffer; if not present, the framebuffer may
> > + be located anywhere in memory.
> > +
> > +Example:
> > +/ {
> > + ...
> > +
> > + dp0: display@c00000 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + compatible = "arm,mali-d71";
> > + reg = <0xc00000 0x20000>;
> > + interrupts = <0 168 4>;
> > + clocks = <&dpu_mclk>, <&dpu_aclk>;
> > + clock-names = "mclk", "pclk";
> > +
> > + dp0_pipe0: pipeline@0 {
> > + clocks = <&fpgaosc2>, <&dpu_aclk>;
> > + clock-names = "pxclk", "aclk";
> > + reg = <0>;
> > +
> > + #address-cells = <1>;
> > + #size-cells = <0>;
>
> These are undocumented and not necessary anyway, as the pipelines will
> inherit display's attributes.

thank you, will fix it in the next version.

> > +
> > + port@0 {
> > + dp0_pipe0_out: endpoint {
> > + remote-endpoint = <&db_dvi0_in>;
> > + };
> > + };
> > + };
> > +
> > + dp0_pipe1: pipeline@1 {
> > + clocks = <&fpgaosc2>, <&dpu_aclk>;
> > + clock-names = "pxclk", "aclk";
> > + reg = <1>;
> > +
> > + #address-cells = <1>;
> > + #size-cells = <0>;
>
> same here.

OK.

>
> > +
> > + port@0 {
> > + dp0_pipe1_out: endpoint {
> > + remote-endpoint = <&db_dvi1_in>;
> > + };
> > + };
> > + };
> > + };
> > + ...
> > +};
> > --
> > 2.17.1
> >
>
> With these changes:
>
> Reviewed-by: Liviu Dudau <[email protected]>
>
> Best regards,
> Liviu
>
>
> --
> ====================
> | I would like to |
> | fix the world, |
> | but they're not |
> | giving me the |
> \ source code! /
> ---------------
> ¯\_(ツ)_/¯

2018-12-27 18:17:42

by James Qian Wang

[permalink] [raw]
Subject: Re: [PATCH v3 1/9] drm/komeda: komeda_dev/pipeline/component definition and initialzation

On Mon, Dec 24, 2018 at 07:57:41PM +0800, Liviu Dudau wrote:
> On Fri, Dec 21, 2018 at 09:58:55AM +0000, james qian wang (Arm Technology China) wrote:
> > 1. Added a brief definition of komeda_dev/pipeline/component, this change
> > didn't add the detailed component features and capabilities, which will
> > be added in the following changes.
> > 2. Corresponding resources discovery and initialzation functions.
> >
> > Signed-off-by: James (Qian) Wang <[email protected]>
> >
> > Changes in v3:
> > - Fixed style problem found by checkpatch.pl --strict.
> >
> > Changes in v2:
> > - Unified abbreviation of "pipeline" to "pipe".
> > ---
> > drivers/gpu/drm/arm/Kconfig | 2 +
> > drivers/gpu/drm/arm/Makefile | 1 +
> > drivers/gpu/drm/arm/display/Kbuild | 3 +
> > drivers/gpu/drm/arm/display/Kconfig | 14 +
> > .../drm/arm/display/include/malidp_product.h | 23 ++
> > .../drm/arm/display/include/malidp_utils.h | 16 +
> > drivers/gpu/drm/arm/display/komeda/Makefile | 11 +
> > .../gpu/drm/arm/display/komeda/komeda_dev.c | 117 ++++++
> > .../gpu/drm/arm/display/komeda/komeda_dev.h | 98 +++++
> > .../drm/arm/display/komeda/komeda_pipeline.c | 198 ++++++++++
> > .../drm/arm/display/komeda/komeda_pipeline.h | 350 ++++++++++++++++++
> > 11 files changed, 833 insertions(+)
> > create mode 100644 drivers/gpu/drm/arm/display/Kbuild
> > create mode 100644 drivers/gpu/drm/arm/display/Kconfig
> > create mode 100644 drivers/gpu/drm/arm/display/include/malidp_product.h
> > create mode 100644 drivers/gpu/drm/arm/display/include/malidp_utils.h
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/Makefile
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> >
> > diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> > index f9f7761cb2f4..a204103b3efb 100644
> > --- a/drivers/gpu/drm/arm/Kconfig
> > +++ b/drivers/gpu/drm/arm/Kconfig
> > @@ -37,4 +37,6 @@ config DRM_MALI_DISPLAY
> >
> > If compiled as a module it will be called mali-dp.
> >
> > +source "drivers/gpu/drm/arm/display/Kconfig"
> > +
> > endmenu
> > diff --git a/drivers/gpu/drm/arm/Makefile b/drivers/gpu/drm/arm/Makefile
> > index 3bf31d1a4722..120bef801fcf 100644
> > --- a/drivers/gpu/drm/arm/Makefile
> > +++ b/drivers/gpu/drm/arm/Makefile
> > @@ -3,3 +3,4 @@ obj-$(CONFIG_DRM_HDLCD) += hdlcd.o
> > mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
> > mali-dp-y += malidp_mw.o
> > obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
> > +obj-$(CONFIG_DRM_KOMEDA) += display/
> > diff --git a/drivers/gpu/drm/arm/display/Kbuild b/drivers/gpu/drm/arm/display/Kbuild
> > new file mode 100644
> > index 000000000000..382f1ca831e4
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/Kbuild
> > @@ -0,0 +1,3 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +obj-$(CONFIG_DRM_KOMEDA) += komeda/
> > diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig
> > new file mode 100644
> > index 000000000000..cec0639e3aa1
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/Kconfig
> > @@ -0,0 +1,14 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +config DRM_KOMEDA
> > + tristate "ARM Komeda display driver"
> > + depends on DRM && OF
> > + depends on COMMON_CLK
> > + select DRM_KMS_HELPER
> > + select DRM_KMS_CMA_HELPER
> > + select DRM_GEM_CMA_HELPER
> > + select VIDEOMODE_HELPERS
> > + help
> > + Choose this option if you want to compile the ARM Komeda display
> > + Processor driver. It supports the D71 variants of the hardware.
> > +
> > + If compiled as a module it will be called komeda.
> > diff --git a/drivers/gpu/drm/arm/display/include/malidp_product.h b/drivers/gpu/drm/arm/display/include/malidp_product.h
> > new file mode 100644
> > index 000000000000..b35fc5db866b
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/include/malidp_product.h
> > @@ -0,0 +1,23 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#ifndef _MALIDP_PRODUCT_H_
> > +#define _MALIDP_PRODUCT_H_
> > +
> > +/* Product identification */
> > +#define MALIDP_CORE_ID(__product, __major, __minor, __status) \
> > + ((((__product) & 0xFFFF) << 16) | (((__major) & 0xF) << 12) | \
> > + (((__minor) & 0xF) << 8) | ((__status) & 0xFF))
> > +
> > +#define MALIDP_CORE_ID_PRODUCT_ID(__core_id) ((__u32)(__core_id) >> 16)
> > +#define MALIDP_CORE_ID_MAJOR(__core_id) (((__u32)(__core_id) >> 12) & 0xF)
> > +#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 8) & 0xF)
> > +#define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF)
> > +
> > +/* Mali-display product IDs */
> > +#define MALIDP_D71_PRODUCT_ID 0x0071
> > +
> > +#endif /* _MALIDP_PRODUCT_H_ */
> > diff --git a/drivers/gpu/drm/arm/display/include/malidp_utils.h b/drivers/gpu/drm/arm/display/include/malidp_utils.h
> > new file mode 100644
> > index 000000000000..63cc47cefcf8
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/include/malidp_utils.h
> > @@ -0,0 +1,16 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#ifndef _MALIDP_UTILS_
> > +#define _MALIDP_UTILS_
> > +
> > +#define has_bit(nr, mask) (BIT(nr) & (mask))
> > +#define has_bits(bits, mask) (((bits) & (mask)) == (bits))
> > +
> > +#define dp_for_each_set_bit(bit, mask) \
> > + for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8)
>
> Given that most of our registers (and masks, by extension) are 32bit, I
> think it might be better to use 32 instead of sizeof(mask) * 8 as we
> don't want to introduce subtle bugs in the future. And I don't think you
> need the (unsigned long *) cast either.
>

Sorry, This MACRO is not only for the registers, but which is mainly used
by the Komeda-CORE for iterating pipeline components by mask (32bit), or
iterating active_inputs (16bit) of a component, maybe also will be used by
the event/irq handling, komeda event will be 64bit value every bit will
indicate a seperated event or error.

> > +
> > +#endif /* _MALIDP_UTILS_ */
> > diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> > new file mode 100644
> > index 000000000000..5b44e36509b1
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> > @@ -0,0 +1,11 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +ccflags-y := \
> > + -I$(src)/../include \
> > + -I$(src)
> > +
> > +komeda-y := \
> > + komeda_dev.o \
> > + komeda_pipeline.o \
> > +
> > +obj-$(CONFIG_DRM_KOMEDA) += komeda.o
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> > new file mode 100644
> > index 000000000000..887a17005367
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
> > @@ -0,0 +1,117 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#include <linux/platform_device.h>
> > +#include <linux/clk.h>
> > +#include <linux/io.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/version.h>
> > +#include "komeda_dev.h"
> > +
> > +struct komeda_dev *komeda_dev_create(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + const struct komeda_product_data *product;
> > + struct komeda_dev *mdev;
> > + struct resource *io_res;
> > + int err = 0;
> > +
> > + product = of_device_get_match_data(dev);
> > + if (!product)
> > + return ERR_PTR(-ENODEV);
> > +
> > + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + if (!io_res) {
> > + DRM_ERROR("No registers defined.\n");
> > + return ERR_PTR(-ENODEV);
> > + }
> > +
> > + mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);
> > + if (!mdev)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + mdev->dev = dev;
> > + mdev->reg_base = devm_ioremap_resource(dev, io_res);
> > + if (IS_ERR(mdev->reg_base)) {
> > + DRM_ERROR("Map register space failed.\n");
> > + err = PTR_ERR(mdev->reg_base);
> > + mdev->reg_base = NULL;
> > + goto err_cleanup;
> > + }
> > +
> > + mdev->pclk = devm_clk_get(dev, "pclk");
> > + if (IS_ERR(mdev->pclk)) {
> > + DRM_ERROR("Get APB clk failed.\n");
> > + err = PTR_ERR(mdev->pclk);
> > + mdev->pclk = NULL;
> > + goto err_cleanup;
> > + }
> > +
> > + /* Enable APB clock to access the registers */
> > + clk_prepare_enable(mdev->pclk);
> > +
> > + mdev->funcs = product->identify(mdev->reg_base, &mdev->chip);
> > + if (!komeda_product_match(mdev, product->product_id)) {
> > + DRM_ERROR("DT configured %x mismatch with real HW %x.\n",
> > + product->product_id,
> > + MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
> > + err = -ENODEV;
> > + goto err_cleanup;
> > + }
> > +
> > + DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
> > + MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),
> > + MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
> > + MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
> > +
> > + err = mdev->funcs->enum_resources(mdev);
> > + if (err) {
> > + DRM_ERROR("enumerate display resource failed.\n");
> > + goto err_cleanup;
> > + }
> > +
> > + return mdev;
> > +
> > +err_cleanup:
> > + komeda_dev_destroy(mdev);
> > + return ERR_PTR(err);
> > +}
> > +
> > +void komeda_dev_destroy(struct komeda_dev *mdev)
> > +{
> > + struct device *dev = mdev->dev;
> > + struct komeda_dev_funcs *funcs = mdev->funcs;
> > + int i;
> > +
> > + for (i = 0; i < mdev->n_pipelines; i++) {
> > + komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
> > + mdev->pipelines[i] = NULL;
> > + }
> > +
> > + mdev->n_pipelines = 0;
> > +
> > + if (funcs && funcs->cleanup)
> > + funcs->cleanup(mdev);
> > +
> > + if (mdev->reg_base) {
> > + devm_iounmap(dev, mdev->reg_base);
> > + mdev->reg_base = NULL;
> > + }
> > +
> > + if (mdev->mclk) {
> > + devm_clk_put(dev, mdev->mclk);
> > + mdev->mclk = NULL;
> > + }
> > +
> > + if (mdev->pclk) {
> > + clk_disable_unprepare(mdev->pclk);
> > + devm_clk_put(dev, mdev->pclk);
> > + mdev->pclk = NULL;
> > + }
> > +
> > + devm_kfree(dev, mdev);
> > +}
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.h b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> > new file mode 100644
> > index 000000000000..ad8fa160eff9
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
> > @@ -0,0 +1,98 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#ifndef _KOMEDA_DEV_H_
> > +#define _KOMEDA_DEV_H_
> > +
> > +#include <linux/device.h>
> > +#include <linux/interrupt.h>
>
> You don't need this header to be included here.

OK.

>
> > +#include "komeda_pipeline.h"
> > +#include "malidp_product.h"
> > +
> > +/* malidp device id */
> > +enum {
> > + MALI_D71 = 0,
> > +};
> > +
> > +/* pipeline DT ports */
> > +enum {
> > + KOMEDA_OF_PORT_OUTPUT = 0,
> > + KOMEDA_OF_PORT_COPROC = 1,
> > +};
> > +
> > +struct komeda_chip_info {
> > + u32 arch_id;
> > + u32 core_id;
> > + u32 core_info;
> > + u32 bus_width;
> > +};
> > +
> > +struct komeda_product_data {
> > + u32 product_id;
> > + struct komeda_dev_funcs *(*identify)(u32 __iomem *reg,
> > + struct komeda_chip_info *info);
> > +};
> > +
> > +struct komeda_dev;
> > +
> > +/**
> > + * struct komeda_dev_funcs
> > + *
> > + * Supplied by chip level and returned by the chip entry function xxx_identify,
> > + */
> > +struct komeda_dev_funcs {
> > + /**
> > + * @enum_resources:
> > + *
> > + * for CHIP to report or add pipeline and component resources to CORE
> > + */
> > + int (*enum_resources)(struct komeda_dev *mdev);
> > + /** @cleanup: call to chip to cleanup komeda_dev->chip data */
> > + void (*cleanup)(struct komeda_dev *mdev);
> > +};
> > +
> > +/**
> > + * struct komeda_dev
> > + *
> > + * Pipeline and component are used to describe how to handle the pixel data.
> > + * komeda_device is for describing the whole view of the device, and the
> > + * control-abilites of device.
> > + */
> > +struct komeda_dev {
> > + struct device *dev;
> > + u32 __iomem *reg_base;
> > +
> > + struct komeda_chip_info chip;
> > +
> > + /** @pclk: APB clock for register access */
> > + struct clk *pclk;
> > + /** @mck: HW main engine clk */
> > + struct clk *mclk;
> > +
> > + int n_pipelines;
> > + struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
> > +
> > + /** @funcs: chip funcs to access to HW */
> > + struct komeda_dev_funcs *funcs;
> > + /**
> > + * @chip_data:
> > + *
> > + * chip data will be added by &komeda_dev_funcs.enum_resources() and
> > + * destroyed by &komeda_dev_funcs.cleanup()
> > + */
> > + void *chip_data;
> > +};
> > +
> > +static inline bool
> > +komeda_product_match(struct komeda_dev *mdev, u32 target)
> > +{
> > + return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
> > +}
> > +
> > +struct komeda_dev *komeda_dev_create(struct device *dev);
> > +void komeda_dev_destroy(struct komeda_dev *mdev);
> > +
> > +#endif /*_KOMEDA_DEV_H_*/
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> > new file mode 100644
> > index 000000000000..9293598b0533
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
> > @@ -0,0 +1,198 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#include <linux/clk.h>
> > +#include "komeda_dev.h"
> > +#include "komeda_pipeline.h"
> > +
> > +/** komeda_pipeline_add - Add a pipeline to &komeda_dev */
> > +struct komeda_pipeline *
> > +komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> > + struct komeda_pipeline_funcs *funcs)
> > +{
> > + struct komeda_pipeline *pipe;
> > +
> > + if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
> > + DRM_ERROR("Exceed max support %d pipelines.\n",
> > + KOMEDA_MAX_PIPELINES);
> > + return NULL;
> > + }
> > +
> > + if (size < sizeof(*pipe)) {
> > + DRM_ERROR("Request pipeline size too small.\n");
> > + return NULL;
> > + }
> > +
> > + pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
> > + if (!pipe)
> > + return NULL;
> > +
> > + pipe->mdev = mdev;
> > + pipe->id = mdev->n_pipelines;
> > + pipe->funcs = funcs;
> > +
> > + mdev->pipelines[mdev->n_pipelines] = pipe;
> > + mdev->n_pipelines++;
> > +
> > + return pipe;
> > +}
> > +
> > +void komeda_pipeline_destroy(struct komeda_dev *mdev,
> > + struct komeda_pipeline *pipe)
> > +{
> > + struct komeda_component *c;
> > + int i;
> > +
> > + dp_for_each_set_bit(i, pipe->avail_comps) {
> > + c = komeda_pipeline_get_component(pipe, i);
> > +
>
> Unnecessary empty line
>

OK, will del it.

> > + komeda_component_destroy(mdev, c);
> > + }
> > +
> > + clk_put(pipe->pxlclk);
> > + clk_put(pipe->aclk);
> > +
> > + devm_kfree(mdev->dev, pipe);
> > +}
> > +
> > +struct komeda_component **
> > +komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
> > +{
> > + struct komeda_dev *mdev = pipe->mdev;
> > + struct komeda_pipeline *temp = NULL;
> > + struct komeda_component **pos = NULL;
> > +
> > + switch (id) {
> > + case KOMEDA_COMPONENT_LAYER0:
> > + case KOMEDA_COMPONENT_LAYER1:
> > + case KOMEDA_COMPONENT_LAYER2:
> > + case KOMEDA_COMPONENT_LAYER3:
> > + pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
> > + break;
> > + case KOMEDA_COMPONENT_WB_LAYER:
> > + pos = to_cpos(pipe->wb_layer);
> > + break;
> > + case KOMEDA_COMPONENT_COMPIZ0:
> > + case KOMEDA_COMPONENT_COMPIZ1:
> > + temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
> > + if (!temp) {
> > + DRM_ERROR("compiz-%d doesn't exist.\n", id);
> > + return NULL;
> > + }
> > + pos = to_cpos(temp->compiz);
> > + break;
> > + case KOMEDA_COMPONENT_SCALER0:
> > + case KOMEDA_COMPONENT_SCALER1:
> > + pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
> > + break;
> > + case KOMEDA_COMPONENT_IPS0:
> > + case KOMEDA_COMPONENT_IPS1:
> > + temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
> > + if (!temp) {
> > + DRM_ERROR("ips-%d doesn't exist.\n", id);
> > + return NULL;
> > + }
> > + pos = to_cpos(temp->improc);
> > + break;
> > + case KOMEDA_COMPONENT_TIMING_CTRLR:
> > + pos = to_cpos(pipe->ctrlr);
> > + break;
> > + default:
> > + pos = NULL;
> > + DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
> > + break;
> > + }
> > +
> > + return pos;
> > +}
> > +
> > +struct komeda_component *
> > +komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
> > +{
> > + struct komeda_component **pos = NULL;
> > + struct komeda_component *c = NULL;
> > +
> > + pos = komeda_pipeline_get_component_pos(pipe, id);
> > + if (pos)
> > + c = *pos;
> > +
> > + return c;
> > +}
> > +
> > +/** komeda_component_add - Add a component to &komeda_pipeline */
> > +struct komeda_component *
> > +komeda_component_add(struct komeda_pipeline *pipe,
> > + size_t comp_sz, u32 id, u32 hw_id,
> > + struct komeda_component_funcs *funcs,
> > + u8 max_active_inputs, u32 supported_inputs,
> > + u8 max_active_outputs, u32 __iomem *reg,
> > + const char *name_fmt, ...)
> > +{
> > + struct komeda_component **pos;
> > + struct komeda_component *c;
> > + int idx, *num = NULL;
> > +
> > + if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
> > + WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
> > + max_active_inputs);
> > + return NULL;
> > + }
> > +
> > + pos = komeda_pipeline_get_component_pos(pipe, id);
> > + if (!pos || !(*pos))
> > + return NULL;
> > +
> > + if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
> > + idx = id - KOMEDA_COMPONENT_LAYER0;
> > + num = &pipe->n_layers;
> > + if (idx != pipe->n_layers) {
> > + DRM_ERROR("please add Layer by id sequence.\n");
> > + return NULL;
> > + }
> > + } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) {
> > + idx = id - KOMEDA_COMPONENT_SCALER0;
> > + num = &pipe->n_scalers;
> > + if (idx != pipe->n_scalers) {
> > + DRM_ERROR("please add Scaler by id sequence.\n");
> > + return NULL;
> > + }
> > + }
> > +
> > + c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
> > + if (!c)
> > + return NULL;
> > +
> > + c->id = id;
> > + c->hw_id = hw_id;
> > + c->reg = reg;
> > + c->pipeline = pipe;
> > + c->max_active_inputs = max_active_inputs;
> > + c->max_active_outputs = max_active_outputs;
> > + c->supported_inputs = supported_inputs;
> > + c->funcs = funcs;
> > +
> > + if (name_fmt) {
> > + va_list args;
> > +
> > + va_start(args, name_fmt);
> > + vsnprintf(c->name, sizeof(c->name), name_fmt, args);
> > + va_end(args);
> > + }
> > +
> > + if (num)
> > + *num = *num + 1;
> > +
> > + pipe->avail_comps |= BIT(c->id);
> > + *pos = c;
> > +
> > + return c;
> > +}
> > +
> > +void komeda_component_destroy(struct komeda_dev *mdev,
> > + struct komeda_component *c)
> > +{
> > + devm_kfree(mdev->dev, c);
> > +}
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > new file mode 100644
> > index 000000000000..2174796d47c5
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > @@ -0,0 +1,350 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#ifndef _KOMEDA_PIPELINE_H_
> > +#define _KOMEDA_PIPELINE_H_
> > +
> > +#include <linux/types.h>
> > +#include <linux/of.h>
> > +#include <linux/bitops.h>
>
> of.h and bitops.h are unnecessary in this header file.

OK, will del these unnecessary headers.

>
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include "malidp_utils.h"
> > +
> > +#define KOMEDA_MAX_PIPELINES 2
> > +#define KOMEDA_PIPELINE_MAX_LAYERS 4
> > +#define KOMEDA_PIPELINE_MAX_SCALERS 2
> > +#define KOMEDA_COMPONENT_N_INPUTS 5
> > +
> > +/* pipeline component IDs */
> > +enum {
> > + KOMEDA_COMPONENT_LAYER0 = 0,
> > + KOMEDA_COMPONENT_LAYER1 = 1,
> > + KOMEDA_COMPONENT_LAYER2 = 2,
> > + KOMEDA_COMPONENT_LAYER3 = 3,
> > + KOMEDA_COMPONENT_WB_LAYER = 7, /* write back layer */
> > + KOMEDA_COMPONENT_SCALER0 = 8,
> > + KOMEDA_COMPONENT_SCALER1 = 9,
> > + KOMEDA_COMPONENT_SPLITTER = 12,
> > + KOMEDA_COMPONENT_MERGER = 14,
> > + KOMEDA_COMPONENT_COMPIZ0 = 16, /* compositor */
> > + KOMEDA_COMPONENT_COMPIZ1 = 17,
> > + KOMEDA_COMPONENT_IPS0 = 20, /* post image processor */
> > + KOMEDA_COMPONENT_IPS1 = 21,
> > + KOMEDA_COMPONENT_TIMING_CTRLR = 22, /* timing controller */
> > +};
> > +
> > +#define KOMEDA_PIPELINE_LAYERS (BIT(KOMEDA_COMPONENT_LAYER0) |\
> > + BIT(KOMEDA_COMPONENT_LAYER1) |\
> > + BIT(KOMEDA_COMPONENT_LAYER2) |\
> > + BIT(KOMEDA_COMPONENT_LAYER3))
> > +
> > +#define KOMEDA_PIPELINE_SCALERS (BIT(KOMEDA_COMPONENT_SCALER0) |\
> > + BIT(KOMEDA_COMPONENT_SCALER1))
> > +
> > +#define KOMEDA_PIPELINE_COMPIZS (BIT(KOMEDA_COMPONENT_COMPIZ0) |\
> > + BIT(KOMEDA_COMPONENT_COMPIZ1))
> > +
> > +#define KOMEDA_PIPELINE_IMPROCS (BIT(KOMEDA_COMPONENT_IPS0) |\
> > + BIT(KOMEDA_COMPONENT_IPS1))
> > +struct komeda_component;
> > +struct komeda_component_state;
> > +
> > +/** komeda_component_funcs - component control functions */
> > +struct komeda_component_funcs {
> > + /** @validate: optional,
> > + * component may has special requirements or limitations, this function
> > + * supply HW the ability to do the further HW specific check.
> > + */
> > + int (*validate)(struct komeda_component *c,
> > + struct komeda_component_state *state);
> > + /** @update: update is a active update */
> > + void (*update)(struct komeda_component *c,
> > + struct komeda_component_state *state);
> > + /** @disable: disable component */
> > + void (*disable)(struct komeda_component *c);
> > + /** @dump_register: Optional, dump registers to seq_file */
> > + void (*dump_register)(struct komeda_component *c, struct seq_file *seq);
> > +};
> > +
> > +/**
> > + * struct komeda_component
> > + *
> > + * struct komeda_component describe the data flow capabilities for how to link a
> > + * component into the display pipeline.
> > + * all specified components are subclass of this structure.
> > + */
> > +struct komeda_component {
> > + /** @obj: treat component as private obj */
> > + struct drm_private_obj obj;
> > + /** @pipeline: the komeda pipeline this component belongs to */
> > + struct komeda_pipeline *pipeline;
> > + /** @name: component name */
> > + char name[32];
> > + /**
> > + * @reg:
> > + * component register base,
> > + * which is initialized by chip and used by chip only
> > + */
> > + u32 __iomem *reg;
> > + /** @id: component id */
> > + u32 id;
> > + /** @hw_ic: component hw id,
> > + * which is initialized by chip and used by chip only
> > + */
> > + u32 hw_id;
> > +
> > + /**
> > + * @max_active_inputs:
> > + * @max_active_outpus:
> > + *
> > + * maximum number of inputs/outputs that can be active in the same time
> > + * Note:
> > + * the number isn't the bit number of @supported_inputs or
> > + * @supported_outputs, but may be less than it, since component may not
> > + * support enabling all @supported_inputs/outputs at the same time.
> > + */
> > + u8 max_active_inputs;
> > + u8 max_active_outputs;
> > + /**
> > + * @supported_inputs:
> > + * @supported_outputs:
> > + *
> > + * bitmask of BIT(component->id) for the supported inputs/outputs
> > + * describes the possibilities of how a component is linked into a
> > + * pipeline.
> > + */
> > + u32 supported_inputs;
> > + u32 supported_outputs;
> > +
> > + /**
> > + * @funcs: chip functions to access HW
> > + */
> > + struct komeda_component_funcs *funcs;
> > +};
> > +
> > +/**
> > + * struct komeda_component_output
> > + *
> > + * a component has multiple outputs, if want to know where the data
> > + * comes from, only know the component is not enough, we still need to know
> > + * its output port
> > + */
> > +struct komeda_component_output {
> > + /** @component: indicate which component the data comes from */
> > + struct komeda_component *component;
> > + /** @output_port:
> > + * the output port of the &komeda_component_output.component
> > + */
> > + u8 output_port;
> > +};
> > +
> > +/**
> > + * struct komeda_component_state
> > + *
> > + * component_state is the data flow configuration of the component, and it's
> > + * the superclass of all specific component_state like @komeda_layer_state,
> > + * @komeda_scaler_state
> > + */
> > +struct komeda_component_state {
> > + /** @obj: tracking component_state by drm_atomic_state */
> > + struct drm_private_state obj;
> > + struct komeda_component *component;
> > + /**
> > + * @binding_user:
> > + * currently bound user, the user can be crtc/plane/wb_conn, which is
> > + * valid decided by @component and @inputs
> > + *
> > + * - Layer: its user always is plane.
> > + * - compiz/improc/timing_ctrlr: the user is crtc.
> > + * - wb_layer: wb_conn;
> > + * - scaler: plane when input is layer, wb_conn if input is compiz.
> > + */
> > + union {
> > + struct drm_crtc *crtc;
> > + struct drm_plane *plane;
> > + struct drm_connector *wb_conn;
> > + void *binding_user;
> > + };
> > + /**
> > + * @active_inputs:
> > + *
> > + * active_inputs is bitmask of @inputs index
> > + *
> > + * - active_inputs = changed_active_inputs + unchanged_active_inputs
> > + * - affected_inputs = old->active_inputs + new->active_inputs;
> > + * - disabling_inputs = affected_inputs ^ active_inputs;
> > + * - changed_inputs = disabling_inputs + changed_active_inputs;
> > + *
> > + * NOTE:
> > + * changed_inputs doesn't include all active_input but only
> > + * @changed_active_inputs, and this bitmask can be used in chip
> > + * level for dirty update.
> > + */
> > + u16 active_inputs;
> > + u16 changed_active_inputs;
> > + u16 affected_inputs;
> > + /**
> > + * @inputs:
> > + *
> > + * the specific inputs[i] only valid on BIT(i) has been set in
> > + * @active_inputs, if not the inputs[i] is undefined.
> > + */
> > + struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];
> > +};
> > +
> > +static inline u16 component_disabling_inputs(struct komeda_component_state *st)
> > +{
> > + return st->affected_inputs ^ st->active_inputs;
> > +}
> > +
> > +static inline u16 component_changed_inputs(struct komeda_component_state *st)
> > +{
> > + return component_disabling_inputs(st) | st->changed_active_inputs;
> > +}
> > +
> > +#define to_comp(__c) (((__c) == NULL) ? NULL : &((__c)->base))
> > +#define to_cpos(__c) ((struct komeda_component **)&(__c))
> > +
> > +/* these structures are going to be filled in in uture patches */
> > +struct komeda_layer {
> > + struct komeda_component base;
> > + /* layer specific features and caps */
> > +};
> > +
> > +struct komeda_layer_state {
> > + struct komeda_component_state base;
> > + /* layer specific configuration state */
> > +};
> > +
> > +struct komeda_compiz {
> > + struct komeda_component base;
> > + /* compiz specific features and caps */
> > +};
> > +
> > +struct komeda_compiz_state {
> > + struct komeda_component_state base;
> > + /* compiz specific configuration state */
> > +};
> > +
> > +struct komeda_scaler {
> > + struct komeda_component base;
> > + /* scaler features and caps */
> > +};
> > +
> > +struct komeda_scaler_state {
> > + struct komeda_component_state base;
> > +};
> > +
> > +struct komeda_improc {
> > + struct komeda_component base;
> > +};
> > +
> > +struct komeda_improc_state {
> > + struct komeda_component_state base;
> > +};
> > +
> > +/* display timing controller */
> > +struct komeda_timing_ctrlr {
> > + struct komeda_component base;
> > +};
> > +
> > +struct komeda_timing_ctrlr_state {
> > + struct komeda_component_state base;
> > +};
> > +
> > +/** struct komeda_pipeline_funcs */
> > +struct komeda_pipeline_funcs {
> > + /* dump_register: Optional, dump registers to seq_file */
> > + void (*dump_register)(struct komeda_pipeline *pipe,
> > + struct seq_file *sf);
> > +};
> > +
> > +/**
> > + * struct komeda_pipeline
> > + *
> > + * Represent a complete display pipeline and hold all functional components.
> > + */
> > +struct komeda_pipeline {
> > + /** @obj: link pipeline as private obj of drm_atomic_state */
> > + struct drm_private_obj obj;
> > + /** @mdev: the parent komeda_dev */
> > + struct komeda_dev *mdev;
> > + /** @pxlclk: pixel clock */
> > + struct clk *pxlclk;
> > + /** @aclk: AXI clock */
> > + struct clk *aclk;
> > + /** @id: pipeline id */
> > + int id;
> > + /** @avail_comps: available components mask of pipeline */
> > + u32 avail_comps;
> > + int n_layers;
> > + struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
> > + int n_scalers;
> > + struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
> > + struct komeda_compiz *compiz;
> > + struct komeda_layer *wb_layer;
> > + struct komeda_improc *improc;
> > + struct komeda_timing_ctrlr *ctrlr;
> > + struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
> > +};
> > +
> > +/**
> > + * struct komeda_pipeline_state
> > + *
> > + * NOTE:
> > + * Unlike the pipeline, pipeline_state doesn’t gather any component_state
> > + * into it. It because all component will be managed by drm_atomic_state.
> > + */
> > +struct komeda_pipeline_state {
> > + /** @obj: tracking pipeline_state by drm_atomic_state */
> > + struct drm_private_state obj;
> > + struct komeda_pipeline *pipe;
> > + /** @crtc: currently bound crtc */
> > + struct drm_crtc *crtc;
> > + /**
> > + * @active_comps:
> > + *
> > + * bitmask - BIT(component->id) of active components
> > + */
> > + u32 active_comps;
> > +};
> > +
> > +#define to_layer(c) container_of(c, struct komeda_layer, base)
> > +#define to_compiz(c) container_of(c, struct komeda_compiz, base)
> > +#define to_scaler(c) container_of(c, struct komeda_scaler, base)
> > +#define to_improc(c) container_of(c, struct komeda_improc, base)
> > +#define to_ctrlr(c) container_of(c, struct komeda_timing_ctrlr, base)
> > +
> > +#define to_layer_st(c) container_of(c, struct komeda_layer_state, base)
> > +#define to_compiz_st(c) container_of(c, struct komeda_compiz_state, base)
> > +#define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
> > +#define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
> > +#define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
> > +
> > +/* pipeline APIs */
> > +struct komeda_pipeline *
> > +komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> > + struct komeda_pipeline_funcs *funcs);
> > +void komeda_pipeline_destroy(struct komeda_dev *mdev,
> > + struct komeda_pipeline *pipe);
> > +
> > +struct komeda_component *
> > +komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
> > +
> > +/* component APIs */
> > +struct komeda_component *
> > +komeda_component_add(struct komeda_pipeline *pipe,
> > + size_t comp_sz, u32 id, u32 hw_id,
> > + struct komeda_component_funcs *funcs,
> > + u8 max_active_inputs, u32 supported_inputs,
> > + u8 max_active_outputs, u32 __iomem *reg,
> > + const char *name_fmt, ...);
> > +
> > +void komeda_component_destroy(struct komeda_dev *mdev,
> > + struct komeda_component *c);
> > +
> > +#endif /* _KOMEDA_PIPELINE_H_*/
> > --
> > 2.17.1
> >
>
> With these small changes:
>
> Reviewed-by: Liviu Dudau <[email protected]>
>
> Best regards,
> Liviu
>
>
> --
> ====================
> | I would like to |
> | fix the world, |
> | but they're not |
> | giving me the |
> \ source code! /
> ---------------
> ¯\_(ツ)_/¯

2018-12-27 18:17:44

by James Qian Wang

[permalink] [raw]
Subject: Re: [PATCH v3 7/9] drm/komeda: Attach komeda_dev to DRM-KMS

On Mon, Dec 24, 2018 at 08:32:14PM +0800, Liviu Dudau wrote:
> On Fri, Dec 21, 2018 at 10:00:33AM +0000, james qian wang (Arm Technology China) wrote:
> > Add komeda_kms abstracton to attach komeda_dev to DRM-KMS
> > CRTC: according to the komeda_pipeline
> > PLANE: according to komeda_layer (layer input pipeline)
> > PRIVATE_OBJS: komeda_pipeline/component all will be treat as private_objs
> >
> > komeda_kms is for connecting DRM-KMS and komeda_dev, like reporting the
> > kms object properties according to the komeda_dev, and pass/convert KMS's
> > requirement to komeda_dev.
> >
> > Changes in v3:
> > - Fixed style problem found by checkpatch.pl --strict.
> >
> > Changes in v2:
> > - Unified abbreviation of "pipeline" to "pipe".
> >
> > Signed-off-by: James (Qian) Wang <[email protected]>
> > ---
> > drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
> > .../gpu/drm/arm/display/komeda/komeda_crtc.c | 106 +++++++++++
> > .../gpu/drm/arm/display/komeda/komeda_drv.c | 19 +-
> > .../gpu/drm/arm/display/komeda/komeda_kms.c | 169 ++++++++++++++++++
> > .../gpu/drm/arm/display/komeda/komeda_kms.h | 113 ++++++++++++
> > .../drm/arm/display/komeda/komeda_pipeline.h | 3 +
> > .../gpu/drm/arm/display/komeda/komeda_plane.c | 109 +++++++++++
> > .../arm/display/komeda/komeda_private_obj.c | 88 +++++++++
> > 8 files changed, 608 insertions(+), 5 deletions(-)
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> >
> > diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> > index 25beae900ed2..1b875e5dc0f6 100644
> > --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> > +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> > @@ -9,7 +9,11 @@ komeda-y := \
> > komeda_dev.o \
> > komeda_format_caps.o \
> > komeda_pipeline.o \
> > - komeda_framebuffer.o
> > + komeda_framebuffer.o \
> > + komeda_kms.o \
> > + komeda_crtc.o \
> > + komeda_plane.o \
> > + komeda_private_obj.o
> >
> > komeda-y += \
> > d71/d71_dev.o
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > new file mode 100644
> > index 000000000000..5bb5a55f6b31
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > @@ -0,0 +1,106 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#include <linux/clk.h>
> > +#include <linux/spinlock.h>
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_plane_helper.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <linux/pm_runtime.h>
> > +#include "komeda_dev.h"
> > +#include "komeda_kms.h"
> > +
> > +struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
> > +};
> > +
> > +static const struct drm_crtc_funcs komeda_crtc_funcs = {
> > +};
> > +
> > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
> > + struct komeda_dev *mdev)
> > +{
> > + struct komeda_crtc *crtc;
> > + struct komeda_pipeline *master;
> > + char str[16];
> > + int i;
> > +
> > + kms->n_crtcs = 0;
> > +
> > + for (i = 0; i < mdev->n_pipelines; i++) {
> > + crtc = &kms->crtcs[kms->n_crtcs];
> > + master = mdev->pipelines[i];
> > +
> > + crtc->master = master;
> > + crtc->slave = NULL;
> > +
> > + if (crtc->slave)
> > + sprintf(str, "pipe-%d", crtc->slave->id);
> > + else
> > + sprintf(str, "None");
> > +
> > + DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
> > + kms->n_crtcs, master->id, str,
> > + master->of_output_dev ?
> > + master->of_output_dev->full_name : "None");
> > +
> > + kms->n_crtcs++;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static struct drm_plane *
> > +get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
> > +{
> > + struct komeda_plane *kplane;
> > + struct drm_plane *plane;
> > +
> > + drm_for_each_plane(plane, &kms->base) {
> > + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> > + continue;
> > +
> > + kplane = to_kplane(plane);
> > + /* only master can be primary */
> > + if (kplane->layer->base.pipeline == crtc->master)
> > + return plane;
> > + }
> > +
> > + return NULL;
> > +}
> > +
> > +static int komeda_crtc_add(struct komeda_kms_dev *kms,
> > + struct komeda_crtc *kcrtc)
> > +{
> > + struct drm_crtc *crtc = &kcrtc->base;
> > + int err;
> > +
> > + err = drm_crtc_init_with_planes(&kms->base, crtc,
> > + get_crtc_primary(kms, kcrtc), NULL,
> > + &komeda_crtc_funcs, NULL);
> > + if (err)
> > + return err;
> > +
> > + drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
> > + drm_crtc_vblank_reset(crtc);
> > +
> > + crtc->port = kcrtc->master->of_output_port;
> > +
> > + return 0;
> > +}
> > +
> > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > +{
> > + int i, err;
> > +
> > + for (i = 0; i < kms->n_crtcs; i++) {
> > + err = komeda_crtc_add(kms, &kms->crtcs[i]);
> > + if (err)
> > + return err;
> > + }
> > +
> > + return 0;
> > +}
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > index a2657b3d09d7..4b8ce717a71c 100644
> > --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > @@ -13,18 +13,21 @@
> >
> > struct komeda_drv {
> > struct komeda_dev *mdev;
> > + struct komeda_kms_dev *kms;
> > };
> >
> > static void komeda_unbind(struct device *dev)
> > {
> > struct komeda_drv *mdrv = dev_get_drvdata(dev);
> >
> > - dev_set_drvdata(dev, NULL);
> > -
>
> I would argue that you're fixing a bug here that was introduced in an
> earlier patch, and that you should fix that patch rather than this
> change.

Sorry, you're right, will fix it the next version.

> > if (!mdrv)
> > return;
> >
> > + komeda_kms_detach(mdrv->kms);
> > +
> > komeda_dev_destroy(mdrv->mdev);
> > +
> > + dev_set_drvdata(dev, NULL);
> > kfree(mdrv);
> > }
> >
> > @@ -33,7 +36,7 @@ static int komeda_bind(struct device *dev)
> > struct komeda_drv *mdrv;
> > int err;
> >
> > - mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
> > + mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
> > if (!mdrv)
> > return -ENOMEM;
> >
> > @@ -45,10 +48,18 @@ static int komeda_bind(struct device *dev)
> >
> > dev_set_drvdata(dev, mdrv);
> >
> > + mdrv->kms = komeda_kms_attach(mdrv->mdev);
> > + if (IS_ERR(mdrv->kms)) {
> > + err = PTR_ERR(mdrv->kms);
>
> does mdrv->kms needs to be set to NULL here?
>
> > + goto destroy_mdev;
> > + }
> > +
> > return 0;
> >
> > +destroy_mdev:
> > + komeda_dev_destroy(mdrv->mdev);
> > free_mdrv:
> > - kfree(mdrv);
> > + devm_kfree(dev, mdrv);
> > return err;
> > }
> >
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > new file mode 100644
> > index 000000000000..fd48360ca524
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > @@ -0,0 +1,169 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#include <linux/component.h>
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_gem_framebuffer_helper.h>
> > +#include <drm/drm_gem_cma_helper.h>
> > +#include <drm/drm_fb_helper.h>
> > +#include <linux/interrupt.h>
> > +#include "komeda_dev.h"
> > +#include "komeda_kms.h"
> > +#include "komeda_framebuffer.h"
> > +
> > +DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
> > +
> > +static int komeda_gem_cma_dumb_create(struct drm_file *file,
> > + struct drm_device *dev,
> > + struct drm_mode_create_dumb *args)
> > +{
> > + u32 alignment = 16; /* TODO get alignment from dev */
> > +
> > + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
> > + alignment);
> > +
> > + return drm_gem_cma_dumb_create_internal(file, dev, args);
> > +}
> > +
> > +static struct drm_driver komeda_kms_driver = {
> > + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
> > + DRIVER_PRIME,
> > + .lastclose = drm_fb_helper_lastclose,
> > + .gem_free_object_unlocked = drm_gem_cma_free_object,
> > + .gem_vm_ops = &drm_gem_cma_vm_ops,
> > + .dumb_create = komeda_gem_cma_dumb_create,
> > + .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> > + .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> > + .gem_prime_export = drm_gem_prime_export,
> > + .gem_prime_import = drm_gem_prime_import,
> > + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> > + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> > + .gem_prime_vmap = drm_gem_cma_prime_vmap,
> > + .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> > + .gem_prime_mmap = drm_gem_cma_prime_mmap,
> > + .fops = &komeda_cma_fops,
> > + .name = "komeda",
> > + .desc = "ARM Mali Komeda Display Processor driver",
> > + .date = "20181101",
> > + .major = 0,
> > + .minor = 1,
> > +};
> > +
> > +static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
> > +{
> > + struct drm_device *dev = old_state->dev;
> > +
> > + drm_atomic_helper_commit_modeset_disables(dev, old_state);
> > +
> > + drm_atomic_helper_commit_planes(dev, old_state, 0);
> > +
> > + drm_atomic_helper_commit_modeset_enables(dev, old_state);
>
> Mainline has also introduced the drm_atomic_helper_fake_vblank(old_state) call
> to help with writebacks on CRTCs that might be otherwise disabled. Do we need
> to have it here too?

we don't need it, since D71 HW still sends flip interrupt even on oneshot
writeback mode.

> > +
> > + drm_atomic_helper_wait_for_flip_done(dev, old_state);
> > +
> > + drm_atomic_helper_commit_hw_done(old_state);
> > +
> > + drm_atomic_helper_cleanup_planes(dev, old_state);
> > +}
> > +
> > +static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
> > + .atomic_commit_tail = komeda_kms_commit_tail,
> > +};
> > +
> > +static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
> > + .fb_create = komeda_fb_create,
> > + .atomic_check = NULL,/*komeda_kms_check*/
>
> I would argue that you should at least use drm_atomic_helper_check here,
> rather than set it to NULL, even if later you will replace it with a
> komeda function.

OK.

>
> > + .atomic_commit = drm_atomic_helper_commit,
> > +};
> > +
> > +static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
> > + struct komeda_dev *mdev)
> > +{
> > + struct drm_mode_config *config = &kms->base.mode_config;
> > +
> > + drm_mode_config_init(&kms->base);
> > +
> > + komeda_kms_setup_crtcs(kms, mdev);
> > +
> > + /* Get value from dev */
> > + config->min_width = 0;
> > + config->min_height = 0;
> > + config->max_width = 4096;
> > + config->max_height = 4096;
> > + config->allow_fb_modifiers = true;
> > +
> > + config->funcs = &komeda_mode_config_funcs;
> > + config->helper_private = &komeda_mode_config_helpers;
> > +}
> > +
> > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
> > +{
> > + struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
> > + struct drm_device *drm;
> > + int err;
> > +
> > + if (!kms)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + drm = &kms->base;
> > + err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
> > + if (err)
> > + goto free_kms;
> > +
> > + drm->dev_private = mdev;
> > +
> > + komeda_kms_mode_config_init(kms, mdev);
> > +
> > + err = komeda_kms_add_private_objs(kms, mdev);
> > + if (err)
> > + goto cleanup_mode_config;
> > +
> > + err = komeda_kms_add_planes(kms, mdev);
> > + if (err)
> > + goto cleanup_mode_config;
> > +
> > + err = drm_vblank_init(drm, kms->n_crtcs);
> > + if (err)
> > + goto cleanup_mode_config;
> > +
> > + err = komeda_kms_add_crtcs(kms, mdev);
> > + if (err)
> > + goto cleanup_mode_config;
> > +
> > + err = component_bind_all(mdev->dev, kms);
> > + if (err)
> > + goto cleanup_mode_config;
> > +
> > + drm_mode_config_reset(drm);
> > +
> > + err = drm_dev_register(drm, 0);
> > + if (err)
> > + goto uninstall_irq;
> > +
> > + return kms;
> > +
> > +uninstall_irq:
> > + drm_irq_uninstall(drm);
> > +cleanup_mode_config:
> > + drm_mode_config_cleanup(drm);
> > +free_kms:
> > + kfree(kms);
> > + return ERR_PTR(err);
> > +}
> > +
> > +void komeda_kms_detach(struct komeda_kms_dev *kms)
> > +{
> > + struct drm_device *drm = &kms->base;
> > + struct komeda_dev *mdev = drm->dev_private;
> > +
> > + drm_dev_unregister(drm);
> > + component_unbind_all(mdev->dev, drm);
> > + komeda_kms_cleanup_private_objs(mdev);
> > + drm_mode_config_cleanup(drm);
> > + drm->dev_private = NULL;
> > + drm_dev_put(drm);
> > +}
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > new file mode 100644
> > index 000000000000..f13666004a42
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > @@ -0,0 +1,113 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#ifndef _KOMEDA_KMS_H_
> > +#define _KOMEDA_KMS_H_
> > +
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <drm/drm_writeback.h>
> > +
> > +/** struct komeda_plane - komeda instance of drm_plane */
> > +struct komeda_plane {
> > + /** @base: &drm_plane */
> > + struct drm_plane base;
> > + /**
> > + * @layer:
> > + *
> > + * represents available layer input pipelines for this plane.
> > + *
> > + * NOTE:
> > + * the layer is not for a specific Layer, but indicate a group of
> > + * Layers with same capabilities.
> > + */
> > + struct komeda_layer *layer;
> > +};
> > +
> > +/**
> > + * struct komeda_plane_state
> > + *
> > + * The plane_state can be split into two data flow (left/right) and handled
> > + * by two layers &komeda_plane.layer and &komeda_plane.layer.right
> > + */
> > +struct komeda_plane_state {
> > + /** @base: &drm_plane_state */
> > + struct drm_plane_state base;
> > +
> > + /* private properties */
> > +};
> > +
> > +/**
> > + * struct komeda_wb_connector
> > + */
> > +struct komeda_wb_connector {
> > + /** @base: &drm_writeback_connector */
> > + struct drm_writeback_connector base;
> > +
> > + /** @wb_layer: represents associated writeback pipeline of komeda */
> > + struct komeda_layer *wb_layer;
> > +};
> > +
> > +/**
> > + * struct komeda_crtc
> > + */
> > +struct komeda_crtc {
> > + /** @base: &drm_crtc */
> > + struct drm_crtc base;
> > + /** @master: only master has display output */
> > + struct komeda_pipeline *master;
> > + /**
> > + * @slave: optional
> > + *
> > + * Doesn't have its own display output, the handled data flow will
> > + * merge into the master.
> > + */
> > + struct komeda_pipeline *slave;
> > +};
> > +
> > +/** struct komeda_crtc_state */
> > +struct komeda_crtc_state {
> > + /** @base: &drm_crtc_state */
> > + struct drm_crtc_state base;
> > +
> > + /* private properties */
> > +
> > + /* computed state which are used by validate/check */
> > + u32 affected_pipes;
> > + u32 active_pipes;
> > +};
> > +
> > +/** struct komeda_kms_dev - for gather KMS related things */
> > +struct komeda_kms_dev {
> > + /** @base: &drm_device */
> > + struct drm_device base;
> > +
> > + /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
> > + int n_crtcs;
> > + /** @crtcs: crtcs list */
> > + struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
> > +};
> > +
> > +#define to_kplane(p) container_of(p, struct komeda_plane, base)
> > +#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
> > +#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
> > +#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
> > +#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
> > +#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
> > +
> > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > +
> > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > + struct komeda_dev *mdev);
> > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
> > +
> > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
> > +void komeda_kms_detach(struct komeda_kms_dev *kms);
> > +
> > +#endif /*_KOMEDA_KMS_H_*/
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > index 2d68ffeae25d..114129d96851 100644
> > --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > @@ -333,6 +333,9 @@ struct komeda_pipeline_state {
> > #define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
> > #define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
> >
> > +#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
> > +#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
> > +
> > /* pipeline APIs */
> > struct komeda_pipeline *
> > komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > new file mode 100644
> > index 000000000000..0a4953a9a909
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > @@ -0,0 +1,109 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#include <drm/drm_atomic.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_plane_helper.h>
> > +#include "komeda_dev.h"
> > +#include "komeda_kms.h"
> > +
> > +static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
> > +};
> > +
> > +static void komeda_plane_destroy(struct drm_plane *plane)
> > +{
> > + drm_plane_cleanup(plane);
> > +
> > + kfree(to_kplane(plane));
> > +}
> > +
> > +static const struct drm_plane_funcs komeda_plane_funcs = {
> > +};
> > +
> > +/* for komeda, which is pipeline can be share between crtcs */
> > +static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
> > + struct komeda_pipeline *pipe)
> > +{
> > + struct komeda_crtc *crtc;
> > + u32 possible_crtcs = 0;
> > + int i;
> > +
> > + for (i = 0; i < kms->n_crtcs; i++) {
> > + crtc = &kms->crtcs[i];
> > +
> > + if ((pipe == crtc->master) || (pipe == crtc->slave))
> > + possible_crtcs |= BIT(i);
> > + }
> > +
> > + return possible_crtcs;
> > +}
> > +
> > +/* use Layer0 as primary */
> > +static u32 get_plane_type(struct komeda_kms_dev *kms,
> > + struct komeda_component *c)
> > +{
> > + bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
> > +
> > + return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
> > +}
> > +
> > +static int komeda_plane_add(struct komeda_kms_dev *kms,
> > + struct komeda_layer *layer)
> > +{
> > + struct komeda_dev *mdev = kms->base.dev_private;
> > + struct komeda_component *c = &layer->base;
> > + struct komeda_plane *kplane;
> > + struct drm_plane *plane;
> > + u32 *formats, n_formats = 0;
> > + int err;
> > +
> > + kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
> > + if (!kplane)
> > + return -ENOMEM;
> > +
> > + plane = &kplane->base;
> > + kplane->layer = layer;
> > +
> > + formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
> > + layer->layer_type, &n_formats);
> > +
> > + err = drm_universal_plane_init(&kms->base, plane,
> > + get_possible_crtcs(kms, c->pipeline),
> > + &komeda_plane_funcs,
> > + formats, n_formats, NULL,
> > + get_plane_type(kms, c),
> > + "%s", c->name);
> > +
> > + komeda_put_fourcc_list(formats);
> > +
> > + if (err)
> > + goto cleanup;
> > +
> > + drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
> > +
> > + return 0;
> > +cleanup:
> > + komeda_plane_destroy(plane);
> > + return err;
> > +}
> > +
> > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > +{
> > + struct komeda_pipeline *pipe;
> > + int i, j, err;
> > +
> > + for (i = 0; i < mdev->n_pipelines; i++) {
> > + pipe = mdev->pipelines[i];
> > +
> > + for (j = 0; j < pipe->n_layers; j++) {
> > + err = komeda_plane_add(kms, pipe->layers[j]);
> > + if (err)
> > + return err;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > new file mode 100644
> > index 000000000000..9edfd6ab0c12
> > --- /dev/null
> > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > @@ -0,0 +1,88 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > + * Author: James.Qian.Wang <[email protected]>
> > + *
> > + */
> > +#include "komeda_dev.h"
> > +#include "komeda_kms.h"
> > +
> > +static struct drm_private_state *
> > +komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
> > +{
> > + struct komeda_pipeline_state *st;
> > +
> > + st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
> > + if (!st)
> > + return NULL;
> > +
> > + st->active_comps = 0;
> > +
> > + __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
> > +
> > + return &st->obj;
> > +}
> > +
> > +static void
> > +komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
> > + struct drm_private_state *state)
> > +{
> > + kfree(priv_to_pipe_st(state));
> > +}
> > +
> > +static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
> > + .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
> > + .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
> > +};
> > +
> > +static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
> > + struct komeda_pipeline *pipe)
> > +{
> > + struct komeda_pipeline_state *st;
> > +
> > + st = kzalloc(sizeof(*st), GFP_KERNEL);
> > + if (!st)
> > + return -ENOMEM;
> > +
> > + st->pipe = pipe;
> > + drm_atomic_private_obj_init(&pipe->obj, &st->obj,
> > + &komeda_pipeline_obj_funcs);
> > +
> > + return 0;
> > +}
> > +
> > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > + struct komeda_dev *mdev)
> > +{
> > + struct komeda_pipeline *pipe;
> > + int i, err;
> > +
> > + for (i = 0; i < mdev->n_pipelines; i++) {
> > + pipe = mdev->pipelines[i];
> > +
> > + err = komeda_pipeline_obj_add(kms, pipe);
> > + if (err)
> > + return err;
> > +
> > + /* Add component */
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
> > +{
> > + struct komeda_pipeline *pipe;
> > + struct komeda_component *c;
> > + int i, id;
> > +
> > + for (i = 0; i < mdev->n_pipelines; i++) {
> > + pipe = mdev->pipelines[i];
> > + dp_for_each_set_bit(id, pipe->avail_comps) {
> > + c = komeda_pipeline_get_component(pipe, id);
> > +
> > + drm_atomic_private_obj_fini(&c->obj);
> > + }
> > + drm_atomic_private_obj_fini(&pipe->obj);
> > + }
> > +}
> > --
> > 2.17.1
> >
>
> Reviewed-by: Liviu Dudau <[email protected]>
>
> Best regards,
> Liviu
>
>
> --
> ====================
> | I would like to |
> | fix the world, |
> | but they're not |
> | giving me the |
> \ source code! /
> ---------------
> ¯\_(ツ)_/¯

2018-12-28 00:38:26

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 7/9] drm/komeda: Attach komeda_dev to DRM-KMS

On Thu, Dec 27, 2018 at 07:09:07AM +0000, james qian wang (Arm Technology China) wrote:
> On Mon, Dec 24, 2018 at 08:32:14PM +0800, Liviu Dudau wrote:
> > On Fri, Dec 21, 2018 at 10:00:33AM +0000, james qian wang (Arm Technology China) wrote:
> > > Add komeda_kms abstracton to attach komeda_dev to DRM-KMS
> > > CRTC: according to the komeda_pipeline
> > > PLANE: according to komeda_layer (layer input pipeline)
> > > PRIVATE_OBJS: komeda_pipeline/component all will be treat as private_objs
> > >
> > > komeda_kms is for connecting DRM-KMS and komeda_dev, like reporting the
> > > kms object properties according to the komeda_dev, and pass/convert KMS's
> > > requirement to komeda_dev.
> > >
> > > Changes in v3:
> > > - Fixed style problem found by checkpatch.pl --strict.
> > >
> > > Changes in v2:
> > > - Unified abbreviation of "pipeline" to "pipe".
> > >
> > > Signed-off-by: James (Qian) Wang <[email protected]>
> > > ---
> > > drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
> > > .../gpu/drm/arm/display/komeda/komeda_crtc.c | 106 +++++++++++
> > > .../gpu/drm/arm/display/komeda/komeda_drv.c | 19 +-
> > > .../gpu/drm/arm/display/komeda/komeda_kms.c | 169 ++++++++++++++++++
> > > .../gpu/drm/arm/display/komeda/komeda_kms.h | 113 ++++++++++++
> > > .../drm/arm/display/komeda/komeda_pipeline.h | 3 +
> > > .../gpu/drm/arm/display/komeda/komeda_plane.c | 109 +++++++++++
> > > .../arm/display/komeda/komeda_private_obj.c | 88 +++++++++
> > > 8 files changed, 608 insertions(+), 5 deletions(-)
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > >
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> > > index 25beae900ed2..1b875e5dc0f6 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> > > +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> > > @@ -9,7 +9,11 @@ komeda-y := \
> > > komeda_dev.o \
> > > komeda_format_caps.o \
> > > komeda_pipeline.o \
> > > - komeda_framebuffer.o
> > > + komeda_framebuffer.o \
> > > + komeda_kms.o \
> > > + komeda_crtc.o \
> > > + komeda_plane.o \
> > > + komeda_private_obj.o
> > >
> > > komeda-y += \
> > > d71/d71_dev.o
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > new file mode 100644
> > > index 000000000000..5bb5a55f6b31
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > @@ -0,0 +1,106 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include <linux/clk.h>
> > > +#include <linux/spinlock.h>
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_plane_helper.h>
> > > +#include <drm/drm_crtc_helper.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +
> > > +struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
> > > +};
> > > +
> > > +static const struct drm_crtc_funcs komeda_crtc_funcs = {
> > > +};
> > > +
> > > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_crtc *crtc;
> > > + struct komeda_pipeline *master;
> > > + char str[16];
> > > + int i;
> > > +
> > > + kms->n_crtcs = 0;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + crtc = &kms->crtcs[kms->n_crtcs];
> > > + master = mdev->pipelines[i];
> > > +
> > > + crtc->master = master;
> > > + crtc->slave = NULL;
> > > +
> > > + if (crtc->slave)
> > > + sprintf(str, "pipe-%d", crtc->slave->id);
> > > + else
> > > + sprintf(str, "None");
> > > +
> > > + DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
> > > + kms->n_crtcs, master->id, str,
> > > + master->of_output_dev ?
> > > + master->of_output_dev->full_name : "None");
> > > +
> > > + kms->n_crtcs++;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static struct drm_plane *
> > > +get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
> > > +{
> > > + struct komeda_plane *kplane;
> > > + struct drm_plane *plane;
> > > +
> > > + drm_for_each_plane(plane, &kms->base) {
> > > + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> > > + continue;
> > > +
> > > + kplane = to_kplane(plane);
> > > + /* only master can be primary */
> > > + if (kplane->layer->base.pipeline == crtc->master)
> > > + return plane;
> > > + }
> > > +
> > > + return NULL;
> > > +}
> > > +
> > > +static int komeda_crtc_add(struct komeda_kms_dev *kms,
> > > + struct komeda_crtc *kcrtc)
> > > +{
> > > + struct drm_crtc *crtc = &kcrtc->base;
> > > + int err;
> > > +
> > > + err = drm_crtc_init_with_planes(&kms->base, crtc,
> > > + get_crtc_primary(kms, kcrtc), NULL,
> > > + &komeda_crtc_funcs, NULL);
> > > + if (err)
> > > + return err;
> > > +
> > > + drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
> > > + drm_crtc_vblank_reset(crtc);
> > > +
> > > + crtc->port = kcrtc->master->of_output_port;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > > +{
> > > + int i, err;
> > > +
> > > + for (i = 0; i < kms->n_crtcs; i++) {
> > > + err = komeda_crtc_add(kms, &kms->crtcs[i]);
> > > + if (err)
> > > + return err;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > index a2657b3d09d7..4b8ce717a71c 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > @@ -13,18 +13,21 @@
> > >
> > > struct komeda_drv {
> > > struct komeda_dev *mdev;
> > > + struct komeda_kms_dev *kms;
> > > };
> > >
> > > static void komeda_unbind(struct device *dev)
> > > {
> > > struct komeda_drv *mdrv = dev_get_drvdata(dev);
> > >
> > > - dev_set_drvdata(dev, NULL);
> > > -
> >
> > I would argue that you're fixing a bug here that was introduced in an
> > earlier patch, and that you should fix that patch rather than this
> > change.
>
> Sorry, you're right, will fix it the next version.
>
> > > if (!mdrv)
> > > return;
> > >
> > > + komeda_kms_detach(mdrv->kms);
> > > +
> > > komeda_dev_destroy(mdrv->mdev);
> > > +
> > > + dev_set_drvdata(dev, NULL);
> > > kfree(mdrv);
> > > }
> > >
> > > @@ -33,7 +36,7 @@ static int komeda_bind(struct device *dev)
> > > struct komeda_drv *mdrv;
> > > int err;
> > >
> > > - mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
> > > + mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
> > > if (!mdrv)
> > > return -ENOMEM;
> > >
> > > @@ -45,10 +48,18 @@ static int komeda_bind(struct device *dev)
> > >
> > > dev_set_drvdata(dev, mdrv);
> > >
> > > + mdrv->kms = komeda_kms_attach(mdrv->mdev);
> > > + if (IS_ERR(mdrv->kms)) {
> > > + err = PTR_ERR(mdrv->kms);
> >
> > does mdrv->kms needs to be set to NULL here?

Ping on this one.

> >
> > > + goto destroy_mdev;
> > > + }
> > > +
> > > return 0;
> > >
> > > +destroy_mdev:
> > > + komeda_dev_destroy(mdrv->mdev);
> > > free_mdrv:
> > > - kfree(mdrv);
> > > + devm_kfree(dev, mdrv);
> > > return err;
> > > }
> > >
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > new file mode 100644
> > > index 000000000000..fd48360ca524
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > @@ -0,0 +1,169 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include <linux/component.h>
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_gem_framebuffer_helper.h>
> > > +#include <drm/drm_gem_cma_helper.h>
> > > +#include <drm/drm_fb_helper.h>
> > > +#include <linux/interrupt.h>
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +#include "komeda_framebuffer.h"
> > > +
> > > +DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
> > > +
> > > +static int komeda_gem_cma_dumb_create(struct drm_file *file,
> > > + struct drm_device *dev,
> > > + struct drm_mode_create_dumb *args)
> > > +{
> > > + u32 alignment = 16; /* TODO get alignment from dev */
> > > +
> > > + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
> > > + alignment);
> > > +
> > > + return drm_gem_cma_dumb_create_internal(file, dev, args);
> > > +}
> > > +
> > > +static struct drm_driver komeda_kms_driver = {
> > > + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
> > > + DRIVER_PRIME,
> > > + .lastclose = drm_fb_helper_lastclose,
> > > + .gem_free_object_unlocked = drm_gem_cma_free_object,
> > > + .gem_vm_ops = &drm_gem_cma_vm_ops,
> > > + .dumb_create = komeda_gem_cma_dumb_create,
> > > + .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> > > + .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> > > + .gem_prime_export = drm_gem_prime_export,
> > > + .gem_prime_import = drm_gem_prime_import,
> > > + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> > > + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> > > + .gem_prime_vmap = drm_gem_cma_prime_vmap,
> > > + .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> > > + .gem_prime_mmap = drm_gem_cma_prime_mmap,
> > > + .fops = &komeda_cma_fops,
> > > + .name = "komeda",
> > > + .desc = "ARM Mali Komeda Display Processor driver",
> > > + .date = "20181101",
> > > + .major = 0,
> > > + .minor = 1,
> > > +};
> > > +
> > > +static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
> > > +{
> > > + struct drm_device *dev = old_state->dev;
> > > +
> > > + drm_atomic_helper_commit_modeset_disables(dev, old_state);
> > > +
> > > + drm_atomic_helper_commit_planes(dev, old_state, 0);
> > > +
> > > + drm_atomic_helper_commit_modeset_enables(dev, old_state);
> >
> > Mainline has also introduced the drm_atomic_helper_fake_vblank(old_state) call
> > to help with writebacks on CRTCs that might be otherwise disabled. Do we need
> > to have it here too?
>
> we don't need it, since D71 HW still sends flip interrupt even on oneshot
> writeback mode.

Yeah, but does it do it when the CRTC is disabled? Given that the
writeback could take a while, and it is something that gets started
during one atomic commit but finishes at some later time without
blocking the next commit, you could have one atomic commit asking for a
writeback and then another commit disabling the CRTC before the
writeback has finished. In that case you still need to fake the vblank
event when the writeback is done, otherwise userspace will hung waiting
forever for the fence to be signalled.


Best regards,
Liviu


>
> > > +
> > > + drm_atomic_helper_wait_for_flip_done(dev, old_state);
> > > +
> > > + drm_atomic_helper_commit_hw_done(old_state);
> > > +
> > > + drm_atomic_helper_cleanup_planes(dev, old_state);
> > > +}
> > > +
> > > +static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
> > > + .atomic_commit_tail = komeda_kms_commit_tail,
> > > +};
> > > +
> > > +static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
> > > + .fb_create = komeda_fb_create,
> > > + .atomic_check = NULL,/*komeda_kms_check*/
> >
> > I would argue that you should at least use drm_atomic_helper_check here,
> > rather than set it to NULL, even if later you will replace it with a
> > komeda function.
>
> OK.
>
> >
> > > + .atomic_commit = drm_atomic_helper_commit,
> > > +};
> > > +
> > > +static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev)
> > > +{
> > > + struct drm_mode_config *config = &kms->base.mode_config;
> > > +
> > > + drm_mode_config_init(&kms->base);
> > > +
> > > + komeda_kms_setup_crtcs(kms, mdev);
> > > +
> > > + /* Get value from dev */
> > > + config->min_width = 0;
> > > + config->min_height = 0;
> > > + config->max_width = 4096;
> > > + config->max_height = 4096;
> > > + config->allow_fb_modifiers = true;
> > > +
> > > + config->funcs = &komeda_mode_config_funcs;
> > > + config->helper_private = &komeda_mode_config_helpers;
> > > +}
> > > +
> > > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
> > > + struct drm_device *drm;
> > > + int err;
> > > +
> > > + if (!kms)
> > > + return ERR_PTR(-ENOMEM);
> > > +
> > > + drm = &kms->base;
> > > + err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
> > > + if (err)
> > > + goto free_kms;
> > > +
> > > + drm->dev_private = mdev;
> > > +
> > > + komeda_kms_mode_config_init(kms, mdev);
> > > +
> > > + err = komeda_kms_add_private_objs(kms, mdev);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = komeda_kms_add_planes(kms, mdev);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = drm_vblank_init(drm, kms->n_crtcs);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = komeda_kms_add_crtcs(kms, mdev);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = component_bind_all(mdev->dev, kms);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + drm_mode_config_reset(drm);
> > > +
> > > + err = drm_dev_register(drm, 0);
> > > + if (err)
> > > + goto uninstall_irq;
> > > +
> > > + return kms;
> > > +
> > > +uninstall_irq:
> > > + drm_irq_uninstall(drm);
> > > +cleanup_mode_config:
> > > + drm_mode_config_cleanup(drm);
> > > +free_kms:
> > > + kfree(kms);
> > > + return ERR_PTR(err);
> > > +}
> > > +
> > > +void komeda_kms_detach(struct komeda_kms_dev *kms)
> > > +{
> > > + struct drm_device *drm = &kms->base;
> > > + struct komeda_dev *mdev = drm->dev_private;
> > > +
> > > + drm_dev_unregister(drm);
> > > + component_unbind_all(mdev->dev, drm);
> > > + komeda_kms_cleanup_private_objs(mdev);
> > > + drm_mode_config_cleanup(drm);
> > > + drm->dev_private = NULL;
> > > + drm_dev_put(drm);
> > > +}
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > new file mode 100644
> > > index 000000000000..f13666004a42
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > @@ -0,0 +1,113 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#ifndef _KOMEDA_KMS_H_
> > > +#define _KOMEDA_KMS_H_
> > > +
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_crtc_helper.h>
> > > +#include <drm/drm_writeback.h>
> > > +
> > > +/** struct komeda_plane - komeda instance of drm_plane */
> > > +struct komeda_plane {
> > > + /** @base: &drm_plane */
> > > + struct drm_plane base;
> > > + /**
> > > + * @layer:
> > > + *
> > > + * represents available layer input pipelines for this plane.
> > > + *
> > > + * NOTE:
> > > + * the layer is not for a specific Layer, but indicate a group of
> > > + * Layers with same capabilities.
> > > + */
> > > + struct komeda_layer *layer;
> > > +};
> > > +
> > > +/**
> > > + * struct komeda_plane_state
> > > + *
> > > + * The plane_state can be split into two data flow (left/right) and handled
> > > + * by two layers &komeda_plane.layer and &komeda_plane.layer.right
> > > + */
> > > +struct komeda_plane_state {
> > > + /** @base: &drm_plane_state */
> > > + struct drm_plane_state base;
> > > +
> > > + /* private properties */
> > > +};
> > > +
> > > +/**
> > > + * struct komeda_wb_connector
> > > + */
> > > +struct komeda_wb_connector {
> > > + /** @base: &drm_writeback_connector */
> > > + struct drm_writeback_connector base;
> > > +
> > > + /** @wb_layer: represents associated writeback pipeline of komeda */
> > > + struct komeda_layer *wb_layer;
> > > +};
> > > +
> > > +/**
> > > + * struct komeda_crtc
> > > + */
> > > +struct komeda_crtc {
> > > + /** @base: &drm_crtc */
> > > + struct drm_crtc base;
> > > + /** @master: only master has display output */
> > > + struct komeda_pipeline *master;
> > > + /**
> > > + * @slave: optional
> > > + *
> > > + * Doesn't have its own display output, the handled data flow will
> > > + * merge into the master.
> > > + */
> > > + struct komeda_pipeline *slave;
> > > +};
> > > +
> > > +/** struct komeda_crtc_state */
> > > +struct komeda_crtc_state {
> > > + /** @base: &drm_crtc_state */
> > > + struct drm_crtc_state base;
> > > +
> > > + /* private properties */
> > > +
> > > + /* computed state which are used by validate/check */
> > > + u32 affected_pipes;
> > > + u32 active_pipes;
> > > +};
> > > +
> > > +/** struct komeda_kms_dev - for gather KMS related things */
> > > +struct komeda_kms_dev {
> > > + /** @base: &drm_device */
> > > + struct drm_device base;
> > > +
> > > + /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
> > > + int n_crtcs;
> > > + /** @crtcs: crtcs list */
> > > + struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
> > > +};
> > > +
> > > +#define to_kplane(p) container_of(p, struct komeda_plane, base)
> > > +#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
> > > +#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
> > > +#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
> > > +#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
> > > +#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
> > > +
> > > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > +
> > > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev);
> > > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
> > > +
> > > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
> > > +void komeda_kms_detach(struct komeda_kms_dev *kms);
> > > +
> > > +#endif /*_KOMEDA_KMS_H_*/
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > index 2d68ffeae25d..114129d96851 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > @@ -333,6 +333,9 @@ struct komeda_pipeline_state {
> > > #define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
> > > #define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
> > >
> > > +#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
> > > +#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
> > > +
> > > /* pipeline APIs */
> > > struct komeda_pipeline *
> > > komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > new file mode 100644
> > > index 000000000000..0a4953a9a909
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > @@ -0,0 +1,109 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_plane_helper.h>
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +
> > > +static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
> > > +};
> > > +
> > > +static void komeda_plane_destroy(struct drm_plane *plane)
> > > +{
> > > + drm_plane_cleanup(plane);
> > > +
> > > + kfree(to_kplane(plane));
> > > +}
> > > +
> > > +static const struct drm_plane_funcs komeda_plane_funcs = {
> > > +};
> > > +
> > > +/* for komeda, which is pipeline can be share between crtcs */
> > > +static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
> > > + struct komeda_pipeline *pipe)
> > > +{
> > > + struct komeda_crtc *crtc;
> > > + u32 possible_crtcs = 0;
> > > + int i;
> > > +
> > > + for (i = 0; i < kms->n_crtcs; i++) {
> > > + crtc = &kms->crtcs[i];
> > > +
> > > + if ((pipe == crtc->master) || (pipe == crtc->slave))
> > > + possible_crtcs |= BIT(i);
> > > + }
> > > +
> > > + return possible_crtcs;
> > > +}
> > > +
> > > +/* use Layer0 as primary */
> > > +static u32 get_plane_type(struct komeda_kms_dev *kms,
> > > + struct komeda_component *c)
> > > +{
> > > + bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
> > > +
> > > + return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
> > > +}
> > > +
> > > +static int komeda_plane_add(struct komeda_kms_dev *kms,
> > > + struct komeda_layer *layer)
> > > +{
> > > + struct komeda_dev *mdev = kms->base.dev_private;
> > > + struct komeda_component *c = &layer->base;
> > > + struct komeda_plane *kplane;
> > > + struct drm_plane *plane;
> > > + u32 *formats, n_formats = 0;
> > > + int err;
> > > +
> > > + kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
> > > + if (!kplane)
> > > + return -ENOMEM;
> > > +
> > > + plane = &kplane->base;
> > > + kplane->layer = layer;
> > > +
> > > + formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
> > > + layer->layer_type, &n_formats);
> > > +
> > > + err = drm_universal_plane_init(&kms->base, plane,
> > > + get_possible_crtcs(kms, c->pipeline),
> > > + &komeda_plane_funcs,
> > > + formats, n_formats, NULL,
> > > + get_plane_type(kms, c),
> > > + "%s", c->name);
> > > +
> > > + komeda_put_fourcc_list(formats);
> > > +
> > > + if (err)
> > > + goto cleanup;
> > > +
> > > + drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
> > > +
> > > + return 0;
> > > +cleanup:
> > > + komeda_plane_destroy(plane);
> > > + return err;
> > > +}
> > > +
> > > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_pipeline *pipe;
> > > + int i, j, err;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + pipe = mdev->pipelines[i];
> > > +
> > > + for (j = 0; j < pipe->n_layers; j++) {
> > > + err = komeda_plane_add(kms, pipe->layers[j]);
> > > + if (err)
> > > + return err;
> > > + }
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > > new file mode 100644
> > > index 000000000000..9edfd6ab0c12
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > > @@ -0,0 +1,88 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +
> > > +static struct drm_private_state *
> > > +komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
> > > +{
> > > + struct komeda_pipeline_state *st;
> > > +
> > > + st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
> > > + if (!st)
> > > + return NULL;
> > > +
> > > + st->active_comps = 0;
> > > +
> > > + __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
> > > +
> > > + return &st->obj;
> > > +}
> > > +
> > > +static void
> > > +komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
> > > + struct drm_private_state *state)
> > > +{
> > > + kfree(priv_to_pipe_st(state));
> > > +}
> > > +
> > > +static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
> > > + .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
> > > + .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
> > > +};
> > > +
> > > +static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
> > > + struct komeda_pipeline *pipe)
> > > +{
> > > + struct komeda_pipeline_state *st;
> > > +
> > > + st = kzalloc(sizeof(*st), GFP_KERNEL);
> > > + if (!st)
> > > + return -ENOMEM;
> > > +
> > > + st->pipe = pipe;
> > > + drm_atomic_private_obj_init(&pipe->obj, &st->obj,
> > > + &komeda_pipeline_obj_funcs);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_pipeline *pipe;
> > > + int i, err;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + pipe = mdev->pipelines[i];
> > > +
> > > + err = komeda_pipeline_obj_add(kms, pipe);
> > > + if (err)
> > > + return err;
> > > +
> > > + /* Add component */
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_pipeline *pipe;
> > > + struct komeda_component *c;
> > > + int i, id;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + pipe = mdev->pipelines[i];
> > > + dp_for_each_set_bit(id, pipe->avail_comps) {
> > > + c = komeda_pipeline_get_component(pipe, id);
> > > +
> > > + drm_atomic_private_obj_fini(&c->obj);
> > > + }
> > > + drm_atomic_private_obj_fini(&pipe->obj);
> > > + }
> > > +}
> > > --
> > > 2.17.1
> > >
> >
> > Reviewed-by: Liviu Dudau <[email protected]>
> >
> > Best regards,
> > Liviu
> >
> >
> > --
> > ====================
> > | I would like to |
> > | fix the world, |
> > | but they're not |
> > | giving me the |
> > \ source code! /
> > ---------------
> > ¯\_(ツ)_/¯

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-28 00:44:07

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 7/9] drm/komeda: Attach komeda_dev to DRM-KMS

On Thu, Dec 27, 2018 at 07:09:07AM +0000, james qian wang (Arm Technology China) wrote:
> On Mon, Dec 24, 2018 at 08:32:14PM +0800, Liviu Dudau wrote:
> > On Fri, Dec 21, 2018 at 10:00:33AM +0000, james qian wang (Arm Technology China) wrote:
> > > Add komeda_kms abstracton to attach komeda_dev to DRM-KMS
> > > CRTC: according to the komeda_pipeline
> > > PLANE: according to komeda_layer (layer input pipeline)
> > > PRIVATE_OBJS: komeda_pipeline/component all will be treat as private_objs
> > >
> > > komeda_kms is for connecting DRM-KMS and komeda_dev, like reporting the
> > > kms object properties according to the komeda_dev, and pass/convert KMS's
> > > requirement to komeda_dev.
> > >
> > > Changes in v3:
> > > - Fixed style problem found by checkpatch.pl --strict.
> > >
> > > Changes in v2:
> > > - Unified abbreviation of "pipeline" to "pipe".
> > >
> > > Signed-off-by: James (Qian) Wang <[email protected]>
> > > ---
> > > drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
> > > .../gpu/drm/arm/display/komeda/komeda_crtc.c | 106 +++++++++++
> > > .../gpu/drm/arm/display/komeda/komeda_drv.c | 19 +-
> > > .../gpu/drm/arm/display/komeda/komeda_kms.c | 169 ++++++++++++++++++
> > > .../gpu/drm/arm/display/komeda/komeda_kms.h | 113 ++++++++++++
> > > .../drm/arm/display/komeda/komeda_pipeline.h | 3 +
> > > .../gpu/drm/arm/display/komeda/komeda_plane.c | 109 +++++++++++
> > > .../arm/display/komeda/komeda_private_obj.c | 88 +++++++++
> > > 8 files changed, 608 insertions(+), 5 deletions(-)
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > >
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> > > index 25beae900ed2..1b875e5dc0f6 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> > > +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> > > @@ -9,7 +9,11 @@ komeda-y := \
> > > komeda_dev.o \
> > > komeda_format_caps.o \
> > > komeda_pipeline.o \
> > > - komeda_framebuffer.o
> > > + komeda_framebuffer.o \
> > > + komeda_kms.o \
> > > + komeda_crtc.o \
> > > + komeda_plane.o \
> > > + komeda_private_obj.o
> > >
> > > komeda-y += \
> > > d71/d71_dev.o
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > new file mode 100644
> > > index 000000000000..5bb5a55f6b31
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > @@ -0,0 +1,106 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include <linux/clk.h>
> > > +#include <linux/spinlock.h>
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_plane_helper.h>
> > > +#include <drm/drm_crtc_helper.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +
> > > +struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
> > > +};
> > > +
> > > +static const struct drm_crtc_funcs komeda_crtc_funcs = {
> > > +};
> > > +
> > > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_crtc *crtc;
> > > + struct komeda_pipeline *master;
> > > + char str[16];
> > > + int i;
> > > +
> > > + kms->n_crtcs = 0;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + crtc = &kms->crtcs[kms->n_crtcs];
> > > + master = mdev->pipelines[i];
> > > +
> > > + crtc->master = master;
> > > + crtc->slave = NULL;
> > > +
> > > + if (crtc->slave)
> > > + sprintf(str, "pipe-%d", crtc->slave->id);
> > > + else
> > > + sprintf(str, "None");
> > > +
> > > + DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
> > > + kms->n_crtcs, master->id, str,
> > > + master->of_output_dev ?
> > > + master->of_output_dev->full_name : "None");
> > > +
> > > + kms->n_crtcs++;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static struct drm_plane *
> > > +get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
> > > +{
> > > + struct komeda_plane *kplane;
> > > + struct drm_plane *plane;
> > > +
> > > + drm_for_each_plane(plane, &kms->base) {
> > > + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> > > + continue;
> > > +
> > > + kplane = to_kplane(plane);
> > > + /* only master can be primary */
> > > + if (kplane->layer->base.pipeline == crtc->master)
> > > + return plane;
> > > + }
> > > +
> > > + return NULL;
> > > +}
> > > +
> > > +static int komeda_crtc_add(struct komeda_kms_dev *kms,
> > > + struct komeda_crtc *kcrtc)
> > > +{
> > > + struct drm_crtc *crtc = &kcrtc->base;
> > > + int err;
> > > +
> > > + err = drm_crtc_init_with_planes(&kms->base, crtc,
> > > + get_crtc_primary(kms, kcrtc), NULL,
> > > + &komeda_crtc_funcs, NULL);
> > > + if (err)
> > > + return err;
> > > +
> > > + drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
> > > + drm_crtc_vblank_reset(crtc);
> > > +
> > > + crtc->port = kcrtc->master->of_output_port;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > > +{
> > > + int i, err;
> > > +
> > > + for (i = 0; i < kms->n_crtcs; i++) {
> > > + err = komeda_crtc_add(kms, &kms->crtcs[i]);
> > > + if (err)
> > > + return err;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > index a2657b3d09d7..4b8ce717a71c 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > @@ -13,18 +13,21 @@
> > >
> > > struct komeda_drv {
> > > struct komeda_dev *mdev;
> > > + struct komeda_kms_dev *kms;
> > > };
> > >
> > > static void komeda_unbind(struct device *dev)
> > > {
> > > struct komeda_drv *mdrv = dev_get_drvdata(dev);
> > >
> > > - dev_set_drvdata(dev, NULL);
> > > -
> >
> > I would argue that you're fixing a bug here that was introduced in an
> > earlier patch, and that you should fix that patch rather than this
> > change.
>
> Sorry, you're right, will fix it the next version.
>
> > > if (!mdrv)
> > > return;
> > >
> > > + komeda_kms_detach(mdrv->kms);
> > > +
> > > komeda_dev_destroy(mdrv->mdev);
> > > +
> > > + dev_set_drvdata(dev, NULL);
> > > kfree(mdrv);
> > > }
> > >
> > > @@ -33,7 +36,7 @@ static int komeda_bind(struct device *dev)
> > > struct komeda_drv *mdrv;
> > > int err;
> > >
> > > - mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
> > > + mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
> > > if (!mdrv)
> > > return -ENOMEM;
> > >
> > > @@ -45,10 +48,18 @@ static int komeda_bind(struct device *dev)
> > >
> > > dev_set_drvdata(dev, mdrv);
> > >
> > > + mdrv->kms = komeda_kms_attach(mdrv->mdev);
> > > + if (IS_ERR(mdrv->kms)) {
> > > + err = PTR_ERR(mdrv->kms);
> >
> > does mdrv->kms needs to be set to NULL here?

Ping on this one.

> >
> > > + goto destroy_mdev;
> > > + }
> > > +
> > > return 0;
> > >
> > > +destroy_mdev:
> > > + komeda_dev_destroy(mdrv->mdev);
> > > free_mdrv:
> > > - kfree(mdrv);
> > > + devm_kfree(dev, mdrv);
> > > return err;
> > > }
> > >
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > new file mode 100644
> > > index 000000000000..fd48360ca524
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > @@ -0,0 +1,169 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include <linux/component.h>
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_gem_framebuffer_helper.h>
> > > +#include <drm/drm_gem_cma_helper.h>
> > > +#include <drm/drm_fb_helper.h>
> > > +#include <linux/interrupt.h>
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +#include "komeda_framebuffer.h"
> > > +
> > > +DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
> > > +
> > > +static int komeda_gem_cma_dumb_create(struct drm_file *file,
> > > + struct drm_device *dev,
> > > + struct drm_mode_create_dumb *args)
> > > +{
> > > + u32 alignment = 16; /* TODO get alignment from dev */
> > > +
> > > + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
> > > + alignment);
> > > +
> > > + return drm_gem_cma_dumb_create_internal(file, dev, args);
> > > +}
> > > +
> > > +static struct drm_driver komeda_kms_driver = {
> > > + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
> > > + DRIVER_PRIME,
> > > + .lastclose = drm_fb_helper_lastclose,
> > > + .gem_free_object_unlocked = drm_gem_cma_free_object,
> > > + .gem_vm_ops = &drm_gem_cma_vm_ops,
> > > + .dumb_create = komeda_gem_cma_dumb_create,
> > > + .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> > > + .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> > > + .gem_prime_export = drm_gem_prime_export,
> > > + .gem_prime_import = drm_gem_prime_import,
> > > + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> > > + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> > > + .gem_prime_vmap = drm_gem_cma_prime_vmap,
> > > + .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> > > + .gem_prime_mmap = drm_gem_cma_prime_mmap,
> > > + .fops = &komeda_cma_fops,
> > > + .name = "komeda",
> > > + .desc = "ARM Mali Komeda Display Processor driver",
> > > + .date = "20181101",
> > > + .major = 0,
> > > + .minor = 1,
> > > +};
> > > +
> > > +static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
> > > +{
> > > + struct drm_device *dev = old_state->dev;
> > > +
> > > + drm_atomic_helper_commit_modeset_disables(dev, old_state);
> > > +
> > > + drm_atomic_helper_commit_planes(dev, old_state, 0);
> > > +
> > > + drm_atomic_helper_commit_modeset_enables(dev, old_state);
> >
> > Mainline has also introduced the drm_atomic_helper_fake_vblank(old_state) call
> > to help with writebacks on CRTCs that might be otherwise disabled. Do we need
> > to have it here too?
>
> we don't need it, since D71 HW still sends flip interrupt even on oneshot
> writeback mode.

Yeah, but does it do it when the CRTC is disabled? Given that the
writeback could take a while, and it is something that gets started
during one atomic commit but finishes at some later time without
blocking the next commit, you could have one atomic commit asking for a
writeback and then another commit disabling the CRTC before the
writeback has finished. In that case you still need to fake the vblank
event when the writeback is done, otherwise userspace will hung waiting
forever for the fence to be signalled.


Best regards,
Liviu



>
> > > +
> > > + drm_atomic_helper_wait_for_flip_done(dev, old_state);
> > > +
> > > + drm_atomic_helper_commit_hw_done(old_state);
> > > +
> > > + drm_atomic_helper_cleanup_planes(dev, old_state);
> > > +}
> > > +
> > > +static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
> > > + .atomic_commit_tail = komeda_kms_commit_tail,
> > > +};
> > > +
> > > +static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
> > > + .fb_create = komeda_fb_create,
> > > + .atomic_check = NULL,/*komeda_kms_check*/
> >
> > I would argue that you should at least use drm_atomic_helper_check here,
> > rather than set it to NULL, even if later you will replace it with a
> > komeda function.
>
> OK.
>
> >
> > > + .atomic_commit = drm_atomic_helper_commit,
> > > +};
> > > +
> > > +static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev)
> > > +{
> > > + struct drm_mode_config *config = &kms->base.mode_config;
> > > +
> > > + drm_mode_config_init(&kms->base);
> > > +
> > > + komeda_kms_setup_crtcs(kms, mdev);
> > > +
> > > + /* Get value from dev */
> > > + config->min_width = 0;
> > > + config->min_height = 0;
> > > + config->max_width = 4096;
> > > + config->max_height = 4096;
> > > + config->allow_fb_modifiers = true;
> > > +
> > > + config->funcs = &komeda_mode_config_funcs;
> > > + config->helper_private = &komeda_mode_config_helpers;
> > > +}
> > > +
> > > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
> > > + struct drm_device *drm;
> > > + int err;
> > > +
> > > + if (!kms)
> > > + return ERR_PTR(-ENOMEM);
> > > +
> > > + drm = &kms->base;
> > > + err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
> > > + if (err)
> > > + goto free_kms;
> > > +
> > > + drm->dev_private = mdev;
> > > +
> > > + komeda_kms_mode_config_init(kms, mdev);
> > > +
> > > + err = komeda_kms_add_private_objs(kms, mdev);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = komeda_kms_add_planes(kms, mdev);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = drm_vblank_init(drm, kms->n_crtcs);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = komeda_kms_add_crtcs(kms, mdev);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + err = component_bind_all(mdev->dev, kms);
> > > + if (err)
> > > + goto cleanup_mode_config;
> > > +
> > > + drm_mode_config_reset(drm);
> > > +
> > > + err = drm_dev_register(drm, 0);
> > > + if (err)
> > > + goto uninstall_irq;
> > > +
> > > + return kms;
> > > +
> > > +uninstall_irq:
> > > + drm_irq_uninstall(drm);
> > > +cleanup_mode_config:
> > > + drm_mode_config_cleanup(drm);
> > > +free_kms:
> > > + kfree(kms);
> > > + return ERR_PTR(err);
> > > +}
> > > +
> > > +void komeda_kms_detach(struct komeda_kms_dev *kms)
> > > +{
> > > + struct drm_device *drm = &kms->base;
> > > + struct komeda_dev *mdev = drm->dev_private;
> > > +
> > > + drm_dev_unregister(drm);
> > > + component_unbind_all(mdev->dev, drm);
> > > + komeda_kms_cleanup_private_objs(mdev);
> > > + drm_mode_config_cleanup(drm);
> > > + drm->dev_private = NULL;
> > > + drm_dev_put(drm);
> > > +}
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > new file mode 100644
> > > index 000000000000..f13666004a42
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > @@ -0,0 +1,113 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#ifndef _KOMEDA_KMS_H_
> > > +#define _KOMEDA_KMS_H_
> > > +
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_crtc_helper.h>
> > > +#include <drm/drm_writeback.h>
> > > +
> > > +/** struct komeda_plane - komeda instance of drm_plane */
> > > +struct komeda_plane {
> > > + /** @base: &drm_plane */
> > > + struct drm_plane base;
> > > + /**
> > > + * @layer:
> > > + *
> > > + * represents available layer input pipelines for this plane.
> > > + *
> > > + * NOTE:
> > > + * the layer is not for a specific Layer, but indicate a group of
> > > + * Layers with same capabilities.
> > > + */
> > > + struct komeda_layer *layer;
> > > +};
> > > +
> > > +/**
> > > + * struct komeda_plane_state
> > > + *
> > > + * The plane_state can be split into two data flow (left/right) and handled
> > > + * by two layers &komeda_plane.layer and &komeda_plane.layer.right
> > > + */
> > > +struct komeda_plane_state {
> > > + /** @base: &drm_plane_state */
> > > + struct drm_plane_state base;
> > > +
> > > + /* private properties */
> > > +};
> > > +
> > > +/**
> > > + * struct komeda_wb_connector
> > > + */
> > > +struct komeda_wb_connector {
> > > + /** @base: &drm_writeback_connector */
> > > + struct drm_writeback_connector base;
> > > +
> > > + /** @wb_layer: represents associated writeback pipeline of komeda */
> > > + struct komeda_layer *wb_layer;
> > > +};
> > > +
> > > +/**
> > > + * struct komeda_crtc
> > > + */
> > > +struct komeda_crtc {
> > > + /** @base: &drm_crtc */
> > > + struct drm_crtc base;
> > > + /** @master: only master has display output */
> > > + struct komeda_pipeline *master;
> > > + /**
> > > + * @slave: optional
> > > + *
> > > + * Doesn't have its own display output, the handled data flow will
> > > + * merge into the master.
> > > + */
> > > + struct komeda_pipeline *slave;
> > > +};
> > > +
> > > +/** struct komeda_crtc_state */
> > > +struct komeda_crtc_state {
> > > + /** @base: &drm_crtc_state */
> > > + struct drm_crtc_state base;
> > > +
> > > + /* private properties */
> > > +
> > > + /* computed state which are used by validate/check */
> > > + u32 affected_pipes;
> > > + u32 active_pipes;
> > > +};
> > > +
> > > +/** struct komeda_kms_dev - for gather KMS related things */
> > > +struct komeda_kms_dev {
> > > + /** @base: &drm_device */
> > > + struct drm_device base;
> > > +
> > > + /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
> > > + int n_crtcs;
> > > + /** @crtcs: crtcs list */
> > > + struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
> > > +};
> > > +
> > > +#define to_kplane(p) container_of(p, struct komeda_plane, base)
> > > +#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
> > > +#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
> > > +#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
> > > +#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
> > > +#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
> > > +
> > > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > +
> > > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev);
> > > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
> > > +
> > > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
> > > +void komeda_kms_detach(struct komeda_kms_dev *kms);
> > > +
> > > +#endif /*_KOMEDA_KMS_H_*/
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > index 2d68ffeae25d..114129d96851 100644
> > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > @@ -333,6 +333,9 @@ struct komeda_pipeline_state {
> > > #define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
> > > #define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
> > >
> > > +#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
> > > +#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
> > > +
> > > /* pipeline APIs */
> > > struct komeda_pipeline *
> > > komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > new file mode 100644
> > > index 000000000000..0a4953a9a909
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > @@ -0,0 +1,109 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include <drm/drm_atomic.h>
> > > +#include <drm/drm_atomic_helper.h>
> > > +#include <drm/drm_plane_helper.h>
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +
> > > +static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
> > > +};
> > > +
> > > +static void komeda_plane_destroy(struct drm_plane *plane)
> > > +{
> > > + drm_plane_cleanup(plane);
> > > +
> > > + kfree(to_kplane(plane));
> > > +}
> > > +
> > > +static const struct drm_plane_funcs komeda_plane_funcs = {
> > > +};
> > > +
> > > +/* for komeda, which is pipeline can be share between crtcs */
> > > +static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
> > > + struct komeda_pipeline *pipe)
> > > +{
> > > + struct komeda_crtc *crtc;
> > > + u32 possible_crtcs = 0;
> > > + int i;
> > > +
> > > + for (i = 0; i < kms->n_crtcs; i++) {
> > > + crtc = &kms->crtcs[i];
> > > +
> > > + if ((pipe == crtc->master) || (pipe == crtc->slave))
> > > + possible_crtcs |= BIT(i);
> > > + }
> > > +
> > > + return possible_crtcs;
> > > +}
> > > +
> > > +/* use Layer0 as primary */
> > > +static u32 get_plane_type(struct komeda_kms_dev *kms,
> > > + struct komeda_component *c)
> > > +{
> > > + bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
> > > +
> > > + return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
> > > +}
> > > +
> > > +static int komeda_plane_add(struct komeda_kms_dev *kms,
> > > + struct komeda_layer *layer)
> > > +{
> > > + struct komeda_dev *mdev = kms->base.dev_private;
> > > + struct komeda_component *c = &layer->base;
> > > + struct komeda_plane *kplane;
> > > + struct drm_plane *plane;
> > > + u32 *formats, n_formats = 0;
> > > + int err;
> > > +
> > > + kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
> > > + if (!kplane)
> > > + return -ENOMEM;
> > > +
> > > + plane = &kplane->base;
> > > + kplane->layer = layer;
> > > +
> > > + formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
> > > + layer->layer_type, &n_formats);
> > > +
> > > + err = drm_universal_plane_init(&kms->base, plane,
> > > + get_possible_crtcs(kms, c->pipeline),
> > > + &komeda_plane_funcs,
> > > + formats, n_formats, NULL,
> > > + get_plane_type(kms, c),
> > > + "%s", c->name);
> > > +
> > > + komeda_put_fourcc_list(formats);
> > > +
> > > + if (err)
> > > + goto cleanup;
> > > +
> > > + drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
> > > +
> > > + return 0;
> > > +cleanup:
> > > + komeda_plane_destroy(plane);
> > > + return err;
> > > +}
> > > +
> > > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_pipeline *pipe;
> > > + int i, j, err;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + pipe = mdev->pipelines[i];
> > > +
> > > + for (j = 0; j < pipe->n_layers; j++) {
> > > + err = komeda_plane_add(kms, pipe->layers[j]);
> > > + if (err)
> > > + return err;
> > > + }
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > > new file mode 100644
> > > index 000000000000..9edfd6ab0c12
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > > @@ -0,0 +1,88 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > + * Author: James.Qian.Wang <[email protected]>
> > > + *
> > > + */
> > > +#include "komeda_dev.h"
> > > +#include "komeda_kms.h"
> > > +
> > > +static struct drm_private_state *
> > > +komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
> > > +{
> > > + struct komeda_pipeline_state *st;
> > > +
> > > + st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
> > > + if (!st)
> > > + return NULL;
> > > +
> > > + st->active_comps = 0;
> > > +
> > > + __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
> > > +
> > > + return &st->obj;
> > > +}
> > > +
> > > +static void
> > > +komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
> > > + struct drm_private_state *state)
> > > +{
> > > + kfree(priv_to_pipe_st(state));
> > > +}
> > > +
> > > +static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
> > > + .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
> > > + .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
> > > +};
> > > +
> > > +static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
> > > + struct komeda_pipeline *pipe)
> > > +{
> > > + struct komeda_pipeline_state *st;
> > > +
> > > + st = kzalloc(sizeof(*st), GFP_KERNEL);
> > > + if (!st)
> > > + return -ENOMEM;
> > > +
> > > + st->pipe = pipe;
> > > + drm_atomic_private_obj_init(&pipe->obj, &st->obj,
> > > + &komeda_pipeline_obj_funcs);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > > + struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_pipeline *pipe;
> > > + int i, err;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + pipe = mdev->pipelines[i];
> > > +
> > > + err = komeda_pipeline_obj_add(kms, pipe);
> > > + if (err)
> > > + return err;
> > > +
> > > + /* Add component */
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
> > > +{
> > > + struct komeda_pipeline *pipe;
> > > + struct komeda_component *c;
> > > + int i, id;
> > > +
> > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > + pipe = mdev->pipelines[i];
> > > + dp_for_each_set_bit(id, pipe->avail_comps) {
> > > + c = komeda_pipeline_get_component(pipe, id);
> > > +
> > > + drm_atomic_private_obj_fini(&c->obj);
> > > + }
> > > + drm_atomic_private_obj_fini(&pipe->obj);
> > > + }
> > > +}
> > > --
> > > 2.17.1
> > >
> >
> > Reviewed-by: Liviu Dudau <[email protected]>
> >
> > Best regards,
> > Liviu
> >
> >
> > --
> > ====================
> > | I would like to |
> > | fix the world, |
> > | but they're not |
> > | giving me the |
> > \ source code! /
> > ---------------
> > ¯\_(ツ)_/¯

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯

2018-12-28 12:22:54

by James Qian Wang

[permalink] [raw]
Subject: Re: [PATCH v3 7/9] drm/komeda: Attach komeda_dev to DRM-KMS

On Thu, Dec 27, 2018 at 10:31:52PM +0800, Liviu Dudau wrote:
> On Thu, Dec 27, 2018 at 07:09:07AM +0000, james qian wang (Arm Technology China) wrote:
> > On Mon, Dec 24, 2018 at 08:32:14PM +0800, Liviu Dudau wrote:
> > > On Fri, Dec 21, 2018 at 10:00:33AM +0000, james qian wang (Arm Technology China) wrote:
> > > > Add komeda_kms abstracton to attach komeda_dev to DRM-KMS
> > > > CRTC: according to the komeda_pipeline
> > > > PLANE: according to komeda_layer (layer input pipeline)
> > > > PRIVATE_OBJS: komeda_pipeline/component all will be treat as private_objs
> > > >
> > > > komeda_kms is for connecting DRM-KMS and komeda_dev, like reporting the
> > > > kms object properties according to the komeda_dev, and pass/convert KMS's
> > > > requirement to komeda_dev.
> > > >
> > > > Changes in v3:
> > > > - Fixed style problem found by checkpatch.pl --strict.
> > > >
> > > > Changes in v2:
> > > > - Unified abbreviation of "pipeline" to "pipe".
> > > >
> > > > Signed-off-by: James (Qian) Wang <[email protected]>
> > > > ---
> > > > drivers/gpu/drm/arm/display/komeda/Makefile | 6 +-
> > > > .../gpu/drm/arm/display/komeda/komeda_crtc.c | 106 +++++++++++
> > > > .../gpu/drm/arm/display/komeda/komeda_drv.c | 19 +-
> > > > .../gpu/drm/arm/display/komeda/komeda_kms.c | 169 ++++++++++++++++++
> > > > .../gpu/drm/arm/display/komeda/komeda_kms.h | 113 ++++++++++++
> > > > .../drm/arm/display/komeda/komeda_pipeline.h | 3 +
> > > > .../gpu/drm/arm/display/komeda/komeda_plane.c | 109 +++++++++++
> > > > .../arm/display/komeda/komeda_private_obj.c | 88 +++++++++
> > > > 8 files changed, 608 insertions(+), 5 deletions(-)
> > > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > > create mode 100644 drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > > >
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile
> > > > index 25beae900ed2..1b875e5dc0f6 100644
> > > > --- a/drivers/gpu/drm/arm/display/komeda/Makefile
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/Makefile
> > > > @@ -9,7 +9,11 @@ komeda-y := \
> > > > komeda_dev.o \
> > > > komeda_format_caps.o \
> > > > komeda_pipeline.o \
> > > > - komeda_framebuffer.o
> > > > + komeda_framebuffer.o \
> > > > + komeda_kms.o \
> > > > + komeda_crtc.o \
> > > > + komeda_plane.o \
> > > > + komeda_private_obj.o
> > > >
> > > > komeda-y += \
> > > > d71/d71_dev.o
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > > new file mode 100644
> > > > index 000000000000..5bb5a55f6b31
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_crtc.c
> > > > @@ -0,0 +1,106 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > > + * Author: James.Qian.Wang <[email protected]>
> > > > + *
> > > > + */
> > > > +#include <linux/clk.h>
> > > > +#include <linux/spinlock.h>
> > > > +#include <drm/drm_atomic.h>
> > > > +#include <drm/drm_atomic_helper.h>
> > > > +#include <drm/drm_plane_helper.h>
> > > > +#include <drm/drm_crtc_helper.h>
> > > > +#include <linux/pm_runtime.h>
> > > > +#include "komeda_dev.h"
> > > > +#include "komeda_kms.h"
> > > > +
> > > > +struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
> > > > +};
> > > > +
> > > > +static const struct drm_crtc_funcs komeda_crtc_funcs = {
> > > > +};
> > > > +
> > > > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
> > > > + struct komeda_dev *mdev)
> > > > +{
> > > > + struct komeda_crtc *crtc;
> > > > + struct komeda_pipeline *master;
> > > > + char str[16];
> > > > + int i;
> > > > +
> > > > + kms->n_crtcs = 0;
> > > > +
> > > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > > + crtc = &kms->crtcs[kms->n_crtcs];
> > > > + master = mdev->pipelines[i];
> > > > +
> > > > + crtc->master = master;
> > > > + crtc->slave = NULL;
> > > > +
> > > > + if (crtc->slave)
> > > > + sprintf(str, "pipe-%d", crtc->slave->id);
> > > > + else
> > > > + sprintf(str, "None");
> > > > +
> > > > + DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
> > > > + kms->n_crtcs, master->id, str,
> > > > + master->of_output_dev ?
> > > > + master->of_output_dev->full_name : "None");
> > > > +
> > > > + kms->n_crtcs++;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static struct drm_plane *
> > > > +get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
> > > > +{
> > > > + struct komeda_plane *kplane;
> > > > + struct drm_plane *plane;
> > > > +
> > > > + drm_for_each_plane(plane, &kms->base) {
> > > > + if (plane->type != DRM_PLANE_TYPE_PRIMARY)
> > > > + continue;
> > > > +
> > > > + kplane = to_kplane(plane);
> > > > + /* only master can be primary */
> > > > + if (kplane->layer->base.pipeline == crtc->master)
> > > > + return plane;
> > > > + }
> > > > +
> > > > + return NULL;
> > > > +}
> > > > +
> > > > +static int komeda_crtc_add(struct komeda_kms_dev *kms,
> > > > + struct komeda_crtc *kcrtc)
> > > > +{
> > > > + struct drm_crtc *crtc = &kcrtc->base;
> > > > + int err;
> > > > +
> > > > + err = drm_crtc_init_with_planes(&kms->base, crtc,
> > > > + get_crtc_primary(kms, kcrtc), NULL,
> > > > + &komeda_crtc_funcs, NULL);
> > > > + if (err)
> > > > + return err;
> > > > +
> > > > + drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
> > > > + drm_crtc_vblank_reset(crtc);
> > > > +
> > > > + crtc->port = kcrtc->master->of_output_port;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > > > +{
> > > > + int i, err;
> > > > +
> > > > + for (i = 0; i < kms->n_crtcs; i++) {
> > > > + err = komeda_crtc_add(kms, &kms->crtcs[i]);
> > > > + if (err)
> > > > + return err;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > > index a2657b3d09d7..4b8ce717a71c 100644
> > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
> > > > @@ -13,18 +13,21 @@
> > > >
> > > > struct komeda_drv {
> > > > struct komeda_dev *mdev;
> > > > + struct komeda_kms_dev *kms;
> > > > };
> > > >
> > > > static void komeda_unbind(struct device *dev)
> > > > {
> > > > struct komeda_drv *mdrv = dev_get_drvdata(dev);
> > > >
> > > > - dev_set_drvdata(dev, NULL);
> > > > -
> > >
> > > I would argue that you're fixing a bug here that was introduced in an
> > > earlier patch, and that you should fix that patch rather than this
> > > change.
> >
> > Sorry, you're right, will fix it the next version.
> >
> > > > if (!mdrv)
> > > > return;
> > > >
> > > > + komeda_kms_detach(mdrv->kms);
> > > > +
> > > > komeda_dev_destroy(mdrv->mdev);
> > > > +
> > > > + dev_set_drvdata(dev, NULL);
> > > > kfree(mdrv);
> > > > }
> > > >
> > > > @@ -33,7 +36,7 @@ static int komeda_bind(struct device *dev)
> > > > struct komeda_drv *mdrv;
> > > > int err;
> > > >
> > > > - mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
> > > > + mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
> > > > if (!mdrv)
> > > > return -ENOMEM;
> > > >
> > > > @@ -45,10 +48,18 @@ static int komeda_bind(struct device *dev)
> > > >
> > > > dev_set_drvdata(dev, mdrv);
> > > >
> > > > + mdrv->kms = komeda_kms_attach(mdrv->mdev);
> > > > + if (IS_ERR(mdrv->kms)) {
> > > > + err = PTR_ERR(mdrv->kms);
> > >
> > > does mdrv->kms needs to be set to NULL here?
>
> Ping on this one.
>

we don't need to set the kms to NULL here, since the next line is goto
destroy_mdev and then free(mdrv). and mdrv->kms has no chance been
accessed in these steps.

> > >
> > > > + goto destroy_mdev;
> > > > + }
> > > > +
> > > > return 0;
> > > >
> > > > +destroy_mdev:
> > > > + komeda_dev_destroy(mdrv->mdev);
> > > > free_mdrv:
> > > > - kfree(mdrv);
> > > > + devm_kfree(dev, mdrv);
> > > > return err;
> > > > }
> > > >
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > > new file mode 100644
> > > > index 000000000000..fd48360ca524
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
> > > > @@ -0,0 +1,169 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > > + * Author: James.Qian.Wang <[email protected]>
> > > > + *
> > > > + */
> > > > +#include <linux/component.h>
> > > > +#include <drm/drm_atomic.h>
> > > > +#include <drm/drm_atomic_helper.h>
> > > > +#include <drm/drm_gem_framebuffer_helper.h>
> > > > +#include <drm/drm_gem_cma_helper.h>
> > > > +#include <drm/drm_fb_helper.h>
> > > > +#include <linux/interrupt.h>
> > > > +#include "komeda_dev.h"
> > > > +#include "komeda_kms.h"
> > > > +#include "komeda_framebuffer.h"
> > > > +
> > > > +DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
> > > > +
> > > > +static int komeda_gem_cma_dumb_create(struct drm_file *file,
> > > > + struct drm_device *dev,
> > > > + struct drm_mode_create_dumb *args)
> > > > +{
> > > > + u32 alignment = 16; /* TODO get alignment from dev */
> > > > +
> > > > + args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
> > > > + alignment);
> > > > +
> > > > + return drm_gem_cma_dumb_create_internal(file, dev, args);
> > > > +}
> > > > +
> > > > +static struct drm_driver komeda_kms_driver = {
> > > > + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
> > > > + DRIVER_PRIME,
> > > > + .lastclose = drm_fb_helper_lastclose,
> > > > + .gem_free_object_unlocked = drm_gem_cma_free_object,
> > > > + .gem_vm_ops = &drm_gem_cma_vm_ops,
> > > > + .dumb_create = komeda_gem_cma_dumb_create,
> > > > + .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> > > > + .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> > > > + .gem_prime_export = drm_gem_prime_export,
> > > > + .gem_prime_import = drm_gem_prime_import,
> > > > + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> > > > + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> > > > + .gem_prime_vmap = drm_gem_cma_prime_vmap,
> > > > + .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> > > > + .gem_prime_mmap = drm_gem_cma_prime_mmap,
> > > > + .fops = &komeda_cma_fops,
> > > > + .name = "komeda",
> > > > + .desc = "ARM Mali Komeda Display Processor driver",
> > > > + .date = "20181101",
> > > > + .major = 0,
> > > > + .minor = 1,
> > > > +};
> > > > +
> > > > +static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
> > > > +{
> > > > + struct drm_device *dev = old_state->dev;
> > > > +
> > > > + drm_atomic_helper_commit_modeset_disables(dev, old_state);
> > > > +
> > > > + drm_atomic_helper_commit_planes(dev, old_state, 0);
> > > > +
> > > > + drm_atomic_helper_commit_modeset_enables(dev, old_state);
> > >
> > > Mainline has also introduced the drm_atomic_helper_fake_vblank(old_state) call
> > > to help with writebacks on CRTCs that might be otherwise disabled. Do we need
> > > to have it here too?
> >
> > we don't need it, since D71 HW still sends flip interrupt even on oneshot
> > writeback mode.
>
> Yeah, but does it do it when the CRTC is disabled? Given that the
> writeback could take a while, and it is something that gets started
> during one atomic commit but finishes at some later time without
> blocking the next commit, you could have one atomic commit asking for a
> writeback and then another commit disabling the CRTC before the
> writeback has finished. In that case you still need to fake the vblank
> event when the writeback is done, otherwise userspace will hung waiting
> forever for the fence to be signalled.
>

Unlike the Dp650 which use a special switch the DP MODE to handle the
CRTC on/off, CVAL(FLIP) for trigger the flip commit.
but for D71, no matter a scene change ((flip) or crtc on/off (modeset)). they
are both configuration changes, all configuration changes in D71 needs to be
triggered by a CVAL(configuartion valid), and then it will take effect in the
next vsync. So for D71 there is no difference for a scene commit and a modeset
on/off commit.

>
> Best regards,
> Liviu
>
>
>
> >
> > > > +
> > > > + drm_atomic_helper_wait_for_flip_done(dev, old_state);
> > > > +
> > > > + drm_atomic_helper_commit_hw_done(old_state);
> > > > +
> > > > + drm_atomic_helper_cleanup_planes(dev, old_state);
> > > > +}
> > > > +
> > > > +static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
> > > > + .atomic_commit_tail = komeda_kms_commit_tail,
> > > > +};
> > > > +
> > > > +static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
> > > > + .fb_create = komeda_fb_create,
> > > > + .atomic_check = NULL,/*komeda_kms_check*/
> > >
> > > I would argue that you should at least use drm_atomic_helper_check here,
> > > rather than set it to NULL, even if later you will replace it with a
> > > komeda function.
> >
> > OK.
> >
> > >
> > > > + .atomic_commit = drm_atomic_helper_commit,
> > > > +};
> > > > +
> > > > +static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
> > > > + struct komeda_dev *mdev)
> > > > +{
> > > > + struct drm_mode_config *config = &kms->base.mode_config;
> > > > +
> > > > + drm_mode_config_init(&kms->base);
> > > > +
> > > > + komeda_kms_setup_crtcs(kms, mdev);
> > > > +
> > > > + /* Get value from dev */
> > > > + config->min_width = 0;
> > > > + config->min_height = 0;
> > > > + config->max_width = 4096;
> > > > + config->max_height = 4096;
> > > > + config->allow_fb_modifiers = true;
> > > > +
> > > > + config->funcs = &komeda_mode_config_funcs;
> > > > + config->helper_private = &komeda_mode_config_helpers;
> > > > +}
> > > > +
> > > > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
> > > > +{
> > > > + struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
> > > > + struct drm_device *drm;
> > > > + int err;
> > > > +
> > > > + if (!kms)
> > > > + return ERR_PTR(-ENOMEM);
> > > > +
> > > > + drm = &kms->base;
> > > > + err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
> > > > + if (err)
> > > > + goto free_kms;
> > > > +
> > > > + drm->dev_private = mdev;
> > > > +
> > > > + komeda_kms_mode_config_init(kms, mdev);
> > > > +
> > > > + err = komeda_kms_add_private_objs(kms, mdev);
> > > > + if (err)
> > > > + goto cleanup_mode_config;
> > > > +
> > > > + err = komeda_kms_add_planes(kms, mdev);
> > > > + if (err)
> > > > + goto cleanup_mode_config;
> > > > +
> > > > + err = drm_vblank_init(drm, kms->n_crtcs);
> > > > + if (err)
> > > > + goto cleanup_mode_config;
> > > > +
> > > > + err = komeda_kms_add_crtcs(kms, mdev);
> > > > + if (err)
> > > > + goto cleanup_mode_config;
> > > > +
> > > > + err = component_bind_all(mdev->dev, kms);
> > > > + if (err)
> > > > + goto cleanup_mode_config;
> > > > +
> > > > + drm_mode_config_reset(drm);
> > > > +
> > > > + err = drm_dev_register(drm, 0);
> > > > + if (err)
> > > > + goto uninstall_irq;
> > > > +
> > > > + return kms;
> > > > +
> > > > +uninstall_irq:
> > > > + drm_irq_uninstall(drm);
> > > > +cleanup_mode_config:
> > > > + drm_mode_config_cleanup(drm);
> > > > +free_kms:
> > > > + kfree(kms);
> > > > + return ERR_PTR(err);
> > > > +}
> > > > +
> > > > +void komeda_kms_detach(struct komeda_kms_dev *kms)
> > > > +{
> > > > + struct drm_device *drm = &kms->base;
> > > > + struct komeda_dev *mdev = drm->dev_private;
> > > > +
> > > > + drm_dev_unregister(drm);
> > > > + component_unbind_all(mdev->dev, drm);
> > > > + komeda_kms_cleanup_private_objs(mdev);
> > > > + drm_mode_config_cleanup(drm);
> > > > + drm->dev_private = NULL;
> > > > + drm_dev_put(drm);
> > > > +}
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.h b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > > new file mode 100644
> > > > index 000000000000..f13666004a42
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.h
> > > > @@ -0,0 +1,113 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > > +/*
> > > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > > + * Author: James.Qian.Wang <[email protected]>
> > > > + *
> > > > + */
> > > > +#ifndef _KOMEDA_KMS_H_
> > > > +#define _KOMEDA_KMS_H_
> > > > +
> > > > +#include <drm/drm_atomic.h>
> > > > +#include <drm/drm_atomic_helper.h>
> > > > +#include <drm/drm_crtc_helper.h>
> > > > +#include <drm/drm_writeback.h>
> > > > +
> > > > +/** struct komeda_plane - komeda instance of drm_plane */
> > > > +struct komeda_plane {
> > > > + /** @base: &drm_plane */
> > > > + struct drm_plane base;
> > > > + /**
> > > > + * @layer:
> > > > + *
> > > > + * represents available layer input pipelines for this plane.
> > > > + *
> > > > + * NOTE:
> > > > + * the layer is not for a specific Layer, but indicate a group of
> > > > + * Layers with same capabilities.
> > > > + */
> > > > + struct komeda_layer *layer;
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct komeda_plane_state
> > > > + *
> > > > + * The plane_state can be split into two data flow (left/right) and handled
> > > > + * by two layers &komeda_plane.layer and &komeda_plane.layer.right
> > > > + */
> > > > +struct komeda_plane_state {
> > > > + /** @base: &drm_plane_state */
> > > > + struct drm_plane_state base;
> > > > +
> > > > + /* private properties */
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct komeda_wb_connector
> > > > + */
> > > > +struct komeda_wb_connector {
> > > > + /** @base: &drm_writeback_connector */
> > > > + struct drm_writeback_connector base;
> > > > +
> > > > + /** @wb_layer: represents associated writeback pipeline of komeda */
> > > > + struct komeda_layer *wb_layer;
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct komeda_crtc
> > > > + */
> > > > +struct komeda_crtc {
> > > > + /** @base: &drm_crtc */
> > > > + struct drm_crtc base;
> > > > + /** @master: only master has display output */
> > > > + struct komeda_pipeline *master;
> > > > + /**
> > > > + * @slave: optional
> > > > + *
> > > > + * Doesn't have its own display output, the handled data flow will
> > > > + * merge into the master.
> > > > + */
> > > > + struct komeda_pipeline *slave;
> > > > +};
> > > > +
> > > > +/** struct komeda_crtc_state */
> > > > +struct komeda_crtc_state {
> > > > + /** @base: &drm_crtc_state */
> > > > + struct drm_crtc_state base;
> > > > +
> > > > + /* private properties */
> > > > +
> > > > + /* computed state which are used by validate/check */
> > > > + u32 affected_pipes;
> > > > + u32 active_pipes;
> > > > +};
> > > > +
> > > > +/** struct komeda_kms_dev - for gather KMS related things */
> > > > +struct komeda_kms_dev {
> > > > + /** @base: &drm_device */
> > > > + struct drm_device base;
> > > > +
> > > > + /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
> > > > + int n_crtcs;
> > > > + /** @crtcs: crtcs list */
> > > > + struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
> > > > +};
> > > > +
> > > > +#define to_kplane(p) container_of(p, struct komeda_plane, base)
> > > > +#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
> > > > +#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
> > > > +#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
> > > > +#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
> > > > +#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
> > > > +
> > > > +int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > > +
> > > > +int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
> > > > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > > > + struct komeda_dev *mdev);
> > > > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
> > > > +
> > > > +struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
> > > > +void komeda_kms_detach(struct komeda_kms_dev *kms);
> > > > +
> > > > +#endif /*_KOMEDA_KMS_H_*/
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > > index 2d68ffeae25d..114129d96851 100644
> > > > --- a/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
> > > > @@ -333,6 +333,9 @@ struct komeda_pipeline_state {
> > > > #define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
> > > > #define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
> > > >
> > > > +#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
> > > > +#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
> > > > +
> > > > /* pipeline APIs */
> > > > struct komeda_pipeline *
> > > > komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_plane.c b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > > new file mode 100644
> > > > index 000000000000..0a4953a9a909
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_plane.c
> > > > @@ -0,0 +1,109 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > > + * Author: James.Qian.Wang <[email protected]>
> > > > + *
> > > > + */
> > > > +#include <drm/drm_atomic.h>
> > > > +#include <drm/drm_atomic_helper.h>
> > > > +#include <drm/drm_plane_helper.h>
> > > > +#include "komeda_dev.h"
> > > > +#include "komeda_kms.h"
> > > > +
> > > > +static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
> > > > +};
> > > > +
> > > > +static void komeda_plane_destroy(struct drm_plane *plane)
> > > > +{
> > > > + drm_plane_cleanup(plane);
> > > > +
> > > > + kfree(to_kplane(plane));
> > > > +}
> > > > +
> > > > +static const struct drm_plane_funcs komeda_plane_funcs = {
> > > > +};
> > > > +
> > > > +/* for komeda, which is pipeline can be share between crtcs */
> > > > +static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
> > > > + struct komeda_pipeline *pipe)
> > > > +{
> > > > + struct komeda_crtc *crtc;
> > > > + u32 possible_crtcs = 0;
> > > > + int i;
> > > > +
> > > > + for (i = 0; i < kms->n_crtcs; i++) {
> > > > + crtc = &kms->crtcs[i];
> > > > +
> > > > + if ((pipe == crtc->master) || (pipe == crtc->slave))
> > > > + possible_crtcs |= BIT(i);
> > > > + }
> > > > +
> > > > + return possible_crtcs;
> > > > +}
> > > > +
> > > > +/* use Layer0 as primary */
> > > > +static u32 get_plane_type(struct komeda_kms_dev *kms,
> > > > + struct komeda_component *c)
> > > > +{
> > > > + bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
> > > > +
> > > > + return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
> > > > +}
> > > > +
> > > > +static int komeda_plane_add(struct komeda_kms_dev *kms,
> > > > + struct komeda_layer *layer)
> > > > +{
> > > > + struct komeda_dev *mdev = kms->base.dev_private;
> > > > + struct komeda_component *c = &layer->base;
> > > > + struct komeda_plane *kplane;
> > > > + struct drm_plane *plane;
> > > > + u32 *formats, n_formats = 0;
> > > > + int err;
> > > > +
> > > > + kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
> > > > + if (!kplane)
> > > > + return -ENOMEM;
> > > > +
> > > > + plane = &kplane->base;
> > > > + kplane->layer = layer;
> > > > +
> > > > + formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
> > > > + layer->layer_type, &n_formats);
> > > > +
> > > > + err = drm_universal_plane_init(&kms->base, plane,
> > > > + get_possible_crtcs(kms, c->pipeline),
> > > > + &komeda_plane_funcs,
> > > > + formats, n_formats, NULL,
> > > > + get_plane_type(kms, c),
> > > > + "%s", c->name);
> > > > +
> > > > + komeda_put_fourcc_list(formats);
> > > > +
> > > > + if (err)
> > > > + goto cleanup;
> > > > +
> > > > + drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
> > > > +
> > > > + return 0;
> > > > +cleanup:
> > > > + komeda_plane_destroy(plane);
> > > > + return err;
> > > > +}
> > > > +
> > > > +int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
> > > > +{
> > > > + struct komeda_pipeline *pipe;
> > > > + int i, j, err;
> > > > +
> > > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > > + pipe = mdev->pipelines[i];
> > > > +
> > > > + for (j = 0; j < pipe->n_layers; j++) {
> > > > + err = komeda_plane_add(kms, pipe->layers[j]);
> > > > + if (err)
> > > > + return err;
> > > > + }
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > > > new file mode 100644
> > > > index 000000000000..9edfd6ab0c12
> > > > --- /dev/null
> > > > +++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
> > > > @@ -0,0 +1,88 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
> > > > + * Author: James.Qian.Wang <[email protected]>
> > > > + *
> > > > + */
> > > > +#include "komeda_dev.h"
> > > > +#include "komeda_kms.h"
> > > > +
> > > > +static struct drm_private_state *
> > > > +komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
> > > > +{
> > > > + struct komeda_pipeline_state *st;
> > > > +
> > > > + st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
> > > > + if (!st)
> > > > + return NULL;
> > > > +
> > > > + st->active_comps = 0;
> > > > +
> > > > + __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
> > > > +
> > > > + return &st->obj;
> > > > +}
> > > > +
> > > > +static void
> > > > +komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
> > > > + struct drm_private_state *state)
> > > > +{
> > > > + kfree(priv_to_pipe_st(state));
> > > > +}
> > > > +
> > > > +static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
> > > > + .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
> > > > + .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
> > > > +};
> > > > +
> > > > +static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
> > > > + struct komeda_pipeline *pipe)
> > > > +{
> > > > + struct komeda_pipeline_state *st;
> > > > +
> > > > + st = kzalloc(sizeof(*st), GFP_KERNEL);
> > > > + if (!st)
> > > > + return -ENOMEM;
> > > > +
> > > > + st->pipe = pipe;
> > > > + drm_atomic_private_obj_init(&pipe->obj, &st->obj,
> > > > + &komeda_pipeline_obj_funcs);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
> > > > + struct komeda_dev *mdev)
> > > > +{
> > > > + struct komeda_pipeline *pipe;
> > > > + int i, err;
> > > > +
> > > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > > + pipe = mdev->pipelines[i];
> > > > +
> > > > + err = komeda_pipeline_obj_add(kms, pipe);
> > > > + if (err)
> > > > + return err;
> > > > +
> > > > + /* Add component */
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
> > > > +{
> > > > + struct komeda_pipeline *pipe;
> > > > + struct komeda_component *c;
> > > > + int i, id;
> > > > +
> > > > + for (i = 0; i < mdev->n_pipelines; i++) {
> > > > + pipe = mdev->pipelines[i];
> > > > + dp_for_each_set_bit(id, pipe->avail_comps) {
> > > > + c = komeda_pipeline_get_component(pipe, id);
> > > > +
> > > > + drm_atomic_private_obj_fini(&c->obj);
> > > > + }
> > > > + drm_atomic_private_obj_fini(&pipe->obj);
> > > > + }
> > > > +}
> > > > --
> > > > 2.17.1
> > > >
> > >
> > > Reviewed-by: Liviu Dudau <[email protected]>
> > >
> > > Best regards,
> > > Liviu
> > >
> > >
> > > --
> > > ====================
> > > | I would like to |
> > > | fix the world, |
> > > | but they're not |
> > > | giving me the |
> > > \ source code! /
> > > ---------------
> > > ¯\_(ツ)_/¯
>
> --
> ====================
> | I would like to |
> | fix the world, |
> | but they're not |
> | giving me the |
> \ source code! /
> ---------------
> ¯\_(ツ)_/¯

2018-12-28 20:09:38

by James Qian Wang

[permalink] [raw]
Subject: Re: [PATCH v3 9/9] MAINTAINERS: Add maintainer for arm komeda driver

On Mon, Dec 24, 2018 at 02:05:43PM +0100, Daniel Vetter wrote:
> On Mon, Dec 24, 2018 at 1:33 PM Liviu Dudau <[email protected]> wrote:
> >
> > On Fri, Dec 21, 2018 at 10:01:06AM +0000, james qian wang (Arm Technology China) wrote:
> > > v2: Adjusted the position of KOMEDA by alphabetical order
> > >
> > > Signed-off-by: James (Qian) Wang <[email protected]>
> >
> > Acked-by: Liviu Dudau <[email protected]>
> >
> > Best regards,
> > Liviu
> >
> > > ---
> > > MAINTAINERS | 9 +++++++++
> > > 1 file changed, 9 insertions(+)
> > >
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index 254b7b267731..e48c2e5fd29f 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -1124,6 +1124,15 @@ S: Supported
> > > F: drivers/gpu/drm/arm/hdlcd_*
> > > F: Documentation/devicetree/bindings/display/arm,hdlcd.txt
> > >
> > > +ARM KOMEDA DRM-KMS DRIVER
> > > +M: James (Qian) Wang <[email protected]>
> > > +M: Mali DP Maintainers <[email protected]>
> > > +S: Supported
> > > +F: drivers/gpu/drm/arm/display/include/
> > > +F: drivers/gpu/drm/arm/display/komeda/
> > > +F: Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> > > +F: Documentation/gpu/komeda-kms.rst
>
> Mentioning the git tree would be good. And I guess you'll do some kind
> of group maintainership? Probably still good if you send out a
> dedicated/topic pull request for this new driver, but from then on
> it's all in the same git repo.
> -Daniel

Hi Daniel:

The komeda driver will use an Arm-hosted tree:

git git://linux-arm.org/linux-ld.git for-upstream/mali-dp

Same as other arm display drivers. And Liviu Dudau will help to send the pull
request to merge this topic into drm-next.

And we are planning to adopt a group maintainership and migrate towards drm-misc-next,
but we just need to have enough people and enough experience with working with upstream
before we jump all in.

Last a T: entry will be added in the next version.

T: git git://linux-arm.org/linux-ld.git for-upstream/mali-dp

James

> > > +
> > > ARM MALI-DP DRM DRIVER
> > > M: Liviu Dudau <[email protected]>
> > > M: Brian Starkey <[email protected]>
> > > --
> > > 2.17.1
> > >
> >
> > --
> > ====================
> > | I would like to |
> > | fix the world, |
> > | but they're not |
> > | giving me the |
> > \ source code! /
> > ---------------
> > ¯\_(ツ)_/¯
>
>
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

2018-12-28 21:32:31

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH v3 9/9] MAINTAINERS: Add maintainer for arm komeda driver

On Fri, Dec 28, 2018 at 12:15 PM james qian wang (Arm Technology
China) <[email protected]> wrote:
>
> On Mon, Dec 24, 2018 at 02:05:43PM +0100, Daniel Vetter wrote:
> > On Mon, Dec 24, 2018 at 1:33 PM Liviu Dudau <[email protected]> wrote:
> > >
> > > On Fri, Dec 21, 2018 at 10:01:06AM +0000, james qian wang (Arm Technology China) wrote:
> > > > v2: Adjusted the position of KOMEDA by alphabetical order
> > > >
> > > > Signed-off-by: James (Qian) Wang <[email protected]>
> > >
> > > Acked-by: Liviu Dudau <[email protected]>
> > >
> > > Best regards,
> > > Liviu
> > >
> > > > ---
> > > > MAINTAINERS | 9 +++++++++
> > > > 1 file changed, 9 insertions(+)
> > > >
> > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > index 254b7b267731..e48c2e5fd29f 100644
> > > > --- a/MAINTAINERS
> > > > +++ b/MAINTAINERS
> > > > @@ -1124,6 +1124,15 @@ S: Supported
> > > > F: drivers/gpu/drm/arm/hdlcd_*
> > > > F: Documentation/devicetree/bindings/display/arm,hdlcd.txt
> > > >
> > > > +ARM KOMEDA DRM-KMS DRIVER
> > > > +M: James (Qian) Wang <[email protected]>
> > > > +M: Mali DP Maintainers <[email protected]>
> > > > +S: Supported
> > > > +F: drivers/gpu/drm/arm/display/include/
> > > > +F: drivers/gpu/drm/arm/display/komeda/
> > > > +F: Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> > > > +F: Documentation/gpu/komeda-kms.rst
> >
> > Mentioning the git tree would be good. And I guess you'll do some kind
> > of group maintainership? Probably still good if you send out a
> > dedicated/topic pull request for this new driver, but from then on
> > it's all in the same git repo.
> > -Daniel
>
> Hi Daniel:
>
> The komeda driver will use an Arm-hosted tree:
>
> git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
>
> Same as other arm display drivers. And Liviu Dudau will help to send the pull
> request to merge this topic into drm-next.
>
> And we are planning to adopt a group maintainership and migrate towards drm-misc-next,
> but we just need to have enough people and enough experience with working with upstream
> before we jump all in.

arm drivers are probably a bit too big for drm-misc, but you could use
the same tooling to maintain a drm-arm tree. I guess that's the idea?
-Daniel

> Last a T: entry will be added in the next version.
>
> T: git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
>
> James
>
> > > > +
> > > > ARM MALI-DP DRM DRIVER
> > > > M: Liviu Dudau <[email protected]>
> > > > M: Brian Starkey <[email protected]>
> > > > --
> > > > 2.17.1
> > > >
> > >
> > > --
> > > ====================
> > > | I would like to |
> > > | fix the world, |
> > > | but they're not |
> > > | giving me the |
> > > \ source code! /
> > > ---------------
> > > ¯\_(ツ)_/¯
> >
> >
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > +41 (0) 79 365 57 48 - http://blog.ffwll.ch



--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

2018-12-29 05:28:37

by Liviu Dudau

[permalink] [raw]
Subject: Re: [PATCH v3 9/9] MAINTAINERS: Add maintainer for arm komeda driver

On Fri, Dec 28, 2018 at 12:56:27PM +0100, Daniel Vetter wrote:
> On Fri, Dec 28, 2018 at 12:15 PM james qian wang (Arm Technology
> China) <[email protected]> wrote:
> >
> > On Mon, Dec 24, 2018 at 02:05:43PM +0100, Daniel Vetter wrote:
> > > On Mon, Dec 24, 2018 at 1:33 PM Liviu Dudau <[email protected]> wrote:
> > > >
> > > > On Fri, Dec 21, 2018 at 10:01:06AM +0000, james qian wang (Arm Technology China) wrote:
> > > > > v2: Adjusted the position of KOMEDA by alphabetical order
> > > > >
> > > > > Signed-off-by: James (Qian) Wang <[email protected]>
> > > >
> > > > Acked-by: Liviu Dudau <[email protected]>
> > > >
> > > > Best regards,
> > > > Liviu
> > > >
> > > > > ---
> > > > > MAINTAINERS | 9 +++++++++
> > > > > 1 file changed, 9 insertions(+)
> > > > >
> > > > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > > > index 254b7b267731..e48c2e5fd29f 100644
> > > > > --- a/MAINTAINERS
> > > > > +++ b/MAINTAINERS
> > > > > @@ -1124,6 +1124,15 @@ S: Supported
> > > > > F: drivers/gpu/drm/arm/hdlcd_*
> > > > > F: Documentation/devicetree/bindings/display/arm,hdlcd.txt
> > > > >
> > > > > +ARM KOMEDA DRM-KMS DRIVER
> > > > > +M: James (Qian) Wang <[email protected]>
> > > > > +M: Mali DP Maintainers <[email protected]>
> > > > > +S: Supported
> > > > > +F: drivers/gpu/drm/arm/display/include/
> > > > > +F: drivers/gpu/drm/arm/display/komeda/
> > > > > +F: Documentation/devicetree/bindings/display/arm/arm,komeda.txt
> > > > > +F: Documentation/gpu/komeda-kms.rst
> > >
> > > Mentioning the git tree would be good. And I guess you'll do some kind
> > > of group maintainership? Probably still good if you send out a
> > > dedicated/topic pull request for this new driver, but from then on
> > > it's all in the same git repo.
> > > -Daniel
> >
> > Hi Daniel:
> >
> > The komeda driver will use an Arm-hosted tree:
> >
> > git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
> >
> > Same as other arm display drivers. And Liviu Dudau will help to send the pull
> > request to merge this topic into drm-next.
> >
> > And we are planning to adopt a group maintainership and migrate towards drm-misc-next,
> > but we just need to have enough people and enough experience with working with upstream
> > before we jump all in.
>
> arm drivers are probably a bit too big for drm-misc, but you could use
> the same tooling to maintain a drm-arm tree. I guess that's the idea?

Yes, the long term plan is to have the same process. We're just at the
early steps right now, where we're getting weened off internal tools had
bad habits :)

Best regards,
Liviu

> -Daniel
>
> > Last a T: entry will be added in the next version.
> >
> > T: git git://linux-arm.org/linux-ld.git for-upstream/mali-dp
> >
> > James
> >
> > > > > +
> > > > > ARM MALI-DP DRM DRIVER
> > > > > M: Liviu Dudau <[email protected]>
> > > > > M: Brian Starkey <[email protected]>
> > > > > --
> > > > > 2.17.1
> > > > >
> > > >
> > >
> > > --
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > +41 (0) 79 365 57 48 - http://blog.ffwll.ch
>
>
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯