diff options
| -rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 55 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 50 | ||||
| -rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 3 |
3 files changed, 91 insertions, 17 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index ceb2f52c8f7e..5f55a25424a7 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
| @@ -157,6 +157,32 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, | |||
| 157 | return 0; | 157 | return 0; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | void tegra_dc_enable_vblank(struct tegra_dc *dc) | ||
| 161 | { | ||
| 162 | unsigned long value, flags; | ||
| 163 | |||
| 164 | spin_lock_irqsave(&dc->lock, flags); | ||
| 165 | |||
| 166 | value = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
| 167 | value |= VBLANK_INT; | ||
| 168 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 169 | |||
| 170 | spin_unlock_irqrestore(&dc->lock, flags); | ||
| 171 | } | ||
| 172 | |||
| 173 | void tegra_dc_disable_vblank(struct tegra_dc *dc) | ||
| 174 | { | ||
| 175 | unsigned long value, flags; | ||
| 176 | |||
| 177 | spin_lock_irqsave(&dc->lock, flags); | ||
| 178 | |||
| 179 | value = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
| 180 | value &= ~VBLANK_INT; | ||
| 181 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 182 | |||
| 183 | spin_unlock_irqrestore(&dc->lock, flags); | ||
| 184 | } | ||
| 185 | |||
| 160 | static const struct drm_crtc_funcs tegra_crtc_funcs = { | 186 | static const struct drm_crtc_funcs tegra_crtc_funcs = { |
| 161 | .set_config = drm_crtc_helper_set_config, | 187 | .set_config = drm_crtc_helper_set_config, |
| 162 | .destroy = drm_crtc_cleanup, | 188 | .destroy = drm_crtc_cleanup, |
| @@ -485,6 +511,8 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, | |||
| 485 | unsigned long div, value; | 511 | unsigned long div, value; |
| 486 | int err; | 512 | int err; |
| 487 | 513 | ||
| 514 | drm_vblank_pre_modeset(crtc->dev, dc->pipe); | ||
| 515 | |||
| 488 | err = tegra_crtc_setup_clk(crtc, mode, &div); | 516 | err = tegra_crtc_setup_clk(crtc, mode, &div); |
| 489 | if (err) { | 517 | if (err) { |
| 490 | dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err); | 518 | dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err); |
| @@ -585,31 +613,23 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) | |||
| 585 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | 613 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); |
| 586 | 614 | ||
| 587 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; | 615 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; |
| 588 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 589 | |||
| 590 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; | ||
| 591 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | 616 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); |
| 617 | |||
| 618 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; | ||
| 619 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 592 | } | 620 | } |
| 593 | 621 | ||
| 594 | static void tegra_crtc_commit(struct drm_crtc *crtc) | 622 | static void tegra_crtc_commit(struct drm_crtc *crtc) |
| 595 | { | 623 | { |
| 596 | struct tegra_dc *dc = to_tegra_dc(crtc); | 624 | struct tegra_dc *dc = to_tegra_dc(crtc); |
| 597 | unsigned long update_mask; | ||
| 598 | unsigned long value; | 625 | unsigned long value; |
| 599 | 626 | ||
| 600 | update_mask = GENERAL_ACT_REQ | WIN_A_ACT_REQ; | 627 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ | |
| 601 | 628 | GENERAL_UPDATE | WIN_A_UPDATE; | |
| 602 | tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL); | ||
| 603 | |||
| 604 | value = tegra_dc_readl(dc, DC_CMD_INT_ENABLE); | ||
| 605 | value |= FRAME_END_INT; | ||
| 606 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | ||
| 607 | 629 | ||
| 608 | value = tegra_dc_readl(dc, DC_CMD_INT_MASK); | 630 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); |
| 609 | value |= FRAME_END_INT; | ||
| 610 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 611 | 631 | ||
| 612 | tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL); | 632 | drm_vblank_post_modeset(crtc->dev, dc->pipe); |
| 613 | } | 633 | } |
| 614 | 634 | ||
| 615 | static void tegra_crtc_load_lut(struct drm_crtc *crtc) | 635 | static void tegra_crtc_load_lut(struct drm_crtc *crtc) |
| @@ -626,7 +646,7 @@ static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { | |||
| 626 | .load_lut = tegra_crtc_load_lut, | 646 | .load_lut = tegra_crtc_load_lut, |
| 627 | }; | 647 | }; |
| 628 | 648 | ||
| 629 | static irqreturn_t tegra_drm_irq(int irq, void *data) | 649 | static irqreturn_t tegra_dc_irq(int irq, void *data) |
| 630 | { | 650 | { |
| 631 | struct tegra_dc *dc = data; | 651 | struct tegra_dc *dc = data; |
| 632 | unsigned long status; | 652 | unsigned long status; |
| @@ -971,7 +991,7 @@ static int tegra_dc_drm_init(struct host1x_client *client, | |||
| 971 | dev_err(dc->dev, "debugfs setup failed: %d\n", err); | 991 | dev_err(dc->dev, "debugfs setup failed: %d\n", err); |
| 972 | } | 992 | } |
| 973 | 993 | ||
| 974 | err = devm_request_irq(dc->dev, dc->irq, tegra_drm_irq, 0, | 994 | err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0, |
| 975 | dev_name(dc->dev), dc); | 995 | dev_name(dc->dev), dc); |
| 976 | if (err < 0) { | 996 | if (err < 0) { |
| 977 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, | 997 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, |
| @@ -1020,6 +1040,7 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
| 1020 | if (!dc) | 1040 | if (!dc) |
| 1021 | return -ENOMEM; | 1041 | return -ENOMEM; |
| 1022 | 1042 | ||
| 1043 | spin_lock_init(&dc->lock); | ||
| 1023 | INIT_LIST_HEAD(&dc->list); | 1044 | INIT_LIST_HEAD(&dc->list); |
| 1024 | dc->dev = &pdev->dev; | 1045 | dc->dev = &pdev->dev; |
| 1025 | 1046 | ||
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 3a503c9e4686..4e31dace5275 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c | |||
| @@ -40,6 +40,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) | |||
| 40 | if (err < 0) | 40 | if (err < 0) |
| 41 | return err; | 41 | return err; |
| 42 | 42 | ||
| 43 | err = drm_vblank_init(drm, drm->mode_config.num_crtc); | ||
| 44 | if (err < 0) | ||
| 45 | return err; | ||
| 46 | |||
| 43 | err = tegra_drm_fb_init(drm); | 47 | err = tegra_drm_fb_init(drm); |
| 44 | if (err < 0) | 48 | if (err < 0) |
| 45 | return err; | 49 | return err; |
| @@ -89,6 +93,48 @@ static const struct file_operations tegra_drm_fops = { | |||
| 89 | .llseek = noop_llseek, | 93 | .llseek = noop_llseek, |
| 90 | }; | 94 | }; |
| 91 | 95 | ||
| 96 | static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe) | ||
| 97 | { | ||
| 98 | struct drm_crtc *crtc; | ||
| 99 | |||
| 100 | list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) { | ||
| 101 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 102 | |||
| 103 | if (dc->pipe == pipe) | ||
| 104 | return crtc; | ||
| 105 | } | ||
| 106 | |||
| 107 | return NULL; | ||
| 108 | } | ||
| 109 | |||
| 110 | static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc) | ||
| 111 | { | ||
| 112 | /* TODO: implement real hardware counter using syncpoints */ | ||
| 113 | return drm_vblank_count(dev, crtc); | ||
| 114 | } | ||
| 115 | |||
| 116 | static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) | ||
| 117 | { | ||
| 118 | struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); | ||
| 119 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 120 | |||
| 121 | if (!crtc) | ||
| 122 | return -ENODEV; | ||
| 123 | |||
| 124 | tegra_dc_enable_vblank(dc); | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe) | ||
| 130 | { | ||
| 131 | struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); | ||
| 132 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 133 | |||
| 134 | if (crtc) | ||
| 135 | tegra_dc_disable_vblank(dc); | ||
| 136 | } | ||
| 137 | |||
| 92 | struct drm_driver tegra_drm_driver = { | 138 | struct drm_driver tegra_drm_driver = { |
| 93 | .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM, | 139 | .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM, |
| 94 | .load = tegra_drm_load, | 140 | .load = tegra_drm_load, |
| @@ -96,6 +142,10 @@ struct drm_driver tegra_drm_driver = { | |||
| 96 | .open = tegra_drm_open, | 142 | .open = tegra_drm_open, |
| 97 | .lastclose = tegra_drm_lastclose, | 143 | .lastclose = tegra_drm_lastclose, |
| 98 | 144 | ||
| 145 | .get_vblank_counter = tegra_drm_get_vblank_counter, | ||
| 146 | .enable_vblank = tegra_drm_enable_vblank, | ||
| 147 | .disable_vblank = tegra_drm_disable_vblank, | ||
| 148 | |||
| 99 | .gem_free_object = drm_gem_cma_free_object, | 149 | .gem_free_object = drm_gem_cma_free_object, |
| 100 | .gem_vm_ops = &drm_gem_cma_vm_ops, | 150 | .gem_vm_ops = &drm_gem_cma_vm_ops, |
| 101 | .dumb_create = drm_gem_cma_dumb_create, | 151 | .dumb_create = drm_gem_cma_dumb_create, |
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 896ff43d32b1..01f0aee12ad9 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h | |||
| @@ -64,6 +64,7 @@ struct tegra_output; | |||
| 64 | 64 | ||
| 65 | struct tegra_dc { | 65 | struct tegra_dc { |
| 66 | struct host1x_client client; | 66 | struct host1x_client client; |
| 67 | spinlock_t lock; | ||
| 67 | 68 | ||
| 68 | struct host1x *host1x; | 69 | struct host1x *host1x; |
| 69 | struct device *dev; | 70 | struct device *dev; |
| @@ -130,6 +131,8 @@ struct tegra_dc_window { | |||
| 130 | extern unsigned int tegra_dc_format(uint32_t format); | 131 | extern unsigned int tegra_dc_format(uint32_t format); |
| 131 | extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | 132 | extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, |
| 132 | const struct tegra_dc_window *window); | 133 | const struct tegra_dc_window *window); |
| 134 | extern void tegra_dc_enable_vblank(struct tegra_dc *dc); | ||
| 135 | extern void tegra_dc_disable_vblank(struct tegra_dc *dc); | ||
| 133 | 136 | ||
| 134 | struct tegra_output_ops { | 137 | struct tegra_output_ops { |
| 135 | int (*enable)(struct tegra_output *output); | 138 | int (*enable)(struct tegra_output *output); |
