diff --git a/[refs] b/[refs] index 6bf1ffaeb022..f9942795546a 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 6717cd2937e7210321c5917f37f036895978f4d3 +refs/heads/master: 48c2169fd9922314d990f944068f107a3284434e diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_connector.c b/trunk/drivers/gpu/drm/omapdrm/omap_connector.c index 912759daf562..c451c41a7a7d 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/trunk/drivers/gpu/drm/omapdrm/omap_connector.c @@ -110,11 +110,6 @@ static enum drm_connector_status omap_connector_detect( ret = connector_status_connected; else ret = connector_status_disconnected; - } else if (dssdev->type == OMAP_DISPLAY_TYPE_DPI || - dssdev->type == OMAP_DISPLAY_TYPE_DBI || - dssdev->type == OMAP_DISPLAY_TYPE_SDI || - dssdev->type == OMAP_DISPLAY_TYPE_DSI) { - ret = connector_status_connected; } else { ret = connector_status_unknown; } @@ -194,30 +189,12 @@ static int omap_connector_mode_valid(struct drm_connector *connector, struct omap_video_timings timings = {0}; struct drm_device *dev = connector->dev; struct drm_display_mode *new_mode; - int r, ret = MODE_BAD; + int ret = MODE_BAD; copy_timings_drm_to_omap(&timings, mode); mode->vrefresh = drm_mode_vrefresh(mode); - /* - * if the panel driver doesn't have a check_timings, it's most likely - * a fixed resolution panel, check if the timings match with the - * panel's timings - */ - if (dssdrv->check_timings) { - r = dssdrv->check_timings(dssdev, &timings); - } else { - struct omap_video_timings t = {0}; - - dssdrv->get_timings(dssdev, &t); - - if (memcmp(&timings, &t, sizeof(struct omap_video_timings))) - r = -EINVAL; - else - r = 0; - } - - if (!r) { + if (!dssdrv->check_timings(dssdev, &timings)) { /* check if vrefresh is still valid */ new_mode = drm_mode_duplicate(dev, mode); new_mode->clock = timings.pixel_clock; diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_crtc.c b/trunk/drivers/gpu/drm/omapdrm/omap_crtc.c index 79b200aee18a..bec66a490b8f 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/trunk/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -74,13 +74,6 @@ struct omap_crtc { struct work_struct page_flip_work; }; -uint32_t pipe2vbl(struct drm_crtc *crtc) -{ - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - - return dispc_mgr_get_vsync_irq(omap_crtc->channel); -} - /* * Manager-ops, callbacks from output when they need to configure * the upstream part of the video pipe. @@ -620,13 +613,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_crtc->apply.pre_apply = omap_crtc_pre_apply; omap_crtc->apply.post_apply = omap_crtc_post_apply; - omap_crtc->channel = channel; - omap_crtc->plane = plane; - omap_crtc->plane->crtc = crtc; - omap_crtc->name = channel_names[channel]; - omap_crtc->pipe = id; - - omap_crtc->apply_irq.irqmask = pipe2vbl(crtc); + omap_crtc->apply_irq.irqmask = pipe2vbl(id); omap_crtc->apply_irq.irq = omap_crtc_apply_irq; omap_crtc->error_irq.irqmask = @@ -634,6 +621,12 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, omap_crtc->error_irq.irq = omap_crtc_error_irq; omap_irq_register(dev, &omap_crtc->error_irq); + omap_crtc->channel = channel; + omap_crtc->plane = plane; + omap_crtc->plane->crtc = crtc; + omap_crtc->name = channel_names[channel]; + omap_crtc->pipe = id; + /* temporary: */ omap_crtc->mgr.id = channel; diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_drv.c b/trunk/drivers/gpu/drm/omapdrm/omap_drv.c index 9c53c25e5201..079c54c6f94c 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/trunk/drivers/gpu/drm/omapdrm/omap_drv.c @@ -74,53 +74,54 @@ static int get_connector_type(struct omap_dss_device *dssdev) } } -static bool channel_used(struct drm_device *dev, enum omap_channel channel) -{ - struct omap_drm_private *priv = dev->dev_private; - int i; - - for (i = 0; i < priv->num_crtcs; i++) { - struct drm_crtc *crtc = priv->crtcs[i]; - - if (omap_crtc_channel(crtc) == channel) - return true; - } - - return false; -} - static int omap_modeset_init(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; struct omap_dss_device *dssdev = NULL; int num_ovls = dss_feat_get_num_ovls(); - int num_mgrs = dss_feat_get_num_mgrs(); - int num_crtcs; - int i, id = 0; + int id; drm_mode_config_init(dev); omap_drm_irq_install(dev); /* - * We usually don't want to create a CRTC for each manager, at least - * not until we have a way to expose private planes to userspace. - * Otherwise there would not be enough video pipes left for drm planes. - * We use the num_crtc argument to limit the number of crtcs we create. + * Create private planes and CRTCs for the last NUM_CRTCs overlay + * plus manager: */ - num_crtcs = min3(num_crtc, num_mgrs, num_ovls); + for (id = 0; id < min(num_crtc, num_ovls); id++) { + struct drm_plane *plane; + struct drm_crtc *crtc; + + plane = omap_plane_init(dev, id, true); + crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); - dssdev = NULL; + BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); + priv->crtcs[id] = crtc; + priv->num_crtcs++; + + priv->planes[id] = plane; + priv->num_planes++; + } + + /* + * Create normal planes for the remaining overlays: + */ + for (; id < num_ovls; id++) { + struct drm_plane *plane = omap_plane_init(dev, id, false); + + BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); + priv->planes[priv->num_planes++] = plane; + } for_each_dss_dev(dssdev) { struct drm_connector *connector; struct drm_encoder *encoder; - enum omap_channel channel; if (!dssdev->driver) { dev_warn(dev->dev, "%s has no driver.. skipping it\n", dssdev->name); - continue; + return 0; } if (!(dssdev->driver->get_timings || @@ -128,7 +129,7 @@ static int omap_modeset_init(struct drm_device *dev) dev_warn(dev->dev, "%s driver does not support " "get_timings or read_edid.. skipping it!\n", dssdev->name); - continue; + return 0; } encoder = omap_encoder_init(dev, dssdev); @@ -156,118 +157,16 @@ static int omap_modeset_init(struct drm_device *dev) drm_mode_connector_attach_encoder(connector, encoder); - /* - * if we have reached the limit of the crtcs we are allowed to - * create, let's not try to look for a crtc for this - * panel/encoder and onwards, we will, of course, populate the - * the possible_crtcs field for all the encoders with the final - * set of crtcs we create - */ - if (id == num_crtcs) - continue; - - /* - * get the recommended DISPC channel for this encoder. For now, - * we only try to get create a crtc out of the recommended, the - * other possible channels to which the encoder can connect are - * not considered. - */ - channel = dssdev->output->dispc_channel; - - /* - * if this channel hasn't already been taken by a previously - * allocated crtc, we create a new crtc for it - */ - if (!channel_used(dev, channel)) { - struct drm_plane *plane; - struct drm_crtc *crtc; - - plane = omap_plane_init(dev, id, true); - crtc = omap_crtc_init(dev, plane, channel, id); - - BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); - priv->crtcs[id] = crtc; - priv->num_crtcs++; - - priv->planes[id] = plane; - priv->num_planes++; - - id++; - } - } - - /* - * we have allocated crtcs according to the need of the panels/encoders, - * adding more crtcs here if needed - */ - for (; id < num_crtcs; id++) { - - /* find a free manager for this crtc */ - for (i = 0; i < num_mgrs; i++) { - if (!channel_used(dev, i)) { - struct drm_plane *plane; - struct drm_crtc *crtc; - - plane = omap_plane_init(dev, id, true); - crtc = omap_crtc_init(dev, plane, i, id); - - BUG_ON(priv->num_crtcs >= - ARRAY_SIZE(priv->crtcs)); - - priv->crtcs[id] = crtc; - priv->num_crtcs++; - - priv->planes[id] = plane; - priv->num_planes++; - - break; - } else { - continue; - } - } - - if (i == num_mgrs) { - /* this shouldn't really happen */ - dev_err(dev->dev, "no managers left for crtc\n"); - return -ENOMEM; - } - } - - /* - * Create normal planes for the remaining overlays: - */ - for (; id < num_ovls; id++) { - struct drm_plane *plane = omap_plane_init(dev, id, false); - - BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); - priv->planes[priv->num_planes++] = plane; - } - - for (i = 0; i < priv->num_encoders; i++) { - struct drm_encoder *encoder = priv->encoders[i]; - struct omap_dss_device *dssdev = - omap_encoder_get_dssdev(encoder); - /* figure out which crtc's we can connect the encoder to: */ encoder->possible_crtcs = 0; for (id = 0; id < priv->num_crtcs; id++) { - struct drm_crtc *crtc = priv->crtcs[id]; - enum omap_channel crtc_channel; - enum omap_dss_output_id supported_outputs; - - crtc_channel = omap_crtc_channel(crtc); - supported_outputs = - dss_feat_get_supported_outputs(crtc_channel); - + enum omap_dss_output_id supported_outputs = + dss_feat_get_supported_outputs(pipe2chan(id)); if (supported_outputs & dssdev->output->id) encoder->possible_crtcs |= (1 << id); } } - DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n", - priv->num_planes, priv->num_crtcs, priv->num_encoders, - priv->num_connectors); - dev->mode_config.min_width = 32; dev->mode_config.min_height = 32; @@ -404,7 +303,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, return ret; } -static struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { +struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_UNLOCKED|DRM_AUTH), DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH), @@ -668,7 +567,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = { }; #endif -static struct platform_driver pdev = { +struct platform_driver pdev = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_drv.h b/trunk/drivers/gpu/drm/omapdrm/omap_drv.h index 215a20dd340c..d4f997bb4ac0 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/trunk/drivers/gpu/drm/omapdrm/omap_drv.h @@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); int omap_gem_resume(struct device *dev); #endif -int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id); -void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id); +int omap_irq_enable_vblank(struct drm_device *dev, int crtc); +void omap_irq_disable_vblank(struct drm_device *dev, int crtc); irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); void omap_irq_preinstall(struct drm_device *dev); int omap_irq_postinstall(struct drm_device *dev); @@ -271,9 +271,39 @@ static inline int align_pitch(int pitch, int width, int bpp) return ALIGN(pitch, 8 * bytespp); } +static inline enum omap_channel pipe2chan(int pipe) +{ + int num_mgrs = dss_feat_get_num_mgrs(); + + /* + * We usually don't want to create a CRTC for each manager, + * at least not until we have a way to expose private planes + * to userspace. Otherwise there would not be enough video + * pipes left for drm planes. The higher #'d managers tend + * to have more features so start in reverse order. + */ + return num_mgrs - pipe - 1; +} + /* map crtc to vblank mask */ -uint32_t pipe2vbl(struct drm_crtc *crtc); -struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder); +static inline uint32_t pipe2vbl(int crtc) +{ + enum omap_channel channel = pipe2chan(crtc); + return dispc_mgr_get_vsync_irq(channel); +} + +static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct omap_drm_private *priv = dev->dev_private; + int i; + + for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++) + if (priv->crtcs[i] == crtc) + return i; + + BUG(); /* bogus CRTC ptr */ + return -1; +} /* should these be made into common util helpers? */ diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_encoder.c b/trunk/drivers/gpu/drm/omapdrm/omap_encoder.c index c29451ba65da..21d126d0317e 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/trunk/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -41,13 +41,6 @@ struct omap_encoder { struct omap_dss_device *dssdev; }; -struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder) -{ - struct omap_encoder *omap_encoder = to_omap_encoder(encoder); - - return omap_encoder->dssdev; -} - static void omap_encoder_destroy(struct drm_encoder *encoder) { struct omap_encoder *omap_encoder = to_omap_encoder(encoder); @@ -135,26 +128,13 @@ int omap_encoder_update(struct drm_encoder *encoder, dssdev->output->manager = mgr; - if (dssdrv->check_timings) { - ret = dssdrv->check_timings(dssdev, timings); - } else { - struct omap_video_timings t = {0}; - - dssdrv->get_timings(dssdev, &t); - - if (memcmp(timings, &t, sizeof(struct omap_video_timings))) - ret = -EINVAL; - else - ret = 0; - } - + ret = dssdrv->check_timings(dssdev, timings); if (ret) { dev_err(dev->dev, "could not set timings: %d\n", ret); return ret; } - if (dssdrv->set_timings) - dssdrv->set_timings(dssdev, timings); + dssdrv->set_timings(dssdev, timings); return 0; } diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/trunk/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index 0682cb5c0150..ac74d1bc67bf 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/trunk/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -178,7 +178,7 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, return omap_gem_mmap_obj(obj, vma); } -static struct dma_buf_ops omap_dmabuf_ops = { +struct dma_buf_ops omap_dmabuf_ops = { .map_dma_buf = omap_gem_map_dma_buf, .unmap_dma_buf = omap_gem_unmap_dma_buf, .release = omap_gem_dmabuf_release, diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_irq.c b/trunk/drivers/gpu/drm/omapdrm/omap_irq.c index 9263db117ff8..e01303ee00c3 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/trunk/drivers/gpu/drm/omapdrm/omap_irq.c @@ -130,13 +130,12 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, * Zero on success, appropriate errno if the given @crtc's vblank * interrupt cannot be enabled. */ -int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id) +int omap_irq_enable_vblank(struct drm_device *dev, int crtc) { struct omap_drm_private *priv = dev->dev_private; - struct drm_crtc *crtc = priv->crtcs[crtc_id]; unsigned long flags; - DBG("dev=%p, crtc=%d", dev, crtc_id); + DBG("dev=%p, crtc=%d", dev, crtc); dispc_runtime_get(); spin_lock_irqsave(&list_lock, flags); @@ -157,13 +156,12 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id) * a hardware vblank counter, this routine should be a no-op, since * interrupts will have to stay on to keep the count accurate. */ -void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id) +void omap_irq_disable_vblank(struct drm_device *dev, int crtc) { struct omap_drm_private *priv = dev->dev_private; - struct drm_crtc *crtc = priv->crtcs[crtc_id]; unsigned long flags; - DBG("dev=%p, crtc=%d", dev, crtc_id); + DBG("dev=%p, crtc=%d", dev, crtc); dispc_runtime_get(); spin_lock_irqsave(&list_lock, flags); @@ -188,12 +186,9 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) VERB("irqs: %08x", irqstatus); - for (id = 0; id < priv->num_crtcs; id++) { - struct drm_crtc *crtc = priv->crtcs[id]; - - if (irqstatus & pipe2vbl(crtc)) + for (id = 0; id < priv->num_crtcs; id++) + if (irqstatus & pipe2vbl(id)) drm_handle_vblank(dev, id); - } spin_lock_irqsave(&list_lock, flags); list_for_each_entry_safe(handler, n, &priv->irq_list, node) { diff --git a/trunk/drivers/gpu/drm/omapdrm/omap_plane.c b/trunk/drivers/gpu/drm/omapdrm/omap_plane.c index 8d225d7ff4e3..2882cda6ea19 100644 --- a/trunk/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/trunk/drivers/gpu/drm/omapdrm/omap_plane.c @@ -247,12 +247,6 @@ static int omap_plane_update(struct drm_plane *plane, { struct omap_plane *omap_plane = to_omap_plane(plane); omap_plane->enabled = true; - - if (plane->fb) - drm_framebuffer_unreference(plane->fb); - - drm_framebuffer_reference(fb); - return omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, diff --git a/trunk/drivers/video/omap2/displays/panel-taal.c b/trunk/drivers/video/omap2/displays/panel-taal.c index 2fc923de23cc..a32407a5735a 100644 --- a/trunk/drivers/video/omap2/displays/panel-taal.c +++ b/trunk/drivers/video/omap2/displays/panel-taal.c @@ -54,6 +54,61 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); static int taal_panel_reset(struct omap_dss_device *dssdev); +/** + * struct panel_config - panel configuration + * @name: panel name + * @type: panel type + * @timings: panel resolution + * @sleep: various panel specific delays, passed to msleep() if non-zero + * @reset_sequence: reset sequence timings, passed to udelay() if non-zero + * @regulators: array of panel regulators + * @num_regulators: number of regulators in the array + */ +struct panel_config { + const char *name; + int type; + + struct omap_video_timings timings; + + struct { + unsigned int sleep_in; + unsigned int sleep_out; + unsigned int hw_reset; + unsigned int enable_te; + } sleep; + + struct { + unsigned int high; + unsigned int low; + } reset_sequence; + +}; + +enum { + PANEL_TAAL, +}; + +static struct panel_config panel_configs[] = { + { + .name = "taal", + .type = PANEL_TAAL, + .timings = { + .x_res = 864, + .y_res = 480, + }, + .sleep = { + .sleep_in = 5, + .sleep_out = 5, + .hw_reset = 5, + .enable_te = 100, /* possible panel bug */ + }, + .reset_sequence = { + .high = 10, + .low = 10, + }, + }, +}; + struct taal_data { struct mutex lock; @@ -66,6 +121,9 @@ struct taal_data { struct omap_dss_device *dssdev; + /* panel specific HW info */ + struct panel_config *panel_config; + /* panel HW configuration from DT or platform data */ int reset_gpio; int ext_te_gpio; @@ -76,6 +134,8 @@ struct taal_data { /* runtime variables */ bool enabled; + u8 rotate; + bool mirror; bool te_enabled; @@ -161,7 +221,8 @@ static int taal_sleep_in(struct taal_data *td) hw_guard_start(td, 120); - msleep(5); + if (td->panel_config->sleep.sleep_in) + msleep(td->panel_config->sleep.sleep_in); return 0; } @@ -178,7 +239,8 @@ static int taal_sleep_out(struct taal_data *td) hw_guard_start(td, 120); - msleep(5); + if (td->panel_config->sleep.sleep_out) + msleep(td->panel_config->sleep.sleep_out); return 0; } @@ -200,6 +262,49 @@ static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3) return 0; } +static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror) +{ + int r; + u8 mode; + int b5, b6, b7; + + r = taal_dcs_read_1(td, MIPI_DCS_GET_ADDRESS_MODE, &mode); + if (r) + return r; + + switch (rotate) { + default: + case 0: + b7 = 0; + b6 = 0; + b5 = 0; + break; + case 1: + b7 = 0; + b6 = 1; + b5 = 1; + break; + case 2: + b7 = 1; + b6 = 1; + b5 = 0; + break; + case 3: + b7 = 1; + b6 = 0; + b5 = 1; + break; + } + + if (mirror) + b6 = !b6; + + mode &= ~((1<<7) | (1<<6) | (1<<5)); + mode |= (b7 << 7) | (b6 << 6) | (b5 << 5); + + return taal_dcs_write_1(td, MIPI_DCS_SET_ADDRESS_MODE, mode); +} + static int taal_set_update_window(struct taal_data *td, u16 x, u16 y, u16 w, u16 h) { @@ -410,8 +515,15 @@ static const struct backlight_ops taal_bl_ops = { static void taal_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres) { - *xres = dssdev->panel.timings.x_res; - *yres = dssdev->panel.timings.y_res; + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + + if (td->rotate == 0 || td->rotate == 2) { + *xres = dssdev->panel.timings.x_res; + *yres = dssdev->panel.timings.y_res; + } else { + *yres = dssdev->panel.timings.x_res; + *xres = dssdev->panel.timings.y_res; + } } static ssize_t taal_num_errors_show(struct device *dev, @@ -733,14 +845,17 @@ static void taal_hw_reset(struct omap_dss_device *dssdev) return; gpio_set_value(td->reset_gpio, 1); - udelay(10); + if (td->panel_config->reset_sequence.high) + udelay(td->panel_config->reset_sequence.high); /* reset the panel */ gpio_set_value(td->reset_gpio, 0); /* assert reset */ - udelay(10); + if (td->panel_config->reset_sequence.low) + udelay(td->panel_config->reset_sequence.low); gpio_set_value(td->reset_gpio, 1); /* wait after releasing reset */ - msleep(5); + if (td->panel_config->sleep.hw_reset) + msleep(td->panel_config->sleep.hw_reset); } static void taal_probe_pdata(struct taal_data *td, @@ -766,7 +881,8 @@ static int taal_probe(struct omap_dss_device *dssdev) struct backlight_properties props; struct taal_data *td; struct backlight_device *bldev = NULL; - int r; + int r, i; + const char *panel_name; dev_dbg(&dssdev->dev, "probe\n"); @@ -781,13 +897,26 @@ static int taal_probe(struct omap_dss_device *dssdev) const struct nokia_dsi_panel_data *pdata = dssdev->data; taal_probe_pdata(td, pdata); + + panel_name = pdata->name; } else { return -ENODEV; } - dssdev->panel.timings.x_res = 864; - dssdev->panel.timings.y_res = 480; - dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000); + if (panel_name == NULL) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { + if (strcmp(panel_name, panel_configs[i].name) == 0) { + td->panel_config = &panel_configs[i]; + break; + } + } + + if (!td->panel_config) + return -EINVAL; + + dssdev->panel.timings = td->panel_config->timings; dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; @@ -920,15 +1049,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); u8 id1, id2, id3; int r; - struct omap_dss_dsi_config dsi_config = { - .mode = OMAP_DSS_DSI_CMD_MODE, - .pixel_format = OMAP_DSS_DSI_FMT_RGB888, - .timings = &dssdev->panel.timings, - .hs_clk_min = 150000000, - .hs_clk_max = 300000000, - .lp_clk_min = 7000000, - .lp_clk_max = 10000000, - }; r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); if (r) { @@ -936,9 +1056,14 @@ static int taal_power_on(struct omap_dss_device *dssdev) goto err0; }; - r = omapdss_dsi_set_config(dssdev, &dsi_config); + omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888); + omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE); + + r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000); if (r) { - dev_err(&dssdev->dev, "failed to configure DSI\n"); + dev_err(&dssdev->dev, "failed to set HS and LP clocks\n"); goto err0; } @@ -961,7 +1086,8 @@ static int taal_power_on(struct omap_dss_device *dssdev) goto err; /* on early Taal revisions CABC is broken */ - if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) + if (td->panel_config->type == PANEL_TAAL && + (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) td->cabc_broken = true; r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff); @@ -978,6 +1104,10 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; + r = taal_set_addr_mode(td, td->rotate, td->mirror); + if (r) + goto err; + if (!td->cabc_broken) { r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode); if (r) @@ -999,8 +1129,8 @@ static int taal_power_on(struct omap_dss_device *dssdev) td->enabled = 1; if (!td->intro_printed) { - dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n", - id1, id2, id3); + dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n", + td->panel_config->name, id1, id2, id3); if (td->cabc_broken) dev_info(&dssdev->dev, "old Taal version, CABC disabled\n"); @@ -1181,8 +1311,8 @@ static int taal_update(struct omap_dss_device *dssdev, /* XXX no need to send this every frame, but dsi break if not done */ r = taal_set_update_window(td, 0, 0, - dssdev->panel.timings.x_res, - dssdev->panel.timings.y_res); + td->panel_config->timings.x_res, + td->panel_config->timings.y_res); if (r) goto err; @@ -1235,8 +1365,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) if (!gpio_is_valid(td->ext_te_gpio)) omapdss_dsi_enable_te(dssdev, enable); - /* possible panel bug */ - msleep(100); + if (td->panel_config->sleep.enable_te) + msleep(td->panel_config->sleep.enable_te); return r; } @@ -1289,6 +1419,112 @@ static int taal_get_te(struct omap_dss_device *dssdev) return r; } +static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) +{ + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + u16 dw, dh; + int r; + + dev_dbg(&dssdev->dev, "rotate %d\n", rotate); + + mutex_lock(&td->lock); + + if (td->rotate == rotate) + goto end; + + dsi_bus_lock(dssdev); + + if (td->enabled) { + r = taal_wake_up(dssdev); + if (r) + goto err; + + r = taal_set_addr_mode(td, rotate, td->mirror); + if (r) + goto err; + } + + if (rotate == 0 || rotate == 2) { + dw = dssdev->panel.timings.x_res; + dh = dssdev->panel.timings.y_res; + } else { + dw = dssdev->panel.timings.y_res; + dh = dssdev->panel.timings.x_res; + } + + omapdss_dsi_set_size(dssdev, dw, dh); + + td->rotate = rotate; + + dsi_bus_unlock(dssdev); +end: + mutex_unlock(&td->lock); + return 0; +err: + dsi_bus_unlock(dssdev); + mutex_unlock(&td->lock); + return r; +} + +static u8 taal_get_rotate(struct omap_dss_device *dssdev) +{ + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&td->lock); + r = td->rotate; + mutex_unlock(&td->lock); + + return r; +} + +static int taal_mirror(struct omap_dss_device *dssdev, bool enable) +{ + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int r; + + dev_dbg(&dssdev->dev, "mirror %d\n", enable); + + mutex_lock(&td->lock); + + if (td->mirror == enable) + goto end; + + dsi_bus_lock(dssdev); + if (td->enabled) { + r = taal_wake_up(dssdev); + if (r) + goto err; + + r = taal_set_addr_mode(td, td->rotate, enable); + if (r) + goto err; + } + + td->mirror = enable; + + dsi_bus_unlock(dssdev); +end: + mutex_unlock(&td->lock); + return 0; +err: + dsi_bus_unlock(dssdev); + mutex_unlock(&td->lock); + return r; +} + +static bool taal_get_mirror(struct omap_dss_device *dssdev) +{ + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&td->lock); + r = td->mirror; + mutex_unlock(&td->lock); + + return r; +} + static int taal_run_test(struct omap_dss_device *dssdev, int test_num) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); @@ -1522,6 +1758,10 @@ static struct omap_dss_driver taal_driver = { .enable_te = taal_enable_te, .get_te = taal_get_te, + .set_rotate = taal_rotate, + .get_rotate = taal_get_rotate, + .set_mirror = taal_mirror, + .get_mirror = taal_get_mirror, .run_test = taal_run_test, .memory_read = taal_memory_read, diff --git a/trunk/drivers/video/omap2/dss/apply.c b/trunk/drivers/video/omap2/dss/apply.c index a4b356a9780d..d446bdfc4c82 100644 --- a/trunk/drivers/video/omap2/dss/apply.c +++ b/trunk/drivers/video/omap2/dss/apply.c @@ -435,27 +435,20 @@ static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_man static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); + struct omap_dss_device *dssdev = mgr->get_device(mgr); u32 irq; int r; - if (mgr->output == NULL) - return -ENODEV; - r = dispc_runtime_get(); if (r) return r; - switch (mgr->output->id) { - case OMAP_DSS_OUTPUT_VENC: + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) irq = DISPC_IRQ_EVSYNC_ODD; - break; - case OMAP_DSS_OUTPUT_HDMI: + else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) irq = DISPC_IRQ_EVSYNC_EVEN; - break; - default: + else irq = dispc_mgr_get_vsync_irq(mgr->id); - break; - } r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); diff --git a/trunk/drivers/video/omap2/dss/core.c b/trunk/drivers/video/omap2/dss/core.c index f8779d4750ba..60cc6fee6548 100644 --- a/trunk/drivers/video/omap2/dss/core.c +++ b/trunk/drivers/video/omap2/dss/core.c @@ -181,10 +181,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, write, &dss_debug_fops); - if (IS_ERR(d)) - return PTR_ERR(d); - - return 0; + return PTR_RET(d); } #else /* CONFIG_OMAP2_DSS_DEBUGFS */ static inline int dss_initialize_debugfs(void) diff --git a/trunk/drivers/video/omap2/dss/dispc.c b/trunk/drivers/video/omap2/dss/dispc.c index 8cfa27b4fdd8..05ff2b91d9e8 100644 --- a/trunk/drivers/video/omap2/dss/dispc.c +++ b/trunk/drivers/video/omap2/dss/dispc.c @@ -97,8 +97,6 @@ static struct { int irq; - unsigned long core_clk_rate; - u32 fifo_size[DISPC_MAX_NR_FIFOS]; /* maps which plane is using a fifo. fifo-id -> plane-id */ int fifo_assignment[DISPC_MAX_NR_FIFOS]; @@ -2953,10 +2951,6 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, dispc_write_reg(DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); - - if (dss_has_feature(FEAT_CORE_CLK_DIV) == false && - channel == OMAP_DSS_CHANNEL_LCD) - dispc.core_clk_rate = dispc_fclk_rate() / lck_div; } static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, @@ -3062,7 +3056,15 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) unsigned long dispc_core_clk_rate(void) { - return dispc.core_clk_rate; + int lcd; + unsigned long fclk = dispc_fclk_rate(); + + if (dss_has_feature(FEAT_CORE_CLK_DIV)) + lcd = REG_GET(DISPC_DIVISOR, 23, 16); + else + lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16); + + return fclk / lcd; } static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) @@ -3311,79 +3313,67 @@ static void dispc_dump_regs(struct seq_file *s) #undef DUMPREG } -/* calculate clock rates using dividers in cinfo */ -int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, +/* with fck as input clock rate, find dispc dividers that produce req_pck */ +void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, struct dispc_clock_info *cinfo) { - if (cinfo->lck_div > 255 || cinfo->lck_div == 0) - return -EINVAL; - if (cinfo->pck_div < 1 || cinfo->pck_div > 255) - return -EINVAL; + u16 pcd_min, pcd_max; + unsigned long best_pck; + u16 best_ld, cur_ld; + u16 best_pd, cur_pd; - cinfo->lck = dispc_fclk_rate / cinfo->lck_div; - cinfo->pck = cinfo->lck / cinfo->pck_div; + pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); + pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); - return 0; -} + best_pck = 0; + best_ld = 0; + best_pd = 0; -bool dispc_div_calc(unsigned long dispc, - unsigned long pck_min, unsigned long pck_max, - dispc_div_calc_func func, void *data) -{ - int lckd, lckd_start, lckd_stop; - int pckd, pckd_start, pckd_stop; - unsigned long pck, lck; - unsigned long lck_max; - unsigned long pckd_hw_min, pckd_hw_max; - unsigned min_fck_per_pck; - unsigned long fck; - -#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK - min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; -#else - min_fck_per_pck = 0; -#endif - - pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); - pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); + for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { + unsigned long lck = fck / cur_ld; - lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) { + unsigned long pck = lck / cur_pd; + long old_delta = abs(best_pck - req_pck); + long new_delta = abs(pck - req_pck); - pck_min = pck_min ? pck_min : 1; - pck_max = pck_max ? pck_max : ULONG_MAX; + if (best_pck == 0 || new_delta < old_delta) { + best_pck = pck; + best_ld = cur_ld; + best_pd = cur_pd; - lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul); - lckd_stop = min(dispc / pck_min, 255ul); - - for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) { - lck = dispc / lckd; + if (pck == req_pck) + goto found; + } - pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min); - pckd_stop = min(lck / pck_min, pckd_hw_max); + if (pck < req_pck) + break; + } - for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) { - pck = lck / pckd; + if (lck / pcd_min < req_pck) + break; + } - /* - * For OMAP2/3 the DISPC fclk is the same as LCD's logic - * clock, which means we're configuring DISPC fclk here - * also. Thus we need to use the calculated lck. For - * OMAP4+ the DISPC fclk is a separate clock. - */ - if (dss_has_feature(FEAT_CORE_CLK_DIV)) - fck = dispc_core_clk_rate(); - else - fck = lck; +found: + cinfo->lck_div = best_ld; + cinfo->pck_div = best_pd; + cinfo->lck = fck / cinfo->lck_div; + cinfo->pck = cinfo->lck / cinfo->pck_div; +} - if (fck < pck * min_fck_per_pck) - continue; +/* calculate clock rates using dividers in cinfo */ +int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, + struct dispc_clock_info *cinfo) +{ + if (cinfo->lck_div > 255 || cinfo->lck_div == 0) + return -EINVAL; + if (cinfo->pck_div < 1 || cinfo->pck_div > 255) + return -EINVAL; - if (func(lckd, pckd, lck, pck, data)) - return true; - } - } + cinfo->lck = dispc_fclk_rate / cinfo->lck_div; + cinfo->pck = cinfo->lck / cinfo->pck_div; - return false; + return 0; } void dispc_mgr_set_clock_div(enum omap_channel channel, @@ -3461,8 +3451,6 @@ static void _omap_dispc_initial_config(void) l = FLD_MOD(l, 1, 0, 0); l = FLD_MOD(l, 1, 23, 16); dispc_write_reg(DISPC_DIVISOR, l); - - dispc.core_clk_rate = dispc_fclk_rate(); } /* FUNCGATED */ diff --git a/trunk/drivers/video/omap2/dss/dpi.c b/trunk/drivers/video/omap2/dss/dpi.c index e93c4debea7f..4af136a04e53 100644 --- a/trunk/drivers/video/omap2/dss/dpi.c +++ b/trunk/drivers/video/omap2/dss/dpi.c @@ -63,29 +63,15 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) case OMAPDSS_VER_OMAP3630: case OMAPDSS_VER_AM35xx: return NULL; + default: + break; + } - case OMAPDSS_VER_OMAP4430_ES1: - case OMAPDSS_VER_OMAP4430_ES2: - case OMAPDSS_VER_OMAP4: - switch (channel) { - case OMAP_DSS_CHANNEL_LCD: - return dsi_get_dsidev_from_id(0); - case OMAP_DSS_CHANNEL_LCD2: - return dsi_get_dsidev_from_id(1); - default: - return NULL; - } - - case OMAPDSS_VER_OMAP5: - switch (channel) { - case OMAP_DSS_CHANNEL_LCD: - return dsi_get_dsidev_from_id(0); - case OMAP_DSS_CHANNEL_LCD3: - return dsi_get_dsidev_from_id(1); - default: - return NULL; - } - + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return dsi_get_dsidev_from_id(0); + case OMAP_DSS_CHANNEL_LCD2: + return dsi_get_dsidev_from_id(1); default: return NULL; } @@ -105,211 +91,75 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) } } -struct dpi_clk_calc_ctx { - struct platform_device *dsidev; - - /* inputs */ - - unsigned long pck_min, pck_max; - - /* outputs */ - - struct dsi_clock_info dsi_cinfo; - struct dss_clock_info dss_cinfo; - struct dispc_clock_info dispc_cinfo; -}; - -static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, - unsigned long pck, void *data) -{ - struct dpi_clk_calc_ctx *ctx = data; - - /* - * Odd dividers give us uneven duty cycle, causing problem when level - * shifted. So skip all odd dividers when the pixel clock is on the - * higher side. - */ - if (ctx->pck_min >= 1000000) { - if (lckd > 1 && lckd % 2 != 0) - return false; - - if (pckd > 1 && pckd % 2 != 0) - return false; - } - - ctx->dispc_cinfo.lck_div = lckd; - ctx->dispc_cinfo.pck_div = pckd; - ctx->dispc_cinfo.lck = lck; - ctx->dispc_cinfo.pck = pck; - - return true; -} - - -static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, - void *data) -{ - struct dpi_clk_calc_ctx *ctx = data; - - /* - * Odd dividers give us uneven duty cycle, causing problem when level - * shifted. So skip all odd dividers when the pixel clock is on the - * higher side. - */ - if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000) - return false; - - ctx->dsi_cinfo.regm_dispc = regm_dispc; - ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; - - return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); -} - - -static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint, - unsigned long pll, - void *data) -{ - struct dpi_clk_calc_ctx *ctx = data; - - ctx->dsi_cinfo.regn = regn; - ctx->dsi_cinfo.regm = regm; - ctx->dsi_cinfo.fint = fint; - ctx->dsi_cinfo.clkin4ddr = pll; - - return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min, - dpi_calc_hsdiv_cb, ctx); -} - -static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data) -{ - struct dpi_clk_calc_ctx *ctx = data; - - ctx->dss_cinfo.fck = fck; - ctx->dss_cinfo.fck_div = fckd; - - return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); -} - -static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) -{ - unsigned long clkin; - unsigned long pll_min, pll_max; - - clkin = dsi_get_pll_clkin(dpi.dsidev); - - memset(ctx, 0, sizeof(*ctx)); - ctx->dsidev = dpi.dsidev; - ctx->pck_min = pck - 1000; - ctx->pck_max = pck + 1000; - ctx->dsi_cinfo.clkin = clkin; - - pll_min = 0; - pll_max = 0; - - return dsi_pll_calc(dpi.dsidev, clkin, - pll_min, pll_max, - dpi_calc_pll_cb, ctx); -} - -static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) -{ - int i; - - /* - * DSS fck gives us very few possibilities, so finding a good pixel - * clock may not be possible. We try multiple times to find the clock, - * each time widening the pixel clock range we look for, up to - * +/- ~15MHz. - */ - - for (i = 0; i < 25; ++i) { - bool ok; - - memset(ctx, 0, sizeof(*ctx)); - if (pck > 1000 * i * i * i) - ctx->pck_min = max(pck - 1000 * i * i * i, 0lu); - else - ctx->pck_min = 0; - ctx->pck_max = pck + 1000 * i * i * i; - - ok = dss_div_calc(ctx->pck_min, dpi_calc_dss_cb, ctx); - if (ok) - return ok; - } - - return false; -} - - - -static int dpi_set_dsi_clk(enum omap_channel channel, +static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, unsigned long pck_req, unsigned long *fck, int *lck_div, int *pck_div) { - struct dpi_clk_calc_ctx ctx; + struct omap_overlay_manager *mgr = dssdev->output->manager; + struct dsi_clock_info dsi_cinfo; + struct dispc_clock_info dispc_cinfo; int r; - bool ok; - ok = dpi_dsi_clk_calc(pck_req, &ctx); - if (!ok) - return -EINVAL; + r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo, + &dispc_cinfo); + if (r) + return r; - r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo); + r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo); if (r) return r; - dss_select_lcd_clk_source(channel, - dpi_get_alt_clk_src(channel)); + dss_select_lcd_clk_source(mgr->id, + dpi_get_alt_clk_src(mgr->id)); - dpi.mgr_config.clock_info = ctx.dispc_cinfo; + dpi.mgr_config.clock_info = dispc_cinfo; - *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; - *lck_div = ctx.dispc_cinfo.lck_div; - *pck_div = ctx.dispc_cinfo.pck_div; + *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; + *lck_div = dispc_cinfo.lck_div; + *pck_div = dispc_cinfo.pck_div; return 0; } -static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, - int *lck_div, int *pck_div) +static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, + unsigned long pck_req, unsigned long *fck, int *lck_div, + int *pck_div) { - struct dpi_clk_calc_ctx ctx; + struct dss_clock_info dss_cinfo; + struct dispc_clock_info dispc_cinfo; int r; - bool ok; - ok = dpi_dss_clk_calc(pck_req, &ctx); - if (!ok) - return -EINVAL; + r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo); + if (r) + return r; - r = dss_set_clock_div(&ctx.dss_cinfo); + r = dss_set_clock_div(&dss_cinfo); if (r) return r; - dpi.mgr_config.clock_info = ctx.dispc_cinfo; + dpi.mgr_config.clock_info = dispc_cinfo; - *fck = ctx.dss_cinfo.fck; - *lck_div = ctx.dispc_cinfo.lck_div; - *pck_div = ctx.dispc_cinfo.pck_div; + *fck = dss_cinfo.fck; + *lck_div = dispc_cinfo.lck_div; + *pck_div = dispc_cinfo.pck_div; return 0; } -static int dpi_set_mode(struct omap_overlay_manager *mgr) +static int dpi_set_mode(struct omap_dss_device *dssdev) { struct omap_video_timings *t = &dpi.timings; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div = 0, pck_div = 0; unsigned long fck = 0; unsigned long pck; int r = 0; if (dpi.dsidev) - r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck, + r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); else - r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck, + r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); if (r) return r; @@ -329,8 +179,10 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr) return 0; } -static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) +static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dpi.mgr_config.stallmode = false; @@ -345,7 +197,7 @@ static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = &dpi.output; + struct omap_dss_output *out = dssdev->output; int r; mutex_lock(&dpi.lock); @@ -378,7 +230,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; - r = dss_dpi_select_source(out->manager->id); + r = dss_dpi_select_source(dssdev->channel); if (r) goto err_src_sel; @@ -392,11 +244,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) goto err_dsi_pll_init; } - r = dpi_set_mode(out->manager); + r = dpi_set_mode(dssdev); if (r) goto err_set_mode; - dpi_config_lcd_manager(out->manager); + dpi_config_lcd_manager(dssdev); mdelay(2); @@ -433,7 +285,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dpi.output.manager; + struct omap_overlay_manager *mgr = dssdev->output->manager; mutex_lock(&dpi.lock); @@ -472,12 +324,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings); int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - struct omap_overlay_manager *mgr = dpi.output.manager; + int r; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div, pck_div; unsigned long fck; unsigned long pck; - struct dpi_clk_calc_ctx ctx; - bool ok; + struct dispc_clock_info dispc_cinfo; if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) return -EINVAL; @@ -486,21 +338,28 @@ int dpi_check_timings(struct omap_dss_device *dssdev, return -EINVAL; if (dpi.dsidev) { - ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx); - if (!ok) - return -EINVAL; + struct dsi_clock_info dsi_cinfo; + r = dsi_pll_calc_clock_div_pck(dpi.dsidev, + timings->pixel_clock * 1000, + &dsi_cinfo, &dispc_cinfo); + + if (r) + return r; - fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; + fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; } else { - ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx); - if (!ok) - return -EINVAL; + struct dss_clock_info dss_cinfo; + r = dss_calc_clock_div(timings->pixel_clock * 1000, + &dss_cinfo, &dispc_cinfo); - fck = ctx.dss_cinfo.fck; + if (r) + return r; + + fck = dss_cinfo.fck; } - lck_div = ctx.dispc_cinfo.lck_div; - pck_div = ctx.dispc_cinfo.pck_div; + lck_div = dispc_cinfo.lck_div; + pck_div = dispc_cinfo.pck_div; pck = fck / lck_div / pck_div / 1000; @@ -542,36 +401,6 @@ static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) return 0; } -/* - * Return a hardcoded channel for the DPI output. This should work for - * current use cases, but this can be later expanded to either resolve - * the channel in some more dynamic manner, or get the channel as a user - * parameter. - */ -static enum omap_channel dpi_get_channel(void) -{ - switch (omapdss_get_version()) { - case OMAPDSS_VER_OMAP24xx: - case OMAPDSS_VER_OMAP34xx_ES1: - case OMAPDSS_VER_OMAP34xx_ES3: - case OMAPDSS_VER_OMAP3630: - case OMAPDSS_VER_AM35xx: - return OMAP_DSS_CHANNEL_LCD; - - case OMAPDSS_VER_OMAP4430_ES1: - case OMAPDSS_VER_OMAP4430_ES2: - case OMAPDSS_VER_OMAP4: - return OMAP_DSS_CHANNEL_LCD2; - - case OMAPDSS_VER_OMAP5: - return OMAP_DSS_CHANNEL_LCD3; - - default: - DSSWARN("unsupported DSS version\n"); - return OMAP_DSS_CHANNEL_LCD; - } -} - static int __init dpi_init_display(struct omap_dss_device *dssdev) { struct platform_device *dsidev; @@ -592,7 +421,12 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) dpi.vdds_dsi_reg = vdds_dsi; } - dsidev = dpi_get_dsidev(dpi.output.dispc_channel); + /* + * XXX We shouldn't need dssdev->channel for this. The dsi pll clock + * source for DPI is SoC integration detail, not something that should + * be configured in the dssdev + */ + dsidev = dpi_get_dsidev(dssdev->channel); if (dsidev && dpi_verify_dsi_pll(dsidev)) { dsidev = NULL; @@ -683,8 +517,6 @@ static void __init dpi_init_output(struct platform_device *pdev) out->pdev = pdev; out->id = OMAP_DSS_OUTPUT_DPI; out->type = OMAP_DISPLAY_TYPE_DPI; - out->name = "dpi.0"; - out->dispc_channel = dpi_get_channel(); dss_register_output(out); } diff --git a/trunk/drivers/video/omap2/dss/dsi.c b/trunk/drivers/video/omap2/dss/dsi.c index 8db29bff0423..28d41d16b7be 100644 --- a/trunk/drivers/video/omap2/dss/dsi.c +++ b/trunk/drivers/video/omap2/dss/dsi.c @@ -200,11 +200,6 @@ struct dsi_reg { u16 idx; }; typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); -static int dsi_display_init_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr); -static void dsi_display_uninit_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr); - #define DSI_MAX_NR_ISRS 2 #define DSI_MAX_NR_LANES 5 @@ -255,24 +250,6 @@ struct dsi_isr_tables { struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS]; }; -struct dsi_clk_calc_ctx { - struct platform_device *dsidev; - - /* inputs */ - - const struct omap_dss_dsi_config *config; - - unsigned long req_pck_min, req_pck_nom, req_pck_max; - - /* outputs */ - - struct dsi_clock_info dsi_cinfo; - struct dispc_clock_info dispc_cinfo; - - struct omap_video_timings dispc_vm; - struct omap_dss_dsi_videomode_timings dsi_vm; -}; - struct dsi_data { struct platform_device *pdev; void __iomem *base; @@ -284,9 +261,6 @@ struct dsi_data { struct clk *dss_clk; struct clk *sys_clk; - struct dispc_clock_info user_dispc_cinfo; - struct dsi_clock_info user_dsi_cinfo; - struct dsi_clock_info current_cinfo; bool vdds_dsi_enabled; @@ -350,7 +324,6 @@ struct dsi_data { unsigned long lpdiv_max; unsigned num_lanes_supported; - unsigned line_buffer_size; struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; unsigned num_lanes_used; @@ -1219,33 +1192,15 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) return r; } -static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo, - unsigned long lp_clk_min, unsigned long lp_clk_max) -{ - unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk; - unsigned lp_clk_div; - unsigned long lp_clk; - - lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2); - lp_clk = dsi_fclk / 2 / lp_clk_div; - - if (lp_clk < lp_clk_min || lp_clk > lp_clk_max) - return -EINVAL; - - cinfo->lp_clk_div = lp_clk_div; - cinfo->lp_clk = lp_clk; - - return 0; -} - -static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) +static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long dsi_fclk; unsigned lp_clk_div; unsigned long lp_clk; - lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div; + lp_clk_div = dssdev->clocks.dsi.lp_clk_div; if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max) return -EINVAL; @@ -1317,75 +1272,6 @@ static int dsi_pll_power(struct platform_device *dsidev, return 0; } -unsigned long dsi_get_pll_clkin(struct platform_device *dsidev) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - return clk_get_rate(dsi->sys_clk); -} - -bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll, - unsigned long out_min, dsi_hsdiv_calc_func func, void *data) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int regm, regm_start, regm_stop; - unsigned long out_max; - unsigned long out; - - out_min = out_min ? out_min : 1; - out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); - - regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul); - regm_stop = min(pll / out_min, dsi->regm_dispc_max); - - for (regm = regm_start; regm <= regm_stop; ++regm) { - out = pll / regm; - - if (func(regm, out, data)) - return true; - } - - return false; -} - -bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin, - unsigned long pll_min, unsigned long pll_max, - dsi_pll_calc_func func, void *data) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int regn, regn_start, regn_stop; - int regm, regm_start, regm_stop; - unsigned long fint, pll; - const unsigned long pll_hw_max = 1800000000; - unsigned long fint_hw_min, fint_hw_max; - - fint_hw_min = dsi->fint_min; - fint_hw_max = dsi->fint_max; - - regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul); - regn_stop = min(clkin / fint_hw_min, dsi->regn_max); - - pll_max = pll_max ? pll_max : ULONG_MAX; - - for (regn = regn_start; regn <= regn_stop; ++regn) { - fint = clkin / regn; - - regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2), - 1ul); - regm_stop = min3(pll_max / fint / 2, - pll_hw_max / fint / 2, - dsi->regm_max); - - for (regm = regm_start; regm <= regm_stop; ++regm) { - pll = 2 * regm * fint; - - if (func(regn, regm, fint, pll, data)) - return true; - } - } - - return false; -} - /* calculate clock rates using dividers in cinfo */ static int dsi_calc_clock_rates(struct platform_device *dsidev, struct dsi_clock_info *cinfo) @@ -1430,7 +1316,192 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev, return 0; } -static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo) +int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, + unsigned long req_pck, struct dsi_clock_info *dsi_cinfo, + struct dispc_clock_info *dispc_cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cur, best; + struct dispc_clock_info best_dispc; + int min_fck_per_pck; + int match = 0; + unsigned long dss_sys_clk, max_dss_fck; + + dss_sys_clk = clk_get_rate(dsi->sys_clk); + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + if (req_pck == dsi->cache_req_pck && + dsi->cache_cinfo.clkin == dss_sys_clk) { + DSSDBG("DSI clock info found from cache\n"); + *dsi_cinfo = dsi->cache_cinfo; + dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk, + dispc_cinfo); + return 0; + } + + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; + + if (min_fck_per_pck && + req_pck * min_fck_per_pck > max_dss_fck) { + DSSERR("Requested pixel clock not possible with the current " + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " + "the constraint off.\n"); + min_fck_per_pck = 0; + } + + DSSDBG("dsi_pll_calc\n"); + +retry: + memset(&best, 0, sizeof(best)); + memset(&best_dispc, 0, sizeof(best_dispc)); + + memset(&cur, 0, sizeof(cur)); + cur.clkin = dss_sys_clk; + + /* 0.75MHz < Fint = clkin / regn < 2.1MHz */ + /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ + for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { + cur.fint = cur.clkin / cur.regn; + + if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) + continue; + + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ + for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { + unsigned long a, b; + + a = 2 * cur.regm * (cur.clkin/1000); + b = cur.regn; + cur.clkin4ddr = a / b * 1000; + + if (cur.clkin4ddr > 1800 * 1000 * 1000) + break; + + /* dsi_pll_hsdiv_dispc_clk(MHz) = + * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */ + for (cur.regm_dispc = 1; cur.regm_dispc < + dsi->regm_dispc_max; ++cur.regm_dispc) { + struct dispc_clock_info cur_dispc; + cur.dsi_pll_hsdiv_dispc_clk = + cur.clkin4ddr / cur.regm_dispc; + + if (cur.regm_dispc > 1 && + cur.regm_dispc % 2 != 0 && + req_pck >= 1000000) + continue; + + /* this will narrow down the search a bit, + * but still give pixclocks below what was + * requested */ + if (cur.dsi_pll_hsdiv_dispc_clk < req_pck) + break; + + if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck) + continue; + + if (min_fck_per_pck && + cur.dsi_pll_hsdiv_dispc_clk < + req_pck * min_fck_per_pck) + continue; + + match = 1; + + dispc_find_clk_divs(req_pck, + cur.dsi_pll_hsdiv_dispc_clk, + &cur_dispc); + + if (abs(cur_dispc.pck - req_pck) < + abs(best_dispc.pck - req_pck)) { + best = cur; + best_dispc = cur_dispc; + + if (cur_dispc.pck == req_pck) + goto found; + } + } + } + } +found: + if (!match) { + if (min_fck_per_pck) { + DSSERR("Could not find suitable clock settings.\n" + "Turning FCK/PCK constraint off and" + "trying again.\n"); + min_fck_per_pck = 0; + goto retry; + } + + DSSERR("Could not find suitable clock settings.\n"); + + return -EINVAL; + } + + /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */ + best.regm_dsi = 0; + best.dsi_pll_hsdiv_dsi_clk = 0; + + if (dsi_cinfo) + *dsi_cinfo = best; + if (dispc_cinfo) + *dispc_cinfo = best_dispc; + + dsi->cache_req_pck = req_pck; + dsi->cache_clk_freq = 0; + dsi->cache_cinfo = best; + + return 0; +} + +static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, + unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cur, best; + + DSSDBG("dsi_pll_calc_ddrfreq\n"); + + memset(&best, 0, sizeof(best)); + memset(&cur, 0, sizeof(cur)); + + cur.clkin = clk_get_rate(dsi->sys_clk); + + for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { + cur.fint = cur.clkin / cur.regn; + + if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) + continue; + + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ + for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { + unsigned long a, b; + + a = 2 * cur.regm * (cur.clkin/1000); + b = cur.regn; + cur.clkin4ddr = a / b * 1000; + + if (cur.clkin4ddr > 1800 * 1000 * 1000) + break; + + if (abs(cur.clkin4ddr - req_clkin4ddr) < + abs(best.clkin4ddr - req_clkin4ddr)) { + best = cur; + DSSDBG("best %ld\n", best.clkin4ddr); + } + + if (cur.clkin4ddr == req_clkin4ddr) + goto found; + } + } +found: + if (cinfo) + *cinfo = best; + + return 0; +} + +static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, + struct dsi_clock_info *cinfo) { unsigned long max_dsi_fck; @@ -1440,6 +1511,90 @@ static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo) cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; } +static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev, + unsigned long req_pck, struct dsi_clock_info *cinfo, + struct dispc_clock_info *dispc_cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + unsigned regm_dispc, best_regm_dispc; + unsigned long dispc_clk, best_dispc_clk; + int min_fck_per_pck; + unsigned long max_dss_fck; + struct dispc_clock_info best_dispc; + bool match; + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; + + if (min_fck_per_pck && + req_pck * min_fck_per_pck > max_dss_fck) { + DSSERR("Requested pixel clock not possible with the current " + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " + "the constraint off.\n"); + min_fck_per_pck = 0; + } + +retry: + best_regm_dispc = 0; + best_dispc_clk = 0; + memset(&best_dispc, 0, sizeof(best_dispc)); + match = false; + + for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) { + struct dispc_clock_info cur_dispc; + + dispc_clk = cinfo->clkin4ddr / regm_dispc; + + /* this will narrow down the search a bit, + * but still give pixclocks below what was + * requested */ + if (dispc_clk < req_pck) + break; + + if (dispc_clk > max_dss_fck) + continue; + + if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck) + continue; + + match = true; + + dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc); + + if (abs(cur_dispc.pck - req_pck) < + abs(best_dispc.pck - req_pck)) { + best_regm_dispc = regm_dispc; + best_dispc_clk = dispc_clk; + best_dispc = cur_dispc; + + if (cur_dispc.pck == req_pck) + goto found; + } + } + + if (!match) { + if (min_fck_per_pck) { + DSSERR("Could not find suitable clock settings.\n" + "Turning FCK/PCK constraint off and" + "trying again.\n"); + min_fck_per_pck = 0; + goto retry; + } + + DSSERR("Could not find suitable clock settings.\n"); + + return -EINVAL; + } +found: + cinfo->regm_dispc = best_regm_dispc; + cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk; + + *dispc_cinfo = best_dispc; + + return 0; +} + int dsi_pll_set_clock_div(struct platform_device *dsidev, struct dsi_clock_info *cinfo) { @@ -2628,7 +2783,6 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel, static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; DSSDBG("Initial config of virtual channel %d", channel); @@ -2653,8 +2807,6 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); - - dsi->vc[channel].source = DSI_VC_SOURCE_L4; } static int dsi_vc_config_source(struct platform_device *dsidev, int channel, @@ -3625,12 +3777,13 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { int bpp = dsi_get_pixel_size(dsi->pix_fmt); + unsigned line_buf_size = dsi_get_line_buf_size(dsidev); struct omap_video_timings *timings = &dsi->timings; /* * Don't use line buffers if width is greater than the video * port's line buffer size */ - if (dsi->line_buffer_size <= timings->x_res * bpp / 8) + if (line_buf_size <= timings->x_res * bpp / 8) num_line_buffers = 0; else num_line_buffers = 2; @@ -3646,22 +3799,18 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) static void dsi_config_vp_sync_events(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - bool sync_end; + bool vsync_end = dsi->vm_timings.vp_vsync_end; + bool hsync_end = dsi->vm_timings.vp_hsync_end; u32 r; - if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE) - sync_end = true; - else - sync_end = false; - r = dsi_read_reg(dsidev, DSI_CTRL); r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */ r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */ - r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */ + r = FLD_MOD(r, vsync_end, 16, 16); /* VP_VSYNC_END */ r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ - r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */ + r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */ dsi_write_reg(dsidev, DSI_CTRL, r); } @@ -3748,8 +3897,9 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, return max(lp_inter, 0); } -static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) +static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int blanking_mode; int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; @@ -3760,7 +3910,7 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) struct omap_video_timings *timings = &dsi->timings; int bpp = dsi_get_pixel_size(dsi->pix_fmt); int ndl = dsi->num_lanes_used - 1; - int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1; + int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; int hsa_interleave_hs = 0, hsa_interleave_lp = 0; int hfp_interleave_hs = 0, hfp_interleave_lp = 0; int hbp_interleave_hs = 0, hbp_interleave_lp = 0; @@ -3865,8 +4015,9 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) dsi_write_reg(dsidev, DSI_VM_TIMING6, r); } -static int dsi_proto_config(struct platform_device *dsidev) +static int dsi_proto_config(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; int buswidth = 0; @@ -3924,7 +4075,7 @@ static int dsi_proto_config(struct platform_device *dsidev) if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_config_vp_sync_events(dsidev); dsi_config_blanking_modes(dsidev); - dsi_config_cmd_mode_interleaving(dsidev); + dsi_config_cmd_mode_interleaving(dssdev); } dsi_vc_initial_config(dsidev, 0); @@ -4008,12 +4159,11 @@ static void dsi_proto_timings(struct platform_device *dsidev) int vfp = dsi->vm_timings.vfp; int vbp = dsi->vm_timings.vbp; int window_sync = dsi->vm_timings.window_sync; - bool hsync_end; + bool hsync_end = dsi->vm_timings.vp_hsync_end; struct omap_video_timings *timings = &dsi->timings; int bpp = dsi_get_pixel_size(dsi->pix_fmt); int tl, t_he, width_bytes; - hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE; t_he = hsync_end ? ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0; @@ -4116,26 +4266,82 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_dsi_configure_pins); +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, + unsigned long ddr_clk, unsigned long lp_clk) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cinfo; + struct dispc_clock_info dispc_cinfo; + unsigned lp_clk_div; + unsigned long dsi_fclk; + int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + unsigned long pck; + int r; + + DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); + + mutex_lock(&dsi->lock); + + /* Calculate PLL output clock */ + r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); + if (r) + goto err; + + /* Calculate PLL's DSI clock */ + dsi_pll_calc_dsi_fck(dsidev, &cinfo); + + /* Calculate PLL's DISPC clock and pck & lck divs */ + pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; + DSSDBG("finding dispc dividers for pck %lu\n", pck); + r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); + if (r) + goto err; + + /* Calculate LP clock */ + dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; + lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); + + dssdev->clocks.dsi.regn = cinfo.regn; + dssdev->clocks.dsi.regm = cinfo.regm; + dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; + dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi; + + dssdev->clocks.dsi.lp_clk_div = lp_clk_div; + + dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; + dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; + + dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; + + dssdev->clocks.dispc.channel.lcd_clk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; + + dssdev->clocks.dsi.dsi_fclk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI; + + mutex_unlock(&dsi->lock); + return 0; +err: + mutex_unlock(&dsi->lock); + return r; +} +EXPORT_SYMBOL(omapdss_dsi_set_clocks); + int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_overlay_manager *mgr = dsi->output.manager; + struct omap_overlay_manager *mgr = dssdev->output->manager; int bpp = dsi_get_pixel_size(dsi->pix_fmt); - struct omap_dss_output *out = &dsi->output; u8 data_type; u16 word_count; int r; - if (out == NULL || out->manager == NULL) { - DSSERR("failed to enable display: no output/manager\n"); - return -ENODEV; - } - - r = dsi_display_init_dispc(dsidev, mgr); - if (r) - goto err_init_dispc; - if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { switch (dsi->pix_fmt) { case OMAP_DSS_DSI_FMT_RGB888: @@ -4151,8 +4357,8 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; break; default: - r = -EINVAL; - goto err_pix_fmt; + BUG(); + return -EINVAL; }; dsi_if_enable(dsidev, false); @@ -4171,20 +4377,16 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) } r = dss_mgr_enable(mgr); - if (r) - goto err_mgr_enable; - - return 0; + if (r) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); + } -err_mgr_enable: - if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); + return r; } -err_pix_fmt: - dsi_display_uninit_dispc(dsidev, mgr); -err_init_dispc: - return r; + + return 0; } EXPORT_SYMBOL(dsi_enable_video_output); @@ -4192,7 +4394,7 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_overlay_manager *mgr = dsi->output.manager; + struct omap_overlay_manager *mgr = dssdev->output->manager; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); @@ -4206,15 +4408,14 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) } dss_mgr_disable(mgr); - - dsi_display_uninit_dispc(dsidev, mgr); } EXPORT_SYMBOL(dsi_disable_video_output); -static void dsi_update_screen_dispc(struct platform_device *dsidev) +static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_overlay_manager *mgr = dsi->output.manager; + struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned bytespp; unsigned bytespl; unsigned bytespf; @@ -4224,7 +4425,7 @@ static void dsi_update_screen_dispc(struct platform_device *dsidev) u32 l; int r; const unsigned channel = dsi->update_channel; - const unsigned line_buf_size = dsi->line_buffer_size; + const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); u16 w = dsi->timings.x_res; u16 h = dsi->timings.y_res; @@ -4370,7 +4571,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel, dsi->update_bytes = dw * dh * dsi_get_pixel_size(dsi->pix_fmt) / 8; #endif - dsi_update_screen_dispc(dsidev); + dsi_update_screen_dispc(dssdev); return 0; } @@ -4378,17 +4579,18 @@ EXPORT_SYMBOL(omap_dsi_update); /* Display funcs */ -static int dsi_configure_dispc_clocks(struct platform_device *dsidev) +static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dispc_clock_info dispc_cinfo; int r; - unsigned long fck; + unsigned long long fck; fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); - dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div; - dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div; + dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div; + dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div; r = dispc_calc_clock_rates(fck, &dispc_cinfo); if (r) { @@ -4401,17 +4603,21 @@ static int dsi_configure_dispc_clocks(struct platform_device *dsidev) return 0; } -static int dsi_display_init_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr) +static int dsi_display_init_dispc(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; - dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ? - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC); - if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { + dsi->timings.hsw = 1; + dsi->timings.hfp = 1; + dsi->timings.hbp = 1; + dsi->timings.vsw = 1; + dsi->timings.vfp = 0; + dsi->timings.vbp = 0; + r = dss_mgr_register_framedone_handler(mgr, dsi_framedone_irq_callback, dsidev); if (r) { @@ -4439,7 +4645,7 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dss_mgr_set_timings(mgr, &dsi->timings); - r = dsi_configure_dispc_clocks(dsidev); + r = dsi_configure_dispc_clocks(dssdev); if (r) goto err1; @@ -4456,30 +4662,30 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, dss_mgr_unregister_framedone_handler(mgr, dsi_framedone_irq_callback, dsidev); err: - dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); return r; } -static void dsi_display_uninit_dispc(struct platform_device *dsidev, - struct omap_overlay_manager *mgr) +static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) dss_mgr_unregister_framedone_handler(mgr, dsi_framedone_irq_callback, dsidev); - - dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); } -static int dsi_configure_dsi_clocks(struct platform_device *dsidev) +static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_clock_info cinfo; int r; - cinfo = dsi->user_dsi_cinfo; - + cinfo.regn = dssdev->clocks.dsi.regn; + cinfo.regm = dssdev->clocks.dsi.regm; + cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc; + cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi; r = dsi_calc_clock_rates(dsidev, &cinfo); if (r) { DSSERR("Failed to calc dsi clocks\n"); @@ -4495,22 +4701,24 @@ static int dsi_configure_dsi_clocks(struct platform_device *dsidev) return 0; } -static int dsi_display_init_dsi(struct platform_device *dsidev) +static int dsi_display_init_dsi(struct omap_dss_device *dssdev) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; r = dsi_pll_init(dsidev, true, true); if (r) goto err0; - r = dsi_configure_dsi_clocks(dsidev); + r = dsi_configure_dsi_clocks(dssdev); if (r) goto err1; - dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ? - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI); + dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); + dss_select_lcd_clk_source(mgr->id, + dssdev->clocks.dispc.channel.lcd_clk_src); DSSDBG("PLL OK\n"); @@ -4521,12 +4729,12 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) _dsi_print_reset_status(dsidev); dsi_proto_timings(dsidev); - dsi_set_lp_clk_divisor(dsidev); + dsi_set_lp_clk_divisor(dssdev); if (1) _dsi_print_reset_status(dsidev); - r = dsi_proto_config(dsidev); + r = dsi_proto_config(dssdev); if (r) goto err3; @@ -4543,16 +4751,20 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) dsi_cio_uninit(dsidev); err2: dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); + err1: dsi_pll_uninit(dsidev, true); err0: return r; } -static void dsi_display_uninit_dsi(struct platform_device *dsidev, +static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, bool disconnect_lanes, bool enter_ulps) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; if (enter_ulps && !dsi->ulps_enabled) dsi_enter_ulps(dsidev); @@ -4565,6 +4777,7 @@ static void dsi_display_uninit_dsi(struct platform_device *dsidev, dsi_vc_enable(dsidev, 3, 0); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); dsi_cio_uninit(dsidev); dsi_pll_uninit(dsidev, disconnect_lanes); } @@ -4573,6 +4786,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = dssdev->output; int r = 0; DSSDBG("dsi_display_enable\n"); @@ -4581,6 +4795,12 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dsi->lock); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); + r = -ENODEV; + goto err_start_dev; + } + r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); @@ -4595,7 +4815,11 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) _dsi_initialize_irq(dsidev); - r = dsi_display_init_dsi(dsidev); + r = dsi_display_init_dispc(dssdev); + if (r) + goto err_init_dispc; + + r = dsi_display_init_dsi(dssdev); if (r) goto err_init_dsi; @@ -4604,6 +4828,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) return 0; err_init_dsi: + dsi_display_uninit_dispc(dssdev); +err_init_dispc: dsi_enable_pll_clock(dsidev, 0); dsi_runtime_put(dsidev); err_get_dsi: @@ -4632,7 +4858,9 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, dsi_sync_vc(dsidev, 2); dsi_sync_vc(dsidev, 3); - dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps); + dsi_display_uninit_dispc(dssdev); + + dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); dsi_runtime_put(dsidev); dsi_enable_pll_clock(dsidev, 0); @@ -4653,577 +4881,75 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) } EXPORT_SYMBOL(omapdss_dsi_enable_te); -#ifdef PRINT_VERBOSE_VM_TIMINGS -static void print_dsi_vm(const char *str, - const struct omap_dss_dsi_videomode_timings *t) -{ - unsigned long byteclk = t->hsclk / 4; - int bl, wc, pps, tot; - - wc = DIV_ROUND_UP(t->hact * t->bitspp, 8); - pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */ - bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp; - tot = bl + pps; - -#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk)) - - pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, " - "%u/%u/%u/%u/%u/%u = %u + %u = %u\n", - str, - byteclk, - t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp, - bl, pps, tot, - TO_DSI_T(t->hss), - TO_DSI_T(t->hsa), - TO_DSI_T(t->hse), - TO_DSI_T(t->hbp), - TO_DSI_T(pps), - TO_DSI_T(t->hfp), - - TO_DSI_T(bl), - TO_DSI_T(pps), - - TO_DSI_T(tot)); -#undef TO_DSI_T -} - -static void print_dispc_vm(const char *str, const struct omap_video_timings *t) -{ - unsigned long pck = t->pixel_clock * 1000; - int hact, bl, tot; - - hact = t->x_res; - bl = t->hsw + t->hbp + t->hfp; - tot = hact + bl; - -#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck)) - - pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, " - "%u/%u/%u/%u = %u + %u = %u\n", - str, - pck, - t->hsw, t->hbp, hact, t->hfp, - bl, hact, tot, - TO_DISPC_T(t->hsw), - TO_DISPC_T(t->hbp), - TO_DISPC_T(hact), - TO_DISPC_T(t->hfp), - TO_DISPC_T(bl), - TO_DISPC_T(hact), - TO_DISPC_T(tot)); -#undef TO_DISPC_T -} - -/* note: this is not quite accurate */ -static void print_dsi_dispc_vm(const char *str, - const struct omap_dss_dsi_videomode_timings *t) -{ - struct omap_video_timings vm = { 0 }; - unsigned long byteclk = t->hsclk / 4; - unsigned long pck; - u64 dsi_tput; - int dsi_hact, dsi_htot; - - dsi_tput = (u64)byteclk * t->ndl * 8; - pck = (u32)div64_u64(dsi_tput, t->bitspp); - dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl); - dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp; - - vm.pixel_clock = pck / 1000; - vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk); - vm.hbp = div64_u64((u64)t->hbp * pck, byteclk); - vm.hfp = div64_u64((u64)t->hfp * pck, byteclk); - vm.x_res = t->hact; - - print_dispc_vm(str, &vm); -} -#endif /* PRINT_VERBOSE_VM_TIMINGS */ - -static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, - unsigned long pck, void *data) +void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { - struct dsi_clk_calc_ctx *ctx = data; - struct omap_video_timings *t = &ctx->dispc_vm; - - ctx->dispc_cinfo.lck_div = lckd; - ctx->dispc_cinfo.pck_div = pckd; - ctx->dispc_cinfo.lck = lck; - ctx->dispc_cinfo.pck = pck; - - *t = *ctx->config->timings; - t->pixel_clock = pck / 1000; - t->x_res = ctx->config->timings->x_res; - t->y_res = ctx->config->timings->y_res; - t->hsw = t->hfp = t->hbp = t->vsw = 1; - t->vfp = t->vbp = 0; - - return true; -} - -static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, - void *data) -{ - struct dsi_clk_calc_ctx *ctx = data; - - ctx->dsi_cinfo.regm_dispc = regm_dispc; - ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; - - return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, - dsi_cm_calc_dispc_cb, ctx); -} - -static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint, - unsigned long pll, void *data) -{ - struct dsi_clk_calc_ctx *ctx = data; - - ctx->dsi_cinfo.regn = regn; - ctx->dsi_cinfo.regm = regm; - ctx->dsi_cinfo.fint = fint; - ctx->dsi_cinfo.clkin4ddr = pll; - - return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, - dsi_cm_calc_hsdiv_cb, ctx); -} - -static bool dsi_cm_calc(struct dsi_data *dsi, - const struct omap_dss_dsi_config *cfg, - struct dsi_clk_calc_ctx *ctx) -{ - unsigned long clkin; - int bitspp, ndl; - unsigned long pll_min, pll_max; - unsigned long pck, txbyteclk; - - clkin = clk_get_rate(dsi->sys_clk); - bitspp = dsi_get_pixel_size(cfg->pixel_format); - ndl = dsi->num_lanes_used - 1; - - /* - * Here we should calculate minimum txbyteclk to be able to send the - * frame in time, and also to handle TE. That's not very simple, though, - * especially as we go to LP between each pixel packet due to HW - * "feature". So let's just estimate very roughly and multiply by 1.5. - */ - pck = cfg->timings->pixel_clock * 1000; - pck = pck * 3 / 2; - txbyteclk = pck * bitspp / 8 / ndl; - - memset(ctx, 0, sizeof(*ctx)); - ctx->dsidev = dsi->pdev; - ctx->config = cfg; - ctx->req_pck_min = pck; - ctx->req_pck_nom = pck; - ctx->req_pck_max = pck * 3 / 2; - ctx->dsi_cinfo.clkin = clkin; - - pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4); - pll_max = cfg->hs_clk_max * 4; - - return dsi_pll_calc(dsi->pdev, clkin, - pll_min, pll_max, - dsi_cm_calc_pll_cb, ctx); -} - -static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev); - const struct omap_dss_dsi_config *cfg = ctx->config; - int bitspp = dsi_get_pixel_size(cfg->pixel_format); - int ndl = dsi->num_lanes_used - 1; - unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4; - unsigned long byteclk = hsclk / 4; - - unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max; - int xres; - int panel_htot, panel_hbl; /* pixels */ - int dispc_htot, dispc_hbl; /* pixels */ - int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */ - int hfp, hsa, hbp; - const struct omap_video_timings *req_vm; - struct omap_video_timings *dispc_vm; - struct omap_dss_dsi_videomode_timings *dsi_vm; - u64 dsi_tput, dispc_tput; - - dsi_tput = (u64)byteclk * ndl * 8; - - req_vm = cfg->timings; - req_pck_min = ctx->req_pck_min; - req_pck_max = ctx->req_pck_max; - req_pck_nom = ctx->req_pck_nom; - - dispc_pck = ctx->dispc_cinfo.pck; - dispc_tput = (u64)dispc_pck * bitspp; - - xres = req_vm->x_res; - - panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw; - panel_htot = xres + panel_hbl; - - dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl); - - /* - * When there are no line buffers, DISPC and DSI must have the - * same tput. Otherwise DISPC tput needs to be higher than DSI's. - */ - if (dsi->line_buffer_size < xres * bitspp / 8) { - if (dispc_tput != dsi_tput) - return false; - } else { - if (dispc_tput < dsi_tput) - return false; - } - - /* DSI tput must be over the min requirement */ - if (dsi_tput < (u64)bitspp * req_pck_min) - return false; - - /* When non-burst mode, DSI tput must be below max requirement. */ - if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) { - if (dsi_tput > (u64)bitspp * req_pck_max) - return false; - } - - hss = DIV_ROUND_UP(4, ndl); - - if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) { - if (ndl == 3 && req_vm->hsw == 0) - hse = 1; - else - hse = DIV_ROUND_UP(4, ndl); - } else { - hse = 0; - } - - /* DSI htot to match the panel's nominal pck */ - dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom); - - /* fail if there would be no time for blanking */ - if (dsi_htot < hss + hse + dsi_hact) - return false; - - /* total DSI blanking needed to achieve panel's TL */ - dsi_hbl = dsi_htot - dsi_hact; - - /* DISPC htot to match the DSI TL */ - dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk); - - /* verify that the DSI and DISPC TLs are the same */ - if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk) - return false; - - dispc_hbl = dispc_htot - xres; - - /* setup DSI videomode */ - - dsi_vm = &ctx->dsi_vm; - memset(dsi_vm, 0, sizeof(*dsi_vm)); - - dsi_vm->hsclk = hsclk; - - dsi_vm->ndl = ndl; - dsi_vm->bitspp = bitspp; - - if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) { - hsa = 0; - } else if (ndl == 3 && req_vm->hsw == 0) { - hsa = 0; - } else { - hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom); - hsa = max(hsa - hse, 1); - } - - hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom); - hbp = max(hbp, 1); - - hfp = dsi_hbl - (hss + hsa + hse + hbp); - if (hfp < 1) { - int t; - /* we need to take cycles from hbp */ - - t = 1 - hfp; - hbp = max(hbp - t, 1); - hfp = dsi_hbl - (hss + hsa + hse + hbp); - - if (hfp < 1 && hsa > 0) { - /* we need to take cycles from hsa */ - t = 1 - hfp; - hsa = max(hsa - t, 1); - hfp = dsi_hbl - (hss + hsa + hse + hbp); - } - } - - if (hfp < 1) - return false; - - dsi_vm->hss = hss; - dsi_vm->hsa = hsa; - dsi_vm->hse = hse; - dsi_vm->hbp = hbp; - dsi_vm->hact = xres; - dsi_vm->hfp = hfp; - - dsi_vm->vsa = req_vm->vsw; - dsi_vm->vbp = req_vm->vbp; - dsi_vm->vact = req_vm->y_res; - dsi_vm->vfp = req_vm->vfp; - - dsi_vm->trans_mode = cfg->trans_mode; - - dsi_vm->blanking_mode = 0; - dsi_vm->hsa_blanking_mode = 1; - dsi_vm->hfp_blanking_mode = 1; - dsi_vm->hbp_blanking_mode = 1; - - dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on; - dsi_vm->window_sync = 4; - - /* setup DISPC videomode */ - - dispc_vm = &ctx->dispc_vm; - *dispc_vm = *req_vm; - dispc_vm->pixel_clock = dispc_pck / 1000; - - if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) { - hsa = div64_u64((u64)req_vm->hsw * dispc_pck, - req_pck_nom); - hsa = max(hsa, 1); - } else { - hsa = 1; - } - - hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom); - hbp = max(hbp, 1); - - hfp = dispc_hbl - hsa - hbp; - if (hfp < 1) { - int t; - /* we need to take cycles from hbp */ - - t = 1 - hfp; - hbp = max(hbp - t, 1); - hfp = dispc_hbl - hsa - hbp; - - if (hfp < 1) { - /* we need to take cycles from hsa */ - t = 1 - hfp; - hsa = max(hsa - t, 1); - hfp = dispc_hbl - hsa - hbp; - } - } + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (hfp < 1) - return false; + mutex_lock(&dsi->lock); - dispc_vm->hfp = hfp; - dispc_vm->hsw = hsa; - dispc_vm->hbp = hbp; + dsi->timings = *timings; - return true; + mutex_unlock(&dsi->lock); } +EXPORT_SYMBOL(omapdss_dsi_set_timings); - -static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, - unsigned long pck, void *data) +void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) { - struct dsi_clk_calc_ctx *ctx = data; - - ctx->dispc_cinfo.lck_div = lckd; - ctx->dispc_cinfo.pck_div = pckd; - ctx->dispc_cinfo.lck = lck; - ctx->dispc_cinfo.pck = pck; + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dsi_vm_calc_blanking(ctx) == false) - return false; + mutex_lock(&dsi->lock); -#ifdef PRINT_VERBOSE_VM_TIMINGS - print_dispc_vm("dispc", &ctx->dispc_vm); - print_dsi_vm("dsi ", &ctx->dsi_vm); - print_dispc_vm("req ", ctx->config->timings); - print_dsi_dispc_vm("act ", &ctx->dsi_vm); -#endif + dsi->timings.x_res = w; + dsi->timings.y_res = h; - return true; + mutex_unlock(&dsi->lock); } +EXPORT_SYMBOL(omapdss_dsi_set_size); -static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, - void *data) +void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, + enum omap_dss_dsi_pixel_format fmt) { - struct dsi_clk_calc_ctx *ctx = data; - unsigned long pck_max; - - ctx->dsi_cinfo.regm_dispc = regm_dispc; - ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; - - /* - * In burst mode we can let the dispc pck be arbitrarily high, but it - * limits our scaling abilities. So for now, don't aim too high. - */ - - if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE) - pck_max = ctx->req_pck_max + 10000000; - else - pck_max = ctx->req_pck_max; - - return dispc_div_calc(dispc, ctx->req_pck_min, pck_max, - dsi_vm_calc_dispc_cb, ctx); -} + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); -static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint, - unsigned long pll, void *data) -{ - struct dsi_clk_calc_ctx *ctx = data; + mutex_lock(&dsi->lock); - ctx->dsi_cinfo.regn = regn; - ctx->dsi_cinfo.regm = regm; - ctx->dsi_cinfo.fint = fint; - ctx->dsi_cinfo.clkin4ddr = pll; + dsi->pix_fmt = fmt; - return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, - dsi_vm_calc_hsdiv_cb, ctx); + mutex_unlock(&dsi->lock); } +EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); -static bool dsi_vm_calc(struct dsi_data *dsi, - const struct omap_dss_dsi_config *cfg, - struct dsi_clk_calc_ctx *ctx) +void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, + enum omap_dss_dsi_mode mode) { - const struct omap_video_timings *t = cfg->timings; - unsigned long clkin; - unsigned long pll_min; - unsigned long pll_max; - int ndl = dsi->num_lanes_used - 1; - int bitspp = dsi_get_pixel_size(cfg->pixel_format); - unsigned long byteclk_min; - - clkin = clk_get_rate(dsi->sys_clk); - - memset(ctx, 0, sizeof(*ctx)); - ctx->dsidev = dsi->pdev; - ctx->config = cfg; - - ctx->dsi_cinfo.clkin = clkin; - - /* these limits should come from the panel driver */ - ctx->req_pck_min = t->pixel_clock * 1000 - 1000; - ctx->req_pck_nom = t->pixel_clock * 1000; - ctx->req_pck_max = t->pixel_clock * 1000 + 1000; - - byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8); - pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4); + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) { - pll_max = cfg->hs_clk_max * 4; - } else { - unsigned long byteclk_max; - byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp, - ndl * 8); + mutex_lock(&dsi->lock); - pll_max = byteclk_max * 4 * 4; - } + dsi->mode = mode; - return dsi_pll_calc(dsi->pdev, clkin, - pll_min, pll_max, - dsi_vm_calc_pll_cb, ctx); + mutex_unlock(&dsi->lock); } +EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); -int omapdss_dsi_set_config(struct omap_dss_device *dssdev, - const struct omap_dss_dsi_config *config) +void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, + struct omap_dss_dsi_videomode_timings *timings) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct dsi_clk_calc_ctx ctx; - bool ok; - int r; mutex_lock(&dsi->lock); - dsi->pix_fmt = config->pixel_format; - dsi->mode = config->mode; - - if (config->mode == OMAP_DSS_DSI_VIDEO_MODE) - ok = dsi_vm_calc(dsi, config, &ctx); - else - ok = dsi_cm_calc(dsi, config, &ctx); - - if (!ok) { - DSSERR("failed to find suitable DSI clock settings\n"); - r = -EINVAL; - goto err; - } - - dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo); - - r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min, - config->lp_clk_max); - if (r) { - DSSERR("failed to find suitable DSI LP clock settings\n"); - goto err; - } - - dsi->user_dsi_cinfo = ctx.dsi_cinfo; - dsi->user_dispc_cinfo = ctx.dispc_cinfo; - - dsi->timings = ctx.dispc_vm; - dsi->vm_timings = ctx.dsi_vm; + dsi->vm_timings = *timings; mutex_unlock(&dsi->lock); - - return 0; -err: - mutex_unlock(&dsi->lock); - - return r; -} -EXPORT_SYMBOL(omapdss_dsi_set_config); - -/* - * Return a hardcoded channel for the DSI output. This should work for - * current use cases, but this can be later expanded to either resolve - * the channel in some more dynamic manner, or get the channel as a user - * parameter. - */ -static enum omap_channel dsi_get_channel(int module_id) -{ - switch (omapdss_get_version()) { - case OMAPDSS_VER_OMAP24xx: - DSSWARN("DSI not supported\n"); - return OMAP_DSS_CHANNEL_LCD; - - case OMAPDSS_VER_OMAP34xx_ES1: - case OMAPDSS_VER_OMAP34xx_ES3: - case OMAPDSS_VER_OMAP3630: - case OMAPDSS_VER_AM35xx: - return OMAP_DSS_CHANNEL_LCD; - - case OMAPDSS_VER_OMAP4430_ES1: - case OMAPDSS_VER_OMAP4430_ES2: - case OMAPDSS_VER_OMAP4: - switch (module_id) { - case 0: - return OMAP_DSS_CHANNEL_LCD; - case 1: - return OMAP_DSS_CHANNEL_LCD2; - default: - DSSWARN("unsupported module id\n"); - return OMAP_DSS_CHANNEL_LCD; - } - - case OMAPDSS_VER_OMAP5: - switch (module_id) { - case 0: - return OMAP_DSS_CHANNEL_LCD; - case 1: - return OMAP_DSS_CHANNEL_LCD3; - default: - DSSWARN("unsupported module id\n"); - return OMAP_DSS_CHANNEL_LCD; - } - - default: - DSSWARN("unsupported DSS version\n"); - return OMAP_DSS_CHANNEL_LCD; - } } +EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings); static int __init dsi_init_display(struct omap_dss_device *dssdev) { @@ -5462,8 +5188,6 @@ static void __init dsi_init_output(struct platform_device *dsidev) OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; out->type = OMAP_DISPLAY_TYPE_DSI; - out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; - out->dispc_channel = dsi_get_channel(dsi->module_id); dss_register_output(out); } @@ -5569,8 +5293,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) else dsi->num_lanes_supported = 3; - dsi->line_buffer_size = dsi_get_line_buf_size(dsidev); - dsi_init_output(dsidev); dsi_probe_pdata(dsidev); diff --git a/trunk/drivers/video/omap2/dss/dss.c b/trunk/drivers/video/omap2/dss/dss.c index b9f6f245d4a1..054c2a22b3f1 100644 --- a/trunk/drivers/video/omap2/dss/dss.c +++ b/trunk/drivers/video/omap2/dss/dss.c @@ -473,47 +473,6 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) return 0; } -bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data) -{ - int fckd, fckd_start, fckd_stop; - unsigned long fck; - unsigned long fck_hw_max; - unsigned long fckd_hw_max; - unsigned long prate; - unsigned m; - - if (dss.dpll4_m4_ck == NULL) { - /* - * TODO: dss1_fclk can be changed on OMAP2, but the available - * dividers are not continuous. We just use the pre-set rate for - * now. - */ - fck = clk_get_rate(dss.dss_clk); - fckd = 1; - return func(fckd, fck, data); - } - - fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); - fckd_hw_max = dss.feat->fck_div_max; - - m = dss.feat->dss_fck_multiplier; - prate = dss_get_dpll4_rate(); - - fck_min = fck_min ? fck_min : 1; - - fckd_start = min(prate * m / fck_min, fckd_hw_max); - fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul); - - for (fckd = fckd_start; fckd >= fckd_stop; --fckd) { - fck = prate / fckd * m; - - if (func(fckd, fck, data)) - return true; - } - - return false; -} - int dss_set_clock_div(struct dss_clock_info *cinfo) { if (dss.dpll4_m4_ck) { @@ -523,8 +482,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); DSSDBG("dpll4_m4 = %ld\n", prate); - r = clk_set_rate(dss.dpll4_m4_ck, - DIV_ROUND_UP(prate, cinfo->fck_div)); + r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); if (r) return r; } else { @@ -534,9 +492,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) dss.dss_clk_rate = clk_get_rate(dss.dss_clk); - WARN_ONCE(dss.dss_clk_rate != cinfo->fck, - "clk rate mismatch: %lu != %lu", dss.dss_clk_rate, - cinfo->fck); + WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); @@ -586,6 +542,121 @@ static int dss_setup_default_clock(void) return 0; } +int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, + struct dispc_clock_info *dispc_cinfo) +{ + unsigned long prate; + struct dss_clock_info best_dss; + struct dispc_clock_info best_dispc; + + unsigned long fck, max_dss_fck; + + u16 fck_div; + + int match = 0; + int min_fck_per_pck; + + prate = dss_get_dpll4_rate(); + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + fck = clk_get_rate(dss.dss_clk); + if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && + dss.cache_dss_cinfo.fck == fck) { + DSSDBG("dispc clock info found from cache.\n"); + *dss_cinfo = dss.cache_dss_cinfo; + *dispc_cinfo = dss.cache_dispc_cinfo; + return 0; + } + + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; + + if (min_fck_per_pck && + req_pck * min_fck_per_pck > max_dss_fck) { + DSSERR("Requested pixel clock not possible with the current " + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " + "the constraint off.\n"); + min_fck_per_pck = 0; + } + +retry: + memset(&best_dss, 0, sizeof(best_dss)); + memset(&best_dispc, 0, sizeof(best_dispc)); + + if (dss.dpll4_m4_ck == NULL) { + struct dispc_clock_info cur_dispc; + /* XXX can we change the clock on omap2? */ + fck = clk_get_rate(dss.dss_clk); + fck_div = 1; + + dispc_find_clk_divs(req_pck, fck, &cur_dispc); + match = 1; + + best_dss.fck = fck; + best_dss.fck_div = fck_div; + + best_dispc = cur_dispc; + + goto found; + } else { + for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { + struct dispc_clock_info cur_dispc; + + fck = prate / fck_div * dss.feat->dss_fck_multiplier; + + if (fck > max_dss_fck) + continue; + + if (min_fck_per_pck && + fck < req_pck * min_fck_per_pck) + continue; + + match = 1; + + dispc_find_clk_divs(req_pck, fck, &cur_dispc); + + if (abs(cur_dispc.pck - req_pck) < + abs(best_dispc.pck - req_pck)) { + + best_dss.fck = fck; + best_dss.fck_div = fck_div; + + best_dispc = cur_dispc; + + if (cur_dispc.pck == req_pck) + goto found; + } + } + } + +found: + if (!match) { + if (min_fck_per_pck) { + DSSERR("Could not find suitable clock settings.\n" + "Turning FCK/PCK constraint off and" + "trying again.\n"); + min_fck_per_pck = 0; + goto retry; + } + + DSSERR("Could not find suitable clock settings.\n"); + + return -EINVAL; + } + + if (dss_cinfo) + *dss_cinfo = best_dss; + if (dispc_cinfo) + *dispc_cinfo = best_dispc; + + dss.cache_req_pck = req_pck; + dss.cache_prate = prate; + dss.cache_dss_cinfo = best_dss; + dss.cache_dispc_cinfo = best_dispc; + + return 0; +} + void dss_set_venc_output(enum omap_dss_venc_type type) { int l = 0; diff --git a/trunk/drivers/video/omap2/dss/dss.h b/trunk/drivers/video/omap2/dss/dss.h index faaf35857b0e..610c8e563daa 100644 --- a/trunk/drivers/video/omap2/dss/dss.h +++ b/trunk/drivers/video/omap2/dss/dss.h @@ -268,9 +268,8 @@ void dss_set_dac_pwrdn_bgz(bool enable); unsigned long dss_get_dpll4_rate(void); int dss_calc_clock_rates(struct dss_clock_info *cinfo); int dss_set_clock_div(struct dss_clock_info *cinfo); - -typedef bool (*dss_div_calc_func)(int fckd, unsigned long fck, void *data); -bool dss_div_calc(unsigned long fck_min, dss_div_calc_func func, void *data); +int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, + struct dispc_clock_info *dispc_cinfo); /* SDI */ int sdi_init_platform_driver(void) __init; @@ -293,21 +292,12 @@ void dsi_dump_clocks(struct seq_file *s); void dsi_irq_handler(void); u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); -unsigned long dsi_get_pll_clkin(struct platform_device *dsidev); - -typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint, - unsigned long pll, void *data); -typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc, - void *data); -bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll, - unsigned long out_min, dsi_hsdiv_calc_func func, void *data); -bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin, - unsigned long pll_min, unsigned long pll_max, - dsi_pll_calc_func func, void *data); - unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); int dsi_pll_set_clock_div(struct platform_device *dsidev, struct dsi_clock_info *cinfo); +int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, + unsigned long req_pck, struct dsi_clock_info *cinfo, + struct dispc_clock_info *dispc_cinfo); int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, bool enable_hsdiv); void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); @@ -338,6 +328,14 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev, WARN("%s: DSI not compiled in\n", __func__); return -ENODEV; } +static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, + unsigned long req_pck, + struct dsi_clock_info *dsi_cinfo, + struct dispc_clock_info *dispc_cinfo) +{ + WARN("%s: DSI not compiled in\n", __func__); + return -ENODEV; +} static inline int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, bool enable_hsdiv) { @@ -378,15 +376,11 @@ void dispc_enable_fifomerge(bool enable); void dispc_enable_gamma_table(bool enable); void dispc_set_loadmode(enum omap_dss_load_mode mode); -typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, - unsigned long pck, void *data); -bool dispc_div_calc(unsigned long dispc, - unsigned long pck_min, unsigned long pck_max, - dispc_div_calc_func func, void *data); - bool dispc_mgr_timings_ok(enum omap_channel channel, const struct omap_video_timings *timings); unsigned long dispc_fclk_rate(void); +void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, + struct dispc_clock_info *cinfo); int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, struct dispc_clock_info *cinfo); diff --git a/trunk/drivers/video/omap2/dss/hdmi.c b/trunk/drivers/video/omap2/dss/hdmi.c index a6f953898d94..72923645dcce 100644 --- a/trunk/drivers/video/omap2/dss/hdmi.c +++ b/trunk/drivers/video/omap2/dss/hdmi.c @@ -472,12 +472,17 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, * Input clock is predivided by N + 1 * out put of which is reference clk */ - - pi->regn = HDMI_DEFAULT_REGN; + if (dssdev->clocks.hdmi.regn == 0) + pi->regn = HDMI_DEFAULT_REGN; + else + pi->regn = dssdev->clocks.hdmi.regn; refclk = clkin / pi->regn; - pi->regm2 = HDMI_DEFAULT_REGM2; + if (dssdev->clocks.hdmi.regm2 == 0) + pi->regm2 = HDMI_DEFAULT_REGM2; + else + pi->regm2 = dssdev->clocks.hdmi.regm2; /* * multiplier is pixel_clk/ref_clk @@ -1012,6 +1017,8 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) hdmi.ls_oe_gpio = priv->ls_oe_gpio; hdmi.hpd_gpio = priv->hpd_gpio; + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + r = hdmi_init_display(dssdev); if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); @@ -1044,8 +1051,6 @@ static void __init hdmi_init_output(struct platform_device *pdev) out->pdev = pdev; out->id = OMAP_DSS_OUTPUT_HDMI; out->type = OMAP_DISPLAY_TYPE_HDMI; - out->name = "hdmi.0"; - out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; dss_register_output(out); } @@ -1092,8 +1097,6 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.phy_offset = HDMI_PHY; - hdmi_init_output(pdev); - r = hdmi_panel_init(); if (r) { DSSERR("can't init panel\n"); @@ -1102,6 +1105,8 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi_init_output(pdev); + hdmi_probe_pdata(pdev); return 0; diff --git a/trunk/drivers/video/omap2/dss/output.c b/trunk/drivers/video/omap2/dss/output.c index 5214df63e0a9..79dea1a1a732 100644 --- a/trunk/drivers/video/omap2/dss/output.c +++ b/trunk/drivers/video/omap2/dss/output.c @@ -113,7 +113,6 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) return NULL; } -EXPORT_SYMBOL(omap_dss_get_output); static const struct dss_mgr_ops *dss_mgr_ops; diff --git a/trunk/drivers/video/omap2/dss/rfbi.c b/trunk/drivers/video/omap2/dss/rfbi.c index 1a691bb27547..e903dd3f54d9 100644 --- a/trunk/drivers/video/omap2/dss/rfbi.c +++ b/trunk/drivers/video/omap2/dss/rfbi.c @@ -1025,8 +1025,6 @@ static void __init rfbi_init_output(struct platform_device *pdev) out->pdev = pdev; out->id = OMAP_DSS_OUTPUT_DBI; out->type = OMAP_DISPLAY_TYPE_DBI; - out->name = "rfbi.0"; - out->dispc_channel = OMAP_DSS_CHANNEL_LCD; dss_register_output(out); } diff --git a/trunk/drivers/video/omap2/dss/sdi.c b/trunk/drivers/video/omap2/dss/sdi.c index e6baee2e84f8..62b5374ce438 100644 --- a/trunk/drivers/video/omap2/dss/sdi.c +++ b/trunk/drivers/video/omap2/dss/sdi.c @@ -41,72 +41,6 @@ static struct { struct omap_dss_output output; } sdi; -struct sdi_clk_calc_ctx { - unsigned long pck_min, pck_max; - - struct dss_clock_info dss_cinfo; - struct dispc_clock_info dispc_cinfo; -}; - -static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, - unsigned long pck, void *data) -{ - struct sdi_clk_calc_ctx *ctx = data; - - ctx->dispc_cinfo.lck_div = lckd; - ctx->dispc_cinfo.pck_div = pckd; - ctx->dispc_cinfo.lck = lck; - ctx->dispc_cinfo.pck = pck; - - return true; -} - -static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data) -{ - struct sdi_clk_calc_ctx *ctx = data; - - ctx->dss_cinfo.fck = fck; - ctx->dss_cinfo.fck_div = fckd; - - return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max, - dpi_calc_dispc_cb, ctx); -} - -static int sdi_calc_clock_div(unsigned long pclk, - struct dss_clock_info *dss_cinfo, - struct dispc_clock_info *dispc_cinfo) -{ - int i; - struct sdi_clk_calc_ctx ctx; - - /* - * DSS fclk gives us very few possibilities, so finding a good pixel - * clock may not be possible. We try multiple times to find the clock, - * each time widening the pixel clock range we look for, up to - * +/- 1MHz. - */ - - for (i = 0; i < 10; ++i) { - bool ok; - - memset(&ctx, 0, sizeof(ctx)); - if (pclk > 1000 * i * i * i) - ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu); - else - ctx.pck_min = 0; - ctx.pck_max = pclk + 1000 * i * i * i; - - ok = dss_div_calc(ctx.pck_min, dpi_calc_dss_cb, &ctx); - if (ok) { - *dss_cinfo = ctx.dss_cinfo; - *dispc_cinfo = ctx.dispc_cinfo; - return 0; - } - } - - return -EINVAL; -} - static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) { struct omap_overlay_manager *mgr = dssdev->output->manager; @@ -154,7 +88,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - r = sdi_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); + r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); if (r) goto err_calc_clock_div; @@ -344,8 +278,6 @@ static void __init sdi_init_output(struct platform_device *pdev) out->pdev = pdev; out->id = OMAP_DSS_OUTPUT_SDI; out->type = OMAP_DISPLAY_TYPE_SDI; - out->name = "sdi.0"; - out->dispc_channel = OMAP_DSS_CHANNEL_LCD; dss_register_output(out); } diff --git a/trunk/drivers/video/omap2/dss/venc.c b/trunk/drivers/video/omap2/dss/venc.c index 5cb983e2f170..006caf3cb509 100644 --- a/trunk/drivers/video/omap2/dss/venc.c +++ b/trunk/drivers/video/omap2/dss/venc.c @@ -786,6 +786,8 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) dss_copy_device_pdata(dssdev, plat_dssdev); + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + r = venc_init_display(dssdev); if (r) { DSSERR("device %s init failed: %d\n", dssdev->name, r); @@ -817,8 +819,6 @@ static void __init venc_init_output(struct platform_device *pdev) out->pdev = pdev; out->id = OMAP_DSS_OUTPUT_VENC; out->type = OMAP_DISPLAY_TYPE_VENC; - out->name = "venc.0"; - out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT; dss_register_output(out); } diff --git a/trunk/drivers/video/omap2/omapfb/omapfb-main.c b/trunk/drivers/video/omap2/omapfb/omapfb-main.c index f38348ea3375..ca585ef37f25 100644 --- a/trunk/drivers/video/omap2/omapfb/omapfb-main.c +++ b/trunk/drivers/video/omap2/omapfb/omapfb-main.c @@ -2388,7 +2388,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; struct omap_dss_output *out = dssdev->output; - mgr = omap_dss_get_overlay_manager(out->dispc_channel); + mgr = omap_dss_get_overlay_manager(dssdev->channel); if (!mgr || !out) continue; diff --git a/trunk/include/video/omapdss.h b/trunk/include/video/omapdss.h index 62ca9a77c1d6..caefa093337d 100644 --- a/trunk/include/video/omapdss.h +++ b/trunk/include/video/omapdss.h @@ -257,31 +257,10 @@ void rfbi_bus_unlock(void); /* DSI */ -enum omap_dss_dsi_trans_mode { - /* Sync Pulses: both sync start and end packets sent */ - OMAP_DSS_DSI_PULSE_MODE, - /* Sync Events: only sync start packets sent */ - OMAP_DSS_DSI_EVENT_MODE, - /* Burst: only sync start packets sent, pixels are time compressed */ - OMAP_DSS_DSI_BURST_MODE, -}; - struct omap_dss_dsi_videomode_timings { - unsigned long hsclk; - - unsigned ndl; - unsigned bitspp; - - /* pixels */ - u16 hact; - /* lines */ - u16 vact; - /* DSI video mode blanking data */ /* Unit: byte clock cycles */ - u16 hss; u16 hsa; - u16 hse; u16 hfp; u16 hbp; /* Unit: line clocks */ @@ -295,24 +274,14 @@ struct omap_dss_dsi_videomode_timings { int hbp_blanking_mode; int hfp_blanking_mode; - enum omap_dss_dsi_trans_mode trans_mode; + /* Video port sync events */ + bool vp_vsync_end; + bool vp_hsync_end; bool ddr_clk_always_on; int window_sync; }; -struct omap_dss_dsi_config { - enum omap_dss_dsi_mode mode; - enum omap_dss_dsi_pixel_format pixel_format; - const struct omap_video_timings *timings; - - unsigned long hs_clk_min, hs_clk_max; - unsigned long lp_clk_min, lp_clk_max; - - bool ddr_clk_always_on; - enum omap_dss_dsi_trans_mode trans_mode; -}; - void dsi_bus_lock(struct omap_dss_device *dssdev); void dsi_bus_unlock(struct omap_dss_device *dssdev); int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data, @@ -572,14 +541,9 @@ struct omap_dss_writeback_info { struct omap_dss_output { struct list_head list; - const char *name; - /* display type supported by the output */ enum omap_display_type type; - /* DISPC channel for this output */ - enum omap_channel dispc_channel; - /* output instance */ enum omap_dss_output_id id; @@ -597,7 +561,6 @@ struct omap_dss_device { enum omap_display_type type; - /* obsolete, to be removed */ enum omap_channel channel; union { @@ -627,11 +590,41 @@ struct omap_dss_device { } venc; } phy; + struct { + struct { + struct { + u16 lck_div; + u16 pck_div; + enum omap_dss_clk_source lcd_clk_src; + } channel; + + enum omap_dss_clk_source dispc_fclk_src; + } dispc; + + struct { + /* regn is one greater than TRM's REGN value */ + u16 regn; + u16 regm; + u16 regm_dispc; + u16 regm_dsi; + + u16 lp_clk_div; + enum omap_dss_clk_source dsi_fclk_src; + } dsi; + + struct { + /* regn is one greater than TRM's REGN value */ + u16 regn; + u16 regm2; + } hdmi; + } clocks; + struct { struct omap_video_timings timings; enum omap_dss_dsi_pixel_format dsi_pix_fmt; enum omap_dss_dsi_mode dsi_mode; + struct omap_dss_dsi_videomode_timings dsi_vm_timings; } panel; struct { @@ -836,8 +829,15 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable); int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); -int omapdss_dsi_set_config(struct omap_dss_device *dssdev, - const struct omap_dss_dsi_config *config); +void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h); +void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, + enum omap_dss_dsi_pixel_format fmt); +void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, + enum omap_dss_dsi_mode mode); +void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, + struct omap_dss_dsi_videomode_timings *timings); int omap_dsi_update(struct omap_dss_device *dssdev, int channel, void (*callback)(int, void *), void *data); @@ -846,6 +846,8 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id); void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel); int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, const struct omap_dsi_pin_config *pin_cfg); +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, + unsigned long ddr_clk, unsigned long lp_clk); int omapdss_dsi_display_enable(struct omap_dss_device *dssdev); void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,