Merge omapdrm work from Laurent
omapdrm IRQ rework, fixed vblank count and timestamp, cleanups.
This commit is contained in:
Коммит
2f1fed12c6
|
@ -595,6 +595,8 @@ static void drm_dev_release(struct kref *ref)
|
|||
{
|
||||
struct drm_device *dev = container_of(ref, struct drm_device, ref);
|
||||
|
||||
drm_vblank_cleanup(dev);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_GEM))
|
||||
drm_gem_destroy(dev);
|
||||
|
||||
|
@ -794,8 +796,6 @@ void drm_dev_unregister(struct drm_device *dev)
|
|||
if (dev->agp)
|
||||
drm_pci_agp_destroy(dev);
|
||||
|
||||
drm_vblank_cleanup(dev);
|
||||
|
||||
list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
|
||||
drm_legacy_rmmap(dev, r_list->map);
|
||||
|
||||
|
|
|
@ -1253,7 +1253,7 @@ static int dsicm_probe(struct platform_device *pdev)
|
|||
dsicm_hw_reset(ddata);
|
||||
|
||||
if (ddata->use_dsi_backlight) {
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.max_brightness = 255;
|
||||
|
||||
props.type = BACKLIGHT_RAW;
|
||||
|
|
|
@ -620,6 +620,19 @@ u32 dispc_wb_get_framedone_irq(void)
|
|||
return DISPC_IRQ_FRAMEDONEWB;
|
||||
}
|
||||
|
||||
void dispc_mgr_enable(enum omap_channel channel, bool enable)
|
||||
{
|
||||
mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
|
||||
/* flush posted write */
|
||||
mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
|
||||
}
|
||||
EXPORT_SYMBOL(dispc_mgr_enable);
|
||||
|
||||
static bool dispc_mgr_is_enabled(enum omap_channel channel)
|
||||
{
|
||||
return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
|
||||
}
|
||||
|
||||
bool dispc_mgr_go_busy(enum omap_channel channel)
|
||||
{
|
||||
return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
|
||||
|
@ -2901,20 +2914,6 @@ enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channe
|
|||
}
|
||||
EXPORT_SYMBOL(dispc_mgr_get_supported_outputs);
|
||||
|
||||
void dispc_mgr_enable(enum omap_channel channel, bool enable)
|
||||
{
|
||||
mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
|
||||
/* flush posted write */
|
||||
mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
|
||||
}
|
||||
EXPORT_SYMBOL(dispc_mgr_enable);
|
||||
|
||||
bool dispc_mgr_is_enabled(enum omap_channel channel)
|
||||
{
|
||||
return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
|
||||
}
|
||||
EXPORT_SYMBOL(dispc_mgr_is_enabled);
|
||||
|
||||
void dispc_wb_enable(bool enable)
|
||||
{
|
||||
dispc_ovl_enable(OMAP_DSS_WB, enable);
|
||||
|
|
|
@ -119,8 +119,7 @@ static void __init omapdss_omapify_node(struct device_node *node)
|
|||
|
||||
static void __init omapdss_add_to_list(struct device_node *node, bool root)
|
||||
{
|
||||
struct dss_conv_node *n = kmalloc(sizeof(struct dss_conv_node),
|
||||
GFP_KERNEL);
|
||||
struct dss_conv_node *n = kmalloc(sizeof(*n), GFP_KERNEL);
|
||||
if (n) {
|
||||
n->node = node;
|
||||
n->root = root;
|
||||
|
|
|
@ -856,7 +856,6 @@ int dispc_runtime_get(void);
|
|||
void dispc_runtime_put(void);
|
||||
|
||||
void dispc_mgr_enable(enum omap_channel channel, bool enable);
|
||||
bool dispc_mgr_is_enabled(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
|
||||
u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel);
|
||||
|
|
|
@ -162,7 +162,7 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
|
|||
|
||||
dssdrv->get_timings(dssdev, &t);
|
||||
|
||||
if (memcmp(&vm, &t, sizeof(struct videomode)))
|
||||
if (memcmp(&vm, &t, sizeof(vm)))
|
||||
r = -EINVAL;
|
||||
else
|
||||
r = 0;
|
||||
|
@ -217,7 +217,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
|
|||
|
||||
omap_dss_get_device(dssdev);
|
||||
|
||||
omap_connector = kzalloc(sizeof(struct omap_connector), GFP_KERNEL);
|
||||
omap_connector = kzalloc(sizeof(*omap_connector), GFP_KERNEL);
|
||||
if (!omap_connector)
|
||||
goto fail;
|
||||
|
||||
|
@ -240,8 +240,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
|
|||
connector->interlace_allowed = 1;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
drm_connector_register(connector);
|
||||
|
||||
return connector;
|
||||
|
||||
fail:
|
||||
|
|
|
@ -36,26 +36,18 @@ struct omap_crtc {
|
|||
|
||||
struct videomode vm;
|
||||
|
||||
struct omap_drm_irq vblank_irq;
|
||||
struct omap_drm_irq error_irq;
|
||||
|
||||
bool ignore_digit_sync_lost;
|
||||
|
||||
bool enabled;
|
||||
bool pending;
|
||||
wait_queue_head_t pending_wait;
|
||||
struct drm_pending_vblank_event *event;
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Helper Functions
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
struct videomode *omap_crtc_timings(struct drm_crtc *crtc)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
|
@ -68,6 +60,19 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
|
|||
return omap_crtc->channel;
|
||||
}
|
||||
|
||||
static bool omap_crtc_is_pending(struct drm_crtc *crtc)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
unsigned long flags;
|
||||
bool pending;
|
||||
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
pending = omap_crtc->pending;
|
||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
int omap_crtc_wait_pending(struct drm_crtc *crtc)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
|
@ -77,7 +82,7 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
|
|||
* a single frame refresh even on slower displays.
|
||||
*/
|
||||
return wait_event_timeout(omap_crtc->pending_wait,
|
||||
!omap_crtc->pending,
|
||||
!omap_crtc_is_pending(crtc),
|
||||
msecs_to_jiffies(250));
|
||||
}
|
||||
|
||||
|
@ -135,14 +140,15 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
|
|||
u32 framedone_irq, vsync_irq;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(omap_crtc->enabled == enable))
|
||||
return;
|
||||
|
||||
if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) {
|
||||
dispc_mgr_enable(channel, enable);
|
||||
omap_crtc->enabled = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispc_mgr_is_enabled(channel) == enable)
|
||||
return;
|
||||
|
||||
if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
|
||||
/*
|
||||
* Digit output produces some sync lost interrupts during the
|
||||
|
@ -173,6 +179,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
|
|||
}
|
||||
|
||||
dispc_mgr_enable(channel, enable);
|
||||
omap_crtc->enabled = enable;
|
||||
|
||||
ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
|
||||
if (ret) {
|
||||
|
@ -259,26 +266,9 @@ static const struct dss_mgr_ops mgr_ops = {
|
|||
* Setup, Flush and Page Flip
|
||||
*/
|
||||
|
||||
static void omap_crtc_complete_page_flip(struct drm_crtc *crtc)
|
||||
void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus)
|
||||
{
|
||||
struct drm_pending_vblank_event *event;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
unsigned long flags;
|
||||
|
||||
event = crtc->state->event;
|
||||
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
drm_crtc_send_vblank_event(crtc, event);
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
||||
{
|
||||
struct omap_crtc *omap_crtc =
|
||||
container_of(irq, struct omap_crtc, error_irq);
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
|
||||
if (omap_crtc->ignore_digit_sync_lost) {
|
||||
irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
|
||||
|
@ -289,29 +279,38 @@ static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
|||
DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
|
||||
}
|
||||
|
||||
static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
||||
void omap_crtc_vblank_irq(struct drm_crtc *crtc)
|
||||
{
|
||||
struct omap_crtc *omap_crtc =
|
||||
container_of(irq, struct omap_crtc, vblank_irq);
|
||||
struct drm_device *dev = omap_crtc->base.dev;
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
bool pending;
|
||||
|
||||
if (dispc_mgr_go_busy(omap_crtc->channel))
|
||||
spin_lock(&crtc->dev->event_lock);
|
||||
/*
|
||||
* If the dispc is busy we're racing the flush operation. Try again on
|
||||
* the next vblank interrupt.
|
||||
*/
|
||||
if (dispc_mgr_go_busy(omap_crtc->channel)) {
|
||||
spin_unlock(&crtc->dev->event_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
pending = omap_crtc->pending;
|
||||
omap_crtc->pending = false;
|
||||
spin_unlock(&crtc->dev->event_lock);
|
||||
|
||||
if (pending)
|
||||
drm_crtc_vblank_put(crtc);
|
||||
|
||||
/* Wake up omap_atomic_complete. */
|
||||
wake_up(&omap_crtc->pending_wait);
|
||||
|
||||
DBG("%s: apply done", omap_crtc->name);
|
||||
|
||||
__omap_irq_unregister(dev, &omap_crtc->vblank_irq);
|
||||
|
||||
rmb();
|
||||
WARN_ON(!omap_crtc->pending);
|
||||
omap_crtc->pending = false;
|
||||
wmb();
|
||||
|
||||
/* wake up userspace */
|
||||
omap_crtc_complete_page_flip(&omap_crtc->base);
|
||||
|
||||
/* wake up omap_atomic_complete */
|
||||
wake_up(&omap_crtc->pending_wait);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -324,9 +323,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
|
|||
|
||||
DBG("%s", omap_crtc->name);
|
||||
|
||||
WARN_ON(omap_crtc->vblank_irq.registered);
|
||||
omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
|
||||
kfree(omap_crtc);
|
||||
|
@ -335,17 +331,18 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
|
|||
static void omap_crtc_enable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
int ret;
|
||||
|
||||
DBG("%s", omap_crtc->name);
|
||||
|
||||
rmb();
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_vblank_on(crtc);
|
||||
ret = drm_crtc_vblank_get(crtc);
|
||||
WARN_ON(ret != 0);
|
||||
|
||||
WARN_ON(omap_crtc->pending);
|
||||
omap_crtc->pending = true;
|
||||
wmb();
|
||||
|
||||
omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
|
||||
|
||||
drm_crtc_vblank_on(crtc);
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
|
||||
static void omap_crtc_disable(struct drm_crtc *crtc)
|
||||
|
@ -390,16 +387,15 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
static void omap_crtc_atomic_begin(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
}
|
||||
|
||||
static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
struct drm_crtc_state *old_crtc_state)
|
||||
{
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
|
||||
WARN_ON(omap_crtc->vblank_irq.registered);
|
||||
int ret;
|
||||
|
||||
if (crtc->state->color_mgmt_changed) {
|
||||
struct drm_color_lut *lut = NULL;
|
||||
|
@ -414,18 +410,30 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
|
|||
dispc_mgr_set_gamma(omap_crtc->channel, lut, length);
|
||||
}
|
||||
|
||||
if (dispc_mgr_is_enabled(omap_crtc->channel)) {
|
||||
/*
|
||||
* Only flush the CRTC if it is currently enabled. CRTCs that require a
|
||||
* mode set are disabled prior plane updates and enabled afterwards.
|
||||
* They are thus not active (regardless of what their CRTC core state
|
||||
* reports) and the DRM core could thus call this function even though
|
||||
* the CRTC is currently disabled. Do nothing in that case.
|
||||
*/
|
||||
if (!omap_crtc->enabled)
|
||||
return;
|
||||
|
||||
DBG("%s: GO", omap_crtc->name);
|
||||
DBG("%s: GO", omap_crtc->name);
|
||||
|
||||
rmb();
|
||||
WARN_ON(omap_crtc->pending);
|
||||
omap_crtc->pending = true;
|
||||
wmb();
|
||||
ret = drm_crtc_vblank_get(crtc);
|
||||
WARN_ON(ret != 0);
|
||||
|
||||
dispc_mgr_go(omap_crtc->channel);
|
||||
omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
|
||||
}
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
dispc_mgr_go(omap_crtc->channel);
|
||||
|
||||
WARN_ON(omap_crtc->pending);
|
||||
omap_crtc->pending = true;
|
||||
|
||||
if (crtc->state->event)
|
||||
omap_crtc->event = crtc->state->event;
|
||||
spin_unlock_irq(&crtc->dev->event_lock);
|
||||
}
|
||||
|
||||
static bool omap_crtc_is_plane_prop(struct drm_crtc *crtc,
|
||||
|
@ -546,14 +554,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
|||
omap_crtc->channel = channel;
|
||||
omap_crtc->name = channel_names[channel];
|
||||
|
||||
omap_crtc->vblank_irq.irqmask = pipe2vbl(crtc);
|
||||
omap_crtc->vblank_irq.irq = omap_crtc_vblank_irq;
|
||||
|
||||
omap_crtc->error_irq.irqmask =
|
||||
dispc_mgr_get_sync_lost_irq(channel);
|
||||
omap_crtc->error_irq.irq = omap_crtc_error_irq;
|
||||
omap_irq_register(dev, &omap_crtc->error_irq);
|
||||
|
||||
ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
|
||||
&omap_crtc_funcs, NULL);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -224,7 +224,7 @@ static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area,
|
|||
int rows = (1 + area->y1 - area->y0);
|
||||
int i = columns*rows;
|
||||
|
||||
pat = alloc_dma(txn, sizeof(struct pat), &pat_pa);
|
||||
pat = alloc_dma(txn, sizeof(*pat), &pat_pa);
|
||||
|
||||
if (txn->last_pat)
|
||||
txn->last_pat->next_pa = (uint32_t)pat_pa;
|
||||
|
@ -735,7 +735,7 @@ static int omap_dmm_probe(struct platform_device *dev)
|
|||
|
||||
/* alloc engines */
|
||||
omap_dmm->engines = kcalloc(omap_dmm->num_engines,
|
||||
sizeof(struct refill_engine), GFP_KERNEL);
|
||||
sizeof(*omap_dmm->engines), GFP_KERNEL);
|
||||
if (!omap_dmm->engines) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
|
|
|
@ -96,7 +96,8 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
|
|||
dispc_runtime_get();
|
||||
|
||||
drm_atomic_helper_commit_modeset_disables(dev, old_state);
|
||||
drm_atomic_helper_commit_planes(dev, old_state, 0);
|
||||
drm_atomic_helper_commit_planes(dev, old_state,
|
||||
DRM_PLANE_COMMIT_ACTIVE_ONLY);
|
||||
drm_atomic_helper_commit_modeset_enables(dev, old_state);
|
||||
|
||||
omap_atomic_wait_for_completion(dev, old_state);
|
||||
|
@ -315,8 +316,6 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
|
||||
drm_mode_config_init(dev);
|
||||
|
||||
omap_drm_irq_install(dev);
|
||||
|
||||
ret = omap_modeset_init_properties(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -489,12 +488,9 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
|
||||
drm_mode_config_reset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
omap_drm_irq_install(dev);
|
||||
|
||||
static void omap_modeset_free(struct drm_device *dev)
|
||||
{
|
||||
drm_mode_config_cleanup(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -632,95 +628,6 @@ static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] =
|
|||
* drm driver funcs
|
||||
*/
|
||||
|
||||
/**
|
||||
* load - setup chip and create an initial config
|
||||
* @dev: DRM device
|
||||
* @flags: startup flags
|
||||
*
|
||||
* The driver load routine has to do several things:
|
||||
* - initialize the memory manager
|
||||
* - allocate initial config memory
|
||||
* - setup the DRM framebuffer with the allocated memory
|
||||
*/
|
||||
static int dev_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
struct omap_drm_platform_data *pdata = dev->dev->platform_data;
|
||||
struct omap_drm_private *priv;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
DBG("load: dev=%p", dev);
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->omaprev = pdata->omaprev;
|
||||
|
||||
dev->dev_private = priv;
|
||||
|
||||
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
|
||||
init_waitqueue_head(&priv->commit.wait);
|
||||
spin_lock_init(&priv->commit.lock);
|
||||
|
||||
spin_lock_init(&priv->list_lock);
|
||||
INIT_LIST_HEAD(&priv->obj_list);
|
||||
|
||||
omap_gem_init(dev);
|
||||
|
||||
ret = omap_modeset_init(dev);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret);
|
||||
dev->dev_private = NULL;
|
||||
kfree(priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize vblank handling, start with all CRTCs disabled. */
|
||||
ret = drm_vblank_init(dev, priv->num_crtcs);
|
||||
if (ret)
|
||||
dev_warn(dev->dev, "could not init vblank\n");
|
||||
|
||||
for (i = 0; i < priv->num_crtcs; i++)
|
||||
drm_crtc_vblank_off(priv->crtcs[i]);
|
||||
|
||||
priv->fbdev = omap_fbdev_init(dev);
|
||||
|
||||
/* store off drm_device for use in pm ops */
|
||||
dev_set_drvdata(dev->dev, dev);
|
||||
|
||||
drm_kms_helper_poll_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dev_unload(struct drm_device *dev)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
|
||||
DBG("unload: dev=%p", dev);
|
||||
|
||||
drm_kms_helper_poll_fini(dev);
|
||||
|
||||
if (priv->fbdev)
|
||||
omap_fbdev_free(dev);
|
||||
|
||||
omap_modeset_free(dev);
|
||||
omap_gem_deinit(dev);
|
||||
|
||||
destroy_workqueue(priv->wq);
|
||||
|
||||
drm_vblank_cleanup(dev);
|
||||
omap_drm_irq_uninstall(dev);
|
||||
|
||||
kfree(dev->dev_private);
|
||||
dev->dev_private = NULL;
|
||||
|
||||
dev_set_drvdata(dev->dev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dev_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
file->driver_priv = NULL;
|
||||
|
@ -805,8 +712,6 @@ static const struct file_operations omapdriver_fops = {
|
|||
static struct drm_driver omap_drm_driver = {
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
|
||||
DRIVER_ATOMIC,
|
||||
.load = dev_load,
|
||||
.unload = dev_unload,
|
||||
.open = dev_open,
|
||||
.lastclose = dev_lastclose,
|
||||
.get_vblank_counter = drm_vblank_no_hw_counter,
|
||||
|
@ -836,30 +741,125 @@ static struct drm_driver omap_drm_driver = {
|
|||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int pdev_probe(struct platform_device *device)
|
||||
static int pdev_probe(struct platform_device *pdev)
|
||||
{
|
||||
int r;
|
||||
struct omap_drm_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct omap_drm_private *priv;
|
||||
struct drm_device *ddev;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
DBG("%s", pdev->name);
|
||||
|
||||
if (omapdss_is_initialized() == false)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
omap_crtc_pre_init();
|
||||
|
||||
r = omap_connect_dssdevs();
|
||||
if (r) {
|
||||
omap_crtc_pre_uninit();
|
||||
return r;
|
||||
ret = omap_connect_dssdevs();
|
||||
if (ret)
|
||||
goto err_crtc_uninit;
|
||||
|
||||
/* Allocate and initialize the driver private structure. */
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
ret = -ENOMEM;
|
||||
goto err_disconnect_dssdevs;
|
||||
}
|
||||
|
||||
DBG("%s", device->name);
|
||||
return drm_platform_init(&omap_drm_driver, device);
|
||||
priv->omaprev = pdata->omaprev;
|
||||
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
|
||||
|
||||
init_waitqueue_head(&priv->commit.wait);
|
||||
spin_lock_init(&priv->commit.lock);
|
||||
spin_lock_init(&priv->list_lock);
|
||||
INIT_LIST_HEAD(&priv->obj_list);
|
||||
|
||||
/* Allocate and initialize the DRM device. */
|
||||
ddev = drm_dev_alloc(&omap_drm_driver, &pdev->dev);
|
||||
if (IS_ERR(ddev)) {
|
||||
ret = PTR_ERR(ddev);
|
||||
goto err_free_priv;
|
||||
}
|
||||
|
||||
ddev->dev_private = priv;
|
||||
platform_set_drvdata(pdev, ddev);
|
||||
|
||||
omap_gem_init(ddev);
|
||||
|
||||
ret = omap_modeset_init(ddev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "omap_modeset_init failed: ret=%d\n", ret);
|
||||
goto err_free_drm_dev;
|
||||
}
|
||||
|
||||
/* Initialize vblank handling, start with all CRTCs disabled. */
|
||||
ret = drm_vblank_init(ddev, priv->num_crtcs);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "could not init vblank\n");
|
||||
goto err_cleanup_modeset;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->num_crtcs; i++)
|
||||
drm_crtc_vblank_off(priv->crtcs[i]);
|
||||
|
||||
priv->fbdev = omap_fbdev_init(ddev);
|
||||
|
||||
drm_kms_helper_poll_init(ddev);
|
||||
|
||||
/*
|
||||
* Register the DRM device with the core and the connectors with
|
||||
* sysfs.
|
||||
*/
|
||||
ret = drm_dev_register(ddev, 0);
|
||||
if (ret)
|
||||
goto err_cleanup_helpers;
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup_helpers:
|
||||
drm_kms_helper_poll_fini(ddev);
|
||||
if (priv->fbdev)
|
||||
omap_fbdev_free(ddev);
|
||||
err_cleanup_modeset:
|
||||
drm_mode_config_cleanup(ddev);
|
||||
omap_drm_irq_uninstall(ddev);
|
||||
err_free_drm_dev:
|
||||
omap_gem_deinit(ddev);
|
||||
drm_dev_unref(ddev);
|
||||
err_free_priv:
|
||||
destroy_workqueue(priv->wq);
|
||||
kfree(priv);
|
||||
err_disconnect_dssdevs:
|
||||
omap_disconnect_dssdevs();
|
||||
err_crtc_uninit:
|
||||
omap_crtc_pre_uninit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pdev_remove(struct platform_device *device)
|
||||
static int pdev_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct drm_device *ddev = platform_get_drvdata(pdev);
|
||||
struct omap_drm_private *priv = ddev->dev_private;
|
||||
|
||||
DBG("");
|
||||
|
||||
drm_put_dev(platform_get_drvdata(device));
|
||||
drm_dev_unregister(ddev);
|
||||
|
||||
drm_kms_helper_poll_fini(ddev);
|
||||
|
||||
if (priv->fbdev)
|
||||
omap_fbdev_free(ddev);
|
||||
|
||||
drm_mode_config_cleanup(ddev);
|
||||
|
||||
omap_drm_irq_uninstall(ddev);
|
||||
omap_gem_deinit(ddev);
|
||||
|
||||
drm_dev_unref(ddev);
|
||||
|
||||
destroy_workqueue(priv->wq);
|
||||
kfree(priv);
|
||||
|
||||
omap_disconnect_dssdevs();
|
||||
omap_crtc_pre_uninit();
|
||||
|
|
|
@ -48,19 +48,6 @@ struct omap_drm_window {
|
|||
uint32_t src_w, src_h;
|
||||
};
|
||||
|
||||
/* For transiently registering for different DSS irqs that various parts
|
||||
* of the KMS code need during setup/configuration. We these are not
|
||||
* necessarily the same as what drm_vblank_get/put() are requesting, and
|
||||
* the hysteresis in drm_vblank_put() is not necessarily desirable for
|
||||
* internal housekeeping related irq usage.
|
||||
*/
|
||||
struct omap_drm_irq {
|
||||
struct list_head node;
|
||||
uint32_t irqmask;
|
||||
bool registered;
|
||||
void (*irq)(struct omap_drm_irq *irq, uint32_t irqstatus);
|
||||
};
|
||||
|
||||
/* For KMS code that needs to wait for a certain # of IRQs:
|
||||
*/
|
||||
struct omap_irq_wait;
|
||||
|
@ -101,9 +88,9 @@ struct omap_drm_private {
|
|||
struct drm_property *zorder_prop;
|
||||
|
||||
/* irq handling: */
|
||||
struct list_head irq_list; /* list of omap_drm_irq */
|
||||
uint32_t vblank_mask; /* irq bits set for userspace vblank */
|
||||
struct omap_drm_irq error_handler;
|
||||
spinlock_t wait_lock; /* protects the wait_list */
|
||||
struct list_head wait_list; /* list of omap_irq_wait */
|
||||
uint32_t irq_mask; /* enabled irqs in addition to wait_list */
|
||||
|
||||
/* atomic commit */
|
||||
struct {
|
||||
|
@ -128,10 +115,6 @@ int omap_gem_resume(struct device *dev);
|
|||
|
||||
int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe);
|
||||
void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
|
||||
void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
|
||||
void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
|
||||
void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
|
||||
void omap_drm_irq_uninstall(struct drm_device *dev);
|
||||
int omap_drm_irq_install(struct drm_device *dev);
|
||||
|
||||
|
@ -155,6 +138,8 @@ void omap_crtc_pre_uninit(void);
|
|||
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
||||
struct drm_plane *plane, enum omap_channel channel, int id);
|
||||
int omap_crtc_wait_pending(struct drm_crtc *crtc);
|
||||
void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus);
|
||||
void omap_crtc_vblank_irq(struct drm_crtc *crtc);
|
||||
|
||||
struct drm_plane *omap_plane_init(struct drm_device *dev,
|
||||
int id, enum drm_plane_type type,
|
||||
|
@ -233,32 +218,6 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
|
|||
struct dma_buf *buffer);
|
||||
|
||||
/* map crtc to vblank mask */
|
||||
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?
|
||||
*/
|
||||
|
||||
static inline int objects_lookup(
|
||||
struct drm_file *filp, uint32_t pixel_format,
|
||||
struct drm_gem_object **bos, const uint32_t *handles)
|
||||
{
|
||||
int i, n = drm_format_num_planes(pixel_format);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
bos[i] = drm_gem_object_lookup(filp, handles[i]);
|
||||
if (!bos[i])
|
||||
goto fail;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
while (--i > 0)
|
||||
drm_gem_object_unreference_unlocked(bos[i]);
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
#endif /* __OMAP_DRV_H__ */
|
||||
|
|
|
@ -117,7 +117,7 @@ static int omap_encoder_update(struct drm_encoder *encoder,
|
|||
|
||||
dssdrv->get_timings(dssdev, &t);
|
||||
|
||||
if (memcmp(vm, &t, sizeof(struct videomode)))
|
||||
if (memcmp(vm, &t, sizeof(*vm)))
|
||||
ret = -EINVAL;
|
||||
else
|
||||
ret = 0;
|
||||
|
|
|
@ -29,37 +29,30 @@
|
|||
* framebuffer funcs
|
||||
*/
|
||||
|
||||
/* per-format info: */
|
||||
struct format {
|
||||
/* DSS to DRM formats mapping */
|
||||
static const struct {
|
||||
enum omap_color_mode dss_format;
|
||||
uint32_t pixel_format;
|
||||
struct {
|
||||
int stride_bpp; /* this times width is stride */
|
||||
int sub_y; /* sub-sample in y dimension */
|
||||
} planes[4];
|
||||
bool yuv;
|
||||
};
|
||||
|
||||
static const struct format formats[] = {
|
||||
} formats[] = {
|
||||
/* 16bpp [A]RGB: */
|
||||
{ OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565, {{2, 1}}, false }, /* RGB16-565 */
|
||||
{ OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */
|
||||
{ OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */
|
||||
{ OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */
|
||||
{ OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444, {{2, 1}}, false }, /* ARGB16-4444 */
|
||||
{ OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */
|
||||
{ OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */
|
||||
{ OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565 }, /* RGB16-565 */
|
||||
{ OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444 }, /* RGB12x-4444 */
|
||||
{ OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444 }, /* xRGB12-4444 */
|
||||
{ OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444 }, /* RGBA12-4444 */
|
||||
{ OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444 }, /* ARGB16-4444 */
|
||||
{ OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555 }, /* xRGB15-1555 */
|
||||
{ OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555 }, /* ARGB16-1555 */
|
||||
/* 24bpp RGB: */
|
||||
{ OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888, {{3, 1}}, false }, /* RGB24-888 */
|
||||
{ OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888 }, /* RGB24-888 */
|
||||
/* 32bpp [A]RGB: */
|
||||
{ OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */
|
||||
{ OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */
|
||||
{ OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */
|
||||
{ OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */
|
||||
{ OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888 }, /* RGBx24-8888 */
|
||||
{ OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888 }, /* xRGB24-8888 */
|
||||
{ OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888 }, /* RGBA32-8888 */
|
||||
{ OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888 }, /* ARGB32-8888 */
|
||||
/* YUV: */
|
||||
{ OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12, {{1, 1}, {1, 2}}, true },
|
||||
{ OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV, {{2, 1}}, true },
|
||||
{ OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true },
|
||||
{ OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12 },
|
||||
{ OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV },
|
||||
{ OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY },
|
||||
};
|
||||
|
||||
/* convert from overlay's pixel formats bitmask to an array of fourcc's */
|
||||
|
@ -89,8 +82,9 @@ struct plane {
|
|||
struct omap_framebuffer {
|
||||
struct drm_framebuffer base;
|
||||
int pin_count;
|
||||
const struct format *format;
|
||||
struct plane planes[4];
|
||||
const struct drm_format_info *format;
|
||||
enum omap_color_mode dss_format;
|
||||
struct plane planes[2];
|
||||
/* lock for pinning (pin_count and planes.paddr) */
|
||||
struct mutex lock;
|
||||
};
|
||||
|
@ -128,13 +122,13 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
|
|||
};
|
||||
|
||||
static uint32_t get_linear_addr(struct plane *plane,
|
||||
const struct format *format, int n, int x, int y)
|
||||
const struct drm_format_info *format, int n, int x, int y)
|
||||
{
|
||||
uint32_t offset;
|
||||
|
||||
offset = plane->offset +
|
||||
(x * format->planes[n].stride_bpp) +
|
||||
(y * plane->pitch / format->planes[n].sub_y);
|
||||
offset = plane->offset
|
||||
+ (x * format->cpp[n] / (n == 0 ? 1 : format->hsub))
|
||||
+ (y * plane->pitch / (n == 0 ? 1 : format->vsub));
|
||||
|
||||
return plane->paddr + offset;
|
||||
}
|
||||
|
@ -153,11 +147,11 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
|
|||
struct omap_drm_window *win, struct omap_overlay_info *info)
|
||||
{
|
||||
struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
|
||||
const struct format *format = omap_fb->format;
|
||||
const struct drm_format_info *format = omap_fb->format;
|
||||
struct plane *plane = &omap_fb->planes[0];
|
||||
uint32_t x, y, orient = 0;
|
||||
|
||||
info->color_mode = format->dss_format;
|
||||
info->color_mode = omap_fb->dss_format;
|
||||
|
||||
info->pos_x = win->crtc_x;
|
||||
info->pos_y = win->crtc_y;
|
||||
|
@ -231,9 +225,9 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
|
|||
}
|
||||
|
||||
/* convert to pixels: */
|
||||
info->screen_width /= format->planes[0].stride_bpp;
|
||||
info->screen_width /= format->cpp[0];
|
||||
|
||||
if (format->dss_format == OMAP_DSS_COLOR_NV12) {
|
||||
if (omap_fb->dss_format == OMAP_DSS_COLOR_NV12) {
|
||||
plane = &omap_fb->planes[1];
|
||||
|
||||
if (info->rotation_type == OMAP_DSS_ROT_TILER) {
|
||||
|
@ -360,47 +354,58 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
|
|||
struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
|
||||
{
|
||||
unsigned int num_planes = drm_format_num_planes(mode_cmd->pixel_format);
|
||||
struct drm_gem_object *bos[4];
|
||||
struct drm_framebuffer *fb;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = objects_lookup(file, mode_cmd->pixel_format,
|
||||
bos, mode_cmd->handles);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
|
||||
if (!bos[i]) {
|
||||
fb = ERR_PTR(-ENOENT);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
fb = omap_framebuffer_init(dev, mode_cmd, bos);
|
||||
if (IS_ERR(fb)) {
|
||||
int i, n = drm_format_num_planes(mode_cmd->pixel_format);
|
||||
for (i = 0; i < n; i++)
|
||||
drm_gem_object_unreference_unlocked(bos[i]);
|
||||
return fb;
|
||||
}
|
||||
if (IS_ERR(fb))
|
||||
goto error;
|
||||
|
||||
return fb;
|
||||
|
||||
error:
|
||||
while (--i > 0)
|
||||
drm_gem_object_unreference_unlocked(bos[i]);
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
|
||||
const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
|
||||
{
|
||||
const struct drm_format_info *format = NULL;
|
||||
struct omap_framebuffer *omap_fb = NULL;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
const struct format *format = NULL;
|
||||
int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
|
||||
enum omap_color_mode dss_format = 0;
|
||||
unsigned int pitch = mode_cmd->pitches[0];
|
||||
int ret, i;
|
||||
|
||||
DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
|
||||
dev, mode_cmd, mode_cmd->width, mode_cmd->height,
|
||||
(char *)&mode_cmd->pixel_format);
|
||||
|
||||
format = drm_format_info(mode_cmd->pixel_format);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(formats); i++) {
|
||||
if (formats[i].pixel_format == mode_cmd->pixel_format) {
|
||||
format = &formats[i];
|
||||
dss_format = formats[i].dss_format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!format) {
|
||||
dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
|
||||
(char *)&mode_cmd->pixel_format);
|
||||
if (!format || !dss_format) {
|
||||
dev_dbg(dev->dev, "unsupported pixel format: %4.4s\n",
|
||||
(char *)&mode_cmd->pixel_format);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
@ -413,40 +418,39 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
|
|||
|
||||
fb = &omap_fb->base;
|
||||
omap_fb->format = format;
|
||||
omap_fb->dss_format = dss_format;
|
||||
mutex_init(&omap_fb->lock);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
/*
|
||||
* The code below assumes that no format use more than two planes, and
|
||||
* that the two planes of multiplane formats need the same number of
|
||||
* bytes per pixel.
|
||||
*/
|
||||
if (format->num_planes == 2 && pitch != mode_cmd->pitches[1]) {
|
||||
dev_dbg(dev->dev, "pitches differ between planes 0 and 1\n");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pitch % format->cpp[0]) {
|
||||
dev_dbg(dev->dev,
|
||||
"buffer pitch (%u bytes) is not a multiple of pixel size (%u bytes)\n",
|
||||
pitch, format->cpp[0]);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < format->num_planes; i++) {
|
||||
struct plane *plane = &omap_fb->planes[i];
|
||||
int size, pitch = mode_cmd->pitches[i];
|
||||
unsigned int vsub = i == 0 ? 1 : format->vsub;
|
||||
unsigned int size;
|
||||
|
||||
if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) {
|
||||
dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n",
|
||||
pitch, mode_cmd->width * format->planes[i].stride_bpp);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
size = pitch * mode_cmd->height / vsub;
|
||||
|
||||
if (pitch % format->planes[i].stride_bpp != 0) {
|
||||
dev_err(dev->dev,
|
||||
"buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n",
|
||||
pitch, format->planes[i].stride_bpp);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size = pitch * mode_cmd->height / format->planes[i].sub_y;
|
||||
|
||||
if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
|
||||
dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
|
||||
bos[i]->size - mode_cmd->offsets[i], size);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (i > 0 && pitch != mode_cmd->pitches[i - 1]) {
|
||||
dev_err(dev->dev,
|
||||
"pitches are not the same between framebuffer planes %d != %d\n",
|
||||
pitch, mode_cmd->pitches[i - 1]);
|
||||
if (size > omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i]) {
|
||||
dev_dbg(dev->dev,
|
||||
"provided buffer object is too small! %d < %d\n",
|
||||
bos[i]->size - mode_cmd->offsets[i], size);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -19,25 +19,24 @@
|
|||
|
||||
#include "omap_drv.h"
|
||||
|
||||
static DEFINE_SPINLOCK(list_lock);
|
||||
struct omap_irq_wait {
|
||||
struct list_head node;
|
||||
wait_queue_head_t wq;
|
||||
uint32_t irqmask;
|
||||
int count;
|
||||
};
|
||||
|
||||
static void omap_irq_error_handler(struct omap_drm_irq *irq,
|
||||
uint32_t irqstatus)
|
||||
{
|
||||
DRM_ERROR("errors: %08x\n", irqstatus);
|
||||
}
|
||||
|
||||
/* call with list_lock and dispc runtime held */
|
||||
/* call with wait_lock and dispc runtime held */
|
||||
static void omap_irq_update(struct drm_device *dev)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
struct omap_drm_irq *irq;
|
||||
uint32_t irqmask = priv->vblank_mask;
|
||||
struct omap_irq_wait *wait;
|
||||
uint32_t irqmask = priv->irq_mask;
|
||||
|
||||
assert_spin_locked(&list_lock);
|
||||
assert_spin_locked(&priv->wait_lock);
|
||||
|
||||
list_for_each_entry(irq, &priv->irq_list, node)
|
||||
irqmask |= irq->irqmask;
|
||||
list_for_each_entry(wait, &priv->wait_list, node)
|
||||
irqmask |= wait->irqmask;
|
||||
|
||||
DBG("irqmask=%08x", irqmask);
|
||||
|
||||
|
@ -45,90 +44,48 @@ static void omap_irq_update(struct drm_device *dev)
|
|||
dispc_read_irqenable(); /* flush posted write */
|
||||
}
|
||||
|
||||
void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
|
||||
static void omap_irq_wait_handler(struct omap_irq_wait *wait)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&list_lock, flags);
|
||||
|
||||
if (!WARN_ON(irq->registered)) {
|
||||
irq->registered = true;
|
||||
list_add(&irq->node, &priv->irq_list);
|
||||
omap_irq_update(dev);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&list_lock, flags);
|
||||
}
|
||||
|
||||
void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
|
||||
{
|
||||
dispc_runtime_get();
|
||||
|
||||
__omap_irq_register(dev, irq);
|
||||
|
||||
dispc_runtime_put();
|
||||
}
|
||||
|
||||
void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&list_lock, flags);
|
||||
|
||||
if (!WARN_ON(!irq->registered)) {
|
||||
irq->registered = false;
|
||||
list_del(&irq->node);
|
||||
omap_irq_update(dev);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&list_lock, flags);
|
||||
}
|
||||
|
||||
void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
|
||||
{
|
||||
dispc_runtime_get();
|
||||
|
||||
__omap_irq_unregister(dev, irq);
|
||||
|
||||
dispc_runtime_put();
|
||||
}
|
||||
|
||||
struct omap_irq_wait {
|
||||
struct omap_drm_irq irq;
|
||||
int count;
|
||||
};
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(wait_event);
|
||||
|
||||
static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
||||
{
|
||||
struct omap_irq_wait *wait =
|
||||
container_of(irq, struct omap_irq_wait, irq);
|
||||
wait->count--;
|
||||
wake_up_all(&wait_event);
|
||||
wake_up(&wait->wq);
|
||||
}
|
||||
|
||||
struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev,
|
||||
uint32_t irqmask, int count)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL);
|
||||
wait->irq.irq = wait_irq;
|
||||
wait->irq.irqmask = irqmask;
|
||||
unsigned long flags;
|
||||
|
||||
init_waitqueue_head(&wait->wq);
|
||||
wait->irqmask = irqmask;
|
||||
wait->count = count;
|
||||
omap_irq_register(dev, &wait->irq);
|
||||
|
||||
spin_lock_irqsave(&priv->wait_lock, flags);
|
||||
list_add(&wait->node, &priv->wait_list);
|
||||
omap_irq_update(dev);
|
||||
spin_unlock_irqrestore(&priv->wait_lock, flags);
|
||||
|
||||
return wait;
|
||||
}
|
||||
|
||||
int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
|
||||
unsigned long timeout)
|
||||
{
|
||||
int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout);
|
||||
omap_irq_unregister(dev, &wait->irq);
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = wait_event_timeout(wait->wq, (wait->count <= 0), timeout);
|
||||
|
||||
spin_lock_irqsave(&priv->wait_lock, flags);
|
||||
list_del(&wait->node);
|
||||
omap_irq_update(dev);
|
||||
spin_unlock_irqrestore(&priv->wait_lock, flags);
|
||||
|
||||
kfree(wait);
|
||||
if (ret == 0)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
return ret == 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,10 +109,10 @@ int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||
|
||||
DBG("dev=%p, crtc=%u", dev, pipe);
|
||||
|
||||
spin_lock_irqsave(&list_lock, flags);
|
||||
priv->vblank_mask |= pipe2vbl(crtc);
|
||||
spin_lock_irqsave(&priv->wait_lock, flags);
|
||||
priv->irq_mask |= dispc_mgr_get_vsync_irq(omap_crtc_channel(crtc));
|
||||
omap_irq_update(dev);
|
||||
spin_unlock_irqrestore(&list_lock, flags);
|
||||
spin_unlock_irqrestore(&priv->wait_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -177,17 +134,66 @@ void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe)
|
|||
|
||||
DBG("dev=%p, crtc=%u", dev, pipe);
|
||||
|
||||
spin_lock_irqsave(&list_lock, flags);
|
||||
priv->vblank_mask &= ~pipe2vbl(crtc);
|
||||
spin_lock_irqsave(&priv->wait_lock, flags);
|
||||
priv->irq_mask &= ~dispc_mgr_get_vsync_irq(omap_crtc_channel(crtc));
|
||||
omap_irq_update(dev);
|
||||
spin_unlock_irqrestore(&list_lock, flags);
|
||||
spin_unlock_irqrestore(&priv->wait_lock, flags);
|
||||
}
|
||||
|
||||
static void omap_irq_fifo_underflow(struct omap_drm_private *priv,
|
||||
u32 irqstatus)
|
||||
{
|
||||
static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
|
||||
DEFAULT_RATELIMIT_BURST);
|
||||
static const struct {
|
||||
const char *name;
|
||||
u32 mask;
|
||||
} sources[] = {
|
||||
{ "gfx", DISPC_IRQ_GFX_FIFO_UNDERFLOW },
|
||||
{ "vid1", DISPC_IRQ_VID1_FIFO_UNDERFLOW },
|
||||
{ "vid2", DISPC_IRQ_VID2_FIFO_UNDERFLOW },
|
||||
{ "vid3", DISPC_IRQ_VID3_FIFO_UNDERFLOW },
|
||||
};
|
||||
|
||||
const u32 mask = DISPC_IRQ_GFX_FIFO_UNDERFLOW
|
||||
| DISPC_IRQ_VID1_FIFO_UNDERFLOW
|
||||
| DISPC_IRQ_VID2_FIFO_UNDERFLOW
|
||||
| DISPC_IRQ_VID3_FIFO_UNDERFLOW;
|
||||
unsigned int i;
|
||||
|
||||
spin_lock(&priv->wait_lock);
|
||||
irqstatus &= priv->irq_mask & mask;
|
||||
spin_unlock(&priv->wait_lock);
|
||||
|
||||
if (!irqstatus)
|
||||
return;
|
||||
|
||||
if (!__ratelimit(&_rs))
|
||||
return;
|
||||
|
||||
DRM_ERROR("FIFO underflow on ");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sources); ++i) {
|
||||
if (sources[i].mask & irqstatus)
|
||||
pr_cont("%s ", sources[i].name);
|
||||
}
|
||||
|
||||
pr_cont("(0x%08x)\n", irqstatus);
|
||||
}
|
||||
|
||||
static void omap_irq_ocp_error_handler(u32 irqstatus)
|
||||
{
|
||||
if (!(irqstatus & DISPC_IRQ_OCP_ERR))
|
||||
return;
|
||||
|
||||
DRM_ERROR("OCP error\n");
|
||||
}
|
||||
|
||||
static irqreturn_t omap_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
struct omap_drm_irq *handler, *n;
|
||||
struct omap_irq_wait *wait, *n;
|
||||
unsigned long flags;
|
||||
unsigned int id;
|
||||
u32 irqstatus;
|
||||
|
@ -200,24 +206,37 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
|
|||
|
||||
for (id = 0; id < priv->num_crtcs; id++) {
|
||||
struct drm_crtc *crtc = priv->crtcs[id];
|
||||
enum omap_channel channel = omap_crtc_channel(crtc);
|
||||
|
||||
if (irqstatus & pipe2vbl(crtc))
|
||||
if (irqstatus & dispc_mgr_get_vsync_irq(channel)) {
|
||||
drm_handle_vblank(dev, id);
|
||||
omap_crtc_vblank_irq(crtc);
|
||||
}
|
||||
|
||||
if (irqstatus & dispc_mgr_get_sync_lost_irq(channel))
|
||||
omap_crtc_error_irq(crtc, irqstatus);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&list_lock, flags);
|
||||
list_for_each_entry_safe(handler, n, &priv->irq_list, node) {
|
||||
if (handler->irqmask & irqstatus) {
|
||||
spin_unlock_irqrestore(&list_lock, flags);
|
||||
handler->irq(handler, handler->irqmask & irqstatus);
|
||||
spin_lock_irqsave(&list_lock, flags);
|
||||
}
|
||||
omap_irq_ocp_error_handler(irqstatus);
|
||||
omap_irq_fifo_underflow(priv, irqstatus);
|
||||
|
||||
spin_lock_irqsave(&priv->wait_lock, flags);
|
||||
list_for_each_entry_safe(wait, n, &priv->wait_list, node) {
|
||||
if (wait->irqmask & irqstatus)
|
||||
omap_irq_wait_handler(wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&list_lock, flags);
|
||||
spin_unlock_irqrestore(&priv->wait_lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const u32 omap_underflow_irqs[] = {
|
||||
[OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
|
||||
[OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
|
||||
[OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
|
||||
[OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
|
||||
};
|
||||
|
||||
/*
|
||||
* We need a special version, instead of just using drm_irq_install(),
|
||||
* because we need to register the irq via omapdss. Once omapdss and
|
||||
|
@ -228,10 +247,25 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
|
|||
int omap_drm_irq_install(struct drm_device *dev)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
struct omap_drm_irq *error_handler = &priv->error_handler;
|
||||
unsigned int num_mgrs = dss_feat_get_num_mgrs();
|
||||
unsigned int max_planes;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
INIT_LIST_HEAD(&priv->irq_list);
|
||||
spin_lock_init(&priv->wait_lock);
|
||||
INIT_LIST_HEAD(&priv->wait_list);
|
||||
|
||||
priv->irq_mask = DISPC_IRQ_OCP_ERR;
|
||||
|
||||
max_planes = min(ARRAY_SIZE(priv->planes),
|
||||
ARRAY_SIZE(omap_underflow_irqs));
|
||||
for (i = 0; i < max_planes; ++i) {
|
||||
if (priv->planes[i])
|
||||
priv->irq_mask |= omap_underflow_irqs[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < num_mgrs; ++i)
|
||||
priv->irq_mask |= dispc_mgr_get_sync_lost_irq(i);
|
||||
|
||||
dispc_runtime_get();
|
||||
dispc_clear_irqstatus(0xffffffff);
|
||||
|
@ -241,16 +275,6 @@ int omap_drm_irq_install(struct drm_device *dev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
error_handler->irq = omap_irq_error_handler;
|
||||
error_handler->irqmask = DISPC_IRQ_OCP_ERR;
|
||||
|
||||
/* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think
|
||||
* we just need to ignore it while enabling tv-out
|
||||
*/
|
||||
error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
|
||||
|
||||
omap_irq_register(dev, error_handler);
|
||||
|
||||
dev->irq_enabled = true;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -43,8 +43,6 @@ struct omap_plane {
|
|||
|
||||
uint32_t nformats;
|
||||
uint32_t formats[32];
|
||||
|
||||
struct omap_drm_irq error_irq;
|
||||
};
|
||||
|
||||
struct omap_plane_state {
|
||||
|
@ -204,8 +202,6 @@ static void omap_plane_destroy(struct drm_plane *plane)
|
|||
|
||||
DBG("%s", omap_plane->name);
|
||||
|
||||
omap_irq_unregister(plane->dev, &omap_plane->error_irq);
|
||||
|
||||
drm_plane_cleanup(plane);
|
||||
|
||||
kfree(omap_plane);
|
||||
|
@ -332,14 +328,6 @@ static const struct drm_plane_funcs omap_plane_funcs = {
|
|||
.atomic_get_property = omap_plane_atomic_get_property,
|
||||
};
|
||||
|
||||
static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
|
||||
{
|
||||
struct omap_plane *omap_plane =
|
||||
container_of(irq, struct omap_plane, error_irq);
|
||||
DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
|
||||
irqstatus);
|
||||
}
|
||||
|
||||
static const char *plane_names[] = {
|
||||
[OMAP_DSS_GFX] = "gfx",
|
||||
[OMAP_DSS_VIDEO1] = "vid1",
|
||||
|
@ -347,13 +335,6 @@ static const char *plane_names[] = {
|
|||
[OMAP_DSS_VIDEO3] = "vid3",
|
||||
};
|
||||
|
||||
static const uint32_t error_irqs[] = {
|
||||
[OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
|
||||
[OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
|
||||
[OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
|
||||
[OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
|
||||
};
|
||||
|
||||
/* initialize plane */
|
||||
struct drm_plane *omap_plane_init(struct drm_device *dev,
|
||||
int id, enum drm_plane_type type,
|
||||
|
@ -377,10 +358,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
|
|||
|
||||
plane = &omap_plane->base;
|
||||
|
||||
omap_plane->error_irq.irqmask = error_irqs[id];
|
||||
omap_plane->error_irq.irq = omap_plane_error_irq;
|
||||
omap_irq_register(dev, &omap_plane->error_irq);
|
||||
|
||||
ret = drm_universal_plane_init(dev, plane, possible_crtcs,
|
||||
&omap_plane_funcs, omap_plane->formats,
|
||||
omap_plane->nformats, type, NULL);
|
||||
|
@ -394,7 +371,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
|
|||
return plane;
|
||||
|
||||
error:
|
||||
omap_irq_unregister(plane->dev, &omap_plane->error_irq);
|
||||
kfree(omap_plane);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ header-y += i810_drm.h
|
|||
header-y += i915_drm.h
|
||||
header-y += mga_drm.h
|
||||
header-y += nouveau_drm.h
|
||||
header-y += omap_drm.h
|
||||
header-y += qxl_drm.h
|
||||
header-y += r128_drm.h
|
||||
header-y += radeon_drm.h
|
||||
|
|
Загрузка…
Ссылка в новой задаче