aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorThierry Reding <thierry.reding@avionic-design.de>2012-11-28 06:00:18 -0500
committerThierry Reding <thierry.reding@avionic-design.de>2013-02-22 02:21:27 -0500
commit3c03c46ac80ea7edc3b8f2ba85085de54aec15cd (patch)
tree3eaec0c908b711961ac00c22d5c09a54faff709d /drivers/gpu
parent6e5ff998997ba7dc5ca10b6662e95a9d07f764c4 (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.c66
-rw-r--r--drivers/gpu/drm/tegra/dc.h2
-rw-r--r--drivers/gpu/drm/tegra/drm.c9
-rw-r--r--drivers/gpu/drm/tegra/drm.h5
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
186static 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
212void 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
229static 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
186static const struct drm_crtc_funcs tegra_crtc_funcs = { 250static 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
138static 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
138struct drm_driver tegra_drm_driver = { 146struct 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
89static inline struct tegra_dc *host1x_client_to_dc(struct host1x_client *client) 92static 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);
134extern void tegra_dc_enable_vblank(struct tegra_dc *dc); 137extern void tegra_dc_enable_vblank(struct tegra_dc *dc);
135extern void tegra_dc_disable_vblank(struct tegra_dc *dc); 138extern void tegra_dc_disable_vblank(struct tegra_dc *dc);
139extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc,
140 struct drm_file *file);
136 141
137struct tegra_output_ops { 142struct tegra_output_ops {
138 int (*enable)(struct tegra_output *output); 143 int (*enable)(struct tegra_output *output);