diff options
author | Dave Airlie <airlied@redhat.com> | 2013-04-16 03:20:03 (GMT) |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-04-16 03:20:03 (GMT) |
commit | dea14dfab9d1fdf5695ae61dc72c587533706edc (patch) | |
tree | b30f80f3581c706f29911cbe334f6b35569a5847 | |
parent | e4fda9f264e154946c678ca7ff07023f573abf6a (diff) | |
parent | 3d62fe5b214fce69ae14abbdb88794a753418614 (diff) | |
download | linux-dea14dfab9d1fdf5695ae61dc72c587533706edc.tar.xz |
Merge tag 'omapdss-for-3.10' of git://gitorious.org/linux-omap-dss2/linux into drm-next
Omapdss patches for 3.10 merge window
The biggest changes are:
* DSI video mode: automatic clock and timing calculation
* Lots of platform data related panel driver cleanups, to prepare for DT
* tag 'omapdss-for-3.10' of git://gitorious.org/linux-omap-dss2/linux: (69 commits)
drm/omap: add statics to a few structs
drm/omap: Fix and improve crtc and overlay manager correlation
drm/omap: Take a fb reference in omap_plane_update()
drm/omap: Make fixed resolution panels work
drm/omap: fix modeset_init if a panel doesn't satisfy omapdrm requirements
OMAPDSS: DPI: widen the pck search when using dss fck
OMAPDSS: fix dss_fck clock rate rounding
omapdss: use devm_clk_get()
OMAPDSS: nec-nl8048 panel: Use dev_pm_ops
OMAPDSS: DISPC: Revert to older DISPC Smart Standby mechanism for OMAP5
OMAPDSS: DISPC: Configure doublestride for NV12 when using 2D Tiler buffers
omapdss: Features: Fix some parameter ranges
omapdss: DISPC: add max pixel clock limits for LCD and TV managers
OMAPDSS: DSI: Use devm_clk_get()
drivers: video: omap2: dss: Use PTR_RET function
OMAPDSS: VENC: remove platform_enable/disable calls
OMAPDSS: n8x0 panel: remove use of platform_enable/disable
OMAPDSS: n8x0 panel: handle gpio data in panel driver
OMAPDSS: picodlp panel: remove platform_enable/disable callbacks
OMAPDSS: picodlp panel: handle gpio data in panel driver
...
53 files changed, 1972 insertions, 1739 deletions
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index a3e0aaa..1322ed7 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -38,7 +38,7 @@ #include "gpmc-smc91x.h" #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-data.h> #include "mux.h" #include "hsmmc.h" diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c index ce812de..2612eea 100644 --- a/arch/arm/mach-omap2/board-3430sdp.c +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -35,7 +35,7 @@ #include "common.h" #include <linux/omap-dma.h> #include <video/omapdss.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include "gpmc.h" #include "gpmc-smc91x.h" diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c index 9fb8590..1d6c288 100644 --- a/arch/arm/mach-omap2/board-am3517evm.c +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -35,8 +35,7 @@ #include "common.h" #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include "am35xx-emac.h" #include "mux.h" diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index af2bb21..bccd3e5 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -41,8 +41,7 @@ #include <linux/platform_data/mtd-nand-omap2.h> #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include "common.h" diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c index 53056c3..12d2126 100644 --- a/arch/arm/mach-omap2/board-devkit8000.c +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -43,8 +43,7 @@ #include "gpmc.h" #include <linux/platform_data/mtd-nand-omap2.h> #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include <linux/input/matrix_keypad.h> diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 812c829..0c1bdd7 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -34,7 +34,7 @@ #include <asm/mach/map.h> #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-data.h> #include "common.h" #include "mux.h" diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c index bf92678..e979d48 100644 --- a/arch/arm/mach-omap2/board-igep0020.c +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -31,7 +31,7 @@ #include <asm/mach/arch.h> #include <video/omapdss.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include <linux/platform_data/mtd-onenand-omap2.h> #include "common.h" diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index b12fe96..8a8e505 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -41,7 +41,7 @@ #include "gpmc-smsc911x.h" #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-data.h> #include "board-flash.h" #include "mux.h" diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index c3558f9..0ce91af 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -43,7 +43,7 @@ #include <asm/mach/flash.h> #include <video/omapdss.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include <linux/platform_data/mtd-nand-omap2.h> #include "common.h" diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 48789e0..233a0d5 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -51,7 +51,7 @@ #include "common.h" #include <linux/platform_data/spi-omap2-mcspi.h> #include <video/omapdss.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include "soc.h" #include "mux.h" diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c index 95c10b3..495b989 100644 --- a/arch/arm/mach-omap2/board-omap3stalker.c +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -44,8 +44,7 @@ #include "gpmc.h" #include <linux/platform_data/mtd-nand-omap2.h> #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include <linux/platform_data/spi-omap2-mcspi.h> diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index 86bab51..6308332 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -47,8 +47,7 @@ #include <asm/mach/map.h> #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> #include "common.h" #include "mux.h" diff --git a/arch/arm/mach-omap2/dss-common.c b/arch/arm/mach-omap2/dss-common.c index 4be5cfc..9c49bbe 100644 --- a/arch/arm/mach-omap2/dss-common.c +++ b/arch/arm/mach-omap2/dss-common.c @@ -27,9 +27,7 @@ #include <linux/gpio.h> #include <video/omapdss.h> -#include <video/omap-panel-tfp410.h> -#include <video/omap-panel-nokia-dsi.h> -#include <video/omap-panel-picodlp.h> +#include <video/omap-panel-data.h> #include "soc.h" #include "dss-common.h" diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index c451c41..912759d 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -110,6 +110,11 @@ static enum drm_connector_status omap_connector_detect( 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; } @@ -189,12 +194,30 @@ 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 ret = MODE_BAD; + int r, ret = MODE_BAD; copy_timings_drm_to_omap(&timings, 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 */ new_mode = drm_mode_duplicate(dev, mode); new_mode->clock = timings.pixel_clock; diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index bec66a4..79b200a 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -74,6 +74,13 @@ 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. @@ -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.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->error_irq.irqmask = @@ -621,12 +634,6 @@ 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/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 079c54c..9c53c25 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -74,54 +74,53 @@ static int get_connector_type(struct omap_dss_device *dssdev) } } +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 id; + int num_mgrs = dss_feat_get_num_mgrs(); + int num_crtcs; + int i, id = 0; drm_mode_config_init(dev); omap_drm_irq_install(dev); /* - * Create private planes and CRTCs for the last NUM_CRTCs overlay - * plus manager: + * 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. */ - 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); + num_crtcs = min3(num_crtc, num_mgrs, num_ovls); - 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; - } + dssdev = NULL; 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); - return 0; + continue; } if (!(dssdev->driver->get_timings || @@ -129,7 +128,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); - return 0; + continue; } encoder = omap_encoder_init(dev, dssdev); @@ -157,16 +156,118 @@ 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++) { - enum omap_dss_output_id supported_outputs = - dss_feat_get_supported_outputs(pipe2chan(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); + 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; @@ -303,7 +404,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, 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_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), @@ -567,7 +668,7 @@ static const struct dev_pm_ops omapdrm_pm_ops = { }; #endif -struct platform_driver pdev = { +static struct platform_driver pdev = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index d4f997b..215a20d 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -139,8 +139,8 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); int omap_gem_resume(struct device *dev); #endif -int omap_irq_enable_vblank(struct drm_device *dev, int crtc); -void omap_irq_disable_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_id); 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,39 +271,9 @@ 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 */ -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; -} +uint32_t pipe2vbl(struct drm_crtc *crtc); +struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder); /* should these be made into common util helpers? */ diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 21d126d..c29451b 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -41,6 +41,13 @@ 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); @@ -128,13 +135,26 @@ int omap_encoder_update(struct drm_encoder *encoder, 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) { dev_err(dev->dev, "could not set timings: %d\n", ret); return ret; } - dssdrv->set_timings(dssdev, timings); + if (dssdrv->set_timings) + dssdrv->set_timings(dssdev, timings); return 0; } diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c index ac74d1b..0682cb5 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c +++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c @@ -178,7 +178,7 @@ out_unlock: 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, .unmap_dma_buf = omap_gem_unmap_dma_buf, .release = omap_gem_dmabuf_release, diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index e01303e..9263db1 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -130,12 +130,13 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, * 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) +int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id) { 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); + DBG("dev=%p, crtc=%d", dev, crtc_id); dispc_runtime_get(); spin_lock_irqsave(&list_lock, flags); @@ -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 * 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 drm_crtc *crtc = priv->crtcs[crtc_id]; unsigned long flags; - DBG("dev=%p, crtc=%d", dev, crtc); + DBG("dev=%p, crtc=%d", dev, crtc_id); dispc_runtime_get(); spin_lock_irqsave(&list_lock, flags); @@ -186,9 +188,12 @@ irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) VERB("irqs: %08x", irqstatus); - for (id = 0; id < priv->num_crtcs; id++) - if (irqstatus & pipe2vbl(id)) + for (id = 0; id < priv->num_crtcs; id++) { + struct drm_crtc *crtc = priv->crtcs[id]; + + if (irqstatus & pipe2vbl(crtc)) 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/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 2882cda..8d225d7 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -247,6 +247,12 @@ static int omap_plane_update(struct drm_plane *plane, { 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/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index 72699f8..d7f69c0 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -29,8 +29,10 @@ #include <linux/sched.h> #include <linux/backlight.h> #include <linux/fb.h> +#include <linux/gpio.h> #include <video/omapdss.h> +#include <video/omap-panel-data.h> #define MIPID_CMD_READ_DISP_ID 0x04 #define MIPID_CMD_READ_RED 0x06 @@ -336,8 +338,6 @@ static int acx565akm_bl_update_status(struct backlight_device *dev) r = 0; if (md->has_bc) acx565akm_set_brightness(md, level); - else if (md->dssdev->set_backlight) - r = md->dssdev->set_backlight(md->dssdev, level); else r = -ENODEV; @@ -352,7 +352,7 @@ static int acx565akm_bl_get_intensity(struct backlight_device *dev) dev_dbg(&dev->dev, "%s\n", __func__); - if (!md->has_bc && md->dssdev->set_backlight == NULL) + if (!md->has_bc) return -ENODEV; if (dev->props.fb_blank == FB_BLANK_UNBLANK && @@ -496,21 +496,38 @@ static struct omap_video_timings acx_panel_timings = { .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, }; +static struct panel_acx565akm_data *get_panel_data(struct omap_dss_device *dssdev) +{ + return (struct panel_acx565akm_data *) dssdev->data; +} + static int acx_panel_probe(struct omap_dss_device *dssdev) { int r; struct acx565akm_device *md = &acx_dev; + struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); struct backlight_device *bldev; int max_brightness, brightness; struct backlight_properties props; dev_dbg(&dssdev->dev, "%s\n", __func__); + if (!panel_data) + return -EINVAL; + /* FIXME AC bias ? */ dssdev->panel.timings = acx_panel_timings; - if (dssdev->platform_enable) - dssdev->platform_enable(dssdev); + if (gpio_is_valid(panel_data->reset_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, panel_data->reset_gpio, + GPIOF_OUT_INIT_LOW, "lcd reset"); + if (r) + return r; + } + + if (gpio_is_valid(panel_data->reset_gpio)) + gpio_set_value(panel_data->reset_gpio, 1); + /* * After reset we have to wait 5 msec before the first * command can be sent. @@ -522,8 +539,9 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) r = panel_detect(md); if (r) { dev_err(&dssdev->dev, "%s panel detect error\n", __func__); - if (!md->enabled && dssdev->platform_disable) - dssdev->platform_disable(dssdev); + if (!md->enabled && gpio_is_valid(panel_data->reset_gpio)) + gpio_set_value(panel_data->reset_gpio, 0); + return r; } @@ -532,8 +550,8 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) mutex_unlock(&acx_dev.mutex); if (!md->enabled) { - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + if (gpio_is_valid(panel_data->reset_gpio)) + gpio_set_value(panel_data->reset_gpio, 0); } /*------- Backlight control --------*/ @@ -557,15 +575,10 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) md->cabc_mode = get_hw_cabc_mode(md); } - if (md->has_bc) - max_brightness = 255; - else - max_brightness = dssdev->max_backlight_level; + max_brightness = 255; if (md->has_bc) brightness = acx565akm_get_actual_brightness(md); - else if (dssdev->get_backlight) - brightness = dssdev->get_backlight(dssdev); else brightness = 0; @@ -591,6 +604,7 @@ static void acx_panel_remove(struct omap_dss_device *dssdev) static int acx_panel_power_on(struct omap_dss_device *dssdev) { struct acx565akm_device *md = &acx_dev; + struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "%s\n", __func__); @@ -612,11 +626,8 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) /*FIXME tweak me */ msleep(50); - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto fail; - } + if (gpio_is_valid(panel_data->reset_gpio)) + gpio_set_value(panel_data->reset_gpio, 1); if (md->enabled) { dev_dbg(&md->spi->dev, "panel already enabled\n"); @@ -645,8 +656,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) mutex_unlock(&md->mutex); return acx565akm_bl_update_status(md->bl_dev); -fail: - omapdss_sdi_display_disable(dssdev); + fail_unlock: mutex_unlock(&md->mutex); return r; @@ -655,6 +665,7 @@ fail_unlock: static void acx_panel_power_off(struct omap_dss_device *dssdev) { struct acx565akm_device *md = &acx_dev; + struct panel_acx565akm_data *panel_data = get_panel_data(dssdev); dev_dbg(&dssdev->dev, "%s\n", __func__); @@ -678,8 +689,8 @@ static void acx_panel_power_off(struct omap_dss_device *dssdev) */ msleep(50); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + if (gpio_is_valid(panel_data->reset_gpio)) + gpio_set_value(panel_data->reset_gpio, 0); /* FIXME need to tweak this delay */ msleep(100); diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index c904f42..97363f7 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -33,9 +33,10 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/gpio.h> #include <video/omapdss.h> -#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-data.h> struct panel_config { struct omap_video_timings timings; @@ -533,7 +534,7 @@ static inline struct panel_generic_dpi_data static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) { - int r; + int r, i; struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); struct panel_config *panel_config = drv_data->panel_config; @@ -552,15 +553,13 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) if (panel_config->power_on_delay) msleep(panel_config->power_on_delay); - if (panel_data->platform_enable) { - r = panel_data->platform_enable(dssdev); - if (r) - goto err1; + for (i = 0; i < panel_data->num_gpios; ++i) { + gpio_set_value_cansleep(panel_data->gpios[i], + panel_data->gpio_invert[i] ? 0 : 1); } return 0; -err1: - omapdss_dpi_display_disable(dssdev); + err0: return r; } @@ -570,12 +569,15 @@ static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev) struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); struct panel_config *panel_config = drv_data->panel_config; + int i; if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return; - if (panel_data->platform_disable) - panel_data->platform_disable(dssdev); + for (i = panel_data->num_gpios - 1; i >= 0; --i) { + gpio_set_value_cansleep(panel_data->gpios[i], + panel_data->gpio_invert[i] ? 1 : 0); + } /* wait couple of vsyncs after disabling the LCD */ if (panel_config->power_off_delay) @@ -589,7 +591,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); struct panel_config *panel_config = NULL; struct panel_drv_data *drv_data = NULL; - int i; + int i, r; dev_dbg(&dssdev->dev, "probe\n"); @@ -606,9 +608,18 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) if (!panel_config) return -EINVAL; + for (i = 0; i < panel_data->num_gpios; ++i) { + r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i], + panel_data->gpio_invert[i] ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, + "panel gpio"); + if (r) + return r; + } + dssdev->panel.timings = panel_config->timings; - drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); + drv_data = devm_kzalloc(&dssdev->dev, sizeof(*drv_data), GFP_KERNEL); if (!drv_data) return -ENOMEM; @@ -624,12 +635,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) { - struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); - dev_dbg(&dssdev->dev, "remove\n"); - kfree(drv_data); - dev_set_drvdata(&dssdev->dev, NULL); } diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 6e5abe8..4ea6548 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c @@ -20,8 +20,10 @@ #include <linux/delay.h> #include <linux/spi/spi.h> #include <linux/mutex.h> +#include <linux/gpio.h> #include <video/omapdss.h> +#include <video/omap-panel-data.h> struct lb035q02_data { struct mutex lock; @@ -48,9 +50,16 @@ static struct omap_video_timings lb035q02_timings = { .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, }; +static inline struct panel_generic_dpi_data +*get_panel_data(const struct omap_dss_device *dssdev) +{ + return (struct panel_generic_dpi_data *) dssdev->data; +} + static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) { - int r; + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + int r, i; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; @@ -62,54 +71,65 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) if (r) goto err0; - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; + for (i = 0; i < panel_data->num_gpios; ++i) { + gpio_set_value_cansleep(panel_data->gpios[i], + panel_data->gpio_invert[i] ? 0 : 1); } return 0; -err1: - omapdss_dpi_display_disable(dssdev); + err0: return r; } static void lb035q02_panel_power_off(struct omap_dss_device *dssdev) { + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); + int i; + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return; - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + for (i = panel_data->num_gpios - 1; i >= 0; --i) { + gpio_set_value_cansleep(panel_data->gpios[i], + panel_data->gpio_invert[i] ? 1 : 0); + } omapdss_dpi_display_disable(dssdev); } static int lb035q02_panel_probe(struct omap_dss_device *dssdev) { + struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev); struct lb035q02_data *ld; - int r; + int r, i; + + if (!panel_data) + return -EINVAL; dssdev->panel.timings = lb035q02_timings; - ld = kzalloc(sizeof(*ld), GFP_KERNEL); - if (!ld) { - r = -ENOMEM; - goto err; + ld = devm_kzalloc(&dssdev->dev, sizeof(*ld), GFP_KERNEL); + if (!ld) + return -ENOMEM; + + for (i = 0; i < panel_data->num_gpios; ++i) { + r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i], + panel_data->gpio_invert[i] ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, + "panel gpio"); + if (r) + return r; } + mutex_init(&ld->lock); dev_set_drvdata(&dssdev->dev, ld); + return 0; -err: - return r; } static void lb035q02_panel_remove(struct omap_dss_device *dssdev) { - struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); - - kfree(ld); } static int lb035q02_panel_enable(struct omap_dss_device *dssdev) diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index dd12947..f94ead6 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -5,11 +5,10 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/spi/spi.h> -#include <linux/backlight.h> #include <linux/fb.h> #include <video/omapdss.h> -#include <video/omap-panel-n8x0.h> +#include <video/omap-panel-data.h> #define BLIZZARD_REV_CODE 0x00 #define BLIZZARD_CONFIG 0x02 @@ -69,7 +68,6 @@ static struct panel_drv_data { struct omap_dss_device *dssdev; struct spi_device *spidev; - struct backlight_device *bldev; int blizzard_ver; } s_drv_data; @@ -297,12 +295,6 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev) gpio_direction_output(bdata->ctrl_pwrdown, 1); - if (bdata->platform_enable) { - r = bdata->platform_enable(dssdev); - if (r) - goto err_plat_en; - } - omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); @@ -375,9 +367,6 @@ err_inv_panel: err_inv_chip: omapdss_rfbi_display_disable(dssdev); err_rfbi_en: - if (bdata->platform_disable) - bdata->platform_disable(dssdev); -err_plat_en: gpio_direction_output(bdata->ctrl_pwrdown, 0); return r; } @@ -394,9 +383,6 @@ static void n8x0_panel_power_off(struct omap_dss_device *dssdev) send_display_off(spi); send_sleep_in(spi); - if (bdata->platform_disable) - bdata->platform_disable(dssdev); - /* * HACK: we should turn off the panel here, but there is some problem * with the initialization sequence, and we fail to init the panel if we @@ -424,54 +410,10 @@ static const struct rfbi_timings n8x0_panel_timings = { .cs_pulse_width = 0, }; -static int n8x0_bl_update_status(struct backlight_device *dev) -{ - struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); - struct panel_n8x0_data *bdata = get_board_data(dssdev); - struct panel_drv_data *ddata = get_drv_data(dssdev); - int r; - int level; - - mutex_lock(&ddata->lock); - - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) - level = dev->props.brightness; - else - level = 0; - - dev_dbg(&dssdev->dev, "update brightness to %d\n", level); - - if (!bdata->set_backlight) - r = -EINVAL; - else - r = bdata->set_backlight(dssdev, level); - - mutex_unlock(&ddata->lock); - - return r; -} - -static int n8x0_bl_get_intensity(struct backlight_device *dev) -{ - if (dev->props.fb_blank == FB_BLANK_UNBLANK && - dev->props.power == FB_BLANK_UNBLANK) - return dev->props.brightness; - - return 0; -} - -static const struct backlight_ops n8x0_bl_ops = { - .get_brightness = n8x0_bl_get_intensity, - .update_status = n8x0_bl_update_status, -}; - static int n8x0_panel_probe(struct omap_dss_device *dssdev) { struct panel_n8x0_data *bdata = get_board_data(dssdev); struct panel_drv_data *ddata; - struct backlight_device *bldev; - struct backlight_properties props; int r; dev_dbg(&dssdev->dev, "probe\n"); @@ -491,40 +433,27 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) dssdev->ctrl.rfbi_timings = n8x0_panel_timings; dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; - memset(&props, 0, sizeof(props)); - props.max_brightness = 127; - props.type = BACKLIGHT_PLATFORM; - bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev, - dssdev, &n8x0_bl_ops, &props); - if (IS_ERR(bldev)) { - r = PTR_ERR(bldev); - dev_err(&dssdev->dev, "register backlight failed\n"); - return r; + if (gpio_is_valid(bdata->panel_reset)) { + r = devm_gpio_request_one(&dssdev->dev, bdata->panel_reset, + GPIOF_OUT_INIT_LOW, "PANEL RESET"); + if (r) + return r; } - ddata->bldev = bldev; - - bldev->props.fb_blank = FB_BLANK_UNBLANK; - bldev->props.power = FB_BLANK_UNBLANK; - bldev->props.brightness = 127; - - n8x0_bl_update_status(bldev); + if (gpio_is_valid(bdata->ctrl_pwrdown)) { + r = devm_gpio_request_one(&dssdev->dev, bdata->ctrl_pwrdown, + GPIOF_OUT_INIT_LOW, "PANEL PWRDOWN"); + if (r) + return r; + } return 0; } static void n8x0_panel_remove(struct omap_dss_device *dssdev) { - struct panel_drv_data *ddata = get_drv_data(dssdev); - struct backlight_device *bldev; - dev_dbg(&dssdev->dev, "remove\n"); - bldev = ddata->bldev; - bldev->props.power = FB_BLANK_POWERDOWN; - n8x0_bl_update_status(bldev); - backlight_device_unregister(bldev); - dev_set_drvdata(&dssdev->dev, NULL); } diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index c4e9c2b..20c3cd9 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -19,10 +19,11 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/spi/spi.h> -#include <linux/backlight.h> #include <linux/fb.h> +#include <linux/gpio.h> #include <video/omapdss.h> +#include <video/omap-panel-data.h> #define LCD_XRES 800 #define LCD_YRES 480 @@ -32,10 +33,6 @@ */ #define LCD_PIXEL_CLOCK 23800 -struct nec_8048_data { - struct backlight_device *bl; -}; - static const struct { unsigned char addr; unsigned char dat; @@ -84,93 +81,47 @@ static struct omap_video_timings nec_8048_panel_timings = { .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, }; -static int nec_8048_bl_update_status(struct backlight_device *bl) -{ - struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); - int level; - - if (!dssdev->set_backlight) - return -EINVAL; - - if (bl->props.fb_blank == FB_BLANK_UNBLANK && - bl->props.power == FB_BLANK_UNBLANK) - level = bl->props.brightness; - else - level = 0; - - return dssdev->set_backlight(dssdev, level); -} - -static int nec_8048_bl_get_brightness(struct backlight_device *bl) +static inline struct panel_nec_nl8048_data +*get_panel_data(const struct omap_dss_device *dssdev) { - if (bl->props.fb_blank == FB_BLANK_UNBLANK && - bl->props.power == FB_BLANK_UNBLANK) - return bl->props.brightness; - - return 0; + return (struct panel_nec_nl8048_data *) dssdev->data; } -static const struct backlight_ops nec_8048_bl_ops = { - .get_brightness = nec_8048_bl_get_brightness, - .update_status = nec_8048_bl_update_status, -}; - static int nec_8048_panel_probe(struct omap_dss_device *dssdev) { - struct backlight_device *bl; - struct nec_8048_data *necd; - struct backlight_properties props; + struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); int r; - dssdev->panel.timings = nec_8048_panel_timings; - - necd = kzalloc(sizeof(*necd), GFP_KERNEL); - if (!necd) - return -ENOMEM; - - dev_set_drvdata(&dssdev->dev, necd); + if (!pd) + return -EINVAL; - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 255; + dssdev->panel.timings = nec_8048_panel_timings; - bl = backlight_device_register("nec-8048", &dssdev->dev, dssdev, - &nec_8048_bl_ops, &props); - if (IS_ERR(bl)) { - r = PTR_ERR(bl); - kfree(necd); - return r; + if (gpio_is_valid(pd->qvga_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, pd->qvga_gpio, + GPIOF_OUT_INIT_HIGH, "lcd QVGA"); + if (r) + return r; } - necd->bl = bl; - - bl->props.fb_blank = FB_BLANK_UNBLANK; - bl->props.power = FB_BLANK_UNBLANK; - bl->props.max_brightness = dssdev->max_backlight_level; - bl->props.brightness = dssdev->max_backlight_level; - r = nec_8048_bl_update_status(bl); - if (r < 0) - dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + if (gpio_is_valid(pd->res_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, pd->res_gpio, + GPIOF_OUT_INIT_LOW, "lcd RES"); + if (r) + return r; + } return 0; } static void nec_8048_panel_remove(struct omap_dss_device *dssdev) { - struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); - struct backlight_device *bl = necd->bl; - - bl->props.power = FB_BLANK_POWERDOWN; - nec_8048_bl_update_status(bl); - backlight_device_unregister(bl); - - kfree(necd); } static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) { + struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); int r; - struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); - struct backlight_device *bl = necd->bl; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; @@ -182,36 +133,24 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) if (r) goto err0; - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; - } - - r = nec_8048_bl_update_status(bl); - if (r < 0) - dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + if (gpio_is_valid(pd->res_gpio)) + gpio_set_value_cansleep(pd->res_gpio, 1); return 0; -err1: - omapdss_dpi_display_disable(dssdev); + err0: return r; } static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) { - struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); - struct backlight_device *bl = necd->bl; + struct panel_nec_nl8048_data *pd = get_panel_data(dssdev); if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return; - bl->props.brightness = 0; - nec_8048_bl_update_status(bl); - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + if (gpio_is_valid(pd->res_gpio)) + gpio_set_value_cansleep(pd->res_gpio, 0); omapdss_dpi_display_disable(dssdev); } @@ -303,16 +242,22 @@ static int nec_8048_spi_remove(struct spi_device *spi) 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); mdelay(40); 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 */ spi_setup(spi); nec_8048_spi_send(spi, 2, 0x00); @@ -321,14 +266,20 @@ static int nec_8048_spi_resume(struct spi_device *spi) 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 = { .probe = nec_8048_spi_probe, .remove = nec_8048_spi_remove, - .suspend = nec_8048_spi_suspend, - .resume = nec_8048_spi_resume, .driver = { .name = "nec_8048_spi", .owner = THIS_MODULE, + .pm = NEC_8048_SPI_PM_OPS, }, }; diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 1b94018..62f2db0 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -31,7 +31,7 @@ #include <linux/gpio.h> #include <video/omapdss.h> -#include <video/omap-panel-picodlp.h> +#include <video/omap-panel-data.h> #include "panel-picodlp.h" @@ -354,12 +354,6 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - return r; - } - gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); msleep(1); gpio_set_value(picodlp_pdata->pwrgood_gpio, 1); @@ -398,9 +392,6 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) err: omapdss_dpi_display_disable(dssdev); err1: - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - return r; } @@ -412,9 +403,6 @@ static void picodlp_panel_power_off(struct omap_dss_device *dssdev) gpio_set_value(picodlp_pdata->emu_done_gpio, 0); gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); } static int picodlp_panel_probe(struct omap_dss_device *dssdev) @@ -423,11 +411,14 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); struct i2c_adapter *adapter; struct i2c_client *picodlp_i2c_client; - int r = 0, picodlp_adapter_id; + int r, picodlp_adapter_id; dssdev->panel.timings = pico_ls_timings; - picod = kzalloc(sizeof(struct picodlp_data), GFP_KERNEL); + if (!picodlp_pdata) + return -EINVAL; + + picod = devm_kzalloc(&dssdev->dev, sizeof(*picod), GFP_KERNEL); if (!picod) return -ENOMEM; @@ -438,25 +429,37 @@ static int picodlp_panel_probe(struct omap_dss_device *dssdev) adapter = i2c_get_adapter(picodlp_adapter_id); if (!adapter) { dev_err(&dssdev->dev, "can't get i2c adapter\n"); - r = -ENODEV; - goto err; + return -ENODEV; } picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); if (!picodlp_i2c_client) { dev_err(&dssdev->dev, "can't add i2c device::" " picodlp_i2c_client is NULL\n"); - r = -ENODEV; - goto err; + return -ENODEV; } picod->picodlp_i2c_client = picodlp_i2c_client; dev_set_drvdata(&dssdev->dev, picod); - return r; -err: - kfree(picod); - return r; + + if (gpio_is_valid(picodlp_pdata->emu_done_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, + picodlp_pdata->emu_done_gpio, + GPIOF_IN, "DLP EMU DONE"); + if (r) + return r; + } + + if (gpio_is_valid(picodlp_pdata->pwrgood_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, + picodlp_pdata->pwrgood_gpio, + GPIOF_OUT_INIT_LOW, "DLP PWRGOOD"); + if (r) + return r; + } + + return 0; } static void picodlp_panel_remove(struct omap_dss_device *dssdev) diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index cada8c6..74cb0eb 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -20,16 +20,13 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/device.h> -#include <linux/backlight.h> #include <linux/fb.h> #include <linux/err.h> #include <linux/slab.h> +#include <linux/gpio.h> #include <video/omapdss.h> - -struct sharp_data { - struct backlight_device *bl; -}; +#include <video/omap-panel-data.h> static struct omap_video_timings sharp_ls_timings = { .x_res = 480, @@ -52,91 +49,67 @@ static struct omap_video_timings sharp_ls_timings = { .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, }; -static int sharp_ls_bl_update_status(struct backlight_device *bl) +static inline struct panel_sharp_ls037v7dw01_data +*get_panel_data(const struct omap_dss_device *dssdev) { - struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev); - int level; - - if (!dssdev->set_backlight) - return -EINVAL; - - if (bl->props.fb_blank == FB_BLANK_UNBLANK && - bl->props.power == FB_BLANK_UNBLANK) - level = bl->props.brightness; - else - level = 0; - - return dssdev->set_backlight(dssdev, level); + return (struct panel_sharp_ls037v7dw01_data *) dssdev->data; } -static int sharp_ls_bl_get_brightness(struct backlight_device *bl) -{ - if (bl->props.fb_blank == FB_BLANK_UNBLANK && - bl->props.power == FB_BLANK_UNBLANK) - return bl->props.brightness; - - return 0; -} - -static const struct backlight_ops sharp_ls_bl_ops = { - .get_brightness = sharp_ls_bl_get_brightness, - .update_status = sharp_ls_bl_update_status, -}; - - - static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) { - struct backlight_properties props; - struct backlight_device *bl; - struct sharp_data *sd; + struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); int r; + if (!pd) + return -EINVAL; + dssdev->panel.timings = sharp_ls_timings; - sd = kzalloc(sizeof(*sd), GFP_KERNEL); - if (!sd) - return -ENOMEM; + if (gpio_is_valid(pd->mo_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, pd->mo_gpio, + GPIOF_OUT_INIT_LOW, "lcd MO"); + if (r) + return r; + } - dev_set_drvdata(&dssdev->dev, sd); + if (gpio_is_valid(pd->lr_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, pd->lr_gpio, + GPIOF_OUT_INIT_HIGH, "lcd LR"); + if (r) + return r; + } - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = dssdev->max_backlight_level; - props.type = BACKLIGHT_RAW; + if (gpio_is_valid(pd->ud_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, pd->ud_gpio, + GPIOF_OUT_INIT_HIGH, "lcd UD"); + if (r) + return r; + } - bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev, - &sharp_ls_bl_ops, &props); - if (IS_ERR(bl)) { - r = PTR_ERR(bl); - kfree(sd); - return r; + if (gpio_is_valid(pd->resb_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, pd->resb_gpio, + GPIOF_OUT_INIT_LOW, "lcd RESB"); + if (r) + return r; } - sd->bl = bl; - bl->props.fb_blank = FB_BLANK_UNBLANK; - bl->props.power = FB_BLANK_UNBLANK; - bl->props.brightness = dssdev->max_backlight_level; - r = sharp_ls_bl_update_status(bl); - if (r < 0) - dev_err(&dssdev->dev, "failed to set lcd brightness\n"); + if (gpio_is_valid(pd->ini_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, pd->ini_gpio, + GPIOF_OUT_INIT_LOW, "lcd INI"); + if (r) + return r; + } return 0; } static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev) { - struct sharp_data *sd = dev_get_drvdata(&dssdev->dev); - struct backlight_device *bl = sd->bl; - - bl->props.power = FB_BLANK_POWERDOWN; - sharp_ls_bl_update_status(bl); - backlight_device_unregister(bl); - - kfree(sd); } static int sharp_ls_power_on(struct omap_dss_device *dssdev) { + struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); int r = 0; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) @@ -152,26 +125,29 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev) /* wait couple of vsyncs until enabling the LCD */ msleep(50); - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; - } + if (gpio_is_valid(pd->resb_gpio)) + gpio_set_value_cansleep(pd->resb_gpio, 1); + + if (gpio_is_valid(pd->ini_gpio)) + gpio_set_value_cansleep(pd->ini_gpio, 1); return 0; -err1: - omapdss_dpi_display_disable(dssdev); err0: return r; } static void sharp_ls_power_off(struct omap_dss_device *dssdev) { + struct panel_sharp_ls037v7dw01_data *pd = get_panel_data(dssdev); + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return; - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + if (gpio_is_valid(pd->ini_gpio)) + gpio_set_value_cansleep(pd->ini_gpio, 0); + + if (gpio_is_valid(pd->resb_gpio)) + gpio_set_value_cansleep(pd->resb_gpio, 0); /* wait at least 5 vsyncs after disabling the LCD */ diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index a32407a..c4f78bd 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -33,7 +33,7 @@ #include <linux/mutex.h> #include <video/omapdss.h> -#include <video/omap-panel-nokia-dsi.h> +#include <video/omap-panel-data.h> #include <video/mipi_display.h> /* DSI Virtual channel. Hardcoded for now. */ @@ -54,61 +54,6 @@ 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; @@ -121,9 +66,6 @@ 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; @@ -134,8 +76,6 @@ struct taal_data { /* runtime variables */ bool enabled; - u8 rotate; - bool mirror; bool te_enabled; @@ -221,8 +161,7 @@ static int taal_sleep_in(struct taal_data *td) hw_guard_start(td, 120); - if (td->panel_config->sleep.sleep_in) - msleep(td->panel_config->sleep.sleep_in); + msleep(5); return 0; } @@ -239,8 +178,7 @@ static int taal_sleep_out(struct taal_data *td) hw_guard_start(td, 120); - if (td->panel_config->sleep.sleep_out) - msleep(td->panel_config->sleep.sleep_out); + msleep(5); return 0; } @@ -262,49 +200,6 @@ 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) { @@ -515,15 +410,8 @@ static const struct backlight_ops taal_bl_ops = { static void taal_get_resolution(struct omap_dss_device *dssdev, u16 *xres, u16 *yres) { - 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; - } + *xres = dssdev->panel.timings.x_res; + *yres = dssdev->panel.timings.y_res; } static ssize_t taal_num_errors_show(struct device *dev, @@ -845,17 +733,14 @@ static void taal_hw_reset(struct omap_dss_device *dssdev) return; gpio_set_value(td->reset_gpio, 1); - if (td->panel_config->reset_sequence.high) - udelay(td->panel_config->reset_sequence.high); + udelay(10); /* reset the panel */ gpio_set_value(td->reset_gpio, 0); /* assert reset */ - if (td->panel_config->reset_sequence.low) - udelay(td->panel_config->reset_sequence.low); + udelay(10); gpio_set_value(td->reset_gpio, 1); /* wait after releasing reset */ - if (td->panel_config->sleep.hw_reset) - msleep(td->panel_config->sleep.hw_reset); + msleep(5); } static void taal_probe_pdata(struct taal_data *td, @@ -881,8 +766,7 @@ static int taal_probe(struct omap_dss_device *dssdev) struct backlight_properties props; struct taal_data *td; struct backlight_device *bldev = NULL; - int r, i; - const char *panel_name; + int r; dev_dbg(&dssdev->dev, "probe\n"); @@ -897,26 +781,13 @@ 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; } - 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.timings.x_res = 864; + dssdev->panel.timings.y_res = 480; + dssdev->panel.timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000); dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; @@ -1049,6 +920,15 @@ 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) { @@ -1056,14 +936,9 @@ static int taal_power_on(struct omap_dss_device *dssdev) goto err0; }; - 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); + r = omapdss_dsi_set_config(dssdev, &dsi_config); if (r) { - dev_err(&dssdev->dev, "failed to set HS and LP clocks\n"); + dev_err(&dssdev->dev, "failed to configure DSI\n"); goto err0; } @@ -1086,8 +961,7 @@ static int taal_power_on(struct omap_dss_device *dssdev) goto err; /* on early Taal revisions CABC is broken */ - if (td->panel_config->type == PANEL_TAAL && - (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) + if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) td->cabc_broken = true; r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff); @@ -1104,10 +978,6 @@ 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) @@ -1129,8 +999,8 @@ static int taal_power_on(struct omap_dss_device *dssdev) td->enabled = 1; if (!td->intro_printed) { - dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n", - td->panel_config->name, id1, id2, id3); + dev_info(&dssdev->dev, "panel revision %02x.%02x.%02x\n", + id1, id2, id3); if (td->cabc_broken) dev_info(&dssdev->dev, "old Taal version, CABC disabled\n"); @@ -1311,8 +1181,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, - td->panel_config->timings.x_res, - td->panel_config->timings.y_res); + dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); if (r) goto err; @@ -1365,8 +1235,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); - if (td->panel_config->sleep.enable_te) - msleep(td->panel_config->sleep.enable_te); + /* possible panel bug */ + msleep(100); return r; } @@ -1419,112 +1289,6 @@ 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); @@ -1758,10 +1522,6 @@ 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/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 8281baa..a1dba868 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c @@ -24,7 +24,7 @@ #include <linux/gpio.h> #include <drm/drm_edid.h> -#include <video/omap-panel-tfp410.h> +#include <video/omap-panel-data.h> static const struct omap_video_timings tfp410_default_timings = { .x_res = 640, diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 048c983..abf2bc4 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <video/omapdss.h> +#include <video/omap-panel-data.h> #define TPO_R02_MODE(x) ((x) & 7) #define TPO_R02_MODE_800x480 7 @@ -278,9 +279,14 @@ static const struct omap_video_timings tpo_td043_timings = { .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, }; +static inline struct panel_tpo_td043_data +*get_panel_data(const struct omap_dss_device *dssdev) +{ + return (struct panel_tpo_td043_data *) dssdev->data; +} + static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) { - int nreset_gpio = tpo_td043->nreset_gpio; int r; if (tpo_td043->powered_on) @@ -293,8 +299,8 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) /* wait for panel to stabilize */ msleep(160); - if (gpio_is_valid(nreset_gpio)) - gpio_set_value(nreset_gpio, 1); + if (gpio_is_valid(tpo_td043->nreset_gpio)) + gpio_set_value(tpo_td043->nreset_gpio, 1); tpo_td043_write(tpo_td043->spi, 2, TPO_R02_MODE(tpo_td043->mode) | TPO_R02_NCLK_RISING); @@ -311,16 +317,14 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) { - int nreset_gpio = tpo_td043->nreset_gpio; - if (!tpo_td043->powered_on) return; tpo_td043_write(tpo_td043->spi, 3, TPO_R03_VAL_STANDBY | TPO_R03_EN_PWM); - if (gpio_is_valid(nreset_gpio)) - gpio_set_value(nreset_gpio, 0); + if (gpio_is_valid(tpo_td043->nreset_gpio)) + gpio_set_value(tpo_td043->nreset_gpio, 0); /* wait for at least 2 vsyncs before cutting off power */ msleep(50); @@ -347,12 +351,6 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) if (r) goto err0; - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - goto err1; - } - /* * If we are resuming from system suspend, SPI clocks might not be * enabled yet, so we'll program the LCD from SPI PM resume callback. @@ -379,9 +377,6 @@ static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return; - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - omapdss_dpi_display_disable(dssdev); if (!tpo_td043->spi_suspended) @@ -407,7 +402,7 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev) static int tpo_td043_probe(struct omap_dss_device *dssdev) { struct tpo_td043_device *tpo_td043 = g_tpo_td043; - int nreset_gpio = dssdev->reset_gpio; + struct panel_tpo_td043_data *pdata = get_panel_data(dssdev); int ret = 0; dev_dbg(&dssdev->dev, "probe\n"); @@ -417,6 +412,11 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) return -ENODEV; } + if (!pdata) + return -EINVAL; + + tpo_td043->nreset_gpio = pdata->nreset_gpio; + dssdev->panel.timings = tpo_td043_timings; dssdev->ctrl.pixel_size = 24; @@ -430,9 +430,10 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) goto fail_regulator; } - if (gpio_is_valid(nreset_gpio)) { - ret = gpio_request_one(nreset_gpio, GPIOF_OUT_INIT_LOW, - "lcd reset"); + if (gpio_is_valid(tpo_td043->nreset_gpio)) { + ret = devm_gpio_request_one(&dssdev->dev, + tpo_td043->nreset_gpio, GPIOF_OUT_INIT_LOW, + "lcd reset"); if (ret < 0) { dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); goto fail_gpio_req; @@ -457,14 +458,11 @@ fail_regulator: static void tpo_td043_remove(struct omap_dss_device *dssdev) { struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); - int nreset_gpio = dssdev->reset_gpio; dev_dbg(&dssdev->dev, "remove\n"); sysfs_remove_group(&dssdev->dev.kobj, &tpo_td043_attr_group); regulator_put(tpo_td043->vcc_reg); - if (gpio_is_valid(nreset_gpio)) - gpio_free(nreset_gpio); } static void tpo_td043_set_timings(struct omap_dss_device *dssdev, @@ -527,7 +525,6 @@ static int tpo_td043_spi_probe(struct spi_device *spi) return -ENOMEM; tpo_td043->spi = spi; - tpo_td043->nreset_gpio = dssdev->reset_gpio; dev_set_drvdata(&spi->dev, tpo_td043); g_tpo_td043 = tpo_td043; diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index d446bdf..a4b356a 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -435,20 +435,27 @@ static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_man 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; - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) + switch (mgr->output->id) { + case OMAP_DSS_OUTPUT_VENC: irq = DISPC_IRQ_EVSYNC_ODD; - else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) + break; + case OMAP_DSS_OUTPUT_HDMI: irq = DISPC_IRQ_EVSYNC_EVEN; - else + break; + default: irq = dispc_mgr_get_vsync_irq(mgr->id); + break; + } r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index f8779d4..60cc6fe 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -181,10 +181,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) 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/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 05ff2b9..b33b016 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -69,6 +69,8 @@ struct dispc_features { u8 mgr_height_start; u16 mgr_width_max; u16 mgr_height_max; + unsigned long max_lcd_pclk; + unsigned long max_tv_pclk; int (*calc_scaling) (unsigned long pclk, unsigned long lclk, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, @@ -85,6 +87,9 @@ struct dispc_features { /* no DISPC_IRQ_FRAMEDONETV on this SoC */ 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 @@ -97,6 +102,8 @@ 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]; @@ -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, + enum omap_dss_rotation_type rotation_type, bool mirroring, enum omap_color_mode color_mode) { bool row_repeat = false; @@ -1634,6 +1642,15 @@ static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, if (dss_has_feature(FEAT_ROWREPEATENABLE)) REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 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) @@ -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_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_pre_mult_alpha(plane, caps, pre_mult_alpha); @@ -2823,6 +2841,15 @@ static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, 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, const struct omap_video_timings *timings) { @@ -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); - if (dss_mgr_is_lcd(channel)) - timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw, - timings->hfp, timings->hbp, - timings->vsw, timings->vfp, - timings->vbp); + timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixel_clock * 1000); + + if (dss_mgr_is_lcd(channel)) { + timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp, + timings->hbp, timings->vsw, timings->vfp, + timings->vbp); + } return timings_ok; } @@ -2951,6 +2980,10 @@ 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, @@ -3056,15 +3089,7 @@ unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) unsigned long dispc_core_clk_rate(void) { - 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; + return dispc.core_clk_rate; } static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) @@ -3313,67 +3338,79 @@ static void dispc_dump_regs(struct seq_file *s) #undef DUMPREG } -/* 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, +/* calculate clock rates using dividers in cinfo */ +int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, struct dispc_clock_info *cinfo) { - u16 pcd_min, pcd_max; - unsigned long best_pck; - u16 best_ld, cur_ld; - u16 best_pd, cur_pd; + if (cinfo->lck_div > 255 || cinfo->lck_div == 0) + return -EINVAL; + if (cinfo->pck_div < 1 || cinfo->pck_div > 255) + return -EINVAL; - pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); - pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); + cinfo->lck = dispc_fclk_rate / cinfo->lck_div; + cinfo->pck = cinfo->lck / cinfo->pck_div; - best_pck = 0; - best_ld = 0; - best_pd = 0; + return 0; +} - for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { - unsigned long lck = fck / cur_ld; +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; - 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); +#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 - if (best_pck == 0 || new_delta < old_delta) { - best_pck = pck; - best_ld = cur_ld; - best_pd = cur_pd; + pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); + pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); - if (pck == req_pck) - goto found; - } + lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); - if (pck < req_pck) - break; - } + pck_min = pck_min ? pck_min : 1; + pck_max = pck_max ? pck_max : ULONG_MAX; - if (lck / pcd_min < req_pck) - break; - } + lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul); + lckd_stop = min(dispc / pck_min, 255ul); -found: - cinfo->lck_div = best_ld; - cinfo->pck_div = best_pd; - cinfo->lck = fck / cinfo->lck_div; - cinfo->pck = cinfo->lck / cinfo->pck_div; -} + for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) { + lck = dispc / lckd; -/* 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; + pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min); + pckd_stop = min(lck / pck_min, pckd_hw_max); - cinfo->lck = dispc_fclk_rate / cinfo->lck_div; - cinfo->pck = cinfo->lck / cinfo->pck_div; + for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) { + 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, @@ -3451,6 +3488,8 @@ 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 */ @@ -3466,6 +3505,9 @@ static void _omap_dispc_initial_config(void) dispc_configure_burst_sizes(); 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 = { @@ -3479,6 +3521,7 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = { .mgr_height_start = 26, .mgr_width_max = 2048, .mgr_height_max = 2048, + .max_lcd_pclk = 66500000, .calc_scaling = dispc_ovl_calc_scaling_24xx, .calc_core_clk = calc_core_clk_24xx, .num_fifos = 3, @@ -3496,6 +3539,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { .mgr_height_start = 26, .mgr_width_max = 2048, .mgr_height_max = 2048, + .max_lcd_pclk = 173000000, + .max_tv_pclk = 59000000, .calc_scaling = dispc_ovl_calc_scaling_34xx, .calc_core_clk = calc_core_clk_34xx, .num_fifos = 3, @@ -3513,6 +3558,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { .mgr_height_start = 26, .mgr_width_max = 2048, .mgr_height_max = 2048, + .max_lcd_pclk = 173000000, + .max_tv_pclk = 59000000, .calc_scaling = dispc_ovl_calc_scaling_34xx, .calc_core_clk = calc_core_clk_34xx, .num_fifos = 3, @@ -3530,6 +3577,8 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { .mgr_height_start = 26, .mgr_width_max = 2048, .mgr_height_max = 2048, + .max_lcd_pclk = 170000000, + .max_tv_pclk = 185625000, .calc_scaling = dispc_ovl_calc_scaling_44xx, .calc_core_clk = calc_core_clk_44xx, .num_fifos = 5, @@ -3547,10 +3596,13 @@ static const struct dispc_features omap54xx_dispc_feats __initconst = { .mgr_height_start = 27, .mgr_width_max = 4096, .mgr_height_max = 4096, + .max_lcd_pclk = 170000000, + .max_tv_pclk = 186000000, .calc_scaling = dispc_ovl_calc_scaling_44xx, .calc_core_clk = calc_core_clk_44xx, .num_fifos = 5, .gfx_fifo_workaround = true, + .mstandby_workaround = true, }; static int __init dispc_init_features(struct platform_device *pdev) diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 222363c6..de4863d 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -39,6 +39,7 @@ #define DISPC_GLOBAL_BUFFER 0x0800 #define DISPC_CONTROL3 0x0848 #define DISPC_CONFIG3 0x084C +#define DISPC_MSTANDBY_CTRL 0x0858 /* DISPC overlay registers */ #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 4af136a..e93c4de 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -63,15 +63,29 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) case OMAPDSS_VER_OMAP3630: case OMAPDSS_VER_AM35xx: return NULL; - default: - break; - } - 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); + 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; + } + default: return NULL; } @@ -91,75 +105,211 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) } } -static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, +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, unsigned long pck_req, unsigned long *fck, int *lck_div, int *pck_div) { - struct omap_overlay_manager *mgr = dssdev->output->manager; - struct dsi_clock_info dsi_cinfo; - struct dispc_clock_info dispc_cinfo; + struct dpi_clk_calc_ctx ctx; int r; + bool ok; - r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo, - &dispc_cinfo); - if (r) - return r; + ok = dpi_dsi_clk_calc(pck_req, &ctx); + if (!ok) + return -EINVAL; - r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo); + r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo); if (r) return r; - dss_select_lcd_clk_source(mgr->id, - dpi_get_alt_clk_src(mgr->id)); + dss_select_lcd_clk_source(channel, + dpi_get_alt_clk_src(channel)); - dpi.mgr_config.clock_info = dispc_cinfo; + dpi.mgr_config.clock_info = ctx.dispc_cinfo; - *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; - *lck_div = dispc_cinfo.lck_div; - *pck_div = dispc_cinfo.pck_div; + *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; + *lck_div = ctx.dispc_cinfo.lck_div; + *pck_div = ctx.dispc_cinfo.pck_div; return 0; } -static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, - unsigned long pck_req, unsigned long *fck, int *lck_div, - int *pck_div) +static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, + int *lck_div, int *pck_div) { - struct dss_clock_info dss_cinfo; - struct dispc_clock_info dispc_cinfo; + struct dpi_clk_calc_ctx ctx; int r; + bool ok; - r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo); - if (r) - return r; + ok = dpi_dss_clk_calc(pck_req, &ctx); + if (!ok) + return -EINVAL; - r = dss_set_clock_div(&dss_cinfo); + r = dss_set_clock_div(&ctx.dss_cinfo); if (r) return r; - dpi.mgr_config.clock_info = dispc_cinfo; + dpi.mgr_config.clock_info = ctx.dispc_cinfo; - *fck = dss_cinfo.fck; - *lck_div = dispc_cinfo.lck_div; - *pck_div = dispc_cinfo.pck_div; + *fck = ctx.dss_cinfo.fck; + *lck_div = ctx.dispc_cinfo.lck_div; + *pck_div = ctx.dispc_cinfo.pck_div; return 0; } -static int dpi_set_mode(struct omap_dss_device *dssdev) +static int dpi_set_mode(struct omap_overlay_manager *mgr) { 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(dssdev, t->pixel_clock * 1000, &fck, + r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); else - r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck, + r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck, &lck_div, &pck_div); if (r) return r; @@ -179,10 +329,8 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) return 0; } -static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) +static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) { - struct omap_overlay_manager *mgr = dssdev->output->manager; - dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dpi.mgr_config.stallmode = false; @@ -197,7 +345,7 @@ static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_output *out = dssdev->output; + struct omap_dss_output *out = &dpi.output; int r; mutex_lock(&dpi.lock); @@ -230,7 +378,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; - r = dss_dpi_select_source(dssdev->channel); + r = dss_dpi_select_source(out->manager->id); if (r) goto err_src_sel; @@ -244,11 +392,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) goto err_dsi_pll_init; } - r = dpi_set_mode(dssdev); + r = dpi_set_mode(out->manager); if (r) goto err_set_mode; - dpi_config_lcd_manager(dssdev); + dpi_config_lcd_manager(out->manager); mdelay(2); @@ -285,7 +433,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = dpi.output.manager; mutex_lock(&dpi.lock); @@ -324,12 +472,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings); int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - int r; - struct omap_overlay_manager *mgr = dssdev->output->manager; + struct omap_overlay_manager *mgr = dpi.output.manager; int lck_div, pck_div; unsigned long fck; unsigned long pck; - struct dispc_clock_info dispc_cinfo; + struct dpi_clk_calc_ctx ctx; + bool ok; if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) return -EINVAL; @@ -338,28 +486,21 @@ int dpi_check_timings(struct omap_dss_device *dssdev, return -EINVAL; if (dpi.dsidev) { - 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; + ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx); + if (!ok) + return -EINVAL; - fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; + fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; } else { - struct dss_clock_info dss_cinfo; - r = dss_calc_clock_div(timings->pixel_clock * 1000, - &dss_cinfo, &dispc_cinfo); + ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx); + if (!ok) + return -EINVAL; - if (r) - return r; - - fck = dss_cinfo.fck; + fck = ctx.dss_cinfo.fck; } - lck_div = dispc_cinfo.lck_div; - pck_div = dispc_cinfo.pck_div; + lck_div = ctx.dispc_cinfo.lck_div; + pck_div = ctx.dispc_cinfo.pck_div; pck = fck / lck_div / pck_div / 1000; @@ -401,6 +542,36 @@ 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; @@ -421,12 +592,7 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) dpi.vdds_dsi_reg = vdds_dsi; } - /* - * 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); + dsidev = dpi_get_dsidev(dpi.output.dispc_channel); if (dsidev && dpi_verify_dsi_pll(dsidev)) { dsidev = NULL; @@ -517,6 +683,8 @@ 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/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 28d41d1..9b1c5ec 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -200,6 +200,11 @@ 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 @@ -250,6 +255,24 @@ 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; @@ -261,6 +284,9 @@ 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; @@ -324,6 +350,7 @@ 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; @@ -1192,15 +1219,33 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) return r; } -static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev) +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) { - 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 = dssdev->clocks.dsi.lp_clk_div; + lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div; if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max) return -EINVAL; @@ -1272,6 +1317,75 @@ 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) @@ -1316,192 +1430,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev, return 0; } -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) +static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo) { unsigned long max_dsi_fck; @@ -1511,90 +1440,6 @@ static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, 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) { @@ -2783,6 +2628,7 @@ 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); @@ -2807,6 +2653,8 @@ 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, @@ -3777,13 +3625,12 @@ 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 (line_buf_size <= timings->x_res * bpp / 8) + if (dsi->line_buffer_size <= timings->x_res * bpp / 8) num_line_buffers = 0; else num_line_buffers = 2; @@ -3799,18 +3646,22 @@ 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 vsync_end = dsi->vm_timings.vp_vsync_end; - bool hsync_end = dsi->vm_timings.vp_hsync_end; + bool sync_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, vsync_end, 16, 16); /* VP_VSYNC_END */ + r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */ r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ - r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */ + r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */ dsi_write_reg(dsidev, DSI_CTRL, r); } @@ -3897,9 +3748,8 @@ 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 omap_dss_device *dssdev) +static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) { - 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; @@ -3910,7 +3760,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) 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 = dssdev->clocks.dsi.regm_dsi + 1; + int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.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; @@ -4015,9 +3865,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_VM_TIMING6, r); } -static int dsi_proto_config(struct omap_dss_device *dssdev) +static int dsi_proto_config(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; int buswidth = 0; @@ -4075,7 +3924,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_config_vp_sync_events(dsidev); dsi_config_blanking_modes(dsidev); - dsi_config_cmd_mode_interleaving(dssdev); + dsi_config_cmd_mode_interleaving(dsidev); } dsi_vc_initial_config(dsidev, 0); @@ -4159,11 +4008,12 @@ 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 = dsi->vm_timings.vp_hsync_end; + bool 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; @@ -4266,82 +4116,26 @@ 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 = dssdev->output->manager; + struct omap_overlay_manager *mgr = dsi->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: @@ -4357,8 +4151,8 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; break; default: - BUG(); - return -EINVAL; + r = -EINVAL; + goto err_pix_fmt; }; dsi_if_enable(dsidev, false); @@ -4377,16 +4171,20 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) } r = dss_mgr_enable(mgr); - if (r) { - if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_if_enable(dsidev, false); - dsi_vc_enable(dsidev, channel, false); - } - - return r; - } + if (r) + goto err_mgr_enable; return 0; + +err_mgr_enable: + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_if_enable(dsidev, false); + dsi_vc_enable(dsidev, channel, false); + } +err_pix_fmt: + dsi_display_uninit_dispc(dsidev, mgr); +err_init_dispc: + return r; } EXPORT_SYMBOL(dsi_enable_video_output); @@ -4394,7 +4192,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 = dssdev->output->manager; + struct omap_overlay_manager *mgr = dsi->output.manager; if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); @@ -4408,14 +4206,15 @@ 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 omap_dss_device *dssdev) +static void dsi_update_screen_dispc(struct platform_device *dsidev) { - 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; + struct omap_overlay_manager *mgr = dsi->output.manager; unsigned bytespp; unsigned bytespl; unsigned bytespf; @@ -4425,7 +4224,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) u32 l; int r; const unsigned channel = dsi->update_channel; - const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); + const unsigned line_buf_size = dsi->line_buffer_size; u16 w = dsi->timings.x_res; u16 h = dsi->timings.y_res; @@ -4571,7 +4370,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(dssdev); + dsi_update_screen_dispc(dsidev); return 0; } @@ -4579,18 +4378,17 @@ EXPORT_SYMBOL(omap_dsi_update); /* Display funcs */ -static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) +static int dsi_configure_dispc_clocks(struct platform_device *dsidev) { - 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 long fck; + unsigned long fck; fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); - dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div; - dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div; + dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div; + dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div; r = dispc_calc_clock_rates(fck, &dispc_cinfo); if (r) { @@ -4603,21 +4401,17 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) return 0; } -static int dsi_display_init_dispc(struct omap_dss_device *dssdev) +static int dsi_display_init_dispc(struct platform_device *dsidev, + struct omap_overlay_manager *mgr) { - 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; - 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; + 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) { r = dss_mgr_register_framedone_handler(mgr, dsi_framedone_irq_callback, dsidev); if (r) { @@ -4645,7 +4439,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dss_mgr_set_timings(mgr, &dsi->timings); - r = dsi_configure_dispc_clocks(dssdev); + r = dsi_configure_dispc_clocks(dsidev); if (r) goto err1; @@ -4662,30 +4456,30 @@ err1: 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 omap_dss_device *dssdev) +static void dsi_display_uninit_dispc(struct platform_device *dsidev, + struct omap_overlay_manager *mgr) { - 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 omap_dss_device *dssdev) +static int dsi_configure_dsi_clocks(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dsi_clock_info cinfo; int r; - 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; + cinfo = dsi->user_dsi_cinfo; + r = dsi_calc_clock_rates(dsidev, &cinfo); if (r) { DSSERR("Failed to calc dsi clocks\n"); @@ -4701,24 +4495,22 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) return 0; } -static int dsi_display_init_dsi(struct omap_dss_device *dssdev) +static int dsi_display_init_dsi(struct platform_device *dsidev) { - 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(dssdev); + r = dsi_configure_dsi_clocks(dsidev); if (r) goto err1; - 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); + 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); DSSDBG("PLL OK\n"); @@ -4729,12 +4521,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) _dsi_print_reset_status(dsidev); dsi_proto_timings(dsidev); - dsi_set_lp_clk_divisor(dssdev); + dsi_set_lp_clk_divisor(dsidev); if (1) _dsi_print_reset_status(dsidev); - r = dsi_proto_config(dssdev); + r = dsi_proto_config(dsidev); if (r) goto err3; @@ -4751,20 +4543,16 @@ err3: 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 omap_dss_device *dssdev, +static void dsi_display_uninit_dsi(struct platform_device *dsidev, 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); @@ -4777,7 +4565,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, 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); } @@ -4786,7 +4573,6 @@ 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"); @@ -4795,12 +4581,6 @@ 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"); @@ -4815,11 +4595,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) _dsi_initialize_irq(dsidev); - r = dsi_display_init_dispc(dssdev); - if (r) - goto err_init_dispc; - - r = dsi_display_init_dsi(dssdev); + r = dsi_display_init_dsi(dsidev); if (r) goto err_init_dsi; @@ -4828,8 +4604,6 @@ 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: @@ -4858,9 +4632,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev, dsi_sync_vc(dsidev, 2); dsi_sync_vc(dsidev, 3); - dsi_display_uninit_dispc(dssdev); - - dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps); + dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps); dsi_runtime_put(dsidev); dsi_enable_pll_clock(dsidev, 0); @@ -4881,75 +4653,577 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) } EXPORT_SYMBOL(omapdss_dsi_enable_te); -void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +#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) { - 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 = data; + struct omap_video_timings *t = &ctx->dispc_vm; - mutex_lock(&dsi->lock); + ctx->dispc_cinfo.lck_div = lckd; + ctx->dispc_cinfo.pck_div = pckd; + ctx->dispc_cinfo.lck = lck; + ctx->dispc_cinfo.pck = pck; - dsi->timings = *timings; + *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; - mutex_unlock(&dsi->lock); + return true; } -EXPORT_SYMBOL(omapdss_dsi_set_timings); -void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) +static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, + void *data) { - 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 = data; - mutex_lock(&dsi->lock); + ctx->dsi_cinfo.regm_dispc = regm_dispc; + ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; - dsi->timings.x_res = w; - dsi->timings.y_res = h; + return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, + dsi_cm_calc_dispc_cb, ctx); +} - mutex_unlock(&dsi->lock); +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); } -EXPORT_SYMBOL(omapdss_dsi_set_size); -void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, - enum omap_dss_dsi_pixel_format fmt) +static bool dsi_cm_calc(struct dsi_data *dsi, + const struct omap_dss_dsi_config *cfg, + struct dsi_clk_calc_ctx *ctx) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + unsigned long clkin; + int bitspp, ndl; + unsigned long pll_min, pll_max; + unsigned long pck, txbyteclk; - mutex_lock(&dsi->lock); + 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; - dsi->pix_fmt = fmt; + 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; - mutex_unlock(&dsi->lock); + 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); } -EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); -void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, - enum omap_dss_dsi_mode mode) +static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + 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; - mutex_lock(&dsi->lock); + 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->mode = mode; + dsi_tput = (u64)byteclk * ndl * 8; - mutex_unlock(&dsi->lock); + 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; + } + } + + if (hfp < 1) + return false; + + dispc_vm->hfp = hfp; + dispc_vm->hsw = hsa; + dispc_vm->hbp = hbp; + + return true; +} + + +static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, + unsigned long pck, void *data) +{ + 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; + + if (dsi_vm_calc_blanking(ctx) == false) + return false; + +#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 + + return true; +} + +static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, + void *data) +{ + 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); +} + +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; + + 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_vm_calc_hsdiv_cb, ctx); +} + +static bool dsi_vm_calc(struct dsi_data *dsi, + const struct omap_dss_dsi_config *cfg, + struct dsi_clk_calc_ctx *ctx) +{ + 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); + + 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); + + pll_max = byteclk_max * 4 * 4; + } + + return dsi_pll_calc(dsi->pdev, clkin, + pll_min, pll_max, + dsi_vm_calc_pll_cb, ctx); } -EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); -void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, - struct omap_dss_dsi_videomode_timings *timings) +int omapdss_dsi_set_config(struct omap_dss_device *dssdev, + const struct omap_dss_dsi_config *config) { 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->vm_timings = *timings; + 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; 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) { @@ -5073,7 +5347,7 @@ static int dsi_get_clocks(struct platform_device *dsidev) struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct clk *clk; - clk = clk_get(&dsidev->dev, "fck"); + clk = devm_clk_get(&dsidev->dev, "fck"); if (IS_ERR(clk)) { DSSERR("can't get fck\n"); return PTR_ERR(clk); @@ -5081,11 +5355,9 @@ static int dsi_get_clocks(struct platform_device *dsidev) dsi->dss_clk = clk; - clk = clk_get(&dsidev->dev, "sys_clk"); + clk = devm_clk_get(&dsidev->dev, "sys_clk"); if (IS_ERR(clk)) { DSSERR("can't get sys_clk\n"); - clk_put(dsi->dss_clk); - dsi->dss_clk = NULL; return PTR_ERR(clk); } @@ -5094,16 +5366,6 @@ static int dsi_get_clocks(struct platform_device *dsidev) return 0; } -static void dsi_put_clocks(struct platform_device *dsidev) -{ - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - - if (dsi->dss_clk) - clk_put(dsi->dss_clk); - if (dsi->sys_clk) - clk_put(dsi->sys_clk); -} - static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; @@ -5188,6 +5450,8 @@ 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); } @@ -5293,6 +5557,8 @@ 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); @@ -5314,7 +5580,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) err_runtime_get: pm_runtime_disable(&dsidev->dev); - dsi_put_clocks(dsidev); return r; } @@ -5330,8 +5595,6 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) pm_runtime_disable(&dsidev->dev); - dsi_put_clocks(dsidev); - if (dsi->vdds_dsi_reg != NULL) { if (dsi->vdds_dsi_enabled) { regulator_disable(dsi->vdds_dsi_reg); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 054c2a2..94f66f9 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -473,6 +473,47 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) 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) { @@ -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)); 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) return r; } else { @@ -492,7 +534,9 @@ 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"); + 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); @@ -542,121 +586,6 @@ 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; @@ -767,13 +696,11 @@ int dss_dpi_select_source(enum omap_channel channel) static int dss_get_clocks(void) { struct clk *clk; - int r; - clk = clk_get(&dss.pdev->dev, "fck"); + clk = devm_clk_get(&dss.pdev->dev, "fck"); if (IS_ERR(clk)) { DSSERR("can't get clock fck\n"); - r = PTR_ERR(clk); - goto err; + return PTR_ERR(clk); } dss.dss_clk = clk; @@ -782,8 +709,7 @@ static int dss_get_clocks(void) clk = clk_get(NULL, dss.feat->clk_name); if (IS_ERR(clk)) { DSSERR("Failed to get %s\n", dss.feat->clk_name); - r = PTR_ERR(clk); - goto err; + return PTR_ERR(clk); } } else { clk = NULL; @@ -792,21 +718,12 @@ static int dss_get_clocks(void) dss.dpll4_m4_ck = clk; 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) { if (dss.dpll4_m4_ck) clk_put(dss.dpll4_m4_ck); - clk_put(dss.dss_clk); } static int dss_runtime_get(void) diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 610c8e5..faaf358 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -268,8 +268,9 @@ void dss_set_dac_pwrdn_bgz(bool enable); 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); -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 */ int sdi_init_platform_driver(void) __init; @@ -292,12 +293,21 @@ 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); @@ -328,14 +338,6 @@ 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) { @@ -376,11 +378,15 @@ 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/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 7f791ae..77dbe0c 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -414,7 +414,7 @@ static const char * const omap5_dss_clk_source_names[] = { }; 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_DSIPLL_REGN] = { 0, 0 }, [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, @@ -459,15 +459,15 @@ static const struct dss_param_range omap4_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_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 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_DSI_FCK] = { 0, 170000000 }, + [FEAT_PARAM_DSI_FCK] = { 0, 209250000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, }; diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 72923645..7939309 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -472,17 +472,12 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, * Input clock is predivided by N + 1 * out put of which is reference clk */ - if (dssdev->clocks.hdmi.regn == 0) - pi->regn = HDMI_DEFAULT_REGN; - else - pi->regn = dssdev->clocks.hdmi.regn; + + pi->regn = HDMI_DEFAULT_REGN; refclk = clkin / pi->regn; - if (dssdev->clocks.hdmi.regm2 == 0) - pi->regm2 = HDMI_DEFAULT_REGM2; - else - pi->regm2 = dssdev->clocks.hdmi.regm2; + pi->regm2 = HDMI_DEFAULT_REGM2; /* * multiplier is pixel_clk/ref_clk @@ -804,7 +799,7 @@ static int hdmi_get_clocks(struct platform_device *pdev) { struct clk *clk; - clk = clk_get(&pdev->dev, "sys_clk"); + clk = devm_clk_get(&pdev->dev, "sys_clk"); if (IS_ERR(clk)) { DSSERR("can't get sys_clk\n"); return PTR_ERR(clk); @@ -815,12 +810,6 @@ static int hdmi_get_clocks(struct platform_device *pdev) return 0; } -static void hdmi_put_clocks(void) -{ - if (hdmi.sys_clk) - clk_put(hdmi.sys_clk); -} - #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) 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) 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); @@ -1051,6 +1038,8 @@ 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); } @@ -1097,23 +1086,19 @@ 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"); - goto err_panel_init; + return r; } dss_debugfs_create_file("hdmi", hdmi_dump_regs); - hdmi_init_output(pdev); - hdmi_probe_pdata(pdev); return 0; - -err_panel_init: - hdmi_put_clocks(); - return r; } 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) pm_runtime_disable(&pdev->dev); - hdmi_put_clocks(); - return 0; } diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c index 79dea1a..5214df6 100644 --- a/drivers/video/omap2/dss/output.c +++ b/drivers/video/omap2/dss/output.c @@ -113,6 +113,7 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) return NULL; } +EXPORT_SYMBOL(omap_dss_get_output); static const struct dss_mgr_ops *dss_mgr_ops; diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index e903dd3..1a691bb 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -1025,6 +1025,8 @@ static void __init rfbi_init_output(struct platform_device *pdev) 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/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 62b5374..e6baee2 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -41,6 +41,72 @@ 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; @@ -88,7 +154,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 = 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) goto err_calc_clock_div; @@ -278,6 +344,8 @@ 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/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 006caf3..17764d1 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -519,10 +519,6 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev) goto err0; } - if (dssdev->platform_enable) - dssdev->platform_enable(dssdev); - - r = venc_power_on(dssdev); if (r) goto err1; @@ -533,8 +529,6 @@ int omapdss_venc_display_enable(struct omap_dss_device *dssdev) return 0; err1: - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); omap_dss_stop_device(dssdev); err0: mutex_unlock(&venc.venc_lock); @@ -551,9 +545,6 @@ void omapdss_venc_display_disable(struct omap_dss_device *dssdev) omap_dss_stop_device(dssdev); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - mutex_unlock(&venc.venc_lock); } @@ -721,7 +712,7 @@ static int venc_get_clocks(struct platform_device *pdev) struct clk *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)) { DSSERR("can't get tv_dac_clk\n"); return PTR_ERR(clk); @@ -735,12 +726,6 @@ static int venc_get_clocks(struct platform_device *pdev) 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) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; @@ -786,8 +771,6 @@ 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); @@ -819,6 +802,8 @@ 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); } @@ -886,7 +871,6 @@ static int __init omap_venchw_probe(struct platform_device *pdev) err_panel_init: err_runtime_get: pm_runtime_disable(&pdev->dev); - venc_put_clocks(); return r; } @@ -904,7 +888,6 @@ static int __exit omap_venchw_remove(struct platform_device *pdev) venc_uninit_output(pdev); pm_runtime_disable(&pdev->dev); - venc_put_clocks(); return 0; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index ca585ef..f38348e 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2388,7 +2388,7 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; 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) continue; diff --git a/include/video/omap-panel-data.h b/include/video/omap-panel-data.h new file mode 100644 index 0000000..0c3b46d --- /dev/null +++ b/include/video/omap-panel-data.h @@ -0,0 +1,150 @@ +/* + * Header containing platform_data structs for omap panels + * + * Copyright (C) 2013 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * Archit Taneja <archit@ti.com> + * + * Copyright (C) 2011 Texas Instruments + * Author: Mayuresh Janorkar <mayur@ti.com> + * + * Copyright (C) 2010 Canonical Ltd. + * Author: Bryan Wu <bryan.wu@canonical.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __OMAP_PANEL_DATA_H +#define __OMAP_PANEL_DATA_H + +struct omap_dss_device; + +/** + * struct panel_generic_dpi_data - panel driver configuration data + * @name: panel name + * @platform_enable: platform specific panel enable function + * @platform_disable: platform specific panel disable function + * @num_gpios: number of gpios connected to panel + * @gpios: gpio numbers on the platform + * @gpio_invert: configure gpio as active high or low + */ +struct panel_generic_dpi_data { + const char *name; + int (*platform_enable)(struct omap_dss_device *dssdev); + void (*platform_disable)(struct omap_dss_device *dssdev); + + int num_gpios; + int gpios[10]; + bool gpio_invert[10]; +}; + +/** + * struct panel_n8x0_data - N800 panel driver configuration data + */ +struct panel_n8x0_data { + int (*platform_enable)(struct omap_dss_device *dssdev); + void (*platform_disable)(struct omap_dss_device *dssdev); + int panel_reset; + int ctrl_pwrdown; +}; + +/** + * struct nokia_dsi_panel_data - Nokia DSI panel driver configuration data + * @name: panel name + * @use_ext_te: use external TE + * @ext_te_gpio: external TE GPIO + * @esd_interval: interval of ESD checks, 0 = disabled (ms) + * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms) + * @use_dsi_backlight: true if panel uses DSI command to control backlight + * @pin_config: DSI pin configuration + */ + +struct nokia_dsi_panel_data { + const char *name; + + int reset_gpio; + + bool use_ext_te; + int ext_te_gpio; + + unsigned esd_interval; + unsigned ulps_timeout; + + bool use_dsi_backlight; + + struct omap_dsi_pin_config pin_config; +}; + +/** + * struct picodlp_panel_data - picodlp panel driver configuration data + * @picodlp_adapter_id: i2c_adapter number for picodlp + */ +struct picodlp_panel_data { + int picodlp_adapter_id; + int emu_done_gpio; + int pwrgood_gpio; +}; + +/** + * struct tfp410_platform_data - tfp410 panel driver configuration data + * @i2c_bus_num: i2c bus id for the panel + * @power_down_gpio: gpio number for PD pin (or -1 if not available) + */ +struct tfp410_platform_data { + int i2c_bus_num; + int power_down_gpio; +}; + +/** + * sharp ls panel driver configuration data + * @resb_gpio: reset signal + * @ini_gpio: power on control + * @mo_gpio: selection for resolution(VGA/QVGA) + * @lr_gpio: selection for horizontal scanning direction + * @ud_gpio: selection for vertical scanning direction + */ +struct panel_sharp_ls037v7dw01_data { + int resb_gpio; + int ini_gpio; + int mo_gpio; + int lr_gpio; + int ud_gpio; +}; + +/** + * acx565akm panel driver configuration data + * @reset_gpio: reset signal + */ +struct panel_acx565akm_data { + int reset_gpio; +}; + +/** + * nec nl8048 panel driver configuration data + * @res_gpio: reset signal + * @qvga_gpio: selection for resolution(QVGA/WVGA) + */ +struct panel_nec_nl8048_data { + int res_gpio; + int qvga_gpio; +}; + +/** + * tpo td043 panel driver configuration data + * @nreset_gpio: reset signal + */ +struct panel_tpo_td043_data { + int nreset_gpio; +}; + +#endif /* __OMAP_PANEL_DATA_H */ diff --git a/include/video/omap-panel-generic-dpi.h b/include/video/omap-panel-generic-dpi.h deleted file mode 100644 index 127e3f2..0000000 --- a/include/video/omap-panel-generic-dpi.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Header for generic DPI panel driver - * - * Copyright (C) 2010 Canonical Ltd. - * Author: Bryan Wu <bryan.wu@canonical.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __OMAP_PANEL_GENERIC_DPI_H -#define __OMAP_PANEL_GENERIC_DPI_H - -struct omap_dss_device; - -/** - * struct panel_generic_dpi_data - panel driver configuration data - * @name: panel name - * @platform_enable: platform specific panel enable function - * @platform_disable: platform specific panel disable function - */ -struct panel_generic_dpi_data { - const char *name; - int (*platform_enable)(struct omap_dss_device *dssdev); - void (*platform_disable)(struct omap_dss_device *dssdev); -}; - -#endif /* __OMAP_PANEL_GENERIC_DPI_H */ diff --git a/include/video/omap-panel-n8x0.h b/include/video/omap-panel-n8x0.h deleted file mode 100644 index 50a1302..0000000 --- a/include/video/omap-panel-n8x0.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __OMAP_PANEL_N8X0_H -#define __OMAP_PANEL_N8X0_H - -struct omap_dss_device; - -struct panel_n8x0_data { - int (*platform_enable)(struct omap_dss_device *dssdev); - void (*platform_disable)(struct omap_dss_device *dssdev); - int panel_reset; - int ctrl_pwrdown; - - int (*set_backlight)(struct omap_dss_device *dssdev, int level); -}; - -#endif diff --git a/include/video/omap-panel-nokia-dsi.h b/include/video/omap-panel-nokia-dsi.h deleted file mode 100644 index 04219a2..0000000 --- a/include/video/omap-panel-nokia-dsi.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __OMAP_NOKIA_DSI_PANEL_H -#define __OMAP_NOKIA_DSI_PANEL_H - -struct omap_dss_device; - -/** - * struct nokia_dsi_panel_data - Nokia DSI panel driver configuration - * @name: panel name - * @use_ext_te: use external TE - * @ext_te_gpio: external TE GPIO - * @esd_interval: interval of ESD checks, 0 = disabled (ms) - * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms) - * @use_dsi_backlight: true if panel uses DSI command to control backlight - * @pin_config: DSI pin configuration - */ -struct nokia_dsi_panel_data { - const char *name; - - int reset_gpio; - - bool use_ext_te; - int ext_te_gpio; - - unsigned esd_interval; - unsigned ulps_timeout; - - bool use_dsi_backlight; - - struct omap_dsi_pin_config pin_config; -}; - -#endif /* __OMAP_NOKIA_DSI_PANEL_H */ diff --git a/include/video/omap-panel-picodlp.h b/include/video/omap-panel-picodlp.h deleted file mode 100644 index 1c342ef..0000000 --- a/include/video/omap-panel-picodlp.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * panel data for picodlp panel - * - * Copyright (C) 2011 Texas Instruments - * - * Author: Mayuresh Janorkar <mayur@ti.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __PANEL_PICODLP_H -#define __PANEL_PICODLP_H -/** - * struct : picodlp panel data - * picodlp_adapter_id: i2c_adapter number for picodlp - */ -struct picodlp_panel_data { - int picodlp_adapter_id; - int emu_done_gpio; - int pwrgood_gpio; -}; -#endif /* __PANEL_PICODLP_H */ diff --git a/include/video/omap-panel-tfp410.h b/include/video/omap-panel-tfp410.h deleted file mode 100644 index aef35e4..0000000 --- a/include/video/omap-panel-tfp410.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Header for TFP410 chip driver - * - * Copyright (C) 2011 Texas Instruments Inc - * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __OMAP_PANEL_TFP410_H -#define __OMAP_PANEL_TFP410_H - -struct omap_dss_device; - -/** - * struct tfp410_platform_data - panel driver configuration data - * @i2c_bus_num: i2c bus id for the panel - * @power_down_gpio: gpio number for PD pin (or -1 if not available) - */ -struct tfp410_platform_data { - int i2c_bus_num; - int power_down_gpio; -}; - -#endif /* __OMAP_PANEL_TFP410_H */ diff --git a/include/video/omapdss.h b/include/video/omapdss.h index caefa09..62ca9a7 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -257,10 +257,31 @@ 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 */ @@ -274,14 +295,24 @@ struct omap_dss_dsi_videomode_timings { int hbp_blanking_mode; int hfp_blanking_mode; - /* Video port sync events */ - bool vp_vsync_end; - bool vp_hsync_end; + enum omap_dss_dsi_trans_mode trans_mode; 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, @@ -541,9 +572,14 @@ 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; @@ -561,6 +597,7 @@ struct omap_dss_device { enum omap_display_type type; + /* obsolete, to be removed */ enum omap_channel channel; union { @@ -591,40 +628,10 @@ struct omap_dss_device { } 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 { @@ -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, bool enable); int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); -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 omapdss_dsi_set_config(struct omap_dss_device *dssdev, + const struct omap_dss_dsi_config *config); int omap_dsi_update(struct omap_dss_device *dssdev, int channel, 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); 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, |