Commit 561564be authored by Daniel Vetter's avatar Daniel Vetter

Merge tag 'omapdrm-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next

omapdrm changes for 5.3

- Add support for DSI command mode displays
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Link: https://patchwork.freedesktop.org/patch/msgid/a709f57d-6909-8550-3932-d84e0b5bc3ef@ti.com
parents 34c8a892 1bb418bf
......@@ -410,8 +410,7 @@ static const struct backlight_ops dsicm_bl_ops = {
static ssize_t dsicm_num_errors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct panel_drv_data *ddata = dev_get_drvdata(dev);
struct omap_dss_device *src = ddata->src;
u8 errors = 0;
int r;
......@@ -442,8 +441,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev,
static ssize_t dsicm_hw_revision_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct panel_drv_data *ddata = dev_get_drvdata(dev);
struct omap_dss_device *src = ddata->src;
u8 id1, id2, id3;
int r;
......@@ -474,8 +472,7 @@ static ssize_t dsicm_store_ulps(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct panel_drv_data *ddata = dev_get_drvdata(dev);
struct omap_dss_device *src = ddata->src;
unsigned long t;
int r;
......@@ -509,8 +506,7 @@ static ssize_t dsicm_show_ulps(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct panel_drv_data *ddata = dev_get_drvdata(dev);
unsigned int t;
mutex_lock(&ddata->lock);
......@@ -524,8 +520,7 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct panel_drv_data *ddata = dev_get_drvdata(dev);
struct omap_dss_device *src = ddata->src;
unsigned long t;
int r;
......@@ -556,8 +551,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct panel_drv_data *ddata = dev_get_drvdata(dev);
unsigned int t;
mutex_lock(&ddata->lock);
......
......@@ -198,6 +198,7 @@ static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = {
{ .compatible = "toppoly,td028ttec1" },
{ .compatible = "tpo,td028ttec1" },
{ .compatible = "tpo,td043mtea1" },
{},
};
static int __init omapdss_boot_init(void)
......
......@@ -32,6 +32,7 @@ struct omap_crtc_state {
/* Shadow values for legacy userspace support. */
unsigned int rotation;
unsigned int zpos;
bool manually_updated;
};
#define to_omap_crtc(x) container_of(x, struct omap_crtc, base)
......@@ -51,6 +52,10 @@ struct omap_crtc {
bool pending;
wait_queue_head_t pending_wait;
struct drm_pending_vblank_event *event;
struct delayed_work update_work;
void (*framedone_handler)(void *);
void *framedone_handler_data;
};
/* -----------------------------------------------------------------------------
......@@ -102,21 +107,18 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
/*
* Manager-ops, callbacks from output when they need to configure
* the upstream part of the video pipe.
*
* Most of these we can ignore until we add support for command-mode
* panels.. for video-mode the crtc-helpers already do an adequate
* job of sequencing the setup of the video pipe in the proper order
*/
/* we can probably ignore these until we support command-mode panels: */
static void omap_crtc_dss_start_update(struct omap_drm_private *priv,
enum omap_channel channel)
{
priv->dispc_ops->mgr_enable(priv->dispc, channel, true);
}
/* Called only from the encoder enable/disable and suspend/resume handlers. */
static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
{
struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);
struct drm_device *dev = crtc->dev;
struct omap_drm_private *priv = dev->dev_private;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
......@@ -128,6 +130,12 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
if (WARN_ON(omap_crtc->enabled == enable))
return;
if (omap_state->manually_updated) {
omap_irq_enable_framedone(crtc, enable);
omap_crtc->enabled = enable;
return;
}
if (omap_crtc->pipe->output->type == OMAP_DISPLAY_TYPE_HDMI) {
priv->dispc_ops->mgr_enable(priv->dispc, channel, enable);
omap_crtc->enabled = enable;
......@@ -230,6 +238,18 @@ static int omap_crtc_dss_register_framedone(
struct omap_drm_private *priv, enum omap_channel channel,
void (*handler)(void *), void *data)
{
struct drm_crtc *crtc = priv->channels[channel]->crtc;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_device *dev = omap_crtc->base.dev;
if (omap_crtc->framedone_handler)
return -EBUSY;
dev_dbg(dev->dev, "register framedone %s", omap_crtc->name);
omap_crtc->framedone_handler = handler;
omap_crtc->framedone_handler_data = data;
return 0;
}
......@@ -237,6 +257,17 @@ static void omap_crtc_dss_unregister_framedone(
struct omap_drm_private *priv, enum omap_channel channel,
void (*handler)(void *), void *data)
{
struct drm_crtc *crtc = priv->channels[channel]->crtc;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_device *dev = omap_crtc->base.dev;
dev_dbg(dev->dev, "unregister framedone %s", omap_crtc->name);
WARN_ON(omap_crtc->framedone_handler != handler);
WARN_ON(omap_crtc->framedone_handler_data != data);
omap_crtc->framedone_handler = NULL;
omap_crtc->framedone_handler_data = NULL;
}
static const struct dss_mgr_ops mgr_ops = {
......@@ -302,6 +333,73 @@ void omap_crtc_vblank_irq(struct drm_crtc *crtc)
DBG("%s: apply done", omap_crtc->name);
}
void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
if (!omap_crtc->framedone_handler)
return;
omap_crtc->framedone_handler(omap_crtc->framedone_handler_data);
spin_lock(&crtc->dev->event_lock);
/* Send the vblank event if one has been requested. */
if (omap_crtc->event) {
drm_crtc_send_vblank_event(crtc, omap_crtc->event);
omap_crtc->event = NULL;
}
omap_crtc->pending = false;
spin_unlock(&crtc->dev->event_lock);
/* Wake up omap_atomic_complete. */
wake_up(&omap_crtc->pending_wait);
}
void omap_crtc_flush(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);
if (!omap_state->manually_updated)
return;
if (!delayed_work_pending(&omap_crtc->update_work))
schedule_delayed_work(&omap_crtc->update_work, 0);
}
static void omap_crtc_manual_display_update(struct work_struct *data)
{
struct omap_crtc *omap_crtc =
container_of(data, struct omap_crtc, update_work.work);
struct drm_display_mode *mode = &omap_crtc->pipe->crtc->mode;
struct omap_dss_device *dssdev = omap_crtc->pipe->output->next;
struct drm_device *dev = omap_crtc->base.dev;
const struct omap_dss_driver *dssdrv;
int ret;
if (!dssdev) {
dev_err_once(dev->dev, "missing display dssdev!");
return;
}
dssdrv = dssdev->driver;
if (!dssdrv || !dssdrv->update) {
dev_err_once(dev->dev, "missing or incorrect dssdrv!");
return;
}
if (dssdrv->sync)
dssdrv->sync(dssdev);
ret = dssdrv->update(dssdev, 0, 0, mode->hdisplay, mode->vdisplay);
if (ret < 0) {
spin_lock_irq(&dev->event_lock);
omap_crtc->pending = false;
spin_unlock_irq(&dev->event_lock);
wake_up(&omap_crtc->pending_wait);
}
}
static void omap_crtc_write_crtc_properties(struct drm_crtc *crtc)
{
struct omap_drm_private *priv = crtc->dev->dev_private;
......@@ -351,12 +449,17 @@ static void omap_crtc_atomic_enable(struct drm_crtc *crtc,
{
struct omap_drm_private *priv = crtc->dev->dev_private;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_crtc_state *omap_state = to_omap_crtc_state(crtc->state);
int ret;
DBG("%s", omap_crtc->name);
priv->dispc_ops->runtime_get(priv->dispc);
/* manual updated display will not trigger vsync irq */
if (omap_state->manually_updated)
return;
spin_lock_irq(&crtc->dev->event_lock);
drm_crtc_vblank_on(crtc);
ret = drm_crtc_vblank_get(crtc);
......@@ -371,6 +474,7 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
{
struct omap_drm_private *priv = crtc->dev->dev_private;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct drm_device *dev = crtc->dev;
DBG("%s", omap_crtc->name);
......@@ -381,6 +485,11 @@ static void omap_crtc_atomic_disable(struct drm_crtc *crtc,
}
spin_unlock_irq(&crtc->dev->event_lock);
cancel_delayed_work(&omap_crtc->update_work);
if (!omap_crtc_wait_pending(crtc))
dev_warn(dev->dev, "manual display update did not finish!");
drm_crtc_vblank_off(crtc);
priv->dispc_ops->runtime_put(priv->dispc);
......@@ -395,10 +504,20 @@ static enum drm_mode_status omap_crtc_mode_valid(struct drm_crtc *crtc,
int r;
drm_display_mode_to_videomode(mode, &vm);
r = priv->dispc_ops->mgr_check_timings(priv->dispc, omap_crtc->channel,
&vm);
if (r)
return r;
/*
* DSI might not call this, since the supplied mode is not a
* valid DISPC mode. DSI will calculate and configure the
* proper DISPC mode later.
*/
if (omap_crtc->pipe->output->next == NULL ||
omap_crtc->pipe->output->next->type != OMAP_DISPLAY_TYPE_DSI) {
r = priv->dispc_ops->mgr_check_timings(priv->dispc,
omap_crtc->channel,
&vm);
if (r)
return r;
}
/* Check for bandwidth limit */
if (priv->max_bandwidth) {
......@@ -441,6 +560,22 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
drm_display_mode_to_videomode(mode, &omap_crtc->vm);
}
static bool omap_crtc_is_manually_updated(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_dss_device *display = omap_crtc->pipe->output->next;
if (!display)
return false;
if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
DBG("detected manually updated display!");
return true;
}
return false;
}
static int omap_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
......@@ -462,6 +597,9 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc,
/* Mirror new values for zpos and rotation in omap_crtc_state */
omap_crtc_state->zpos = pri_state->zpos;
omap_crtc_state->rotation = pri_state->rotation;
/* Check if this CRTC is for a manually updated display */
omap_crtc_state->manually_updated = omap_crtc_is_manually_updated(crtc);
}
return 0;
......@@ -477,6 +615,7 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
{
struct omap_drm_private *priv = crtc->dev->dev_private;
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
struct omap_crtc_state *omap_crtc_state = to_omap_crtc_state(crtc->state);
int ret;
if (crtc->state->color_mgmt_changed) {
......@@ -501,6 +640,15 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
DBG("%s: GO", omap_crtc->name);
if (omap_crtc_state->manually_updated) {
/* send new image for page flips and modeset changes */
spin_lock_irq(&crtc->dev->event_lock);
omap_crtc_flush(crtc);
omap_crtc_arm_event(crtc);
spin_unlock_irq(&crtc->dev->event_lock);
return;
}
ret = drm_crtc_vblank_get(crtc);
WARN_ON(ret != 0);
......@@ -586,6 +734,7 @@ omap_crtc_duplicate_state(struct drm_crtc *crtc)
state->zpos = current_state->zpos;
state->rotation = current_state->rotation;
state->manually_updated = current_state->manually_updated;
return &state->base;
}
......@@ -662,6 +811,19 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_crtc->channel = channel;
omap_crtc->name = channel_names[channel];
/*
* We want to refresh manually updated displays from dirty callback,
* which is called quite often (e.g. for each drawn line). This will
* be used to do the display update asynchronously to avoid blocking
* the rendering process and merges multiple dirty calls into one
* update if they arrive very fast. We also call this function for
* atomic display updates (e.g. for page flips), which means we do
* not need extra locking. Atomic updates should be synchronous, but
* need to wait for the framedone interrupt anyways.
*/
INIT_DELAYED_WORK(&omap_crtc->update_work,
omap_crtc_manual_display_update);
ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
&omap_crtc_funcs, NULL);
if (ret < 0) {
......
......@@ -41,5 +41,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
int omap_crtc_wait_pending(struct drm_crtc *crtc);
void omap_crtc_error_irq(struct drm_crtc *crtc, u32 irqstatus);
void omap_crtc_vblank_irq(struct drm_crtc *crtc);
void omap_crtc_framedone_irq(struct drm_crtc *crtc, uint32_t irqstatus);
void omap_crtc_flush(struct drm_crtc *crtc);
#endif /* __OMAPDRM_CRTC_H__ */
......@@ -439,20 +439,6 @@ static int ioctl_get_param(struct drm_device *dev, void *data,
return 0;
}
static int ioctl_set_param(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_omap_param *args = data;
switch (args->param) {
default:
DBG("unknown parameter %lld", args->param);
return -EINVAL;
}
return 0;
}
#define OMAP_BO_USER_MASK 0x00ffffff /* flags settable by userspace */
static int ioctl_gem_new(struct drm_device *dev, void *data,
......@@ -492,7 +478,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = {
DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param,
DRM_AUTH | DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param,
DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, drm_invalid_op,
DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new,
DRM_AUTH | DRM_RENDER_ALLOW),
......
......@@ -37,8 +37,8 @@
#include "omap_irq.h"
#include "omap_plane.h"
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */
#define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__)
#define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt, ##__VA_ARGS__) /* verbose debug */
#define MODULE_NAME "omapdrm"
......
......@@ -66,8 +66,27 @@ struct omap_framebuffer {
struct mutex lock;
};
static int omap_framebuffer_dirty(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned flags, unsigned color,
struct drm_clip_rect *clips,
unsigned num_clips)
{
struct drm_crtc *crtc;
drm_modeset_lock_all(fb->dev);
drm_for_each_crtc(crtc, fb->dev)
omap_crtc_flush(crtc);
drm_modeset_unlock_all(fb->dev);
return 0;
}
static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
.create_handle = drm_gem_fb_create_handle,
.dirty = omap_framebuffer_dirty,
.destroy = drm_gem_fb_destroy,
};
......
......@@ -85,6 +85,28 @@ int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
return ret == 0 ? -1 : 0;
}
int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable)
{
struct drm_device *dev = crtc->dev;
struct omap_drm_private *priv = dev->dev_private;
unsigned long flags;
enum omap_channel channel = omap_crtc_channel(crtc);
int framedone_irq =
priv->dispc_ops->mgr_get_framedone_irq(priv->dispc, channel);
DBG("dev=%p, crtc=%u, enable=%d", dev, channel, enable);
spin_lock_irqsave(&priv->wait_lock, flags);
if (enable)
priv->irq_mask |= framedone_irq;
else
priv->irq_mask &= ~framedone_irq;
omap_irq_update(dev);
spin_unlock_irqrestore(&priv->wait_lock, flags);
return 0;
}
/**
* enable_vblank - enable vblank interrupt events
* @dev: DRM device
......@@ -217,6 +239,9 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
if (irqstatus & priv->dispc_ops->mgr_get_sync_lost_irq(priv->dispc, channel))
omap_crtc_error_irq(crtc, irqstatus);
if (irqstatus & priv->dispc_ops->mgr_get_framedone_irq(priv->dispc, channel))
omap_crtc_framedone_irq(crtc, irqstatus);
}
omap_irq_ocp_error_handler(dev, irqstatus);
......
......@@ -27,6 +27,7 @@ struct drm_device;
struct omap_irq_wait;
int omap_irq_enable_vblank(struct drm_crtc *crtc);
int omap_irq_enable_framedone(struct drm_crtc *crtc, bool enable);
void omap_irq_disable_vblank(struct drm_crtc *crtc);
void omap_drm_irq_uninstall(struct drm_device *dev);
int omap_drm_irq_install(struct drm_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment