blob: 5f2516fca079b9ba3784f5508261b64d4cf17579 [file] [log] [blame]
CK Hu119f5172016-01-04 18:36:34 +01001/*
2 * Copyright (c) 2015 MediaTek Inc.
3 * Author: CK Hu <ck.hu@mediatek.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
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.
13 */
14
15#include <drm/drmP.h>
16#include <drm/drm_atomic.h>
17#include <drm/drm_atomic_helper.h>
18#include <drm/drm_plane_helper.h>
19
20#include "mtk_drm_crtc.h"
21#include "mtk_drm_ddp_comp.h"
22#include "mtk_drm_drv.h"
23#include "mtk_drm_fb.h"
24#include "mtk_drm_gem.h"
25#include "mtk_drm_plane.h"
26
27static const u32 formats[] = {
28 DRM_FORMAT_XRGB8888,
29 DRM_FORMAT_ARGB8888,
30 DRM_FORMAT_RGB565,
31};
32
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030033static void mtk_plane_enable(struct mtk_drm_plane *mtk_plane,
34 dma_addr_t addr)
CK Hu119f5172016-01-04 18:36:34 +010035{
36 struct drm_plane *plane = &mtk_plane->base;
37 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
38 unsigned int pitch, format;
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030039 bool enable;
CK Hu119f5172016-01-04 18:36:34 +010040
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030041 if (WARN_ON(!plane->state))
42 return;
43
44 enable = state->base.visible;
45
46 if (WARN_ON(enable && !plane->state->fb))
CK Hu119f5172016-01-04 18:36:34 +010047 return;
48
49 if (plane->state->fb) {
50 pitch = plane->state->fb->pitches[0];
51 format = plane->state->fb->pixel_format;
52 } else {
53 pitch = 0;
54 format = DRM_FORMAT_RGBA8888;
55 }
56
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030057 addr += (state->base.src.x1 >> 16) * 4;
58 addr += (state->base.src.y1 >> 16) * pitch;
CK Hu119f5172016-01-04 18:36:34 +010059
60 state->pending.enable = enable;
61 state->pending.pitch = pitch;
62 state->pending.format = format;
63 state->pending.addr = addr;
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030064 state->pending.x = state->base.dst.x1;
65 state->pending.y = state->base.dst.y1;
66 state->pending.width = drm_rect_width(&state->base.dst);
67 state->pending.height = drm_rect_height(&state->base.dst);
CK Hu119f5172016-01-04 18:36:34 +010068 wmb(); /* Make sure the above parameters are set before update */
69 state->pending.dirty = true;
70}
71
72static void mtk_plane_reset(struct drm_plane *plane)
73{
74 struct mtk_plane_state *state;
75
76 if (plane->state) {
77 if (plane->state->fb)
78 drm_framebuffer_unreference(plane->state->fb);
79
80 state = to_mtk_plane_state(plane->state);
81 memset(state, 0, sizeof(*state));
82 } else {
83 state = kzalloc(sizeof(*state), GFP_KERNEL);
84 if (!state)
85 return;
86 plane->state = &state->base;
87 }
88
89 state->base.plane = plane;
90 state->pending.format = DRM_FORMAT_RGB565;
91}
92
93static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
94{
95 struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
96 struct mtk_plane_state *state;
97
98 state = kzalloc(sizeof(*state), GFP_KERNEL);
99 if (!state)
100 return NULL;
101
102 __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
103
104 WARN_ON(state->base.plane != plane);
105
106 state->pending = old_state->pending;
107
108 return &state->base;
109}
110
111static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
112 struct drm_plane_state *state)
113{
Daniel Vetter2f701692016-05-09 16:34:10 +0200114 __drm_atomic_helper_plane_destroy_state(state);
CK Hu119f5172016-01-04 18:36:34 +0100115 kfree(to_mtk_plane_state(state));
116}
117
118static const struct drm_plane_funcs mtk_plane_funcs = {
119 .update_plane = drm_atomic_helper_update_plane,
120 .disable_plane = drm_atomic_helper_disable_plane,
121 .destroy = drm_plane_cleanup,
122 .reset = mtk_plane_reset,
123 .atomic_duplicate_state = mtk_plane_duplicate_state,
124 .atomic_destroy_state = mtk_drm_plane_destroy_state,
125};
126
127static int mtk_plane_atomic_check(struct drm_plane *plane,
128 struct drm_plane_state *state)
129{
130 struct drm_framebuffer *fb = state->fb;
131 struct drm_crtc_state *crtc_state;
CK Hu119f5172016-01-04 18:36:34 +0100132 struct drm_rect clip = { 0, };
133
134 if (!fb)
135 return 0;
136
137 if (!mtk_fb_get_gem_obj(fb)) {
138 DRM_DEBUG_KMS("buffer is null\n");
139 return -EFAULT;
140 }
141
142 if (!state->crtc)
143 return 0;
144
145 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
146 if (IS_ERR(crtc_state))
147 return PTR_ERR(crtc_state);
148
149 clip.x2 = crtc_state->mode.hdisplay;
150 clip.y2 = crtc_state->mode.vdisplay;
151
Ville Syrjälä0e4faf62016-07-26 19:07:03 +0300152 return drm_plane_helper_check_state(state, &clip,
153 DRM_PLANE_HELPER_NO_SCALING,
154 DRM_PLANE_HELPER_NO_SCALING,
155 true, true);
CK Hu119f5172016-01-04 18:36:34 +0100156}
157
158static void mtk_plane_atomic_update(struct drm_plane *plane,
159 struct drm_plane_state *old_state)
160{
161 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
162 struct drm_crtc *crtc = state->base.crtc;
163 struct drm_gem_object *gem;
164 struct mtk_drm_gem_obj *mtk_gem;
165 struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
CK Hu119f5172016-01-04 18:36:34 +0100166
167 if (!crtc)
168 return;
169
CK Hu119f5172016-01-04 18:36:34 +0100170 gem = mtk_fb_get_gem_obj(state->base.fb);
171 mtk_gem = to_mtk_gem_obj(gem);
Ville Syrjälä0e4faf62016-07-26 19:07:03 +0300172 mtk_plane_enable(mtk_plane, mtk_gem->dma_addr);
CK Hu119f5172016-01-04 18:36:34 +0100173}
174
175static void mtk_plane_atomic_disable(struct drm_plane *plane,
176 struct drm_plane_state *old_state)
177{
178 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
179
180 state->pending.enable = false;
181 wmb(); /* Make sure the above parameter is set before update */
182 state->pending.dirty = true;
183}
184
185static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
186 .atomic_check = mtk_plane_atomic_check,
187 .atomic_update = mtk_plane_atomic_update,
188 .atomic_disable = mtk_plane_atomic_disable,
189};
190
191int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *mtk_plane,
192 unsigned long possible_crtcs, enum drm_plane_type type,
193 unsigned int zpos)
194{
195 int err;
196
197 err = drm_universal_plane_init(dev, &mtk_plane->base, possible_crtcs,
198 &mtk_plane_funcs, formats,
199 ARRAY_SIZE(formats), type, NULL);
200 if (err) {
201 DRM_ERROR("failed to initialize plane\n");
202 return err;
203 }
204
205 drm_plane_helper_add(&mtk_plane->base, &mtk_plane_helper_funcs);
206 mtk_plane->idx = zpos;
207
208 return 0;
209}