Commit 3d62fe5b authored by Tomi Valkeinen's avatar Tomi Valkeinen

OMAPDSS: Merge omapdss topic branches

...@@ -110,6 +110,11 @@ static enum drm_connector_status omap_connector_detect( ...@@ -110,6 +110,11 @@ static enum drm_connector_status omap_connector_detect(
ret = connector_status_connected; ret = connector_status_connected;
else else
ret = connector_status_disconnected; 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 { } else {
ret = connector_status_unknown; ret = connector_status_unknown;
} }
...@@ -189,12 +194,30 @@ static int omap_connector_mode_valid(struct drm_connector *connector, ...@@ -189,12 +194,30 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
struct omap_video_timings timings = {0}; struct omap_video_timings timings = {0};
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct drm_display_mode *new_mode; struct drm_display_mode *new_mode;
int ret = MODE_BAD; int r, ret = MODE_BAD;
copy_timings_drm_to_omap(&timings, mode); copy_timings_drm_to_omap(&timings, mode);
mode->vrefresh = drm_mode_vrefresh(mode); mode->vrefresh = drm_mode_vrefresh(mode);
if (!dssdrv->check_timings(dssdev, &timings)) { /*
* 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) {
/* check if vrefresh is still valid */ /* check if vrefresh is still valid */
new_mode = drm_mode_duplicate(dev, mode); new_mode = drm_mode_duplicate(dev, mode);
new_mode->clock = timings.pixel_clock; new_mode->clock = timings.pixel_clock;
......
...@@ -74,6 +74,13 @@ struct omap_crtc { ...@@ -74,6 +74,13 @@ struct omap_crtc {
struct work_struct page_flip_work; 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 * Manager-ops, callbacks from output when they need to configure
* the upstream part of the video pipe. * the upstream part of the video pipe.
...@@ -613,7 +620,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -613,7 +620,13 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc->apply.pre_apply = omap_crtc_pre_apply; omap_crtc->apply.pre_apply = omap_crtc_pre_apply;
omap_crtc->apply.post_apply = omap_crtc_post_apply; omap_crtc->apply.post_apply = omap_crtc_post_apply;
omap_crtc->apply_irq.irqmask = pipe2vbl(id); 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.irq = omap_crtc_apply_irq; omap_crtc->apply_irq.irq = omap_crtc_apply_irq;
omap_crtc->error_irq.irqmask = omap_crtc->error_irq.irqmask =
...@@ -621,12 +634,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, ...@@ -621,12 +634,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc->error_irq.irq = omap_crtc_error_irq; omap_crtc->error_irq.irq = omap_crtc_error_irq;
omap_irq_register(dev, &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: */ /* temporary: */
omap_crtc->mgr.id = channel; omap_crtc->mgr.id = channel;
......
...@@ -74,54 +74,53 @@ static int get_connector_type(struct omap_dss_device *dssdev) ...@@ -74,54 +74,53 @@ 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) static int omap_modeset_init(struct drm_device *dev)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
struct omap_dss_device *dssdev = NULL; struct omap_dss_device *dssdev = NULL;
int num_ovls = dss_feat_get_num_ovls(); int num_ovls = dss_feat_get_num_ovls();
int id; int num_mgrs = dss_feat_get_num_mgrs();
int num_crtcs;
int i, id = 0;
drm_mode_config_init(dev); drm_mode_config_init(dev);
omap_drm_irq_install(dev); omap_drm_irq_install(dev);
/* /*
* Create private planes and CRTCs for the last NUM_CRTCs overlay * We usually don't want to create a CRTC for each manager, at least
* plus manager: * 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.
*/ */
for (id = 0; id < min(num_crtc, num_ovls); id++) { num_crtcs = min3(num_crtc, num_mgrs, num_ovls);
struct drm_plane *plane;
struct drm_crtc *crtc;
plane = omap_plane_init(dev, id, true);
crtc = omap_crtc_init(dev, plane, pipe2chan(id), id);
BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); dssdev = NULL;
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) { for_each_dss_dev(dssdev) {
struct drm_connector *connector; struct drm_connector *connector;
struct drm_encoder *encoder; struct drm_encoder *encoder;
enum omap_channel channel;
if (!dssdev->driver) { if (!dssdev->driver) {
dev_warn(dev->dev, "%s has no driver.. skipping it\n", dev_warn(dev->dev, "%s has no driver.. skipping it\n",
dssdev->name); dssdev->name);
return 0; continue;
} }
if (!(dssdev->driver->get_timings || if (!(dssdev->driver->get_timings ||
...@@ -129,7 +128,7 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -129,7 +128,7 @@ static int omap_modeset_init(struct drm_device *dev)
dev_warn(dev->dev, "%s driver does not support " dev_warn(dev->dev, "%s driver does not support "
"get_timings or read_edid.. skipping it!\n", "get_timings or read_edid.. skipping it!\n",
dssdev->name); dssdev->name);
return 0; continue;
} }
encoder = omap_encoder_init(dev, dssdev); encoder = omap_encoder_init(dev, dssdev);
...@@ -157,16 +156,118 @@ static int omap_modeset_init(struct drm_device *dev) ...@@ -157,16 +156,118 @@ static int omap_modeset_init(struct drm_device *dev)
drm_mode_connector_attach_encoder(connector, encoder); 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: */ /* figure out which crtc's we can connect the encoder to: */
encoder->possible_crtcs = 0; encoder->possible_crtcs = 0;
for (id = 0; id < priv->num_crtcs; id++) { for (id = 0; id < priv->num_crtcs; id++) {
enum omap_dss_output_id supported_outputs = struct drm_crtc *crtc = priv->crtcs[id];
dss_feat_get_supported_outputs(pipe2chan(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);
if (supported_outputs & dssdev->output->id) if (supported_outputs & dssdev->output->id)
encoder->possible_crtcs |= (1 << 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_width = 32;
dev->mode_config.min_height = 32; dev->mode_config.min_height = 32;
...@@ -303,7 +404,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, ...@@ -303,7 +404,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
return ret; return ret;
} }
struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { static 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_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_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), DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH),
...@@ -567,7 +668,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = { ...@@ -567,7 +668,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = {
}; };
#endif #endif
struct platform_driver pdev = { static struct platform_driver pdev = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); ...@@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m);
int omap_gem_resume(struct device *dev); int omap_gem_resume(struct device *dev);
#endif #endif
int omap_irq_enable_vblank(struct drm_device *dev, int crtc); int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id);
void omap_irq_disable_vblank(struct drm_device *dev, int crtc); void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id);
irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); irqreturn_t omap_irq_handler(DRM_IRQ_ARGS);
void omap_irq_preinstall(struct drm_device *dev); void omap_irq_preinstall(struct drm_device *dev);
int omap_irq_postinstall(struct drm_device *dev); int omap_irq_postinstall(struct drm_device *dev);
...@@ -271,39 +271,9 @@ static inline int align_pitch(int pitch, int width, int bpp) ...@@ -271,39 +271,9 @@ static inline int align_pitch(int pitch, int width, int bpp)
return ALIGN(pitch, 8 * bytespp); 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 */ /* map crtc to vblank mask */
static inline uint32_t pipe2vbl(int crtc) uint32_t pipe2vbl(struct drm_crtc *crtc);
{ struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder);
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? /* should these be made into common util helpers?
*/ */
......
...@@ -41,6 +41,13 @@ struct omap_encoder { ...@@ -41,6 +41,13 @@ struct omap_encoder {
struct omap_dss_device *dssdev; 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) static void omap_encoder_destroy(struct drm_encoder *encoder)
{ {
struct omap_encoder *omap_encoder = to_omap_encoder(encoder); struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
...@@ -128,13 +135,26 @@ int omap_encoder_update(struct drm_encoder *encoder, ...@@ -128,13 +135,26 @@ int omap_encoder_update(struct drm_encoder *encoder,
dssdev->output->manager = mgr; dssdev->output->manager = mgr;
ret = dssdrv->check_timings(dssdev, timings); 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;
}
if (ret) { if (ret) {
dev_err(dev->dev, "could not set timings: %d\n", ret); dev_err(dev->dev, "could not set timings: %d\n", ret);
return ret; return ret;
} }
dssdrv->set_timings(dssdev, timings); if (dssdrv->set_timings)
dssdrv->set_timings(dssdev, timings);
return 0; return 0;
} }
......
...@@ -178,7 +178,7 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, ...@@ -178,7 +178,7 @@ static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
return omap_gem_mmap_obj(obj, vma); return omap_gem_mmap_obj(obj, vma);
} }
struct dma_buf_ops omap_dmabuf_ops = { static struct dma_buf_ops omap_dmabuf_ops = {
.map_dma_buf = omap_gem_map_dma_buf, .map_dma_buf = omap_gem_map_dma_buf,
.unmap_dma_buf = omap_gem_unmap_dma_buf, .unmap_dma_buf = omap_gem_unmap_dma_buf,
.release = omap_gem_dmabuf_release, .release = omap_gem_dmabuf_release,
......
...@@ -130,12 +130,13 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, ...@@ -130,12 +130,13 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
* Zero on success, appropriate errno if the given @crtc's vblank * Zero on success, appropriate errno if the given @crtc's vblank
* interrupt cannot be enabled. * interrupt cannot be enabled.
*/ */
int omap_irq_enable_vblank(struct drm_device *dev, int crtc) int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc = priv->crtcs[crtc_id];
unsigned long flags; unsigned long flags;
DBG("dev=%p, crtc=%d", dev, crtc); DBG("dev=%p, crtc=%d", dev, crtc_id);
dispc_runtime_get(); dispc_runtime_get();
spin_lock_irqsave(&list_lock, flags); spin_lock_irqsave(&list_lock, flags);
...@@ -156,12 +157,13 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc) ...@@ -156,12 +157,13 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc)
* a hardware vblank counter, this routine should be a no-op, since * a hardware vblank counter, this routine should be a no-op, since
* interrupts will have to stay on to keep the count accurate. * interrupts will have to stay on to keep the count accurate.
*/ */
void omap_irq_disable_vblank(struct drm_device *dev, int crtc) void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id)
{ {
struct omap_drm_private *priv = dev->dev_private; struct omap_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc = priv->crtcs[crtc_id];
unsigned long flags; unsigned long flags;
DBG("dev=%p, crtc=%d", dev, crtc); DBG("dev=%p, crtc=%d", dev, crtc_id);
dispc_runtime_get(); dispc_runtime_get();
spin_lock_irqsave(&list_lock, flags); spin_lock_irqsave(&list_lock, flags);
...@@ -186,9 +188,12 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) ...@@ -186,9 +188,12 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS)
VERB("irqs: %08x", irqstatus); VERB("irqs: %08x", irqstatus);
for (id = 0; id < priv->num_crtcs; id++) for (id = 0; id < priv->num_crtcs; id++) {
if (irqstatus & pipe2vbl(id)) struct drm_crtc *crtc = priv->crtcs[id];
if (irqstatus & pipe2vbl(crtc))
drm_handle_vblank(dev, id); drm_handle_vblank(dev, id);
}
spin_lock_irqsave(&list_lock, flags); spin_lock_irqsave(&list_lock, flags);
list_for_each_entry_safe(handler, n, &priv->irq_list, node) { list_for_each_entry_safe(handler, n, &priv->irq_list, node) {
......
...@@ -247,6 +247,12 @@ static int omap_plane_update(struct drm_plane *plane, ...@@ -247,6 +247,12 @@ static int omap_plane_update(struct drm_plane *plane,
{ {
struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_plane *omap_plane = to_omap_plane(plane);
omap_plane->enabled = true; omap_plane->enabled = true;
if (plane->fb)
drm_framebuffer_unreference(plane->fb);
drm_framebuffer_reference(fb);
return omap_plane_mode_set(plane, crtc, fb, return omap_plane_mode_set(plane, crtc, fb,
crtc_x, crtc_y, crtc_w, crtc_h, crtc_x, crtc_y, crtc_w, crtc_h,
src_x, src_y, src_w, src_h, src_x, src_y, src_w, src_h,
......
...@@ -242,16 +242,22 @@ static int nec_8048_spi_remove(struct spi_device *spi) ...@@ -242,16 +242,22 @@ static int nec_8048_spi_remove(struct spi_device *spi)
return 0; return 0;
} }
static int nec_8048_spi_suspend(struct spi_device *spi, pm_message_t mesg) #ifdef CONFIG_PM_SLEEP
static int nec_8048_spi_suspend(struct device *dev)
{ {
struct spi_device *spi = to_spi_device(dev);
nec_8048_spi_send(spi, 2, 0x01); nec_8048_spi_send(spi, 2, 0x01);
mdelay(40); mdelay(40);
return 0; return 0;
} }
static int nec_8048_spi_resume(struct spi_device *spi) static int nec_8048_spi_resume(struct device *dev)
{ {
struct spi_device *spi = to_spi_device(dev);
/* reinitialize the panel */ /* reinitialize the panel */
spi_setup(spi); spi_setup(spi);
nec_8048_spi_send(spi, 2, 0x00); nec_8048_spi_send(spi, 2, 0x00);
...@@ -260,14 +266,20 @@ static int nec_8048_spi_resume(struct spi_device *spi) ...@@ -260,14 +266,20 @@ static int nec_8048_spi_resume(struct spi_device *spi)
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(nec_8048_spi_pm_ops, nec_8048_spi_suspend,
nec_8048_spi_resume);
#define NEC_8048_SPI_PM_OPS (&nec_8048_spi_pm_ops)
#else
#define NEC_8048_SPI_PM_OPS NULL
#endif
static struct spi_driver nec_8048_spi_driver = { static struct spi_driver nec_8048_spi_driver = {
.probe = nec_8048_spi_probe, .probe = nec_8048_spi_probe,
.remove = nec_8048_spi_remove, .remove = nec_8048_spi_remove,
.suspend = nec_8048_spi_suspend,
.resume = nec_8048_spi_resume,
.driver = { .driver = {
.name = "nec_8048_spi", .name = "nec_8048_spi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = NEC_8048_SPI_PM_OPS,
}, },
}; };
......
This diff is collapsed.
...@@ -435,20 +435,27 @@ static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_man ...@@ -435,20 +435,27 @@ 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) static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr)
{ {
unsigned long timeout = msecs_to_jiffies(500); unsigned long timeout = msecs_to_jiffies(500);
struct omap_dss_device *dssdev = mgr->get_device(mgr);
u32 irq; u32 irq;
int r; int r;
if (mgr->output == NULL)
return -ENODEV;
r = dispc_runtime_get(); r = dispc_runtime_get();
if (r) if (r)
return r; return r;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) switch (mgr->output->id) {
case OMAP_DSS_OUTPUT_VENC:
irq = DISPC_IRQ_EVSYNC_ODD; irq = DISPC_IRQ_EVSYNC_ODD;
else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) break;
case OMAP_DSS_OUTPUT_HDMI:
irq = DISPC_IRQ_EVSYNC_EVEN; irq = DISPC_IRQ_EVSYNC_EVEN;
else break;
default:
irq = dispc_mgr_get_vsync_irq(mgr->id); irq = dispc_mgr_get_vsync_irq(mgr->id);
break;
}
r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
......
...@@ -181,10 +181,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) ...@@ -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, d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
write, &dss_debug_fops); write, &dss_debug_fops);
if (IS_ERR(d)) return PTR_RET(d);
return PTR_ERR(d);
return 0;
} }
#else /* CONFIG_OMAP2_DSS_DEBUGFS */ #else /* CONFIG_OMAP2_DSS_DEBUGFS */
static inline int dss_initialize_debugfs(void) static inline int dss_initialize_debugfs(void)
......
...@@ -69,6 +69,8 @@ struct dispc_features { ...@@ -69,6 +69,8 @@ struct dispc_features {
u8 mgr_height_start; u8 mgr_height_start;
u16 mgr_width_max; u16 mgr_width_max;
u16 mgr_height_max; u16 mgr_height_max;
unsigned long max_lcd_pclk;
unsigned long max_tv_pclk;
int (*calc_scaling) (unsigned long pclk, unsigned long lclk, int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
const struct omap_video_timings *mgr_timings, const struct omap_video_timings *mgr_timings,
u16 width, u16 height, u16 out_width, u16 out_height, u16 width, u16 height, u16 out_width, u16 out_height,
...@@ -85,6 +87,9 @@ struct dispc_features { ...@@ -85,6 +87,9 @@ struct dispc_features {
/* no DISPC_IRQ_FRAMEDONETV on this SoC */ /* no DISPC_IRQ_FRAMEDONETV on this SoC */
bool no_framedone_tv:1; bool no_framedone_tv:1;
/* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
bool mstandby_workaround:1;
}; };
#define DISPC_MAX_NR_FIFOS 5 #define DISPC_MAX_NR_FIFOS 5
...@@ -97,6 +102,8 @@ static struct { ...@@ -97,6 +102,8 @@ static struct {
int irq; int irq;
unsigned long core_clk_rate;
u32 fifo_size[DISPC_MAX_NR_FIFOS]; u32 fifo_size[DISPC_MAX_NR_FIFOS];
/* maps which plane is using a fifo. fifo-id -> plane-id */ /* maps which plane is using a fifo. fifo-id -> plane-id */
int fifo_assignment[DISPC_MAX_NR_FIFOS]; int fifo_assignment[DISPC_MAX_NR_FIFOS];
...@@ -1584,6 +1591,7 @@ static void dispc_ovl_set_scaling(enum omap_plane plane, ...@@ -1584,6 +1591,7 @@ static void dispc_ovl_set_scaling(enum omap_plane plane,
} }
static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
enum omap_dss_rotation_type rotation_type,
bool mirroring, enum omap_color_mode color_mode) bool mirroring, enum omap_color_mode color_mode)
{ {
bool row_repeat = false; bool row_repeat = false;
...@@ -1634,6 +1642,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, ...@@ -1634,6 +1642,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
if (dss_has_feature(FEAT_ROWREPEATENABLE)) if (dss_has_feature(FEAT_ROWREPEATENABLE))
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
row_repeat ? 1 : 0, 18, 18); row_repeat ? 1 : 0, 18, 18);
if (color_mode == OMAP_DSS_COLOR_NV12) {
bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) &&
(rotation == OMAP_DSS_ROT_0 ||
rotation == OMAP_DSS_ROT_180);
/* DOUBLESTRIDE */
REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
}
} }
static int color_mode_to_bpp(enum omap_color_mode color_mode) static int color_mode_to_bpp(enum omap_color_mode color_mode)
...@@ -2512,7 +2529,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane, ...@@ -2512,7 +2529,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
dispc_ovl_set_vid_color_conv(plane, cconv); dispc_ovl_set_vid_color_conv(plane, cconv);
} }
dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
color_mode);
dispc_ovl_set_zorder(plane, caps, zorder); dispc_ovl_set_zorder(plane, caps, zorder);
dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
...@@ -2823,6 +2841,15 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, ...@@ -2823,6 +2841,15 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
return true; return true;
} }
static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
unsigned long pclk)
{
if (dss_mgr_is_lcd(channel))
return pclk <= dispc.feat->max_lcd_pclk ? true : false;
else
return pclk <= dispc.feat->max_tv_pclk ? true : false;
}
bool dispc_mgr_timings_ok(enum omap_channel channel, bool dispc_mgr_timings_ok(enum omap_channel channel,
const struct omap_video_timings *timings) const struct omap_video_timings *timings)
{ {
...@@ -2830,11 +2857,13 @@ bool dispc_mgr_timings_ok(enum omap_channel channel, ...@@ -2830,11 +2857,13 @@ bool dispc_mgr_timings_ok(enum omap_channel channel,
timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res);
if (dss_mgr_is_lcd(channel)) timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixel_clock * 1000);
timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw,
timings->hfp, timings->hbp, if (dss_mgr_is_lcd(channel)) {
timings->vsw, timings->vfp, timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
timings->vbp); timings->hbp, timings->vsw, timings->vfp,
timings->vbp);
}
return timings_ok; return timings_ok;
} }
...@@ -2951,6 +2980,10 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, ...@@ -2951,6 +2980,10 @@ static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
dispc_write_reg(DISPC_DIVISORo(channel), dispc_write_reg(DISPC_DIVISORo(channel),
FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); 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, static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
...@@ -3056,15 +3089,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) ...@@ -3056,15 +3089,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
unsigned long dispc_core_clk_rate(void) unsigned long dispc_core_clk_rate(void)
{ {
int lcd; return dispc.core_clk_rate;
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) static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
...@@ -3313,67 +3338,79 @@ static void dispc_dump_regs(struct seq_file *s) ...@@ -3313,67 +3338,79 @@ static void dispc_dump_regs(struct seq_file *s)
#undef DUMPREG #undef DUMPREG
} }
/* with fck as input clock rate, find dispc dividers that produce req_pck */ /* calculate clock rates using dividers in cinfo */
void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo) struct dispc_clock_info *cinfo)
{ {
u16 pcd_min, pcd_max; if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
unsigned long best_pck; return -EINVAL;
u16 best_ld, cur_ld; if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
u16 best_pd, cur_pd; return -EINVAL;
pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); cinfo->pck = cinfo->lck / cinfo->pck_div;
best_pck = 0; return 0;
best_ld = 0; }
best_pd = 0;
for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { bool dispc_div_calc(unsigned long dispc,
unsigned long lck = fck / cur_ld; 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;
for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) { #ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
unsigned long pck = lck / cur_pd; min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
long old_delta = abs(best_pck - req_pck); #else
long new_delta = abs(pck - req_pck); min_fck_per_pck = 0;
#endif
if (best_pck == 0 || new_delta < old_delta) { pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
best_pck = pck; pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
best_ld = cur_ld;
best_pd = cur_pd;
if (pck == req_pck) lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
goto found;
}
if (pck < req_pck) pck_min = pck_min ? pck_min : 1;
break; pck_max = pck_max ? pck_max : ULONG_MAX;
}
if (lck / pcd_min < req_pck) lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
break; lckd_stop = min(dispc / pck_min, 255ul);
}
found: for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
cinfo->lck_div = best_ld; lck = dispc / lckd;
cinfo->pck_div = best_pd;
cinfo->lck = fck / cinfo->lck_div;
cinfo->pck = cinfo->lck / cinfo->pck_div;
}
/* calculate clock rates using dividers in cinfo */ pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, pckd_stop = min(lck / pck_min, pckd_hw_max);
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;
cinfo->lck = dispc_fclk_rate / cinfo->lck_div; for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
cinfo->pck = cinfo->lck / cinfo->pck_div; pck = lck / pckd;
return 0; /*
* 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;
if (fck < pck * min_fck_per_pck)
continue;
if (func(lckd, pckd, lck, pck, data))
return true;
}
}
return false;
} }
void dispc_mgr_set_clock_div(enum omap_channel channel, void dispc_mgr_set_clock_div(enum omap_channel channel,
...@@ -3451,6 +3488,8 @@ static void _omap_dispc_initial_config(void) ...@@ -3451,6 +3488,8 @@ static void _omap_dispc_initial_config(void)
l = FLD_MOD(l, 1, 0, 0); l = FLD_MOD(l, 1, 0, 0);
l = FLD_MOD(l, 1, 23, 16); l = FLD_MOD(l, 1, 23, 16);
dispc_write_reg(DISPC_DIVISOR, l); dispc_write_reg(DISPC_DIVISOR, l);
dispc.core_clk_rate = dispc_fclk_rate();
} }
/* FUNCGATED */ /* FUNCGATED */
...@@ -3466,6 +3505,9 @@ static void _omap_dispc_initial_config(void) ...@@ -3466,6 +3505,9 @@ static void _omap_dispc_initial_config(void)
dispc_configure_burst_sizes(); dispc_configure_burst_sizes();
dispc_ovl_enable_zorder_planes(); dispc_ovl_enable_zorder_planes();
if (dispc.feat->mstandby_workaround)
REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
} }
static const struct dispc_features omap24xx_dispc_feats __initconst = { static const struct dispc_features omap24xx_dispc_feats __initconst = {
...@@ -3479,6 +3521,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = { ...@@ -3479,6 +3521,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = {
.mgr_height_start = 26, .mgr_height_start = 26,
.mgr_width_max = 2048, .mgr_width_max = 2048,
.mgr_height_max = 2048, .mgr_height_max = 2048,
.max_lcd_pclk = 66500000,
.calc_scaling = dispc_ovl_calc_scaling_24xx, .calc_scaling = dispc_ovl_calc_scaling_24xx,
.calc_core_clk = calc_core_clk_24xx, .calc_core_clk = calc_core_clk_24xx,
.num_fifos = 3, .num_fifos = 3,
...@@ -3496,6 +3539,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { ...@@ -3496,6 +3539,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
.mgr_height_start = 26, .mgr_height_start = 26,
.mgr_width_max = 2048, .mgr_width_max = 2048,
.mgr_height_max = 2048, .mgr_height_max = 2048,
.max_lcd_pclk = 173000000,
.max_tv_pclk = 59000000,
.calc_scaling = dispc_ovl_calc_scaling_34xx, .calc_scaling = dispc_ovl_calc_scaling_34xx,
.calc_core_clk = calc_core_clk_34xx, .calc_core_clk = calc_core_clk_34xx,
.num_fifos = 3, .num_fifos = 3,
...@@ -3513,6 +3558,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { ...@@ -3513,6 +3558,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
.mgr_height_start = 26, .mgr_height_start = 26,
.mgr_width_max = 2048, .mgr_width_max = 2048,
.mgr_height_max = 2048, .mgr_height_max = 2048,
.max_lcd_pclk = 173000000,
.max_tv_pclk = 59000000,
.calc_scaling = dispc_ovl_calc_scaling_34xx, .calc_scaling = dispc_ovl_calc_scaling_34xx,
.calc_core_clk = calc_core_clk_34xx, .calc_core_clk = calc_core_clk_34xx,
.num_fifos = 3, .num_fifos = 3,
...@@ -3530,6 +3577,8 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { ...@@ -3530,6 +3577,8 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = {
.mgr_height_start = 26, .mgr_height_start = 26,
.mgr_width_max = 2048, .mgr_width_max = 2048,
.mgr_height_max = 2048, .mgr_height_max = 2048,
.max_lcd_pclk = 170000000,
.max_tv_pclk = 185625000,
.calc_scaling = dispc_ovl_calc_scaling_44xx, .calc_scaling = dispc_ovl_calc_scaling_44xx,
.calc_core_clk = calc_core_clk_44xx, .calc_core_clk = calc_core_clk_44xx,
.num_fifos = 5, .num_fifos = 5,
...@@ -3547,10 +3596,13 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = { ...@@ -3547,10 +3596,13 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = {
.mgr_height_start = 27, .mgr_height_start = 27,
.mgr_width_max = 4096, .mgr_width_max = 4096,
.mgr_height_max = 4096, .mgr_height_max = 4096,
.max_lcd_pclk = 170000000,
.max_tv_pclk = 186000000,
.calc_scaling = dispc_ovl_calc_scaling_44xx, .calc_scaling = dispc_ovl_calc_scaling_44xx,
.calc_core_clk = calc_core_clk_44xx, .calc_core_clk = calc_core_clk_44xx,
.num_fifos = 5, .num_fifos = 5,
.gfx_fifo_workaround = true, .gfx_fifo_workaround = true,
.mstandby_workaround = true,
}; };
static int __init dispc_init_features(struct platform_device *pdev) static int __init dispc_init_features(struct platform_device *pdev)
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define DISPC_GLOBAL_BUFFER 0x0800 #define DISPC_GLOBAL_BUFFER 0x0800
#define DISPC_CONTROL3 0x0848 #define DISPC_CONTROL3 0x0848
#define DISPC_CONFIG3 0x084C #define DISPC_CONFIG3 0x084C
#define DISPC_MSTANDBY_CTRL 0x0858
/* DISPC overlay registers */ /* DISPC overlay registers */
#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
......
This diff is collapsed.
This diff is collapsed.
...@@ -473,6 +473,47 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) ...@@ -473,6 +473,47 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
return 0; 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) int dss_set_clock_div(struct dss_clock_info *cinfo)
{ {
if (dss.dpll4_m4_ck) { if (dss.dpll4_m4_ck) {
...@@ -482,7 +523,8 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) ...@@ -482,7 +523,8 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
DSSDBG("dpll4_m4 = %ld\n", prate); DSSDBG("dpll4_m4 = %ld\n", prate);
r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); r = clk_set_rate(dss.dpll4_m4_ck,
DIV_ROUND_UP(prate, cinfo->fck_div));
if (r) if (r)
return r; return r;
} else { } else {
...@@ -492,7 +534,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) ...@@ -492,7 +534,9 @@ int dss_set_clock_div(struct dss_clock_info *cinfo)
dss.dss_clk_rate = clk_get_rate(dss.dss_clk); dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); WARN_ONCE(dss.dss_clk_rate != cinfo->fck,
"clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
cinfo->fck);
DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
...@@ -542,121 +586,6 @@ static int dss_setup_default_clock(void) ...@@ -542,121 +586,6 @@ static int dss_setup_default_clock(void)
return 0; 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) void dss_set_venc_output(enum omap_dss_venc_type type)
{ {
int l = 0; int l = 0;
...@@ -767,13 +696,11 @@ int dss_dpi_select_source(enum omap_channel channel) ...@@ -767,13 +696,11 @@ int dss_dpi_select_source(enum omap_channel channel)
static int dss_get_clocks(void) static int dss_get_clocks(void)
{ {
struct clk *clk; struct clk *clk;
int r;
clk = clk_get(&dss.pdev->dev, "fck"); clk = devm_clk_get(&dss.pdev->dev, "fck");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
DSSERR("can't get clock fck\n"); DSSERR("can't get clock fck\n");
r = PTR_ERR(clk); return PTR_ERR(clk);
goto err;
} }
dss.dss_clk = clk; dss.dss_clk = clk;
...@@ -782,8 +709,7 @@ static int dss_get_clocks(void) ...@@ -782,8 +709,7 @@ static int dss_get_clocks(void)
clk = clk_get(NULL, dss.feat->clk_name); clk = clk_get(NULL, dss.feat->clk_name);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
DSSERR("Failed to get %s\n", dss.feat->clk_name); DSSERR("Failed to get %s\n", dss.feat->clk_name);
r = PTR_ERR(clk); return PTR_ERR(clk);
goto err;
} }
} else { } else {
clk = NULL; clk = NULL;
...@@ -792,21 +718,12 @@ static int dss_get_clocks(void) ...@@ -792,21 +718,12 @@ static int dss_get_clocks(void)
dss.dpll4_m4_ck = clk; dss.dpll4_m4_ck = clk;
return 0; return 0;
err:
if (dss.dss_clk)
clk_put(dss.dss_clk);
if (dss.dpll4_m4_ck)
clk_put(dss.dpll4_m4_ck);
return r;
} }
static void dss_put_clocks(void) static void dss_put_clocks(void)
{ {
if (dss.dpll4_m4_ck) if (dss.dpll4_m4_ck)
clk_put(dss.dpll4_m4_ck); clk_put(dss.dpll4_m4_ck);
clk_put(dss.dss_clk);
} }
static int dss_runtime_get(void) static int dss_runtime_get(void)
......
...@@ -268,8 +268,9 @@ void dss_set_dac_pwrdn_bgz(bool enable); ...@@ -268,8 +268,9 @@ void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void); unsigned long dss_get_dpll4_rate(void);
int dss_calc_clock_rates(struct dss_clock_info *cinfo); int dss_calc_clock_rates(struct dss_clock_info *cinfo);
int dss_set_clock_div(struct dss_clock_info *cinfo); int dss_set_clock_div(struct dss_clock_info *cinfo);
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_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);
/* SDI */ /* SDI */
int sdi_init_platform_driver(void) __init; int sdi_init_platform_driver(void) __init;
...@@ -292,12 +293,21 @@ void dsi_dump_clocks(struct seq_file *s); ...@@ -292,12 +293,21 @@ void dsi_dump_clocks(struct seq_file *s);
void dsi_irq_handler(void); void dsi_irq_handler(void);
u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); 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); unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
int dsi_pll_set_clock_div(struct platform_device *dsidev, int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo); 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, int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
bool enable_hsdiv); bool enable_hsdiv);
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
...@@ -328,14 +338,6 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev, ...@@ -328,14 +338,6 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
WARN("%s: DSI not compiled in\n", __func__); WARN("%s: DSI not compiled in\n", __func__);
return -ENODEV; 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, static inline int dsi_pll_init(struct platform_device *dsidev,
bool enable_hsclk, bool enable_hsdiv) bool enable_hsclk, bool enable_hsdiv)
{ {
...@@ -376,11 +378,15 @@ void dispc_enable_fifomerge(bool enable); ...@@ -376,11 +378,15 @@ void dispc_enable_fifomerge(bool enable);
void dispc_enable_gamma_table(bool enable); void dispc_enable_gamma_table(bool enable);
void dispc_set_loadmode(enum omap_dss_load_mode mode); 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, bool dispc_mgr_timings_ok(enum omap_channel channel,
const struct omap_video_timings *timings); const struct omap_video_timings *timings);
unsigned long dispc_fclk_rate(void); 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, int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
struct dispc_clock_info *cinfo); struct dispc_clock_info *cinfo);
......
...@@ -414,7 +414,7 @@ static const char * const omap5_dss_clk_source_names[] = { ...@@ -414,7 +414,7 @@ static const char * const omap5_dss_clk_source_names[] = {
}; };
static const struct dss_param_range omap2_dss_param_range[] = { static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, [FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 }, [FEAT_PARAM_DSS_PCD] = { 2, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
...@@ -459,15 +459,15 @@ static const struct dss_param_range omap4_dss_param_range[] = { ...@@ -459,15 +459,15 @@ static const struct dss_param_range omap4_dss_param_range[] = {
}; };
static const struct dss_param_range omap5_dss_param_range[] = { static const struct dss_param_range omap5_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, [FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 }, [FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, [FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, [FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
[FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, [FEAT_PARAM_LINEWIDTH] = { 1, 2048 },
}; };
......
...@@ -472,17 +472,12 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, ...@@ -472,17 +472,12 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
* Input clock is predivided by N + 1 * Input clock is predivided by N + 1
* out put of which is reference clk * out put of which is reference clk
*/ */
if (dssdev->clocks.hdmi.regn == 0)
pi->regn = HDMI_DEFAULT_REGN; pi->regn = HDMI_DEFAULT_REGN;
else
pi->regn = dssdev->clocks.hdmi.regn;
refclk = clkin / pi->regn; refclk = clkin / pi->regn;
if (dssdev->clocks.hdmi.regm2 == 0) pi->regm2 = HDMI_DEFAULT_REGM2;
pi->regm2 = HDMI_DEFAULT_REGM2;
else
pi->regm2 = dssdev->clocks.hdmi.regm2;
/* /*
* multiplier is pixel_clk/ref_clk * multiplier is pixel_clk/ref_clk
...@@ -804,7 +799,7 @@ static int hdmi_get_clocks(struct platform_device *pdev) ...@@ -804,7 +799,7 @@ static int hdmi_get_clocks(struct platform_device *pdev)
{ {
struct clk *clk; struct clk *clk;
clk = clk_get(&pdev->dev, "sys_clk"); clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n"); DSSERR("can't get sys_clk\n");
return PTR_ERR(clk); return PTR_ERR(clk);
...@@ -815,12 +810,6 @@ static int hdmi_get_clocks(struct platform_device *pdev) ...@@ -815,12 +810,6 @@ static int hdmi_get_clocks(struct platform_device *pdev)
return 0; return 0;
} }
static void hdmi_put_clocks(void)
{
if (hdmi.sys_clk)
clk_put(hdmi.sys_clk);
}
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts) int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts)
{ {
...@@ -1017,8 +1006,6 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) ...@@ -1017,8 +1006,6 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev)
hdmi.ls_oe_gpio = priv->ls_oe_gpio; hdmi.ls_oe_gpio = priv->ls_oe_gpio;
hdmi.hpd_gpio = priv->hpd_gpio; hdmi.hpd_gpio = priv->hpd_gpio;
dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
r = hdmi_init_display(dssdev); r = hdmi_init_display(dssdev);
if (r) { if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r); DSSERR("device %s init failed: %d\n", dssdev->name, r);
...@@ -1051,6 +1038,8 @@ static void __init hdmi_init_output(struct platform_device *pdev) ...@@ -1051,6 +1038,8 @@ static void __init hdmi_init_output(struct platform_device *pdev)
out->pdev = pdev; out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_HDMI; out->id = OMAP_DSS_OUTPUT_HDMI;
out->type = OMAP_DISPLAY_TYPE_HDMI; out->type = OMAP_DISPLAY_TYPE_HDMI;
out->name = "hdmi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
dss_register_output(out); dss_register_output(out);
} }
...@@ -1097,23 +1086,19 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -1097,23 +1086,19 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev)
hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.pll_offset = HDMI_PLLCTRL;
hdmi.ip_data.phy_offset = HDMI_PHY; hdmi.ip_data.phy_offset = HDMI_PHY;
hdmi_init_output(pdev);
r = hdmi_panel_init(); r = hdmi_panel_init();
if (r) { if (r) {
DSSERR("can't init panel\n"); DSSERR("can't init panel\n");
goto err_panel_init; return r;
} }
dss_debugfs_create_file("hdmi", hdmi_dump_regs); dss_debugfs_create_file("hdmi", hdmi_dump_regs);
hdmi_init_output(pdev);
hdmi_probe_pdata(pdev); hdmi_probe_pdata(pdev);
return 0; return 0;
err_panel_init:
hdmi_put_clocks();
return r;
} }
static int __exit hdmi_remove_child(struct device *dev, void *data) static int __exit hdmi_remove_child(struct device *dev, void *data)
...@@ -1135,8 +1120,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) ...@@ -1135,8 +1120,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
hdmi_put_clocks();
return 0; return 0;
} }
......
...@@ -113,6 +113,7 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) ...@@ -113,6 +113,7 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id)
return NULL; return NULL;
} }
EXPORT_SYMBOL(omap_dss_get_output);
static const struct dss_mgr_ops *dss_mgr_ops; static const struct dss_mgr_ops *dss_mgr_ops;
......
...@@ -1025,6 +1025,8 @@ static void __init rfbi_init_output(struct platform_device *pdev) ...@@ -1025,6 +1025,8 @@ static void __init rfbi_init_output(struct platform_device *pdev)
out->pdev = pdev; out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_DBI; out->id = OMAP_DSS_OUTPUT_DBI;
out->type = OMAP_DISPLAY_TYPE_DBI; out->type = OMAP_DISPLAY_TYPE_DBI;
out->name = "rfbi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
dss_register_output(out); dss_register_output(out);
} }
......
...@@ -41,6 +41,72 @@ static struct { ...@@ -41,6 +41,72 @@ static struct {
struct omap_dss_output output; struct omap_dss_output output;
} sdi; } 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) static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
{ {
struct omap_overlay_manager *mgr = dssdev->output->manager; struct omap_overlay_manager *mgr = dssdev->output->manager;
...@@ -88,7 +154,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) ...@@ -88,7 +154,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); r = sdi_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo);
if (r) if (r)
goto err_calc_clock_div; goto err_calc_clock_div;
...@@ -278,6 +344,8 @@ static void __init sdi_init_output(struct platform_device *pdev) ...@@ -278,6 +344,8 @@ static void __init sdi_init_output(struct platform_device *pdev)
out->pdev = pdev; out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_SDI; out->id = OMAP_DSS_OUTPUT_SDI;
out->type = OMAP_DISPLAY_TYPE_SDI; out->type = OMAP_DISPLAY_TYPE_SDI;
out->name = "sdi.0";
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
dss_register_output(out); dss_register_output(out);
} }
......
...@@ -712,7 +712,7 @@ static int venc_get_clocks(struct platform_device *pdev) ...@@ -712,7 +712,7 @@ static int venc_get_clocks(struct platform_device *pdev)
struct clk *clk; struct clk *clk;
if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) {
clk = clk_get(&pdev->dev, "tv_dac_clk"); clk = devm_clk_get(&pdev->dev, "tv_dac_clk");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
DSSERR("can't get tv_dac_clk\n"); DSSERR("can't get tv_dac_clk\n");
return PTR_ERR(clk); return PTR_ERR(clk);
...@@ -726,12 +726,6 @@ static int venc_get_clocks(struct platform_device *pdev) ...@@ -726,12 +726,6 @@ static int venc_get_clocks(struct platform_device *pdev)
return 0; return 0;
} }
static void venc_put_clocks(void)
{
if (venc.tv_dac_clk)
clk_put(venc.tv_dac_clk);
}
static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev)
{ {
struct omap_dss_board_info *pdata = pdev->dev.platform_data; struct omap_dss_board_info *pdata = pdev->dev.platform_data;
...@@ -777,8 +771,6 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) ...@@ -777,8 +771,6 @@ static void __init venc_probe_pdata(struct platform_device *vencdev)
dss_copy_device_pdata(dssdev, plat_dssdev); dss_copy_device_pdata(dssdev, plat_dssdev);
dssdev->channel = OMAP_DSS_CHANNEL_DIGIT;
r = venc_init_display(dssdev); r = venc_init_display(dssdev);
if (r) { if (r) {
DSSERR("device %s init failed: %d\n", dssdev->name, r); DSSERR("device %s init failed: %d\n", dssdev->name, r);
...@@ -810,6 +802,8 @@ static void __init venc_init_output(struct platform_device *pdev) ...@@ -810,6 +802,8 @@ static void __init venc_init_output(struct platform_device *pdev)
out->pdev = pdev; out->pdev = pdev;
out->id = OMAP_DSS_OUTPUT_VENC; out->id = OMAP_DSS_OUTPUT_VENC;
out->type = OMAP_DISPLAY_TYPE_VENC; out->type = OMAP_DISPLAY_TYPE_VENC;
out->name = "venc.0";
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
dss_register_output(out); dss_register_output(out);
} }
...@@ -877,7 +871,6 @@ static int __init omap_venchw_probe(struct platform_device *pdev) ...@@ -877,7 +871,6 @@ static int __init omap_venchw_probe(struct platform_device *pdev)
err_panel_init: err_panel_init:
err_runtime_get: err_runtime_get:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
venc_put_clocks();
return r; return r;
} }
...@@ -895,7 +888,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev) ...@@ -895,7 +888,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev)
venc_uninit_output(pdev); venc_uninit_output(pdev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
venc_put_clocks();
return 0; return 0;
} }
......
...@@ -2388,7 +2388,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, ...@@ -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_device *dssdev = fbdev->displays[i].dssdev;
struct omap_dss_output *out = dssdev->output; struct omap_dss_output *out = dssdev->output;
mgr = omap_dss_get_overlay_manager(dssdev->channel); mgr = omap_dss_get_overlay_manager(out->dispc_channel);
if (!mgr || !out) if (!mgr || !out)
continue; continue;
......
...@@ -257,10 +257,31 @@ void rfbi_bus_unlock(void); ...@@ -257,10 +257,31 @@ void rfbi_bus_unlock(void);
/* DSI */ /* 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 { struct omap_dss_dsi_videomode_timings {
unsigned long hsclk;
unsigned ndl;
unsigned bitspp;
/* pixels */
u16 hact;
/* lines */
u16 vact;
/* DSI video mode blanking data */ /* DSI video mode blanking data */
/* Unit: byte clock cycles */ /* Unit: byte clock cycles */
u16 hss;
u16 hsa; u16 hsa;
u16 hse;
u16 hfp; u16 hfp;
u16 hbp; u16 hbp;
/* Unit: line clocks */ /* Unit: line clocks */
...@@ -274,14 +295,24 @@ struct omap_dss_dsi_videomode_timings { ...@@ -274,14 +295,24 @@ struct omap_dss_dsi_videomode_timings {
int hbp_blanking_mode; int hbp_blanking_mode;
int hfp_blanking_mode; int hfp_blanking_mode;
/* Video port sync events */ enum omap_dss_dsi_trans_mode trans_mode;
bool vp_vsync_end;
bool vp_hsync_end;
bool ddr_clk_always_on; bool ddr_clk_always_on;
int window_sync; 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_lock(struct omap_dss_device *dssdev);
void dsi_bus_unlock(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, int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
...@@ -541,9 +572,14 @@ struct omap_dss_writeback_info { ...@@ -541,9 +572,14 @@ struct omap_dss_writeback_info {
struct omap_dss_output { struct omap_dss_output {
struct list_head list; struct list_head list;
const char *name;
/* display type supported by the output */ /* display type supported by the output */
enum omap_display_type type; enum omap_display_type type;
/* DISPC channel for this output */
enum omap_channel dispc_channel;
/* output instance */ /* output instance */
enum omap_dss_output_id id; enum omap_dss_output_id id;
...@@ -561,6 +597,7 @@ struct omap_dss_device { ...@@ -561,6 +597,7 @@ struct omap_dss_device {
enum omap_display_type type; enum omap_display_type type;
/* obsolete, to be removed */
enum omap_channel channel; enum omap_channel channel;
union { union {
...@@ -590,41 +627,11 @@ struct omap_dss_device { ...@@ -590,41 +627,11 @@ struct omap_dss_device {
} venc; } venc;
} phy; } 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 {
struct omap_video_timings timings; struct omap_video_timings timings;
enum omap_dss_dsi_pixel_format dsi_pix_fmt; enum omap_dss_dsi_pixel_format dsi_pix_fmt;
enum omap_dss_dsi_mode dsi_mode; enum omap_dss_dsi_mode dsi_mode;
struct omap_dss_dsi_videomode_timings dsi_vm_timings;
} panel; } panel;
struct { struct {
...@@ -829,15 +836,8 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, ...@@ -829,15 +836,8 @@ 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, void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
bool enable); bool enable);
int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, int omapdss_dsi_set_config(struct omap_dss_device *dssdev,
struct omap_video_timings *timings); const struct omap_dss_dsi_config *config);
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, int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
void (*callback)(int, void *), void *data); void (*callback)(int, void *), void *data);
...@@ -846,8 +846,6 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id); ...@@ -846,8 +846,6 @@ 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); void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
const struct omap_dsi_pin_config *pin_cfg); 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); int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment