blob: 17172ba40959cb937d36558d27853ea93136e735 [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
Daniel Kurtz5bfafad2016-08-04 10:59:53 +080033static void mtk_plane_enable(struct drm_plane *plane,
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030034 dma_addr_t addr)
CK Hu119f5172016-01-04 18:36:34 +010035{
CK Hu119f5172016-01-04 18:36:34 +010036 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
37 unsigned int pitch, format;
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030038 bool enable;
CK Hu119f5172016-01-04 18:36:34 +010039
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030040 if (WARN_ON(!plane->state))
41 return;
42
43 enable = state->base.visible;
44
45 if (WARN_ON(enable && !plane->state->fb))
CK Hu119f5172016-01-04 18:36:34 +010046 return;
47
48 if (plane->state->fb) {
49 pitch = plane->state->fb->pitches[0];
50 format = plane->state->fb->pixel_format;
51 } else {
52 pitch = 0;
53 format = DRM_FORMAT_RGBA8888;
54 }
55
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030056 addr += (state->base.src.x1 >> 16) * 4;
57 addr += (state->base.src.y1 >> 16) * pitch;
CK Hu119f5172016-01-04 18:36:34 +010058
59 state->pending.enable = enable;
60 state->pending.pitch = pitch;
61 state->pending.format = format;
62 state->pending.addr = addr;
Ville Syrjälä0e4faf62016-07-26 19:07:03 +030063 state->pending.x = state->base.dst.x1;
64 state->pending.y = state->base.dst.y1;
65 state->pending.width = drm_rect_width(&state->base.dst);
66 state->pending.height = drm_rect_height(&state->base.dst);
CK Hu119f5172016-01-04 18:36:34 +010067 wmb(); /* Make sure the above parameters are set before update */
68 state->pending.dirty = true;
69}
70
71static void mtk_plane_reset(struct drm_plane *plane)
72{
73 struct mtk_plane_state *state;
74
75 if (plane->state) {
Bibby Hsieh903daff2016-08-04 10:59:54 +080076 __drm_atomic_helper_plane_destroy_state(plane->state);
CK Hu119f5172016-01-04 18:36:34 +010077
78 state = to_mtk_plane_state(plane->state);
79 memset(state, 0, sizeof(*state));
80 } else {
81 state = kzalloc(sizeof(*state), GFP_KERNEL);
82 if (!state)
83 return;
84 plane->state = &state->base;
85 }
86
87 state->base.plane = plane;
88 state->pending.format = DRM_FORMAT_RGB565;
89}
90
91static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
92{
93 struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
94 struct mtk_plane_state *state;
95
96 state = kzalloc(sizeof(*state), GFP_KERNEL);
97 if (!state)
98 return NULL;
99
100 __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
101
102 WARN_ON(state->base.plane != plane);
103
104 state->pending = old_state->pending;
105
106 return &state->base;
107}
108
109static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
110 struct drm_plane_state *state)
111{
Daniel Vetter2f701692016-05-09 16:34:10 +0200112 __drm_atomic_helper_plane_destroy_state(state);
CK Hu119f5172016-01-04 18:36:34 +0100113 kfree(to_mtk_plane_state(state));
114}
115
116static const struct drm_plane_funcs mtk_plane_funcs = {
117 .update_plane = drm_atomic_helper_update_plane,
118 .disable_plane = drm_atomic_helper_disable_plane,
119 .destroy = drm_plane_cleanup,
120 .reset = mtk_plane_reset,
121 .atomic_duplicate_state = mtk_plane_duplicate_state,
122 .atomic_destroy_state = mtk_drm_plane_destroy_state,
123};
124
125static int mtk_plane_atomic_check(struct drm_plane *plane,
126 struct drm_plane_state *state)
127{
128 struct drm_framebuffer *fb = state->fb;
129 struct drm_crtc_state *crtc_state;
CK Hu119f5172016-01-04 18:36:34 +0100130 struct drm_rect clip = { 0, };
131
132 if (!fb)
133 return 0;
134
135 if (!mtk_fb_get_gem_obj(fb)) {
136 DRM_DEBUG_KMS("buffer is null\n");
137 return -EFAULT;
138 }
139
140 if (!state->crtc)
141 return 0;
142
143 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
144 if (IS_ERR(crtc_state))
145 return PTR_ERR(crtc_state);
146
147 clip.x2 = crtc_state->mode.hdisplay;
148 clip.y2 = crtc_state->mode.vdisplay;
149
Ville Syrjälä0e4faf62016-07-26 19:07:03 +0300150 return drm_plane_helper_check_state(state, &clip,
151 DRM_PLANE_HELPER_NO_SCALING,
152 DRM_PLANE_HELPER_NO_SCALING,
153 true, true);
CK Hu119f5172016-01-04 18:36:34 +0100154}
155
156static void mtk_plane_atomic_update(struct drm_plane *plane,
157 struct drm_plane_state *old_state)
158{
159 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
160 struct drm_crtc *crtc = state->base.crtc;
161 struct drm_gem_object *gem;
162 struct mtk_drm_gem_obj *mtk_gem;
CK Hu119f5172016-01-04 18:36:34 +0100163
164 if (!crtc)
165 return;
166
CK Hu119f5172016-01-04 18:36:34 +0100167 gem = mtk_fb_get_gem_obj(state->base.fb);
168 mtk_gem = to_mtk_gem_obj(gem);
Daniel Kurtz5bfafad2016-08-04 10:59:53 +0800169 mtk_plane_enable(plane, mtk_gem->dma_addr);
CK Hu119f5172016-01-04 18:36:34 +0100170}
171
172static void mtk_plane_atomic_disable(struct drm_plane *plane,
173 struct drm_plane_state *old_state)
174{
175 struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
176
177 state->pending.enable = false;
178 wmb(); /* Make sure the above parameter is set before update */
179 state->pending.dirty = true;
180}
181
182static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
183 .atomic_check = mtk_plane_atomic_check,
184 .atomic_update = mtk_plane_atomic_update,
185 .atomic_disable = mtk_plane_atomic_disable,
186};
187
Daniel Kurtz5bfafad2016-08-04 10:59:53 +0800188int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
Daniel Kurtz0d5a32b2016-08-04 10:59:52 +0800189 unsigned long possible_crtcs, enum drm_plane_type type)
CK Hu119f5172016-01-04 18:36:34 +0100190{
191 int err;
192
Daniel Kurtz5bfafad2016-08-04 10:59:53 +0800193 err = drm_universal_plane_init(dev, plane, possible_crtcs,
CK Hu119f5172016-01-04 18:36:34 +0100194 &mtk_plane_funcs, formats,
195 ARRAY_SIZE(formats), type, NULL);
196 if (err) {
197 DRM_ERROR("failed to initialize plane\n");
198 return err;
199 }
200
Daniel Kurtz5bfafad2016-08-04 10:59:53 +0800201 drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
CK Hu119f5172016-01-04 18:36:34 +0100202
203 return 0;
204}