diff options
author | Dave Airlie <airlied@redhat.com> | 2013-04-15 23:20:03 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-04-15 23:20:03 -0400 |
commit | dea14dfab9d1fdf5695ae61dc72c587533706edc (patch) | |
tree | b30f80f3581c706f29911cbe334f6b35569a5847 /drivers | |
parent | e4fda9f264e154946c678ca7ff07023f573abf6a (diff) | |
parent | 3d62fe5b214fce69ae14abbdb88794a753418614 (diff) |
Merge tag 'omapdss-for-3.10' of git://gitorious.org/linux-omap-dss2/linux into drm-next
Omapdss patches for 3.10 merge window
The biggest changes are:
* DSI video mode: automatic clock and timing calculation
* Lots of platform data related panel driver cleanups, to prepare for DT
* tag 'omapdss-for-3.10' of git://gitorious.org/linux-omap-dss2/linux: (69 commits)
drm/omap: add statics to a few structs
drm/omap: Fix and improve crtc and overlay manager correlation
drm/omap: Take a fb reference in omap_plane_update()
drm/omap: Make fixed resolution panels work
drm/omap: fix modeset_init if a panel doesn't satisfy omapdrm requirements
OMAPDSS: DPI: widen the pck search when using dss fck
OMAPDSS: fix dss_fck clock rate rounding
omapdss: use devm_clk_get()
OMAPDSS: nec-nl8048 panel: Use dev_pm_ops
OMAPDSS: DISPC: Revert to older DISPC Smart Standby mechanism for OMAP5
OMAPDSS: DISPC: Configure doublestride for NV12 when using 2D Tiler buffers
omapdss: Features: Fix some parameter ranges
omapdss: DISPC: add max pixel clock limits for LCD and TV managers
OMAPDSS: DSI: Use devm_clk_get()
drivers: video: omap2: dss: Use PTR_RET function
OMAPDSS: VENC: remove platform_enable/disable calls
OMAPDSS: n8x0 panel: remove use of platform_enable/disable
OMAPDSS: n8x0 panel: handle gpio data in panel driver
OMAPDSS: picodlp panel: remove platform_enable/disable callbacks
OMAPDSS: picodlp panel: handle gpio data in panel driver
...
Diffstat (limited to 'drivers')
33 files changed, 1767 insertions, 1533 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index c451c41a7a7d..912759daf562 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c | |||
@@ -110,6 +110,11 @@ static enum drm_connector_status omap_connector_detect( | |||
110 | ret = connector_status_connected; | 110 | ret = connector_status_connected; |
111 | else | 111 | else |
112 | ret = connector_status_disconnected; | 112 | ret = connector_status_disconnected; |
113 | } else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI || | ||
114 | dssdev->type == OMAP_DISPLAY_TYPE_DBI || | ||
115 | dssdev->type == OMAP_DISPLAY_TYPE_SDI || | ||
116 | dssdev->type == OMAP_DISPLAY_TYPE_DSI) { | ||
117 | ret = connector_status_connected; | ||
113 | } else { | 118 | } else { |
114 | ret = connector_status_unknown; | 119 | ret = connector_status_unknown; |
115 | } | 120 | } |
@@ -189,12 +194,30 @@ static int omap_connector_mode_valid(struct drm_connector *connector, | |||
189 | struct omap_video_timings timings = {0}; | 194 | struct omap_video_timings timings = {0}; |
190 | struct drm_device *dev = connector->dev; | 195 | struct drm_device *dev = connector->dev; |
191 | struct drm_display_mode *new_mode; | 196 | struct drm_display_mode *new_mode; |
192 | int ret = MODE_BAD; | 197 | int r, ret = MODE_BAD; |
193 | 198 | ||
194 | copy_timings_drm_to_omap(&timings, mode); | 199 | copy_timings_drm_to_omap(&timings, mode); |
195 | mode->vrefresh = drm_mode_vrefresh(mode); | 200 | mode->vrefresh = drm_mode_vrefresh(mode); |
196 | 201 | ||
197 | if (!dssdrv->check_timings(dssdev, &timings)) { | 202 | /* |
203 | * if the panel driver doesn't have a check_timings, it's most likely | ||
204 | * a fixed resolution panel, check if the timings match with the | ||
205 | * panel's timings | ||
206 | */ | ||
207 | if (dssdrv->check_timings) { | ||
208 | r = dssdrv->check_timings(dssdev, &timings); | ||
209 | } else { | ||
210 | struct omap_video_timings t = {0}; | ||
211 | |||
212 | dssdrv->get_timings(dssdev, &t); | ||
213 | |||
214 | if (memcmp(&timings, &t, sizeof(struct omap_video_timings))) | ||
215 | r = -EINVAL; | ||
216 | else | ||
217 | r = 0; | ||
218 | } | ||
219 | |||
220 | if (!r) { | ||
198 | /* check if vrefresh is still valid */ | 221 | /* check if vrefresh is still valid */ |
199 | new_mode = drm_mode_duplicate(dev, mode); | 222 | new_mode = drm_mode_duplicate(dev, mode); |
200 | new_mode->clock = timings.pixel_clock; | 223 | new_mode->clock = timings.pixel_clock; |
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 079c54c6f94c..9c53c25e5201 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c | |||
@@ -74,54 +74,53 @@ 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. |
108 | * Otherwise there would not be enough video pipes left for drm planes. | ||
109 | * We use the num_crtc argument to limit the number of crtcs we create. | ||
91 | */ | 110 | */ |
92 | for (id = 0; id < min(num_crtc, num_ovls); id++) { | 111 | num_crtcs = min3(num_crtc, num_mgrs, num_ovls); |
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 | 112 | ||
99 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); | 113 | dssdev = NULL; |
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 | for (; id < num_ovls; id++) { | ||
111 | struct drm_plane *plane = omap_plane_init(dev, id, false); | ||
112 | |||
113 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); | ||
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", |
123 | dssdev->name); | 122 | dssdev->name); |
124 | return 0; | 123 | continue; |
125 | } | 124 | } |
126 | 125 | ||
127 | if (!(dssdev->driver->get_timings || | 126 | if (!(dssdev->driver->get_timings || |
@@ -129,7 +128,7 @@ static int omap_modeset_init(struct drm_device *dev) | |||
129 | dev_warn(dev->dev, "%s driver does not support " | 128 | dev_warn(dev->dev, "%s driver does not support " |
130 | "get_timings or read_edid.. skipping it!\n", | 129 | "get_timings or read_edid.. skipping it!\n", |
131 | dssdev->name); | 130 | dssdev->name); |
132 | return 0; | 131 | continue; |
133 | } | 132 | } |
134 | 133 | ||
135 | encoder = omap_encoder_init(dev, dssdev); | 134 | encoder = omap_encoder_init(dev, dssdev); |
@@ -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 | ||
@@ -303,7 +404,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, | |||
303 | return ret; | 404 | return ret; |
304 | } | 405 | } |
305 | 406 | ||
306 | struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { | 407 | static struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { |
307 | DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_UNLOCKED|DRM_AUTH), | 408 | DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_UNLOCKED|DRM_AUTH), |
308 | DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), | 409 | DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
309 | DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH), | 410 | DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH), |
@@ -567,7 +668,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = { | |||
567 | }; | 668 | }; |
568 | #endif | 669 | #endif |
569 | 670 | ||
570 | struct platform_driver pdev = { | 671 | static struct platform_driver pdev = { |
571 | .driver = { | 672 | .driver = { |
572 | .name = DRIVER_NAME, | 673 | .name = DRIVER_NAME, |
573 | .owner = THIS_MODULE, | 674 | .owner = THIS_MODULE, |
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 21d126d0317e..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); |
@@ -128,13 +135,26 @@ int omap_encoder_update(struct drm_encoder *encoder, | |||
128 | 135 | ||
129 | dssdev->output->manager = mgr; | 136 | dssdev->output->manager = mgr; |
130 | 137 | ||
131 | ret = dssdrv->check_timings(dssdev, timings); | 138 | if (dssdrv->check_timings) { |
139 | ret = dssdrv->check_timings(dssdev, timings); | ||
140 | } else { | ||
141 | struct omap_video_timings t = {0}; | ||
142 | |||
143 | dssdrv->get_timings(dssdev, &t); | ||
144 | |||
145 | if (memcmp(timings, &t, sizeof(struct omap_video_timings))) | ||
146 | ret = -EINVAL; | ||
147 | else | ||
148 | ret = 0; | ||
149 | } | ||
150 | |||
132 | if (ret) { | 151 | if (ret) { |
133 | dev_err(dev->dev, "could not set timings: %d\n", ret); | 152 | dev_err(dev->dev, "could not set timings: %d\n", ret); |
134 | return ret; | 153 | return ret; |
135 | } | 154 | } |
136 | 155 | ||
137 | dssdrv->set_timings(dssdev, timings); | 156 | if (dssdrv->set_timings) |
157 | dssdrv->set_timings(dssdev, timings); | ||
138 | 158 | ||
139 | return 0; | 159 | return 0; |
140 | } | 160 | } |
diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index ac74d1bc67bf..0682cb5c0150 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c | |||
@@ -178,7 +178,7 @@ out_unlock: | |||
178 | return omap_gem_mmap_obj(obj, vma); | 178 | return omap_gem_mmap_obj(obj, vma); |
179 | } | 179 | } |
180 | 180 | ||
181 | struct dma_buf_ops omap_dmabuf_ops = { | 181 | static struct dma_buf_ops omap_dmabuf_ops = { |
182 | .map_dma_buf = omap_gem_map_dma_buf, | 182 | .map_dma_buf = omap_gem_map_dma_buf, |
183 | .unmap_dma_buf = omap_gem_unmap_dma_buf, | 183 | .unmap_dma_buf = omap_gem_unmap_dma_buf, |
184 | .release = omap_gem_dmabuf_release, | 184 | .release = omap_gem_dmabuf_release, |
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) { |
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 2882cda6ea19..8d225d7ff4e3 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c | |||
@@ -247,6 +247,12 @@ static int omap_plane_update(struct drm_plane *plane, | |||
247 | { | 247 | { |
248 | struct omap_plane *omap_plane = to_omap_plane(plane); | 248 | struct omap_plane *omap_plane = to_omap_plane(plane); |
249 | omap_plane->enabled = true; | 249 | omap_plane->enabled = true; |
250 | |||
251 | if (plane->fb) | ||
252 | drm_framebuffer_unreference(plane->fb); | ||
253 | |||
254 | drm_framebuffer_reference(fb); | ||
255 | |||
250 | return omap_plane_mode_set(plane, crtc, fb, | 256 | return omap_plane_mode_set(plane, crtc, fb, |
251 | crtc_x, crtc_y, crtc_w, crtc_h, | 257 | crtc_x, crtc_y, crtc_w, crtc_h, |
252 | src_x, src_y, src_w, src_h, | 258 | src_x, src_y, src_w, src_h, |
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index 72699f88c002..d7f69c09ecf1 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c | |||
@@ -29,8 +29,10 @@ | |||
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/backlight.h> | 30 | #include <linux/backlight.h> |
31 | #include <linux/fb.h> | 31 | #include <linux/fb.h> |
32 | #include <linux/gpio.h> | ||
32 | 33 | ||
33 | #include <video/omapdss.h> | 34 | #include <video/omapdss.h> |
35 | #include <video/omap-panel-data.h> | ||
34 | 36 | ||
35 | #define MIPID_CMD_READ_DISP_ID 0x04 | 37 | #define MIPID_CMD_READ_DISP_ID 0x04 |
36 | #define MIPID_CMD_READ_RED 0x06 | 38 | #define MIPID_CMD_READ_RED 0x06 |
@@ -336,8 +338,6 @@ static int acx565akm_bl_update_status(struct backlight_device *dev) | |||
336 | r = 0; | 338 | r = 0; |
337 | if (md->has_bc) | 339 | if (md->has_bc) |
338 | acx565akm_set_brightness(md, level); | 340 | acx565akm_set_brightness(md, level); |
339 | else if (md->dssdev->set_backlight) | ||
340 | r = md->dssdev->set_backlight(md->dssdev, level); | ||
341 | else | 341 | else |
342 | r = -ENODEV; | 342 | r = -ENODEV; |
343 | 343 | ||
@@ -352,7 +352,7 @@ static int acx565akm_bl_get_intensity(struct backlight_device *dev) | |||
352 | 352 | ||
353 | dev_dbg(&dev->dev, "%s\n", __func__); | 353 | dev_dbg(&dev->dev, "%s\n", __func__); |
354 | 354 | ||
355 | if (!md->has_bc && md->dssdev->set_backlight == NULL) | 355 | if (!md->has_bc) |
356 | return -ENODEV; | 356 | return -ENODEV; |
357 | 357 | ||
358 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | 358 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && |
@@ -496,21 +496,38 @@ static struct omap_video_timings acx_panel_timings = { | |||
496 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | 496 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, |
497 | }; | 497 | }; |
498 | 498 | ||
499 | static struct panel_acx565akm_data *get_panel_data(struct omap_dss_device *dssdev) | ||
500 | { | ||
501 | return (struct panel_acx565akm_data *) dssdev->data; | ||
502 | } | ||
503 | |||
499 | static int acx_panel_probe(struct omap_dss_device *dssdev) | 504 | static int acx_panel_probe(struct omap_dss_device *dssdev) |
500 | { | 505 | { |
501 | int r; | 506 | int r; |
502 | struct acx565akm_device *md = &acx_dev; | 507 | struct acx565akm_device *md = &acx_dev; |
508 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | ||
503 | struct backlight_device *bldev; | 509 | struct backlight_device *bldev; |
504 | int max_brightness, brightness; | 510 | int max_brightness, brightness; |
505 | struct backlight_properties props; | 511 | struct backlight_properties props; |
506 | 512 | ||
507 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 513 | dev_dbg(&dssdev->dev, "%s\n", __func__); |
508 | 514 | ||
515 | if (!panel_data) | ||
516 | return -EINVAL; | ||
517 | |||
509 | /* FIXME AC bias ? */ | 518 | /* FIXME AC bias ? */ |
510 | dssdev->panel.timings = acx_panel_timings; | 519 | dssdev->panel.timings = acx_panel_timings; |
511 | 520 | ||
512 | if (dssdev->platform_enable) | 521 | if (gpio_is_valid(panel_data->reset_gpio)) { |
513 | dssdev->platform_enable(dssdev); | 522 | r = devm_gpio_request_one(&dssdev->dev, panel_data->reset_gpio, |
523 | GPIOF_OUT_INIT_LOW, "lcd reset"); | ||
524 | if (r) | ||
525 | return r; | ||
526 | } | ||
527 | |||
528 | if (gpio_is_valid(panel_data->reset_gpio)) | ||
529 | gpio_set_value(panel_data->reset_gpio, 1); | ||
530 | |||
514 | /* | 531 | /* |
515 | * After reset we have to wait 5 msec before the first | 532 | * After reset we have to wait 5 msec before the first |
516 | * command can be sent. | 533 | * command can be sent. |
@@ -522,8 +539,9 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
522 | r = panel_detect(md); | 539 | r = panel_detect(md); |
523 | if (r) { | 540 | if (r) { |
524 | dev_err(&dssdev->dev, "%s panel detect error\n", __func__); | 541 | dev_err(&dssdev->dev, "%s panel detect error\n", __func__); |
525 | if (!md->enabled && dssdev->platform_disable) | 542 | if (!md->enabled && gpio_is_valid(panel_data->reset_gpio)) |
526 | dssdev->platform_disable(dssdev); | 543 | gpio_set_value(panel_data->reset_gpio, 0); |
544 | |||
527 | return r; | 545 | return r; |
528 | } | 546 | } |
529 | 547 | ||
@@ -532,8 +550,8 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
532 | mutex_unlock(&acx_dev.mutex); | 550 | mutex_unlock(&acx_dev.mutex); |
533 | 551 | ||
534 | if (!md->enabled) { | 552 | if (!md->enabled) { |
535 | if (dssdev->platform_disable) | 553 | if (gpio_is_valid(panel_data->reset_gpio)) |
536 | dssdev->platform_disable(dssdev); | 554 | gpio_set_value(panel_data->reset_gpio, 0); |
537 | } | 555 | } |
538 | 556 | ||
539 | /*------- Backlight control --------*/ | 557 | /*------- Backlight control --------*/ |
@@ -557,15 +575,10 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
557 | md->cabc_mode = get_hw_cabc_mode(md); | 575 | md->cabc_mode = get_hw_cabc_mode(md); |
558 | } | 576 | } |
559 | 577 | ||
560 | if (md->has_bc) | 578 | max_brightness = 255; |
561 | max_brightness = 255; | ||
562 | else | ||
563 | max_brightness = dssdev->max_backlight_level; | ||
564 | 579 | ||
565 | if (md->has_bc) | 580 | if (md->has_bc) |
566 | brightness = acx565akm_get_actual_brightness(md); | 581 | brightness = acx565akm_get_actual_brightness(md); |
567 | else if (dssdev->get_backlight) | ||
568 | brightness = dssdev->get_backlight(dssdev); | ||
569 | else | 582 | else |
570 | brightness = 0; | 583 | brightness = 0; |
571 | 584 | ||
@@ -591,6 +604,7 @@ static void acx_panel_remove(struct omap_dss_device *dssdev) | |||
591 | static int acx_panel_power_on(struct omap_dss_device *dssdev) | 604 | static int acx_panel_power_on(struct omap_dss_device *dssdev) |
592 | { | 605 | { |
593 | struct acx565akm_device *md = &acx_dev; | 606 | struct acx565akm_device *md = &acx_dev; |
607 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | ||
594 | int r; | 608 | int r; |
595 | 609 | ||
596 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 610 | dev_dbg(&dssdev->dev, "%s\n", __func__); |
@@ -612,11 +626,8 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) | |||
612 | /*FIXME tweak me */ | 626 | /*FIXME tweak me */ |
613 | msleep(50); | 627 | msleep(50); |
614 | 628 | ||
615 | if (dssdev->platform_enable) { | 629 | if (gpio_is_valid(panel_data->reset_gpio)) |
616 | r = dssdev->platform_enable(dssdev); | 630 | gpio_set_value(panel_data->reset_gpio, 1); |
617 | if (r) | ||
618 | goto fail; | ||
619 | } | ||
620 | 631 | ||
621 | if (md->enabled) { | 632 | if (md->enabled) { |
622 | dev_dbg(&md->spi->dev, "panel already enabled\n"); | 633 | dev_dbg(&md->spi->dev, "panel already enabled\n"); |
@@ -645,8 +656,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) | |||
645 | mutex_unlock(&md->mutex); | 656 | mutex_unlock(&md->mutex); |
646 | 657 | ||
647 | return acx565akm_bl_update_status(md->bl_dev); | 658 | return acx565akm_bl_update_status(md->bl_dev); |
648 | fail: | 659 | |
649 | omapdss_sdi_display_disable(dssdev); | ||
650 | fail_unlock: | 660 | fail_unlock: |
651 | mutex_unlock(&md->mutex); | 661 | mutex_unlock(&md->mutex); |
652 | return r; | 662 | return r; |
@@ -655,6 +665,7 @@ fail_unlock: | |||
655 | static void acx_panel_power_off(struct omap_dss_device *dssdev) | 665 | static void acx_panel_power_off(struct omap_dss_device *dssdev) |
656 | { | 666 | { |
657 | struct acx565akm_device *md = &acx_dev; | 667 | struct acx565akm_device *md = &acx_dev; |
668 | struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); | ||
658 | 669 | ||
659 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 670 | dev_dbg(&dssdev->dev, "%s\n", __func__); |
660 | 671 | ||
@@ -678,8 +689,8 @@ static void acx_panel_power_off(struct omap_dss_device *dssdev) | |||
678 | */ | 689 | */ |
679 | msleep(50); | 690 | msleep(50); |
680 | 691 | ||
681 | if (dssdev->platform_disable) | 692 | if (gpio_is_valid(panel_data->reset_gpio)) |
682 | dssdev->platform_disable(dssdev); | 693 | gpio_set_value(panel_data->reset_gpio, 0); |
683 | 694 | ||
684 | /* FIXME need to tweak this delay */ | 695 | /* FIXME need to tweak this delay */ |
685 | msleep(100); | 696 | msleep(100); |
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index c904f42d81c1..97363f733683 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c | |||
@@ -33,9 +33,10 @@ | |||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/gpio.h> | ||
36 | #include <video/omapdss.h> | 37 | #include <video/omapdss.h> |
37 | 38 | ||
38 | #include <video/omap-panel-generic-dpi.h> | 39 | #include <video/omap-panel-data.h> |
39 | 40 | ||
40 | struct panel_config { | 41 | struct panel_config { |
41 | struct omap_video_timings timings; | 42 | struct omap_video_timings timings; |
@@ -533,7 +534,7 @@ static inline struct panel_generic_dpi_data | |||
533 | 534 | ||
534 | static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) | 535 | static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) |
535 | { | 536 | { |
536 | int r; | 537 | int r, i; |
537 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | 538 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); |
538 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 539 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); |
539 | struct panel_config *panel_config = drv_data->panel_config; | 540 | struct panel_config *panel_config = drv_data->panel_config; |
@@ -552,15 +553,13 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) | |||
552 | if (panel_config->power_on_delay) | 553 | if (panel_config->power_on_delay) |
553 | msleep(panel_config->power_on_delay); | 554 | msleep(panel_config->power_on_delay); |
554 | 555 | ||
555 | if (panel_data->platform_enable) { | 556 | for (i = 0; i < panel_data->num_gpios; ++i) { |
556 | r = panel_data->platform_enable(dssdev); | 557 | gpio_set_value_cansleep(panel_data->gpios[i], |
557 | if (r) | 558 | panel_data->gpio_invert[i] ? 0 : 1); |
558 | goto err1; | ||
559 | } | 559 | } |
560 | 560 | ||
561 | return 0; | 561 | return 0; |
562 | err1: | 562 | |
563 | omapdss_dpi_display_disable(dssdev); | ||
564 | err0: | 563 | err0: |
565 | return r; | 564 | return r; |
566 | } | 565 | } |
@@ -570,12 +569,15 @@ static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) | |||
570 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | 569 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); |
571 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 570 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); |
572 | struct panel_config *panel_config = drv_data->panel_config; | 571 | struct panel_config *panel_config = drv_data->panel_config; |
572 | int i; | ||
573 | 573 | ||
574 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 574 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
575 | return; | 575 | return; |
576 | 576 | ||
577 | if (panel_data->platform_disable) | 577 | for (i = panel_data->num_gpios - 1; i >= 0; --i) { |
578 | panel_data->platform_disable(dssdev); | 578 | gpio_set_value_cansleep(panel_data->gpios[i], |
579 | panel_data->gpio_invert[i] ? 1 : 0); | ||
580 | } | ||
579 | 581 | ||
580 | /* wait couple of vsyncs after disabling the LCD */ | 582 | /* wait couple of vsyncs after disabling the LCD */ |
581 | if (panel_config->power_off_delay) | 583 | if (panel_config->power_off_delay) |
@@ -589,7 +591,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
589 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | 591 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); |
590 | struct panel_config *panel_config = NULL; | 592 | struct panel_config *panel_config = NULL; |
591 | struct panel_drv_data *drv_data = NULL; | 593 | struct panel_drv_data *drv_data = NULL; |
592 | int i; | 594 | int i, r; |
593 | 595 | ||
594 | dev_dbg(&dssdev->dev, "probe\n"); | 596 | dev_dbg(&dssdev->dev, "probe\n"); |
595 | 597 | ||
@@ -606,9 +608,18 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
606 | if (!panel_config) | 608 | if (!panel_config) |
607 | return -EINVAL; | 609 | return -EINVAL; |
608 | 610 | ||
611 | for (i = 0; i < panel_data->num_gpios; ++i) { | ||
612 | r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i], | ||
613 | panel_data->gpio_invert[i] ? | ||
614 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, | ||
615 | "panel gpio"); | ||
616 | if (r) | ||
617 | return r; | ||
618 | } | ||
619 | |||
609 | dssdev->panel.timings = panel_config->timings; | 620 | dssdev->panel.timings = panel_config->timings; |
610 | 621 | ||
611 | drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); | 622 | drv_data = devm_kzalloc(&dssdev->dev, sizeof(*drv_data), GFP_KERNEL); |
612 | if (!drv_data) | 623 | if (!drv_data) |
613 | return -ENOMEM; | 624 | return -ENOMEM; |
614 | 625 | ||
@@ -624,12 +635,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
624 | 635 | ||
625 | static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) | 636 | static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) |
626 | { | 637 | { |
627 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | ||
628 | |||
629 | dev_dbg(&dssdev->dev, "remove\n"); | 638 | dev_dbg(&dssdev->dev, "remove\n"); |
630 | 639 | ||
631 | kfree(drv_data); | ||
632 | |||
633 | dev_set_drvdata(&dssdev->dev, NULL); | 640 | dev_set_drvdata(&dssdev->dev, NULL); |
634 | } | 641 | } |
635 | 642 | ||
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 6e5abe8fd2dd..4ea6548c0ae9 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c | |||
@@ -20,8 +20,10 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/gpio.h> | ||
23 | 24 | ||
24 | #include <video/omapdss.h> | 25 | #include <video/omapdss.h> |
26 | #include <video/omap-panel-data.h> | ||
25 | 27 | ||
26 | struct lb035q02_data { | 28 | struct lb035q02_data { |
27 | struct mutex lock; | 29 | struct mutex lock; |
@@ -48,9 +50,16 @@ static struct omap_video_timings lb035q02_timings = { | |||
48 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | 50 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, |
49 | }; | 51 | }; |
50 | 52 | ||
53 | static inline struct panel_generic_dpi_data | ||
54 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
55 | { | ||
56 | return (struct panel_generic_dpi_data *) dssdev->data; | ||
57 | } | ||
58 | |||
51 | static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) | 59 | static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) |
52 | { | 60 | { |
53 | int r; | 61 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); |
62 | int r, i; | ||
54 | 63 | ||
55 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 64 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
56 | return 0; | 65 | return 0; |
@@ -62,54 +71,65 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) | |||
62 | if (r) | 71 | if (r) |
63 | goto err0; | 72 | goto err0; |
64 | 73 | ||
65 | if (dssdev->platform_enable) { | 74 | for (i = 0; i < panel_data->num_gpios; ++i) { |
66 | r = dssdev->platform_enable(dssdev); | 75 | gpio_set_value_cansleep(panel_data->gpios[i], |
67 | if (r) | 76 | panel_data->gpio_invert[i] ? 0 : 1); |
68 | goto err1; | ||
69 | } | 77 | } |
70 | 78 | ||
71 | return 0; | 79 | return 0; |
72 | err1: | 80 | |
73 | omapdss_dpi_display_disable(dssdev); | ||
74 | err0: | 81 | err0: |
75 | return r; | 82 | return r; |
76 | } | 83 | } |
77 | 84 | ||
78 | static void lb035q02_panel_power_off(struct omap_dss_device *dssdev) | 85 | static void lb035q02_panel_power_off(struct omap_dss_device *dssdev) |
79 | { | 86 | { |
87 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
88 | int i; | ||
89 | |||
80 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 90 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
81 | return; | 91 | return; |
82 | 92 | ||
83 | if (dssdev->platform_disable) | 93 | for (i = panel_data->num_gpios - 1; i >= 0; --i) { |
84 | dssdev->platform_disable(dssdev); | 94 | gpio_set_value_cansleep(panel_data->gpios[i], |
95 | panel_data->gpio_invert[i] ? 1 : 0); | ||
96 | } | ||
85 | 97 | ||
86 | omapdss_dpi_display_disable(dssdev); | 98 | omapdss_dpi_display_disable(dssdev); |
87 | } | 99 | } |
88 | 100 | ||
89 | static int lb035q02_panel_probe(struct omap_dss_device *dssdev) | 101 | static int lb035q02_panel_probe(struct omap_dss_device *dssdev) |
90 | { | 102 | { |
103 | struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); | ||
91 | struct lb035q02_data *ld; | 104 | struct lb035q02_data *ld; |
92 | int r; | 105 | int r, i; |
106 | |||
107 | if (!panel_data) | ||
108 | return -EINVAL; | ||
93 | 109 | ||
94 | dssdev->panel.timings = lb035q02_timings; | 110 | dssdev->panel.timings = lb035q02_timings; |
95 | 111 | ||
96 | ld = kzalloc(sizeof(*ld), GFP_KERNEL); | 112 | ld = devm_kzalloc(&dssdev->dev, sizeof(*ld), GFP_KERNEL); |
97 | if (!ld) { | 113 | if (!ld) |
98 | r = -ENOMEM; | 114 | return -ENOMEM; |
99 | goto err; | 115 | |
116 | for (i = 0; i < panel_data->num_gpios; ++i) { | ||
117 | r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i], | ||
118 | panel_data->gpio_invert[i] ? | ||
119 | GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, | ||
120 | "panel gpio"); | ||
121 | if (r) | ||
122 | return r; | ||
100 | } | 123 | } |
124 | |||
101 | mutex_init(&ld->lock); | 125 | mutex_init(&ld->lock); |
102 | dev_set_drvdata(&dssdev->dev, ld); | 126 | dev_set_drvdata(&dssdev->dev, ld); |
127 | |||
103 | return 0; | 128 | return 0; |
104 | err: | ||
105 | return r; | ||
106 | } | 129 | } |
107 | 130 | ||
108 | static void lb035q02_panel_remove(struct omap_dss_device *dssdev) | 131 | static void lb035q02_panel_remove(struct omap_dss_device *dssdev) |
109 | { | 132 | { |
110 | struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); | ||
111 | |||
112 | kfree(ld); | ||
113 | } | 133 | } |
114 | 134 | ||
115 | static int lb035q02_panel_enable(struct omap_dss_device *dssdev) | 135 | static int lb035q02_panel_enable(struct omap_dss_device *dssdev) |
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index dd1294750802..f94ead6a3183 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c | |||
@@ -5,11 +5,10 @@ | |||
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/gpio.h> | 6 | #include <linux/gpio.h> |
7 | #include <linux/spi/spi.h> | 7 | #include <linux/spi/spi.h> |
8 | #include <linux/backlight.h> | ||
9 | #include <linux/fb.h> | 8 | #include <linux/fb.h> |
10 | 9 | ||
11 | #include <video/omapdss.h> | 10 | #include <video/omapdss.h> |
12 | #include <video/omap-panel-n8x0.h> | 11 | #include <video/omap-panel-data.h> |
13 | 12 | ||
14 | #define BLIZZARD_REV_CODE 0x00 | 13 | #define BLIZZARD_REV_CODE 0x00 |
15 | #define BLIZZARD_CONFIG 0x02 | 14 | #define BLIZZARD_CONFIG 0x02 |
@@ -69,7 +68,6 @@ static struct panel_drv_data { | |||
69 | 68 | ||
70 | struct omap_dss_device *dssdev; | 69 | struct omap_dss_device *dssdev; |
71 | struct spi_device *spidev; | 70 | struct spi_device *spidev; |
72 | struct backlight_device *bldev; | ||
73 | 71 | ||
74 | int blizzard_ver; | 72 | int blizzard_ver; |
75 | } s_drv_data; | 73 | } s_drv_data; |
@@ -297,12 +295,6 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev) | |||
297 | 295 | ||
298 | gpio_direction_output(bdata->ctrl_pwrdown, 1); | 296 | gpio_direction_output(bdata->ctrl_pwrdown, 1); |
299 | 297 | ||
300 | if (bdata->platform_enable) { | ||
301 | r = bdata->platform_enable(dssdev); | ||
302 | if (r) | ||
303 | goto err_plat_en; | ||
304 | } | ||
305 | |||
306 | omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, | 298 | omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, |
307 | dssdev->panel.timings.y_res); | 299 | dssdev->panel.timings.y_res); |
308 | omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); | 300 | omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); |
@@ -375,9 +367,6 @@ err_inv_panel: | |||
375 | err_inv_chip: | 367 | err_inv_chip: |
376 | omapdss_rfbi_display_disable(dssdev); | 368 | omapdss_rfbi_display_disable(dssdev); |
377 | err_rfbi_en: | 369 | err_rfbi_en: |
378 | if (bdata->platform_disable) | ||
379 | bdata->platform_disable(dssdev); | ||
380 | err_plat_en: | ||
381 | gpio_direction_output(bdata->ctrl_pwrdown, 0); | 370 | gpio_direction_output(bdata->ctrl_pwrdown, 0); |
382 | return r; | 371 | return r; |
383 | } | 372 | } |
@@ -394,9 +383,6 @@ static void n8x0_panel_power_off(struct omap_dss_device *dssdev) | |||
394 | send_display_off(spi); | 383 | send_display_off(spi); |
395 | send_sleep_in(spi); | 384 | send_sleep_in(spi); |
396 | 385 | ||
397 | if (bdata->platform_disable) | ||
398 | bdata->platform_disable(dssdev); | ||
399 | |||
400 | /* | 386 | /* |
401 | * HACK: we should turn off the panel here, but there is some problem | 387 | * HACK: we should turn off the panel here, but there is some problem |
402 | * with the initialization sequence, and we fail to init the panel if we | 388 | * with the initialization sequence, and we fail to init the panel if we |
@@ -424,54 +410,10 @@ static const struct rfbi_timings n8x0_panel_timings = { | |||
424 | .cs_pulse_width = 0, | 410 | .cs_pulse_width = 0, |
425 | }; | 411 | }; |
426 | 412 | ||
427 | static int n8x0_bl_update_status(struct backlight_device *dev) | ||
428 | { | ||
429 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); | ||
430 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
431 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
432 | int r; | ||
433 | int level; | ||
434 | |||
435 | mutex_lock(&ddata->lock); | ||
436 | |||
437 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
438 | dev->props.power == FB_BLANK_UNBLANK) | ||
439 | level = dev->props.brightness; | ||
440 | else | ||
441 | level = 0; | ||
442 | |||
443 | dev_dbg(&dssdev->dev, "update brightness to %d\n", level); | ||
444 | |||
445 | if (!bdata->set_backlight) | ||
446 | r = -EINVAL; | ||
447 | else | ||
448 | r = bdata->set_backlight(dssdev, level); | ||
449 | |||
450 | mutex_unlock(&ddata->lock); | ||
451 | |||
452 | return r; | ||
453 | } | ||
454 | |||
455 | static int n8x0_bl_get_intensity(struct backlight_device *dev) | ||
456 | { | ||
457 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
458 | dev->props.power == FB_BLANK_UNBLANK) | ||
459 | return dev->props.brightness; | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static const struct backlight_ops n8x0_bl_ops = { | ||
465 | .get_brightness = n8x0_bl_get_intensity, | ||
466 | .update_status = n8x0_bl_update_status, | ||
467 | }; | ||
468 | |||
469 | static int n8x0_panel_probe(struct omap_dss_device *dssdev) | 413 | static int n8x0_panel_probe(struct omap_dss_device *dssdev) |
470 | { | 414 | { |
471 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | 415 | struct panel_n8x0_data *bdata = get_board_data(dssdev); |
472 | struct panel_drv_data *ddata; | 416 | struct panel_drv_data *ddata; |
473 | struct backlight_device *bldev; | ||
474 | struct backlight_properties props; | ||
475 | int r; | 417 | int r; |
476 | 418 | ||
477 | dev_dbg(&dssdev->dev, "probe\n"); | 419 | dev_dbg(&dssdev->dev, "probe\n"); |
@@ -491,40 +433,27 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) | |||
491 | dssdev->ctrl.rfbi_timings = n8x0_panel_timings; | 433 | dssdev->ctrl.rfbi_timings = n8x0_panel_timings; |
492 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | 434 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; |
493 | 435 | ||
494 | memset(&props, 0, sizeof(props)); | 436 | if (gpio_is_valid(bdata->panel_reset)) { |
495 | props.max_brightness = 127; | 437 | r = devm_gpio_request_one(&dssdev->dev, bdata->panel_reset, |
496 | props.type = BACKLIGHT_PLATFORM; | 438 | GPIOF_OUT_INIT_LOW, "PANEL RESET"); |
497 | bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev, | 439 | if (r) |
498 | dssdev, &n8x0_bl_ops, &props); | 440 | return r; |
499 | if (IS_ERR(bldev)) { | ||
500 | r = PTR_ERR(bldev); | ||
501 | dev_err(&dssdev->dev, "register backlight failed\n"); | ||
502 | return r; | ||
503 | } | 441 | } |
504 | 442 | ||
505 | ddata->bldev = bldev; | 443 | if (gpio_is_valid(bdata->ctrl_pwrdown)) { |
506 | 444 | r = devm_gpio_request_one(&dssdev->dev, bdata->ctrl_pwrdown, | |
507 | bldev->props.fb_blank = FB_BLANK_UNBLANK; | 445 | GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN"); |
508 | bldev->props.power = FB_BLANK_UNBLANK; | 446 | if (r) |
509 | bldev->props.brightness = 127; | 447 | return r; |
510 | 448 | } | |
511 | n8x0_bl_update_status(bldev); | ||
512 | 449 | ||
513 | return 0; | 450 | return 0; |
514 | } | 451 | } |
515 | 452 | ||
516 | static void n8x0_panel_remove(struct omap_dss_device *dssdev) | 453 | static void n8x0_panel_remove(struct omap_dss_device *dssdev) |
517 | { | 454 | { |
518 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
519 | struct backlight_device *bldev; | ||
520 | |||
521 | dev_dbg(&dssdev->dev, "remove\n"); | 455 | dev_dbg(&dssdev->dev, "remove\n"); |
522 | 456 | ||
523 | bldev = ddata->bldev; | ||
524 | bldev->props.power = FB_BLANK_POWERDOWN; | ||
525 | n8x0_bl_update_status(bldev); | ||
526 | backlight_device_unregister(bldev); | ||
527 | |||
528 | dev_set_drvdata(&dssdev->dev, NULL); | 457 | dev_set_drvdata(&dssdev->dev, NULL); |
529 | } | 458 | } |
530 | 459 | ||
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index c4e9c2b1b465..20c3cd91ff9b 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c | |||
@@ -19,10 +19,11 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
22 | #include <linux/backlight.h> | ||
23 | #include <linux/fb.h> | 22 | #include <linux/fb.h> |
23 | #include <linux/gpio.h> | ||
24 | 24 | ||
25 | #include <video/omapdss.h> | 25 | #include <video/omapdss.h> |
26 | #include <video/omap-panel-data.h> | ||
26 | 27 | ||
27 | #define LCD_XRES 800 | 28 | #define LCD_XRES 800 |
28 | #define LCD_YRES 480 | 29 | #define LCD_YRES 480 |
@@ -32,10 +33,6 @@ | |||
32 | */ | 33 | */ |
33 | #define LCD_PIXEL_CLOCK 23800 | 34 | #define LCD_PIXEL_CLOCK 23800 |
34 | 35 | ||
35 | struct nec_8048_data { | ||
36 | struct backlight_device *bl; | ||
37 | }; | ||
38 | |||
39 | static const struct { | 36 | static const struct { |
40 | unsigned char addr; | 37 | unsigned char addr; |
41 | unsigned char dat; | 38 | unsigned char dat; |
@@ -84,93 +81,47 @@ static struct omap_video_timings nec_8048_panel_timings = { | |||
84 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | 81 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, |
85 | }; | 82 | }; |
86 | 83 | ||
87 | static int nec_8048_bl_update_status(struct backlight_device *bl) | 84 | static inline struct panel_nec_nl8048_data |
88 | { | 85 | *get_panel_data(const struct omap_dss_device *dssdev) |
89 | struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); | ||
90 | int level; | ||
91 | |||
92 | if (!dssdev->set_backlight) | ||
93 | return -EINVAL; | ||
94 | |||
95 | if (bl->props.fb_blank == FB_BLANK_UNBLANK && | ||
96 | bl->props.power == FB_BLANK_UNBLANK) | ||
97 | level = bl->props.brightness; | ||
98 | else | ||
99 | level = 0; | ||
100 | |||
101 | return dssdev->set_backlight(dssdev, level); | ||
102 | } | ||
103 | |||
104 | static int nec_8048_bl_get_brightness(struct backlight_device *bl) | ||
105 | { | 86 | { |
106 | if (bl->props.fb_blank == FB_BLANK_UNBLANK && | 87 | return (struct panel_nec_nl8048_data *) dssdev->data; |
107 | bl->props.power == FB_BLANK_UNBLANK) | ||
108 | return bl->props.brightness; | ||
109 | |||
110 | return 0; | ||
111 | } | 88 | } |
112 | 89 | ||
113 | static const struct backlight_ops nec_8048_bl_ops = { | ||
114 | .get_brightness = nec_8048_bl_get_brightness, | ||
115 | .update_status = nec_8048_bl_update_status, | ||
116 | }; | ||
117 | |||
118 | static int nec_8048_panel_probe(struct omap_dss_device *dssdev) | 90 | static int nec_8048_panel_probe(struct omap_dss_device *dssdev) |
119 | { | 91 | { |
120 | struct backlight_device *bl; | 92 | struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); |
121 | struct nec_8048_data *necd; | ||
122 | struct backlight_properties props; | ||
123 | int r; | 93 | int r; |
124 | 94 | ||
125 | dssdev->panel.timings = nec_8048_panel_timings; | 95 | if (!pd) |
126 | 96 | return -EINVAL; | |
127 | necd = kzalloc(sizeof(*necd), GFP_KERNEL); | ||
128 | if (!necd) | ||
129 | return -ENOMEM; | ||
130 | |||
131 | dev_set_drvdata(&dssdev->dev, necd); | ||
132 | 97 | ||
133 | memset(&props, 0, sizeof(struct backlight_properties)); | 98 | dssdev->panel.timings = nec_8048_panel_timings; |
134 | props.max_brightness = 255; | ||
135 | 99 | ||
136 | bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev, | 100 | if (gpio_is_valid(pd->qvga_gpio)) { |
137 | &nec_8048_bl_ops, &props); | 101 | r = devm_gpio_request_one(&dssdev->dev, pd->qvga_gpio, |
138 | if (IS_ERR(bl)) { | 102 | GPIOF_OUT_INIT_HIGH, "lcd QVGA"); |
139 | r = PTR_ERR(bl); | 103 | if (r) |
140 | kfree(necd); | 104 | return r; |
141 | return r; | ||
142 | } | 105 | } |
143 | necd->bl = bl; | ||
144 | |||
145 | bl->props.fb_blank = FB_BLANK_UNBLANK; | ||
146 | bl->props.power = FB_BLANK_UNBLANK; | ||
147 | bl->props.max_brightness = dssdev->max_backlight_level; | ||
148 | bl->props.brightness = dssdev->max_backlight_level; | ||
149 | 106 | ||
150 | r = nec_8048_bl_update_status(bl); | 107 | if (gpio_is_valid(pd->res_gpio)) { |
151 | if (r < 0) | 108 | r = devm_gpio_request_one(&dssdev->dev, pd->res_gpio, |
152 | dev_err(&dssdev->dev, "failed to set lcd brightness\n"); | 109 | GPIOF_OUT_INIT_LOW, "lcd RES"); |
110 | if (r) | ||
111 | return r; | ||
112 | } | ||
153 | 113 | ||
154 | return 0; | 114 | return 0; |
155 | } | 115 | } |
156 | 116 | ||
157 | static void nec_8048_panel_remove(struct omap_dss_device *dssdev) | 117 | static void nec_8048_panel_remove(struct omap_dss_device *dssdev) |
158 | { | 118 | { |
159 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); | ||
160 | struct backlight_device *bl = necd->bl; | ||
161 | |||
162 | bl->props.power = FB_BLANK_POWERDOWN; | ||
163 | nec_8048_bl_update_status(bl); | ||
164 | backlight_device_unregister(bl); | ||
165 | |||
166 | kfree(necd); | ||
167 | } | 119 | } |
168 | 120 | ||
169 | static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) | 121 | static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) |
170 | { | 122 | { |
123 | struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); | ||
171 | int r; | 124 | int r; |
172 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); | ||
173 | struct backlight_device *bl = necd->bl; | ||
174 | 125 | ||
175 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 126 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
176 | return 0; | 127 | return 0; |
@@ -182,36 +133,24 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) | |||
182 | if (r) | 133 | if (r) |
183 | goto err0; | 134 | goto err0; |
184 | 135 | ||
185 | if (dssdev->platform_enable) { | 136 | if (gpio_is_valid(pd->res_gpio)) |
186 | r = dssdev->platform_enable(dssdev); | 137 | gpio_set_value_cansleep(pd->res_gpio, 1); |
187 | if (r) | ||
188 | goto err1; | ||
189 | } | ||
190 | |||
191 | r = nec_8048_bl_update_status(bl); | ||
192 | if (r < 0) | ||
193 | dev_err(&dssdev->dev, "failed to set lcd brightness\n"); | ||
194 | 138 | ||
195 | return 0; | 139 | return 0; |
196 | err1: | 140 | |
197 | omapdss_dpi_display_disable(dssdev); | ||
198 | err0: | 141 | err0: |
199 | return r; | 142 | return r; |
200 | } | 143 | } |
201 | 144 | ||
202 | static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) | 145 | static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) |
203 | { | 146 | { |
204 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); | 147 | struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); |
205 | struct backlight_device *bl = necd->bl; | ||
206 | 148 | ||
207 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 149 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
208 | return; | 150 | return; |
209 | 151 | ||
210 | bl->props.brightness = 0; | 152 | if (gpio_is_valid(pd->res_gpio)) |
211 | nec_8048_bl_update_status(bl); | 153 | gpio_set_value_cansleep(pd->res_gpio, 0); |
212 | |||
213 | if (dssdev->platform_disable) | ||
214 | dssdev->platform_disable(dssdev); | ||
215 | 154 | ||
216 | omapdss_dpi_display_disable(dssdev); | 155 | omapdss_dpi_display_disable(dssdev); |
217 | } | 156 | } |
@@ -303,16 +242,22 @@ static int nec_8048_spi_remove(struct spi_device *spi) | |||
303 | return 0; | 242 | return 0; |
304 | } | 243 | } |
305 | 244 | ||
306 | static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg) | 245 | #ifdef CONFIG_PM_SLEEP |
246 | |||
247 | static int nec_8048_spi_suspend(struct device *dev) | ||
307 | { | 248 | { |
249 | struct spi_device *spi = to_spi_device(dev); | ||
250 | |||
308 | nec_8048_spi_send(spi, 2, 0x01); | 251 | nec_8048_spi_send(spi, 2, 0x01); |
309 | mdelay(40); | 252 | mdelay(40); |
310 | 253 | ||
311 | return 0; | 254 | return 0; |
312 | } | 255 | } |
313 | 256 | ||
314 | static int nec_8048_spi_resume(struct spi_device *spi) | 257 | static int nec_8048_spi_resume(struct device *dev) |
315 | { | 258 | { |
259 | struct spi_device *spi = to_spi_device(dev); | ||
260 | |||
316 | /* reinitialize the panel */ | 261 | /* reinitialize the panel */ |
317 | spi_setup(spi); | 262 | spi_setup(spi); |
318 | nec_8048_spi_send(spi, 2, 0x00); | 263 | nec_8048_spi_send(spi, 2, 0x00); |
@@ -321,14 +266,20 @@ static int nec_8048_spi_resume(struct spi_device *spi) | |||
321 | return 0; | 266 | return 0; |
322 | } | 267 | } |
323 | 268 | ||
269 | static SIMPLE_DEV_PM_OPS(nec_8048_spi_pm_ops, nec_8048_spi_suspend, | ||
270 | nec_8048_spi_resume); | ||
271 | #define NEC_8048_SPI_PM_OPS (&nec_8048_spi_pm_ops) | ||
272 | #else | ||
273 | #define NEC_8048_SPI_PM_OPS NULL | ||
274 | #endif | ||
275 | |||
324 | static struct spi_driver nec_8048_spi_driver = { | 276 | static struct spi_driver nec_8048_spi_driver = { |
325 | .probe = nec_8048_spi_probe, | 277 | .probe = nec_8048_spi_probe, |
326 | .remove = nec_8048_spi_remove, | 278 | .remove = nec_8048_spi_remove, |
327 | .suspend = nec_8048_spi_suspend, | ||
328 | .resume = nec_8048_spi_resume, | ||
329 | .driver = { | 279 | .driver = { |
330 | .name = "nec_8048_spi", | 280 | .name = "nec_8048_spi", |
331 | .owner = THIS_MODULE, | 281 | .owner = THIS_MODULE, |
282 | .pm = NEC_8048_SPI_PM_OPS, | ||
332 | }, | 283 | }, |
333 | }; | 284 | }; |
334 | 285 | ||
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 1b94018aac3e..62f2db04fbc8 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <linux/gpio.h> | 31 | #include <linux/gpio.h> |
32 | 32 | ||
33 | #include <video/omapdss.h> | 33 | #include <video/omapdss.h> |
34 | #include <video/omap-panel-picodlp.h> | 34 | #include <video/omap-panel-data.h> |
35 | 35 | ||
36 | #include "panel-picodlp.h" | 36 | #include "panel-picodlp.h" |
37 | 37 | ||
@@ -354,12 +354,6 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) | |||
354 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | 354 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); |
355 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | 355 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); |
356 | 356 | ||
357 | if (dssdev->platform_enable) { | ||
358 | r = dssdev->platform_enable(dssdev); | ||
359 | if (r) | ||
360 | return r; | ||
361 | } | ||
362 | |||
363 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); | 357 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); |
364 | msleep(1); | 358 | msleep(1); |
365 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 1); | 359 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 1); |
@@ -398,9 +392,6 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) | |||
398 | err: | 392 | err: |
399 | omapdss_dpi_display_disable(dssdev); | 393 | omapdss_dpi_display_disable(dssdev); |
400 | err1: | 394 | err1: |
401 | if (dssdev->platform_disable) | ||
402 | dssdev->platform_disable(dssdev); | ||
403 | |||
404 | return r; | 395 | return r; |
405 | } | 396 | } |
406 | 397 | ||
@@ -412,9 +403,6 @@ static void picodlp_panel_power_off(struct omap_dss_device *dssdev) | |||
412 | 403 | ||
413 | gpio_set_value(picodlp_pdata->emu_done_gpio, 0); | 404 | gpio_set_value(picodlp_pdata->emu_done_gpio, 0); |
414 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); | 405 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); |
415 | |||
416 | if (dssdev->platform_disable) | ||
417 | dssdev->platform_disable(dssdev); | ||
418 | } | 406 | } |
419 | 407 | ||
420 | static int picodlp_panel_probe(struct omap_dss_device *dssdev) | 408 | static int picodlp_panel_probe(struct omap_dss_device *dssdev) |
@@ -423,11 +411,14 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) | |||
423 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | 411 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); |
424 | struct i2c_adapter *adapter; | 412 | struct i2c_adapter *adapter; |
425 | struct i2c_client *picodlp_i2c_client; | 413 | struct i2c_client *picodlp_i2c_client; |
426 | int r = 0, picodlp_adapter_id; | 414 | int r, picodlp_adapter_id; |
427 | 415 | ||
428 | dssdev->panel.timings = pico_ls_timings; | 416 | dssdev->panel.timings = pico_ls_timings; |
429 | 417 | ||
430 | picod = kzalloc(sizeof(struct picodlp_data), GFP_KERNEL); | 418 | if (!picodlp_pdata) |
419 | return -EINVAL; | ||
420 | |||
421 | picod = devm_kzalloc(&dssdev->dev, sizeof(*picod), GFP_KERNEL); | ||
431 | if (!picod) | 422 | if (!picod) |
432 | return -ENOMEM; | 423 | return -ENOMEM; |
433 | 424 | ||
@@ -438,25 +429,37 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) | |||
438 | adapter = i2c_get_adapter(picodlp_adapter_id); | 429 | adapter = i2c_get_adapter(picodlp_adapter_id); |
439 | if (!adapter) { | 430 | if (!adapter) { |
440 | dev_err(&dssdev->dev, "can't get i2c adapter\n"); | 431 | dev_err(&dssdev->dev, "can't get i2c adapter\n"); |
441 | r = -ENODEV; | 432 | return -ENODEV; |
442 | goto err; | ||
443 | } | 433 | } |
444 | 434 | ||
445 | picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); | 435 | picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); |
446 | if (!picodlp_i2c_client) { | 436 | if (!picodlp_i2c_client) { |
447 | dev_err(&dssdev->dev, "can't add i2c device::" | 437 | dev_err(&dssdev->dev, "can't add i2c device::" |
448 | " picodlp_i2c_client is NULL\n"); | 438 | " picodlp_i2c_client is NULL\n"); |
449 | r = -ENODEV; | 439 | return -ENODEV; |
450 | goto err; | ||
451 | } | 440 | } |
452 | 441 | ||
453 | picod->picodlp_i2c_client = picodlp_i2c_client; | 442 | picod->picodlp_i2c_client = picodlp_i2c_client; |
454 | 443 | ||
455 | dev_set_drvdata(&dssdev->dev, picod); | 444 | dev_set_drvdata(&dssdev->dev, picod); |
456 | return r; | 445 | |
457 | err: | 446 | if (gpio_is_valid(picodlp_pdata->emu_done_gpio)) { |
458 | kfree(picod); | 447 | r = devm_gpio_request_one(&dssdev->dev, |
459 | return r; | 448 | picodlp_pdata->emu_done_gpio, |
449 | GPIOF_IN, "DLP EMU DONE"); | ||
450 | if (r) | ||
451 | return r; | ||
452 | } | ||
453 | |||
454 | if (gpio_is_valid(picodlp_pdata->pwrgood_gpio)) { | ||
455 | r = devm_gpio_request_one(&dssdev->dev, | ||
456 | picodlp_pdata->pwrgood_gpio, | ||
457 | GPIOF_OUT_INIT_LOW, "DLP PWRGOOD"); | ||
458 | if (r) | ||
459 | return r; | ||
460 | } | ||
461 | |||
462 | return 0; | ||
460 | } | 463 | } |
461 | 464 | ||
462 | static void picodlp_panel_remove(struct omap_dss_device *dssdev) | 465 | static void picodlp_panel_remove(struct omap_dss_device *dssdev) |
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index cada8c621e01..74cb0eb45311 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c | |||
@@ -20,16 +20,13 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/backlight.h> | ||
24 | #include <linux/fb.h> | 23 | #include <linux/fb.h> |
25 | #include <linux/err.h> | 24 | #include <linux/err.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/gpio.h> | ||
27 | 27 | ||
28 | #include <video/omapdss.h> | 28 | #include <video/omapdss.h> |
29 | 29 | #include <video/omap-panel-data.h> | |
30 | struct sharp_data { | ||
31 | struct backlight_device *bl; | ||
32 | }; | ||
33 | 30 | ||
34 | static struct omap_video_timings sharp_ls_timings = { | 31 | static struct omap_video_timings sharp_ls_timings = { |
35 | .x_res = 480, | 32 | .x_res = 480, |
@@ -52,91 +49,67 @@ static struct omap_video_timings sharp_ls_timings = { | |||
52 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | 49 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, |
53 | }; | 50 | }; |
54 | 51 | ||
55 | static int sharp_ls_bl_update_status(struct backlight_device *bl) | 52 | static inline struct panel_sharp_ls037v7dw01_data |
53 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
56 | { | 54 | { |
57 | struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); | 55 | return (struct panel_sharp_ls037v7dw01_data *) dssdev->data; |
58 | int level; | ||
59 | |||
60 | if (!dssdev->set_backlight) | ||
61 | return -EINVAL; | ||
62 | |||
63 | if (bl->props.fb_blank == FB_BLANK_UNBLANK && | ||
64 | bl->props.power == FB_BLANK_UNBLANK) | ||
65 | level = bl->props.brightness; | ||
66 | else | ||
67 | level = 0; | ||
68 | |||
69 | return dssdev->set_backlight(dssdev, level); | ||
70 | } | 56 | } |
71 | 57 | ||
72 | static int sharp_ls_bl_get_brightness(struct backlight_device *bl) | ||
73 | { | ||
74 | if (bl->props.fb_blank == FB_BLANK_UNBLANK && | ||
75 | bl->props.power == FB_BLANK_UNBLANK) | ||
76 | return bl->props.brightness; | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | static const struct backlight_ops sharp_ls_bl_ops = { | ||
82 | .get_brightness = sharp_ls_bl_get_brightness, | ||
83 | .update_status = sharp_ls_bl_update_status, | ||
84 | }; | ||
85 | |||
86 | |||
87 | |||
88 | static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) | 58 | static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) |
89 | { | 59 | { |
90 | struct backlight_properties props; | 60 | struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); |
91 | struct backlight_device *bl; | ||
92 | struct sharp_data *sd; | ||
93 | int r; | 61 | int r; |
94 | 62 | ||
63 | if (!pd) | ||
64 | return -EINVAL; | ||
65 | |||
95 | dssdev->panel.timings = sharp_ls_timings; | 66 | dssdev->panel.timings = sharp_ls_timings; |
96 | 67 | ||
97 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); | 68 | if (gpio_is_valid(pd->mo_gpio)) { |
98 | if (!sd) | 69 | r = devm_gpio_request_one(&dssdev->dev, pd->mo_gpio, |
99 | return -ENOMEM; | 70 | GPIOF_OUT_INIT_LOW, "lcd MO"); |
71 | if (r) | ||
72 | return r; | ||
73 | } | ||
100 | 74 | ||
101 | dev_set_drvdata(&dssdev->dev, sd); | 75 | if (gpio_is_valid(pd->lr_gpio)) { |
76 | r = devm_gpio_request_one(&dssdev->dev, pd->lr_gpio, | ||
77 | GPIOF_OUT_INIT_HIGH, "lcd LR"); | ||
78 | if (r) | ||
79 | return r; | ||
80 | } | ||
102 | 81 | ||
103 | memset(&props, 0, sizeof(struct backlight_properties)); | 82 | if (gpio_is_valid(pd->ud_gpio)) { |
104 | props.max_brightness = dssdev->max_backlight_level; | 83 | r = devm_gpio_request_one(&dssdev->dev, pd->ud_gpio, |
105 | props.type = BACKLIGHT_RAW; | 84 | GPIOF_OUT_INIT_HIGH, "lcd UD"); |
85 | if (r) | ||
86 | return r; | ||
87 | } | ||
106 | 88 | ||
107 | bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev, | 89 | if (gpio_is_valid(pd->resb_gpio)) { |
108 | &sharp_ls_bl_ops, &props); | 90 | r = devm_gpio_request_one(&dssdev->dev, pd->resb_gpio, |
109 | if (IS_ERR(bl)) { | 91 | GPIOF_OUT_INIT_LOW, "lcd RESB"); |
110 | r = PTR_ERR(bl); | 92 | if (r) |
111 | kfree(sd); | 93 | return r; |
112 | return r; | ||
113 | } | 94 | } |
114 | sd->bl = bl; | ||
115 | 95 | ||
116 | bl->props.fb_blank = FB_BLANK_UNBLANK; | 96 | if (gpio_is_valid(pd->ini_gpio)) { |
117 | bl->props.power = FB_BLANK_UNBLANK; | 97 | r = devm_gpio_request_one(&dssdev->dev, pd->ini_gpio, |
118 | bl->props.brightness = dssdev->max_backlight_level; | 98 | GPIOF_OUT_INIT_LOW, "lcd INI"); |
119 | r = sharp_ls_bl_update_status(bl); | 99 | if (r) |
120 | if (r < 0) | 100 | return r; |
121 | dev_err(&dssdev->dev, "failed to set lcd brightness\n"); | 101 | } |
122 | 102 | ||
123 | return 0; | 103 | return 0; |
124 | } | 104 | } |
125 | 105 | ||
126 | static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev) | 106 | static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev) |
127 | { | 107 | { |
128 | struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); | ||
129 | struct backlight_device *bl = sd->bl; | ||
130 | |||
131 | bl->props.power = FB_BLANK_POWERDOWN; | ||
132 | sharp_ls_bl_update_status(bl); | ||
133 | backlight_device_unregister(bl); | ||
134 | |||
135 | kfree(sd); | ||
136 | } | 108 | } |
137 | 109 | ||
138 | static int sharp_ls_power_on(struct omap_dss_device *dssdev) | 110 | static int sharp_ls_power_on(struct omap_dss_device *dssdev) |
139 | { | 111 | { |
112 | struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); | ||
140 | int r = 0; | 113 | int r = 0; |
141 | 114 | ||
142 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 115 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
@@ -152,26 +125,29 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev) | |||
152 | /* wait couple of vsyncs until enabling the LCD */ | 125 | /* wait couple of vsyncs until enabling the LCD */ |
153 | msleep(50); | 126 | msleep(50); |
154 | 127 | ||
155 | if (dssdev->platform_enable) { | 128 | if (gpio_is_valid(pd->resb_gpio)) |
156 | r = dssdev->platform_enable(dssdev); | 129 | gpio_set_value_cansleep(pd->resb_gpio, 1); |
157 | if (r) | 130 | |
158 | goto err1; | 131 | if (gpio_is_valid(pd->ini_gpio)) |
159 | } | 132 | gpio_set_value_cansleep(pd->ini_gpio, 1); |
160 | 133 | ||
161 | return 0; | 134 | return 0; |
162 | err1: | ||
163 | omapdss_dpi_display_disable(dssdev); | ||
164 | err0: | 135 | err0: |
165 | return r; | 136 | return r; |
166 | } | 137 | } |
167 | 138 | ||
168 | static void sharp_ls_power_off(struct omap_dss_device *dssdev) | 139 | static void sharp_ls_power_off(struct omap_dss_device *dssdev) |
169 | { | 140 | { |
141 | struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); | ||
142 | |||
170 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 143 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
171 | return; | 144 | return; |
172 | 145 | ||
173 | if (dssdev->platform_disable) | 146 | if (gpio_is_valid(pd->ini_gpio)) |
174 | dssdev->platform_disable(dssdev); | 147 | gpio_set_value_cansleep(pd->ini_gpio, 0); |
148 | |||
149 | if (gpio_is_valid(pd->resb_gpio)) | ||
150 | gpio_set_value_cansleep(pd->resb_gpio, 0); | ||
175 | 151 | ||
176 | /* wait at least 5 vsyncs after disabling the LCD */ | 152 | /* wait at least 5 vsyncs after disabling the LCD */ |
177 | 153 | ||
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index a32407a5735a..c4f78bda115a 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
@@ -33,7 +33,7 @@ | |||
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | 34 | ||
35 | #include <video/omapdss.h> | 35 | #include <video/omapdss.h> |
36 | #include <video/omap-panel-nokia-dsi.h> | 36 | #include <video/omap-panel-data.h> |
37 | #include <video/mipi_display.h> | 37 | #include <video/mipi_display.h> |
38 | 38 | ||
39 | /* DSI Virtual channel. Hardcoded for now. */ | 39 | /* DSI Virtual channel. Hardcoded for now. */ |
@@ -54,61 +54,6 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); | |||
54 | 54 | ||
55 | static int taal_panel_reset(struct omap_dss_device *dssdev); | 55 | static int taal_panel_reset(struct omap_dss_device *dssdev); |
56 | 56 | ||
57 | /** | ||
58 | * struct panel_config - panel configuration | ||
59 | * @name: panel name | ||
60 | * @type: panel type | ||
61 | * @timings: panel resolution | ||
62 | * @sleep: various panel specific delays, passed to msleep() if non-zero | ||
63 | * @reset_sequence: reset sequence timings, passed to udelay() if non-zero | ||
64 | * @regulators: array of panel regulators | ||
65 | * @num_regulators: number of regulators in the array | ||
66 | */ | ||
67 | struct panel_config { | ||
68 | const char *name; | ||
69 | int type; | ||
70 | |||
71 | struct omap_video_timings timings; | ||
72 | |||
73 | struct { | ||
74 | unsigned int sleep_in; | ||
75 | unsigned int sleep_out; | ||
76 | unsigned int hw_reset; | ||
77 | unsigned int enable_te; | ||
78 | } sleep; | ||
79 | |||
80 | struct { | ||
81 | unsigned int high; | ||
82 | unsigned int low; | ||
83 | } reset_sequence; | ||
84 | |||
85 | }; | ||
86 | |||
87 | enum { | ||
88 | PANEL_TAAL, | ||
89 | }; | ||
90 | |||
91 | static struct panel_config panel_configs[] = { | ||
92 | { | ||
93 | .name = "taal", | ||
94 | .type = PANEL_TAAL, | ||
95 | .timings = { | ||
96 | .x_res = 864, | ||
97 | .y_res = 480, | ||
98 | }, | ||
99 | .sleep = { | ||
100 | .sleep_in = 5, | ||
101 | .sleep_out = 5, | ||
102 | .hw_reset = 5, | ||
103 | .enable_te = 100, /* possible panel bug */ | ||
104 | }, | ||
105 | .reset_sequence = { | ||
106 | .high = 10, | ||
107 | .low = 10, | ||
108 | }, | ||
109 | }, | ||
110 | }; | ||
111 | |||
112 | struct taal_data { | 57 | struct taal_data { |
113 | struct mutex lock; | 58 | struct mutex lock; |
114 | 59 | ||
@@ -121,9 +66,6 @@ struct taal_data { | |||
121 | 66 | ||
122 | struct omap_dss_device *dssdev; | 67 | struct omap_dss_device *dssdev; |
123 | 68 | ||
124 | /* panel specific HW info */ | ||
125 | struct panel_config *panel_config; | ||
126 | |||
127 | /* panel HW configuration from DT or platform data */ | 69 | /* panel HW configuration from DT or platform data */ |
128 | int reset_gpio; | 70 | int reset_gpio; |
129 | int ext_te_gpio; | 71 | int ext_te_gpio; |
@@ -134,8 +76,6 @@ struct taal_data { | |||
134 | 76 | ||
135 | /* runtime variables */ | 77 | /* runtime variables */ |
136 | bool enabled; | 78 | bool enabled; |
137 | u8 rotate; | ||
138 | bool mirror; | ||
139 | 79 | ||
140 | bool te_enabled; | 80 | bool te_enabled; |
141 | 81 | ||
@@ -221,8 +161,7 @@ static int taal_sleep_in(struct taal_data *td) | |||
221 | 161 | ||
222 | hw_guard_start(td, 120); | 162 | hw_guard_start(td, 120); |
223 | 163 | ||
224 | if (td->panel_config->sleep.sleep_in) | 164 | msleep(5); |
225 | msleep(td->panel_config->sleep.sleep_in); | ||
226 | 165 | ||
227 | return 0; | 166 | return 0; |
228 | } | 167 | } |
@@ -239,8 +178,7 @@ static int taal_sleep_out(struct taal_data *td) | |||
239 | 178 | ||
240 | hw_guard_start(td, 120); | 179 | hw_guard_start(td, 120); |
241 | 180 | ||
242 | if (td->panel_config->sleep.sleep_out) | 181 | msleep(5); |
243 | msleep(td->panel_config->sleep.sleep_out); | ||
244 | 182 | ||
245 | return 0; | 183 | return 0; |
246 | } | 184 | } |
@@ -262,49 +200,6 @@ static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3) | |||
262 | return 0; | 200 | return 0; |
263 | } | 201 | } |
264 | 202 | ||
265 | static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror) | ||
266 | { | ||
267 | int r; | ||
268 | u8 mode; | ||
269 | int b5, b6, b7; | ||
270 | |||
271 | r = taal_dcs_read_1(td, MIPI_DCS_GET_ADDRESS_MODE, &mode); | ||
272 | if (r) | ||
273 | return r; | ||
274 | |||
275 | switch (rotate) { | ||
276 | default: | ||
277 | case 0: | ||
278 | b7 = 0; | ||
279 | b6 = 0; | ||
280 | b5 = 0; | ||
281 | break; | ||
282 | case 1: | ||
283 | b7 = 0; | ||
284 | b6 = 1; | ||
285 | b5 = 1; | ||
286 | break; | ||
287 | case 2: | ||
288 | b7 = 1; | ||
289 | b6 = 1; | ||
290 | b5 = 0; | ||
291 | break; | ||
292 | case 3: | ||
293 | b7 = 1; | ||
294 | b6 = 0; | ||
295 | b5 = 1; | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | if (mirror) | ||
300 | b6 = !b6; | ||
301 | |||
302 | mode &= ~((1<<7) | (1<<6) | (1<<5)); | ||
303 | mode |= (b7 << 7) | (b6 << 6) | (b5 << 5); | ||
304 | |||
305 | return taal_dcs_write_1(td, MIPI_DCS_SET_ADDRESS_MODE, mode); | ||
306 | } | ||
307 | |||
308 | static int taal_set_update_window(struct taal_data *td, | 203 | static int taal_set_update_window(struct taal_data *td, |
309 | u16 x, u16 y, u16 w, u16 h) | 204 | u16 x, u16 y, u16 w, u16 h) |
310 | { | 205 | { |
@@ -515,15 +410,8 @@ static const struct backlight_ops taal_bl_ops = { | |||
515 | static void taal_get_resolution(struct omap_dss_device *dssdev, | 410 | static void taal_get_resolution(struct omap_dss_device *dssdev, |
516 | u16 *xres, u16 *yres) | 411 | u16 *xres, u16 *yres) |
517 | { | 412 | { |
518 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 413 | *xres = dssdev->panel.timings.x_res; |
519 | 414 | *yres = dssdev->panel.timings.y_res; | |
520 | if (td->rotate == 0 || td->rotate == 2) { | ||
521 | *xres = dssdev->panel.timings.x_res; | ||
522 | *yres = dssdev->panel.timings.y_res; | ||
523 | } else { | ||
524 | *yres = dssdev->panel.timings.x_res; | ||
525 | *xres = dssdev->panel.timings.y_res; | ||
526 | } | ||
527 | } | 415 | } |
528 | 416 | ||
529 | static ssize_t taal_num_errors_show(struct device *dev, | 417 | static ssize_t taal_num_errors_show(struct device *dev, |
@@ -845,17 +733,14 @@ static void taal_hw_reset(struct omap_dss_device *dssdev) | |||
845 | return; | 733 | return; |
846 | 734 | ||
847 | gpio_set_value(td->reset_gpio, 1); | 735 | gpio_set_value(td->reset_gpio, 1); |
848 | if (td->panel_config->reset_sequence.high) | 736 | udelay(10); |
849 | udelay(td->panel_config->reset_sequence.high); | ||
850 | /* reset the panel */ | 737 | /* reset the panel */ |
851 | gpio_set_value(td->reset_gpio, 0); | 738 | gpio_set_value(td->reset_gpio, 0); |
852 | /* assert reset */ | 739 | /* assert reset */ |
853 | if (td->panel_config->reset_sequence.low) | 740 | udelay(10); |
854 | udelay(td->panel_config->reset_sequence.low); | ||
855 | gpio_set_value(td->reset_gpio, 1); | 741 | gpio_set_value(td->reset_gpio, 1); |
856 | /* wait after releasing reset */ | 742 | /* wait after releasing reset */ |
857 | if (td->panel_config->sleep.hw_reset) | 743 | msleep(5); |
858 | msleep(td->panel_config->sleep.hw_reset); | ||
859 | } | 744 | } |
860 | 745 | ||
861 | static void taal_probe_pdata(struct taal_data *td, | 746 | static void taal_probe_pdata(struct taal_data *td, |
@@ -881,8 +766,7 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
881 | struct backlight_properties props; | 766 | struct backlight_properties props; |
882 | struct taal_data *td; | 767 | struct taal_data *td; |
883 | struct backlight_device *bldev = NULL; | 768 | struct backlight_device *bldev = NULL; |
884 | int r, i; | 769 | int r; |
885 | const char *panel_name; | ||
886 | 770 | ||
887 | dev_dbg(&dssdev->dev, "probe\n"); | 771 | dev_dbg(&dssdev->dev, "probe\n"); |
888 | 772 | ||
@@ -897,26 +781,13 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
897 | const struct nokia_dsi_panel_data *pdata = dssdev->data; | 781 | const struct nokia_dsi_panel_data *pdata = dssdev->data; |
898 | 782 | ||
899 | taal_probe_pdata(td, pdata); | 783 | taal_probe_pdata(td, pdata); |
900 | |||
901 | panel_name = pdata->name; | ||
902 | } else { | 784 | } else { |
903 | return -ENODEV; | 785 | return -ENODEV; |
904 | } | 786 | } |
905 | 787 | ||
906 | if (panel_name == NULL) | 788 | dssdev->panel.timings.x_res = 864; |
907 | return -EINVAL; | 789 | dssdev->panel.timings.y_res = 480; |
908 | 790 | dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000); | |
909 | for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { | ||
910 | if (strcmp(panel_name, panel_configs[i].name) == 0) { | ||
911 | td->panel_config = &panel_configs[i]; | ||
912 | break; | ||
913 | } | ||
914 | } | ||
915 | |||
916 | if (!td->panel_config) | ||
917 | return -EINVAL; | ||
918 | |||
919 | dssdev->panel.timings = td->panel_config->timings; | ||
920 | dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; | 791 | dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; |
921 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | 792 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | |
922 | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; | 793 | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; |
@@ -1049,6 +920,15 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1049 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 920 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1050 | u8 id1, id2, id3; | 921 | u8 id1, id2, id3; |
1051 | int r; | 922 | int r; |
923 | struct omap_dss_dsi_config dsi_config = { | ||
924 | .mode = OMAP_DSS_DSI_CMD_MODE, | ||
925 | .pixel_format = OMAP_DSS_DSI_FMT_RGB888, | ||
926 | .timings = &dssdev->panel.timings, | ||
927 | .hs_clk_min = 150000000, | ||
928 | .hs_clk_max = 300000000, | ||
929 | .lp_clk_min = 7000000, | ||
930 | .lp_clk_max = 10000000, | ||
931 | }; | ||
1052 | 932 | ||
1053 | r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); | 933 | r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); |
1054 | if (r) { | 934 | if (r) { |
@@ -1056,14 +936,9 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1056 | goto err0; | 936 | goto err0; |
1057 | }; | 937 | }; |
1058 | 938 | ||
1059 | omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res, | 939 | r = omapdss_dsi_set_config(dssdev, &dsi_config); |
1060 | dssdev->panel.timings.y_res); | ||
1061 | omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888); | ||
1062 | omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE); | ||
1063 | |||
1064 | r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000); | ||
1065 | if (r) { | 940 | if (r) { |
1066 | dev_err(&dssdev->dev, "failed to set HS and LP clocks\n"); | 941 | dev_err(&dssdev->dev, "failed to configure DSI\n"); |
1067 | goto err0; | 942 | goto err0; |
1068 | } | 943 | } |
1069 | 944 | ||
@@ -1086,8 +961,7 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1086 | goto err; | 961 | goto err; |
1087 | 962 | ||
1088 | /* on early Taal revisions CABC is broken */ | 963 | /* on early Taal revisions CABC is broken */ |
1089 | if (td->panel_config->type == PANEL_TAAL && | 964 | if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) |
1090 | (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) | ||
1091 | td->cabc_broken = true; | 965 | td->cabc_broken = true; |
1092 | 966 | ||
1093 | r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff); | 967 | r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff); |
@@ -1104,10 +978,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1104 | if (r) | 978 | if (r) |
1105 | goto err; | 979 | goto err; |
1106 | 980 | ||
1107 | r = taal_set_addr_mode(td, td->rotate, td->mirror); | ||
1108 | if (r) | ||
1109 | goto err; | ||
1110 | |||
1111 | if (!td->cabc_broken) { | 981 | if (!td->cabc_broken) { |
1112 | r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode); | 982 | r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode); |
1113 | if (r) | 983 | if (r) |
@@ -1129,8 +999,8 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1129 | td->enabled = 1; | 999 | td->enabled = 1; |
1130 | 1000 | ||
1131 | if (!td->intro_printed) { | 1001 | if (!td->intro_printed) { |
1132 | dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n", | 1002 | dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n", |
1133 | td->panel_config->name, id1, id2, id3); | 1003 | id1, id2, id3); |
1134 | if (td->cabc_broken) | 1004 | if (td->cabc_broken) |
1135 | dev_info(&dssdev->dev, | 1005 | dev_info(&dssdev->dev, |
1136 | "old Taal version, CABC disabled\n"); | 1006 | "old Taal version, CABC disabled\n"); |
@@ -1311,8 +1181,8 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
1311 | 1181 | ||
1312 | /* XXX no need to send this every frame, but dsi break if not done */ | 1182 | /* XXX no need to send this every frame, but dsi break if not done */ |
1313 | r = taal_set_update_window(td, 0, 0, | 1183 | r = taal_set_update_window(td, 0, 0, |
1314 | td->panel_config->timings.x_res, | 1184 | dssdev->panel.timings.x_res, |
1315 | td->panel_config->timings.y_res); | 1185 | dssdev->panel.timings.y_res); |
1316 | if (r) | 1186 | if (r) |
1317 | goto err; | 1187 | goto err; |
1318 | 1188 | ||
@@ -1365,8 +1235,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
1365 | if (!gpio_is_valid(td->ext_te_gpio)) | 1235 | if (!gpio_is_valid(td->ext_te_gpio)) |
1366 | omapdss_dsi_enable_te(dssdev, enable); | 1236 | omapdss_dsi_enable_te(dssdev, enable); |
1367 | 1237 | ||
1368 | if (td->panel_config->sleep.enable_te) | 1238 | /* possible panel bug */ |
1369 | msleep(td->panel_config->sleep.enable_te); | 1239 | msleep(100); |
1370 | 1240 | ||
1371 | return r; | 1241 | return r; |
1372 | } | 1242 | } |
@@ -1419,112 +1289,6 @@ static int taal_get_te(struct omap_dss_device *dssdev) | |||
1419 | return r; | 1289 | return r; |
1420 | } | 1290 | } |
1421 | 1291 | ||
1422 | static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | ||
1423 | { | ||
1424 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
1425 | u16 dw, dh; | ||
1426 | int r; | ||
1427 | |||
1428 | dev_dbg(&dssdev->dev, "rotate %d\n", rotate); | ||
1429 | |||
1430 | mutex_lock(&td->lock); | ||
1431 | |||
1432 | if (td->rotate == rotate) | ||
1433 | goto end; | ||
1434 | |||
1435 | dsi_bus_lock(dssdev); | ||
1436 | |||
1437 | if (td->enabled) { | ||
1438 | r = taal_wake_up(dssdev); | ||
1439 | if (r) | ||
1440 | goto err; | ||
1441 | |||
1442 | r = taal_set_addr_mode(td, rotate, td->mirror); | ||
1443 | if (r) | ||
1444 | goto err; | ||
1445 | } | ||
1446 | |||
1447 | if (rotate == 0 || rotate == 2) { | ||
1448 | dw = dssdev->panel.timings.x_res; | ||
1449 | dh = dssdev->panel.timings.y_res; | ||
1450 | } else { | ||
1451 | dw = dssdev->panel.timings.y_res; | ||
1452 | dh = dssdev->panel.timings.x_res; | ||
1453 | } | ||
1454 | |||
1455 | omapdss_dsi_set_size(dssdev, dw, dh); | ||
1456 | |||
1457 | td->rotate = rotate; | ||
1458 | |||
1459 | dsi_bus_unlock(dssdev); | ||
1460 | end: | ||
1461 | mutex_unlock(&td->lock); | ||
1462 | return 0; | ||
1463 | err: | ||
1464 | dsi_bus_unlock(dssdev); | ||
1465 | mutex_unlock(&td->lock); | ||
1466 | return r; | ||
1467 | } | ||
1468 | |||
1469 | static u8 taal_get_rotate(struct omap_dss_device *dssdev) | ||
1470 | { | ||
1471 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
1472 | int r; | ||
1473 | |||
1474 | mutex_lock(&td->lock); | ||
1475 | r = td->rotate; | ||
1476 | mutex_unlock(&td->lock); | ||
1477 | |||
1478 | return r; | ||
1479 | } | ||
1480 | |||
1481 | static int taal_mirror(struct omap_dss_device *dssdev, bool enable) | ||
1482 | { | ||
1483 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
1484 | int r; | ||
1485 | |||
1486 | dev_dbg(&dssdev->dev, "mirror %d\n", enable); | ||
1487 | |||
1488 | mutex_lock(&td->lock); | ||
1489 | |||
1490 | if (td->mirror == enable) | ||
1491 | goto end; | ||
1492 | |||
1493 | dsi_bus_lock(dssdev); | ||
1494 | if (td->enabled) { | ||
1495 | r = taal_wake_up(dssdev); | ||
1496 | if (r) | ||
1497 | goto err; | ||
1498 | |||
1499 | r = taal_set_addr_mode(td, td->rotate, enable); | ||
1500 | if (r) | ||
1501 | goto err; | ||
1502 | } | ||
1503 | |||
1504 | td->mirror = enable; | ||
1505 | |||
1506 | dsi_bus_unlock(dssdev); | ||
1507 | end: | ||
1508 | mutex_unlock(&td->lock); | ||
1509 | return 0; | ||
1510 | err: | ||
1511 | dsi_bus_unlock(dssdev); | ||
1512 | mutex_unlock(&td->lock); | ||
1513 | return r; | ||
1514 | } | ||
1515 | |||
1516 | static bool taal_get_mirror(struct omap_dss_device *dssdev) | ||
1517 | { | ||
1518 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
1519 | int r; | ||
1520 | |||
1521 | mutex_lock(&td->lock); | ||
1522 | r = td->mirror; | ||
1523 | mutex_unlock(&td->lock); | ||
1524 | |||
1525 | return r; | ||
1526 | } | ||
1527 | |||
1528 | static int taal_run_test(struct omap_dss_device *dssdev, int test_num) | 1292 | static int taal_run_test(struct omap_dss_device *dssdev, int test_num) |
1529 | { | 1293 | { |
1530 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1294 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
@@ -1758,10 +1522,6 @@ static struct omap_dss_driver taal_driver = { | |||
1758 | .enable_te = taal_enable_te, | 1522 | .enable_te = taal_enable_te, |
1759 | .get_te = taal_get_te, | 1523 | .get_te = taal_get_te, |
1760 | 1524 | ||
1761 | .set_rotate = taal_rotate, | ||
1762 | .get_rotate = taal_get_rotate, | ||
1763 | .set_mirror = taal_mirror, | ||
1764 | .get_mirror = taal_get_mirror, | ||
1765 | .run_test = taal_run_test, | 1525 | .run_test = taal_run_test, |
1766 | .memory_read = taal_memory_read, | 1526 | .memory_read = taal_memory_read, |
1767 | 1527 | ||
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 8281baafe1ef..a1dba868cef1 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | #include <drm/drm_edid.h> | 25 | #include <drm/drm_edid.h> |
26 | 26 | ||
27 | #include <video/omap-panel-tfp410.h> | 27 | #include <video/omap-panel-data.h> |
28 | 28 | ||
29 | static const struct omap_video_timings tfp410_default_timings = { | 29 | static const struct omap_video_timings tfp410_default_timings = { |
30 | .x_res = 640, | 30 | .x_res = 640, |
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 048c98381ef6..abf2bc4a18ab 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | 19 | ||
20 | #include <video/omapdss.h> | 20 | #include <video/omapdss.h> |
21 | #include <video/omap-panel-data.h> | ||
21 | 22 | ||
22 | #define TPO_R02_MODE(x) ((x) & 7) | 23 | #define TPO_R02_MODE(x) ((x) & 7) |
23 | #define TPO_R02_MODE_800x480 7 | 24 | #define TPO_R02_MODE_800x480 7 |
@@ -278,9 +279,14 @@ static const struct omap_video_timings tpo_td043_timings = { | |||
278 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | 279 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, |
279 | }; | 280 | }; |
280 | 281 | ||
282 | static inline struct panel_tpo_td043_data | ||
283 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
284 | { | ||
285 | return (struct panel_tpo_td043_data *) dssdev->data; | ||
286 | } | ||
287 | |||
281 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | 288 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) |
282 | { | 289 | { |
283 | int nreset_gpio = tpo_td043->nreset_gpio; | ||
284 | int r; | 290 | int r; |
285 | 291 | ||
286 | if (tpo_td043->powered_on) | 292 | if (tpo_td043->powered_on) |
@@ -293,8 +299,8 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | |||
293 | /* wait for panel to stabilize */ | 299 | /* wait for panel to stabilize */ |
294 | msleep(160); | 300 | msleep(160); |
295 | 301 | ||
296 | if (gpio_is_valid(nreset_gpio)) | 302 | if (gpio_is_valid(tpo_td043->nreset_gpio)) |
297 | gpio_set_value(nreset_gpio, 1); | 303 | gpio_set_value(tpo_td043->nreset_gpio, 1); |
298 | 304 | ||
299 | tpo_td043_write(tpo_td043->spi, 2, | 305 | tpo_td043_write(tpo_td043->spi, 2, |
300 | TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING); | 306 | TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING); |
@@ -311,16 +317,14 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | |||
311 | 317 | ||
312 | static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) | 318 | static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) |
313 | { | 319 | { |
314 | int nreset_gpio = tpo_td043->nreset_gpio; | ||
315 | |||
316 | if (!tpo_td043->powered_on) | 320 | if (!tpo_td043->powered_on) |
317 | return; | 321 | return; |
318 | 322 | ||
319 | tpo_td043_write(tpo_td043->spi, 3, | 323 | tpo_td043_write(tpo_td043->spi, 3, |
320 | TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); | 324 | TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); |
321 | 325 | ||
322 | if (gpio_is_valid(nreset_gpio)) | 326 | if (gpio_is_valid(tpo_td043->nreset_gpio)) |
323 | gpio_set_value(nreset_gpio, 0); | 327 | gpio_set_value(tpo_td043->nreset_gpio, 0); |
324 | 328 | ||
325 | /* wait for at least 2 vsyncs before cutting off power */ | 329 | /* wait for at least 2 vsyncs before cutting off power */ |
326 | msleep(50); | 330 | msleep(50); |
@@ -347,12 +351,6 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) | |||
347 | if (r) | 351 | if (r) |
348 | goto err0; | 352 | goto err0; |
349 | 353 | ||
350 | if (dssdev->platform_enable) { | ||
351 | r = dssdev->platform_enable(dssdev); | ||
352 | if (r) | ||
353 | goto err1; | ||
354 | } | ||
355 | |||
356 | /* | 354 | /* |
357 | * If we are resuming from system suspend, SPI clocks might not be | 355 | * If we are resuming from system suspend, SPI clocks might not be |
358 | * enabled yet, so we'll program the LCD from SPI PM resume callback. | 356 | * enabled yet, so we'll program the LCD from SPI PM resume callback. |
@@ -379,9 +377,6 @@ static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) | |||
379 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 377 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
380 | return; | 378 | return; |
381 | 379 | ||
382 | if (dssdev->platform_disable) | ||
383 | dssdev->platform_disable(dssdev); | ||
384 | |||
385 | omapdss_dpi_display_disable(dssdev); | 380 | omapdss_dpi_display_disable(dssdev); |
386 | 381 | ||
387 | if (!tpo_td043->spi_suspended) | 382 | if (!tpo_td043->spi_suspended) |
@@ -407,7 +402,7 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev) | |||
407 | static int tpo_td043_probe(struct omap_dss_device *dssdev) | 402 | static int tpo_td043_probe(struct omap_dss_device *dssdev) |
408 | { | 403 | { |
409 | struct tpo_td043_device *tpo_td043 = g_tpo_td043; | 404 | struct tpo_td043_device *tpo_td043 = g_tpo_td043; |
410 | int nreset_gpio = dssdev->reset_gpio; | 405 | struct panel_tpo_td043_data *pdata = get_panel_data(dssdev); |
411 | int ret = 0; | 406 | int ret = 0; |
412 | 407 | ||
413 | dev_dbg(&dssdev->dev, "probe\n"); | 408 | dev_dbg(&dssdev->dev, "probe\n"); |
@@ -417,6 +412,11 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
417 | return -ENODEV; | 412 | return -ENODEV; |
418 | } | 413 | } |
419 | 414 | ||
415 | if (!pdata) | ||
416 | return -EINVAL; | ||
417 | |||
418 | tpo_td043->nreset_gpio = pdata->nreset_gpio; | ||
419 | |||
420 | dssdev->panel.timings = tpo_td043_timings; | 420 | dssdev->panel.timings = tpo_td043_timings; |
421 | dssdev->ctrl.pixel_size = 24; | 421 | dssdev->ctrl.pixel_size = 24; |
422 | 422 | ||
@@ -430,9 +430,10 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
430 | goto fail_regulator; | 430 | goto fail_regulator; |
431 | } | 431 | } |
432 | 432 | ||
433 | if (gpio_is_valid(nreset_gpio)) { | 433 | if (gpio_is_valid(tpo_td043->nreset_gpio)) { |
434 | ret = gpio_request_one(nreset_gpio, GPIOF_OUT_INIT_LOW, | 434 | ret = devm_gpio_request_one(&dssdev->dev, |
435 | "lcd reset"); | 435 | tpo_td043->nreset_gpio, GPIOF_OUT_INIT_LOW, |
436 | "lcd reset"); | ||
436 | if (ret < 0) { | 437 | if (ret < 0) { |
437 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); | 438 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); |
438 | goto fail_gpio_req; | 439 | goto fail_gpio_req; |
@@ -457,14 +458,11 @@ fail_regulator: | |||
457 | static void tpo_td043_remove(struct omap_dss_device *dssdev) | 458 | static void tpo_td043_remove(struct omap_dss_device *dssdev) |
458 | { | 459 | { |
459 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 460 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); |
460 | int nreset_gpio = dssdev->reset_gpio; | ||
461 | 461 | ||
462 | dev_dbg(&dssdev->dev, "remove\n"); | 462 | dev_dbg(&dssdev->dev, "remove\n"); |
463 | 463 | ||
464 | sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group); | 464 | sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group); |
465 | regulator_put(tpo_td043->vcc_reg); | 465 | regulator_put(tpo_td043->vcc_reg); |
466 | if (gpio_is_valid(nreset_gpio)) | ||
467 | gpio_free(nreset_gpio); | ||
468 | } | 466 | } |
469 | 467 | ||
470 | static void tpo_td043_set_timings(struct omap_dss_device *dssdev, | 468 | static void tpo_td043_set_timings(struct omap_dss_device *dssdev, |
@@ -527,7 +525,6 @@ static int tpo_td043_spi_probe(struct spi_device *spi) | |||
527 | return -ENOMEM; | 525 | return -ENOMEM; |
528 | 526 | ||
529 | tpo_td043->spi = spi; | 527 | tpo_td043->spi = spi; |
530 | tpo_td043->nreset_gpio = dssdev->reset_gpio; | ||
531 | dev_set_drvdata(&spi->dev, tpo_td043); | 528 | dev_set_drvdata(&spi->dev, tpo_td043); |
532 | g_tpo_td043 = tpo_td043; | 529 | g_tpo_td043 = tpo_td043; |
533 | 530 | ||
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index d446bdfc4c82..a4b356a9780d 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c | |||
@@ -435,20 +435,27 @@ static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_man | |||
435 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | 435 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) |
436 | { | 436 | { |
437 | unsigned long timeout = msecs_to_jiffies(500); | 437 | unsigned long timeout = msecs_to_jiffies(500); |
438 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
439 | u32 irq; | 438 | u32 irq; |
440 | int r; | 439 | int r; |
441 | 440 | ||
441 | if (mgr->output == NULL) | ||
442 | return -ENODEV; | ||
443 | |||
442 | r = dispc_runtime_get(); | 444 | r = dispc_runtime_get(); |
443 | if (r) | 445 | if (r) |
444 | return r; | 446 | return r; |
445 | 447 | ||
446 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) | 448 | switch (mgr->output->id) { |
449 | case OMAP_DSS_OUTPUT_VENC: | ||
447 | irq = DISPC_IRQ_EVSYNC_ODD; | 450 | irq = DISPC_IRQ_EVSYNC_ODD; |
448 | else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) | 451 | break; |
452 | case OMAP_DSS_OUTPUT_HDMI: | ||
449 | irq = DISPC_IRQ_EVSYNC_EVEN; | 453 | irq = DISPC_IRQ_EVSYNC_EVEN; |
450 | else | 454 | break; |
455 | default: | ||
451 | irq = dispc_mgr_get_vsync_irq(mgr->id); | 456 | irq = dispc_mgr_get_vsync_irq(mgr->id); |
457 | break; | ||
458 | } | ||
452 | 459 | ||
453 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | 460 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); |
454 | 461 | ||
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index f8779d4750ba..60cc6fee6548 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
@@ -181,10 +181,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) | |||
181 | d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, | 181 | d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, |
182 | write, &dss_debug_fops); | 182 | write, &dss_debug_fops); |
183 | 183 | ||
184 | if (IS_ERR(d)) | 184 | return PTR_RET(d); |
185 | return PTR_ERR(d); | ||
186 | |||
187 | return 0; | ||
188 | } | 185 | } |
189 | #else /* CONFIG_OMAP2_DSS_DEBUGFS */ | 186 | #else /* CONFIG_OMAP2_DSS_DEBUGFS */ |
190 | static inline int dss_initialize_debugfs(void) | 187 | static inline int dss_initialize_debugfs(void) |
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 05ff2b91d9e8..b33b0169bb3b 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -69,6 +69,8 @@ struct dispc_features { | |||
69 | u8 mgr_height_start; | 69 | u8 mgr_height_start; |
70 | u16 mgr_width_max; | 70 | u16 mgr_width_max; |
71 | u16 mgr_height_max; | 71 | u16 mgr_height_max; |
72 | unsigned long max_lcd_pclk; | ||
73 | unsigned long max_tv_pclk; | ||
72 | int (*calc_scaling) (unsigned long pclk, unsigned long lclk, | 74 | int (*calc_scaling) (unsigned long pclk, unsigned long lclk, |
73 | const struct omap_video_timings *mgr_timings, | 75 | const struct omap_video_timings *mgr_timings, |
74 | u16 width, u16 height, u16 out_width, u16 out_height, | 76 | u16 width, u16 height, u16 out_width, u16 out_height, |
@@ -85,6 +87,9 @@ struct dispc_features { | |||
85 | 87 | ||
86 | /* no DISPC_IRQ_FRAMEDONETV on this SoC */ | 88 | /* no DISPC_IRQ_FRAMEDONETV on this SoC */ |
87 | bool no_framedone_tv:1; | 89 | bool no_framedone_tv:1; |
90 | |||
91 | /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */ | ||
92 | bool mstandby_workaround:1; | ||
88 | }; | 93 | }; |
89 | 94 | ||
90 | #define DISPC_MAX_NR_FIFOS 5 | 95 | #define DISPC_MAX_NR_FIFOS 5 |
@@ -97,6 +102,8 @@ static struct { | |||
97 | 102 | ||
98 | int irq; | 103 | int irq; |
99 | 104 | ||
105 | unsigned long core_clk_rate; | ||
106 | |||
100 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; | 107 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; |
101 | /* maps which plane is using a fifo. fifo-id -> plane-id */ | 108 | /* maps which plane is using a fifo. fifo-id -> plane-id */ |
102 | int fifo_assignment[DISPC_MAX_NR_FIFOS]; | 109 | int fifo_assignment[DISPC_MAX_NR_FIFOS]; |
@@ -1584,6 +1591,7 @@ static void dispc_ovl_set_scaling(enum omap_plane plane, | |||
1584 | } | 1591 | } |
1585 | 1592 | ||
1586 | static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, | 1593 | static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, |
1594 | enum omap_dss_rotation_type rotation_type, | ||
1587 | bool mirroring, enum omap_color_mode color_mode) | 1595 | bool mirroring, enum omap_color_mode color_mode) |
1588 | { | 1596 | { |
1589 | bool row_repeat = false; | 1597 | bool row_repeat = false; |
@@ -1634,6 +1642,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, | |||
1634 | if (dss_has_feature(FEAT_ROWREPEATENABLE)) | 1642 | if (dss_has_feature(FEAT_ROWREPEATENABLE)) |
1635 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), | 1643 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), |
1636 | row_repeat ? 1 : 0, 18, 18); | 1644 | row_repeat ? 1 : 0, 18, 18); |
1645 | |||
1646 | if (color_mode == OMAP_DSS_COLOR_NV12) { | ||
1647 | bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) && | ||
1648 | (rotation == OMAP_DSS_ROT_0 || | ||
1649 | rotation == OMAP_DSS_ROT_180); | ||
1650 | /* DOUBLESTRIDE */ | ||
1651 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22); | ||
1652 | } | ||
1653 | |||
1637 | } | 1654 | } |
1638 | 1655 | ||
1639 | static int color_mode_to_bpp(enum omap_color_mode color_mode) | 1656 | static int color_mode_to_bpp(enum omap_color_mode color_mode) |
@@ -2512,7 +2529,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
2512 | dispc_ovl_set_vid_color_conv(plane, cconv); | 2529 | dispc_ovl_set_vid_color_conv(plane, cconv); |
2513 | } | 2530 | } |
2514 | 2531 | ||
2515 | dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); | 2532 | dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror, |
2533 | color_mode); | ||
2516 | 2534 | ||
2517 | dispc_ovl_set_zorder(plane, caps, zorder); | 2535 | dispc_ovl_set_zorder(plane, caps, zorder); |
2518 | dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); | 2536 | dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); |
@@ -2823,6 +2841,15 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, | |||
2823 | return true; | 2841 | return true; |
2824 | } | 2842 | } |
2825 | 2843 | ||
2844 | static bool _dispc_mgr_pclk_ok(enum omap_channel channel, | ||
2845 | unsigned long pclk) | ||
2846 | { | ||
2847 | if (dss_mgr_is_lcd(channel)) | ||
2848 | return pclk <= dispc.feat->max_lcd_pclk ? true : false; | ||
2849 | else | ||
2850 | return pclk <= dispc.feat->max_tv_pclk ? true : false; | ||
2851 | } | ||
2852 | |||
2826 | bool dispc_mgr_timings_ok(enum omap_channel channel, | 2853 | bool dispc_mgr_timings_ok(enum omap_channel channel, |
2827 | const struct omap_video_timings *timings) | 2854 | const struct omap_video_timings *timings) |
2828 | { | 2855 | { |
@@ -2830,11 +2857,13 @@ bool dispc_mgr_timings_ok(enum omap_channel channel, | |||
2830 | 2857 | ||
2831 | timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); | 2858 | timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); |
2832 | 2859 | ||
2833 | if (dss_mgr_is_lcd(channel)) | 2860 | timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixel_clock * 1000); |
2834 | timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw, | 2861 | |
2835 | timings->hfp, timings->hbp, | 2862 | if (dss_mgr_is_lcd(channel)) { |
2836 | timings->vsw, timings->vfp, | 2863 | timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp, |
2837 | timings->vbp); | 2864 | timings->hbp, timings->vsw, timings->vfp, |
2865 | timings->vbp); | ||
2866 | } | ||
2838 | 2867 | ||
2839 | return timings_ok; | 2868 | return timings_ok; |
2840 | } | 2869 | } |
@@ -2951,6 +2980,10 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, | |||
2951 | 2980 | ||
2952 | dispc_write_reg(DISPC_DIVISORo(channel), | 2981 | dispc_write_reg(DISPC_DIVISORo(channel), |
2953 | FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); | 2982 | FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); |
2983 | |||
2984 | if (dss_has_feature(FEAT_CORE_CLK_DIV) == false && | ||
2985 | channel == OMAP_DSS_CHANNEL_LCD) | ||
2986 | dispc.core_clk_rate = dispc_fclk_rate() / lck_div; | ||
2954 | } | 2987 | } |
2955 | 2988 | ||
2956 | static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, | 2989 | static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, |
@@ -3056,15 +3089,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) | |||
3056 | 3089 | ||
3057 | unsigned long dispc_core_clk_rate(void) | 3090 | unsigned long dispc_core_clk_rate(void) |
3058 | { | 3091 | { |
3059 | int lcd; | 3092 | return dispc.core_clk_rate; |
3060 | unsigned long fclk = dispc_fclk_rate(); | ||
3061 | |||
3062 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | ||
3063 | lcd = REG_GET(DISPC_DIVISOR, 23, 16); | ||
3064 | else | ||
3065 | lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16); | ||
3066 | |||
3067 | return fclk / lcd; | ||
3068 | } | 3093 | } |
3069 | 3094 | ||
3070 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) | 3095 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) |
@@ -3313,67 +3338,79 @@ static void dispc_dump_regs(struct seq_file *s) | |||
3313 | #undef DUMPREG | 3338 | #undef DUMPREG |
3314 | } | 3339 | } |
3315 | 3340 | ||
3316 | /* with fck as input clock rate, find dispc dividers that produce req_pck */ | 3341 | /* calculate clock rates using dividers in cinfo */ |
3317 | void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, | 3342 | int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, |
3318 | struct dispc_clock_info *cinfo) | 3343 | struct dispc_clock_info *cinfo) |
3319 | { | 3344 | { |
3320 | u16 pcd_min, pcd_max; | 3345 | if (cinfo->lck_div > 255 || cinfo->lck_div == 0) |
3321 | unsigned long best_pck; | 3346 | return -EINVAL; |
3322 | u16 best_ld, cur_ld; | 3347 | if (cinfo->pck_div < 1 || cinfo->pck_div > 255) |
3323 | u16 best_pd, cur_pd; | 3348 | return -EINVAL; |
3324 | 3349 | ||
3325 | pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); | 3350 | cinfo->lck = dispc_fclk_rate / cinfo->lck_div; |
3326 | pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); | 3351 | cinfo->pck = cinfo->lck / cinfo->pck_div; |
3327 | 3352 | ||
3328 | best_pck = 0; | 3353 | return 0; |
3329 | best_ld = 0; | 3354 | } |
3330 | best_pd = 0; | ||
3331 | 3355 | ||
3332 | for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { | 3356 | bool dispc_div_calc(unsigned long dispc, |
3333 | unsigned long lck = fck / cur_ld; | 3357 | unsigned long pck_min, unsigned long pck_max, |
3358 | dispc_div_calc_func func, void *data) | ||
3359 | { | ||
3360 | int lckd, lckd_start, lckd_stop; | ||
3361 | int pckd, pckd_start, pckd_stop; | ||
3362 | unsigned long pck, lck; | ||
3363 | unsigned long lck_max; | ||
3364 | unsigned long pckd_hw_min, pckd_hw_max; | ||
3365 | unsigned min_fck_per_pck; | ||
3366 | unsigned long fck; | ||
3334 | 3367 | ||
3335 | for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) { | 3368 | #ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK |
3336 | unsigned long pck = lck / cur_pd; | 3369 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; |
3337 | long old_delta = abs(best_pck - req_pck); | 3370 | #else |
3338 | long new_delta = abs(pck - req_pck); | 3371 | min_fck_per_pck = 0; |
3372 | #endif | ||
3339 | 3373 | ||
3340 | if (best_pck == 0 || new_delta < old_delta) { | 3374 | pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); |
3341 | best_pck = pck; | 3375 | pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); |
3342 | best_ld = cur_ld; | ||
3343 | best_pd = cur_pd; | ||
3344 | 3376 | ||
3345 | if (pck == req_pck) | 3377 | lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); |
3346 | goto found; | ||
3347 | } | ||
3348 | 3378 | ||
3349 | if (pck < req_pck) | 3379 | pck_min = pck_min ? pck_min : 1; |
3350 | break; | 3380 | pck_max = pck_max ? pck_max : ULONG_MAX; |
3351 | } | ||
3352 | 3381 | ||
3353 | if (lck / pcd_min < req_pck) | 3382 | lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul); |
3354 | break; | 3383 | lckd_stop = min(dispc / pck_min, 255ul); |
3355 | } | ||
3356 | 3384 | ||
3357 | found: | 3385 | for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) { |
3358 | cinfo->lck_div = best_ld; | 3386 | lck = dispc / lckd; |
3359 | cinfo->pck_div = best_pd; | ||
3360 | cinfo->lck = fck / cinfo->lck_div; | ||
3361 | cinfo->pck = cinfo->lck / cinfo->pck_div; | ||
3362 | } | ||
3363 | 3387 | ||
3364 | /* calculate clock rates using dividers in cinfo */ | 3388 | pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min); |
3365 | int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | 3389 | pckd_stop = min(lck / pck_min, pckd_hw_max); |
3366 | struct dispc_clock_info *cinfo) | ||
3367 | { | ||
3368 | if (cinfo->lck_div > 255 || cinfo->lck_div == 0) | ||
3369 | return -EINVAL; | ||
3370 | if (cinfo->pck_div < 1 || cinfo->pck_div > 255) | ||
3371 | return -EINVAL; | ||
3372 | 3390 | ||
3373 | cinfo->lck = dispc_fclk_rate / cinfo->lck_div; | 3391 | for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) { |
3374 | cinfo->pck = cinfo->lck / cinfo->pck_div; | 3392 | pck = lck / pckd; |
3375 | 3393 | ||
3376 | return 0; | 3394 | /* |
3395 | * For OMAP2/3 the DISPC fclk is the same as LCD's logic | ||
3396 | * clock, which means we're configuring DISPC fclk here | ||
3397 | * also. Thus we need to use the calculated lck. For | ||
3398 | * OMAP4+ the DISPC fclk is a separate clock. | ||
3399 | */ | ||
3400 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | ||
3401 | fck = dispc_core_clk_rate(); | ||
3402 | else | ||
3403 | fck = lck; | ||
3404 | |||
3405 | if (fck < pck * min_fck_per_pck) | ||
3406 | continue; | ||
3407 | |||
3408 | if (func(lckd, pckd, lck, pck, data)) | ||
3409 | return true; | ||
3410 | } | ||
3411 | } | ||
3412 | |||
3413 | return false; | ||
3377 | } | 3414 | } |
3378 | 3415 | ||
3379 | void dispc_mgr_set_clock_div(enum omap_channel channel, | 3416 | void dispc_mgr_set_clock_div(enum omap_channel channel, |
@@ -3451,6 +3488,8 @@ static void _omap_dispc_initial_config(void) | |||
3451 | l = FLD_MOD(l, 1, 0, 0); | 3488 | l = FLD_MOD(l, 1, 0, 0); |
3452 | l = FLD_MOD(l, 1, 23, 16); | 3489 | l = FLD_MOD(l, 1, 23, 16); |
3453 | dispc_write_reg(DISPC_DIVISOR, l); | 3490 | dispc_write_reg(DISPC_DIVISOR, l); |
3491 | |||
3492 | dispc.core_clk_rate = dispc_fclk_rate(); | ||
3454 | } | 3493 | } |
3455 | 3494 | ||
3456 | /* FUNCGATED */ | 3495 | /* FUNCGATED */ |
@@ -3466,6 +3505,9 @@ static void _omap_dispc_initial_config(void) | |||
3466 | dispc_configure_burst_sizes(); | 3505 | dispc_configure_burst_sizes(); |
3467 | 3506 | ||
3468 | dispc_ovl_enable_zorder_planes(); | 3507 | dispc_ovl_enable_zorder_planes(); |
3508 | |||
3509 | if (dispc.feat->mstandby_workaround) | ||
3510 | REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0); | ||
3469 | } | 3511 | } |
3470 | 3512 | ||
3471 | static const struct dispc_features omap24xx_dispc_feats __initconst = { | 3513 | static const struct dispc_features omap24xx_dispc_feats __initconst = { |
@@ -3479,6 +3521,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = { | |||
3479 | .mgr_height_start = 26, | 3521 | .mgr_height_start = 26, |
3480 | .mgr_width_max = 2048, | 3522 | .mgr_width_max = 2048, |
3481 | .mgr_height_max = 2048, | 3523 | .mgr_height_max = 2048, |
3524 | .max_lcd_pclk = 66500000, | ||
3482 | .calc_scaling = dispc_ovl_calc_scaling_24xx, | 3525 | .calc_scaling = dispc_ovl_calc_scaling_24xx, |
3483 | .calc_core_clk = calc_core_clk_24xx, | 3526 | .calc_core_clk = calc_core_clk_24xx, |
3484 | .num_fifos = 3, | 3527 | .num_fifos = 3, |
@@ -3496,6 +3539,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { | |||
3496 | .mgr_height_start = 26, | 3539 | .mgr_height_start = 26, |
3497 | .mgr_width_max = 2048, | 3540 | .mgr_width_max = 2048, |
3498 | .mgr_height_max = 2048, | 3541 | .mgr_height_max = 2048, |
3542 | .max_lcd_pclk = 173000000, | ||
3543 | .max_tv_pclk = 59000000, | ||
3499 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | 3544 | .calc_scaling = dispc_ovl_calc_scaling_34xx, |
3500 | .calc_core_clk = calc_core_clk_34xx, | 3545 | .calc_core_clk = calc_core_clk_34xx, |
3501 | .num_fifos = 3, | 3546 | .num_fifos = 3, |
@@ -3513,6 +3558,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { | |||
3513 | .mgr_height_start = 26, | 3558 | .mgr_height_start = 26, |
3514 | .mgr_width_max = 2048, | 3559 | .mgr_width_max = 2048, |
3515 | .mgr_height_max = 2048, | 3560 | .mgr_height_max = 2048, |
3561 | .max_lcd_pclk = 173000000, | ||
3562 | .max_tv_pclk = 59000000, | ||
3516 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | 3563 | .calc_scaling = dispc_ovl_calc_scaling_34xx, |
3517 | .calc_core_clk = calc_core_clk_34xx, | 3564 | .calc_core_clk = calc_core_clk_34xx, |
3518 | .num_fifos = 3, | 3565 | .num_fifos = 3, |
@@ -3530,6 +3577,8 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { | |||
3530 | .mgr_height_start = 26, | 3577 | .mgr_height_start = 26, |
3531 | .mgr_width_max = 2048, | 3578 | .mgr_width_max = 2048, |
3532 | .mgr_height_max = 2048, | 3579 | .mgr_height_max = 2048, |
3580 | .max_lcd_pclk = 170000000, | ||
3581 | .max_tv_pclk = 185625000, | ||
3533 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | 3582 | .calc_scaling = dispc_ovl_calc_scaling_44xx, |
3534 | .calc_core_clk = calc_core_clk_44xx, | 3583 | .calc_core_clk = calc_core_clk_44xx, |
3535 | .num_fifos = 5, | 3584 | .num_fifos = 5, |
@@ -3547,10 +3596,13 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = { | |||
3547 | .mgr_height_start = 27, | 3596 | .mgr_height_start = 27, |
3548 | .mgr_width_max = 4096, | 3597 | .mgr_width_max = 4096, |
3549 | .mgr_height_max = 4096, | 3598 | .mgr_height_max = 4096, |
3599 | .max_lcd_pclk = 170000000, | ||
3600 | .max_tv_pclk = 186000000, | ||
3550 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | 3601 | .calc_scaling = dispc_ovl_calc_scaling_44xx, |
3551 | .calc_core_clk = calc_core_clk_44xx, | 3602 | .calc_core_clk = calc_core_clk_44xx, |
3552 | .num_fifos = 5, | 3603 | .num_fifos = 5, |
3553 | .gfx_fifo_workaround = true, | 3604 | .gfx_fifo_workaround = true, |
3605 | .mstandby_workaround = true, | ||
3554 | }; | 3606 | }; |
3555 | 3607 | ||
3556 | static int __init dispc_init_features(struct platform_device *pdev) | 3608 | static int __init dispc_init_features(struct platform_device *pdev) |
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 222363c6e623..de4863d21ab7 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h | |||
@@ -39,6 +39,7 @@ | |||
39 | #define DISPC_GLOBAL_BUFFER 0x0800 | 39 | #define DISPC_GLOBAL_BUFFER 0x0800 |
40 | #define DISPC_CONTROL3 0x0848 | 40 | #define DISPC_CONTROL3 0x0848 |
41 | #define DISPC_CONFIG3 0x084C | 41 | #define DISPC_CONFIG3 0x084C |
42 | #define DISPC_MSTANDBY_CTRL 0x0858 | ||
42 | 43 | ||
43 | /* DISPC overlay registers */ | 44 | /* DISPC overlay registers */ |
44 | #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ | 45 | #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ |
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 4af136a04e53..e93c4debea7f 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
@@ -63,15 +63,29 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) | |||
63 | case OMAPDSS_VER_OMAP3630: | 63 | case OMAPDSS_VER_OMAP3630: |
64 | case OMAPDSS_VER_AM35xx: | 64 | case OMAPDSS_VER_AM35xx: |
65 | return NULL; | 65 | return NULL; |
66 | default: | ||
67 | break; | ||
68 | } | ||
69 | 66 | ||
70 | switch (channel) { | 67 | case OMAPDSS_VER_OMAP4430_ES1: |
71 | case OMAP_DSS_CHANNEL_LCD: | 68 | case OMAPDSS_VER_OMAP4430_ES2: |
72 | return dsi_get_dsidev_from_id(0); | 69 | case OMAPDSS_VER_OMAP4: |
73 | case OMAP_DSS_CHANNEL_LCD2: | 70 | switch (channel) { |
74 | return dsi_get_dsidev_from_id(1); | 71 | case OMAP_DSS_CHANNEL_LCD: |
72 | return dsi_get_dsidev_from_id(0); | ||
73 | case OMAP_DSS_CHANNEL_LCD2: | ||
74 | return dsi_get_dsidev_from_id(1); | ||
75 | default: | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | case OMAPDSS_VER_OMAP5: | ||
80 | switch (channel) { | ||
81 | case OMAP_DSS_CHANNEL_LCD: | ||
82 | return dsi_get_dsidev_from_id(0); | ||
83 | case OMAP_DSS_CHANNEL_LCD3: | ||
84 | return dsi_get_dsidev_from_id(1); | ||
85 | default: | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
75 | default: | 89 | default: |
76 | return NULL; | 90 | return NULL; |
77 | } | 91 | } |
@@ -91,75 +105,211 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) | |||
91 | } | 105 | } |
92 | } | 106 | } |
93 | 107 | ||
94 | static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | 108 | struct dpi_clk_calc_ctx { |
109 | struct platform_device *dsidev; | ||
110 | |||
111 | /* inputs */ | ||
112 | |||
113 | unsigned long pck_min, pck_max; | ||
114 | |||
115 | /* outputs */ | ||
116 | |||
117 | struct dsi_clock_info dsi_cinfo; | ||
118 | struct dss_clock_info dss_cinfo; | ||
119 | struct dispc_clock_info dispc_cinfo; | ||
120 | }; | ||
121 | |||
122 | static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | ||
123 | unsigned long pck, void *data) | ||
124 | { | ||
125 | struct dpi_clk_calc_ctx *ctx = data; | ||
126 | |||
127 | /* | ||
128 | * Odd dividers give us uneven duty cycle, causing problem when level | ||
129 | * shifted. So skip all odd dividers when the pixel clock is on the | ||
130 | * higher side. | ||
131 | */ | ||
132 | if (ctx->pck_min >= 1000000) { | ||
133 | if (lckd > 1 && lckd % 2 != 0) | ||
134 | return false; | ||
135 | |||
136 | if (pckd > 1 && pckd % 2 != 0) | ||
137 | return false; | ||
138 | } | ||
139 | |||
140 | ctx->dispc_cinfo.lck_div = lckd; | ||
141 | ctx->dispc_cinfo.pck_div = pckd; | ||
142 | ctx->dispc_cinfo.lck = lck; | ||
143 | ctx->dispc_cinfo.pck = pck; | ||
144 | |||
145 | return true; | ||
146 | } | ||
147 | |||
148 | |||
149 | static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | ||
150 | void *data) | ||
151 | { | ||
152 | struct dpi_clk_calc_ctx *ctx = data; | ||
153 | |||
154 | /* | ||
155 | * Odd dividers give us uneven duty cycle, causing problem when level | ||
156 | * shifted. So skip all odd dividers when the pixel clock is on the | ||
157 | * higher side. | ||
158 | */ | ||
159 | if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000) | ||
160 | return false; | ||
161 | |||
162 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | ||
163 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | ||
164 | |||
165 | return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, | ||
166 | dpi_calc_dispc_cb, ctx); | ||
167 | } | ||
168 | |||
169 | |||
170 | static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint, | ||
171 | unsigned long pll, | ||
172 | void *data) | ||
173 | { | ||
174 | struct dpi_clk_calc_ctx *ctx = data; | ||
175 | |||
176 | ctx->dsi_cinfo.regn = regn; | ||
177 | ctx->dsi_cinfo.regm = regm; | ||
178 | ctx->dsi_cinfo.fint = fint; | ||
179 | ctx->dsi_cinfo.clkin4ddr = pll; | ||
180 | |||
181 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min, | ||
182 | dpi_calc_hsdiv_cb, ctx); | ||
183 | } | ||
184 | |||
185 | static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data) | ||
186 | { | ||
187 | struct dpi_clk_calc_ctx *ctx = data; | ||
188 | |||
189 | ctx->dss_cinfo.fck = fck; | ||
190 | ctx->dss_cinfo.fck_div = fckd; | ||
191 | |||
192 | return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, | ||
193 | dpi_calc_dispc_cb, ctx); | ||
194 | } | ||
195 | |||
196 | static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) | ||
197 | { | ||
198 | unsigned long clkin; | ||
199 | unsigned long pll_min, pll_max; | ||
200 | |||
201 | clkin = dsi_get_pll_clkin(dpi.dsidev); | ||
202 | |||
203 | memset(ctx, 0, sizeof(*ctx)); | ||
204 | ctx->dsidev = dpi.dsidev; | ||
205 | ctx->pck_min = pck - 1000; | ||
206 | ctx->pck_max = pck + 1000; | ||
207 | ctx->dsi_cinfo.clkin = clkin; | ||
208 | |||
209 | pll_min = 0; | ||
210 | pll_max = 0; | ||
211 | |||
212 | return dsi_pll_calc(dpi.dsidev, clkin, | ||
213 | pll_min, pll_max, | ||
214 | dpi_calc_pll_cb, ctx); | ||
215 | } | ||
216 | |||
217 | static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) | ||
218 | { | ||
219 | int i; | ||
220 | |||
221 | /* | ||
222 | * DSS fck gives us very few possibilities, so finding a good pixel | ||
223 | * clock may not be possible. We try multiple times to find the clock, | ||
224 | * each time widening the pixel clock range we look for, up to | ||
225 | * +/- ~15MHz. | ||
226 | */ | ||
227 | |||
228 | for (i = 0; i < 25; ++i) { | ||
229 | bool ok; | ||
230 | |||
231 | memset(ctx, 0, sizeof(*ctx)); | ||
232 | if (pck > 1000 * i * i * i) | ||
233 | ctx->pck_min = max(pck - 1000 * i * i * i, 0lu); | ||
234 | else | ||
235 | ctx->pck_min = 0; | ||
236 | ctx->pck_max = pck + 1000 * i * i * i; | ||
237 | |||
238 | ok = dss_div_calc(ctx->pck_min, dpi_calc_dss_cb, ctx); | ||
239 | if (ok) | ||
240 | return ok; | ||
241 | } | ||
242 | |||
243 | return false; | ||
244 | } | ||
245 | |||
246 | |||
247 | |||
248 | static int dpi_set_dsi_clk(enum omap_channel channel, | ||
95 | unsigned long pck_req, unsigned long *fck, int *lck_div, | 249 | unsigned long pck_req, unsigned long *fck, int *lck_div, |
96 | int *pck_div) | 250 | int *pck_div) |
97 | { | 251 | { |
98 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 252 | struct dpi_clk_calc_ctx ctx; |
99 | struct dsi_clock_info dsi_cinfo; | ||
100 | struct dispc_clock_info dispc_cinfo; | ||
101 | int r; | 253 | int r; |
254 | bool ok; | ||
102 | 255 | ||
103 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo, | 256 | ok = dpi_dsi_clk_calc(pck_req, &ctx); |
104 | &dispc_cinfo); | 257 | if (!ok) |
105 | if (r) | 258 | return -EINVAL; |
106 | return r; | ||
107 | 259 | ||
108 | r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo); | 260 | r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo); |
109 | if (r) | 261 | if (r) |
110 | return r; | 262 | return r; |
111 | 263 | ||
112 | dss_select_lcd_clk_source(mgr->id, | 264 | dss_select_lcd_clk_source(channel, |
113 | dpi_get_alt_clk_src(mgr->id)); | 265 | dpi_get_alt_clk_src(channel)); |
114 | 266 | ||
115 | dpi.mgr_config.clock_info = dispc_cinfo; | 267 | dpi.mgr_config.clock_info = ctx.dispc_cinfo; |
116 | 268 | ||
117 | *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; | 269 | *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; |
118 | *lck_div = dispc_cinfo.lck_div; | 270 | *lck_div = ctx.dispc_cinfo.lck_div; |
119 | *pck_div = dispc_cinfo.pck_div; | 271 | *pck_div = ctx.dispc_cinfo.pck_div; |
120 | 272 | ||
121 | return 0; | 273 | return 0; |
122 | } | 274 | } |
123 | 275 | ||
124 | static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, | 276 | static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, |
125 | unsigned long pck_req, unsigned long *fck, int *lck_div, | 277 | int *lck_div, int *pck_div) |
126 | int *pck_div) | ||
127 | { | 278 | { |
128 | struct dss_clock_info dss_cinfo; | 279 | struct dpi_clk_calc_ctx ctx; |
129 | struct dispc_clock_info dispc_cinfo; | ||
130 | int r; | 280 | int r; |
281 | bool ok; | ||
131 | 282 | ||
132 | r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo); | 283 | ok = dpi_dss_clk_calc(pck_req, &ctx); |
133 | if (r) | 284 | if (!ok) |
134 | return r; | 285 | return -EINVAL; |
135 | 286 | ||
136 | r = dss_set_clock_div(&dss_cinfo); | 287 | r = dss_set_clock_div(&ctx.dss_cinfo); |
137 | if (r) | 288 | if (r) |
138 | return r; | 289 | return r; |
139 | 290 | ||
140 | dpi.mgr_config.clock_info = dispc_cinfo; | 291 | dpi.mgr_config.clock_info = ctx.dispc_cinfo; |
141 | 292 | ||
142 | *fck = dss_cinfo.fck; | 293 | *fck = ctx.dss_cinfo.fck; |
143 | *lck_div = dispc_cinfo.lck_div; | 294 | *lck_div = ctx.dispc_cinfo.lck_div; |
144 | *pck_div = dispc_cinfo.pck_div; | 295 | *pck_div = ctx.dispc_cinfo.pck_div; |
145 | 296 | ||
146 | return 0; | 297 | return 0; |
147 | } | 298 | } |
148 | 299 | ||
149 | static int dpi_set_mode(struct omap_dss_device *dssdev) | 300 | static int dpi_set_mode(struct omap_overlay_manager *mgr) |
150 | { | 301 | { |
151 | struct omap_video_timings *t = &dpi.timings; | 302 | struct omap_video_timings *t = &dpi.timings; |
152 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
153 | int lck_div = 0, pck_div = 0; | 303 | int lck_div = 0, pck_div = 0; |
154 | unsigned long fck = 0; | 304 | unsigned long fck = 0; |
155 | unsigned long pck; | 305 | unsigned long pck; |
156 | int r = 0; | 306 | int r = 0; |
157 | 307 | ||
158 | if (dpi.dsidev) | 308 | if (dpi.dsidev) |
159 | r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, | 309 | r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck, |
160 | &lck_div, &pck_div); | 310 | &lck_div, &pck_div); |
161 | else | 311 | else |
162 | r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck, | 312 | r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck, |
163 | &lck_div, &pck_div); | 313 | &lck_div, &pck_div); |
164 | if (r) | 314 | if (r) |
165 | return r; | 315 | return r; |
@@ -179,10 +329,8 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) | |||
179 | return 0; | 329 | return 0; |
180 | } | 330 | } |
181 | 331 | ||
182 | static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) | 332 | static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) |
183 | { | 333 | { |
184 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
185 | |||
186 | dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 334 | dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; |
187 | 335 | ||
188 | dpi.mgr_config.stallmode = false; | 336 | dpi.mgr_config.stallmode = false; |
@@ -197,7 +345,7 @@ static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) | |||
197 | 345 | ||
198 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | 346 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) |
199 | { | 347 | { |
200 | struct omap_dss_output *out = dssdev->output; | 348 | struct omap_dss_output *out = &dpi.output; |
201 | int r; | 349 | int r; |
202 | 350 | ||
203 | mutex_lock(&dpi.lock); | 351 | mutex_lock(&dpi.lock); |
@@ -230,7 +378,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
230 | if (r) | 378 | if (r) |
231 | goto err_get_dispc; | 379 | goto err_get_dispc; |
232 | 380 | ||
233 | r = dss_dpi_select_source(dssdev->channel); | 381 | r = dss_dpi_select_source(out->manager->id); |
234 | if (r) | 382 | if (r) |
235 | goto err_src_sel; | 383 | goto err_src_sel; |
236 | 384 | ||
@@ -244,11 +392,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
244 | goto err_dsi_pll_init; | 392 | goto err_dsi_pll_init; |
245 | } | 393 | } |
246 | 394 | ||
247 | r = dpi_set_mode(dssdev); | 395 | r = dpi_set_mode(out->manager); |
248 | if (r) | 396 | if (r) |
249 | goto err_set_mode; | 397 | goto err_set_mode; |
250 | 398 | ||
251 | dpi_config_lcd_manager(dssdev); | 399 | dpi_config_lcd_manager(out->manager); |
252 | 400 | ||
253 | mdelay(2); | 401 | mdelay(2); |
254 | 402 | ||
@@ -285,7 +433,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable); | |||
285 | 433 | ||
286 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | 434 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) |
287 | { | 435 | { |
288 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 436 | struct omap_overlay_manager *mgr = dpi.output.manager; |
289 | 437 | ||
290 | mutex_lock(&dpi.lock); | 438 | mutex_lock(&dpi.lock); |
291 | 439 | ||
@@ -324,12 +472,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings); | |||
324 | int dpi_check_timings(struct omap_dss_device *dssdev, | 472 | int dpi_check_timings(struct omap_dss_device *dssdev, |
325 | struct omap_video_timings *timings) | 473 | struct omap_video_timings *timings) |
326 | { | 474 | { |
327 | int r; | 475 | struct omap_overlay_manager *mgr = dpi.output.manager; |
328 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
329 | int lck_div, pck_div; | 476 | int lck_div, pck_div; |
330 | unsigned long fck; | 477 | unsigned long fck; |
331 | unsigned long pck; | 478 | unsigned long pck; |
332 | struct dispc_clock_info dispc_cinfo; | 479 | struct dpi_clk_calc_ctx ctx; |
480 | bool ok; | ||
333 | 481 | ||
334 | if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) | 482 | if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) |
335 | return -EINVAL; | 483 | return -EINVAL; |
@@ -338,28 +486,21 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
338 | return -EINVAL; | 486 | return -EINVAL; |
339 | 487 | ||
340 | if (dpi.dsidev) { | 488 | if (dpi.dsidev) { |
341 | struct dsi_clock_info dsi_cinfo; | 489 | ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx); |
342 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, | 490 | if (!ok) |
343 | timings->pixel_clock * 1000, | 491 | return -EINVAL; |
344 | &dsi_cinfo, &dispc_cinfo); | ||
345 | |||
346 | if (r) | ||
347 | return r; | ||
348 | 492 | ||
349 | fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; | 493 | fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; |
350 | } else { | 494 | } else { |
351 | struct dss_clock_info dss_cinfo; | 495 | ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx); |
352 | r = dss_calc_clock_div(timings->pixel_clock * 1000, | 496 | if (!ok) |
353 | &dss_cinfo, &dispc_cinfo); | 497 | return -EINVAL; |
354 | 498 | ||
355 | if (r) | 499 | fck = ctx.dss_cinfo.fck; |
356 | return r; | ||
357 | |||
358 | fck = dss_cinfo.fck; | ||
359 | } | 500 | } |
360 | 501 | ||
361 | lck_div = dispc_cinfo.lck_div; | 502 | lck_div = ctx.dispc_cinfo.lck_div; |
362 | pck_div = dispc_cinfo.pck_div; | 503 | pck_div = ctx.dispc_cinfo.pck_div; |
363 | 504 | ||
364 | pck = fck / lck_div / pck_div / 1000; | 505 | pck = fck / lck_div / pck_div / 1000; |
365 | 506 | ||
@@ -401,6 +542,36 @@ static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) | |||
401 | return 0; | 542 | return 0; |
402 | } | 543 | } |
403 | 544 | ||
545 | /* | ||
546 | * Return a hardcoded channel for the DPI output. This should work for | ||
547 | * current use cases, but this can be later expanded to either resolve | ||
548 | * the channel in some more dynamic manner, or get the channel as a user | ||
549 | * parameter. | ||
550 | */ | ||
551 | static enum omap_channel dpi_get_channel(void) | ||
552 | { | ||
553 | switch (omapdss_get_version()) { | ||
554 | case OMAPDSS_VER_OMAP24xx: | ||
555 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
556 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
557 | case OMAPDSS_VER_OMAP3630: | ||
558 | case OMAPDSS_VER_AM35xx: | ||
559 | return OMAP_DSS_CHANNEL_LCD; | ||
560 | |||
561 | case OMAPDSS_VER_OMAP4430_ES1: | ||
562 | case OMAPDSS_VER_OMAP4430_ES2: | ||
563 | case OMAPDSS_VER_OMAP4: | ||
564 | return OMAP_DSS_CHANNEL_LCD2; | ||
565 | |||
566 | case OMAPDSS_VER_OMAP5: | ||
567 | return OMAP_DSS_CHANNEL_LCD3; | ||
568 | |||
569 | default: | ||
570 | DSSWARN("unsupported DSS version\n"); | ||
571 | return OMAP_DSS_CHANNEL_LCD; | ||
572 | } | ||
573 | } | ||
574 | |||
404 | static int __init dpi_init_display(struct omap_dss_device *dssdev) | 575 | static int __init dpi_init_display(struct omap_dss_device *dssdev) |
405 | { | 576 | { |
406 | struct platform_device *dsidev; | 577 | struct platform_device *dsidev; |
@@ -421,12 +592,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) | |||
421 | dpi.vdds_dsi_reg = vdds_dsi; | 592 | dpi.vdds_dsi_reg = vdds_dsi; |
422 | } | 593 | } |
423 | 594 | ||
424 | /* | 595 | dsidev = dpi_get_dsidev(dpi.output.dispc_channel); |
425 | * XXX We shouldn't need dssdev->channel for this. The dsi pll clock | ||
426 | * source for DPI is SoC integration detail, not something that should | ||
427 | * be configured in the dssdev | ||
428 | */ | ||
429 | dsidev = dpi_get_dsidev(dssdev->channel); | ||
430 | 596 | ||
431 | if (dsidev && dpi_verify_dsi_pll(dsidev)) { | 597 | if (dsidev && dpi_verify_dsi_pll(dsidev)) { |
432 | dsidev = NULL; | 598 | dsidev = NULL; |
@@ -517,6 +683,8 @@ static void __init dpi_init_output(struct platform_device *pdev) | |||
517 | out->pdev = pdev; | 683 | out->pdev = pdev; |
518 | out->id = OMAP_DSS_OUTPUT_DPI; | 684 | out->id = OMAP_DSS_OUTPUT_DPI; |
519 | out->type = OMAP_DISPLAY_TYPE_DPI; | 685 | out->type = OMAP_DISPLAY_TYPE_DPI; |
686 | out->name = "dpi.0"; | ||
687 | out->dispc_channel = dpi_get_channel(); | ||
520 | 688 | ||
521 | dss_register_output(out); | 689 | dss_register_output(out); |
522 | } | 690 | } |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 28d41d16b7be..9b1c5ecee115 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -200,6 +200,11 @@ struct dsi_reg { u16 idx; }; | |||
200 | 200 | ||
201 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); | 201 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); |
202 | 202 | ||
203 | static int dsi_display_init_dispc(struct platform_device *dsidev, | ||
204 | struct omap_overlay_manager *mgr); | ||
205 | static void dsi_display_uninit_dispc(struct platform_device *dsidev, | ||
206 | struct omap_overlay_manager *mgr); | ||
207 | |||
203 | #define DSI_MAX_NR_ISRS 2 | 208 | #define DSI_MAX_NR_ISRS 2 |
204 | #define DSI_MAX_NR_LANES 5 | 209 | #define DSI_MAX_NR_LANES 5 |
205 | 210 | ||
@@ -250,6 +255,24 @@ struct dsi_isr_tables { | |||
250 | struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS]; | 255 | struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS]; |
251 | }; | 256 | }; |
252 | 257 | ||
258 | struct dsi_clk_calc_ctx { | ||
259 | struct platform_device *dsidev; | ||
260 | |||
261 | /* inputs */ | ||
262 | |||
263 | const struct omap_dss_dsi_config *config; | ||
264 | |||
265 | unsigned long req_pck_min, req_pck_nom, req_pck_max; | ||
266 | |||
267 | /* outputs */ | ||
268 | |||
269 | struct dsi_clock_info dsi_cinfo; | ||
270 | struct dispc_clock_info dispc_cinfo; | ||
271 | |||
272 | struct omap_video_timings dispc_vm; | ||
273 | struct omap_dss_dsi_videomode_timings dsi_vm; | ||
274 | }; | ||
275 | |||
253 | struct dsi_data { | 276 | struct dsi_data { |
254 | struct platform_device *pdev; | 277 | struct platform_device *pdev; |
255 | void __iomem *base; | 278 | void __iomem *base; |
@@ -261,6 +284,9 @@ struct dsi_data { | |||
261 | struct clk *dss_clk; | 284 | struct clk *dss_clk; |
262 | struct clk *sys_clk; | 285 | struct clk *sys_clk; |
263 | 286 | ||
287 | struct dispc_clock_info user_dispc_cinfo; | ||
288 | struct dsi_clock_info user_dsi_cinfo; | ||
289 | |||
264 | struct dsi_clock_info current_cinfo; | 290 | struct dsi_clock_info current_cinfo; |
265 | 291 | ||
266 | bool vdds_dsi_enabled; | 292 | bool vdds_dsi_enabled; |
@@ -324,6 +350,7 @@ struct dsi_data { | |||
324 | unsigned long lpdiv_max; | 350 | unsigned long lpdiv_max; |
325 | 351 | ||
326 | unsigned num_lanes_supported; | 352 | unsigned num_lanes_supported; |
353 | unsigned line_buffer_size; | ||
327 | 354 | ||
328 | struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; | 355 | struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; |
329 | unsigned num_lanes_used; | 356 | unsigned num_lanes_used; |
@@ -1192,15 +1219,33 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) | |||
1192 | return r; | 1219 | return r; |
1193 | } | 1220 | } |
1194 | 1221 | ||
1195 | static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev) | 1222 | static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo, |
1223 | unsigned long lp_clk_min, unsigned long lp_clk_max) | ||
1224 | { | ||
1225 | unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk; | ||
1226 | unsigned lp_clk_div; | ||
1227 | unsigned long lp_clk; | ||
1228 | |||
1229 | lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2); | ||
1230 | lp_clk = dsi_fclk / 2 / lp_clk_div; | ||
1231 | |||
1232 | if (lp_clk < lp_clk_min || lp_clk > lp_clk_max) | ||
1233 | return -EINVAL; | ||
1234 | |||
1235 | cinfo->lp_clk_div = lp_clk_div; | ||
1236 | cinfo->lp_clk = lp_clk; | ||
1237 | |||
1238 | return 0; | ||
1239 | } | ||
1240 | |||
1241 | static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) | ||
1196 | { | 1242 | { |
1197 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
1198 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1243 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
1199 | unsigned long dsi_fclk; | 1244 | unsigned long dsi_fclk; |
1200 | unsigned lp_clk_div; | 1245 | unsigned lp_clk_div; |
1201 | unsigned long lp_clk; | 1246 | unsigned long lp_clk; |
1202 | 1247 | ||
1203 | lp_clk_div = dssdev->clocks.dsi.lp_clk_div; | 1248 | lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div; |
1204 | 1249 | ||
1205 | if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max) | 1250 | if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max) |
1206 | return -EINVAL; | 1251 | return -EINVAL; |
@@ -1272,6 +1317,75 @@ static int dsi_pll_power(struct platform_device *dsidev, | |||
1272 | return 0; | 1317 | return 0; |
1273 | } | 1318 | } |
1274 | 1319 | ||
1320 | unsigned long dsi_get_pll_clkin(struct platform_device *dsidev) | ||
1321 | { | ||
1322 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1323 | return clk_get_rate(dsi->sys_clk); | ||
1324 | } | ||
1325 | |||
1326 | bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll, | ||
1327 | unsigned long out_min, dsi_hsdiv_calc_func func, void *data) | ||
1328 | { | ||
1329 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1330 | int regm, regm_start, regm_stop; | ||
1331 | unsigned long out_max; | ||
1332 | unsigned long out; | ||
1333 | |||
1334 | out_min = out_min ? out_min : 1; | ||
1335 | out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
1336 | |||
1337 | regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul); | ||
1338 | regm_stop = min(pll / out_min, dsi->regm_dispc_max); | ||
1339 | |||
1340 | for (regm = regm_start; regm <= regm_stop; ++regm) { | ||
1341 | out = pll / regm; | ||
1342 | |||
1343 | if (func(regm, out, data)) | ||
1344 | return true; | ||
1345 | } | ||
1346 | |||
1347 | return false; | ||
1348 | } | ||
1349 | |||
1350 | bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin, | ||
1351 | unsigned long pll_min, unsigned long pll_max, | ||
1352 | dsi_pll_calc_func func, void *data) | ||
1353 | { | ||
1354 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1355 | int regn, regn_start, regn_stop; | ||
1356 | int regm, regm_start, regm_stop; | ||
1357 | unsigned long fint, pll; | ||
1358 | const unsigned long pll_hw_max = 1800000000; | ||
1359 | unsigned long fint_hw_min, fint_hw_max; | ||
1360 | |||
1361 | fint_hw_min = dsi->fint_min; | ||
1362 | fint_hw_max = dsi->fint_max; | ||
1363 | |||
1364 | regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul); | ||
1365 | regn_stop = min(clkin / fint_hw_min, dsi->regn_max); | ||
1366 | |||
1367 | pll_max = pll_max ? pll_max : ULONG_MAX; | ||
1368 | |||
1369 | for (regn = regn_start; regn <= regn_stop; ++regn) { | ||
1370 | fint = clkin / regn; | ||
1371 | |||
1372 | regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2), | ||
1373 | 1ul); | ||
1374 | regm_stop = min3(pll_max / fint / 2, | ||
1375 | pll_hw_max / fint / 2, | ||
1376 | dsi->regm_max); | ||
1377 | |||
1378 | for (regm = regm_start; regm <= regm_stop; ++regm) { | ||
1379 | pll = 2 * regm * fint; | ||
1380 | |||
1381 | if (func(regn, regm, fint, pll, data)) | ||
1382 | return true; | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | return false; | ||
1387 | } | ||
1388 | |||
1275 | /* calculate clock rates using dividers in cinfo */ | 1389 | /* calculate clock rates using dividers in cinfo */ |
1276 | static int dsi_calc_clock_rates(struct platform_device *dsidev, | 1390 | static int dsi_calc_clock_rates(struct platform_device *dsidev, |
1277 | struct dsi_clock_info *cinfo) | 1391 | struct dsi_clock_info *cinfo) |
@@ -1316,192 +1430,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev, | |||
1316 | return 0; | 1430 | return 0; |
1317 | } | 1431 | } |
1318 | 1432 | ||
1319 | int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, | 1433 | static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo) |
1320 | unsigned long req_pck, struct dsi_clock_info *dsi_cinfo, | ||
1321 | struct dispc_clock_info *dispc_cinfo) | ||
1322 | { | ||
1323 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1324 | struct dsi_clock_info cur, best; | ||
1325 | struct dispc_clock_info best_dispc; | ||
1326 | int min_fck_per_pck; | ||
1327 | int match = 0; | ||
1328 | unsigned long dss_sys_clk, max_dss_fck; | ||
1329 | |||
1330 | dss_sys_clk = clk_get_rate(dsi->sys_clk); | ||
1331 | |||
1332 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
1333 | |||
1334 | if (req_pck == dsi->cache_req_pck && | ||
1335 | dsi->cache_cinfo.clkin == dss_sys_clk) { | ||
1336 | DSSDBG("DSI clock info found from cache\n"); | ||
1337 | *dsi_cinfo = dsi->cache_cinfo; | ||
1338 | dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk, | ||
1339 | dispc_cinfo); | ||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1343 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; | ||
1344 | |||
1345 | if (min_fck_per_pck && | ||
1346 | req_pck * min_fck_per_pck > max_dss_fck) { | ||
1347 | DSSERR("Requested pixel clock not possible with the current " | ||
1348 | "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " | ||
1349 | "the constraint off.\n"); | ||
1350 | min_fck_per_pck = 0; | ||
1351 | } | ||
1352 | |||
1353 | DSSDBG("dsi_pll_calc\n"); | ||
1354 | |||
1355 | retry: | ||
1356 | memset(&best, 0, sizeof(best)); | ||
1357 | memset(&best_dispc, 0, sizeof(best_dispc)); | ||
1358 | |||
1359 | memset(&cur, 0, sizeof(cur)); | ||
1360 | cur.clkin = dss_sys_clk; | ||
1361 | |||
1362 | /* 0.75MHz < Fint = clkin / regn < 2.1MHz */ | ||
1363 | /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ | ||
1364 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { | ||
1365 | cur.fint = cur.clkin / cur.regn; | ||
1366 | |||
1367 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) | ||
1368 | continue; | ||
1369 | |||
1370 | /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ | ||
1371 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { | ||
1372 | unsigned long a, b; | ||
1373 | |||
1374 | a = 2 * cur.regm * (cur.clkin/1000); | ||
1375 | b = cur.regn; | ||
1376 | cur.clkin4ddr = a / b * 1000; | ||
1377 | |||
1378 | if (cur.clkin4ddr > 1800 * 1000 * 1000) | ||
1379 | break; | ||
1380 | |||
1381 | /* dsi_pll_hsdiv_dispc_clk(MHz) = | ||
1382 | * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */ | ||
1383 | for (cur.regm_dispc = 1; cur.regm_dispc < | ||
1384 | dsi->regm_dispc_max; ++cur.regm_dispc) { | ||
1385 | struct dispc_clock_info cur_dispc; | ||
1386 | cur.dsi_pll_hsdiv_dispc_clk = | ||
1387 | cur.clkin4ddr / cur.regm_dispc; | ||
1388 | |||
1389 | if (cur.regm_dispc > 1 && | ||
1390 | cur.regm_dispc % 2 != 0 && | ||
1391 | req_pck >= 1000000) | ||
1392 | continue; | ||
1393 | |||
1394 | /* this will narrow down the search a bit, | ||
1395 | * but still give pixclocks below what was | ||
1396 | * requested */ | ||
1397 | if (cur.dsi_pll_hsdiv_dispc_clk < req_pck) | ||
1398 | break; | ||
1399 | |||
1400 | if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck) | ||
1401 | continue; | ||
1402 | |||
1403 | if (min_fck_per_pck && | ||
1404 | cur.dsi_pll_hsdiv_dispc_clk < | ||
1405 | req_pck * min_fck_per_pck) | ||
1406 | continue; | ||
1407 | |||
1408 | match = 1; | ||
1409 | |||
1410 | dispc_find_clk_divs(req_pck, | ||
1411 | cur.dsi_pll_hsdiv_dispc_clk, | ||
1412 | &cur_dispc); | ||
1413 | |||
1414 | if (abs(cur_dispc.pck - req_pck) < | ||
1415 | abs(best_dispc.pck - req_pck)) { | ||
1416 | best = cur; | ||
1417 | best_dispc = cur_dispc; | ||
1418 | |||
1419 | if (cur_dispc.pck == req_pck) | ||
1420 | goto found; | ||
1421 | } | ||
1422 | } | ||
1423 | } | ||
1424 | } | ||
1425 | found: | ||
1426 | if (!match) { | ||
1427 | if (min_fck_per_pck) { | ||
1428 | DSSERR("Could not find suitable clock settings.\n" | ||
1429 | "Turning FCK/PCK constraint off and" | ||
1430 | "trying again.\n"); | ||
1431 | min_fck_per_pck = 0; | ||
1432 | goto retry; | ||
1433 | } | ||
1434 | |||
1435 | DSSERR("Could not find suitable clock settings.\n"); | ||
1436 | |||
1437 | return -EINVAL; | ||
1438 | } | ||
1439 | |||
1440 | /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */ | ||
1441 | best.regm_dsi = 0; | ||
1442 | best.dsi_pll_hsdiv_dsi_clk = 0; | ||
1443 | |||
1444 | if (dsi_cinfo) | ||
1445 | *dsi_cinfo = best; | ||
1446 | if (dispc_cinfo) | ||
1447 | *dispc_cinfo = best_dispc; | ||
1448 | |||
1449 | dsi->cache_req_pck = req_pck; | ||
1450 | dsi->cache_clk_freq = 0; | ||
1451 | dsi->cache_cinfo = best; | ||
1452 | |||
1453 | return 0; | ||
1454 | } | ||
1455 | |||
1456 | static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, | ||
1457 | unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo) | ||
1458 | { | ||
1459 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1460 | struct dsi_clock_info cur, best; | ||
1461 | |||
1462 | DSSDBG("dsi_pll_calc_ddrfreq\n"); | ||
1463 | |||
1464 | memset(&best, 0, sizeof(best)); | ||
1465 | memset(&cur, 0, sizeof(cur)); | ||
1466 | |||
1467 | cur.clkin = clk_get_rate(dsi->sys_clk); | ||
1468 | |||
1469 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { | ||
1470 | cur.fint = cur.clkin / cur.regn; | ||
1471 | |||
1472 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) | ||
1473 | continue; | ||
1474 | |||
1475 | /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ | ||
1476 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { | ||
1477 | unsigned long a, b; | ||
1478 | |||
1479 | a = 2 * cur.regm * (cur.clkin/1000); | ||
1480 | b = cur.regn; | ||
1481 | cur.clkin4ddr = a / b * 1000; | ||
1482 | |||
1483 | if (cur.clkin4ddr > 1800 * 1000 * 1000) | ||
1484 | break; | ||
1485 | |||
1486 | if (abs(cur.clkin4ddr - req_clkin4ddr) < | ||
1487 | abs(best.clkin4ddr - req_clkin4ddr)) { | ||
1488 | best = cur; | ||
1489 | DSSDBG("best %ld\n", best.clkin4ddr); | ||
1490 | } | ||
1491 | |||
1492 | if (cur.clkin4ddr == req_clkin4ddr) | ||
1493 | goto found; | ||
1494 | } | ||
1495 | } | ||
1496 | found: | ||
1497 | if (cinfo) | ||
1498 | *cinfo = best; | ||
1499 | |||
1500 | return 0; | ||
1501 | } | ||
1502 | |||
1503 | static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, | ||
1504 | struct dsi_clock_info *cinfo) | ||
1505 | { | 1434 | { |
1506 | unsigned long max_dsi_fck; | 1435 | unsigned long max_dsi_fck; |
1507 | 1436 | ||
@@ -1511,90 +1440,6 @@ static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, | |||
1511 | cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; | 1440 | cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; |
1512 | } | 1441 | } |
1513 | 1442 | ||
1514 | static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev, | ||
1515 | unsigned long req_pck, struct dsi_clock_info *cinfo, | ||
1516 | struct dispc_clock_info *dispc_cinfo) | ||
1517 | { | ||
1518 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1519 | unsigned regm_dispc, best_regm_dispc; | ||
1520 | unsigned long dispc_clk, best_dispc_clk; | ||
1521 | int min_fck_per_pck; | ||
1522 | unsigned long max_dss_fck; | ||
1523 | struct dispc_clock_info best_dispc; | ||
1524 | bool match; | ||
1525 | |||
1526 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
1527 | |||
1528 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; | ||
1529 | |||
1530 | if (min_fck_per_pck && | ||
1531 | req_pck * min_fck_per_pck > max_dss_fck) { | ||
1532 | DSSERR("Requested pixel clock not possible with the current " | ||
1533 | "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " | ||
1534 | "the constraint off.\n"); | ||
1535 | min_fck_per_pck = 0; | ||
1536 | } | ||
1537 | |||
1538 | retry: | ||
1539 | best_regm_dispc = 0; | ||
1540 | best_dispc_clk = 0; | ||
1541 | memset(&best_dispc, 0, sizeof(best_dispc)); | ||
1542 | match = false; | ||
1543 | |||
1544 | for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) { | ||
1545 | struct dispc_clock_info cur_dispc; | ||
1546 | |||
1547 | dispc_clk = cinfo->clkin4ddr / regm_dispc; | ||
1548 | |||
1549 | /* this will narrow down the search a bit, | ||
1550 | * but still give pixclocks below what was | ||
1551 | * requested */ | ||
1552 | if (dispc_clk < req_pck) | ||
1553 | break; | ||
1554 | |||
1555 | if (dispc_clk > max_dss_fck) | ||
1556 | continue; | ||
1557 | |||
1558 | if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck) | ||
1559 | continue; | ||
1560 | |||
1561 | match = true; | ||
1562 | |||
1563 | dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc); | ||
1564 | |||
1565 | if (abs(cur_dispc.pck - req_pck) < | ||
1566 | abs(best_dispc.pck - req_pck)) { | ||
1567 | best_regm_dispc = regm_dispc; | ||
1568 | best_dispc_clk = dispc_clk; | ||
1569 | best_dispc = cur_dispc; | ||
1570 | |||
1571 | if (cur_dispc.pck == req_pck) | ||
1572 | goto found; | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | if (!match) { | ||
1577 | if (min_fck_per_pck) { | ||
1578 | DSSERR("Could not find suitable clock settings.\n" | ||
1579 | "Turning FCK/PCK constraint off and" | ||
1580 | "trying again.\n"); | ||
1581 | min_fck_per_pck = 0; | ||
1582 | goto retry; | ||
1583 | } | ||
1584 | |||
1585 | DSSERR("Could not find suitable clock settings.\n"); | ||
1586 | |||
1587 | return -EINVAL; | ||
1588 | } | ||
1589 | found: | ||
1590 | cinfo->regm_dispc = best_regm_dispc; | ||
1591 | cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk; | ||
1592 | |||
1593 | *dispc_cinfo = best_dispc; | ||
1594 | |||
1595 | return 0; | ||
1596 | } | ||
1597 | |||
1598 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | 1443 | int dsi_pll_set_clock_div(struct platform_device *dsidev, |
1599 | struct dsi_clock_info *cinfo) | 1444 | struct dsi_clock_info *cinfo) |
1600 | { | 1445 | { |
@@ -2783,6 +2628,7 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel, | |||
2783 | 2628 | ||
2784 | static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) | 2629 | static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) |
2785 | { | 2630 | { |
2631 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2786 | u32 r; | 2632 | u32 r; |
2787 | 2633 | ||
2788 | DSSDBG("Initial config of virtual channel %d", channel); | 2634 | DSSDBG("Initial config of virtual channel %d", channel); |
@@ -2807,6 +2653,8 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) | |||
2807 | r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ | 2653 | r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ |
2808 | 2654 | ||
2809 | dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); | 2655 | dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); |
2656 | |||
2657 | dsi->vc[channel].source = DSI_VC_SOURCE_L4; | ||
2810 | } | 2658 | } |
2811 | 2659 | ||
2812 | static int dsi_vc_config_source(struct platform_device *dsidev, int channel, | 2660 | static int dsi_vc_config_source(struct platform_device *dsidev, int channel, |
@@ -3777,13 +3625,12 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) | |||
3777 | 3625 | ||
3778 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | 3626 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3779 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | 3627 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
3780 | unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | ||
3781 | struct omap_video_timings *timings = &dsi->timings; | 3628 | struct omap_video_timings *timings = &dsi->timings; |
3782 | /* | 3629 | /* |
3783 | * Don't use line buffers if width is greater than the video | 3630 | * Don't use line buffers if width is greater than the video |
3784 | * port's line buffer size | 3631 | * port's line buffer size |
3785 | */ | 3632 | */ |
3786 | if (line_buf_size <= timings->x_res * bpp / 8) | 3633 | if (dsi->line_buffer_size <= timings->x_res * bpp / 8) |
3787 | num_line_buffers = 0; | 3634 | num_line_buffers = 0; |
3788 | else | 3635 | else |
3789 | num_line_buffers = 2; | 3636 | num_line_buffers = 2; |
@@ -3799,18 +3646,22 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) | |||
3799 | static void dsi_config_vp_sync_events(struct platform_device *dsidev) | 3646 | static void dsi_config_vp_sync_events(struct platform_device *dsidev) |
3800 | { | 3647 | { |
3801 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3648 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3802 | bool vsync_end = dsi->vm_timings.vp_vsync_end; | 3649 | bool sync_end; |
3803 | bool hsync_end = dsi->vm_timings.vp_hsync_end; | ||
3804 | u32 r; | 3650 | u32 r; |
3805 | 3651 | ||
3652 | if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE) | ||
3653 | sync_end = true; | ||
3654 | else | ||
3655 | sync_end = false; | ||
3656 | |||
3806 | r = dsi_read_reg(dsidev, DSI_CTRL); | 3657 | r = dsi_read_reg(dsidev, DSI_CTRL); |
3807 | r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ | 3658 | r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ |
3808 | r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */ | 3659 | r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */ |
3809 | r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ | 3660 | r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ |
3810 | r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */ | 3661 | r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */ |
3811 | r = FLD_MOD(r, vsync_end, 16, 16); /* VP_VSYNC_END */ | 3662 | r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */ |
3812 | r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ | 3663 | r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ |
3813 | r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */ | 3664 | r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */ |
3814 | dsi_write_reg(dsidev, DSI_CTRL, r); | 3665 | dsi_write_reg(dsidev, DSI_CTRL, r); |
3815 | } | 3666 | } |
3816 | 3667 | ||
@@ -3897,9 +3748,8 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, | |||
3897 | return max(lp_inter, 0); | 3748 | return max(lp_inter, 0); |
3898 | } | 3749 | } |
3899 | 3750 | ||
3900 | static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | 3751 | static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) |
3901 | { | 3752 | { |
3902 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3903 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3753 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3904 | int blanking_mode; | 3754 | int blanking_mode; |
3905 | int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; | 3755 | int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; |
@@ -3910,7 +3760,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | |||
3910 | struct omap_video_timings *timings = &dsi->timings; | 3760 | struct omap_video_timings *timings = &dsi->timings; |
3911 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | 3761 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
3912 | int ndl = dsi->num_lanes_used - 1; | 3762 | int ndl = dsi->num_lanes_used - 1; |
3913 | int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; | 3763 | int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1; |
3914 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; | 3764 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; |
3915 | int hfp_interleave_hs = 0, hfp_interleave_lp = 0; | 3765 | int hfp_interleave_hs = 0, hfp_interleave_lp = 0; |
3916 | int hbp_interleave_hs = 0, hbp_interleave_lp = 0; | 3766 | int hbp_interleave_hs = 0, hbp_interleave_lp = 0; |
@@ -4015,9 +3865,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | |||
4015 | dsi_write_reg(dsidev, DSI_VM_TIMING6, r); | 3865 | dsi_write_reg(dsidev, DSI_VM_TIMING6, r); |
4016 | } | 3866 | } |
4017 | 3867 | ||
4018 | static int dsi_proto_config(struct omap_dss_device *dssdev) | 3868 | static int dsi_proto_config(struct platform_device *dsidev) |
4019 | { | 3869 | { |
4020 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4021 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3870 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4022 | u32 r; | 3871 | u32 r; |
4023 | int buswidth = 0; | 3872 | int buswidth = 0; |
@@ -4075,7 +3924,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
4075 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | 3924 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
4076 | dsi_config_vp_sync_events(dsidev); | 3925 | dsi_config_vp_sync_events(dsidev); |
4077 | dsi_config_blanking_modes(dsidev); | 3926 | dsi_config_blanking_modes(dsidev); |
4078 | dsi_config_cmd_mode_interleaving(dssdev); | 3927 | dsi_config_cmd_mode_interleaving(dsidev); |
4079 | } | 3928 | } |
4080 | 3929 | ||
4081 | dsi_vc_initial_config(dsidev, 0); | 3930 | dsi_vc_initial_config(dsidev, 0); |
@@ -4159,11 +4008,12 @@ static void dsi_proto_timings(struct platform_device *dsidev) | |||
4159 | int vfp = dsi->vm_timings.vfp; | 4008 | int vfp = dsi->vm_timings.vfp; |
4160 | int vbp = dsi->vm_timings.vbp; | 4009 | int vbp = dsi->vm_timings.vbp; |
4161 | int window_sync = dsi->vm_timings.window_sync; | 4010 | int window_sync = dsi->vm_timings.window_sync; |
4162 | bool hsync_end = dsi->vm_timings.vp_hsync_end; | 4011 | bool hsync_end; |
4163 | struct omap_video_timings *timings = &dsi->timings; | 4012 | struct omap_video_timings *timings = &dsi->timings; |
4164 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | 4013 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
4165 | int tl, t_he, width_bytes; | 4014 | int tl, t_he, width_bytes; |
4166 | 4015 | ||
4016 | hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE; | ||
4167 | t_he = hsync_end ? | 4017 | t_he = hsync_end ? |
4168 | ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0; | 4018 | ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0; |
4169 | 4019 | ||
@@ -4266,82 +4116,26 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, | |||
4266 | } | 4116 | } |
4267 | EXPORT_SYMBOL(omapdss_dsi_configure_pins); | 4117 | EXPORT_SYMBOL(omapdss_dsi_configure_pins); |
4268 | 4118 | ||
4269 | int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, | ||
4270 | unsigned long ddr_clk, unsigned long lp_clk) | ||
4271 | { | ||
4272 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4273 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4274 | struct dsi_clock_info cinfo; | ||
4275 | struct dispc_clock_info dispc_cinfo; | ||
4276 | unsigned lp_clk_div; | ||
4277 | unsigned long dsi_fclk; | ||
4278 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | ||
4279 | unsigned long pck; | ||
4280 | int r; | ||
4281 | |||
4282 | DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); | ||
4283 | |||
4284 | mutex_lock(&dsi->lock); | ||
4285 | |||
4286 | /* Calculate PLL output clock */ | ||
4287 | r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); | ||
4288 | if (r) | ||
4289 | goto err; | ||
4290 | |||
4291 | /* Calculate PLL's DSI clock */ | ||
4292 | dsi_pll_calc_dsi_fck(dsidev, &cinfo); | ||
4293 | |||
4294 | /* Calculate PLL's DISPC clock and pck & lck divs */ | ||
4295 | pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; | ||
4296 | DSSDBG("finding dispc dividers for pck %lu\n", pck); | ||
4297 | r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); | ||
4298 | if (r) | ||
4299 | goto err; | ||
4300 | |||
4301 | /* Calculate LP clock */ | ||
4302 | dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; | ||
4303 | lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); | ||
4304 | |||
4305 | dssdev->clocks.dsi.regn = cinfo.regn; | ||
4306 | dssdev->clocks.dsi.regm = cinfo.regm; | ||
4307 | dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; | ||
4308 | dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi; | ||
4309 | |||
4310 | dssdev->clocks.dsi.lp_clk_div = lp_clk_div; | ||
4311 | |||
4312 | dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; | ||
4313 | dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; | ||
4314 | |||
4315 | dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; | ||
4316 | |||
4317 | dssdev->clocks.dispc.channel.lcd_clk_src = | ||
4318 | dsi->module_id == 0 ? | ||
4319 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : | ||
4320 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; | ||
4321 | |||
4322 | dssdev->clocks.dsi.dsi_fclk_src = | ||
4323 | dsi->module_id == 0 ? | ||
4324 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : | ||
4325 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI; | ||
4326 | |||
4327 | mutex_unlock(&dsi->lock); | ||
4328 | return 0; | ||
4329 | err: | ||
4330 | mutex_unlock(&dsi->lock); | ||
4331 | return r; | ||
4332 | } | ||
4333 | EXPORT_SYMBOL(omapdss_dsi_set_clocks); | ||
4334 | |||
4335 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | 4119 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) |
4336 | { | 4120 | { |
4337 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4121 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4338 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4122 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4339 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 4123 | struct omap_overlay_manager *mgr = dsi->output.manager; |
4340 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | 4124 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
4125 | struct omap_dss_output *out = &dsi->output; | ||
4341 | u8 data_type; | 4126 | u8 data_type; |
4342 | u16 word_count; | 4127 | u16 word_count; |
4343 | int r; | 4128 | int r; |
4344 | 4129 | ||
4130 | if (out == NULL || out->manager == NULL) { | ||
4131 | DSSERR("failed to enable display: no output/manager\n"); | ||
4132 | return -ENODEV; | ||
4133 | } | ||
4134 | |||
4135 | r = dsi_display_init_dispc(dsidev, mgr); | ||
4136 | if (r) | ||
4137 | goto err_init_dispc; | ||
4138 | |||
4345 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4139 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
4346 | switch (dsi->pix_fmt) { | 4140 | switch (dsi->pix_fmt) { |
4347 | case OMAP_DSS_DSI_FMT_RGB888: | 4141 | case OMAP_DSS_DSI_FMT_RGB888: |
@@ -4357,8 +4151,8 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4357 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 4151 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
4358 | break; | 4152 | break; |
4359 | default: | 4153 | default: |
4360 | BUG(); | 4154 | r = -EINVAL; |
4361 | return -EINVAL; | 4155 | goto err_pix_fmt; |
4362 | }; | 4156 | }; |
4363 | 4157 | ||
4364 | dsi_if_enable(dsidev, false); | 4158 | dsi_if_enable(dsidev, false); |
@@ -4377,16 +4171,20 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4377 | } | 4171 | } |
4378 | 4172 | ||
4379 | r = dss_mgr_enable(mgr); | 4173 | r = dss_mgr_enable(mgr); |
4380 | if (r) { | 4174 | if (r) |
4381 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4175 | goto err_mgr_enable; |
4382 | dsi_if_enable(dsidev, false); | ||
4383 | dsi_vc_enable(dsidev, channel, false); | ||
4384 | } | ||
4385 | |||
4386 | return r; | ||
4387 | } | ||
4388 | 4176 | ||
4389 | return 0; | 4177 | return 0; |
4178 | |||
4179 | err_mgr_enable: | ||
4180 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
4181 | dsi_if_enable(dsidev, false); | ||
4182 | dsi_vc_enable(dsidev, channel, false); | ||
4183 | } | ||
4184 | err_pix_fmt: | ||
4185 | dsi_display_uninit_dispc(dsidev, mgr); | ||
4186 | err_init_dispc: | ||
4187 | return r; | ||
4390 | } | 4188 | } |
4391 | EXPORT_SYMBOL(dsi_enable_video_output); | 4189 | EXPORT_SYMBOL(dsi_enable_video_output); |
4392 | 4190 | ||
@@ -4394,7 +4192,7 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4394 | { | 4192 | { |
4395 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4193 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4396 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4194 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4397 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 4195 | struct omap_overlay_manager *mgr = dsi->output.manager; |
4398 | 4196 | ||
4399 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | 4197 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { |
4400 | dsi_if_enable(dsidev, false); | 4198 | dsi_if_enable(dsidev, false); |
@@ -4408,14 +4206,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) | |||
4408 | } | 4206 | } |
4409 | 4207 | ||
4410 | dss_mgr_disable(mgr); | 4208 | dss_mgr_disable(mgr); |
4209 | |||
4210 | dsi_display_uninit_dispc(dsidev, mgr); | ||
4411 | } | 4211 | } |
4412 | EXPORT_SYMBOL(dsi_disable_video_output); | 4212 | EXPORT_SYMBOL(dsi_disable_video_output); |
4413 | 4213 | ||
4414 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) | 4214 | static void dsi_update_screen_dispc(struct platform_device *dsidev) |
4415 | { | 4215 | { |
4416 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4417 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4216 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4418 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 4217 | struct omap_overlay_manager *mgr = dsi->output.manager; |
4419 | unsigned bytespp; | 4218 | unsigned bytespp; |
4420 | unsigned bytespl; | 4219 | unsigned bytespl; |
4421 | unsigned bytespf; | 4220 | unsigned bytespf; |
@@ -4425,7 +4224,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) | |||
4425 | u32 l; | 4224 | u32 l; |
4426 | int r; | 4225 | int r; |
4427 | const unsigned channel = dsi->update_channel; | 4226 | const unsigned channel = dsi->update_channel; |
4428 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | 4227 | const unsigned line_buf_size = dsi->line_buffer_size; |
4429 | u16 w = dsi->timings.x_res; | 4228 | u16 w = dsi->timings.x_res; |
4430 | u16 h = dsi->timings.y_res; | 4229 | u16 h = dsi->timings.y_res; |
4431 | 4230 | ||
@@ -4571,7 +4370,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel, | |||
4571 | dsi->update_bytes = dw * dh * | 4370 | dsi->update_bytes = dw * dh * |
4572 | dsi_get_pixel_size(dsi->pix_fmt) / 8; | 4371 | dsi_get_pixel_size(dsi->pix_fmt) / 8; |
4573 | #endif | 4372 | #endif |
4574 | dsi_update_screen_dispc(dssdev); | 4373 | dsi_update_screen_dispc(dsidev); |
4575 | 4374 | ||
4576 | return 0; | 4375 | return 0; |
4577 | } | 4376 | } |
@@ -4579,18 +4378,17 @@ EXPORT_SYMBOL(omap_dsi_update); | |||
4579 | 4378 | ||
4580 | /* Display funcs */ | 4379 | /* Display funcs */ |
4581 | 4380 | ||
4582 | static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) | 4381 | static int dsi_configure_dispc_clocks(struct platform_device *dsidev) |
4583 | { | 4382 | { |
4584 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4585 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4383 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4586 | struct dispc_clock_info dispc_cinfo; | 4384 | struct dispc_clock_info dispc_cinfo; |
4587 | int r; | 4385 | int r; |
4588 | unsigned long long fck; | 4386 | unsigned long fck; |
4589 | 4387 | ||
4590 | fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 4388 | fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); |
4591 | 4389 | ||
4592 | dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div; | 4390 | dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div; |
4593 | dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div; | 4391 | dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div; |
4594 | 4392 | ||
4595 | r = dispc_calc_clock_rates(fck, &dispc_cinfo); | 4393 | r = dispc_calc_clock_rates(fck, &dispc_cinfo); |
4596 | if (r) { | 4394 | if (r) { |
@@ -4603,21 +4401,17 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) | |||
4603 | return 0; | 4401 | return 0; |
4604 | } | 4402 | } |
4605 | 4403 | ||
4606 | static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | 4404 | static int dsi_display_init_dispc(struct platform_device *dsidev, |
4405 | struct omap_overlay_manager *mgr) | ||
4607 | { | 4406 | { |
4608 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4609 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4407 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4610 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4611 | int r; | 4408 | int r; |
4612 | 4409 | ||
4613 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { | 4410 | dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ? |
4614 | dsi->timings.hsw = 1; | 4411 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : |
4615 | dsi->timings.hfp = 1; | 4412 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC); |
4616 | dsi->timings.hbp = 1; | ||
4617 | dsi->timings.vsw = 1; | ||
4618 | dsi->timings.vfp = 0; | ||
4619 | dsi->timings.vbp = 0; | ||
4620 | 4413 | ||
4414 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { | ||
4621 | r = dss_mgr_register_framedone_handler(mgr, | 4415 | r = dss_mgr_register_framedone_handler(mgr, |
4622 | dsi_framedone_irq_callback, dsidev); | 4416 | dsi_framedone_irq_callback, dsidev); |
4623 | if (r) { | 4417 | if (r) { |
@@ -4645,7 +4439,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4645 | 4439 | ||
4646 | dss_mgr_set_timings(mgr, &dsi->timings); | 4440 | dss_mgr_set_timings(mgr, &dsi->timings); |
4647 | 4441 | ||
4648 | r = dsi_configure_dispc_clocks(dssdev); | 4442 | r = dsi_configure_dispc_clocks(dsidev); |
4649 | if (r) | 4443 | if (r) |
4650 | goto err1; | 4444 | goto err1; |
4651 | 4445 | ||
@@ -4662,30 +4456,30 @@ err1: | |||
4662 | dss_mgr_unregister_framedone_handler(mgr, | 4456 | dss_mgr_unregister_framedone_handler(mgr, |
4663 | dsi_framedone_irq_callback, dsidev); | 4457 | dsi_framedone_irq_callback, dsidev); |
4664 | err: | 4458 | err: |
4459 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | ||
4665 | return r; | 4460 | return r; |
4666 | } | 4461 | } |
4667 | 4462 | ||
4668 | static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) | 4463 | static void dsi_display_uninit_dispc(struct platform_device *dsidev, |
4464 | struct omap_overlay_manager *mgr) | ||
4669 | { | 4465 | { |
4670 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4671 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4466 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4672 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4673 | 4467 | ||
4674 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) | 4468 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) |
4675 | dss_mgr_unregister_framedone_handler(mgr, | 4469 | dss_mgr_unregister_framedone_handler(mgr, |
4676 | dsi_framedone_irq_callback, dsidev); | 4470 | dsi_framedone_irq_callback, dsidev); |
4471 | |||
4472 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | ||
4677 | } | 4473 | } |
4678 | 4474 | ||
4679 | static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | 4475 | static int dsi_configure_dsi_clocks(struct platform_device *dsidev) |
4680 | { | 4476 | { |
4681 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4477 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4682 | struct dsi_clock_info cinfo; | 4478 | struct dsi_clock_info cinfo; |
4683 | int r; | 4479 | int r; |
4684 | 4480 | ||
4685 | cinfo.regn = dssdev->clocks.dsi.regn; | 4481 | cinfo = dsi->user_dsi_cinfo; |
4686 | cinfo.regm = dssdev->clocks.dsi.regm; | 4482 | |
4687 | cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc; | ||
4688 | cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi; | ||
4689 | r = dsi_calc_clock_rates(dsidev, &cinfo); | 4483 | r = dsi_calc_clock_rates(dsidev, &cinfo); |
4690 | if (r) { | 4484 | if (r) { |
4691 | DSSERR("Failed to calc dsi clocks\n"); | 4485 | DSSERR("Failed to calc dsi clocks\n"); |
@@ -4701,24 +4495,22 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | |||
4701 | return 0; | 4495 | return 0; |
4702 | } | 4496 | } |
4703 | 4497 | ||
4704 | static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | 4498 | static int dsi_display_init_dsi(struct platform_device *dsidev) |
4705 | { | 4499 | { |
4706 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4707 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4500 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4708 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4709 | int r; | 4501 | int r; |
4710 | 4502 | ||
4711 | r = dsi_pll_init(dsidev, true, true); | 4503 | r = dsi_pll_init(dsidev, true, true); |
4712 | if (r) | 4504 | if (r) |
4713 | goto err0; | 4505 | goto err0; |
4714 | 4506 | ||
4715 | r = dsi_configure_dsi_clocks(dssdev); | 4507 | r = dsi_configure_dsi_clocks(dsidev); |
4716 | if (r) | 4508 | if (r) |
4717 | goto err1; | 4509 | goto err1; |
4718 | 4510 | ||
4719 | dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); | 4511 | dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ? |
4720 | dss_select_lcd_clk_source(mgr->id, | 4512 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : |
4721 | dssdev->clocks.dispc.channel.lcd_clk_src); | 4513 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI); |
4722 | 4514 | ||
4723 | DSSDBG("PLL OK\n"); | 4515 | DSSDBG("PLL OK\n"); |
4724 | 4516 | ||
@@ -4729,12 +4521,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4729 | _dsi_print_reset_status(dsidev); | 4521 | _dsi_print_reset_status(dsidev); |
4730 | 4522 | ||
4731 | dsi_proto_timings(dsidev); | 4523 | dsi_proto_timings(dsidev); |
4732 | dsi_set_lp_clk_divisor(dssdev); | 4524 | dsi_set_lp_clk_divisor(dsidev); |
4733 | 4525 | ||
4734 | if (1) | 4526 | if (1) |
4735 | _dsi_print_reset_status(dsidev); | 4527 | _dsi_print_reset_status(dsidev); |
4736 | 4528 | ||
4737 | r = dsi_proto_config(dssdev); | 4529 | r = dsi_proto_config(dsidev); |
4738 | if (r) | 4530 | if (r) |
4739 | goto err3; | 4531 | goto err3; |
4740 | 4532 | ||
@@ -4751,20 +4543,16 @@ err3: | |||
4751 | dsi_cio_uninit(dsidev); | 4543 | dsi_cio_uninit(dsidev); |
4752 | err2: | 4544 | err2: |
4753 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4545 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
4754 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | ||
4755 | |||
4756 | err1: | 4546 | err1: |
4757 | dsi_pll_uninit(dsidev, true); | 4547 | dsi_pll_uninit(dsidev, true); |
4758 | err0: | 4548 | err0: |
4759 | return r; | 4549 | return r; |
4760 | } | 4550 | } |
4761 | 4551 | ||
4762 | static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | 4552 | static void dsi_display_uninit_dsi(struct platform_device *dsidev, |
4763 | bool disconnect_lanes, bool enter_ulps) | 4553 | bool disconnect_lanes, bool enter_ulps) |
4764 | { | 4554 | { |
4765 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4766 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4555 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4767 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4768 | 4556 | ||
4769 | if (enter_ulps && !dsi->ulps_enabled) | 4557 | if (enter_ulps && !dsi->ulps_enabled) |
4770 | dsi_enter_ulps(dsidev); | 4558 | dsi_enter_ulps(dsidev); |
@@ -4777,7 +4565,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
4777 | dsi_vc_enable(dsidev, 3, 0); | 4565 | dsi_vc_enable(dsidev, 3, 0); |
4778 | 4566 | ||
4779 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4567 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
4780 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | ||
4781 | dsi_cio_uninit(dsidev); | 4568 | dsi_cio_uninit(dsidev); |
4782 | dsi_pll_uninit(dsidev, disconnect_lanes); | 4569 | dsi_pll_uninit(dsidev, disconnect_lanes); |
4783 | } | 4570 | } |
@@ -4786,7 +4573,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4786 | { | 4573 | { |
4787 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4574 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4788 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4575 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4789 | struct omap_dss_output *out = dssdev->output; | ||
4790 | int r = 0; | 4576 | int r = 0; |
4791 | 4577 | ||
4792 | DSSDBG("dsi_display_enable\n"); | 4578 | DSSDBG("dsi_display_enable\n"); |
@@ -4795,12 +4581,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4795 | 4581 | ||
4796 | mutex_lock(&dsi->lock); | 4582 | mutex_lock(&dsi->lock); |
4797 | 4583 | ||
4798 | if (out == NULL || out->manager == NULL) { | ||
4799 | DSSERR("failed to enable display: no output/manager\n"); | ||
4800 | r = -ENODEV; | ||
4801 | goto err_start_dev; | ||
4802 | } | ||
4803 | |||
4804 | r = omap_dss_start_device(dssdev); | 4584 | r = omap_dss_start_device(dssdev); |
4805 | if (r) { | 4585 | if (r) { |
4806 | DSSERR("failed to start device\n"); | 4586 | DSSERR("failed to start device\n"); |
@@ -4815,11 +4595,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4815 | 4595 | ||
4816 | _dsi_initialize_irq(dsidev); | 4596 | _dsi_initialize_irq(dsidev); |
4817 | 4597 | ||
4818 | r = dsi_display_init_dispc(dssdev); | 4598 | r = dsi_display_init_dsi(dsidev); |
4819 | if (r) | ||
4820 | goto err_init_dispc; | ||
4821 | |||
4822 | r = dsi_display_init_dsi(dssdev); | ||
4823 | if (r) | 4599 | if (r) |
4824 | goto err_init_dsi; | 4600 | goto err_init_dsi; |
4825 | 4601 | ||
@@ -4828,8 +4604,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4828 | return 0; | 4604 | return 0; |
4829 | 4605 | ||
4830 | err_init_dsi: | 4606 | err_init_dsi: |
4831 | dsi_display_uninit_dispc(dssdev); | ||
4832 | err_init_dispc: | ||
4833 | dsi_enable_pll_clock(dsidev, 0); | 4607 | dsi_enable_pll_clock(dsidev, 0); |
4834 | dsi_runtime_put(dsidev); | 4608 | dsi_runtime_put(dsidev); |
4835 | err_get_dsi: | 4609 | err_get_dsi: |
@@ -4858,9 +4632,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, | |||
4858 | dsi_sync_vc(dsidev, 2); | 4632 | dsi_sync_vc(dsidev, 2); |
4859 | dsi_sync_vc(dsidev, 3); | 4633 | dsi_sync_vc(dsidev, 3); |
4860 | 4634 | ||
4861 | dsi_display_uninit_dispc(dssdev); | 4635 | dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps); |
4862 | |||
4863 | dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); | ||
4864 | 4636 | ||
4865 | dsi_runtime_put(dsidev); | 4637 | dsi_runtime_put(dsidev); |
4866 | dsi_enable_pll_clock(dsidev, 0); | 4638 | dsi_enable_pll_clock(dsidev, 0); |
@@ -4881,75 +4653,577 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
4881 | } | 4653 | } |
4882 | EXPORT_SYMBOL(omapdss_dsi_enable_te); | 4654 | EXPORT_SYMBOL(omapdss_dsi_enable_te); |
4883 | 4655 | ||
4884 | void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, | 4656 | #ifdef PRINT_VERBOSE_VM_TIMINGS |
4885 | struct omap_video_timings *timings) | 4657 | static void print_dsi_vm(const char *str, |
4658 | const struct omap_dss_dsi_videomode_timings *t) | ||
4659 | { | ||
4660 | unsigned long byteclk = t->hsclk / 4; | ||
4661 | int bl, wc, pps, tot; | ||
4662 | |||
4663 | wc = DIV_ROUND_UP(t->hact * t->bitspp, 8); | ||
4664 | pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */ | ||
4665 | bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp; | ||
4666 | tot = bl + pps; | ||
4667 | |||
4668 | #define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk)) | ||
4669 | |||
4670 | pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, " | ||
4671 | "%u/%u/%u/%u/%u/%u = %u + %u = %u\n", | ||
4672 | str, | ||
4673 | byteclk, | ||
4674 | t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp, | ||
4675 | bl, pps, tot, | ||
4676 | TO_DSI_T(t->hss), | ||
4677 | TO_DSI_T(t->hsa), | ||
4678 | TO_DSI_T(t->hse), | ||
4679 | TO_DSI_T(t->hbp), | ||
4680 | TO_DSI_T(pps), | ||
4681 | TO_DSI_T(t->hfp), | ||
4682 | |||
4683 | TO_DSI_T(bl), | ||
4684 | TO_DSI_T(pps), | ||
4685 | |||
4686 | TO_DSI_T(tot)); | ||
4687 | #undef TO_DSI_T | ||
4688 | } | ||
4689 | |||
4690 | static void print_dispc_vm(const char *str, const struct omap_video_timings *t) | ||
4691 | { | ||
4692 | unsigned long pck = t->pixel_clock * 1000; | ||
4693 | int hact, bl, tot; | ||
4694 | |||
4695 | hact = t->x_res; | ||
4696 | bl = t->hsw + t->hbp + t->hfp; | ||
4697 | tot = hact + bl; | ||
4698 | |||
4699 | #define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck)) | ||
4700 | |||
4701 | pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, " | ||
4702 | "%u/%u/%u/%u = %u + %u = %u\n", | ||
4703 | str, | ||
4704 | pck, | ||
4705 | t->hsw, t->hbp, hact, t->hfp, | ||
4706 | bl, hact, tot, | ||
4707 | TO_DISPC_T(t->hsw), | ||
4708 | TO_DISPC_T(t->hbp), | ||
4709 | TO_DISPC_T(hact), | ||
4710 | TO_DISPC_T(t->hfp), | ||
4711 | TO_DISPC_T(bl), | ||
4712 | TO_DISPC_T(hact), | ||
4713 | TO_DISPC_T(tot)); | ||
4714 | #undef TO_DISPC_T | ||
4715 | } | ||
4716 | |||
4717 | /* note: this is not quite accurate */ | ||
4718 | static void print_dsi_dispc_vm(const char *str, | ||
4719 | const struct omap_dss_dsi_videomode_timings *t) | ||
4720 | { | ||
4721 | struct omap_video_timings vm = { 0 }; | ||
4722 | unsigned long byteclk = t->hsclk / 4; | ||
4723 | unsigned long pck; | ||
4724 | u64 dsi_tput; | ||
4725 | int dsi_hact, dsi_htot; | ||
4726 | |||
4727 | dsi_tput = (u64)byteclk * t->ndl * 8; | ||
4728 | pck = (u32)div64_u64(dsi_tput, t->bitspp); | ||
4729 | dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl); | ||
4730 | dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp; | ||
4731 | |||
4732 | vm.pixel_clock = pck / 1000; | ||
4733 | vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk); | ||
4734 | vm.hbp = div64_u64((u64)t->hbp * pck, byteclk); | ||
4735 | vm.hfp = div64_u64((u64)t->hfp * pck, byteclk); | ||
4736 | vm.x_res = t->hact; | ||
4737 | |||
4738 | print_dispc_vm(str, &vm); | ||
4739 | } | ||
4740 | #endif /* PRINT_VERBOSE_VM_TIMINGS */ | ||
4741 | |||
4742 | static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | ||
4743 | unsigned long pck, void *data) | ||
4886 | { | 4744 | { |
4887 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4745 | struct dsi_clk_calc_ctx *ctx = data; |
4888 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4746 | struct omap_video_timings *t = &ctx->dispc_vm; |
4889 | 4747 | ||
4890 | mutex_lock(&dsi->lock); | 4748 | ctx->dispc_cinfo.lck_div = lckd; |
4749 | ctx->dispc_cinfo.pck_div = pckd; | ||
4750 | ctx->dispc_cinfo.lck = lck; | ||
4751 | ctx->dispc_cinfo.pck = pck; | ||
4891 | 4752 | ||
4892 | dsi->timings = *timings; | 4753 | *t = *ctx->config->timings; |
4754 | t->pixel_clock = pck / 1000; | ||
4755 | t->x_res = ctx->config->timings->x_res; | ||
4756 | t->y_res = ctx->config->timings->y_res; | ||
4757 | t->hsw = t->hfp = t->hbp = t->vsw = 1; | ||
4758 | t->vfp = t->vbp = 0; | ||
4893 | 4759 | ||
4894 | mutex_unlock(&dsi->lock); | 4760 | return true; |
4895 | } | 4761 | } |
4896 | EXPORT_SYMBOL(omapdss_dsi_set_timings); | ||
4897 | 4762 | ||
4898 | void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) | 4763 | static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, |
4764 | void *data) | ||
4899 | { | 4765 | { |
4900 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4766 | struct dsi_clk_calc_ctx *ctx = data; |
4901 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4902 | 4767 | ||
4903 | mutex_lock(&dsi->lock); | 4768 | ctx->dsi_cinfo.regm_dispc = regm_dispc; |
4769 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | ||
4904 | 4770 | ||
4905 | dsi->timings.x_res = w; | 4771 | return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, |
4906 | dsi->timings.y_res = h; | 4772 | dsi_cm_calc_dispc_cb, ctx); |
4773 | } | ||
4907 | 4774 | ||
4908 | mutex_unlock(&dsi->lock); | 4775 | static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint, |
4776 | unsigned long pll, void *data) | ||
4777 | { | ||
4778 | struct dsi_clk_calc_ctx *ctx = data; | ||
4779 | |||
4780 | ctx->dsi_cinfo.regn = regn; | ||
4781 | ctx->dsi_cinfo.regm = regm; | ||
4782 | ctx->dsi_cinfo.fint = fint; | ||
4783 | ctx->dsi_cinfo.clkin4ddr = pll; | ||
4784 | |||
4785 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, | ||
4786 | dsi_cm_calc_hsdiv_cb, ctx); | ||
4909 | } | 4787 | } |
4910 | EXPORT_SYMBOL(omapdss_dsi_set_size); | ||
4911 | 4788 | ||
4912 | void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, | 4789 | static bool dsi_cm_calc(struct dsi_data *dsi, |
4913 | enum omap_dss_dsi_pixel_format fmt) | 4790 | const struct omap_dss_dsi_config *cfg, |
4791 | struct dsi_clk_calc_ctx *ctx) | ||
4914 | { | 4792 | { |
4915 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4793 | unsigned long clkin; |
4916 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4794 | int bitspp, ndl; |
4795 | unsigned long pll_min, pll_max; | ||
4796 | unsigned long pck, txbyteclk; | ||
4917 | 4797 | ||
4918 | mutex_lock(&dsi->lock); | 4798 | clkin = clk_get_rate(dsi->sys_clk); |
4799 | bitspp = dsi_get_pixel_size(cfg->pixel_format); | ||
4800 | ndl = dsi->num_lanes_used - 1; | ||
4801 | |||
4802 | /* | ||
4803 | * Here we should calculate minimum txbyteclk to be able to send the | ||
4804 | * frame in time, and also to handle TE. That's not very simple, though, | ||
4805 | * especially as we go to LP between each pixel packet due to HW | ||
4806 | * "feature". So let's just estimate very roughly and multiply by 1.5. | ||
4807 | */ | ||
4808 | pck = cfg->timings->pixel_clock * 1000; | ||
4809 | pck = pck * 3 / 2; | ||
4810 | txbyteclk = pck * bitspp / 8 / ndl; | ||
4919 | 4811 | ||
4920 | dsi->pix_fmt = fmt; | 4812 | memset(ctx, 0, sizeof(*ctx)); |
4813 | ctx->dsidev = dsi->pdev; | ||
4814 | ctx->config = cfg; | ||
4815 | ctx->req_pck_min = pck; | ||
4816 | ctx->req_pck_nom = pck; | ||
4817 | ctx->req_pck_max = pck * 3 / 2; | ||
4818 | ctx->dsi_cinfo.clkin = clkin; | ||
4921 | 4819 | ||
4922 | mutex_unlock(&dsi->lock); | 4820 | pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4); |
4821 | pll_max = cfg->hs_clk_max * 4; | ||
4822 | |||
4823 | return dsi_pll_calc(dsi->pdev, clkin, | ||
4824 | pll_min, pll_max, | ||
4825 | dsi_cm_calc_pll_cb, ctx); | ||
4923 | } | 4826 | } |
4924 | EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); | ||
4925 | 4827 | ||
4926 | void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, | 4828 | static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) |
4927 | enum omap_dss_dsi_mode mode) | ||
4928 | { | 4829 | { |
4929 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4830 | struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); |
4930 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4831 | const struct omap_dss_dsi_config *cfg = ctx->config; |
4832 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); | ||
4833 | int ndl = dsi->num_lanes_used - 1; | ||
4834 | unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4; | ||
4835 | unsigned long byteclk = hsclk / 4; | ||
4931 | 4836 | ||
4932 | mutex_lock(&dsi->lock); | 4837 | unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max; |
4838 | int xres; | ||
4839 | int panel_htot, panel_hbl; /* pixels */ | ||
4840 | int dispc_htot, dispc_hbl; /* pixels */ | ||
4841 | int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */ | ||
4842 | int hfp, hsa, hbp; | ||
4843 | const struct omap_video_timings *req_vm; | ||
4844 | struct omap_video_timings *dispc_vm; | ||
4845 | struct omap_dss_dsi_videomode_timings *dsi_vm; | ||
4846 | u64 dsi_tput, dispc_tput; | ||
4933 | 4847 | ||
4934 | dsi->mode = mode; | 4848 | dsi_tput = (u64)byteclk * ndl * 8; |
4935 | 4849 | ||
4936 | mutex_unlock(&dsi->lock); | 4850 | req_vm = cfg->timings; |
4851 | req_pck_min = ctx->req_pck_min; | ||
4852 | req_pck_max = ctx->req_pck_max; | ||
4853 | req_pck_nom = ctx->req_pck_nom; | ||
4854 | |||
4855 | dispc_pck = ctx->dispc_cinfo.pck; | ||
4856 | dispc_tput = (u64)dispc_pck * bitspp; | ||
4857 | |||
4858 | xres = req_vm->x_res; | ||
4859 | |||
4860 | panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw; | ||
4861 | panel_htot = xres + panel_hbl; | ||
4862 | |||
4863 | dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl); | ||
4864 | |||
4865 | /* | ||
4866 | * When there are no line buffers, DISPC and DSI must have the | ||
4867 | * same tput. Otherwise DISPC tput needs to be higher than DSI's. | ||
4868 | */ | ||
4869 | if (dsi->line_buffer_size < xres * bitspp / 8) { | ||
4870 | if (dispc_tput != dsi_tput) | ||
4871 | return false; | ||
4872 | } else { | ||
4873 | if (dispc_tput < dsi_tput) | ||
4874 | return false; | ||
4875 | } | ||
4876 | |||
4877 | /* DSI tput must be over the min requirement */ | ||
4878 | if (dsi_tput < (u64)bitspp * req_pck_min) | ||
4879 | return false; | ||
4880 | |||
4881 | /* When non-burst mode, DSI tput must be below max requirement. */ | ||
4882 | if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) { | ||
4883 | if (dsi_tput > (u64)bitspp * req_pck_max) | ||
4884 | return false; | ||
4885 | } | ||
4886 | |||
4887 | hss = DIV_ROUND_UP(4, ndl); | ||
4888 | |||
4889 | if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) { | ||
4890 | if (ndl == 3 && req_vm->hsw == 0) | ||
4891 | hse = 1; | ||
4892 | else | ||
4893 | hse = DIV_ROUND_UP(4, ndl); | ||
4894 | } else { | ||
4895 | hse = 0; | ||
4896 | } | ||
4897 | |||
4898 | /* DSI htot to match the panel's nominal pck */ | ||
4899 | dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom); | ||
4900 | |||
4901 | /* fail if there would be no time for blanking */ | ||
4902 | if (dsi_htot < hss + hse + dsi_hact) | ||
4903 | return false; | ||
4904 | |||
4905 | /* total DSI blanking needed to achieve panel's TL */ | ||
4906 | dsi_hbl = dsi_htot - dsi_hact; | ||
4907 | |||
4908 | /* DISPC htot to match the DSI TL */ | ||
4909 | dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk); | ||
4910 | |||
4911 | /* verify that the DSI and DISPC TLs are the same */ | ||
4912 | if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk) | ||
4913 | return false; | ||
4914 | |||
4915 | dispc_hbl = dispc_htot - xres; | ||
4916 | |||
4917 | /* setup DSI videomode */ | ||
4918 | |||
4919 | dsi_vm = &ctx->dsi_vm; | ||
4920 | memset(dsi_vm, 0, sizeof(*dsi_vm)); | ||
4921 | |||
4922 | dsi_vm->hsclk = hsclk; | ||
4923 | |||
4924 | dsi_vm->ndl = ndl; | ||
4925 | dsi_vm->bitspp = bitspp; | ||
4926 | |||
4927 | if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) { | ||
4928 | hsa = 0; | ||
4929 | } else if (ndl == 3 && req_vm->hsw == 0) { | ||
4930 | hsa = 0; | ||
4931 | } else { | ||
4932 | hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom); | ||
4933 | hsa = max(hsa - hse, 1); | ||
4934 | } | ||
4935 | |||
4936 | hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom); | ||
4937 | hbp = max(hbp, 1); | ||
4938 | |||
4939 | hfp = dsi_hbl - (hss + hsa + hse + hbp); | ||
4940 | if (hfp < 1) { | ||
4941 | int t; | ||
4942 | /* we need to take cycles from hbp */ | ||
4943 | |||
4944 | t = 1 - hfp; | ||
4945 | hbp = max(hbp - t, 1); | ||
4946 | hfp = dsi_hbl - (hss + hsa + hse + hbp); | ||
4947 | |||
4948 | if (hfp < 1 && hsa > 0) { | ||
4949 | /* we need to take cycles from hsa */ | ||
4950 | t = 1 - hfp; | ||
4951 | hsa = max(hsa - t, 1); | ||
4952 | hfp = dsi_hbl - (hss + hsa + hse + hbp); | ||
4953 | } | ||
4954 | } | ||
4955 | |||
4956 | if (hfp < 1) | ||
4957 | return false; | ||
4958 | |||
4959 | dsi_vm->hss = hss; | ||
4960 | dsi_vm->hsa = hsa; | ||
4961 | dsi_vm->hse = hse; | ||
4962 | dsi_vm->hbp = hbp; | ||
4963 | dsi_vm->hact = xres; | ||
4964 | dsi_vm->hfp = hfp; | ||
4965 | |||
4966 | dsi_vm->vsa = req_vm->vsw; | ||
4967 | dsi_vm->vbp = req_vm->vbp; | ||
4968 | dsi_vm->vact = req_vm->y_res; | ||
4969 | dsi_vm->vfp = req_vm->vfp; | ||
4970 | |||
4971 | dsi_vm->trans_mode = cfg->trans_mode; | ||
4972 | |||
4973 | dsi_vm->blanking_mode = 0; | ||
4974 | dsi_vm->hsa_blanking_mode = 1; | ||
4975 | dsi_vm->hfp_blanking_mode = 1; | ||
4976 | dsi_vm->hbp_blanking_mode = 1; | ||
4977 | |||
4978 | dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on; | ||
4979 | dsi_vm->window_sync = 4; | ||
4980 | |||
4981 | /* setup DISPC videomode */ | ||
4982 | |||
4983 | dispc_vm = &ctx->dispc_vm; | ||
4984 | *dispc_vm = *req_vm; | ||
4985 | dispc_vm->pixel_clock = dispc_pck / 1000; | ||
4986 | |||
4987 | if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) { | ||
4988 | hsa = div64_u64((u64)req_vm->hsw * dispc_pck, | ||
4989 | req_pck_nom); | ||
4990 | hsa = max(hsa, 1); | ||
4991 | } else { | ||
4992 | hsa = 1; | ||
4993 | } | ||
4994 | |||
4995 | hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom); | ||
4996 | hbp = max(hbp, 1); | ||
4997 | |||
4998 | hfp = dispc_hbl - hsa - hbp; | ||
4999 | if (hfp < 1) { | ||
5000 | int t; | ||
5001 | /* we need to take cycles from hbp */ | ||
5002 | |||
5003 | t = 1 - hfp; | ||
5004 | hbp = max(hbp - t, 1); | ||
5005 | hfp = dispc_hbl - hsa - hbp; | ||
5006 | |||
5007 | if (hfp < 1) { | ||
5008 | /* we need to take cycles from hsa */ | ||
5009 | t = 1 - hfp; | ||
5010 | hsa = max(hsa - t, 1); | ||
5011 | hfp = dispc_hbl - hsa - hbp; | ||
5012 | } | ||
5013 | } | ||
5014 | |||
5015 | if (hfp < 1) | ||
5016 | return false; | ||
5017 | |||
5018 | dispc_vm->hfp = hfp; | ||
5019 | dispc_vm->hsw = hsa; | ||
5020 | dispc_vm->hbp = hbp; | ||
5021 | |||
5022 | return true; | ||
5023 | } | ||
5024 | |||
5025 | |||
5026 | static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | ||
5027 | unsigned long pck, void *data) | ||
5028 | { | ||
5029 | struct dsi_clk_calc_ctx *ctx = data; | ||
5030 | |||
5031 | ctx->dispc_cinfo.lck_div = lckd; | ||
5032 | ctx->dispc_cinfo.pck_div = pckd; | ||
5033 | ctx->dispc_cinfo.lck = lck; | ||
5034 | ctx->dispc_cinfo.pck = pck; | ||
5035 | |||
5036 | if (dsi_vm_calc_blanking(ctx) == false) | ||
5037 | return false; | ||
5038 | |||
5039 | #ifdef PRINT_VERBOSE_VM_TIMINGS | ||
5040 | print_dispc_vm("dispc", &ctx->dispc_vm); | ||
5041 | print_dsi_vm("dsi ", &ctx->dsi_vm); | ||
5042 | print_dispc_vm("req ", ctx->config->timings); | ||
5043 | print_dsi_dispc_vm("act ", &ctx->dsi_vm); | ||
5044 | #endif | ||
5045 | |||
5046 | return true; | ||
5047 | } | ||
5048 | |||
5049 | static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | ||
5050 | void *data) | ||
5051 | { | ||
5052 | struct dsi_clk_calc_ctx *ctx = data; | ||
5053 | unsigned long pck_max; | ||
5054 | |||
5055 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | ||
5056 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | ||
5057 | |||
5058 | /* | ||
5059 | * In burst mode we can let the dispc pck be arbitrarily high, but it | ||
5060 | * limits our scaling abilities. So for now, don't aim too high. | ||
5061 | */ | ||
5062 | |||
5063 | if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE) | ||
5064 | pck_max = ctx->req_pck_max + 10000000; | ||
5065 | else | ||
5066 | pck_max = ctx->req_pck_max; | ||
5067 | |||
5068 | return dispc_div_calc(dispc, ctx->req_pck_min, pck_max, | ||
5069 | dsi_vm_calc_dispc_cb, ctx); | ||
5070 | } | ||
5071 | |||
5072 | static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint, | ||
5073 | unsigned long pll, void *data) | ||
5074 | { | ||
5075 | struct dsi_clk_calc_ctx *ctx = data; | ||
5076 | |||
5077 | ctx->dsi_cinfo.regn = regn; | ||
5078 | ctx->dsi_cinfo.regm = regm; | ||
5079 | ctx->dsi_cinfo.fint = fint; | ||
5080 | ctx->dsi_cinfo.clkin4ddr = pll; | ||
5081 | |||
5082 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, | ||
5083 | dsi_vm_calc_hsdiv_cb, ctx); | ||
5084 | } | ||
5085 | |||
5086 | static bool dsi_vm_calc(struct dsi_data *dsi, | ||
5087 | const struct omap_dss_dsi_config *cfg, | ||
5088 | struct dsi_clk_calc_ctx *ctx) | ||
5089 | { | ||
5090 | const struct omap_video_timings *t = cfg->timings; | ||
5091 | unsigned long clkin; | ||
5092 | unsigned long pll_min; | ||
5093 | unsigned long pll_max; | ||
5094 | int ndl = dsi->num_lanes_used - 1; | ||
5095 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); | ||
5096 | unsigned long byteclk_min; | ||
5097 | |||
5098 | clkin = clk_get_rate(dsi->sys_clk); | ||
5099 | |||
5100 | memset(ctx, 0, sizeof(*ctx)); | ||
5101 | ctx->dsidev = dsi->pdev; | ||
5102 | ctx->config = cfg; | ||
5103 | |||
5104 | ctx->dsi_cinfo.clkin = clkin; | ||
5105 | |||
5106 | /* these limits should come from the panel driver */ | ||
5107 | ctx->req_pck_min = t->pixel_clock * 1000 - 1000; | ||
5108 | ctx->req_pck_nom = t->pixel_clock * 1000; | ||
5109 | ctx->req_pck_max = t->pixel_clock * 1000 + 1000; | ||
5110 | |||
5111 | byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8); | ||
5112 | pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4); | ||
5113 | |||
5114 | if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) { | ||
5115 | pll_max = cfg->hs_clk_max * 4; | ||
5116 | } else { | ||
5117 | unsigned long byteclk_max; | ||
5118 | byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp, | ||
5119 | ndl * 8); | ||
5120 | |||
5121 | pll_max = byteclk_max * 4 * 4; | ||
5122 | } | ||
5123 | |||
5124 | return dsi_pll_calc(dsi->pdev, clkin, | ||
5125 | pll_min, pll_max, | ||
5126 | dsi_vm_calc_pll_cb, ctx); | ||
4937 | } | 5127 | } |
4938 | EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); | ||
4939 | 5128 | ||
4940 | void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, | 5129 | int omapdss_dsi_set_config(struct omap_dss_device *dssdev, |
4941 | struct omap_dss_dsi_videomode_timings *timings) | 5130 | const struct omap_dss_dsi_config *config) |
4942 | { | 5131 | { |
4943 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 5132 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4944 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 5133 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
5134 | struct dsi_clk_calc_ctx ctx; | ||
5135 | bool ok; | ||
5136 | int r; | ||
4945 | 5137 | ||
4946 | mutex_lock(&dsi->lock); | 5138 | mutex_lock(&dsi->lock); |
4947 | 5139 | ||
4948 | dsi->vm_timings = *timings; | 5140 | dsi->pix_fmt = config->pixel_format; |
5141 | dsi->mode = config->mode; | ||
5142 | |||
5143 | if (config->mode == OMAP_DSS_DSI_VIDEO_MODE) | ||
5144 | ok = dsi_vm_calc(dsi, config, &ctx); | ||
5145 | else | ||
5146 | ok = dsi_cm_calc(dsi, config, &ctx); | ||
5147 | |||
5148 | if (!ok) { | ||
5149 | DSSERR("failed to find suitable DSI clock settings\n"); | ||
5150 | r = -EINVAL; | ||
5151 | goto err; | ||
5152 | } | ||
5153 | |||
5154 | dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo); | ||
5155 | |||
5156 | r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min, | ||
5157 | config->lp_clk_max); | ||
5158 | if (r) { | ||
5159 | DSSERR("failed to find suitable DSI LP clock settings\n"); | ||
5160 | goto err; | ||
5161 | } | ||
5162 | |||
5163 | dsi->user_dsi_cinfo = ctx.dsi_cinfo; | ||
5164 | dsi->user_dispc_cinfo = ctx.dispc_cinfo; | ||
5165 | |||
5166 | dsi->timings = ctx.dispc_vm; | ||
5167 | dsi->vm_timings = ctx.dsi_vm; | ||
4949 | 5168 | ||
4950 | mutex_unlock(&dsi->lock); | 5169 | mutex_unlock(&dsi->lock); |
5170 | |||
5171 | return 0; | ||
5172 | err: | ||
5173 | mutex_unlock(&dsi->lock); | ||
5174 | |||
5175 | return r; | ||
5176 | } | ||
5177 | EXPORT_SYMBOL(omapdss_dsi_set_config); | ||
5178 | |||
5179 | /* | ||
5180 | * Return a hardcoded channel for the DSI output. This should work for | ||
5181 | * current use cases, but this can be later expanded to either resolve | ||
5182 | * the channel in some more dynamic manner, or get the channel as a user | ||
5183 | * parameter. | ||
5184 | */ | ||
5185 | static enum omap_channel dsi_get_channel(int module_id) | ||
5186 | { | ||
5187 | switch (omapdss_get_version()) { | ||
5188 | case OMAPDSS_VER_OMAP24xx: | ||
5189 | DSSWARN("DSI not supported\n"); | ||
5190 | return OMAP_DSS_CHANNEL_LCD; | ||
5191 | |||
5192 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
5193 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
5194 | case OMAPDSS_VER_OMAP3630: | ||
5195 | case OMAPDSS_VER_AM35xx: | ||
5196 | return OMAP_DSS_CHANNEL_LCD; | ||
5197 | |||
5198 | case OMAPDSS_VER_OMAP4430_ES1: | ||
5199 | case OMAPDSS_VER_OMAP4430_ES2: | ||
5200 | case OMAPDSS_VER_OMAP4: | ||
5201 | switch (module_id) { | ||
5202 | case 0: | ||
5203 | return OMAP_DSS_CHANNEL_LCD; | ||
5204 | case 1: | ||
5205 | return OMAP_DSS_CHANNEL_LCD2; | ||
5206 | default: | ||
5207 | DSSWARN("unsupported module id\n"); | ||
5208 | return OMAP_DSS_CHANNEL_LCD; | ||
5209 | } | ||
5210 | |||
5211 | case OMAPDSS_VER_OMAP5: | ||
5212 | switch (module_id) { | ||
5213 | case 0: | ||
5214 | return OMAP_DSS_CHANNEL_LCD; | ||
5215 | case 1: | ||
5216 | return OMAP_DSS_CHANNEL_LCD3; | ||
5217 | default: | ||
5218 | DSSWARN("unsupported module id\n"); | ||
5219 | return OMAP_DSS_CHANNEL_LCD; | ||
5220 | } | ||
5221 | |||
5222 | default: | ||
5223 | DSSWARN("unsupported DSS version\n"); | ||
5224 | return OMAP_DSS_CHANNEL_LCD; | ||
5225 | } | ||
4951 | } | 5226 | } |
4952 | EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings); | ||
4953 | 5227 | ||
4954 | static int __init dsi_init_display(struct omap_dss_device *dssdev) | 5228 | static int __init dsi_init_display(struct omap_dss_device *dssdev) |
4955 | { | 5229 | { |
@@ -5073,7 +5347,7 @@ static int dsi_get_clocks(struct platform_device *dsidev) | |||
5073 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 5347 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
5074 | struct clk *clk; | 5348 | struct clk *clk; |
5075 | 5349 | ||
5076 | clk = clk_get(&dsidev->dev, "fck"); | 5350 | clk = devm_clk_get(&dsidev->dev, "fck"); |
5077 | if (IS_ERR(clk)) { | 5351 | if (IS_ERR(clk)) { |
5078 | DSSERR("can't get fck\n"); | 5352 | DSSERR("can't get fck\n"); |
5079 | return PTR_ERR(clk); | 5353 | return PTR_ERR(clk); |
@@ -5081,11 +5355,9 @@ static int dsi_get_clocks(struct platform_device *dsidev) | |||
5081 | 5355 | ||
5082 | dsi->dss_clk = clk; | 5356 | dsi->dss_clk = clk; |
5083 | 5357 | ||
5084 | clk = clk_get(&dsidev->dev, "sys_clk"); | 5358 | clk = devm_clk_get(&dsidev->dev, "sys_clk"); |
5085 | if (IS_ERR(clk)) { | 5359 | if (IS_ERR(clk)) { |
5086 | DSSERR("can't get sys_clk\n"); | 5360 | DSSERR("can't get sys_clk\n"); |
5087 | clk_put(dsi->dss_clk); | ||
5088 | dsi->dss_clk = NULL; | ||
5089 | return PTR_ERR(clk); | 5361 | return PTR_ERR(clk); |
5090 | } | 5362 | } |
5091 | 5363 | ||
@@ -5094,16 +5366,6 @@ static int dsi_get_clocks(struct platform_device *dsidev) | |||
5094 | return 0; | 5366 | return 0; |
5095 | } | 5367 | } |
5096 | 5368 | ||
5097 | static void dsi_put_clocks(struct platform_device *dsidev) | ||
5098 | { | ||
5099 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
5100 | |||
5101 | if (dsi->dss_clk) | ||
5102 | clk_put(dsi->dss_clk); | ||
5103 | if (dsi->sys_clk) | ||
5104 | clk_put(dsi->sys_clk); | ||
5105 | } | ||
5106 | |||
5107 | static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) | 5369 | static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) |
5108 | { | 5370 | { |
5109 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 5371 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
@@ -5188,6 +5450,8 @@ static void __init dsi_init_output(struct platform_device *dsidev) | |||
5188 | OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; | 5450 | OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; |
5189 | 5451 | ||
5190 | out->type = OMAP_DISPLAY_TYPE_DSI; | 5452 | out->type = OMAP_DISPLAY_TYPE_DSI; |
5453 | out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; | ||
5454 | out->dispc_channel = dsi_get_channel(dsi->module_id); | ||
5191 | 5455 | ||
5192 | dss_register_output(out); | 5456 | dss_register_output(out); |
5193 | } | 5457 | } |
@@ -5293,6 +5557,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) | |||
5293 | else | 5557 | else |
5294 | dsi->num_lanes_supported = 3; | 5558 | dsi->num_lanes_supported = 3; |
5295 | 5559 | ||
5560 | dsi->line_buffer_size = dsi_get_line_buf_size(dsidev); | ||
5561 | |||
5296 | dsi_init_output(dsidev); | 5562 | dsi_init_output(dsidev); |
5297 | 5563 | ||
5298 | dsi_probe_pdata(dsidev); | 5564 | dsi_probe_pdata(dsidev); |
@@ -5314,7 +5580,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) | |||
5314 | 5580 | ||
5315 | err_runtime_get: | 5581 | err_runtime_get: |
5316 | pm_runtime_disable(&dsidev->dev); | 5582 | pm_runtime_disable(&dsidev->dev); |
5317 | dsi_put_clocks(dsidev); | ||
5318 | return r; | 5583 | return r; |
5319 | } | 5584 | } |
5320 | 5585 | ||
@@ -5330,8 +5595,6 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) | |||
5330 | 5595 | ||
5331 | pm_runtime_disable(&dsidev->dev); | 5596 | pm_runtime_disable(&dsidev->dev); |
5332 | 5597 | ||
5333 | dsi_put_clocks(dsidev); | ||
5334 | |||
5335 | if (dsi->vdds_dsi_reg != NULL) { | 5598 | if (dsi->vdds_dsi_reg != NULL) { |
5336 | if (dsi->vdds_dsi_enabled) { | 5599 | if (dsi->vdds_dsi_enabled) { |
5337 | regulator_disable(dsi->vdds_dsi_reg); | 5600 | regulator_disable(dsi->vdds_dsi_reg); |
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 054c2a22b3f1..94f66f9f10a3 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
@@ -473,6 +473,47 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) | |||
473 | return 0; | 473 | return 0; |
474 | } | 474 | } |
475 | 475 | ||
476 | bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data) | ||
477 | { | ||
478 | int fckd, fckd_start, fckd_stop; | ||
479 | unsigned long fck; | ||
480 | unsigned long fck_hw_max; | ||
481 | unsigned long fckd_hw_max; | ||
482 | unsigned long prate; | ||
483 | unsigned m; | ||
484 | |||
485 | if (dss.dpll4_m4_ck == NULL) { | ||
486 | /* | ||
487 | * TODO: dss1_fclk can be changed on OMAP2, but the available | ||
488 | * dividers are not continuous. We just use the pre-set rate for | ||
489 | * now. | ||
490 | */ | ||
491 | fck = clk_get_rate(dss.dss_clk); | ||
492 | fckd = 1; | ||
493 | return func(fckd, fck, data); | ||
494 | } | ||
495 | |||
496 | fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
497 | fckd_hw_max = dss.feat->fck_div_max; | ||
498 | |||
499 | m = dss.feat->dss_fck_multiplier; | ||
500 | prate = dss_get_dpll4_rate(); | ||
501 | |||
502 | fck_min = fck_min ? fck_min : 1; | ||
503 | |||
504 | fckd_start = min(prate * m / fck_min, fckd_hw_max); | ||
505 | fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul); | ||
506 | |||
507 | for (fckd = fckd_start; fckd >= fckd_stop; --fckd) { | ||
508 | fck = prate / fckd * m; | ||
509 | |||
510 | if (func(fckd, fck, data)) | ||
511 | return true; | ||
512 | } | ||
513 | |||
514 | return false; | ||
515 | } | ||
516 | |||
476 | int dss_set_clock_div(struct dss_clock_info *cinfo) | 517 | int dss_set_clock_div(struct dss_clock_info *cinfo) |
477 | { | 518 | { |
478 | if (dss.dpll4_m4_ck) { | 519 | if (dss.dpll4_m4_ck) { |
@@ -482,7 +523,8 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) | |||
482 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | 523 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); |
483 | DSSDBG("dpll4_m4 = %ld\n", prate); | 524 | DSSDBG("dpll4_m4 = %ld\n", prate); |
484 | 525 | ||
485 | r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); | 526 | r = clk_set_rate(dss.dpll4_m4_ck, |
527 | DIV_ROUND_UP(prate, cinfo->fck_div)); | ||
486 | if (r) | 528 | if (r) |
487 | return r; | 529 | return r; |
488 | } else { | 530 | } else { |
@@ -492,7 +534,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) | |||
492 | 534 | ||
493 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); | 535 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); |
494 | 536 | ||
495 | WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); | 537 | WARN_ONCE(dss.dss_clk_rate != cinfo->fck, |
538 | "clk rate mismatch: %lu != %lu", dss.dss_clk_rate, | ||
539 | cinfo->fck); | ||
496 | 540 | ||
497 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); | 541 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); |
498 | 542 | ||
@@ -542,121 +586,6 @@ static int dss_setup_default_clock(void) | |||
542 | return 0; | 586 | return 0; |
543 | } | 587 | } |
544 | 588 | ||
545 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | ||
546 | struct dispc_clock_info *dispc_cinfo) | ||
547 | { | ||
548 | unsigned long prate; | ||
549 | struct dss_clock_info best_dss; | ||
550 | struct dispc_clock_info best_dispc; | ||
551 | |||
552 | unsigned long fck, max_dss_fck; | ||
553 | |||
554 | u16 fck_div; | ||
555 | |||
556 | int match = 0; | ||
557 | int min_fck_per_pck; | ||
558 | |||
559 | prate = dss_get_dpll4_rate(); | ||
560 | |||
561 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
562 | |||
563 | fck = clk_get_rate(dss.dss_clk); | ||
564 | if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && | ||
565 | dss.cache_dss_cinfo.fck == fck) { | ||
566 | DSSDBG("dispc clock info found from cache.\n"); | ||
567 | *dss_cinfo = dss.cache_dss_cinfo; | ||
568 | *dispc_cinfo = dss.cache_dispc_cinfo; | ||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; | ||
573 | |||
574 | if (min_fck_per_pck && | ||
575 | req_pck * min_fck_per_pck > max_dss_fck) { | ||
576 | DSSERR("Requested pixel clock not possible with the current " | ||
577 | "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " | ||
578 | "the constraint off.\n"); | ||
579 | min_fck_per_pck = 0; | ||
580 | } | ||
581 | |||
582 | retry: | ||
583 | memset(&best_dss, 0, sizeof(best_dss)); | ||
584 | memset(&best_dispc, 0, sizeof(best_dispc)); | ||
585 | |||
586 | if (dss.dpll4_m4_ck == NULL) { | ||
587 | struct dispc_clock_info cur_dispc; | ||
588 | /* XXX can we change the clock on omap2? */ | ||
589 | fck = clk_get_rate(dss.dss_clk); | ||
590 | fck_div = 1; | ||
591 | |||
592 | dispc_find_clk_divs(req_pck, fck, &cur_dispc); | ||
593 | match = 1; | ||
594 | |||
595 | best_dss.fck = fck; | ||
596 | best_dss.fck_div = fck_div; | ||
597 | |||
598 | best_dispc = cur_dispc; | ||
599 | |||
600 | goto found; | ||
601 | } else { | ||
602 | for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { | ||
603 | struct dispc_clock_info cur_dispc; | ||
604 | |||
605 | fck = prate / fck_div * dss.feat->dss_fck_multiplier; | ||
606 | |||
607 | if (fck > max_dss_fck) | ||
608 | continue; | ||
609 | |||
610 | if (min_fck_per_pck && | ||
611 | fck < req_pck * min_fck_per_pck) | ||
612 | continue; | ||
613 | |||
614 | match = 1; | ||
615 | |||
616 | dispc_find_clk_divs(req_pck, fck, &cur_dispc); | ||
617 | |||
618 | if (abs(cur_dispc.pck - req_pck) < | ||
619 | abs(best_dispc.pck - req_pck)) { | ||
620 | |||
621 | best_dss.fck = fck; | ||
622 | best_dss.fck_div = fck_div; | ||
623 | |||
624 | best_dispc = cur_dispc; | ||
625 | |||
626 | if (cur_dispc.pck == req_pck) | ||
627 | goto found; | ||
628 | } | ||
629 | } | ||
630 | } | ||
631 | |||
632 | found: | ||
633 | if (!match) { | ||
634 | if (min_fck_per_pck) { | ||
635 | DSSERR("Could not find suitable clock settings.\n" | ||
636 | "Turning FCK/PCK constraint off and" | ||
637 | "trying again.\n"); | ||
638 | min_fck_per_pck = 0; | ||
639 | goto retry; | ||
640 | } | ||
641 | |||
642 | DSSERR("Could not find suitable clock settings.\n"); | ||
643 | |||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
647 | if (dss_cinfo) | ||
648 | *dss_cinfo = best_dss; | ||
649 | if (dispc_cinfo) | ||
650 | *dispc_cinfo = best_dispc; | ||
651 | |||
652 | dss.cache_req_pck = req_pck; | ||
653 | dss.cache_prate = prate; | ||
654 | dss.cache_dss_cinfo = best_dss; | ||
655 | dss.cache_dispc_cinfo = best_dispc; | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | void dss_set_venc_output(enum omap_dss_venc_type type) | 589 | void dss_set_venc_output(enum omap_dss_venc_type type) |
661 | { | 590 | { |
662 | int l = 0; | 591 | int l = 0; |
@@ -767,13 +696,11 @@ int dss_dpi_select_source(enum omap_channel channel) | |||
767 | static int dss_get_clocks(void) | 696 | static int dss_get_clocks(void) |
768 | { | 697 | { |
769 | struct clk *clk; | 698 | struct clk *clk; |
770 | int r; | ||
771 | 699 | ||
772 | clk = clk_get(&dss.pdev->dev, "fck"); | 700 | clk = devm_clk_get(&dss.pdev->dev, "fck"); |
773 | if (IS_ERR(clk)) { | 701 | if (IS_ERR(clk)) { |
774 | DSSERR("can't get clock fck\n"); | 702 | DSSERR("can't get clock fck\n"); |
775 | r = PTR_ERR(clk); | 703 | return PTR_ERR(clk); |
776 | goto err; | ||
777 | } | 704 | } |
778 | 705 | ||
779 | dss.dss_clk = clk; | 706 | dss.dss_clk = clk; |
@@ -782,8 +709,7 @@ static int dss_get_clocks(void) | |||
782 | clk = clk_get(NULL, dss.feat->clk_name); | 709 | clk = clk_get(NULL, dss.feat->clk_name); |
783 | if (IS_ERR(clk)) { | 710 | if (IS_ERR(clk)) { |
784 | DSSERR("Failed to get %s\n", dss.feat->clk_name); | 711 | DSSERR("Failed to get %s\n", dss.feat->clk_name); |
785 | r = PTR_ERR(clk); | 712 | return PTR_ERR(clk); |
786 | goto err; | ||
787 | } | 713 | } |
788 | } else { | 714 | } else { |
789 | clk = NULL; | 715 | clk = NULL; |
@@ -792,21 +718,12 @@ static int dss_get_clocks(void) | |||
792 | dss.dpll4_m4_ck = clk; | 718 | dss.dpll4_m4_ck = clk; |
793 | 719 | ||
794 | return 0; | 720 | return 0; |
795 | |||
796 | err: | ||
797 | if (dss.dss_clk) | ||
798 | clk_put(dss.dss_clk); | ||
799 | if (dss.dpll4_m4_ck) | ||
800 | clk_put(dss.dpll4_m4_ck); | ||
801 | |||
802 | return r; | ||
803 | } | 721 | } |
804 | 722 | ||
805 | static void dss_put_clocks(void) | 723 | static void dss_put_clocks(void) |
806 | { | 724 | { |
807 | if (dss.dpll4_m4_ck) | 725 | if (dss.dpll4_m4_ck) |
808 | clk_put(dss.dpll4_m4_ck); | 726 | clk_put(dss.dpll4_m4_ck); |
809 | clk_put(dss.dss_clk); | ||
810 | } | 727 | } |
811 | 728 | ||
812 | static int dss_runtime_get(void) | 729 | static int dss_runtime_get(void) |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 610c8e563daa..faaf35857b0e 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -268,8 +268,9 @@ void dss_set_dac_pwrdn_bgz(bool enable); | |||
268 | unsigned long dss_get_dpll4_rate(void); | 268 | unsigned long dss_get_dpll4_rate(void); |
269 | int dss_calc_clock_rates(struct dss_clock_info *cinfo); | 269 | int dss_calc_clock_rates(struct dss_clock_info *cinfo); |
270 | int dss_set_clock_div(struct dss_clock_info *cinfo); | 270 | int dss_set_clock_div(struct dss_clock_info *cinfo); |
271 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | 271 | |
272 | struct dispc_clock_info *dispc_cinfo); | 272 | typedef bool (*dss_div_calc_func)(int fckd, unsigned long fck, void *data); |
273 | bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data); | ||
273 | 274 | ||
274 | /* SDI */ | 275 | /* SDI */ |
275 | int sdi_init_platform_driver(void) __init; | 276 | int sdi_init_platform_driver(void) __init; |
@@ -292,12 +293,21 @@ void dsi_dump_clocks(struct seq_file *s); | |||
292 | void dsi_irq_handler(void); | 293 | void dsi_irq_handler(void); |
293 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); | 294 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); |
294 | 295 | ||
296 | unsigned long dsi_get_pll_clkin(struct platform_device *dsidev); | ||
297 | |||
298 | typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint, | ||
299 | unsigned long pll, void *data); | ||
300 | typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc, | ||
301 | void *data); | ||
302 | bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll, | ||
303 | unsigned long out_min, dsi_hsdiv_calc_func func, void *data); | ||
304 | bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin, | ||
305 | unsigned long pll_min, unsigned long pll_max, | ||
306 | dsi_pll_calc_func func, void *data); | ||
307 | |||
295 | unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); | 308 | unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); |
296 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | 309 | int dsi_pll_set_clock_div(struct platform_device *dsidev, |
297 | struct dsi_clock_info *cinfo); | 310 | struct dsi_clock_info *cinfo); |
298 | int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, | ||
299 | unsigned long req_pck, struct dsi_clock_info *cinfo, | ||
300 | struct dispc_clock_info *dispc_cinfo); | ||
301 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | 311 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, |
302 | bool enable_hsdiv); | 312 | bool enable_hsdiv); |
303 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); | 313 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); |
@@ -328,14 +338,6 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
328 | WARN("%s: DSI not compiled in\n", __func__); | 338 | WARN("%s: DSI not compiled in\n", __func__); |
329 | return -ENODEV; | 339 | return -ENODEV; |
330 | } | 340 | } |
331 | static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, | ||
332 | unsigned long req_pck, | ||
333 | struct dsi_clock_info *dsi_cinfo, | ||
334 | struct dispc_clock_info *dispc_cinfo) | ||
335 | { | ||
336 | WARN("%s: DSI not compiled in\n", __func__); | ||
337 | return -ENODEV; | ||
338 | } | ||
339 | static inline int dsi_pll_init(struct platform_device *dsidev, | 341 | static inline int dsi_pll_init(struct platform_device *dsidev, |
340 | bool enable_hsclk, bool enable_hsdiv) | 342 | bool enable_hsclk, bool enable_hsdiv) |
341 | { | 343 | { |
@@ -376,11 +378,15 @@ void dispc_enable_fifomerge(bool enable); | |||
376 | void dispc_enable_gamma_table(bool enable); | 378 | void dispc_enable_gamma_table(bool enable); |
377 | void dispc_set_loadmode(enum omap_dss_load_mode mode); | 379 | void dispc_set_loadmode(enum omap_dss_load_mode mode); |
378 | 380 | ||
381 | typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, | ||
382 | unsigned long pck, void *data); | ||
383 | bool dispc_div_calc(unsigned long dispc, | ||
384 | unsigned long pck_min, unsigned long pck_max, | ||
385 | dispc_div_calc_func func, void *data); | ||
386 | |||
379 | bool dispc_mgr_timings_ok(enum omap_channel channel, | 387 | bool dispc_mgr_timings_ok(enum omap_channel channel, |
380 | const struct omap_video_timings *timings); | 388 | const struct omap_video_timings *timings); |
381 | unsigned long dispc_fclk_rate(void); | 389 | unsigned long dispc_fclk_rate(void); |
382 | void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, | ||
383 | struct dispc_clock_info *cinfo); | ||
384 | int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | 390 | int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, |
385 | struct dispc_clock_info *cinfo); | 391 | struct dispc_clock_info *cinfo); |
386 | 392 | ||
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 7f791aeda4d2..77dbe0cfb34c 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -414,7 +414,7 @@ static const char * const omap5_dss_clk_source_names[] = { | |||
414 | }; | 414 | }; |
415 | 415 | ||
416 | static const struct dss_param_range omap2_dss_param_range[] = { | 416 | static const struct dss_param_range omap2_dss_param_range[] = { |
417 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, | 417 | [FEAT_PARAM_DSS_FCK] = { 0, 133000000 }, |
418 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, | 418 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, |
419 | [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, | 419 | [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, |
420 | [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, | 420 | [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, |
@@ -459,15 +459,15 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
459 | }; | 459 | }; |
460 | 460 | ||
461 | static const struct dss_param_range omap5_dss_param_range[] = { | 461 | static const struct dss_param_range omap5_dss_param_range[] = { |
462 | [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, | 462 | [FEAT_PARAM_DSS_FCK] = { 0, 209250000 }, |
463 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | 463 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, |
464 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, | 464 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, |
465 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, | 465 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, |
466 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, | 466 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, |
467 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, | 467 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, |
468 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | 468 | [FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 }, |
469 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 469 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
470 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | 470 | [FEAT_PARAM_DSI_FCK] = { 0, 209250000 }, |
471 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 471 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
472 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | 472 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, |
473 | }; | 473 | }; |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 72923645dcce..79393099d505 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -472,17 +472,12 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | |||
472 | * Input clock is predivided by N + 1 | 472 | * Input clock is predivided by N + 1 |
473 | * out put of which is reference clk | 473 | * out put of which is reference clk |
474 | */ | 474 | */ |
475 | if (dssdev->clocks.hdmi.regn == 0) | 475 | |
476 | pi->regn = HDMI_DEFAULT_REGN; | 476 | pi->regn = HDMI_DEFAULT_REGN; |
477 | else | ||
478 | pi->regn = dssdev->clocks.hdmi.regn; | ||
479 | 477 | ||
480 | refclk = clkin / pi->regn; | 478 | refclk = clkin / pi->regn; |
481 | 479 | ||
482 | if (dssdev->clocks.hdmi.regm2 == 0) | 480 | pi->regm2 = HDMI_DEFAULT_REGM2; |
483 | pi->regm2 = HDMI_DEFAULT_REGM2; | ||
484 | else | ||
485 | pi->regm2 = dssdev->clocks.hdmi.regm2; | ||
486 | 481 | ||
487 | /* | 482 | /* |
488 | * multiplier is pixel_clk/ref_clk | 483 | * multiplier is pixel_clk/ref_clk |
@@ -804,7 +799,7 @@ static int hdmi_get_clocks(struct platform_device *pdev) | |||
804 | { | 799 | { |
805 | struct clk *clk; | 800 | struct clk *clk; |
806 | 801 | ||
807 | clk = clk_get(&pdev->dev, "sys_clk"); | 802 | clk = devm_clk_get(&pdev->dev, "sys_clk"); |
808 | if (IS_ERR(clk)) { | 803 | if (IS_ERR(clk)) { |
809 | DSSERR("can't get sys_clk\n"); | 804 | DSSERR("can't get sys_clk\n"); |
810 | return PTR_ERR(clk); | 805 | return PTR_ERR(clk); |
@@ -815,12 +810,6 @@ static int hdmi_get_clocks(struct platform_device *pdev) | |||
815 | return 0; | 810 | return 0; |
816 | } | 811 | } |
817 | 812 | ||
818 | static void hdmi_put_clocks(void) | ||
819 | { | ||
820 | if (hdmi.sys_clk) | ||
821 | clk_put(hdmi.sys_clk); | ||
822 | } | ||
823 | |||
824 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | 813 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) |
825 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts) | 814 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts) |
826 | { | 815 | { |
@@ -1017,8 +1006,6 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) | |||
1017 | hdmi.ls_oe_gpio = priv->ls_oe_gpio; | 1006 | hdmi.ls_oe_gpio = priv->ls_oe_gpio; |
1018 | hdmi.hpd_gpio = priv->hpd_gpio; | 1007 | hdmi.hpd_gpio = priv->hpd_gpio; |
1019 | 1008 | ||
1020 | dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; | ||
1021 | |||
1022 | r = hdmi_init_display(dssdev); | 1009 | r = hdmi_init_display(dssdev); |
1023 | if (r) { | 1010 | if (r) { |
1024 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 1011 | DSSERR("device %s init failed: %d\n", dssdev->name, r); |
@@ -1051,6 +1038,8 @@ static void __init hdmi_init_output(struct platform_device *pdev) | |||
1051 | out->pdev = pdev; | 1038 | out->pdev = pdev; |
1052 | out->id = OMAP_DSS_OUTPUT_HDMI; | 1039 | out->id = OMAP_DSS_OUTPUT_HDMI; |
1053 | out->type = OMAP_DISPLAY_TYPE_HDMI; | 1040 | out->type = OMAP_DISPLAY_TYPE_HDMI; |
1041 | out->name = "hdmi.0"; | ||
1042 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; | ||
1054 | 1043 | ||
1055 | dss_register_output(out); | 1044 | dss_register_output(out); |
1056 | } | 1045 | } |
@@ -1097,23 +1086,19 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1097 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | 1086 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; |
1098 | hdmi.ip_data.phy_offset = HDMI_PHY; | 1087 | hdmi.ip_data.phy_offset = HDMI_PHY; |
1099 | 1088 | ||
1089 | hdmi_init_output(pdev); | ||
1090 | |||
1100 | r = hdmi_panel_init(); | 1091 | r = hdmi_panel_init(); |
1101 | if (r) { | 1092 | if (r) { |
1102 | DSSERR("can't init panel\n"); | 1093 | DSSERR("can't init panel\n"); |
1103 | goto err_panel_init; | 1094 | return r; |
1104 | } | 1095 | } |
1105 | 1096 | ||
1106 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 1097 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
1107 | 1098 | ||
1108 | hdmi_init_output(pdev); | ||
1109 | |||
1110 | hdmi_probe_pdata(pdev); | 1099 | hdmi_probe_pdata(pdev); |
1111 | 1100 | ||
1112 | return 0; | 1101 | return 0; |
1113 | |||
1114 | err_panel_init: | ||
1115 | hdmi_put_clocks(); | ||
1116 | return r; | ||
1117 | } | 1102 | } |
1118 | 1103 | ||
1119 | static int __exit hdmi_remove_child(struct device *dev, void *data) | 1104 | static int __exit hdmi_remove_child(struct device *dev, void *data) |
@@ -1135,8 +1120,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | |||
1135 | 1120 | ||
1136 | pm_runtime_disable(&pdev->dev); | 1121 | pm_runtime_disable(&pdev->dev); |
1137 | 1122 | ||
1138 | hdmi_put_clocks(); | ||
1139 | |||
1140 | return 0; | 1123 | return 0; |
1141 | } | 1124 | } |
1142 | 1125 | ||
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c index 79dea1a1a732..5214df63e0a9 100644 --- a/drivers/video/omap2/dss/output.c +++ b/drivers/video/omap2/dss/output.c | |||
@@ -113,6 +113,7 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) | |||
113 | 113 | ||
114 | return NULL; | 114 | return NULL; |
115 | } | 115 | } |
116 | EXPORT_SYMBOL(omap_dss_get_output); | ||
116 | 117 | ||
117 | static const struct dss_mgr_ops *dss_mgr_ops; | 118 | static const struct dss_mgr_ops *dss_mgr_ops; |
118 | 119 | ||
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index e903dd3f54d9..1a691bb27547 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
@@ -1025,6 +1025,8 @@ static void __init rfbi_init_output(struct platform_device *pdev) | |||
1025 | out->pdev = pdev; | 1025 | out->pdev = pdev; |
1026 | out->id = OMAP_DSS_OUTPUT_DBI; | 1026 | out->id = OMAP_DSS_OUTPUT_DBI; |
1027 | out->type = OMAP_DISPLAY_TYPE_DBI; | 1027 | out->type = OMAP_DISPLAY_TYPE_DBI; |
1028 | out->name = "rfbi.0"; | ||
1029 | out->dispc_channel = OMAP_DSS_CHANNEL_LCD; | ||
1028 | 1030 | ||
1029 | dss_register_output(out); | 1031 | dss_register_output(out); |
1030 | } | 1032 | } |
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 62b5374ce438..e6baee2e84f8 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
@@ -41,6 +41,72 @@ static struct { | |||
41 | struct omap_dss_output output; | 41 | struct omap_dss_output output; |
42 | } sdi; | 42 | } sdi; |
43 | 43 | ||
44 | struct sdi_clk_calc_ctx { | ||
45 | unsigned long pck_min, pck_max; | ||
46 | |||
47 | struct dss_clock_info dss_cinfo; | ||
48 | struct dispc_clock_info dispc_cinfo; | ||
49 | }; | ||
50 | |||
51 | static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | ||
52 | unsigned long pck, void *data) | ||
53 | { | ||
54 | struct sdi_clk_calc_ctx *ctx = data; | ||
55 | |||
56 | ctx->dispc_cinfo.lck_div = lckd; | ||
57 | ctx->dispc_cinfo.pck_div = pckd; | ||
58 | ctx->dispc_cinfo.lck = lck; | ||
59 | ctx->dispc_cinfo.pck = pck; | ||
60 | |||
61 | return true; | ||
62 | } | ||
63 | |||
64 | static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data) | ||
65 | { | ||
66 | struct sdi_clk_calc_ctx *ctx = data; | ||
67 | |||
68 | ctx->dss_cinfo.fck = fck; | ||
69 | ctx->dss_cinfo.fck_div = fckd; | ||
70 | |||
71 | return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, | ||
72 | dpi_calc_dispc_cb, ctx); | ||
73 | } | ||
74 | |||
75 | static int sdi_calc_clock_div(unsigned long pclk, | ||
76 | struct dss_clock_info *dss_cinfo, | ||
77 | struct dispc_clock_info *dispc_cinfo) | ||
78 | { | ||
79 | int i; | ||
80 | struct sdi_clk_calc_ctx ctx; | ||
81 | |||
82 | /* | ||
83 | * DSS fclk gives us very few possibilities, so finding a good pixel | ||
84 | * clock may not be possible. We try multiple times to find the clock, | ||
85 | * each time widening the pixel clock range we look for, up to | ||
86 | * +/- 1MHz. | ||
87 | */ | ||
88 | |||
89 | for (i = 0; i < 10; ++i) { | ||
90 | bool ok; | ||
91 | |||
92 | memset(&ctx, 0, sizeof(ctx)); | ||
93 | if (pclk > 1000 * i * i * i) | ||
94 | ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu); | ||
95 | else | ||
96 | ctx.pck_min = 0; | ||
97 | ctx.pck_max = pclk + 1000 * i * i * i; | ||
98 | |||
99 | ok = dss_div_calc(ctx.pck_min, dpi_calc_dss_cb, &ctx); | ||
100 | if (ok) { | ||
101 | *dss_cinfo = ctx.dss_cinfo; | ||
102 | *dispc_cinfo = ctx.dispc_cinfo; | ||
103 | return 0; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | return -EINVAL; | ||
108 | } | ||
109 | |||
44 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) | 110 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) |
45 | { | 111 | { |
46 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 112 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
@@ -88,7 +154,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
88 | t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 154 | t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; |
89 | t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 155 | t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; |
90 | 156 | ||
91 | r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); | 157 | r = sdi_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); |
92 | if (r) | 158 | if (r) |
93 | goto err_calc_clock_div; | 159 | goto err_calc_clock_div; |
94 | 160 | ||
@@ -278,6 +344,8 @@ static void __init sdi_init_output(struct platform_device *pdev) | |||
278 | out->pdev = pdev; | 344 | out->pdev = pdev; |
279 | out->id = OMAP_DSS_OUTPUT_SDI; | 345 | out->id = OMAP_DSS_OUTPUT_SDI; |
280 | out->type = OMAP_DISPLAY_TYPE_SDI; | 346 | out->type = OMAP_DISPLAY_TYPE_SDI; |
347 | out->name = "sdi.0"; | ||
348 | out->dispc_channel = OMAP_DSS_CHANNEL_LCD; | ||
281 | 349 | ||
282 | dss_register_output(out); | 350 | dss_register_output(out); |
283 | } | 351 | } |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 006caf3cb509..17764d136398 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
@@ -519,10 +519,6 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev) | |||
519 | goto err0; | 519 | goto err0; |
520 | } | 520 | } |
521 | 521 | ||
522 | if (dssdev->platform_enable) | ||
523 | dssdev->platform_enable(dssdev); | ||
524 | |||
525 | |||
526 | r = venc_power_on(dssdev); | 522 | r = venc_power_on(dssdev); |
527 | if (r) | 523 | if (r) |
528 | goto err1; | 524 | goto err1; |
@@ -533,8 +529,6 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev) | |||
533 | 529 | ||
534 | return 0; | 530 | return 0; |
535 | err1: | 531 | err1: |
536 | if (dssdev->platform_disable) | ||
537 | dssdev->platform_disable(dssdev); | ||
538 | omap_dss_stop_device(dssdev); | 532 | omap_dss_stop_device(dssdev); |
539 | err0: | 533 | err0: |
540 | mutex_unlock(&venc.venc_lock); | 534 | mutex_unlock(&venc.venc_lock); |
@@ -551,9 +545,6 @@ void omapdss_venc_display_disable(struct omap_dss_device *dssdev) | |||
551 | 545 | ||
552 | omap_dss_stop_device(dssdev); | 546 | omap_dss_stop_device(dssdev); |
553 | 547 | ||
554 | if (dssdev->platform_disable) | ||
555 | dssdev->platform_disable(dssdev); | ||
556 | |||
557 | mutex_unlock(&venc.venc_lock); | 548 | mutex_unlock(&venc.venc_lock); |
558 | } | 549 | } |
559 | 550 | ||
@@ -721,7 +712,7 @@ static int venc_get_clocks(struct platform_device *pdev) | |||
721 | struct clk *clk; | 712 | struct clk *clk; |
722 | 713 | ||
723 | if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { | 714 | if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { |
724 | clk = clk_get(&pdev->dev, "tv_dac_clk"); | 715 | clk = devm_clk_get(&pdev->dev, "tv_dac_clk"); |
725 | if (IS_ERR(clk)) { | 716 | if (IS_ERR(clk)) { |
726 | DSSERR("can't get tv_dac_clk\n"); | 717 | DSSERR("can't get tv_dac_clk\n"); |
727 | return PTR_ERR(clk); | 718 | return PTR_ERR(clk); |
@@ -735,12 +726,6 @@ static int venc_get_clocks(struct platform_device *pdev) | |||
735 | return 0; | 726 | return 0; |
736 | } | 727 | } |
737 | 728 | ||
738 | static void venc_put_clocks(void) | ||
739 | { | ||
740 | if (venc.tv_dac_clk) | ||
741 | clk_put(venc.tv_dac_clk); | ||
742 | } | ||
743 | |||
744 | static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) | 729 | static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) |
745 | { | 730 | { |
746 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 731 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
@@ -786,8 +771,6 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) | |||
786 | 771 | ||
787 | dss_copy_device_pdata(dssdev, plat_dssdev); | 772 | dss_copy_device_pdata(dssdev, plat_dssdev); |
788 | 773 | ||
789 | dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; | ||
790 | |||
791 | r = venc_init_display(dssdev); | 774 | r = venc_init_display(dssdev); |
792 | if (r) { | 775 | if (r) { |
793 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 776 | DSSERR("device %s init failed: %d\n", dssdev->name, r); |
@@ -819,6 +802,8 @@ static void __init venc_init_output(struct platform_device *pdev) | |||
819 | out->pdev = pdev; | 802 | out->pdev = pdev; |
820 | out->id = OMAP_DSS_OUTPUT_VENC; | 803 | out->id = OMAP_DSS_OUTPUT_VENC; |
821 | out->type = OMAP_DISPLAY_TYPE_VENC; | 804 | out->type = OMAP_DISPLAY_TYPE_VENC; |
805 | out->name = "venc.0"; | ||
806 | out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; | ||
822 | 807 | ||
823 | dss_register_output(out); | 808 | dss_register_output(out); |
824 | } | 809 | } |
@@ -886,7 +871,6 @@ static int __init omap_venchw_probe(struct platform_device *pdev) | |||
886 | err_panel_init: | 871 | err_panel_init: |
887 | err_runtime_get: | 872 | err_runtime_get: |
888 | pm_runtime_disable(&pdev->dev); | 873 | pm_runtime_disable(&pdev->dev); |
889 | venc_put_clocks(); | ||
890 | return r; | 874 | return r; |
891 | } | 875 | } |
892 | 876 | ||
@@ -904,7 +888,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev) | |||
904 | venc_uninit_output(pdev); | 888 | venc_uninit_output(pdev); |
905 | 889 | ||
906 | pm_runtime_disable(&pdev->dev); | 890 | pm_runtime_disable(&pdev->dev); |
907 | venc_put_clocks(); | ||
908 | 891 | ||
909 | return 0; | 892 | return 0; |
910 | } | 893 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index ca585ef37f25..f38348ea3375 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
@@ -2388,7 +2388,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, | |||
2388 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; | 2388 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; |
2389 | struct omap_dss_output *out = dssdev->output; | 2389 | struct omap_dss_output *out = dssdev->output; |
2390 | 2390 | ||
2391 | mgr = omap_dss_get_overlay_manager(dssdev->channel); | 2391 | mgr = omap_dss_get_overlay_manager(out->dispc_channel); |
2392 | 2392 | ||
2393 | if (!mgr || !out) | 2393 | if (!mgr || !out) |
2394 | continue; | 2394 | continue; |