aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/arm/Kconfig12
-rw-r--r--drivers/gpu/drm/arm/Makefile1
-rw-r--r--drivers/gpu/drm/arm/display/Kbuild3
-rw-r--r--drivers/gpu/drm/arm/display/Kconfig14
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_io.h42
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_product.h23
-rw-r--r--drivers/gpu/drm/arm/display/include/malidp_utils.h16
-rw-r--r--drivers/gpu/drm/arm/display/komeda/Makefile21
-rw-r--r--drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c111
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_crtc.c106
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_dev.c186
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_dev.h110
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_drv.c144
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_format_caps.c75
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_format_caps.h89
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c165
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h34
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.c167
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_kms.h113
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c200
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h359
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_plane.c109
-rw-r--r--drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c88
24 files changed, 2183 insertions, 7 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ce8d1d384319..f0c1f8731a27 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -51,7 +51,7 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
51obj-$(CONFIG_DRM) += drm.o 51obj-$(CONFIG_DRM) += drm.o
52obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o 52obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
53obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o 53obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
54obj-$(CONFIG_DRM_ARM) += arm/ 54obj-y += arm/
55obj-$(CONFIG_DRM_TTM) += ttm/ 55obj-$(CONFIG_DRM_TTM) += ttm/
56obj-$(CONFIG_DRM_SCHED) += scheduler/ 56obj-$(CONFIG_DRM_SCHED) += scheduler/
57obj-$(CONFIG_DRM_TDFX) += tdfx/ 57obj-$(CONFIG_DRM_TDFX) += tdfx/
diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index 9a18e1bd57b4..a204103b3efb 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -1,13 +1,10 @@
1config DRM_ARM 1# SPDX-License-Identifier: GPL-2.0
2 bool 2menu "ARM devices"
3 help
4 Choose this option to select drivers for ARM's devices
5 3
6config DRM_HDLCD 4config DRM_HDLCD
7 tristate "ARM HDLCD" 5 tristate "ARM HDLCD"
8 depends on DRM && OF && (ARM || ARM64) 6 depends on DRM && OF && (ARM || ARM64)
9 depends on COMMON_CLK 7 depends on COMMON_CLK
10 select DRM_ARM
11 select DRM_KMS_HELPER 8 select DRM_KMS_HELPER
12 select DRM_KMS_CMA_HELPER 9 select DRM_KMS_CMA_HELPER
13 help 10 help
@@ -29,7 +26,6 @@ config DRM_MALI_DISPLAY
29 tristate "ARM Mali Display Processor" 26 tristate "ARM Mali Display Processor"
30 depends on DRM && OF && (ARM || ARM64) 27 depends on DRM && OF && (ARM || ARM64)
31 depends on COMMON_CLK 28 depends on COMMON_CLK
32 select DRM_ARM
33 select DRM_KMS_HELPER 29 select DRM_KMS_HELPER
34 select DRM_KMS_CMA_HELPER 30 select DRM_KMS_CMA_HELPER
35 select DRM_GEM_CMA_HELPER 31 select DRM_GEM_CMA_HELPER
@@ -40,3 +36,7 @@ config DRM_MALI_DISPLAY
40 of the hardware. 36 of the hardware.
41 37
42 If compiled as a module it will be called mali-dp. 38 If compiled as a module it will be called mali-dp.
39
40source "drivers/gpu/drm/arm/display/Kconfig"
41
42endmenu
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
3mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o 3mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o
4mali-dp-y += malidp_mw.o 4mali-dp-y += malidp_mw.o
5obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o 5obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o
6obj-$(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 @@
1# SPDX-License-Identifier: GPL-2.0
2
3obj-$(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 @@
1# SPDX-License-Identifier: GPL-2.0
2config DRM_KOMEDA
3 tristate "ARM Komeda display driver"
4 depends on DRM && OF
5 depends on COMMON_CLK
6 select DRM_KMS_HELPER
7 select DRM_KMS_CMA_HELPER
8 select DRM_GEM_CMA_HELPER
9 select VIDEOMODE_HELPERS
10 help
11 Choose this option if you want to compile the ARM Komeda display
12 Processor driver. It supports the D71 variants of the hardware.
13
14 If compiled as a module it will be called komeda.
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 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _MALIDP_IO_H_
8#define _MALIDP_IO_H_
9
10#include <linux/io.h>
11
12static inline u32
13malidp_read32(u32 __iomem *base, u32 offset)
14{
15 return readl((base + (offset >> 2)));
16}
17
18static inline void
19malidp_write32(u32 __iomem *base, u32 offset, u32 v)
20{
21 writel(v, (base + (offset >> 2)));
22}
23
24static inline void
25malidp_write32_mask(u32 __iomem *base, u32 offset, u32 m, u32 v)
26{
27 u32 tmp = malidp_read32(base, offset);
28
29 tmp &= (~m);
30 malidp_write32(base, offset, v | tmp);
31}
32
33static inline void
34malidp_write_group(u32 __iomem *base, u32 offset, int num, const u32 *values)
35{
36 int i;
37
38 for (i = 0; i < num; i++)
39 malidp_write32(base, offset + i * 4, values[i]);
40}
41
42#endif /*_MALIDP_IO_H_*/
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 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _MALIDP_PRODUCT_H_
8#define _MALIDP_PRODUCT_H_
9
10/* Product identification */
11#define MALIDP_CORE_ID(__product, __major, __minor, __status) \
12 ((((__product) & 0xFFFF) << 16) | (((__major) & 0xF) << 12) | \
13 (((__minor) & 0xF) << 8) | ((__status) & 0xFF))
14
15#define MALIDP_CORE_ID_PRODUCT_ID(__core_id) ((__u32)(__core_id) >> 16)
16#define MALIDP_CORE_ID_MAJOR(__core_id) (((__u32)(__core_id) >> 12) & 0xF)
17#define MALIDP_CORE_ID_MINOR(__core_id) (((__u32)(__core_id) >> 8) & 0xF)
18#define MALIDP_CORE_ID_STATUS(__core_id) (((__u32)(__core_id)) & 0xFF)
19
20/* Mali-display product IDs */
21#define MALIDP_D71_PRODUCT_ID 0x0071
22
23#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 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _MALIDP_UTILS_
8#define _MALIDP_UTILS_
9
10#define has_bit(nr, mask) (BIT(nr) & (mask))
11#define has_bits(bits, mask) (((bits) & (mask)) == (bits))
12
13#define dp_for_each_set_bit(bit, mask) \
14 for_each_set_bit((bit), ((unsigned long *)&(mask)), sizeof(mask) * 8)
15
16#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..1b875e5dc0f6
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/Makefile
@@ -0,0 +1,21 @@
1# SPDX-License-Identifier: GPL-2.0
2
3ccflags-y := \
4 -I$(src)/../include \
5 -I$(src)
6
7komeda-y := \
8 komeda_drv.o \
9 komeda_dev.o \
10 komeda_format_caps.o \
11 komeda_pipeline.o \
12 komeda_framebuffer.o \
13 komeda_kms.o \
14 komeda_crtc.o \
15 komeda_plane.o \
16 komeda_private_obj.o
17
18komeda-y += \
19 d71/d71_dev.o
20
21obj-$(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..edbf9daa1545
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/d71/d71_dev.c
@@ -0,0 +1,111 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include "malidp_io.h"
8#include "komeda_dev.h"
9
10static int d71_enum_resources(struct komeda_dev *mdev)
11{
12 /* TODO add enum resources */
13 return -1;
14}
15
16#define __HW_ID(__group, __format) \
17 ((((__group) & 0x7) << 3) | ((__format) & 0x7))
18
19#define RICH KOMEDA_FMT_RICH_LAYER
20#define SIMPLE KOMEDA_FMT_SIMPLE_LAYER
21#define RICH_SIMPLE (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_SIMPLE_LAYER)
22#define RICH_WB (KOMEDA_FMT_RICH_LAYER | KOMEDA_FMT_WB_LAYER)
23#define RICH_SIMPLE_WB (RICH_SIMPLE | KOMEDA_FMT_WB_LAYER)
24
25#define Rot_0 DRM_MODE_ROTATE_0
26#define Flip_H_V (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | Rot_0)
27#define Rot_ALL_H_V (DRM_MODE_ROTATE_MASK | Flip_H_V)
28
29#define LYT_NM BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)
30#define LYT_WB BIT(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
31#define LYT_NM_WB (LYT_NM | LYT_WB)
32
33#define AFB_TH AFBC(_TILED | _SPARSE)
34#define AFB_TH_SC_YTR AFBC(_TILED | _SC | _SPARSE | _YTR)
35#define AFB_TH_SC_YTR_BS AFBC(_TILED | _SC | _SPARSE | _YTR | _SPLIT)
36
37static struct komeda_format_caps d71_format_caps_table[] = {
38 /* HW_ID | fourcc | tile_sz | layer_types | rots | afbc_layouts | afbc_features */
39 /* ABGR_2101010*/
40 {__HW_ID(0, 0), DRM_FORMAT_ARGB2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
41 {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
42 {__HW_ID(0, 1), DRM_FORMAT_ABGR2101010, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
43 {__HW_ID(0, 2), DRM_FORMAT_RGBA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
44 {__HW_ID(0, 3), DRM_FORMAT_BGRA1010102, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
45 /* ABGR_8888*/
46 {__HW_ID(1, 0), DRM_FORMAT_ARGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
47 {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
48 {__HW_ID(1, 1), DRM_FORMAT_ABGR8888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
49 {__HW_ID(1, 2), DRM_FORMAT_RGBA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
50 {__HW_ID(1, 3), DRM_FORMAT_BGRA8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
51 /* XBGB_8888 */
52 {__HW_ID(2, 0), DRM_FORMAT_XRGB8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
53 {__HW_ID(2, 1), DRM_FORMAT_XBGR8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
54 {__HW_ID(2, 2), DRM_FORMAT_RGBX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
55 {__HW_ID(2, 3), DRM_FORMAT_BGRX8888, 1, RICH_SIMPLE_WB, Flip_H_V, 0, 0},
56 /* BGR_888 */ /* none-afbc RGB888 doesn't support rotation and flip */
57 {__HW_ID(3, 0), DRM_FORMAT_RGB888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
58 {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE_WB, Rot_0, 0, 0},
59 {__HW_ID(3, 1), DRM_FORMAT_BGR888, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR_BS}, /* afbc */
60 /* BGR 16bpp */
61 {__HW_ID(4, 0), DRM_FORMAT_RGBA5551, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
62 {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
63 {__HW_ID(4, 1), DRM_FORMAT_ABGR1555, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
64 {__HW_ID(4, 2), DRM_FORMAT_RGB565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
65 {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Flip_H_V, 0, 0},
66 {__HW_ID(4, 3), DRM_FORMAT_BGR565, 1, RICH_SIMPLE, Rot_ALL_H_V, LYT_NM_WB, AFB_TH_SC_YTR}, /* afbc */
67 {__HW_ID(4, 4), DRM_FORMAT_R8, 1, SIMPLE, Rot_0, 0, 0},
68 /* YUV 444/422/420 8bit */
69 {__HW_ID(5, 0), 0 /*XYUV8888*/, 1, 0, 0, 0, 0},
70 /* XYUV unsupported*/
71 {__HW_ID(5, 1), DRM_FORMAT_YUYV, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
72 {__HW_ID(5, 2), DRM_FORMAT_YUYV, 1, RICH, Flip_H_V, 0, 0},
73 {__HW_ID(5, 3), DRM_FORMAT_UYVY, 1, RICH, Flip_H_V, 0, 0},
74 {__HW_ID(5, 4), 0, /*X0L0 */ 2, 0, 0, 0}, /* Y0L0 unsupported */
75 {__HW_ID(5, 6), DRM_FORMAT_NV12, 1, RICH, Flip_H_V, 0, 0},
76 {__HW_ID(5, 6), 0/*DRM_FORMAT_YUV420_8BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH}, /* afbc */
77 {__HW_ID(5, 7), DRM_FORMAT_YUV420, 1, RICH, Flip_H_V, 0, 0},
78 /* YUV 10bit*/
79 {__HW_ID(6, 0), 0,/*XVYU2101010*/ 1, 0, 0, 0, 0},/* VYV30 unsupported */
80 {__HW_ID(6, 6), 0/*DRM_FORMAT_X0L2*/, 2, RICH, Flip_H_V, 0, 0},
81 {__HW_ID(6, 7), 0/*DRM_FORMAT_P010*/, 1, RICH, Flip_H_V, 0, 0},
82 {__HW_ID(6, 7), 0/*DRM_FORMAT_YUV420_10BIT*/, 1, RICH, Rot_ALL_H_V, LYT_NM, AFB_TH},
83};
84
85static void d71_init_fmt_tbl(struct komeda_dev *mdev)
86{
87 struct komeda_format_caps_table *table = &mdev->fmt_tbl;
88
89 table->format_caps = d71_format_caps_table;
90 table->n_formats = ARRAY_SIZE(d71_format_caps_table);
91}
92
93static struct komeda_dev_funcs d71_chip_funcs = {
94 .init_format_table = d71_init_fmt_tbl,
95 .enum_resources = d71_enum_resources,
96 .cleanup = NULL,
97};
98
99#define GLB_ARCH_ID 0x000
100#define GLB_CORE_ID 0x004
101#define GLB_CORE_INFO 0x008
102
103struct komeda_dev_funcs *
104d71_identify(u32 __iomem *reg_base, struct komeda_chip_info *chip)
105{
106 chip->arch_id = malidp_read32(reg_base, GLB_ARCH_ID);
107 chip->core_id = malidp_read32(reg_base, GLB_CORE_ID);
108 chip->core_info = malidp_read32(reg_base, GLB_CORE_INFO);
109
110 return &d71_chip_funcs;
111}
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 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/clk.h>
8#include <linux/spinlock.h>
9#include <drm/drm_atomic.h>
10#include <drm/drm_atomic_helper.h>
11#include <drm/drm_plane_helper.h>
12#include <drm/drm_crtc_helper.h>
13#include <linux/pm_runtime.h>
14#include "komeda_dev.h"
15#include "komeda_kms.h"
16
17struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = {
18};
19
20static const struct drm_crtc_funcs komeda_crtc_funcs = {
21};
22
23int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms,
24 struct komeda_dev *mdev)
25{
26 struct komeda_crtc *crtc;
27 struct komeda_pipeline *master;
28 char str[16];
29 int i;
30
31 kms->n_crtcs = 0;
32
33 for (i = 0; i < mdev->n_pipelines; i++) {
34 crtc = &kms->crtcs[kms->n_crtcs];
35 master = mdev->pipelines[i];
36
37 crtc->master = master;
38 crtc->slave = NULL;
39
40 if (crtc->slave)
41 sprintf(str, "pipe-%d", crtc->slave->id);
42 else
43 sprintf(str, "None");
44
45 DRM_INFO("crtc%d: master(pipe-%d) slave(%s) output: %s.\n",
46 kms->n_crtcs, master->id, str,
47 master->of_output_dev ?
48 master->of_output_dev->full_name : "None");
49
50 kms->n_crtcs++;
51 }
52
53 return 0;
54}
55
56static struct drm_plane *
57get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc)
58{
59 struct komeda_plane *kplane;
60 struct drm_plane *plane;
61
62 drm_for_each_plane(plane, &kms->base) {
63 if (plane->type != DRM_PLANE_TYPE_PRIMARY)
64 continue;
65
66 kplane = to_kplane(plane);
67 /* only master can be primary */
68 if (kplane->layer->base.pipeline == crtc->master)
69 return plane;
70 }
71
72 return NULL;
73}
74
75static int komeda_crtc_add(struct komeda_kms_dev *kms,
76 struct komeda_crtc *kcrtc)
77{
78 struct drm_crtc *crtc = &kcrtc->base;
79 int err;
80
81 err = drm_crtc_init_with_planes(&kms->base, crtc,
82 get_crtc_primary(kms, kcrtc), NULL,
83 &komeda_crtc_funcs, NULL);
84 if (err)
85 return err;
86
87 drm_crtc_helper_add(crtc, &komeda_crtc_helper_funcs);
88 drm_crtc_vblank_reset(crtc);
89
90 crtc->port = kcrtc->master->of_output_port;
91
92 return 0;
93}
94
95int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
96{
97 int i, err;
98
99 for (i = 0; i < kms->n_crtcs; i++) {
100 err = komeda_crtc_add(kms, &kms->crtcs[i]);
101 if (err)
102 return err;
103 }
104
105 return 0;
106}
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..0fe6954fbbf4
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
@@ -0,0 +1,186 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/platform_device.h>
8#include <linux/of_device.h>
9#include <linux/of_graph.h>
10#include "komeda_dev.h"
11
12static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
13{
14 struct komeda_pipeline *pipe;
15 struct clk *clk;
16 u32 pipe_id;
17 int ret = 0;
18
19 ret = of_property_read_u32(np, "reg", &pipe_id);
20 if (ret != 0 || pipe_id >= mdev->n_pipelines)
21 return -EINVAL;
22
23 pipe = mdev->pipelines[pipe_id];
24
25 clk = of_clk_get_by_name(np, "aclk");
26 if (IS_ERR(clk)) {
27 DRM_ERROR("get aclk for pipeline %d failed!\n", pipe_id);
28 return PTR_ERR(clk);
29 }
30 pipe->aclk = clk;
31
32 clk = of_clk_get_by_name(np, "pxclk");
33 if (IS_ERR(clk)) {
34 DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id);
35 return PTR_ERR(clk);
36 }
37 pipe->pxlclk = clk;
38
39 /* enum ports */
40 pipe->of_output_dev =
41 of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
42 pipe->of_output_port =
43 of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
44
45 pipe->of_node = np;
46
47 return 0;
48}
49
50static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
51{
52 struct device_node *child, *np = dev->of_node;
53 struct clk *clk;
54 int ret;
55
56 clk = devm_clk_get(dev, "mclk");
57 if (IS_ERR(clk))
58 return PTR_ERR(clk);
59
60 mdev->mclk = clk;
61
62 for_each_available_child_of_node(np, child) {
63 if (of_node_cmp(child->name, "pipeline") == 0) {
64 ret = komeda_parse_pipe_dt(mdev, child);
65 if (ret) {
66 DRM_ERROR("parse pipeline dt error!\n");
67 of_node_put(child);
68 break;
69 }
70 }
71 }
72
73 return ret;
74}
75
76struct komeda_dev *komeda_dev_create(struct device *dev)
77{
78 struct platform_device *pdev = to_platform_device(dev);
79 const struct komeda_product_data *product;
80 struct komeda_dev *mdev;
81 struct resource *io_res;
82 int err = 0;
83
84 product = of_device_get_match_data(dev);
85 if (!product)
86 return ERR_PTR(-ENODEV);
87
88 io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
89 if (!io_res) {
90 DRM_ERROR("No registers defined.\n");
91 return ERR_PTR(-ENODEV);
92 }
93
94 mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);
95 if (!mdev)
96 return ERR_PTR(-ENOMEM);
97
98 mdev->dev = dev;
99 mdev->reg_base = devm_ioremap_resource(dev, io_res);
100 if (IS_ERR(mdev->reg_base)) {
101 DRM_ERROR("Map register space failed.\n");
102 err = PTR_ERR(mdev->reg_base);
103 mdev->reg_base = NULL;
104 goto err_cleanup;
105 }
106
107 mdev->pclk = devm_clk_get(dev, "pclk");
108 if (IS_ERR(mdev->pclk)) {
109 DRM_ERROR("Get APB clk failed.\n");
110 err = PTR_ERR(mdev->pclk);
111 mdev->pclk = NULL;
112 goto err_cleanup;
113 }
114
115 /* Enable APB clock to access the registers */
116 clk_prepare_enable(mdev->pclk);
117
118 mdev->funcs = product->identify(mdev->reg_base, &mdev->chip);
119 if (!komeda_product_match(mdev, product->product_id)) {
120 DRM_ERROR("DT configured %x mismatch with real HW %x.\n",
121 product->product_id,
122 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id));
123 err = -ENODEV;
124 goto err_cleanup;
125 }
126
127 DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
128 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),
129 MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
130 MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
131
132 mdev->funcs->init_format_table(mdev);
133
134 err = mdev->funcs->enum_resources(mdev);
135 if (err) {
136 DRM_ERROR("enumerate display resource failed.\n");
137 goto err_cleanup;
138 }
139
140 err = komeda_parse_dt(dev, mdev);
141 if (err) {
142 DRM_ERROR("parse device tree failed.\n");
143 goto err_cleanup;
144 }
145
146 return mdev;
147
148err_cleanup:
149 komeda_dev_destroy(mdev);
150 return ERR_PTR(err);
151}
152
153void komeda_dev_destroy(struct komeda_dev *mdev)
154{
155 struct device *dev = mdev->dev;
156 struct komeda_dev_funcs *funcs = mdev->funcs;
157 int i;
158
159 for (i = 0; i < mdev->n_pipelines; i++) {
160 komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
161 mdev->pipelines[i] = NULL;
162 }
163
164 mdev->n_pipelines = 0;
165
166 if (funcs && funcs->cleanup)
167 funcs->cleanup(mdev);
168
169 if (mdev->reg_base) {
170 devm_iounmap(dev, mdev->reg_base);
171 mdev->reg_base = NULL;
172 }
173
174 if (mdev->mclk) {
175 devm_clk_put(dev, mdev->mclk);
176 mdev->mclk = NULL;
177 }
178
179 if (mdev->pclk) {
180 clk_disable_unprepare(mdev->pclk);
181 devm_clk_put(dev, mdev->pclk);
182 mdev->pclk = NULL;
183 }
184
185 devm_kfree(dev, mdev);
186}
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..0f77dead6a23
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h
@@ -0,0 +1,110 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_DEV_H_
8#define _KOMEDA_DEV_H_
9
10#include <linux/device.h>
11#include <linux/clk.h>
12#include "komeda_pipeline.h"
13#include "malidp_product.h"
14#include "komeda_format_caps.h"
15
16/* malidp device id */
17enum {
18 MALI_D71 = 0,
19};
20
21/* pipeline DT ports */
22enum {
23 KOMEDA_OF_PORT_OUTPUT = 0,
24 KOMEDA_OF_PORT_COPROC = 1,
25};
26
27struct komeda_chip_info {
28 u32 arch_id;
29 u32 core_id;
30 u32 core_info;
31 u32 bus_width;
32};
33
34struct komeda_product_data {
35 u32 product_id;
36 struct komeda_dev_funcs *(*identify)(u32 __iomem *reg,
37 struct komeda_chip_info *info);
38};
39
40struct komeda_dev;
41
42/**
43 * struct komeda_dev_funcs
44 *
45 * Supplied by chip level and returned by the chip entry function xxx_identify,
46 */
47struct komeda_dev_funcs {
48 /**
49 * @init_format_table:
50 *
51 * initialize &komeda_dev->format_table, this function should be called
52 * before the &enum_resource
53 */
54 void (*init_format_table)(struct komeda_dev *mdev);
55 /**
56 * @enum_resources:
57 *
58 * for CHIP to report or add pipeline and component resources to CORE
59 */
60 int (*enum_resources)(struct komeda_dev *mdev);
61 /** @cleanup: call to chip to cleanup komeda_dev->chip data */
62 void (*cleanup)(struct komeda_dev *mdev);
63};
64
65/**
66 * struct komeda_dev
67 *
68 * Pipeline and component are used to describe how to handle the pixel data.
69 * komeda_device is for describing the whole view of the device, and the
70 * control-abilites of device.
71 */
72struct komeda_dev {
73 struct device *dev;
74 u32 __iomem *reg_base;
75
76 struct komeda_chip_info chip;
77 /** @fmt_tbl: initialized by &komeda_dev_funcs->init_format_table */
78 struct komeda_format_caps_table fmt_tbl;
79 /** @pclk: APB clock for register access */
80 struct clk *pclk;
81 /** @mck: HW main engine clk */
82 struct clk *mclk;
83
84 int n_pipelines;
85 struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES];
86
87 /** @funcs: chip funcs to access to HW */
88 struct komeda_dev_funcs *funcs;
89 /**
90 * @chip_data:
91 *
92 * chip data will be added by &komeda_dev_funcs.enum_resources() and
93 * destroyed by &komeda_dev_funcs.cleanup()
94 */
95 void *chip_data;
96};
97
98static inline bool
99komeda_product_match(struct komeda_dev *mdev, u32 target)
100{
101 return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target;
102}
103
104struct komeda_dev_funcs *
105d71_identify(u32 __iomem *reg, struct komeda_chip_info *chip);
106
107struct komeda_dev *komeda_dev_create(struct device *dev);
108void komeda_dev_destroy(struct komeda_dev *mdev);
109
110#endif /*_KOMEDA_DEV_H_*/
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..2bdd189b041d
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c
@@ -0,0 +1,144 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/module.h>
8#include <linux/kernel.h>
9#include <linux/platform_device.h>
10#include <linux/component.h>
11#include <drm/drm_of.h>
12#include "komeda_dev.h"
13#include "komeda_kms.h"
14
15struct komeda_drv {
16 struct komeda_dev *mdev;
17 struct komeda_kms_dev *kms;
18};
19
20static void komeda_unbind(struct device *dev)
21{
22 struct komeda_drv *mdrv = dev_get_drvdata(dev);
23
24 if (!mdrv)
25 return;
26
27 komeda_kms_detach(mdrv->kms);
28 komeda_dev_destroy(mdrv->mdev);
29
30 dev_set_drvdata(dev, NULL);
31 devm_kfree(dev, mdrv);
32}
33
34static int komeda_bind(struct device *dev)
35{
36 struct komeda_drv *mdrv;
37 int err;
38
39 mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
40 if (!mdrv)
41 return -ENOMEM;
42
43 mdrv->mdev = komeda_dev_create(dev);
44 if (IS_ERR(mdrv->mdev)) {
45 err = PTR_ERR(mdrv->mdev);
46 goto free_mdrv;
47 }
48
49 mdrv->kms = komeda_kms_attach(mdrv->mdev);
50 if (IS_ERR(mdrv->kms)) {
51 err = PTR_ERR(mdrv->kms);
52 goto destroy_mdev;
53 }
54
55 dev_set_drvdata(dev, mdrv);
56
57 return 0;
58
59destroy_mdev:
60 komeda_dev_destroy(mdrv->mdev);
61
62free_mdrv:
63 devm_kfree(dev, mdrv);
64 return err;
65}
66
67static const struct component_master_ops komeda_master_ops = {
68 .bind = komeda_bind,
69 .unbind = komeda_unbind,
70};
71
72static int compare_of(struct device *dev, void *data)
73{
74 return dev->of_node == data;
75}
76
77static void komeda_add_slave(struct device *master,
78 struct component_match **match,
79 struct device_node *np, int port)
80{
81 struct device_node *remote;
82
83 remote = of_graph_get_remote_node(np, port, 0);
84 if (remote) {
85 drm_of_component_match_add(master, match, compare_of, remote);
86 of_node_put(remote);
87 }
88}
89
90static int komeda_platform_probe(struct platform_device *pdev)
91{
92 struct device *dev = &pdev->dev;
93 struct component_match *match = NULL;
94 struct device_node *child;
95
96 if (!dev->of_node)
97 return -ENODEV;
98
99 for_each_available_child_of_node(dev->of_node, child) {
100 if (of_node_cmp(child->name, "pipeline") != 0)
101 continue;
102
103 /* add connector */
104 komeda_add_slave(dev, &match, child, KOMEDA_OF_PORT_OUTPUT);
105 }
106
107 return component_master_add_with_match(dev, &komeda_master_ops, match);
108}
109
110static int komeda_platform_remove(struct platform_device *pdev)
111{
112 component_master_del(&pdev->dev, &komeda_master_ops);
113 return 0;
114}
115
116static const struct komeda_product_data komeda_products[] = {
117 [MALI_D71] = {
118 .product_id = MALIDP_D71_PRODUCT_ID,
119 .identify = d71_identify,
120 },
121};
122
123const struct of_device_id komeda_of_match[] = {
124 { .compatible = "arm,mali-d71", .data = &komeda_products[MALI_D71], },
125 {},
126};
127
128MODULE_DEVICE_TABLE(of, komeda_of_match);
129
130static struct platform_driver komeda_platform_driver = {
131 .probe = komeda_platform_probe,
132 .remove = komeda_platform_remove,
133 .driver = {
134 .name = "komeda",
135 .of_match_table = komeda_of_match,
136 .pm = NULL,
137 },
138};
139
140module_platform_driver(komeda_platform_driver);
141
142MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>");
143MODULE_DESCRIPTION("Komeda KMS driver");
144MODULE_LICENSE("GPL v2");
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 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7
8#include <linux/slab.h>
9#include "komeda_format_caps.h"
10#include "malidp_utils.h"
11
12const struct komeda_format_caps *
13komeda_get_format_caps(struct komeda_format_caps_table *table,
14 u32 fourcc, u64 modifier)
15{
16 const struct komeda_format_caps *caps;
17 u64 afbc_features = modifier & ~(AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
18 u32 afbc_layout = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
19 int id;
20
21 for (id = 0; id < table->n_formats; id++) {
22 caps = &table->format_caps[id];
23
24 if (fourcc != caps->fourcc)
25 continue;
26
27 if ((modifier == 0ULL) && (caps->supported_afbc_layouts == 0))
28 return caps;
29
30 if (has_bits(afbc_features, caps->supported_afbc_features) &&
31 has_bit(afbc_layout, caps->supported_afbc_layouts))
32 return caps;
33 }
34
35 return NULL;
36}
37
38u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
39 u32 layer_type, u32 *n_fmts)
40{
41 const struct komeda_format_caps *cap;
42 u32 *fmts;
43 int i, j, n = 0;
44
45 fmts = kcalloc(table->n_formats, sizeof(u32), GFP_KERNEL);
46 if (!fmts)
47 return NULL;
48
49 for (i = 0; i < table->n_formats; i++) {
50 cap = &table->format_caps[i];
51 if (!(layer_type & cap->supported_layer_types) ||
52 (cap->fourcc == 0))
53 continue;
54
55 /* one fourcc may has two caps items in table (afbc/none-afbc),
56 * so check the existing list to avoid adding a duplicated one.
57 */
58 for (j = n - 1; j >= 0; j--)
59 if (fmts[j] == cap->fourcc)
60 break;
61
62 if (j < 0)
63 fmts[n++] = cap->fourcc;
64 }
65
66 if (n_fmts)
67 *n_fmts = n;
68
69 return fmts;
70}
71
72void komeda_put_fourcc_list(u32 *fourcc_list)
73{
74 kfree(fourcc_list);
75}
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 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7
8#ifndef _KOMEDA_FORMAT_CAPS_H_
9#define _KOMEDA_FORMAT_CAPS_H_
10
11#include <linux/types.h>
12#include <uapi/drm/drm_fourcc.h>
13#include <drm/drm_fourcc.h>
14
15#define AFBC(x) DRM_FORMAT_MOD_ARM_AFBC(x)
16
17/* afbc layerout */
18#define AFBC_16x16(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | (x))
19#define AFBC_32x8(x) AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | (x))
20
21/* afbc features */
22#define _YTR AFBC_FORMAT_MOD_YTR
23#define _SPLIT AFBC_FORMAT_MOD_SPLIT
24#define _SPARSE AFBC_FORMAT_MOD_SPARSE
25#define _CBR AFBC_FORMAT_MOD_CBR
26#define _TILED AFBC_FORMAT_MOD_TILED
27#define _SC AFBC_FORMAT_MOD_SC
28
29/* layer_type */
30#define KOMEDA_FMT_RICH_LAYER BIT(0)
31#define KOMEDA_FMT_SIMPLE_LAYER BIT(1)
32#define KOMEDA_FMT_WB_LAYER BIT(2)
33
34#define AFBC_TH_LAYOUT_ALIGNMENT 8
35#define AFBC_HEADER_SIZE 16
36#define AFBC_SUPERBLK_ALIGNMENT 128
37#define AFBC_SUPERBLK_PIXELS 256
38#define AFBC_BODY_START_ALIGNMENT 1024
39#define AFBC_TH_BODY_START_ALIGNMENT 4096
40
41/**
42 * struct komeda_format_caps
43 *
44 * komeda_format_caps is for describing ARM display specific features and
45 * limitations for a specific format, and format_caps will be linked into
46 * &komeda_framebuffer like a extension of &drm_format_info.
47 *
48 * NOTE: one fourcc may has two different format_caps items for fourcc and
49 * fourcc+modifier
50 *
51 * @hw_id: hw format id, hw specific value.
52 * @fourcc: drm fourcc format.
53 * @tile_size: format tiled size, used by ARM format X0L0/X0L2
54 * @supported_layer_types: indicate which layer supports this format
55 * @supported_rots: allowed rotations for this format
56 * @supported_afbc_layouts: supported afbc layerout
57 * @supported_afbc_features: supported afbc features
58 */
59struct komeda_format_caps {
60 u32 hw_id;
61 u32 fourcc;
62 u32 tile_size;
63 u32 supported_layer_types;
64 u32 supported_rots;
65 u32 supported_afbc_layouts;
66 u64 supported_afbc_features;
67};
68
69/**
70 * struct komeda_format_caps_table - format_caps mananger
71 *
72 * @n_formats: the size of format_caps list.
73 * @format_caps: format_caps list.
74 */
75struct komeda_format_caps_table {
76 u32 n_formats;
77 const struct komeda_format_caps *format_caps;
78};
79
80const struct komeda_format_caps *
81komeda_get_format_caps(struct komeda_format_caps_table *table,
82 u32 fourcc, u64 modifier);
83
84u32 *komeda_get_layer_fourcc_list(struct komeda_format_caps_table *table,
85 u32 layer_type, u32 *n_fmts);
86
87void komeda_put_fourcc_list(u32 *fourcc_list);
88
89#endif
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..23ee74d42239
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c
@@ -0,0 +1,165 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <drm/drm_gem.h>
8#include <drm/drm_gem_framebuffer_helper.h>
9#include <drm/drm_fb_cma_helper.h>
10#include <drm/drm_gem_cma_helper.h>
11#include "komeda_framebuffer.h"
12#include "komeda_dev.h"
13
14static void komeda_fb_destroy(struct drm_framebuffer *fb)
15{
16 struct komeda_fb *kfb = to_kfb(fb);
17 u32 i;
18
19 for (i = 0; i < fb->format->num_planes; i++)
20 drm_gem_object_put_unlocked(fb->obj[i]);
21
22 drm_framebuffer_cleanup(fb);
23 kfree(kfb);
24}
25
26static int komeda_fb_create_handle(struct drm_framebuffer *fb,
27 struct drm_file *file, u32 *handle)
28{
29 return drm_gem_handle_create(file, fb->obj[0], handle);
30}
31
32static const struct drm_framebuffer_funcs komeda_fb_funcs = {
33 .destroy = komeda_fb_destroy,
34 .create_handle = komeda_fb_create_handle,
35};
36
37static int
38komeda_fb_none_afbc_size_check(struct komeda_dev *mdev, struct komeda_fb *kfb,
39 struct drm_file *file,
40 const struct drm_mode_fb_cmd2 *mode_cmd)
41{
42 struct drm_framebuffer *fb = &kfb->base;
43 struct drm_gem_object *obj;
44 u32 min_size = 0;
45 u32 i;
46
47 for (i = 0; i < fb->format->num_planes; i++) {
48 obj = drm_gem_object_lookup(file, mode_cmd->handles[i]);
49 if (!obj) {
50 DRM_DEBUG_KMS("Failed to lookup GEM object\n");
51 fb->obj[i] = NULL;
52
53 return -ENOENT;
54 }
55
56 kfb->aligned_w = fb->width / (i ? fb->format->hsub : 1);
57 kfb->aligned_h = fb->height / (i ? fb->format->vsub : 1);
58
59 if (fb->pitches[i] % mdev->chip.bus_width) {
60 DRM_DEBUG_KMS("Pitch[%d]: 0x%x doesn't align to 0x%x\n",
61 i, fb->pitches[i], mdev->chip.bus_width);
62 drm_gem_object_put_unlocked(obj);
63 fb->obj[i] = NULL;
64
65 return -EINVAL;
66 }
67
68 min_size = ((kfb->aligned_h / kfb->format_caps->tile_size - 1)
69 * fb->pitches[i])
70 + (kfb->aligned_w * fb->format->cpp[i]
71 * kfb->format_caps->tile_size)
72 + fb->offsets[i];
73
74 if (obj->size < min_size) {
75 DRM_DEBUG_KMS("Fail to check none afbc fb size.\n");
76 drm_gem_object_put_unlocked(obj);
77 fb->obj[i] = NULL;
78
79 return -EINVAL;
80 }
81
82 fb->obj[i] = obj;
83 }
84
85 if (fb->format->num_planes == 3) {
86 if (fb->pitches[1] != fb->pitches[2]) {
87 DRM_DEBUG_KMS("The pitch[1] and [2] are not same\n");
88 return -EINVAL;
89 }
90 }
91
92 return 0;
93}
94
95struct drm_framebuffer *
96komeda_fb_create(struct drm_device *dev, struct drm_file *file,
97 const struct drm_mode_fb_cmd2 *mode_cmd)
98{
99 struct komeda_dev *mdev = dev->dev_private;
100 struct komeda_fb *kfb;
101 int ret = 0, i;
102
103 kfb = kzalloc(sizeof(*kfb), GFP_KERNEL);
104 if (!kfb)
105 return ERR_PTR(-ENOMEM);
106
107 kfb->format_caps = komeda_get_format_caps(&mdev->fmt_tbl,
108 mode_cmd->pixel_format,
109 mode_cmd->modifier[0]);
110 if (!kfb->format_caps) {
111 DRM_DEBUG_KMS("FMT %x is not supported.\n",
112 mode_cmd->pixel_format);
113 kfree(kfb);
114 return ERR_PTR(-EINVAL);
115 }
116
117 drm_helper_mode_fill_fb_struct(dev, &kfb->base, mode_cmd);
118
119 ret = komeda_fb_none_afbc_size_check(mdev, kfb, file, mode_cmd);
120 if (ret < 0)
121 goto err_cleanup;
122
123 ret = drm_framebuffer_init(dev, &kfb->base, &komeda_fb_funcs);
124 if (ret < 0) {
125 DRM_DEBUG_KMS("failed to initialize fb\n");
126
127 goto err_cleanup;
128 }
129
130 return &kfb->base;
131
132err_cleanup:
133 for (i = 0; i < kfb->base.format->num_planes; i++)
134 drm_gem_object_put_unlocked(kfb->base.obj[i]);
135
136 kfree(kfb);
137 return ERR_PTR(ret);
138}
139
140dma_addr_t
141komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane)
142{
143 struct drm_framebuffer *fb = &kfb->base;
144 const struct drm_gem_cma_object *obj;
145 u32 plane_x, plane_y, cpp, pitch, offset;
146
147 if (plane >= fb->format->num_planes) {
148 DRM_DEBUG_KMS("Out of max plane num.\n");
149 return -EINVAL;
150 }
151
152 obj = drm_fb_cma_get_gem_obj(fb, plane);
153
154 offset = fb->offsets[plane];
155 if (!fb->modifier) {
156 plane_x = x / (plane ? fb->format->hsub : 1);
157 plane_y = y / (plane ? fb->format->vsub : 1);
158 cpp = fb->format->cpp[plane];
159 pitch = fb->pitches[plane];
160 offset += plane_x * cpp * kfb->format_caps->tile_size +
161 (plane_y * pitch) / kfb->format_caps->tile_size;
162 }
163
164 return obj->paddr + offset;
165}
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..0de2e4a2afd2
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h
@@ -0,0 +1,34 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_FRAMEBUFFER_H_
8#define _KOMEDA_FRAMEBUFFER_H_
9
10#include <drm/drm_framebuffer.h>
11#include "komeda_format_caps.h"
12
13/** struct komeda_fb - entend drm_framebuffer with komeda attribute */
14struct komeda_fb {
15 /** @base: &drm_framebuffer */
16 struct drm_framebuffer base;
17 /* @format_caps: &komeda_format_caps */
18 const struct komeda_format_caps *format_caps;
19 /** @aligned_w: aligned frame buffer width */
20 u32 aligned_w;
21 /** @aligned_h: aligned frame buffer height */
22 u32 aligned_h;
23};
24
25#define to_kfb(dfb) container_of(dfb, struct komeda_fb, base)
26
27struct drm_framebuffer *
28komeda_fb_create(struct drm_device *dev, struct drm_file *file,
29 const struct drm_mode_fb_cmd2 *mode_cmd);
30dma_addr_t
31komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane);
32bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type);
33
34#endif
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..3fc096d3883e
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c
@@ -0,0 +1,167 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <linux/component.h>
8#include <drm/drm_atomic.h>
9#include <drm/drm_atomic_helper.h>
10#include <drm/drm_gem_framebuffer_helper.h>
11#include <drm/drm_gem_cma_helper.h>
12#include <drm/drm_fb_helper.h>
13#include <linux/interrupt.h>
14#include "komeda_dev.h"
15#include "komeda_kms.h"
16#include "komeda_framebuffer.h"
17
18DEFINE_DRM_GEM_CMA_FOPS(komeda_cma_fops);
19
20static int komeda_gem_cma_dumb_create(struct drm_file *file,
21 struct drm_device *dev,
22 struct drm_mode_create_dumb *args)
23{
24 u32 alignment = 16; /* TODO get alignment from dev */
25
26 args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
27 alignment);
28
29 return drm_gem_cma_dumb_create_internal(file, dev, args);
30}
31
32static struct drm_driver komeda_kms_driver = {
33 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
34 DRIVER_PRIME,
35 .lastclose = drm_fb_helper_lastclose,
36 .gem_free_object_unlocked = drm_gem_cma_free_object,
37 .gem_vm_ops = &drm_gem_cma_vm_ops,
38 .dumb_create = komeda_gem_cma_dumb_create,
39 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
40 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
41 .gem_prime_export = drm_gem_prime_export,
42 .gem_prime_import = drm_gem_prime_import,
43 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
44 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
45 .gem_prime_vmap = drm_gem_cma_prime_vmap,
46 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
47 .gem_prime_mmap = drm_gem_cma_prime_mmap,
48 .fops = &komeda_cma_fops,
49 .name = "komeda",
50 .desc = "Arm Komeda Display Processor driver",
51 .date = "20181101",
52 .major = 0,
53 .minor = 1,
54};
55
56static void komeda_kms_commit_tail(struct drm_atomic_state *old_state)
57{
58 struct drm_device *dev = old_state->dev;
59
60 drm_atomic_helper_commit_modeset_disables(dev, old_state);
61
62 drm_atomic_helper_commit_planes(dev, old_state, 0);
63
64 drm_atomic_helper_commit_modeset_enables(dev, old_state);
65
66 drm_atomic_helper_wait_for_flip_done(dev, old_state);
67
68 drm_atomic_helper_commit_hw_done(old_state);
69
70 drm_atomic_helper_cleanup_planes(dev, old_state);
71}
72
73static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
74 .atomic_commit_tail = komeda_kms_commit_tail,
75};
76
77static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
78 .fb_create = komeda_fb_create,
79 .atomic_check = drm_atomic_helper_check,
80 .atomic_commit = drm_atomic_helper_commit,
81};
82
83static void komeda_kms_mode_config_init(struct komeda_kms_dev *kms,
84 struct komeda_dev *mdev)
85{
86 struct drm_mode_config *config = &kms->base.mode_config;
87
88 drm_mode_config_init(&kms->base);
89
90 komeda_kms_setup_crtcs(kms, mdev);
91
92 /* Get value from dev */
93 config->min_width = 0;
94 config->min_height = 0;
95 config->max_width = 4096;
96 config->max_height = 4096;
97 config->allow_fb_modifiers = false;
98
99 config->funcs = &komeda_mode_config_funcs;
100 config->helper_private = &komeda_mode_config_helpers;
101}
102
103struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
104{
105 struct komeda_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
106 struct drm_device *drm;
107 int err;
108
109 if (!kms)
110 return ERR_PTR(-ENOMEM);
111
112 drm = &kms->base;
113 err = drm_dev_init(drm, &komeda_kms_driver, mdev->dev);
114 if (err)
115 goto free_kms;
116
117 drm->dev_private = mdev;
118
119 komeda_kms_mode_config_init(kms, mdev);
120
121 err = komeda_kms_add_private_objs(kms, mdev);
122 if (err)
123 goto cleanup_mode_config;
124
125 err = komeda_kms_add_planes(kms, mdev);
126 if (err)
127 goto cleanup_mode_config;
128
129 err = drm_vblank_init(drm, kms->n_crtcs);
130 if (err)
131 goto cleanup_mode_config;
132
133 err = komeda_kms_add_crtcs(kms, mdev);
134 if (err)
135 goto cleanup_mode_config;
136
137 err = component_bind_all(mdev->dev, kms);
138 if (err)
139 goto cleanup_mode_config;
140
141 drm_mode_config_reset(drm);
142
143 err = drm_dev_register(drm, 0);
144 if (err)
145 goto cleanup_mode_config;
146
147 return kms;
148
149cleanup_mode_config:
150 drm_mode_config_cleanup(drm);
151free_kms:
152 kfree(kms);
153 return ERR_PTR(err);
154}
155
156void komeda_kms_detach(struct komeda_kms_dev *kms)
157{
158 struct drm_device *drm = &kms->base;
159 struct komeda_dev *mdev = drm->dev_private;
160
161 drm_dev_unregister(drm);
162 component_unbind_all(mdev->dev, drm);
163 komeda_kms_cleanup_private_objs(mdev);
164 drm_mode_config_cleanup(drm);
165 drm->dev_private = NULL;
166 drm_dev_put(drm);
167}
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 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_KMS_H_
8#define _KOMEDA_KMS_H_
9
10#include <drm/drm_atomic.h>
11#include <drm/drm_atomic_helper.h>
12#include <drm/drm_crtc_helper.h>
13#include <drm/drm_writeback.h>
14
15/** struct komeda_plane - komeda instance of drm_plane */
16struct komeda_plane {
17 /** @base: &drm_plane */
18 struct drm_plane base;
19 /**
20 * @layer:
21 *
22 * represents available layer input pipelines for this plane.
23 *
24 * NOTE:
25 * the layer is not for a specific Layer, but indicate a group of
26 * Layers with same capabilities.
27 */
28 struct komeda_layer *layer;
29};
30
31/**
32 * struct komeda_plane_state
33 *
34 * The plane_state can be split into two data flow (left/right) and handled
35 * by two layers &komeda_plane.layer and &komeda_plane.layer.right
36 */
37struct komeda_plane_state {
38 /** @base: &drm_plane_state */
39 struct drm_plane_state base;
40
41 /* private properties */
42};
43
44/**
45 * struct komeda_wb_connector
46 */
47struct komeda_wb_connector {
48 /** @base: &drm_writeback_connector */
49 struct drm_writeback_connector base;
50
51 /** @wb_layer: represents associated writeback pipeline of komeda */
52 struct komeda_layer *wb_layer;
53};
54
55/**
56 * struct komeda_crtc
57 */
58struct komeda_crtc {
59 /** @base: &drm_crtc */
60 struct drm_crtc base;
61 /** @master: only master has display output */
62 struct komeda_pipeline *master;
63 /**
64 * @slave: optional
65 *
66 * Doesn't have its own display output, the handled data flow will
67 * merge into the master.
68 */
69 struct komeda_pipeline *slave;
70};
71
72/** struct komeda_crtc_state */
73struct komeda_crtc_state {
74 /** @base: &drm_crtc_state */
75 struct drm_crtc_state base;
76
77 /* private properties */
78
79 /* computed state which are used by validate/check */
80 u32 affected_pipes;
81 u32 active_pipes;
82};
83
84/** struct komeda_kms_dev - for gather KMS related things */
85struct komeda_kms_dev {
86 /** @base: &drm_device */
87 struct drm_device base;
88
89 /** @n_crtcs: valid numbers of crtcs in &komeda_kms_dev.crtcs */
90 int n_crtcs;
91 /** @crtcs: crtcs list */
92 struct komeda_crtc crtcs[KOMEDA_MAX_PIPELINES];
93};
94
95#define to_kplane(p) container_of(p, struct komeda_plane, base)
96#define to_kplane_st(p) container_of(p, struct komeda_plane_state, base)
97#define to_kconn(p) container_of(p, struct komeda_wb_connector, base)
98#define to_kcrtc(p) container_of(p, struct komeda_crtc, base)
99#define to_kcrtc_st(p) container_of(p, struct komeda_crtc_state, base)
100#define to_kdev(p) container_of(p, struct komeda_kms_dev, base)
101
102int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
103
104int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
105int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev);
106int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
107 struct komeda_dev *mdev);
108void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev);
109
110struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev);
111void komeda_kms_detach(struct komeda_kms_dev *kms);
112
113#endif /*_KOMEDA_KMS_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..edb1cd7795f9
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
@@ -0,0 +1,200 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include "komeda_dev.h"
8#include "komeda_pipeline.h"
9
10/** komeda_pipeline_add - Add a pipeline to &komeda_dev */
11struct komeda_pipeline *
12komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
13 struct komeda_pipeline_funcs *funcs)
14{
15 struct komeda_pipeline *pipe;
16
17 if (mdev->n_pipelines + 1 > KOMEDA_MAX_PIPELINES) {
18 DRM_ERROR("Exceed max support %d pipelines.\n",
19 KOMEDA_MAX_PIPELINES);
20 return NULL;
21 }
22
23 if (size < sizeof(*pipe)) {
24 DRM_ERROR("Request pipeline size too small.\n");
25 return NULL;
26 }
27
28 pipe = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
29 if (!pipe)
30 return NULL;
31
32 pipe->mdev = mdev;
33 pipe->id = mdev->n_pipelines;
34 pipe->funcs = funcs;
35
36 mdev->pipelines[mdev->n_pipelines] = pipe;
37 mdev->n_pipelines++;
38
39 return pipe;
40}
41
42void komeda_pipeline_destroy(struct komeda_dev *mdev,
43 struct komeda_pipeline *pipe)
44{
45 struct komeda_component *c;
46 int i;
47
48 dp_for_each_set_bit(i, pipe->avail_comps) {
49 c = komeda_pipeline_get_component(pipe, i);
50 komeda_component_destroy(mdev, c);
51 }
52
53 clk_put(pipe->pxlclk);
54 clk_put(pipe->aclk);
55
56 of_node_put(pipe->of_output_dev);
57 of_node_put(pipe->of_output_port);
58 of_node_put(pipe->of_node);
59
60 devm_kfree(mdev->dev, pipe);
61}
62
63struct komeda_component **
64komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id)
65{
66 struct komeda_dev *mdev = pipe->mdev;
67 struct komeda_pipeline *temp = NULL;
68 struct komeda_component **pos = NULL;
69
70 switch (id) {
71 case KOMEDA_COMPONENT_LAYER0:
72 case KOMEDA_COMPONENT_LAYER1:
73 case KOMEDA_COMPONENT_LAYER2:
74 case KOMEDA_COMPONENT_LAYER3:
75 pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]);
76 break;
77 case KOMEDA_COMPONENT_WB_LAYER:
78 pos = to_cpos(pipe->wb_layer);
79 break;
80 case KOMEDA_COMPONENT_COMPIZ0:
81 case KOMEDA_COMPONENT_COMPIZ1:
82 temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0];
83 if (!temp) {
84 DRM_ERROR("compiz-%d doesn't exist.\n", id);
85 return NULL;
86 }
87 pos = to_cpos(temp->compiz);
88 break;
89 case KOMEDA_COMPONENT_SCALER0:
90 case KOMEDA_COMPONENT_SCALER1:
91 pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]);
92 break;
93 case KOMEDA_COMPONENT_IPS0:
94 case KOMEDA_COMPONENT_IPS1:
95 temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0];
96 if (!temp) {
97 DRM_ERROR("ips-%d doesn't exist.\n", id);
98 return NULL;
99 }
100 pos = to_cpos(temp->improc);
101 break;
102 case KOMEDA_COMPONENT_TIMING_CTRLR:
103 pos = to_cpos(pipe->ctrlr);
104 break;
105 default:
106 pos = NULL;
107 DRM_ERROR("Unknown pipeline resource ID: %d.\n", id);
108 break;
109 }
110
111 return pos;
112}
113
114struct komeda_component *
115komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id)
116{
117 struct komeda_component **pos = NULL;
118 struct komeda_component *c = NULL;
119
120 pos = komeda_pipeline_get_component_pos(pipe, id);
121 if (pos)
122 c = *pos;
123
124 return c;
125}
126
127/** komeda_component_add - Add a component to &komeda_pipeline */
128struct komeda_component *
129komeda_component_add(struct komeda_pipeline *pipe,
130 size_t comp_sz, u32 id, u32 hw_id,
131 struct komeda_component_funcs *funcs,
132 u8 max_active_inputs, u32 supported_inputs,
133 u8 max_active_outputs, u32 __iomem *reg,
134 const char *name_fmt, ...)
135{
136 struct komeda_component **pos;
137 struct komeda_component *c;
138 int idx, *num = NULL;
139
140 if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) {
141 WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n",
142 max_active_inputs);
143 return NULL;
144 }
145
146 pos = komeda_pipeline_get_component_pos(pipe, id);
147 if (!pos || (*pos))
148 return NULL;
149
150 if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) {
151 idx = id - KOMEDA_COMPONENT_LAYER0;
152 num = &pipe->n_layers;
153 if (idx != pipe->n_layers) {
154 DRM_ERROR("please add Layer by id sequence.\n");
155 return NULL;
156 }
157 } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) {
158 idx = id - KOMEDA_COMPONENT_SCALER0;
159 num = &pipe->n_scalers;
160 if (idx != pipe->n_scalers) {
161 DRM_ERROR("please add Scaler by id sequence.\n");
162 return NULL;
163 }
164 }
165
166 c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL);
167 if (!c)
168 return NULL;
169
170 c->id = id;
171 c->hw_id = hw_id;
172 c->reg = reg;
173 c->pipeline = pipe;
174 c->max_active_inputs = max_active_inputs;
175 c->max_active_outputs = max_active_outputs;
176 c->supported_inputs = supported_inputs;
177 c->funcs = funcs;
178
179 if (name_fmt) {
180 va_list args;
181
182 va_start(args, name_fmt);
183 vsnprintf(c->name, sizeof(c->name), name_fmt, args);
184 va_end(args);
185 }
186
187 if (num)
188 *num = *num + 1;
189
190 pipe->avail_comps |= BIT(c->id);
191 *pos = c;
192
193 return c;
194}
195
196void komeda_component_destroy(struct komeda_dev *mdev,
197 struct komeda_component *c)
198{
199 devm_kfree(mdev->dev, c);
200}
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..8c950bc8ae96
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h
@@ -0,0 +1,359 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#ifndef _KOMEDA_PIPELINE_H_
8#define _KOMEDA_PIPELINE_H_
9
10#include <linux/types.h>
11#include <drm/drm_atomic.h>
12#include <drm/drm_atomic_helper.h>
13#include "malidp_utils.h"
14
15#define KOMEDA_MAX_PIPELINES 2
16#define KOMEDA_PIPELINE_MAX_LAYERS 4
17#define KOMEDA_PIPELINE_MAX_SCALERS 2
18#define KOMEDA_COMPONENT_N_INPUTS 5
19
20/* pipeline component IDs */
21enum {
22 KOMEDA_COMPONENT_LAYER0 = 0,
23 KOMEDA_COMPONENT_LAYER1 = 1,
24 KOMEDA_COMPONENT_LAYER2 = 2,
25 KOMEDA_COMPONENT_LAYER3 = 3,
26 KOMEDA_COMPONENT_WB_LAYER = 7, /* write back layer */
27 KOMEDA_COMPONENT_SCALER0 = 8,
28 KOMEDA_COMPONENT_SCALER1 = 9,
29 KOMEDA_COMPONENT_SPLITTER = 12,
30 KOMEDA_COMPONENT_MERGER = 14,
31 KOMEDA_COMPONENT_COMPIZ0 = 16, /* compositor */
32 KOMEDA_COMPONENT_COMPIZ1 = 17,
33 KOMEDA_COMPONENT_IPS0 = 20, /* post image processor */
34 KOMEDA_COMPONENT_IPS1 = 21,
35 KOMEDA_COMPONENT_TIMING_CTRLR = 22, /* timing controller */
36};
37
38#define KOMEDA_PIPELINE_LAYERS (BIT(KOMEDA_COMPONENT_LAYER0) |\
39 BIT(KOMEDA_COMPONENT_LAYER1) |\
40 BIT(KOMEDA_COMPONENT_LAYER2) |\
41 BIT(KOMEDA_COMPONENT_LAYER3))
42
43#define KOMEDA_PIPELINE_SCALERS (BIT(KOMEDA_COMPONENT_SCALER0) |\
44 BIT(KOMEDA_COMPONENT_SCALER1))
45
46#define KOMEDA_PIPELINE_COMPIZS (BIT(KOMEDA_COMPONENT_COMPIZ0) |\
47 BIT(KOMEDA_COMPONENT_COMPIZ1))
48
49#define KOMEDA_PIPELINE_IMPROCS (BIT(KOMEDA_COMPONENT_IPS0) |\
50 BIT(KOMEDA_COMPONENT_IPS1))
51struct komeda_component;
52struct komeda_component_state;
53
54/** komeda_component_funcs - component control functions */
55struct komeda_component_funcs {
56 /** @validate: optional,
57 * component may has special requirements or limitations, this function
58 * supply HW the ability to do the further HW specific check.
59 */
60 int (*validate)(struct komeda_component *c,
61 struct komeda_component_state *state);
62 /** @update: update is a active update */
63 void (*update)(struct komeda_component *c,
64 struct komeda_component_state *state);
65 /** @disable: disable component */
66 void (*disable)(struct komeda_component *c);
67 /** @dump_register: Optional, dump registers to seq_file */
68 void (*dump_register)(struct komeda_component *c, struct seq_file *seq);
69};
70
71/**
72 * struct komeda_component
73 *
74 * struct komeda_component describe the data flow capabilities for how to link a
75 * component into the display pipeline.
76 * all specified components are subclass of this structure.
77 */
78struct komeda_component {
79 /** @obj: treat component as private obj */
80 struct drm_private_obj obj;
81 /** @pipeline: the komeda pipeline this component belongs to */
82 struct komeda_pipeline *pipeline;
83 /** @name: component name */
84 char name[32];
85 /**
86 * @reg:
87 * component register base,
88 * which is initialized by chip and used by chip only
89 */
90 u32 __iomem *reg;
91 /** @id: component id */
92 u32 id;
93 /** @hw_ic: component hw id,
94 * which is initialized by chip and used by chip only
95 */
96 u32 hw_id;
97
98 /**
99 * @max_active_inputs:
100 * @max_active_outpus:
101 *
102 * maximum number of inputs/outputs that can be active in the same time
103 * Note:
104 * the number isn't the bit number of @supported_inputs or
105 * @supported_outputs, but may be less than it, since component may not
106 * support enabling all @supported_inputs/outputs at the same time.
107 */
108 u8 max_active_inputs;
109 u8 max_active_outputs;
110 /**
111 * @supported_inputs:
112 * @supported_outputs:
113 *
114 * bitmask of BIT(component->id) for the supported inputs/outputs
115 * describes the possibilities of how a component is linked into a
116 * pipeline.
117 */
118 u32 supported_inputs;
119 u32 supported_outputs;
120
121 /**
122 * @funcs: chip functions to access HW
123 */
124 struct komeda_component_funcs *funcs;
125};
126
127/**
128 * struct komeda_component_output
129 *
130 * a component has multiple outputs, if want to know where the data
131 * comes from, only know the component is not enough, we still need to know
132 * its output port
133 */
134struct komeda_component_output {
135 /** @component: indicate which component the data comes from */
136 struct komeda_component *component;
137 /** @output_port:
138 * the output port of the &komeda_component_output.component
139 */
140 u8 output_port;
141};
142
143/**
144 * struct komeda_component_state
145 *
146 * component_state is the data flow configuration of the component, and it's
147 * the superclass of all specific component_state like @komeda_layer_state,
148 * @komeda_scaler_state
149 */
150struct komeda_component_state {
151 /** @obj: tracking component_state by drm_atomic_state */
152 struct drm_private_state obj;
153 struct komeda_component *component;
154 /**
155 * @binding_user:
156 * currently bound user, the user can be crtc/plane/wb_conn, which is
157 * valid decided by @component and @inputs
158 *
159 * - Layer: its user always is plane.
160 * - compiz/improc/timing_ctrlr: the user is crtc.
161 * - wb_layer: wb_conn;
162 * - scaler: plane when input is layer, wb_conn if input is compiz.
163 */
164 union {
165 struct drm_crtc *crtc;
166 struct drm_plane *plane;
167 struct drm_connector *wb_conn;
168 void *binding_user;
169 };
170 /**
171 * @active_inputs:
172 *
173 * active_inputs is bitmask of @inputs index
174 *
175 * - active_inputs = changed_active_inputs + unchanged_active_inputs
176 * - affected_inputs = old->active_inputs + new->active_inputs;
177 * - disabling_inputs = affected_inputs ^ active_inputs;
178 * - changed_inputs = disabling_inputs + changed_active_inputs;
179 *
180 * NOTE:
181 * changed_inputs doesn't include all active_input but only
182 * @changed_active_inputs, and this bitmask can be used in chip
183 * level for dirty update.
184 */
185 u16 active_inputs;
186 u16 changed_active_inputs;
187 u16 affected_inputs;
188 /**
189 * @inputs:
190 *
191 * the specific inputs[i] only valid on BIT(i) has been set in
192 * @active_inputs, if not the inputs[i] is undefined.
193 */
194 struct komeda_component_output inputs[KOMEDA_COMPONENT_N_INPUTS];
195};
196
197static inline u16 component_disabling_inputs(struct komeda_component_state *st)
198{
199 return st->affected_inputs ^ st->active_inputs;
200}
201
202static inline u16 component_changed_inputs(struct komeda_component_state *st)
203{
204 return component_disabling_inputs(st) | st->changed_active_inputs;
205}
206
207#define to_comp(__c) (((__c) == NULL) ? NULL : &((__c)->base))
208#define to_cpos(__c) ((struct komeda_component **)&(__c))
209
210/* these structures are going to be filled in in uture patches */
211struct komeda_layer {
212 struct komeda_component base;
213 /* layer specific features and caps */
214 int layer_type; /* RICH, SIMPLE or WB */
215};
216
217struct komeda_layer_state {
218 struct komeda_component_state base;
219 /* layer specific configuration state */
220};
221
222struct komeda_compiz {
223 struct komeda_component base;
224 /* compiz specific features and caps */
225};
226
227struct komeda_compiz_state {
228 struct komeda_component_state base;
229 /* compiz specific configuration state */
230};
231
232struct komeda_scaler {
233 struct komeda_component base;
234 /* scaler features and caps */
235};
236
237struct komeda_scaler_state {
238 struct komeda_component_state base;
239};
240
241struct komeda_improc {
242 struct komeda_component base;
243};
244
245struct komeda_improc_state {
246 struct komeda_component_state base;
247};
248
249/* display timing controller */
250struct komeda_timing_ctrlr {
251 struct komeda_component base;
252};
253
254struct komeda_timing_ctrlr_state {
255 struct komeda_component_state base;
256};
257
258/** struct komeda_pipeline_funcs */
259struct komeda_pipeline_funcs {
260 /* dump_register: Optional, dump registers to seq_file */
261 void (*dump_register)(struct komeda_pipeline *pipe,
262 struct seq_file *sf);
263};
264
265/**
266 * struct komeda_pipeline
267 *
268 * Represent a complete display pipeline and hold all functional components.
269 */
270struct komeda_pipeline {
271 /** @obj: link pipeline as private obj of drm_atomic_state */
272 struct drm_private_obj obj;
273 /** @mdev: the parent komeda_dev */
274 struct komeda_dev *mdev;
275 /** @pxlclk: pixel clock */
276 struct clk *pxlclk;
277 /** @aclk: AXI clock */
278 struct clk *aclk;
279 /** @id: pipeline id */
280 int id;
281 /** @avail_comps: available components mask of pipeline */
282 u32 avail_comps;
283 int n_layers;
284 struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS];
285 int n_scalers;
286 struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS];
287 struct komeda_compiz *compiz;
288 struct komeda_layer *wb_layer;
289 struct komeda_improc *improc;
290 struct komeda_timing_ctrlr *ctrlr;
291 struct komeda_pipeline_funcs *funcs; /* private pipeline functions */
292
293 /** @of_node: pipeline dt node */
294 struct device_node *of_node;
295 /** @of_output_port: pipeline output port */
296 struct device_node *of_output_port;
297 /** @of_output_dev: output connector device node */
298 struct device_node *of_output_dev;
299};
300
301/**
302 * struct komeda_pipeline_state
303 *
304 * NOTE:
305 * Unlike the pipeline, pipeline_state doesn’t gather any component_state
306 * into it. It because all component will be managed by drm_atomic_state.
307 */
308struct komeda_pipeline_state {
309 /** @obj: tracking pipeline_state by drm_atomic_state */
310 struct drm_private_state obj;
311 struct komeda_pipeline *pipe;
312 /** @crtc: currently bound crtc */
313 struct drm_crtc *crtc;
314 /**
315 * @active_comps:
316 *
317 * bitmask - BIT(component->id) of active components
318 */
319 u32 active_comps;
320};
321
322#define to_layer(c) container_of(c, struct komeda_layer, base)
323#define to_compiz(c) container_of(c, struct komeda_compiz, base)
324#define to_scaler(c) container_of(c, struct komeda_scaler, base)
325#define to_improc(c) container_of(c, struct komeda_improc, base)
326#define to_ctrlr(c) container_of(c, struct komeda_timing_ctrlr, base)
327
328#define to_layer_st(c) container_of(c, struct komeda_layer_state, base)
329#define to_compiz_st(c) container_of(c, struct komeda_compiz_state, base)
330#define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base)
331#define to_improc_st(c) container_of(c, struct komeda_improc_state, base)
332#define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base)
333
334#define priv_to_comp_st(o) container_of(o, struct komeda_component_state, obj)
335#define priv_to_pipe_st(o) container_of(o, struct komeda_pipeline_state, obj)
336
337/* pipeline APIs */
338struct komeda_pipeline *
339komeda_pipeline_add(struct komeda_dev *mdev, size_t size,
340 struct komeda_pipeline_funcs *funcs);
341void komeda_pipeline_destroy(struct komeda_dev *mdev,
342 struct komeda_pipeline *pipe);
343
344struct komeda_component *
345komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
346
347/* component APIs */
348struct komeda_component *
349komeda_component_add(struct komeda_pipeline *pipe,
350 size_t comp_sz, u32 id, u32 hw_id,
351 struct komeda_component_funcs *funcs,
352 u8 max_active_inputs, u32 supported_inputs,
353 u8 max_active_outputs, u32 __iomem *reg,
354 const char *name_fmt, ...);
355
356void komeda_component_destroy(struct komeda_dev *mdev,
357 struct komeda_component *c);
358
359#endif /* _KOMEDA_PIPELINE_H_*/
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 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include <drm/drm_atomic.h>
8#include <drm/drm_atomic_helper.h>
9#include <drm/drm_plane_helper.h>
10#include "komeda_dev.h"
11#include "komeda_kms.h"
12
13static const struct drm_plane_helper_funcs komeda_plane_helper_funcs = {
14};
15
16static void komeda_plane_destroy(struct drm_plane *plane)
17{
18 drm_plane_cleanup(plane);
19
20 kfree(to_kplane(plane));
21}
22
23static const struct drm_plane_funcs komeda_plane_funcs = {
24};
25
26/* for komeda, which is pipeline can be share between crtcs */
27static u32 get_possible_crtcs(struct komeda_kms_dev *kms,
28 struct komeda_pipeline *pipe)
29{
30 struct komeda_crtc *crtc;
31 u32 possible_crtcs = 0;
32 int i;
33
34 for (i = 0; i < kms->n_crtcs; i++) {
35 crtc = &kms->crtcs[i];
36
37 if ((pipe == crtc->master) || (pipe == crtc->slave))
38 possible_crtcs |= BIT(i);
39 }
40
41 return possible_crtcs;
42}
43
44/* use Layer0 as primary */
45static u32 get_plane_type(struct komeda_kms_dev *kms,
46 struct komeda_component *c)
47{
48 bool is_primary = (c->id == KOMEDA_COMPONENT_LAYER0);
49
50 return is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
51}
52
53static int komeda_plane_add(struct komeda_kms_dev *kms,
54 struct komeda_layer *layer)
55{
56 struct komeda_dev *mdev = kms->base.dev_private;
57 struct komeda_component *c = &layer->base;
58 struct komeda_plane *kplane;
59 struct drm_plane *plane;
60 u32 *formats, n_formats = 0;
61 int err;
62
63 kplane = kzalloc(sizeof(*kplane), GFP_KERNEL);
64 if (!kplane)
65 return -ENOMEM;
66
67 plane = &kplane->base;
68 kplane->layer = layer;
69
70 formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
71 layer->layer_type, &n_formats);
72
73 err = drm_universal_plane_init(&kms->base, plane,
74 get_possible_crtcs(kms, c->pipeline),
75 &komeda_plane_funcs,
76 formats, n_formats, NULL,
77 get_plane_type(kms, c),
78 "%s", c->name);
79
80 komeda_put_fourcc_list(formats);
81
82 if (err)
83 goto cleanup;
84
85 drm_plane_helper_add(plane, &komeda_plane_helper_funcs);
86
87 return 0;
88cleanup:
89 komeda_plane_destroy(plane);
90 return err;
91}
92
93int komeda_kms_add_planes(struct komeda_kms_dev *kms, struct komeda_dev *mdev)
94{
95 struct komeda_pipeline *pipe;
96 int i, j, err;
97
98 for (i = 0; i < mdev->n_pipelines; i++) {
99 pipe = mdev->pipelines[i];
100
101 for (j = 0; j < pipe->n_layers; j++) {
102 err = komeda_plane_add(kms, pipe->layers[j]);
103 if (err)
104 return err;
105 }
106 }
107
108 return 0;
109}
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..f1c9e3fefa86
--- /dev/null
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_private_obj.c
@@ -0,0 +1,88 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
5 *
6 */
7#include "komeda_dev.h"
8#include "komeda_kms.h"
9
10static struct drm_private_state *
11komeda_pipeline_atomic_duplicate_state(struct drm_private_obj *obj)
12{
13 struct komeda_pipeline_state *st;
14
15 st = kmemdup(obj->state, sizeof(*st), GFP_KERNEL);
16 if (!st)
17 return NULL;
18
19 st->active_comps = 0;
20
21 __drm_atomic_helper_private_obj_duplicate_state(obj, &st->obj);
22
23 return &st->obj;
24}
25
26static void
27komeda_pipeline_atomic_destroy_state(struct drm_private_obj *obj,
28 struct drm_private_state *state)
29{
30 kfree(priv_to_pipe_st(state));
31}
32
33static const struct drm_private_state_funcs komeda_pipeline_obj_funcs = {
34 .atomic_duplicate_state = komeda_pipeline_atomic_duplicate_state,
35 .atomic_destroy_state = komeda_pipeline_atomic_destroy_state,
36};
37
38static int komeda_pipeline_obj_add(struct komeda_kms_dev *kms,
39 struct komeda_pipeline *pipe)
40{
41 struct komeda_pipeline_state *st;
42
43 st = kzalloc(sizeof(*st), GFP_KERNEL);
44 if (!st)
45 return -ENOMEM;
46
47 st->pipe = pipe;
48 drm_atomic_private_obj_init(&kms->base, &pipe->obj, &st->obj,
49 &komeda_pipeline_obj_funcs);
50
51 return 0;
52}
53
54int komeda_kms_add_private_objs(struct komeda_kms_dev *kms,
55 struct komeda_dev *mdev)
56{
57 struct komeda_pipeline *pipe;
58 int i, err;
59
60 for (i = 0; i < mdev->n_pipelines; i++) {
61 pipe = mdev->pipelines[i];
62
63 err = komeda_pipeline_obj_add(kms, pipe);
64 if (err)
65 return err;
66
67 /* Add component */
68 }
69
70 return 0;
71}
72
73void komeda_kms_cleanup_private_objs(struct komeda_dev *mdev)
74{
75 struct komeda_pipeline *pipe;
76 struct komeda_component *c;
77 int i, id;
78
79 for (i = 0; i < mdev->n_pipelines; i++) {
80 pipe = mdev->pipelines[i];
81 dp_for_each_set_bit(id, pipe->avail_comps) {
82 c = komeda_pipeline_get_component(pipe, id);
83
84 drm_atomic_private_obj_fini(&c->obj);
85 }
86 drm_atomic_private_obj_fini(&pipe->obj);
87 }
88}