Commit 284b2884 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'omapdrm-4.2-atomic' of...

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

omapdrm atomic modesetting support

Atomic modesetting support for omapdrm.

" we've had issues with omapdrm for years,
which we've not been able to fix properly (like warnings/crashes when unloading
modules, page-flips tearing, race issues with fbs). All those problems seem to
be gone after this rewrite of omapdrm for atomic modesetting, and the resulting
code is much cleaner and more maintainable."

* tag 'omapdrm-4.2-atomic' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (43 commits)
  drm: omapdrm: new vblank and event handling
  drm: omapdrm: merge omap_crtc_flush and omap_crtc_atomic_flush
  drm: omapdrm: add lock for fb pinning
  drm: omapdrm: if omap_plane_atomic_update fails, disable plane
  drm: omapdrm: inline omap_plane_setup into update/disable
  drm: omapdrm: omap_plane_setup() cannot fail, use WARN
  drm: omapdrm: Don't setup planes manually from CRTC .enable()/.disable()
  drm: omapdrm: Don't flush CRTC when enabling or disabling it
  drm: omapdrm: Move encoder setup to encoder operations
  drm: omapdrm: Simplify DSS power management
  drm: omapdrm: Remove nested PM get/sync when configuring encoders
  drm: omapdrm: Support unlinking page flip events prematurely
  drm: omapdrm: omap_crtc_flush() isn't called with modeset locked
  drm: omapdrm: Don't get/put dispc in omap_crtc_flush()
  drm: omapdrm: Make the omap_crtc_flush function static
  drm: omapdrm: Remove omap_plane enabled field
  drm: omapdrm: Remove omap_crtc enabled field
  drm: omapdrm: Move crtc info out of the crtc structure
  drm: omapdrm: Move plane info and win out of the plane structure
  drm: omapdrm: Switch crtc and plane set_property to atomic helpers
  ...
parents b9a1077a 5f741b39
......@@ -17,10 +17,11 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "omap_drv.h"
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "omap_drv.h"
/*
* connector funcs
......@@ -259,10 +260,13 @@ struct drm_encoder *omap_connector_attached_encoder(
}
static const struct drm_connector_funcs omap_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.dpms = drm_atomic_helper_connector_dpms,
.reset = drm_atomic_helper_connector_reset,
.detect = omap_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = omap_connector_destroy,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
......
This diff is collapsed.
......@@ -17,12 +17,12 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
#include "omap_drv.h"
#include "omap_dmm_tiler.h"
#include "drm_fb_helper.h"
#ifdef CONFIG_DEBUG_FS
static int gem_show(struct seq_file *m, void *arg)
......
......@@ -15,21 +15,22 @@
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h> /* platform_device() */
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/time.h>
#include <linux/list.h>
#include <linux/completion.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include "omap_dmm_tiler.h"
#include "omap_dmm_priv.h"
......
......@@ -17,11 +17,15 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "omap_drv.h"
#include <linux/wait.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include "drm_crtc_helper.h"
#include "drm_fb_helper.h"
#include "omap_dmm_tiler.h"
#include "omap_drv.h"
#define DRIVER_NAME MODULE_NAME
#define DRIVER_DESC "OMAP DRM"
......@@ -55,9 +59,153 @@ static void omap_fb_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(priv->fbdev);
}
struct omap_atomic_state_commit {
struct work_struct work;
struct drm_device *dev;
struct drm_atomic_state *state;
u32 crtcs;
};
static void omap_atomic_wait_for_completion(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
struct drm_crtc_state *old_crtc_state;
struct drm_crtc *crtc;
unsigned int i;
int ret;
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) {
if (!crtc->state->enable)
continue;
ret = omap_crtc_wait_pending(crtc);
if (!ret)
dev_warn(dev->dev,
"atomic complete timeout (pipe %u)!\n", i);
}
}
static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
{
struct drm_device *dev = commit->dev;
struct omap_drm_private *priv = dev->dev_private;
struct drm_atomic_state *old_state = commit->state;
/* Apply the atomic update. */
dispc_runtime_get();
drm_atomic_helper_commit_modeset_disables(dev, old_state);
drm_atomic_helper_commit_planes(dev, old_state);
drm_atomic_helper_commit_modeset_enables(dev, old_state);
omap_atomic_wait_for_completion(dev, old_state);
drm_atomic_helper_cleanup_planes(dev, old_state);
dispc_runtime_put();
drm_atomic_state_free(old_state);
/* Complete the commit, wake up any waiter. */
spin_lock(&priv->commit.lock);
priv->commit.pending &= ~commit->crtcs;
spin_unlock(&priv->commit.lock);
wake_up_all(&priv->commit.wait);
kfree(commit);
}
static void omap_atomic_work(struct work_struct *work)
{
struct omap_atomic_state_commit *commit =
container_of(work, struct omap_atomic_state_commit, work);
omap_atomic_complete(commit);
}
static bool omap_atomic_is_pending(struct omap_drm_private *priv,
struct omap_atomic_state_commit *commit)
{
bool pending;
spin_lock(&priv->commit.lock);
pending = priv->commit.pending & commit->crtcs;
spin_unlock(&priv->commit.lock);
return pending;
}
static int omap_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state, bool async)
{
struct omap_drm_private *priv = dev->dev_private;
struct omap_atomic_state_commit *commit;
unsigned long flags;
unsigned int i;
int ret;
ret = drm_atomic_helper_prepare_planes(dev, state);
if (ret)
return ret;
/* Allocate the commit object. */
commit = kzalloc(sizeof(*commit), GFP_KERNEL);
if (commit == NULL) {
ret = -ENOMEM;
goto error;
}
INIT_WORK(&commit->work, omap_atomic_work);
commit->dev = dev;
commit->state = state;
/* Wait until all affected CRTCs have completed previous commits and
* mark them as pending.
*/
for (i = 0; i < dev->mode_config.num_crtc; ++i) {
if (state->crtcs[i])
commit->crtcs |= 1 << drm_crtc_index(state->crtcs[i]);
}
wait_event(priv->commit.wait, !omap_atomic_is_pending(priv, commit));
spin_lock(&priv->commit.lock);
priv->commit.pending |= commit->crtcs;
spin_unlock(&priv->commit.lock);
/* Keep track of all CRTC events to unlink them in preclose(). */
spin_lock_irqsave(&dev->event_lock, flags);
for (i = 0; i < dev->mode_config.num_crtc; ++i) {
struct drm_crtc_state *cstate = state->crtc_states[i];
if (cstate && cstate->event)
list_add_tail(&cstate->event->base.link,
&priv->commit.events);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
/* Swap the state, this is the point of no return. */
drm_atomic_helper_swap_state(dev, state);
if (async)
schedule_work(&commit->work);
else
omap_atomic_complete(commit);
return 0;
error:
drm_atomic_helper_cleanup_planes(dev, state);
return ret;
}
static const struct drm_mode_config_funcs omap_mode_config_funcs = {
.fb_create = omap_framebuffer_create,
.output_poll_changed = omap_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = omap_atomic_commit,
};
static int get_connector_type(struct omap_dss_device *dssdev)
......@@ -151,6 +299,27 @@ static int omap_modeset_create_crtc(struct drm_device *dev, int id,
return 0;
}
static int omap_modeset_init_properties(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
if (priv->has_dmm) {
dev->mode_config.rotation_property =
drm_mode_create_rotation_property(dev,
BIT(DRM_ROTATE_0) | BIT(DRM_ROTATE_90) |
BIT(DRM_ROTATE_180) | BIT(DRM_ROTATE_270) |
BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
if (!dev->mode_config.rotation_property)
return -ENOMEM;
}
priv->zorder_prop = drm_property_create_range(dev, 0, "zorder", 0, 3);
if (!priv->zorder_prop)
return -ENOMEM;
return 0;
}
static int omap_modeset_init(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
......@@ -165,6 +334,10 @@ static int omap_modeset_init(struct drm_device *dev)
omap_drm_irq_install(dev);
ret = omap_modeset_init_properties(dev);
if (ret < 0)
return ret;
/*
* 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.
......@@ -325,6 +498,8 @@ static int omap_modeset_init(struct drm_device *dev)
dev->mode_config.funcs = &omap_mode_config_funcs;
drm_mode_config_reset(dev);
return 0;
}
......@@ -477,6 +652,7 @@ 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);
......@@ -490,6 +666,9 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = priv;
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
init_waitqueue_head(&priv->commit.wait);
spin_lock_init(&priv->commit.lock);
INIT_LIST_HEAD(&priv->commit.events);
spin_lock_init(&priv->list_lock);
INIT_LIST_HEAD(&priv->obj_list);
......@@ -504,10 +683,14 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
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);
if (!priv->fbdev) {
dev_warn(dev->dev, "omap_fbdev_init failed\n");
......@@ -525,7 +708,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
static int dev_unload(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
int i;
DBG("unload: dev=%p", dev);
......@@ -534,10 +716,6 @@ static int dev_unload(struct drm_device *dev)
if (priv->fbdev)
omap_fbdev_free(dev);
/* flush crtcs so the fbs get released */
for (i = 0; i < priv->num_crtcs; i++)
omap_crtc_flush(priv->crtcs[i]);
omap_modeset_free(dev);
omap_gem_deinit(dev);
......@@ -583,7 +761,7 @@ static void dev_lastclose(struct drm_device *dev)
DBG("lastclose: dev=%p", dev);
if (priv->rotation_prop) {
if (dev->mode_config.rotation_property) {
/* need to restore default rotation state.. not sure
* if there is a cleaner way to restore properties to
* default state? Maybe a flag that properties should
......@@ -592,12 +770,12 @@ static void dev_lastclose(struct drm_device *dev)
*/
for (i = 0; i < priv->num_crtcs; i++) {
drm_object_property_set_value(&priv->crtcs[i]->base,
priv->rotation_prop, 0);
dev->mode_config.rotation_property, 0);
}
for (i = 0; i < priv->num_planes; i++) {
drm_object_property_set_value(&priv->planes[i]->base,
priv->rotation_prop, 0);
dev->mode_config.rotation_property, 0);
}
}
......@@ -610,7 +788,24 @@ static void dev_lastclose(struct drm_device *dev)
static void dev_preclose(struct drm_device *dev, struct drm_file *file)
{
struct omap_drm_private *priv = dev->dev_private;
struct drm_pending_event *event;
unsigned long flags;
DBG("preclose: dev=%p", dev);
/*
* Unlink all pending CRTC events to make sure they won't be queued up
* by a pending asynchronous commit.
*/
spin_lock_irqsave(&dev->event_lock, flags);
list_for_each_entry(event, &priv->commit.events, link) {
if (event->file_priv == file) {
file->event_space += event->event->length;
event->file_priv = NULL;
}
}
spin_unlock_irqrestore(&dev->event_lock, flags);
}
static void dev_postclose(struct drm_device *dev, struct drm_file *file)
......@@ -636,8 +831,7 @@ static const struct file_operations omapdriver_fops = {
};
static struct drm_driver omap_drm_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM
| DRIVER_PRIME,
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = dev_load,
.unload = dev_unload,
.open = dev_open,
......@@ -648,10 +842,6 @@ static struct drm_driver omap_drm_driver = {
.get_vblank_counter = drm_vblank_count,
.enable_vblank = omap_irq_enable_vblank,
.disable_vblank = omap_irq_disable_vblank,
.irq_preinstall = omap_irq_preinstall,
.irq_postinstall = omap_irq_postinstall,
.irq_uninstall = omap_irq_uninstall,
.irq_handler = omap_irq_handler,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = omap_debugfs_init,
.debugfs_cleanup = omap_debugfs_cleanup,
......
......@@ -20,15 +20,16 @@
#ifndef __OMAP_DRV_H__
#define __OMAP_DRV_H__
#include <video/omapdss.h>
#include <linux/module.h>
#include <linux/platform_data/omap_drm.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <video/omapdss.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/omap_drm.h>
#include <drm/drm_gem.h>
#include <linux/platform_data/omap_drm.h>
#include <drm/omap_drm.h>
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
#define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */
......@@ -50,21 +51,6 @@ struct omap_drm_window {
uint32_t src_w, src_h;
};
/* Once GO bit is set, we can't make further updates to shadowed registers
* until the GO bit is cleared. So various parts in the kms code that need
* to update shadowed registers queue up a pair of callbacks, pre_apply
* which is called before setting GO bit, and post_apply that is called
* after GO bit is cleared. The crtc manages the queuing, and everyone
* else goes thru omap_crtc_apply() using these callbacks so that the
* code which has to deal w/ GO bit state is centralized.
*/
struct omap_drm_apply {
struct list_head pending_node, queued_node;
bool queued;
void (*pre_apply)(struct omap_drm_apply *apply);
void (*post_apply)(struct omap_drm_apply *apply);
};
/* 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
......@@ -114,13 +100,20 @@ struct omap_drm_private {
bool has_dmm;
/* properties: */
struct drm_property *rotation_prop;
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;
/* atomic commit */
struct {
struct list_head events;
wait_queue_head_t wait;
u32 pending;
spinlock_t lock; /* Protects commit.pending */
} commit;
};
......@@ -138,51 +131,31 @@ int omap_gem_resume(struct device *dev);
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(int irq, void *arg);
void omap_irq_preinstall(struct drm_device *dev);
int omap_irq_postinstall(struct drm_device *dev);
void omap_irq_uninstall(struct drm_device *dev);
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);
int omap_drm_irq_uninstall(struct drm_device *dev);
void omap_drm_irq_uninstall(struct drm_device *dev);
int omap_drm_irq_install(struct drm_device *dev);
struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev);
void omap_fbdev_free(struct drm_device *dev);
const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
int omap_crtc_apply(struct drm_crtc *crtc,
struct omap_drm_apply *apply);
void omap_crtc_pre_init(void);
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);
void omap_crtc_flush(struct drm_crtc *crtc);
int omap_crtc_wait_pending(struct drm_crtc *crtc);
struct drm_plane *omap_plane_init(struct drm_device *dev,
int id, enum drm_plane_type type);
int omap_plane_set_enable(struct drm_plane *plane, bool enable);
int omap_plane_mode_set(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
unsigned int src_x, unsigned int src_y,
unsigned int src_w, unsigned int src_h,
void (*fxn)(void *), void *arg);
void omap_plane_install_properties(struct drm_plane *plane,
struct drm_mode_object *obj);
int omap_plane_set_property(struct drm_plane *plane,
struct drm_property *property, uint64_t val);
struct drm_encoder *omap_encoder_init(struct drm_device *dev,
struct omap_dss_device *dssdev);
int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled);
int omap_encoder_update(struct drm_encoder *encoder,
struct omap_overlay_manager *mgr,
struct omap_video_timings *timings);
struct drm_connector *omap_connector_init(struct drm_device *dev,
int connector_type, struct omap_dss_device *dssdev,
......
......@@ -17,16 +17,14 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/list.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include "omap_drv.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include <linux/list.h>
/*
* encoder funcs
*/
......@@ -54,8 +52,6 @@ static void omap_encoder_destroy(struct drm_encoder *encoder)
{
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
omap_encoder_set_enabled(encoder, false);
drm_encoder_cleanup(encoder);
kfree(omap_encoder);
}
......@@ -64,29 +60,6 @@ static const struct drm_encoder_funcs omap_encoder_funcs = {
.destroy = omap_encoder_destroy,
};
/*
* The CRTC drm_crtc_helper_set_mode() doesn't really give us the right
* order.. the easiest way to work around this for now is to make all
* the encoder-helper's no-op's and have the omap_crtc code take care
* of the sequencing and call us in the right points.
*
* Eventually to handle connecting CRTCs to different encoders properly,
* either the CRTC helpers need to change or we need to replace
* drm_crtc_helper_set_mode(), but lets wait until atomic-modeset for
* that.
*/
static void omap_encoder_dpms(struct drm_encoder *encoder, int mode)
{
}
static bool omap_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void omap_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
......@@ -118,44 +91,18 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
}
}
static void omap_encoder_prepare(struct drm_encoder *encoder)
{
}
static void omap_encoder_commit(struct drm_encoder *encoder)
{
}
static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
.dpms = omap_encoder_dpms,
.mode_fixup = omap_encoder_mode_fixup,
.mode_set = omap_encoder_mode_set,
.prepare = omap_encoder_prepare,
.commit = omap_encoder_commit,
};
/*
* Instead of relying on the helpers for modeset, the omap_crtc code
* calls these functions in the proper sequence.
*/
int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled)
static void omap_encoder_disable(struct drm_encoder *encoder)
{
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
struct omap_dss_device *dssdev = omap_encoder->dssdev;
struct omap_dss_driver *dssdrv = dssdev->driver;
if (enabled) {
return dssdrv->enable(dssdev);
} else {
dssdrv->disable(dssdev);
return 0;
}
dssdrv->disable(dssdev);
}
int omap_encoder_update(struct drm_encoder *encoder,
struct omap_overlay_manager *mgr,
struct omap_video_timings *timings)
static int omap_encoder_update(struct drm_encoder *encoder,
enum omap_channel channel,
struct omap_video_timings *timings)
{
struct drm_device *dev = encoder->dev;
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
......@@ -163,7 +110,7 @@ int omap_encoder_update(struct drm_encoder *encoder,
struct omap_dss_driver *dssdrv = dssdev->driver;
int ret;
dssdev->src->manager = mgr;
dssdev->src->manager = omap_dss_get_overlay_manager(channel);
if (dssdrv->check_timings) {
ret = dssdrv->check_timings(dssdev, timings);
......@@ -189,6 +136,32 @@ int omap_encoder_update(struct drm_encoder *encoder,
return 0;
}
static void omap_encoder_enable(struct drm_encoder *encoder)
{
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
struct omap_dss_device *dssdev = omap_encoder->dssdev;
struct omap_dss_driver *dssdrv = dssdev->driver;
omap_encoder_update(encoder, omap_crtc_channel(encoder->crtc),
omap_crtc_timings(encoder->crtc));
dssdrv->enable(dssdev);
}
static int omap_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
return 0;
}
static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
.mode_set = omap_encoder_mode_set,
.disable = omap_encoder_disable,
.enable = omap_encoder_enable,
.atomic_check = omap_encoder_atomic_check,
};
/* initialize encoder */
struct drm_encoder *omap_encoder_init(struct drm_device *dev,
struct omap_dss_device *dssdev)
......
......@@ -17,11 +17,11 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "omap_drv.h"
#include "omap_dmm_tiler.h"
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "omap_dmm_tiler.h"
#include "omap_drv.h"
/*
* framebuffer funcs
......@@ -89,6 +89,8 @@ struct omap_framebuffer {
int pin_count;
const struct format *format;
struct plane planes[4];
/* lock for pinning (pin_count and planes.paddr) */
struct mutex lock;
};
static int omap_framebuffer_create_handle(struct drm_framebuffer *fb,
......@@ -250,8 +252,11 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
int ret, i, n = drm_format_num_planes(fb->pixel_format);
mutex_lock(&omap_fb->lock);
if (omap_fb->pin_count > 0) {
omap_fb->pin_count++;
mutex_unlock(&omap_fb->lock);
return 0;
}
......@@ -265,6 +270,8 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
omap_fb->pin_count++;
mutex_unlock(&omap_fb->lock);
return 0;
fail:
......@@ -274,6 +281,8 @@ int omap_framebuffer_pin(struct drm_framebuffer *fb)
plane->paddr = 0;
}
mutex_unlock(&omap_fb->lock);
return ret;
}
......@@ -283,10 +292,14 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb)
struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
int ret, i, n = drm_format_num_planes(fb->pixel_format);
mutex_lock(&omap_fb->lock);
omap_fb->pin_count--;
if (omap_fb->pin_count > 0)
if (omap_fb->pin_count > 0) {
mutex_unlock(&omap_fb->lock);
return 0;
}
for (i = 0; i < n; i++) {
struct plane *plane = &omap_fb->planes[i];
......@@ -296,9 +309,12 @@ int omap_framebuffer_unpin(struct drm_framebuffer *fb)
plane->paddr = 0;
}
mutex_unlock(&omap_fb->lock);
return 0;
fail:
mutex_unlock(&omap_fb->lock);
return ret;
}
......@@ -411,6 +427,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
fb = &omap_fb->base;
omap_fb->format = format;
mutex_init(&omap_fb->lock);
for (i = 0; i < n; i++) {
struct plane *plane = &omap_fb->planes[i];
......
......@@ -17,10 +17,10 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "omap_drv.h"
#include <drm/drm_crtc.h>
#include <drm/drm_fb_helper.h>
#include "drm_crtc.h"
#include "drm_fb_helper.h"
#include "omap_drv.h"
MODULE_PARM_DESC(ywrap, "Enable ywrap scrolling (omap44xx and later, default 'y')");
static bool ywrap_enabled = true;
......
......@@ -17,9 +17,9 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/spinlock.h>
#include <linux/shmem_fs.h>
#include <linux/spinlock.h>
#include <drm/drm_vma_manager.h>
#include "omap_drv.h"
......
......@@ -17,10 +17,10 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "omap_drv.h"
#include <linux/dma-buf.h>
#include "omap_drv.h"
static struct sg_table *omap_gem_map_dma_buf(
struct dma_buf_attachment *attachment,
enum dma_data_direction dir)
......
......@@ -152,12 +152,10 @@ int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id)
DBG("dev=%p, crtc=%d", dev, crtc_id);
dispc_runtime_get();
spin_lock_irqsave(&list_lock, flags);
priv->vblank_mask |= pipe2vbl(crtc);
omap_irq_update(dev);
spin_unlock_irqrestore(&list_lock, flags);
dispc_runtime_put();
return 0;
}
......@@ -179,15 +177,13 @@ void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id)
DBG("dev=%p, crtc=%d", dev, crtc_id);
dispc_runtime_get();
spin_lock_irqsave(&list_lock, flags);
priv->vblank_mask &= ~pipe2vbl(crtc);
omap_irq_update(dev);
spin_unlock_irqrestore(&list_lock, flags);
dispc_runtime_put();
}
irqreturn_t omap_irq_handler(int irq, void *arg)
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;
......@@ -222,23 +218,29 @@ irqreturn_t omap_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
void omap_irq_preinstall(struct drm_device *dev)
{
DBG("dev=%p", dev);
dispc_runtime_get();
dispc_clear_irqstatus(0xffffffff);
dispc_runtime_put();
}
/*
* We need a special version, instead of just using drm_irq_install(),
* because we need to register the irq via omapdss. Once omapdss and
* omapdrm are merged together we can assign the dispc hwmod data to
* ourselves and drop these and just use drm_irq_{install,uninstall}()
*/
int omap_irq_postinstall(struct drm_device *dev)
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;
DBG("dev=%p", dev);
int ret;
INIT_LIST_HEAD(&priv->irq_list);
dispc_runtime_get();
dispc_clear_irqstatus(0xffffffff);
dispc_runtime_put();
ret = dispc_request_irq(omap_irq_handler, dev);
if (ret < 0)
return ret;
error_handler->irq = omap_irq_error_handler;
error_handler->irqmask = DISPC_IRQ_OCP_ERR;
......@@ -249,76 +251,22 @@ int omap_irq_postinstall(struct drm_device *dev)
omap_irq_register(dev, error_handler);
return 0;
}
void omap_irq_uninstall(struct drm_device *dev)
{
DBG("dev=%p", dev);
// TODO prolly need to call drm_irq_uninstall() somewhere too
}
/*
* We need a special version, instead of just using drm_irq_install(),
* because we need to register the irq via omapdss. Once omapdss and
* omapdrm are merged together we can assign the dispc hwmod data to
* ourselves and drop these and just use drm_irq_{install,uninstall}()
*/
int omap_drm_irq_install(struct drm_device *dev)
{
int ret;
mutex_lock(&dev->struct_mutex);
if (dev->irq_enabled) {
mutex_unlock(&dev->struct_mutex);
return -EBUSY;
}
dev->irq_enabled = true;
mutex_unlock(&dev->struct_mutex);
/* Before installing handler */
if (dev->driver->irq_preinstall)
dev->driver->irq_preinstall(dev);
ret = dispc_request_irq(dev->driver->irq_handler, dev);
if (ret < 0) {
mutex_lock(&dev->struct_mutex);
dev->irq_enabled = false;
mutex_unlock(&dev->struct_mutex);
return ret;
}
/* After installing handler */
if (dev->driver->irq_postinstall)
ret = dev->driver->irq_postinstall(dev);
if (ret < 0) {
mutex_lock(&dev->struct_mutex);
dev->irq_enabled = false;
mutex_unlock(&dev->struct_mutex);
dispc_free_irq(dev);
}
return ret;
return 0;
}
int omap_drm_irq_uninstall(struct drm_device *dev)
void omap_drm_irq_uninstall(struct drm_device *dev)
{
unsigned long irqflags;
bool irq_enabled;
int i;
mutex_lock(&dev->struct_mutex);
irq_enabled = dev->irq_enabled;
if (!dev->irq_enabled)
return;
dev->irq_enabled = false;
mutex_unlock(&dev->struct_mutex);
/*
* Wake up any waiters so they don't hang.
*/
/* Wake up any waiters so they don't hang. */
if (dev->num_crtcs) {
spin_lock_irqsave(&dev->vbl_lock, irqflags);
for (i = 0; i < dev->num_crtcs; i++) {
......@@ -330,13 +278,5 @@ int omap_drm_irq_uninstall(struct drm_device *dev)
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
}
if (!irq_enabled)
return -EINVAL;
if (dev->driver->irq_uninstall)
dev->driver->irq_uninstall(dev);
dispc_free_irq(dev);
return 0;
}
This diff is collapsed.
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