Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
96f60e37 RK |
2 | /* |
3 | * Copyright (C) 2012 Russell King | |
96f60e37 | 4 | */ |
25e28ef2 | 5 | |
fcd70cd3 | 6 | #include <drm/drm_modeset_helper.h> |
96f60e37 | 7 | #include <drm/drm_fb_helper.h> |
25e28ef2 | 8 | #include <drm/drm_fourcc.h> |
ecb8a947 | 9 | #include <drm/drm_gem_framebuffer_helper.h> |
25e28ef2 | 10 | |
96f60e37 RK |
11 | #include "armada_drm.h" |
12 | #include "armada_fb.h" | |
13 | #include "armada_gem.h" | |
14 | #include "armada_hw.h" | |
15 | ||
96f60e37 | 16 | static const struct drm_framebuffer_funcs armada_fb_funcs = { |
ecb8a947 DS |
17 | .destroy = drm_gem_fb_destroy, |
18 | .create_handle = drm_gem_fb_create_handle, | |
96f60e37 RK |
19 | }; |
20 | ||
21 | struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, | |
1eb83451 | 22 | const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj) |
96f60e37 RK |
23 | { |
24 | struct armada_framebuffer *dfb; | |
25 | uint8_t format, config; | |
26 | int ret; | |
27 | ||
28 | switch (mode->pixel_format) { | |
29 | #define FMT(drm, fmt, mod) \ | |
30 | case DRM_FORMAT_##drm: \ | |
31 | format = CFG_##fmt; \ | |
32 | config = mod; \ | |
33 | break | |
34 | FMT(RGB565, 565, CFG_SWAPRB); | |
35 | FMT(BGR565, 565, 0); | |
36 | FMT(ARGB1555, 1555, CFG_SWAPRB); | |
37 | FMT(ABGR1555, 1555, 0); | |
38 | FMT(RGB888, 888PACK, CFG_SWAPRB); | |
39 | FMT(BGR888, 888PACK, 0); | |
40 | FMT(XRGB8888, X888, CFG_SWAPRB); | |
41 | FMT(XBGR8888, X888, 0); | |
42 | FMT(ARGB8888, 8888, CFG_SWAPRB); | |
43 | FMT(ABGR8888, 8888, 0); | |
44 | FMT(YUYV, 422PACK, CFG_YUV2RGB | CFG_SWAPYU | CFG_SWAPUV); | |
45 | FMT(UYVY, 422PACK, CFG_YUV2RGB); | |
46 | FMT(VYUY, 422PACK, CFG_YUV2RGB | CFG_SWAPUV); | |
47 | FMT(YVYU, 422PACK, CFG_YUV2RGB | CFG_SWAPYU); | |
48 | FMT(YUV422, 422, CFG_YUV2RGB); | |
49 | FMT(YVU422, 422, CFG_YUV2RGB | CFG_SWAPUV); | |
50 | FMT(YUV420, 420, CFG_YUV2RGB); | |
51 | FMT(YVU420, 420, CFG_YUV2RGB | CFG_SWAPUV); | |
52 | FMT(C8, PSEUDO8, 0); | |
53 | #undef FMT | |
54 | default: | |
55 | return ERR_PTR(-EINVAL); | |
56 | } | |
57 | ||
58 | dfb = kzalloc(sizeof(*dfb), GFP_KERNEL); | |
59 | if (!dfb) { | |
60 | DRM_ERROR("failed to allocate Armada fb object\n"); | |
61 | return ERR_PTR(-ENOMEM); | |
62 | } | |
63 | ||
64 | dfb->fmt = format; | |
65 | dfb->mod = config; | |
ecb8a947 | 66 | dfb->fb.obj[0] = &obj->obj; |
96f60e37 | 67 | |
a3f913ca | 68 | drm_helper_mode_fill_fb_struct(dev, &dfb->fb, mode); |
96f60e37 RK |
69 | |
70 | ret = drm_framebuffer_init(dev, &dfb->fb, &armada_fb_funcs); | |
71 | if (ret) { | |
72 | kfree(dfb); | |
73 | return ERR_PTR(ret); | |
74 | } | |
75 | ||
76 | /* | |
77 | * Take a reference on our object as we're successful - the | |
78 | * caller already holds a reference, which keeps us safe for | |
79 | * the above call, but the caller will drop their reference | |
80 | * to it. Hence we need to take our own reference. | |
81 | */ | |
4c3cf375 | 82 | drm_gem_object_get(&obj->obj); |
96f60e37 RK |
83 | |
84 | return dfb; | |
85 | } | |
86 | ||
3382a6b9 | 87 | struct drm_framebuffer *armada_fb_create(struct drm_device *dev, |
1eb83451 | 88 | struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode) |
96f60e37 | 89 | { |
05c452c1 | 90 | const struct drm_format_info *info = drm_get_format_info(dev, mode); |
96f60e37 RK |
91 | struct armada_gem_object *obj; |
92 | struct armada_framebuffer *dfb; | |
93 | int ret; | |
94 | ||
95 | DRM_DEBUG_DRIVER("w%u h%u pf%08x f%u p%u,%u,%u\n", | |
96 | mode->width, mode->height, mode->pixel_format, | |
97 | mode->flags, mode->pitches[0], mode->pitches[1], | |
98 | mode->pitches[2]); | |
99 | ||
100 | /* We can only handle a single plane at the moment */ | |
05c452c1 | 101 | if (info->num_planes > 1 && |
96f60e37 RK |
102 | (mode->handles[0] != mode->handles[1] || |
103 | mode->handles[0] != mode->handles[2])) { | |
104 | ret = -EINVAL; | |
105 | goto err; | |
106 | } | |
107 | ||
a8ad0bd8 | 108 | obj = armada_gem_object_lookup(dfile, mode->handles[0]); |
96f60e37 RK |
109 | if (!obj) { |
110 | ret = -ENOENT; | |
111 | goto err; | |
112 | } | |
113 | ||
114 | if (obj->obj.import_attach && !obj->sgt) { | |
115 | ret = armada_gem_map_import(obj); | |
116 | if (ret) | |
117 | goto err_unref; | |
118 | } | |
119 | ||
120 | /* Framebuffer objects must have a valid device address for scanout */ | |
b4005857 | 121 | if (!obj->mapped) { |
96f60e37 RK |
122 | ret = -EINVAL; |
123 | goto err_unref; | |
124 | } | |
125 | ||
126 | dfb = armada_framebuffer_create(dev, mode, obj); | |
127 | if (IS_ERR(dfb)) { | |
128 | ret = PTR_ERR(dfb); | |
129 | goto err; | |
130 | } | |
131 | ||
dda156cf | 132 | drm_gem_object_put(&obj->obj); |
96f60e37 RK |
133 | |
134 | return &dfb->fb; | |
135 | ||
136 | err_unref: | |
dda156cf | 137 | drm_gem_object_put(&obj->obj); |
96f60e37 RK |
138 | err: |
139 | DRM_ERROR("failed to initialize framebuffer: %d\n", ret); | |
140 | return ERR_PTR(ret); | |
141 | } |