2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3 * Author:Mark Yao <mark.yao@rock-chips.com>
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/kernel.h>
18 #include <drm/drm_atomic.h>
19 #include <drm/drm_fb_helper.h>
20 #include <drm/drm_crtc_helper.h>
22 #include "rockchip_drm_drv.h"
23 #include "rockchip_drm_fb.h"
24 #include "rockchip_drm_gem.h"
25 #include "rockchip_drm_psr.h"
27 #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
29 struct rockchip_drm_fb
{
30 struct drm_framebuffer fb
;
31 struct drm_gem_object
*obj
[ROCKCHIP_MAX_FB_BUFFER
];
34 struct drm_gem_object
*rockchip_fb_get_gem_obj(struct drm_framebuffer
*fb
,
37 struct rockchip_drm_fb
*rk_fb
= to_rockchip_fb(fb
);
39 if (plane
>= ROCKCHIP_MAX_FB_BUFFER
)
42 return rk_fb
->obj
[plane
];
45 static void rockchip_drm_fb_destroy(struct drm_framebuffer
*fb
)
47 struct rockchip_drm_fb
*rockchip_fb
= to_rockchip_fb(fb
);
50 for (i
= 0; i
< ROCKCHIP_MAX_FB_BUFFER
; i
++)
51 drm_gem_object_put_unlocked(rockchip_fb
->obj
[i
]);
53 drm_framebuffer_cleanup(fb
);
57 static int rockchip_drm_fb_create_handle(struct drm_framebuffer
*fb
,
58 struct drm_file
*file_priv
,
61 struct rockchip_drm_fb
*rockchip_fb
= to_rockchip_fb(fb
);
63 return drm_gem_handle_create(file_priv
,
64 rockchip_fb
->obj
[0], handle
);
67 static int rockchip_drm_fb_dirty(struct drm_framebuffer
*fb
,
68 struct drm_file
*file
,
69 unsigned int flags
, unsigned int color
,
70 struct drm_clip_rect
*clips
,
71 unsigned int num_clips
)
73 rockchip_drm_psr_flush_all(fb
->dev
);
77 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs
= {
78 .destroy
= rockchip_drm_fb_destroy
,
79 .create_handle
= rockchip_drm_fb_create_handle
,
80 .dirty
= rockchip_drm_fb_dirty
,
83 static struct rockchip_drm_fb
*
84 rockchip_fb_alloc(struct drm_device
*dev
, const struct drm_mode_fb_cmd2
*mode_cmd
,
85 struct drm_gem_object
**obj
, unsigned int num_planes
)
87 struct rockchip_drm_fb
*rockchip_fb
;
91 rockchip_fb
= kzalloc(sizeof(*rockchip_fb
), GFP_KERNEL
);
93 return ERR_PTR(-ENOMEM
);
95 drm_helper_mode_fill_fb_struct(dev
, &rockchip_fb
->fb
, mode_cmd
);
97 for (i
= 0; i
< num_planes
; i
++)
98 rockchip_fb
->obj
[i
] = obj
[i
];
100 ret
= drm_framebuffer_init(dev
, &rockchip_fb
->fb
,
101 &rockchip_drm_fb_funcs
);
103 DRM_DEV_ERROR(dev
->dev
,
104 "Failed to initialize framebuffer: %d\n",
113 static struct drm_framebuffer
*
114 rockchip_user_fb_create(struct drm_device
*dev
, struct drm_file
*file_priv
,
115 const struct drm_mode_fb_cmd2
*mode_cmd
)
117 struct rockchip_drm_fb
*rockchip_fb
;
118 struct drm_gem_object
*objs
[ROCKCHIP_MAX_FB_BUFFER
];
119 struct drm_gem_object
*obj
;
126 hsub
= drm_format_horz_chroma_subsampling(mode_cmd
->pixel_format
);
127 vsub
= drm_format_vert_chroma_subsampling(mode_cmd
->pixel_format
);
128 num_planes
= min(drm_format_num_planes(mode_cmd
->pixel_format
),
129 ROCKCHIP_MAX_FB_BUFFER
);
131 for (i
= 0; i
< num_planes
; i
++) {
132 unsigned int width
= mode_cmd
->width
/ (i
? hsub
: 1);
133 unsigned int height
= mode_cmd
->height
/ (i
? vsub
: 1);
134 unsigned int min_size
;
136 obj
= drm_gem_object_lookup(file_priv
, mode_cmd
->handles
[i
]);
138 DRM_DEV_ERROR(dev
->dev
,
139 "Failed to lookup GEM object\n");
141 goto err_gem_object_unreference
;
144 min_size
= (height
- 1) * mode_cmd
->pitches
[i
] +
145 mode_cmd
->offsets
[i
] +
146 width
* drm_format_plane_cpp(mode_cmd
->pixel_format
, i
);
148 if (obj
->size
< min_size
) {
149 drm_gem_object_put_unlocked(obj
);
151 goto err_gem_object_unreference
;
156 rockchip_fb
= rockchip_fb_alloc(dev
, mode_cmd
, objs
, i
);
157 if (IS_ERR(rockchip_fb
)) {
158 ret
= PTR_ERR(rockchip_fb
);
159 goto err_gem_object_unreference
;
162 return &rockchip_fb
->fb
;
164 err_gem_object_unreference
:
165 for (i
--; i
>= 0; i
--)
166 drm_gem_object_put_unlocked(objs
[i
]);
170 static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers
= {
171 .atomic_commit_tail
= drm_atomic_helper_commit_tail_rpm
,
174 static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs
= {
175 .fb_create
= rockchip_user_fb_create
,
176 .output_poll_changed
= drm_fb_helper_output_poll_changed
,
177 .atomic_check
= drm_atomic_helper_check
,
178 .atomic_commit
= drm_atomic_helper_commit
,
181 struct drm_framebuffer
*
182 rockchip_drm_framebuffer_init(struct drm_device
*dev
,
183 const struct drm_mode_fb_cmd2
*mode_cmd
,
184 struct drm_gem_object
*obj
)
186 struct rockchip_drm_fb
*rockchip_fb
;
188 rockchip_fb
= rockchip_fb_alloc(dev
, mode_cmd
, &obj
, 1);
189 if (IS_ERR(rockchip_fb
))
190 return ERR_CAST(rockchip_fb
);
192 return &rockchip_fb
->fb
;
195 void rockchip_drm_mode_config_init(struct drm_device
*dev
)
197 dev
->mode_config
.min_width
= 0;
198 dev
->mode_config
.min_height
= 0;
201 * set max width and height as default value(4096x4096).
202 * this value would be used to check framebuffer size limitation
203 * at drm_mode_addfb().
205 dev
->mode_config
.max_width
= 4096;
206 dev
->mode_config
.max_height
= 4096;
208 dev
->mode_config
.funcs
= &rockchip_drm_mode_config_funcs
;
209 dev
->mode_config
.helper_private
= &rockchip_mode_config_helpers
;