diff options
author | james qian wang (Arm Technology China) <james.qian.wang@arm.com> | 2019-01-03 06:39:48 -0500 |
---|---|---|
committer | Liviu Dudau <Liviu.Dudau@arm.com> | 2019-01-14 06:09:23 -0500 |
commit | bd628c1bed7902ec1f24ba0fe70758949146abbe (patch) | |
tree | 103461a1622a7d62b26d7b41d784f621a074ca74 | |
parent | 37fc9bb022c654e261c5a7d2ce600c6ce26c022d (diff) |
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.
Changes in v4:
- Deleted unnecessary headers
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 (Arm Technology China) <james.qian.wang@arm.com>
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
-rw-r--r-- | drivers/gpu/drm/arm/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/Kbuild | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/Kconfig | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/include/malidp_product.h | 23 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/include/malidp_utils.h | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/Makefile | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_dev.c | 114 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_dev.h | 98 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c | 196 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h | 348 |
11 files changed, 826 insertions, 0 deletions
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 | |||
37 | 37 | ||
38 | If compiled as a module it will be called mali-dp. | 38 | If compiled as a module it will be called mali-dp. |
39 | 39 | ||
40 | source "drivers/gpu/drm/arm/display/Kconfig" | ||
41 | |||
40 | endmenu | 42 | 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 | |||
3 | mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o | 3 | mali-dp-y := malidp_drv.o malidp_hw.o malidp_planes.o malidp_crtc.o |
4 | mali-dp-y += malidp_mw.o | 4 | mali-dp-y += malidp_mw.o |
5 | obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o | 5 | obj-$(CONFIG_DRM_MALI_DISPLAY) += mali-dp.o |
6 | 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 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | 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 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | config 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_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..5b44e36509b1 --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | |||
3 | ccflags-y := \ | ||
4 | -I$(src)/../include \ | ||
5 | -I$(src) | ||
6 | |||
7 | komeda-y := \ | ||
8 | komeda_dev.o \ | ||
9 | komeda_pipeline.o \ | ||
10 | |||
11 | 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..4dec259cecac --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c | |||
@@ -0,0 +1,114 @@ | |||
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 | |||
12 | struct komeda_dev *komeda_dev_create(struct device *dev) | ||
13 | { | ||
14 | struct platform_device *pdev = to_platform_device(dev); | ||
15 | const struct komeda_product_data *product; | ||
16 | struct komeda_dev *mdev; | ||
17 | struct resource *io_res; | ||
18 | int err = 0; | ||
19 | |||
20 | product = of_device_get_match_data(dev); | ||
21 | if (!product) | ||
22 | return ERR_PTR(-ENODEV); | ||
23 | |||
24 | io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
25 | if (!io_res) { | ||
26 | DRM_ERROR("No registers defined.\n"); | ||
27 | return ERR_PTR(-ENODEV); | ||
28 | } | ||
29 | |||
30 | mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL); | ||
31 | if (!mdev) | ||
32 | return ERR_PTR(-ENOMEM); | ||
33 | |||
34 | mdev->dev = dev; | ||
35 | mdev->reg_base = devm_ioremap_resource(dev, io_res); | ||
36 | if (IS_ERR(mdev->reg_base)) { | ||
37 | DRM_ERROR("Map register space failed.\n"); | ||
38 | err = PTR_ERR(mdev->reg_base); | ||
39 | mdev->reg_base = NULL; | ||
40 | goto err_cleanup; | ||
41 | } | ||
42 | |||
43 | mdev->pclk = devm_clk_get(dev, "pclk"); | ||
44 | if (IS_ERR(mdev->pclk)) { | ||
45 | DRM_ERROR("Get APB clk failed.\n"); | ||
46 | err = PTR_ERR(mdev->pclk); | ||
47 | mdev->pclk = NULL; | ||
48 | goto err_cleanup; | ||
49 | } | ||
50 | |||
51 | /* Enable APB clock to access the registers */ | ||
52 | clk_prepare_enable(mdev->pclk); | ||
53 | |||
54 | mdev->funcs = product->identify(mdev->reg_base, &mdev->chip); | ||
55 | if (!komeda_product_match(mdev, product->product_id)) { | ||
56 | DRM_ERROR("DT configured %x mismatch with real HW %x.\n", | ||
57 | product->product_id, | ||
58 | MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id)); | ||
59 | err = -ENODEV; | ||
60 | goto err_cleanup; | ||
61 | } | ||
62 | |||
63 | DRM_INFO("Found ARM Mali-D%x version r%dp%d\n", | ||
64 | MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id), | ||
65 | MALIDP_CORE_ID_MAJOR(mdev->chip.core_id), | ||
66 | MALIDP_CORE_ID_MINOR(mdev->chip.core_id)); | ||
67 | |||
68 | err = mdev->funcs->enum_resources(mdev); | ||
69 | if (err) { | ||
70 | DRM_ERROR("enumerate display resource failed.\n"); | ||
71 | goto err_cleanup; | ||
72 | } | ||
73 | |||
74 | return mdev; | ||
75 | |||
76 | err_cleanup: | ||
77 | komeda_dev_destroy(mdev); | ||
78 | return ERR_PTR(err); | ||
79 | } | ||
80 | |||
81 | void komeda_dev_destroy(struct komeda_dev *mdev) | ||
82 | { | ||
83 | struct device *dev = mdev->dev; | ||
84 | struct komeda_dev_funcs *funcs = mdev->funcs; | ||
85 | int i; | ||
86 | |||
87 | for (i = 0; i < mdev->n_pipelines; i++) { | ||
88 | komeda_pipeline_destroy(mdev, mdev->pipelines[i]); | ||
89 | mdev->pipelines[i] = NULL; | ||
90 | } | ||
91 | |||
92 | mdev->n_pipelines = 0; | ||
93 | |||
94 | if (funcs && funcs->cleanup) | ||
95 | funcs->cleanup(mdev); | ||
96 | |||
97 | if (mdev->reg_base) { | ||
98 | devm_iounmap(dev, mdev->reg_base); | ||
99 | mdev->reg_base = NULL; | ||
100 | } | ||
101 | |||
102 | if (mdev->mclk) { | ||
103 | devm_clk_put(dev, mdev->mclk); | ||
104 | mdev->mclk = NULL; | ||
105 | } | ||
106 | |||
107 | if (mdev->pclk) { | ||
108 | clk_disable_unprepare(mdev->pclk); | ||
109 | devm_clk_put(dev, mdev->pclk); | ||
110 | mdev->pclk = NULL; | ||
111 | } | ||
112 | |||
113 | devm_kfree(dev, mdev); | ||
114 | } | ||
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..03b8703736c2 --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.h | |||
@@ -0,0 +1,98 @@ | |||
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 | |||
15 | /* malidp device id */ | ||
16 | enum { | ||
17 | MALI_D71 = 0, | ||
18 | }; | ||
19 | |||
20 | /* pipeline DT ports */ | ||
21 | enum { | ||
22 | KOMEDA_OF_PORT_OUTPUT = 0, | ||
23 | KOMEDA_OF_PORT_COPROC = 1, | ||
24 | }; | ||
25 | |||
26 | struct komeda_chip_info { | ||
27 | u32 arch_id; | ||
28 | u32 core_id; | ||
29 | u32 core_info; | ||
30 | u32 bus_width; | ||
31 | }; | ||
32 | |||
33 | struct komeda_product_data { | ||
34 | u32 product_id; | ||
35 | struct komeda_dev_funcs *(*identify)(u32 __iomem *reg, | ||
36 | struct komeda_chip_info *info); | ||
37 | }; | ||
38 | |||
39 | struct komeda_dev; | ||
40 | |||
41 | /** | ||
42 | * struct komeda_dev_funcs | ||
43 | * | ||
44 | * Supplied by chip level and returned by the chip entry function xxx_identify, | ||
45 | */ | ||
46 | struct komeda_dev_funcs { | ||
47 | /** | ||
48 | * @enum_resources: | ||
49 | * | ||
50 | * for CHIP to report or add pipeline and component resources to CORE | ||
51 | */ | ||
52 | int (*enum_resources)(struct komeda_dev *mdev); | ||
53 | /** @cleanup: call to chip to cleanup komeda_dev->chip data */ | ||
54 | void (*cleanup)(struct komeda_dev *mdev); | ||
55 | }; | ||
56 | |||
57 | /** | ||
58 | * struct komeda_dev | ||
59 | * | ||
60 | * Pipeline and component are used to describe how to handle the pixel data. | ||
61 | * komeda_device is for describing the whole view of the device, and the | ||
62 | * control-abilites of device. | ||
63 | */ | ||
64 | struct komeda_dev { | ||
65 | struct device *dev; | ||
66 | u32 __iomem *reg_base; | ||
67 | |||
68 | struct komeda_chip_info chip; | ||
69 | |||
70 | /** @pclk: APB clock for register access */ | ||
71 | struct clk *pclk; | ||
72 | /** @mck: HW main engine clk */ | ||
73 | struct clk *mclk; | ||
74 | |||
75 | int n_pipelines; | ||
76 | struct komeda_pipeline *pipelines[KOMEDA_MAX_PIPELINES]; | ||
77 | |||
78 | /** @funcs: chip funcs to access to HW */ | ||
79 | struct komeda_dev_funcs *funcs; | ||
80 | /** | ||
81 | * @chip_data: | ||
82 | * | ||
83 | * chip data will be added by &komeda_dev_funcs.enum_resources() and | ||
84 | * destroyed by &komeda_dev_funcs.cleanup() | ||
85 | */ | ||
86 | void *chip_data; | ||
87 | }; | ||
88 | |||
89 | static inline bool | ||
90 | komeda_product_match(struct komeda_dev *mdev, u32 target) | ||
91 | { | ||
92 | return MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id) == target; | ||
93 | } | ||
94 | |||
95 | struct komeda_dev *komeda_dev_create(struct device *dev); | ||
96 | void komeda_dev_destroy(struct komeda_dev *mdev); | ||
97 | |||
98 | #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..179122fc93ff --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c | |||
@@ -0,0 +1,196 @@ | |||
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 */ | ||
11 | struct komeda_pipeline * | ||
12 | komeda_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 | |||
42 | void 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 | devm_kfree(mdev->dev, pipe); | ||
57 | } | ||
58 | |||
59 | struct komeda_component ** | ||
60 | komeda_pipeline_get_component_pos(struct komeda_pipeline *pipe, int id) | ||
61 | { | ||
62 | struct komeda_dev *mdev = pipe->mdev; | ||
63 | struct komeda_pipeline *temp = NULL; | ||
64 | struct komeda_component **pos = NULL; | ||
65 | |||
66 | switch (id) { | ||
67 | case KOMEDA_COMPONENT_LAYER0: | ||
68 | case KOMEDA_COMPONENT_LAYER1: | ||
69 | case KOMEDA_COMPONENT_LAYER2: | ||
70 | case KOMEDA_COMPONENT_LAYER3: | ||
71 | pos = to_cpos(pipe->layers[id - KOMEDA_COMPONENT_LAYER0]); | ||
72 | break; | ||
73 | case KOMEDA_COMPONENT_WB_LAYER: | ||
74 | pos = to_cpos(pipe->wb_layer); | ||
75 | break; | ||
76 | case KOMEDA_COMPONENT_COMPIZ0: | ||
77 | case KOMEDA_COMPONENT_COMPIZ1: | ||
78 | temp = mdev->pipelines[id - KOMEDA_COMPONENT_COMPIZ0]; | ||
79 | if (!temp) { | ||
80 | DRM_ERROR("compiz-%d doesn't exist.\n", id); | ||
81 | return NULL; | ||
82 | } | ||
83 | pos = to_cpos(temp->compiz); | ||
84 | break; | ||
85 | case KOMEDA_COMPONENT_SCALER0: | ||
86 | case KOMEDA_COMPONENT_SCALER1: | ||
87 | pos = to_cpos(pipe->scalers[id - KOMEDA_COMPONENT_SCALER0]); | ||
88 | break; | ||
89 | case KOMEDA_COMPONENT_IPS0: | ||
90 | case KOMEDA_COMPONENT_IPS1: | ||
91 | temp = mdev->pipelines[id - KOMEDA_COMPONENT_IPS0]; | ||
92 | if (!temp) { | ||
93 | DRM_ERROR("ips-%d doesn't exist.\n", id); | ||
94 | return NULL; | ||
95 | } | ||
96 | pos = to_cpos(temp->improc); | ||
97 | break; | ||
98 | case KOMEDA_COMPONENT_TIMING_CTRLR: | ||
99 | pos = to_cpos(pipe->ctrlr); | ||
100 | break; | ||
101 | default: | ||
102 | pos = NULL; | ||
103 | DRM_ERROR("Unknown pipeline resource ID: %d.\n", id); | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | return pos; | ||
108 | } | ||
109 | |||
110 | struct komeda_component * | ||
111 | komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id) | ||
112 | { | ||
113 | struct komeda_component **pos = NULL; | ||
114 | struct komeda_component *c = NULL; | ||
115 | |||
116 | pos = komeda_pipeline_get_component_pos(pipe, id); | ||
117 | if (pos) | ||
118 | c = *pos; | ||
119 | |||
120 | return c; | ||
121 | } | ||
122 | |||
123 | /** komeda_component_add - Add a component to &komeda_pipeline */ | ||
124 | struct komeda_component * | ||
125 | komeda_component_add(struct komeda_pipeline *pipe, | ||
126 | size_t comp_sz, u32 id, u32 hw_id, | ||
127 | struct komeda_component_funcs *funcs, | ||
128 | u8 max_active_inputs, u32 supported_inputs, | ||
129 | u8 max_active_outputs, u32 __iomem *reg, | ||
130 | const char *name_fmt, ...) | ||
131 | { | ||
132 | struct komeda_component **pos; | ||
133 | struct komeda_component *c; | ||
134 | int idx, *num = NULL; | ||
135 | |||
136 | if (max_active_inputs > KOMEDA_COMPONENT_N_INPUTS) { | ||
137 | WARN(1, "please large KOMEDA_COMPONENT_N_INPUTS to %d.\n", | ||
138 | max_active_inputs); | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | pos = komeda_pipeline_get_component_pos(pipe, id); | ||
143 | if (!pos || (*pos)) | ||
144 | return NULL; | ||
145 | |||
146 | if (has_bit(id, KOMEDA_PIPELINE_LAYERS)) { | ||
147 | idx = id - KOMEDA_COMPONENT_LAYER0; | ||
148 | num = &pipe->n_layers; | ||
149 | if (idx != pipe->n_layers) { | ||
150 | DRM_ERROR("please add Layer by id sequence.\n"); | ||
151 | return NULL; | ||
152 | } | ||
153 | } else if (has_bit(id, KOMEDA_PIPELINE_SCALERS)) { | ||
154 | idx = id - KOMEDA_COMPONENT_SCALER0; | ||
155 | num = &pipe->n_scalers; | ||
156 | if (idx != pipe->n_scalers) { | ||
157 | DRM_ERROR("please add Scaler by id sequence.\n"); | ||
158 | return NULL; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | c = devm_kzalloc(pipe->mdev->dev, comp_sz, GFP_KERNEL); | ||
163 | if (!c) | ||
164 | return NULL; | ||
165 | |||
166 | c->id = id; | ||
167 | c->hw_id = hw_id; | ||
168 | c->reg = reg; | ||
169 | c->pipeline = pipe; | ||
170 | c->max_active_inputs = max_active_inputs; | ||
171 | c->max_active_outputs = max_active_outputs; | ||
172 | c->supported_inputs = supported_inputs; | ||
173 | c->funcs = funcs; | ||
174 | |||
175 | if (name_fmt) { | ||
176 | va_list args; | ||
177 | |||
178 | va_start(args, name_fmt); | ||
179 | vsnprintf(c->name, sizeof(c->name), name_fmt, args); | ||
180 | va_end(args); | ||
181 | } | ||
182 | |||
183 | if (num) | ||
184 | *num = *num + 1; | ||
185 | |||
186 | pipe->avail_comps |= BIT(c->id); | ||
187 | *pos = c; | ||
188 | |||
189 | return c; | ||
190 | } | ||
191 | |||
192 | void komeda_component_destroy(struct komeda_dev *mdev, | ||
193 | struct komeda_component *c) | ||
194 | { | ||
195 | devm_kfree(mdev->dev, c); | ||
196 | } | ||
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..7daba0e1946b --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h | |||
@@ -0,0 +1,348 @@ | |||
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 */ | ||
21 | enum { | ||
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)) | ||
51 | struct komeda_component; | ||
52 | struct komeda_component_state; | ||
53 | |||
54 | /** komeda_component_funcs - component control functions */ | ||
55 | struct 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 | */ | ||
78 | struct 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 | */ | ||
134 | struct 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 | */ | ||
150 | struct 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 | |||
197 | static inline u16 component_disabling_inputs(struct komeda_component_state *st) | ||
198 | { | ||
199 | return st->affected_inputs ^ st->active_inputs; | ||
200 | } | ||
201 | |||
202 | static 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 */ | ||
211 | struct komeda_layer { | ||
212 | struct komeda_component base; | ||
213 | /* layer specific features and caps */ | ||
214 | }; | ||
215 | |||
216 | struct komeda_layer_state { | ||
217 | struct komeda_component_state base; | ||
218 | /* layer specific configuration state */ | ||
219 | }; | ||
220 | |||
221 | struct komeda_compiz { | ||
222 | struct komeda_component base; | ||
223 | /* compiz specific features and caps */ | ||
224 | }; | ||
225 | |||
226 | struct komeda_compiz_state { | ||
227 | struct komeda_component_state base; | ||
228 | /* compiz specific configuration state */ | ||
229 | }; | ||
230 | |||
231 | struct komeda_scaler { | ||
232 | struct komeda_component base; | ||
233 | /* scaler features and caps */ | ||
234 | }; | ||
235 | |||
236 | struct komeda_scaler_state { | ||
237 | struct komeda_component_state base; | ||
238 | }; | ||
239 | |||
240 | struct komeda_improc { | ||
241 | struct komeda_component base; | ||
242 | }; | ||
243 | |||
244 | struct komeda_improc_state { | ||
245 | struct komeda_component_state base; | ||
246 | }; | ||
247 | |||
248 | /* display timing controller */ | ||
249 | struct komeda_timing_ctrlr { | ||
250 | struct komeda_component base; | ||
251 | }; | ||
252 | |||
253 | struct komeda_timing_ctrlr_state { | ||
254 | struct komeda_component_state base; | ||
255 | }; | ||
256 | |||
257 | /** struct komeda_pipeline_funcs */ | ||
258 | struct komeda_pipeline_funcs { | ||
259 | /* dump_register: Optional, dump registers to seq_file */ | ||
260 | void (*dump_register)(struct komeda_pipeline *pipe, | ||
261 | struct seq_file *sf); | ||
262 | }; | ||
263 | |||
264 | /** | ||
265 | * struct komeda_pipeline | ||
266 | * | ||
267 | * Represent a complete display pipeline and hold all functional components. | ||
268 | */ | ||
269 | struct komeda_pipeline { | ||
270 | /** @obj: link pipeline as private obj of drm_atomic_state */ | ||
271 | struct drm_private_obj obj; | ||
272 | /** @mdev: the parent komeda_dev */ | ||
273 | struct komeda_dev *mdev; | ||
274 | /** @pxlclk: pixel clock */ | ||
275 | struct clk *pxlclk; | ||
276 | /** @aclk: AXI clock */ | ||
277 | struct clk *aclk; | ||
278 | /** @id: pipeline id */ | ||
279 | int id; | ||
280 | /** @avail_comps: available components mask of pipeline */ | ||
281 | u32 avail_comps; | ||
282 | int n_layers; | ||
283 | struct komeda_layer *layers[KOMEDA_PIPELINE_MAX_LAYERS]; | ||
284 | int n_scalers; | ||
285 | struct komeda_scaler *scalers[KOMEDA_PIPELINE_MAX_SCALERS]; | ||
286 | struct komeda_compiz *compiz; | ||
287 | struct komeda_layer *wb_layer; | ||
288 | struct komeda_improc *improc; | ||
289 | struct komeda_timing_ctrlr *ctrlr; | ||
290 | struct komeda_pipeline_funcs *funcs; /* private pipeline functions */ | ||
291 | }; | ||
292 | |||
293 | /** | ||
294 | * struct komeda_pipeline_state | ||
295 | * | ||
296 | * NOTE: | ||
297 | * Unlike the pipeline, pipeline_state doesn’t gather any component_state | ||
298 | * into it. It because all component will be managed by drm_atomic_state. | ||
299 | */ | ||
300 | struct komeda_pipeline_state { | ||
301 | /** @obj: tracking pipeline_state by drm_atomic_state */ | ||
302 | struct drm_private_state obj; | ||
303 | struct komeda_pipeline *pipe; | ||
304 | /** @crtc: currently bound crtc */ | ||
305 | struct drm_crtc *crtc; | ||
306 | /** | ||
307 | * @active_comps: | ||
308 | * | ||
309 | * bitmask - BIT(component->id) of active components | ||
310 | */ | ||
311 | u32 active_comps; | ||
312 | }; | ||
313 | |||
314 | #define to_layer(c) container_of(c, struct komeda_layer, base) | ||
315 | #define to_compiz(c) container_of(c, struct komeda_compiz, base) | ||
316 | #define to_scaler(c) container_of(c, struct komeda_scaler, base) | ||
317 | #define to_improc(c) container_of(c, struct komeda_improc, base) | ||
318 | #define to_ctrlr(c) container_of(c, struct komeda_timing_ctrlr, base) | ||
319 | |||
320 | #define to_layer_st(c) container_of(c, struct komeda_layer_state, base) | ||
321 | #define to_compiz_st(c) container_of(c, struct komeda_compiz_state, base) | ||
322 | #define to_scaler_st(c) container_of(c, struct komeda_scaler_state, base) | ||
323 | #define to_improc_st(c) container_of(c, struct komeda_improc_state, base) | ||
324 | #define to_ctrlr_st(c) container_of(c, struct komeda_timing_ctrlr_state, base) | ||
325 | |||
326 | /* pipeline APIs */ | ||
327 | struct komeda_pipeline * | ||
328 | komeda_pipeline_add(struct komeda_dev *mdev, size_t size, | ||
329 | struct komeda_pipeline_funcs *funcs); | ||
330 | void komeda_pipeline_destroy(struct komeda_dev *mdev, | ||
331 | struct komeda_pipeline *pipe); | ||
332 | |||
333 | struct komeda_component * | ||
334 | komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id); | ||
335 | |||
336 | /* component APIs */ | ||
337 | struct komeda_component * | ||
338 | komeda_component_add(struct komeda_pipeline *pipe, | ||
339 | size_t comp_sz, u32 id, u32 hw_id, | ||
340 | struct komeda_component_funcs *funcs, | ||
341 | u8 max_active_inputs, u32 supported_inputs, | ||
342 | u8 max_active_outputs, u32 __iomem *reg, | ||
343 | const char *name_fmt, ...); | ||
344 | |||
345 | void komeda_component_destroy(struct komeda_dev *mdev, | ||
346 | struct komeda_component *c); | ||
347 | |||
348 | #endif /* _KOMEDA_PIPELINE_H_*/ | ||