diff options
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 157 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.h | 38 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_encoder.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_irq.c | 17 |
5 files changed, 165 insertions, 75 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index bec66a490b8f..79b200aee18a 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c | |||
@@ -74,6 +74,13 @@ struct omap_crtc { | |||
74 | struct work_struct page_flip_work; | 74 | struct work_struct page_flip_work; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | uint32_t pipe2vbl(struct drm_crtc *crtc) | ||
78 | { | ||
79 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
80 | |||
81 | return dispc_mgr_get_vsync_irq(omap_crtc->channel); | ||
82 | } | ||
83 | |||
77 | /* | 84 | /* |
78 | * Manager-ops, callbacks from output when they need to configure | 85 | * Manager-ops, callbacks from output when they need to configure |
79 | * the upstream part of the video pipe. | 86 | * the upstream part of the video pipe. |
@@ -613,7 +620,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
613 | omap_crtc->apply.pre_apply = omap_crtc_pre_apply; | 620 | omap_crtc->apply.pre_apply = omap_crtc_pre_apply; |
614 | omap_crtc->apply.post_apply = omap_crtc_post_apply; | 621 | omap_crtc->apply.post_apply = omap_crtc_post_apply; |
615 | 622 | ||
616 | omap_crtc->apply_irq.irqmask = pipe2vbl(id); | 623 | omap_crtc->channel = channel; |
624 | omap_crtc->plane = plane; | ||
625 | omap_crtc->plane->crtc = crtc; | ||
626 | omap_crtc->name = channel_names[channel]; | ||
627 | omap_crtc->pipe = id; | ||
628 | |||
629 | omap_crtc->apply_irq.irqmask = pipe2vbl(crtc); | ||
617 | omap_crtc->apply_irq.irq = omap_crtc_apply_irq; | 630 | omap_crtc->apply_irq.irq = omap_crtc_apply_irq; |
618 | 631 | ||
619 | omap_crtc->error_irq.irqmask = | 632 | omap_crtc->error_irq.irqmask = |
@@ -621,12 +634,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
621 | omap_crtc->error_irq.irq = omap_crtc_error_irq; | 634 | omap_crtc->error_irq.irq = omap_crtc_error_irq; |
622 | omap_irq_register(dev, &omap_crtc->error_irq); | 635 | omap_irq_register(dev, &omap_crtc->error_irq); |
623 | 636 | ||
624 | omap_crtc->channel = channel; | ||
625 | omap_crtc->plane = plane; | ||
626 | omap_crtc->plane->crtc = crtc; | ||
627 | omap_crtc->name = channel_names[channel]; | ||
628 | omap_crtc->pipe = id; | ||
629 | |||
630 | /* temporary: */ | 637 | /* temporary: */ |
631 | omap_crtc->mgr.id = channel; | 638 | omap_crtc->mgr.id = channel; |
632 | 639 | ||
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 77b72259f15b..cbaa00338b62 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c | |||
@@ -74,49 +74,48 @@ static int get_connector_type(struct omap_dss_device *dssdev) | |||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | static bool channel_used(struct drm_device *dev, enum omap_channel channel) | ||
78 | { | ||
79 | struct omap_drm_private *priv = dev->dev_private; | ||
80 | int i; | ||
81 | |||
82 | for (i = 0; i < priv->num_crtcs; i++) { | ||
83 | struct drm_crtc *crtc = priv->crtcs[i]; | ||
84 | |||
85 | if (omap_crtc_channel(crtc) == channel) | ||
86 | return true; | ||
87 | } | ||
88 | |||
89 | return false; | ||
90 | } | ||
91 | |||
77 | static int omap_modeset_init(struct drm_device *dev) | 92 | static int omap_modeset_init(struct drm_device *dev) |
78 | { | 93 | { |
79 | struct omap_drm_private *priv = dev->dev_private; | 94 | struct omap_drm_private *priv = dev->dev_private; |
80 | struct omap_dss_device *dssdev = NULL; | 95 | struct omap_dss_device *dssdev = NULL; |
81 | int num_ovls = dss_feat_get_num_ovls(); | 96 | int num_ovls = dss_feat_get_num_ovls(); |
82 | int id; | 97 | int num_mgrs = dss_feat_get_num_mgrs(); |
98 | int num_crtcs; | ||
99 | int i, id = 0; | ||
83 | 100 | ||
84 | drm_mode_config_init(dev); | 101 | drm_mode_config_init(dev); |
85 | 102 | ||
86 | omap_drm_irq_install(dev); | 103 | omap_drm_irq_install(dev); |
87 | 104 | ||
88 | /* | 105 | /* |
89 | * Create private planes and CRTCs for the last NUM_CRTCs overlay | 106 | * We usually don't want to create a CRTC for each manager, at least |
90 | * plus manager: | 107 | * not until we have a way to expose private planes to userspace. |
91 | */ | 108 | * Otherwise there would not be enough video pipes left for drm planes. |
92 | for (id = 0; id < min(num_crtc, num_ovls); id++) { | 109 | * We use the num_crtc argument to limit the number of crtcs we create. |
93 | struct drm_plane *plane; | ||
94 | struct drm_crtc *crtc; | ||
95 | |||
96 | plane = omap_plane_init(dev, id, true); | ||
97 | crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); | ||
98 | |||
99 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); | ||
100 | priv->crtcs[id] = crtc; | ||
101 | priv->num_crtcs++; | ||
102 | |||
103 | priv->planes[id] = plane; | ||
104 | priv->num_planes++; | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Create normal planes for the remaining overlays: | ||
109 | */ | 110 | */ |
110 | for (; id < num_ovls; id++) { | 111 | num_crtcs = min3(num_crtc, num_mgrs, num_ovls); |
111 | struct drm_plane *plane = omap_plane_init(dev, id, false); | ||
112 | 112 | ||
113 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); | 113 | dssdev = NULL; |
114 | priv->planes[priv->num_planes++] = plane; | ||
115 | } | ||
116 | 114 | ||
117 | for_each_dss_dev(dssdev) { | 115 | for_each_dss_dev(dssdev) { |
118 | struct drm_connector *connector; | 116 | struct drm_connector *connector; |
119 | struct drm_encoder *encoder; | 117 | struct drm_encoder *encoder; |
118 | enum omap_channel channel; | ||
120 | 119 | ||
121 | if (!dssdev->driver) { | 120 | if (!dssdev->driver) { |
122 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | 121 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", |
@@ -157,16 +156,118 @@ static int omap_modeset_init(struct drm_device *dev) | |||
157 | 156 | ||
158 | drm_mode_connector_attach_encoder(connector, encoder); | 157 | drm_mode_connector_attach_encoder(connector, encoder); |
159 | 158 | ||
159 | /* | ||
160 | * if we have reached the limit of the crtcs we are allowed to | ||
161 | * create, let's not try to look for a crtc for this | ||
162 | * panel/encoder and onwards, we will, of course, populate the | ||
163 | * the possible_crtcs field for all the encoders with the final | ||
164 | * set of crtcs we create | ||
165 | */ | ||
166 | if (id == num_crtcs) | ||
167 | continue; | ||
168 | |||
169 | /* | ||
170 | * get the recommended DISPC channel for this encoder. For now, | ||
171 | * we only try to get create a crtc out of the recommended, the | ||
172 | * other possible channels to which the encoder can connect are | ||
173 | * not considered. | ||
174 | */ | ||
175 | channel = dssdev->output->dispc_channel; | ||
176 | |||
177 | /* | ||
178 | * if this channel hasn't already been taken by a previously | ||
179 | * allocated crtc, we create a new crtc for it | ||
180 | */ | ||
181 | if (!channel_used(dev, channel)) { | ||
182 | struct drm_plane *plane; | ||
183 | struct drm_crtc *crtc; | ||
184 | |||
185 | plane = omap_plane_init(dev, id, true); | ||
186 | crtc = omap_crtc_init(dev, plane, channel, id); | ||
187 | |||
188 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); | ||
189 | priv->crtcs[id] = crtc; | ||
190 | priv->num_crtcs++; | ||
191 | |||
192 | priv->planes[id] = plane; | ||
193 | priv->num_planes++; | ||
194 | |||
195 | id++; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * we have allocated crtcs according to the need of the panels/encoders, | ||
201 | * adding more crtcs here if needed | ||
202 | */ | ||
203 | for (; id < num_crtcs; id++) { | ||
204 | |||
205 | /* find a free manager for this crtc */ | ||
206 | for (i = 0; i < num_mgrs; i++) { | ||
207 | if (!channel_used(dev, i)) { | ||
208 | struct drm_plane *plane; | ||
209 | struct drm_crtc *crtc; | ||
210 | |||
211 | plane = omap_plane_init(dev, id, true); | ||
212 | crtc = omap_crtc_init(dev, plane, i, id); | ||
213 | |||
214 | BUG_ON(priv->num_crtcs >= | ||
215 | ARRAY_SIZE(priv->crtcs)); | ||
216 | |||
217 | priv->crtcs[id] = crtc; | ||
218 | priv->num_crtcs++; | ||
219 | |||
220 | priv->planes[id] = plane; | ||
221 | priv->num_planes++; | ||
222 | |||
223 | break; | ||
224 | } else { | ||
225 | continue; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | if (i == num_mgrs) { | ||
230 | /* this shouldn't really happen */ | ||
231 | dev_err(dev->dev, "no managers left for crtc\n"); | ||
232 | return -ENOMEM; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Create normal planes for the remaining overlays: | ||
238 | */ | ||
239 | for (; id < num_ovls; id++) { | ||
240 | struct drm_plane *plane = omap_plane_init(dev, id, false); | ||
241 | |||
242 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); | ||
243 | priv->planes[priv->num_planes++] = plane; | ||
244 | } | ||
245 | |||
246 | for (i = 0; i < priv->num_encoders; i++) { | ||
247 | struct drm_encoder *encoder = priv->encoders[i]; | ||
248 | struct omap_dss_device *dssdev = | ||
249 | omap_encoder_get_dssdev(encoder); | ||
250 | |||
160 | /* figure out which crtc's we can connect the encoder to: */ | 251 | /* figure out which crtc's we can connect the encoder to: */ |
161 | encoder->possible_crtcs = 0; | 252 | encoder->possible_crtcs = 0; |
162 | for (id = 0; id < priv->num_crtcs; id++) { | 253 | for (id = 0; id < priv->num_crtcs; id++) { |
163 | enum omap_dss_output_id supported_outputs = | 254 | struct drm_crtc *crtc = priv->crtcs[id]; |
164 | dss_feat_get_supported_outputs(pipe2chan(id)); | 255 | enum omap_channel crtc_channel; |
256 | enum omap_dss_output_id supported_outputs; | ||
257 | |||
258 | crtc_channel = omap_crtc_channel(crtc); | ||
259 | supported_outputs = | ||
260 | dss_feat_get_supported_outputs(crtc_channel); | ||
261 | |||
165 | if (supported_outputs & dssdev->output->id) | 262 | if (supported_outputs & dssdev->output->id) |
166 | encoder->possible_crtcs |= (1 << id); | 263 | encoder->possible_crtcs |= (1 << id); |
167 | } | 264 | } |
168 | } | 265 | } |
169 | 266 | ||
267 | DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", | ||
268 | priv->num_planes, priv->num_crtcs, priv->num_encoders, | ||
269 | priv->num_connectors); | ||
270 | |||
170 | dev->mode_config.min_width = 32; | 271 | dev->mode_config.min_width = 32; |
171 | dev->mode_config.min_height = 32; | 272 | dev->mode_config.min_height = 32; |
172 | 273 | ||
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index d4f997bb4ac0..215a20dd340c 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h | |||
@@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); | |||
139 | int omap_gem_resume(struct device *dev); | 139 | int omap_gem_resume(struct device *dev); |
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc); | 142 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id); |
143 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc); | 143 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id); |
144 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); | 144 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); |
145 | void omap_irq_preinstall(struct drm_device *dev); | 145 | void omap_irq_preinstall(struct drm_device *dev); |
146 | int omap_irq_postinstall(struct drm_device *dev); | 146 | int omap_irq_postinstall(struct drm_device *dev); |
@@ -271,39 +271,9 @@ static inline int align_pitch(int pitch, int width, int bpp) | |||
271 | return ALIGN(pitch, 8 * bytespp); | 271 | return ALIGN(pitch, 8 * bytespp); |
272 | } | 272 | } |
273 | 273 | ||
274 | static inline enum omap_channel pipe2chan(int pipe) | ||
275 | { | ||
276 | int num_mgrs = dss_feat_get_num_mgrs(); | ||
277 | |||
278 | /* | ||
279 | * We usually don't want to create a CRTC for each manager, | ||
280 | * at least not until we have a way to expose private planes | ||
281 | * to userspace. Otherwise there would not be enough video | ||
282 | * pipes left for drm planes. The higher #'d managers tend | ||
283 | * to have more features so start in reverse order. | ||
284 | */ | ||
285 | return num_mgrs - pipe - 1; | ||
286 | } | ||
287 | |||
288 | /* map crtc to vblank mask */ | 274 | /* map crtc to vblank mask */ |
289 | static inline uint32_t pipe2vbl(int crtc) | 275 | uint32_t pipe2vbl(struct drm_crtc *crtc); |
290 | { | 276 | struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder); |
291 | enum omap_channel channel = pipe2chan(crtc); | ||
292 | return dispc_mgr_get_vsync_irq(channel); | ||
293 | } | ||
294 | |||
295 | static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc) | ||
296 | { | ||
297 | struct omap_drm_private *priv = dev->dev_private; | ||
298 | int i; | ||
299 | |||
300 | for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++) | ||
301 | if (priv->crtcs[i] == crtc) | ||
302 | return i; | ||
303 | |||
304 | BUG(); /* bogus CRTC ptr */ | ||
305 | return -1; | ||
306 | } | ||
307 | 277 | ||
308 | /* should these be made into common util helpers? | 278 | /* should these be made into common util helpers? |
309 | */ | 279 | */ |
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 18be00dd7b5e..c29451ba65da 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c | |||
@@ -41,6 +41,13 @@ struct omap_encoder { | |||
41 | struct omap_dss_device *dssdev; | 41 | struct omap_dss_device *dssdev; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder) | ||
45 | { | ||
46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
47 | |||
48 | return omap_encoder->dssdev; | ||
49 | } | ||
50 | |||
44 | static void omap_encoder_destroy(struct drm_encoder *encoder) | 51 | static void omap_encoder_destroy(struct drm_encoder *encoder) |
45 | { | 52 | { |
46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | 53 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); |
diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index e01303ee00c3..9263db117ff8 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c | |||
@@ -130,12 +130,13 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, | |||
130 | * Zero on success, appropriate errno if the given @crtc's vblank | 130 | * Zero on success, appropriate errno if the given @crtc's vblank |
131 | * interrupt cannot be enabled. | 131 | * interrupt cannot be enabled. |
132 | */ | 132 | */ |
133 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc) | 133 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id) |
134 | { | 134 | { |
135 | struct omap_drm_private *priv = dev->dev_private; | 135 | struct omap_drm_private *priv = dev->dev_private; |
136 | struct drm_crtc *crtc = priv->crtcs[crtc_id]; | ||
136 | unsigned long flags; | 137 | unsigned long flags; |
137 | 138 | ||
138 | DBG("dev=%p, crtc=%d", dev, crtc); | 139 | DBG("dev=%p, crtc=%d", dev, crtc_id); |
139 | 140 | ||
140 | dispc_runtime_get(); | 141 | dispc_runtime_get(); |
141 | spin_lock_irqsave(&list_lock, flags); | 142 | spin_lock_irqsave(&list_lock, flags); |
@@ -156,12 +157,13 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc) | |||
156 | * a hardware vblank counter, this routine should be a no-op, since | 157 | * a hardware vblank counter, this routine should be a no-op, since |
157 | * interrupts will have to stay on to keep the count accurate. | 158 | * interrupts will have to stay on to keep the count accurate. |
158 | */ | 159 | */ |
159 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc) | 160 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id) |
160 | { | 161 | { |
161 | struct omap_drm_private *priv = dev->dev_private; | 162 | struct omap_drm_private *priv = dev->dev_private; |
163 | struct drm_crtc *crtc = priv->crtcs[crtc_id]; | ||
162 | unsigned long flags; | 164 | unsigned long flags; |
163 | 165 | ||
164 | DBG("dev=%p, crtc=%d", dev, crtc); | 166 | DBG("dev=%p, crtc=%d", dev, crtc_id); |
165 | 167 | ||
166 | dispc_runtime_get(); | 168 | dispc_runtime_get(); |
167 | spin_lock_irqsave(&list_lock, flags); | 169 | spin_lock_irqsave(&list_lock, flags); |
@@ -186,9 +188,12 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) | |||
186 | 188 | ||
187 | VERB("irqs: %08x", irqstatus); | 189 | VERB("irqs: %08x", irqstatus); |
188 | 190 | ||
189 | for (id = 0; id < priv->num_crtcs; id++) | 191 | for (id = 0; id < priv->num_crtcs; id++) { |
190 | if (irqstatus & pipe2vbl(id)) | 192 | struct drm_crtc *crtc = priv->crtcs[id]; |
193 | |||
194 | if (irqstatus & pipe2vbl(crtc)) | ||
191 | drm_handle_vblank(dev, id); | 195 | drm_handle_vblank(dev, id); |
196 | } | ||
192 | 197 | ||
193 | spin_lock_irqsave(&list_lock, flags); | 198 | spin_lock_irqsave(&list_lock, flags); |
194 | list_for_each_entry_safe(handler, n, &priv->irq_list, node) { | 199 | list_for_each_entry_safe(handler, n, &priv->irq_list, node) { |