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/drm | |
| 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/drm')
| -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); |
