diff options
author | Thierry Reding <thierry.reding@avionic-design.de> | 2012-11-28 06:00:18 -0500 |
---|---|---|
committer | Thierry Reding <thierry.reding@avionic-design.de> | 2013-02-22 02:21:27 -0500 |
commit | 3c03c46ac80ea7edc3b8f2ba85085de54aec15cd (patch) | |
tree | 3eaec0c908b711961ac00c22d5c09a54faff709d /drivers/gpu | |
parent | 6e5ff998997ba7dc5ca10b6662e95a9d07f764c4 (diff) |
drm/tegra: Implement page-flipping support
All the necessary support bits like .mode_set_base() and VBLANK are now
available, so page-flipping case easily be implemented on top.
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 66 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 5 |
4 files changed, 82 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 5f55a25424a7..c5d825fd25fe 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
@@ -183,7 +183,72 @@ void tegra_dc_disable_vblank(struct tegra_dc *dc) | |||
183 | spin_unlock_irqrestore(&dc->lock, flags); | 183 | spin_unlock_irqrestore(&dc->lock, flags); |
184 | } | 184 | } |
185 | 185 | ||
186 | static void tegra_dc_finish_page_flip(struct tegra_dc *dc) | ||
187 | { | ||
188 | struct drm_device *drm = dc->base.dev; | ||
189 | struct drm_crtc *crtc = &dc->base; | ||
190 | struct drm_gem_cma_object *gem; | ||
191 | unsigned long flags, base; | ||
192 | |||
193 | if (!dc->event) | ||
194 | return; | ||
195 | |||
196 | gem = drm_fb_cma_get_gem_obj(crtc->fb, 0); | ||
197 | |||
198 | /* check if new start address has been latched */ | ||
199 | tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); | ||
200 | base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); | ||
201 | tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); | ||
202 | |||
203 | if (base == gem->paddr + crtc->fb->offsets[0]) { | ||
204 | spin_lock_irqsave(&drm->event_lock, flags); | ||
205 | drm_send_vblank_event(drm, dc->pipe, dc->event); | ||
206 | drm_vblank_put(drm, dc->pipe); | ||
207 | dc->event = NULL; | ||
208 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) | ||
213 | { | ||
214 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
215 | struct drm_device *drm = crtc->dev; | ||
216 | unsigned long flags; | ||
217 | |||
218 | spin_lock_irqsave(&drm->event_lock, flags); | ||
219 | |||
220 | if (dc->event && dc->event->base.file_priv == file) { | ||
221 | dc->event->base.destroy(&dc->event->base); | ||
222 | drm_vblank_put(drm, dc->pipe); | ||
223 | dc->event = NULL; | ||
224 | } | ||
225 | |||
226 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
227 | } | ||
228 | |||
229 | static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | ||
230 | struct drm_pending_vblank_event *event) | ||
231 | { | ||
232 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
233 | struct drm_device *drm = crtc->dev; | ||
234 | |||
235 | if (dc->event) | ||
236 | return -EBUSY; | ||
237 | |||
238 | if (event) { | ||
239 | event->pipe = dc->pipe; | ||
240 | dc->event = event; | ||
241 | drm_vblank_get(drm, dc->pipe); | ||
242 | } | ||
243 | |||
244 | tegra_dc_set_base(dc, 0, 0, fb); | ||
245 | crtc->fb = fb; | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
186 | static const struct drm_crtc_funcs tegra_crtc_funcs = { | 250 | static const struct drm_crtc_funcs tegra_crtc_funcs = { |
251 | .page_flip = tegra_dc_page_flip, | ||
187 | .set_config = drm_crtc_helper_set_config, | 252 | .set_config = drm_crtc_helper_set_config, |
188 | .destroy = drm_crtc_cleanup, | 253 | .destroy = drm_crtc_cleanup, |
189 | }; | 254 | }; |
@@ -665,6 +730,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data) | |||
665 | dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); | 730 | dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); |
666 | */ | 731 | */ |
667 | drm_handle_vblank(dc->base.dev, dc->pipe); | 732 | drm_handle_vblank(dc->base.dev, dc->pipe); |
733 | tegra_dc_finish_page_flip(dc); | ||
668 | } | 734 | } |
669 | 735 | ||
670 | if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) { | 736 | if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) { |
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index e2fa328861ca..79eaec9aac77 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h | |||
@@ -58,6 +58,8 @@ | |||
58 | #define DC_CMD_SIGNAL_RAISE3 0x03e | 58 | #define DC_CMD_SIGNAL_RAISE3 0x03e |
59 | 59 | ||
60 | #define DC_CMD_STATE_ACCESS 0x040 | 60 | #define DC_CMD_STATE_ACCESS 0x040 |
61 | #define READ_MUX (1 << 0) | ||
62 | #define WRITE_MUX (1 << 2) | ||
61 | 63 | ||
62 | #define DC_CMD_STATE_CONTROL 0x041 | 64 | #define DC_CMD_STATE_CONTROL 0x041 |
63 | #define GENERAL_ACT_REQ (1 << 0) | 65 | #define GENERAL_ACT_REQ (1 << 0) |
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 4e31dace5275..97485af6eaf9 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
@@ -135,11 +135,20 @@ static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe) | |||
135 | tegra_dc_disable_vblank(dc); | 135 | tegra_dc_disable_vblank(dc); |
136 | } | 136 | } |
137 | 137 | ||
138 | static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) | ||
139 | { | ||
140 | struct drm_crtc *crtc; | ||
141 | |||
142 | list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) | ||
143 | tegra_dc_cancel_page_flip(crtc, file); | ||
144 | } | ||
145 | |||
138 | struct drm_driver tegra_drm_driver = { | 146 | struct drm_driver tegra_drm_driver = { |
139 | .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM, | 147 | .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM, |
140 | .load = tegra_drm_load, | 148 | .load = tegra_drm_load, |
141 | .unload = tegra_drm_unload, | 149 | .unload = tegra_drm_unload, |
142 | .open = tegra_drm_open, | 150 | .open = tegra_drm_open, |
151 | .preclose = tegra_drm_preclose, | ||
143 | .lastclose = tegra_drm_lastclose, | 152 | .lastclose = tegra_drm_lastclose, |
144 | 153 | ||
145 | .get_vblank_counter = tegra_drm_get_vblank_counter, | 154 | .get_vblank_counter = tegra_drm_get_vblank_counter, |
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 01f0aee12ad9..6dd75a2600eb 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h | |||
@@ -84,6 +84,9 @@ struct tegra_dc { | |||
84 | struct drm_info_list *debugfs_files; | 84 | struct drm_info_list *debugfs_files; |
85 | struct drm_minor *minor; | 85 | struct drm_minor *minor; |
86 | struct dentry *debugfs; | 86 | struct dentry *debugfs; |
87 | |||
88 | /* page-flip handling */ | ||
89 | struct drm_pending_vblank_event *event; | ||
87 | }; | 90 | }; |
88 | 91 | ||
89 | static inline struct tegra_dc *host1x_client_to_dc(struct host1x_client *client) | 92 | static inline struct tegra_dc *host1x_client_to_dc(struct host1x_client *client) |
@@ -133,6 +136,8 @@ extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | |||
133 | const struct tegra_dc_window *window); | 136 | const struct tegra_dc_window *window); |
134 | extern void tegra_dc_enable_vblank(struct tegra_dc *dc); | 137 | extern void tegra_dc_enable_vblank(struct tegra_dc *dc); |
135 | extern void tegra_dc_disable_vblank(struct tegra_dc *dc); | 138 | extern void tegra_dc_disable_vblank(struct tegra_dc *dc); |
139 | extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, | ||
140 | struct drm_file *file); | ||
136 | 141 | ||
137 | struct tegra_output_ops { | 142 | struct tegra_output_ops { |
138 | int (*enable)(struct tegra_output *output); | 143 | int (*enable)(struct tegra_output *output); |