Skip to content

Commit

Permalink
Merge tag 'imx-drm-next-2016-09-19' of git://git.pengutronix.de/git/p…
Browse files Browse the repository at this point in the history
…za/linux into drm-next

imx-drm active plane reconfiguration, cleanup, FSU/IC/IRT/VDIC support

- add active plane reconfiguration support (v4),
  use the atomic_disable callback
- stop calling disable_plane manually in the plane destroy path
- let mode cleanup destroy mode objects on driver unbind
- drop deprecated load/unload drm_driver ops
- add exclusive fence to plane state, so the atomic helper can
  wait on them, remove the open-coded fence wait from imx-drm
- add low level deinterlacer (VDIC) support
- add support for channel linking via the frame synchronisation unit (FSU)
- add queued image conversion support for memory-to-memory scaling, rotation,
  and color space conversion, using IC and IRT.

* tag 'imx-drm-next-2016-09-19' of git://git.pengutronix.de/git/pza/linux:
  gpu: ipu-v3: Add queued image conversion support
  gpu: ipu-v3: Add ipu_rot_mode_is_irt()
  gpu: ipu-v3: fix a possible NULL dereference
  drm/imx: parallel-display: detach bridge or panel on unbind
  drm/imx: imx-ldb: detach bridge on unbind
  drm/imx: imx-ldb: detach panel on unbind
  gpu: ipu-v3: Add FSU channel linking support
  gpu: ipu-v3: Add Video Deinterlacer unit
  drm/imx: add exclusive fence to plane state
  drm/imx: fold ipu_plane_disable into ipu_disable_plane
  drm/imx: don't destroy mode objects manually on driver unbind
  drm/imx: drop deprecated load/unload drm_driver ops
  drm/imx: don't call disable_plane in plane destroy path
  drm/imx: Add active plane reconfiguration support
  drm/imx: Use DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET flag
  drm/imx: ipuv3-crtc: Use the callback ->atomic_disable instead of ->disable
  gpu: ipu-v3: Do not wait for DMFC FIFO to clear when disabling DMFC channel
  • Loading branch information
airlied committed Sep 19, 2016
2 parents b81a617 + cd98e85 commit 26e34d2
Show file tree
Hide file tree
Showing 16 changed files with 2,612 additions and 230 deletions.
3 changes: 0 additions & 3 deletions drivers/gpu/drm/bridge/dw-hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1813,9 +1813,6 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);

hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder->funcs->destroy(hdmi->encoder);

clk_disable_unprepare(hdmi->iahb_clk);
clk_disable_unprepare(hdmi->isfr_clk);
i2c_put_adapter(hdmi->ddc);
Expand Down
332 changes: 167 additions & 165 deletions drivers/gpu/drm/imx/imx-drm-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,6 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
}

static int imx_drm_driver_unload(struct drm_device *drm)
{
struct imx_drm_device *imxdrm = drm->dev_private;

drm_kms_helper_poll_fini(drm);

if (imxdrm->fbhelper)
drm_fbdev_cma_fini(imxdrm->fbhelper);

component_unbind_all(drm->dev, drm);

drm_vblank_cleanup(drm);
drm_mode_config_cleanup(drm);

platform_set_drvdata(drm->platformdev, NULL);

return 0;
}

static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
{
struct imx_drm_device *imxdrm = drm->dev_private;
Expand Down Expand Up @@ -146,55 +127,73 @@ static void imx_drm_output_poll_changed(struct drm_device *drm)
drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
}

static int imx_drm_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
int ret;

ret = drm_atomic_helper_check_modeset(dev, state);
if (ret)
return ret;

ret = drm_atomic_helper_check_planes(dev, state);
if (ret)
return ret;

/*
* Check modeset again in case crtc_state->mode_changed is
* updated in plane's ->atomic_check callback.
*/
ret = drm_atomic_helper_check_modeset(dev, state);
if (ret)
return ret;

return ret;
}

static int imx_drm_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state,
bool nonblock)
{
struct drm_plane_state *plane_state;
struct drm_plane *plane;
struct dma_buf *dma_buf;
int i;

/*
* If the plane fb has an dma-buf attached, fish out the exclusive
* fence for the atomic helper to wait on.
*/
for_each_plane_in_state(state, plane, plane_state, i) {
if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
0)->base.dma_buf;
if (!dma_buf)
continue;
plane_state->fence =
reservation_object_get_excl_rcu(dma_buf->resv);
}
}

return drm_atomic_helper_commit(dev, state, nonblock);
}

static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.output_poll_changed = imx_drm_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
.atomic_check = imx_drm_atomic_check,
.atomic_commit = imx_drm_atomic_commit,
};

static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
struct drm_plane_state *plane_state;
struct drm_gem_cma_object *cma_obj;
struct fence *excl;
unsigned shared_count;
struct fence **shared;
unsigned int i, j;
int ret;

/* Wait for fences. */
for_each_crtc_in_state(state, crtc, crtc_state, i) {
plane_state = crtc->primary->state;
if (plane_state->fb) {
cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0);
if (cma_obj->base.dma_buf) {
ret = reservation_object_get_fences_rcu(
cma_obj->base.dma_buf->resv, &excl,
&shared_count, &shared);
if (unlikely(ret))
DRM_ERROR("failed to get fences "
"for buffer\n");

if (excl) {
fence_wait(excl, false);
fence_put(excl);
}
for (j = 0; j < shared_count; i++) {
fence_wait(shared[j], false);
fence_put(shared[j]);
}
}
}
}

drm_atomic_helper_commit_modeset_disables(dev, state);

drm_atomic_helper_commit_planes(dev, state,
DRM_PLANE_COMMIT_ACTIVE_ONLY);
DRM_PLANE_COMMIT_ACTIVE_ONLY |
DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);

drm_atomic_helper_commit_modeset_enables(dev, state);

Expand All @@ -209,111 +208,6 @@ static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
.atomic_commit_tail = imx_drm_atomic_commit_tail,
};

/*
* Main DRM initialisation. This binds, initialises and registers
* with DRM the subcomponents of the driver.
*/
static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
{
struct imx_drm_device *imxdrm;
struct drm_connector *connector;
int ret;

imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
if (!imxdrm)
return -ENOMEM;

imxdrm->drm = drm;

drm->dev_private = imxdrm;

/*
* enable drm irq mode.
* - with irq_enabled = true, we can use the vblank feature.
*
* P.S. note that we wouldn't use drm irq handler but
* just specific driver own one instead because
* drm framework supports only one irq handler and
* drivers can well take care of their interrupts
*/
drm->irq_enabled = true;

/*
* set max width and height as default value(4096x4096).
* this value would be used to check framebuffer size limitation
* at drm_mode_addfb().
*/
drm->mode_config.min_width = 64;
drm->mode_config.min_height = 64;
drm->mode_config.max_width = 4096;
drm->mode_config.max_height = 4096;
drm->mode_config.funcs = &imx_drm_mode_config_funcs;
drm->mode_config.helper_private = &imx_drm_mode_config_helpers;

drm_mode_config_init(drm);

ret = drm_vblank_init(drm, MAX_CRTC);
if (ret)
goto err_kms;

platform_set_drvdata(drm->platformdev, drm);

/* Now try and bind all our sub-components */
ret = component_bind_all(drm->dev, drm);
if (ret)
goto err_vblank;

/*
* All components are now added, we can publish the connector sysfs
* entries to userspace. This will generate hotplug events and so
* userspace will expect to be able to access DRM at this point.
*/
list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
ret = drm_connector_register(connector);
if (ret) {
dev_err(drm->dev,
"[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
connector->base.id,
connector->name, ret);
goto err_unbind;
}
}

drm_mode_config_reset(drm);

/*
* All components are now initialised, so setup the fb helper.
* The fb helper takes copies of key hardware information, so the
* crtcs/connectors/encoders must not change after this point.
*/
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
if (legacyfb_depth != 16 && legacyfb_depth != 32) {
dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
legacyfb_depth = 16;
}
imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
drm->mode_config.num_crtc, MAX_CRTC);
if (IS_ERR(imxdrm->fbhelper)) {
ret = PTR_ERR(imxdrm->fbhelper);
imxdrm->fbhelper = NULL;
goto err_unbind;
}
#endif

drm_kms_helper_poll_init(drm);

return 0;

err_unbind:
component_unbind_all(drm->dev, drm);
err_vblank:
drm_vblank_cleanup(drm);
err_kms:
drm_mode_config_cleanup(drm);

return ret;
}

/*
* imx_drm_add_crtc - add a new crtc
*/
Expand Down Expand Up @@ -406,8 +300,6 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = {
static struct drm_driver imx_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
DRIVER_ATOMIC,
.load = imx_drm_driver_load,
.unload = imx_drm_driver_unload,
.lastclose = imx_drm_driver_lastclose,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
Expand Down Expand Up @@ -460,12 +352,122 @@ static int compare_of(struct device *dev, void *data)

static int imx_drm_bind(struct device *dev)
{
return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
struct drm_device *drm;
struct imx_drm_device *imxdrm;
int ret;

drm = drm_dev_alloc(&imx_drm_driver, dev);
if (!drm)
return -ENOMEM;

imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
if (!imxdrm) {
ret = -ENOMEM;
goto err_unref;
}

imxdrm->drm = drm;
drm->dev_private = imxdrm;

/*
* enable drm irq mode.
* - with irq_enabled = true, we can use the vblank feature.
*
* P.S. note that we wouldn't use drm irq handler but
* just specific driver own one instead because
* drm framework supports only one irq handler and
* drivers can well take care of their interrupts
*/
drm->irq_enabled = true;

/*
* set max width and height as default value(4096x4096).
* this value would be used to check framebuffer size limitation
* at drm_mode_addfb().
*/
drm->mode_config.min_width = 64;
drm->mode_config.min_height = 64;
drm->mode_config.max_width = 4096;
drm->mode_config.max_height = 4096;
drm->mode_config.funcs = &imx_drm_mode_config_funcs;
drm->mode_config.helper_private = &imx_drm_mode_config_helpers;

drm_mode_config_init(drm);

ret = drm_vblank_init(drm, MAX_CRTC);
if (ret)
goto err_kms;

dev_set_drvdata(dev, drm);

/* Now try and bind all our sub-components */
ret = component_bind_all(dev, drm);
if (ret)
goto err_vblank;

drm_mode_config_reset(drm);

/*
* All components are now initialised, so setup the fb helper.
* The fb helper takes copies of key hardware information, so the
* crtcs/connectors/encoders must not change after this point.
*/
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
if (legacyfb_depth != 16 && legacyfb_depth != 32) {
dev_warn(dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
legacyfb_depth = 16;
}
imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
drm->mode_config.num_crtc, MAX_CRTC);
if (IS_ERR(imxdrm->fbhelper)) {
ret = PTR_ERR(imxdrm->fbhelper);
imxdrm->fbhelper = NULL;
goto err_unbind;
}
#endif

drm_kms_helper_poll_init(drm);

ret = drm_dev_register(drm, 0);
if (ret)
goto err_fbhelper;

return 0;

err_fbhelper:
drm_kms_helper_poll_fini(drm);
if (imxdrm->fbhelper)
drm_fbdev_cma_fini(imxdrm->fbhelper);
err_unbind:
component_unbind_all(drm->dev, drm);
err_vblank:
drm_vblank_cleanup(drm);
err_kms:
drm_mode_config_cleanup(drm);
err_unref:
drm_dev_unref(drm);

return ret;
}

static void imx_drm_unbind(struct device *dev)
{
drm_put_dev(dev_get_drvdata(dev));
struct drm_device *drm = dev_get_drvdata(dev);
struct imx_drm_device *imxdrm = drm->dev_private;

drm_dev_unregister(drm);

drm_kms_helper_poll_fini(drm);

if (imxdrm->fbhelper)
drm_fbdev_cma_fini(imxdrm->fbhelper);

drm_mode_config_cleanup(drm);

component_unbind_all(drm->dev, drm);
dev_set_drvdata(dev, NULL);

drm_dev_unref(drm);
}

static const struct component_master_ops imx_drm_ops = {
Expand Down
Loading

0 comments on commit 26e34d2

Please sign in to comment.