1 // SPDX-License-Identifier: GPL-2.0+
2
3 #include <linux/slab.h>
4 #include <drm/drm_colorop.h>
5 #include <drm/drm_print.h>
6 #include <drm/drm_property.h>
7 #include <drm/drm_plane.h>
8
9 #include "vkms_drv.h"
10
11 static const u64 supported_tfs =
12 BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) |
13 BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF);
14
15 #define MAX_COLOR_PIPELINE_OPS 4
16
vkms_initialize_color_pipeline(struct drm_plane * plane,struct drm_prop_enum_list * list)17 static int vkms_initialize_color_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list)
18 {
19 struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
20 struct drm_device *dev = plane->dev;
21 int ret;
22 int i = 0, j = 0;
23
24 memset(ops, 0, sizeof(ops));
25
26 /* 1st op: 1d curve */
27 ops[i] = kzalloc_obj(*ops[i]);
28 if (!ops[i]) {
29 drm_err(dev, "KMS: Failed to allocate colorop\n");
30 ret = -ENOMEM;
31 goto cleanup;
32 }
33
34 ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane, supported_tfs,
35 DRM_COLOROP_FLAG_ALLOW_BYPASS);
36 if (ret)
37 goto cleanup;
38
39 list->type = ops[i]->base.id;
40
41 i++;
42
43 /* 2nd op: 3x4 matrix */
44 ops[i] = kzalloc_obj(*ops[i]);
45 if (!ops[i]) {
46 drm_err(dev, "KMS: Failed to allocate colorop\n");
47 ret = -ENOMEM;
48 goto cleanup;
49 }
50
51 ret = drm_plane_colorop_ctm_3x4_init(dev, ops[i], plane, DRM_COLOROP_FLAG_ALLOW_BYPASS);
52 if (ret)
53 goto cleanup;
54
55 drm_colorop_set_next_property(ops[i - 1], ops[i]);
56
57 i++;
58
59 /* 3rd op: 3x4 matrix */
60 ops[i] = kzalloc_obj(*ops[i]);
61 if (!ops[i]) {
62 drm_err(dev, "KMS: Failed to allocate colorop\n");
63 ret = -ENOMEM;
64 goto cleanup;
65 }
66
67 ret = drm_plane_colorop_ctm_3x4_init(dev, ops[i], plane, DRM_COLOROP_FLAG_ALLOW_BYPASS);
68 if (ret)
69 goto cleanup;
70
71 drm_colorop_set_next_property(ops[i - 1], ops[i]);
72
73 i++;
74
75 /* 4th op: 1d curve */
76 ops[i] = kzalloc_obj(*ops[i]);
77 if (!ops[i]) {
78 drm_err(dev, "KMS: Failed to allocate colorop\n");
79 ret = -ENOMEM;
80 goto cleanup;
81 }
82
83 ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane, supported_tfs,
84 DRM_COLOROP_FLAG_ALLOW_BYPASS);
85 if (ret)
86 goto cleanup;
87
88 drm_colorop_set_next_property(ops[i - 1], ops[i]);
89
90 list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[0]->base.id);
91
92 return 0;
93
94 cleanup:
95 for (j = 0; j < i; j++) {
96 if (ops[j]) {
97 drm_colorop_cleanup(ops[j]);
98 kfree(ops[j]);
99 }
100 }
101
102 return ret;
103 }
104
vkms_initialize_colorops(struct drm_plane * plane)105 int vkms_initialize_colorops(struct drm_plane *plane)
106 {
107 struct drm_prop_enum_list pipeline = {};
108 int ret = 0;
109
110 /* Add color pipeline */
111 ret = vkms_initialize_color_pipeline(plane, &pipeline);
112 if (ret)
113 goto out;
114
115 /* Create COLOR_PIPELINE property and attach */
116 ret = drm_plane_create_color_pipeline_property(plane, &pipeline, 1);
117
118 kfree(pipeline.name);
119 out:
120 return ret;
121 }
122