]> Git Repo - linux.git/blob - drivers/gpu/drm/meson/meson_crtc.c
Merge branches 'acpi-tables', 'acpi-soc', 'acpi-apei' and 'acpi-misc'
[linux.git] / drivers / gpu / drm / meson / meson_crtc.c
1 /*
2  * Copyright (C) 2016 BayLibre, SAS
3  * Author: Neil Armstrong <[email protected]>
4  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
5  * Copyright (C) 2014 Endless Mobile
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * Written by:
21  *     Jasper St. Pierre <[email protected]>
22  */
23
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/mutex.h>
27 #include <linux/platform_device.h>
28 #include <drm/drmP.h>
29 #include <drm/drm_atomic.h>
30 #include <drm/drm_atomic_helper.h>
31 #include <drm/drm_flip_work.h>
32 #include <drm/drm_crtc_helper.h>
33
34 #include "meson_crtc.h"
35 #include "meson_plane.h"
36 #include "meson_venc.h"
37 #include "meson_vpp.h"
38 #include "meson_viu.h"
39 #include "meson_canvas.h"
40 #include "meson_registers.h"
41
42 /* CRTC definition */
43
44 struct meson_crtc {
45         struct drm_crtc base;
46         struct drm_pending_vblank_event *event;
47         struct meson_drm *priv;
48         bool enabled;
49 };
50 #define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
51
52 /* CRTC */
53
54 static int meson_crtc_enable_vblank(struct drm_crtc *crtc)
55 {
56         struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
57         struct meson_drm *priv = meson_crtc->priv;
58
59         meson_venc_enable_vsync(priv);
60
61         return 0;
62 }
63
64 static void meson_crtc_disable_vblank(struct drm_crtc *crtc)
65 {
66         struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
67         struct meson_drm *priv = meson_crtc->priv;
68
69         meson_venc_disable_vsync(priv);
70 }
71
72 static const struct drm_crtc_funcs meson_crtc_funcs = {
73         .atomic_destroy_state   = drm_atomic_helper_crtc_destroy_state,
74         .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
75         .destroy                = drm_crtc_cleanup,
76         .page_flip              = drm_atomic_helper_page_flip,
77         .reset                  = drm_atomic_helper_crtc_reset,
78         .set_config             = drm_atomic_helper_set_config,
79         .enable_vblank          = meson_crtc_enable_vblank,
80         .disable_vblank         = meson_crtc_disable_vblank,
81
82 };
83
84 static void meson_crtc_enable(struct drm_crtc *crtc)
85 {
86         struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
87         struct drm_crtc_state *crtc_state = crtc->state;
88         struct meson_drm *priv = meson_crtc->priv;
89
90         DRM_DEBUG_DRIVER("\n");
91
92         if (!crtc_state) {
93                 DRM_ERROR("Invalid crtc_state\n");
94                 return;
95         }
96
97         /* Enable VPP Postblend */
98         writel(crtc_state->mode.hdisplay,
99                priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
100
101         writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
102                             priv->io_base + _REG(VPP_MISC));
103
104         drm_crtc_vblank_on(crtc);
105
106         meson_crtc->enabled = true;
107 }
108
109 static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
110                                      struct drm_crtc_state *old_state)
111 {
112         struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
113         struct meson_drm *priv = meson_crtc->priv;
114
115         DRM_DEBUG_DRIVER("\n");
116
117         if (!meson_crtc->enabled)
118                 meson_crtc_enable(crtc);
119
120         priv->viu.osd1_enabled = true;
121 }
122
123 static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
124                                       struct drm_crtc_state *old_state)
125 {
126         struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
127         struct meson_drm *priv = meson_crtc->priv;
128
129         drm_crtc_vblank_off(crtc);
130
131         priv->viu.osd1_enabled = false;
132         priv->viu.osd1_commit = false;
133
134         /* Disable VPP Postblend */
135         writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
136                             priv->io_base + _REG(VPP_MISC));
137
138         if (crtc->state->event && !crtc->state->active) {
139                 spin_lock_irq(&crtc->dev->event_lock);
140                 drm_crtc_send_vblank_event(crtc, crtc->state->event);
141                 spin_unlock_irq(&crtc->dev->event_lock);
142
143                 crtc->state->event = NULL;
144         }
145
146         meson_crtc->enabled = false;
147 }
148
149 static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
150                                     struct drm_crtc_state *state)
151 {
152         struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
153         unsigned long flags;
154
155         if (crtc->state->enable && !meson_crtc->enabled)
156                 meson_crtc_enable(crtc);
157
158         if (crtc->state->event) {
159                 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
160
161                 spin_lock_irqsave(&crtc->dev->event_lock, flags);
162                 meson_crtc->event = crtc->state->event;
163                 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
164                 crtc->state->event = NULL;
165         }
166 }
167
168 static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
169                                     struct drm_crtc_state *old_crtc_state)
170 {
171         struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
172         struct meson_drm *priv = meson_crtc->priv;
173
174         priv->viu.osd1_commit = true;
175 }
176
177 static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
178         .atomic_begin   = meson_crtc_atomic_begin,
179         .atomic_flush   = meson_crtc_atomic_flush,
180         .atomic_enable  = meson_crtc_atomic_enable,
181         .atomic_disable = meson_crtc_atomic_disable,
182 };
183
184 void meson_crtc_irq(struct meson_drm *priv)
185 {
186         struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc);
187         unsigned long flags;
188
189         /* Update the OSD registers */
190         if (priv->viu.osd1_enabled && priv->viu.osd1_commit) {
191                 writel_relaxed(priv->viu.osd1_ctrl_stat,
192                                 priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
193                 writel_relaxed(priv->viu.osd1_blk0_cfg[0],
194                                 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0));
195                 writel_relaxed(priv->viu.osd1_blk0_cfg[1],
196                                 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1));
197                 writel_relaxed(priv->viu.osd1_blk0_cfg[2],
198                                 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2));
199                 writel_relaxed(priv->viu.osd1_blk0_cfg[3],
200                                 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
201                 writel_relaxed(priv->viu.osd1_blk0_cfg[4],
202                                 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
203
204                 /* If output is interlace, make use of the Scaler */
205                 if (priv->viu.osd1_interlace) {
206                         struct drm_plane *plane = priv->primary_plane;
207                         struct drm_plane_state *state = plane->state;
208                         struct drm_rect dest = {
209                                 .x1 = state->crtc_x,
210                                 .y1 = state->crtc_y,
211                                 .x2 = state->crtc_x + state->crtc_w,
212                                 .y2 = state->crtc_y + state->crtc_h,
213                         };
214
215                         meson_vpp_setup_interlace_vscaler_osd1(priv, &dest);
216                 } else
217                         meson_vpp_disable_interlace_vscaler_osd1(priv);
218
219                 meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
220                            priv->viu.osd1_addr, priv->viu.osd1_stride,
221                            priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
222                            MESON_CANVAS_BLKMODE_LINEAR);
223
224                 /* Enable OSD1 */
225                 writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
226                                     priv->io_base + _REG(VPP_MISC));
227
228                 priv->viu.osd1_commit = false;
229         }
230
231         drm_crtc_handle_vblank(priv->crtc);
232
233         spin_lock_irqsave(&priv->drm->event_lock, flags);
234         if (meson_crtc->event) {
235                 drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
236                 drm_crtc_vblank_put(priv->crtc);
237                 meson_crtc->event = NULL;
238         }
239         spin_unlock_irqrestore(&priv->drm->event_lock, flags);
240 }
241
242 int meson_crtc_create(struct meson_drm *priv)
243 {
244         struct meson_crtc *meson_crtc;
245         struct drm_crtc *crtc;
246         int ret;
247
248         meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
249                                   GFP_KERNEL);
250         if (!meson_crtc)
251                 return -ENOMEM;
252
253         meson_crtc->priv = priv;
254         crtc = &meson_crtc->base;
255         ret = drm_crtc_init_with_planes(priv->drm, crtc,
256                                         priv->primary_plane, NULL,
257                                         &meson_crtc_funcs, "meson_crtc");
258         if (ret) {
259                 dev_err(priv->drm->dev, "Failed to init CRTC\n");
260                 return ret;
261         }
262
263         drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs);
264
265         priv->crtc = crtc;
266
267         return 0;
268 }
This page took 0.047019 seconds and 4 git commands to generate.