Commit | Line | Data |
---|---|---|
cd5351f4 RC |
1 | /* |
2 | * drivers/staging/omapdrm/omap_crtc.c | |
3 | * | |
4 | * Copyright (C) 2011 Texas Instruments | |
5 | * Author: Rob Clark <rob@ti.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License version 2 as published by | |
9 | * the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include "omap_drv.h" | |
21 | ||
22 | #include "drm_mode.h" | |
23 | #include "drm_crtc.h" | |
24 | #include "drm_crtc_helper.h" | |
25 | ||
26 | #define to_omap_crtc(x) container_of(x, struct omap_crtc, base) | |
27 | ||
28 | struct omap_crtc { | |
29 | struct drm_crtc base; | |
bb5c2d9a RC |
30 | struct drm_plane *plane; |
31 | const char *name; | |
cd5351f4 RC |
32 | int id; |
33 | ||
bb5c2d9a | 34 | /* if there is a pending flip, these will be non-null: */ |
cd5351f4 | 35 | struct drm_pending_vblank_event *event; |
bb5c2d9a | 36 | struct drm_framebuffer *old_fb; |
cd5351f4 RC |
37 | }; |
38 | ||
cd5351f4 RC |
39 | static void omap_crtc_gamma_set(struct drm_crtc *crtc, |
40 | u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size) | |
41 | { | |
bb5c2d9a | 42 | /* not supported.. at least not yet */ |
cd5351f4 RC |
43 | } |
44 | ||
45 | static void omap_crtc_destroy(struct drm_crtc *crtc) | |
46 | { | |
47 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
bb5c2d9a | 48 | omap_crtc->plane->funcs->destroy(omap_crtc->plane); |
cd5351f4 RC |
49 | drm_crtc_cleanup(crtc); |
50 | kfree(omap_crtc); | |
51 | } | |
52 | ||
53 | static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) | |
54 | { | |
bb5c2d9a | 55 | struct omap_drm_private *priv = crtc->dev->dev_private; |
cd5351f4 | 56 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
bb5c2d9a | 57 | int i; |
cd5351f4 | 58 | |
bb5c2d9a | 59 | WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); |
cd5351f4 | 60 | |
bb5c2d9a RC |
61 | for (i = 0; i < priv->num_planes; i++) { |
62 | struct drm_plane *plane = priv->planes[i]; | |
63 | if (plane->crtc == crtc) | |
64 | WARN_ON(omap_plane_dpms(plane, mode)); | |
cd5351f4 | 65 | } |
cd5351f4 RC |
66 | } |
67 | ||
68 | static bool omap_crtc_mode_fixup(struct drm_crtc *crtc, | |
bb5c2d9a RC |
69 | struct drm_display_mode *mode, |
70 | struct drm_display_mode *adjusted_mode) | |
cd5351f4 | 71 | { |
cd5351f4 RC |
72 | return true; |
73 | } | |
74 | ||
75 | static int omap_crtc_mode_set(struct drm_crtc *crtc, | |
bb5c2d9a RC |
76 | struct drm_display_mode *mode, |
77 | struct drm_display_mode *adjusted_mode, | |
78 | int x, int y, | |
79 | struct drm_framebuffer *old_fb) | |
cd5351f4 RC |
80 | { |
81 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
bb5c2d9a | 82 | struct drm_plane *plane = omap_crtc->plane; |
cd5351f4 | 83 | |
bb5c2d9a RC |
84 | return plane->funcs->update_plane(plane, crtc, crtc->fb, |
85 | 0, 0, mode->hdisplay, mode->vdisplay, | |
86 | x << 16, y << 16, | |
87 | mode->hdisplay << 16, mode->vdisplay << 16); | |
cd5351f4 RC |
88 | } |
89 | ||
90 | static void omap_crtc_prepare(struct drm_crtc *crtc) | |
91 | { | |
92 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
bb5c2d9a | 93 | DBG("%s", omap_crtc->name); |
cd5351f4 RC |
94 | omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
95 | } | |
96 | ||
97 | static void omap_crtc_commit(struct drm_crtc *crtc) | |
98 | { | |
99 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
bb5c2d9a | 100 | DBG("%s", omap_crtc->name); |
cd5351f4 RC |
101 | omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON); |
102 | } | |
103 | ||
104 | static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | |
bb5c2d9a | 105 | struct drm_framebuffer *old_fb) |
cd5351f4 RC |
106 | { |
107 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
bb5c2d9a RC |
108 | struct drm_plane *plane = omap_crtc->plane; |
109 | struct drm_display_mode *mode = &crtc->mode; | |
cd5351f4 | 110 | |
bb5c2d9a RC |
111 | return plane->funcs->update_plane(plane, crtc, crtc->fb, |
112 | 0, 0, mode->hdisplay, mode->vdisplay, | |
113 | x << 16, y << 16, | |
114 | mode->hdisplay << 16, mode->vdisplay << 16); | |
cd5351f4 RC |
115 | } |
116 | ||
117 | static void omap_crtc_load_lut(struct drm_crtc *crtc) | |
118 | { | |
cd5351f4 RC |
119 | } |
120 | ||
121 | static void page_flip_cb(void *arg) | |
122 | { | |
123 | struct drm_crtc *crtc = arg; | |
124 | struct drm_device *dev = crtc->dev; | |
125 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
126 | struct drm_pending_vblank_event *event = omap_crtc->event; | |
bb5c2d9a | 127 | struct drm_framebuffer *old_fb = omap_crtc->old_fb; |
cd5351f4 RC |
128 | struct timeval now; |
129 | unsigned long flags; | |
130 | ||
131 | WARN_ON(!event); | |
132 | ||
133 | omap_crtc->event = NULL; | |
bb5c2d9a | 134 | omap_crtc->old_fb = NULL; |
cd5351f4 | 135 | |
bb5c2d9a | 136 | omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); |
cd5351f4 RC |
137 | |
138 | /* wakeup userspace */ | |
139 | /* TODO: this should happen *after* flip in vsync IRQ handler */ | |
140 | if (event) { | |
141 | spin_lock_irqsave(&dev->event_lock, flags); | |
142 | event->event.sequence = drm_vblank_count_and_time( | |
143 | dev, omap_crtc->id, &now); | |
144 | event->event.tv_sec = now.tv_sec; | |
145 | event->event.tv_usec = now.tv_usec; | |
146 | list_add_tail(&event->base.link, | |
147 | &event->base.file_priv->event_list); | |
148 | wake_up_interruptible(&event->base.file_priv->event_wait); | |
149 | spin_unlock_irqrestore(&dev->event_lock, flags); | |
150 | } | |
151 | } | |
152 | ||
153 | static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, | |
154 | struct drm_framebuffer *fb, | |
155 | struct drm_pending_vblank_event *event) | |
156 | { | |
157 | struct drm_device *dev = crtc->dev; | |
158 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
159 | ||
160 | DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id); | |
161 | ||
162 | if (omap_crtc->event) { | |
163 | dev_err(dev->dev, "already a pending flip\n"); | |
164 | return -EINVAL; | |
165 | } | |
166 | ||
bb5c2d9a | 167 | omap_crtc->old_fb = crtc->fb; |
cd5351f4 | 168 | omap_crtc->event = event; |
bb5c2d9a | 169 | crtc->fb = fb; |
cd5351f4 | 170 | |
9a0774e0 | 171 | omap_gem_op_async(omap_framebuffer_bo(fb, 0), OMAP_GEM_READ, |
cd5351f4 RC |
172 | page_flip_cb, crtc); |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
177 | static const struct drm_crtc_funcs omap_crtc_funcs = { | |
178 | .gamma_set = omap_crtc_gamma_set, | |
179 | .set_config = drm_crtc_helper_set_config, | |
180 | .destroy = omap_crtc_destroy, | |
181 | .page_flip = omap_crtc_page_flip_locked, | |
182 | }; | |
183 | ||
184 | static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { | |
185 | .dpms = omap_crtc_dpms, | |
186 | .mode_fixup = omap_crtc_mode_fixup, | |
187 | .mode_set = omap_crtc_mode_set, | |
188 | .prepare = omap_crtc_prepare, | |
189 | .commit = omap_crtc_commit, | |
190 | .mode_set_base = omap_crtc_mode_set_base, | |
191 | .load_lut = omap_crtc_load_lut, | |
192 | }; | |
193 | ||
cd5351f4 RC |
194 | /* initialize crtc */ |
195 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |
196 | struct omap_overlay *ovl, int id) | |
197 | { | |
198 | struct drm_crtc *crtc = NULL; | |
199 | struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); | |
200 | ||
201 | DBG("%s", ovl->name); | |
202 | ||
203 | if (!omap_crtc) { | |
204 | dev_err(dev->dev, "could not allocate CRTC\n"); | |
205 | goto fail; | |
206 | } | |
207 | ||
cd5351f4 | 208 | crtc = &omap_crtc->base; |
bb5c2d9a RC |
209 | |
210 | omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true); | |
211 | omap_crtc->plane->crtc = crtc; | |
212 | omap_crtc->name = ovl->name; | |
213 | omap_crtc->id = id; | |
214 | ||
cd5351f4 RC |
215 | drm_crtc_init(dev, crtc, &omap_crtc_funcs); |
216 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); | |
217 | ||
218 | return crtc; | |
219 | ||
220 | fail: | |
221 | if (crtc) { | |
65b0bd06 | 222 | omap_crtc_destroy(crtc); |
cd5351f4 RC |
223 | } |
224 | return NULL; | |
225 | } |