diff options
author | james qian wang (Arm Technology China) <james.qian.wang@arm.com> | 2019-01-03 06:41:13 -0500 |
---|---|---|
committer | Liviu Dudau <Liviu.Dudau@arm.com> | 2019-01-14 06:20:11 -0500 |
commit | c46c24bb6b115b0d74789cf089894384875189c7 (patch) | |
tree | 1ecef26b05cf1895eddd07ecdadaed385f0bc64f /drivers/gpu/drm/arm | |
parent | 981d29d2db7c96b942aa4b73fed31469140bcf9d (diff) |
drm/komeda: Add komeda_framebuffer
komeda_framebuffer is for extending drm_framebuffer to add komeda own
attributes and komeda specific fb handling.
Changes in v3:
- Fixed style problem found by checkpatch.pl --strict.
Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
Acked-by: Liviu Dudau <liviu.dudau@arm.com>
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
Diffstat (limited to 'drivers/gpu/drm/arm')
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | 165 | ||||
-rw-r--r-- | drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.h | 34 |
3 files changed, 201 insertions, 1 deletions
diff --git a/drivers/gpu/drm/arm/display/komeda/Makefile b/drivers/gpu/drm/arm/display/komeda/Makefile index 394fc2aa434a..25beae900ed2 100644 --- a/drivers/gpu/drm/arm/display/komeda/Makefile +++ b/drivers/gpu/drm/arm/display/komeda/Makefile | |||
@@ -8,7 +8,8 @@ komeda-y := \ | |||
8 | komeda_drv.o \ | 8 | komeda_drv.o \ |
9 | komeda_dev.o \ | 9 | komeda_dev.o \ |
10 | komeda_format_caps.o \ | 10 | komeda_format_caps.o \ |
11 | komeda_pipeline.o | 11 | komeda_pipeline.o \ |
12 | komeda_framebuffer.o | ||
12 | 13 | ||
13 | komeda-y += \ | 14 | komeda-y += \ |
14 | d71/d71_dev.o | 15 | d71/d71_dev.o |
diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c new file mode 100644 index 000000000000..4ddd5314ca23 --- /dev/null +++ b/drivers/gpu/drm/arm/display/komeda/komeda_framebuffer.c | |||
@@ -0,0 +1,165 @@ | |||
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 | |||
14 | static 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 | |||
26 | static 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 | |||
32 | static const struct drm_framebuffer_funcs komeda_fb_funcs = { | ||
33 | .destroy = komeda_fb_destroy, | ||
34 | .create_handle = komeda_fb_create_handle, | ||
35 | }; | ||
36 | |||
37 | static int | ||
38 | komeda_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 | |||
95 | struct drm_framebuffer * | ||
96 | komeda_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 | |||
132 | err_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 | |||
140 | dma_addr_t | ||
141 | komeda_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 */ | ||
14 | struct 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 | |||
27 | struct drm_framebuffer * | ||
28 | komeda_fb_create(struct drm_device *dev, struct drm_file *file, | ||
29 | const struct drm_mode_fb_cmd2 *mode_cmd); | ||
30 | dma_addr_t | ||
31 | komeda_fb_get_pixel_addr(struct komeda_fb *kfb, int x, int y, int plane); | ||
32 | bool komeda_fb_is_layer_supported(struct komeda_fb *kfb, u32 layer_type); | ||
33 | |||
34 | #endif | ||