diff options
Diffstat (limited to 'drivers')
-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); |