diff options
author | Dave Airlie | 2016-09-20 06:24:26 +1000 |
---|---|---|
committer | Dave Airlie | 2016-09-20 06:24:26 +1000 |
commit | 26e34d2d8ba7aca0fe86e5362ce5811749df77b2 (patch) | |
tree | 51fba9f283f18d86de24bf5a21d150c57c14121d /drivers/gpu/ipu-v3/ipu-common.c | |
parent | b81a6179b6035a77d9d56d08ba1c0f81d6d4c2c5 (diff) | |
parent | cd98e85a6b786da83e0b120b53a182d100c19c9b (diff) |
Merge tag 'imx-drm-next-2016-09-19' of git://git.pengutronix.de/git/pza/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
Diffstat (limited to 'drivers/gpu/ipu-v3/ipu-common.c')
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 157 |
1 files changed, 154 insertions, 3 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index d230988ddb8f..b9539f7c5e9a 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -730,6 +730,137 @@ void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi) } EXPORT_SYMBOL_GPL(ipu_set_ic_src_mux); + +/* Frame Synchronization Unit Channel Linking */ + +struct fsu_link_reg_info { + int chno; + u32 reg; + u32 mask; + u32 val; +}; + +struct fsu_link_info { + struct fsu_link_reg_info src; + struct fsu_link_reg_info sink; +}; + +static const struct fsu_link_info fsu_link_info[] = { + { + .src = { IPUV3_CHANNEL_IC_PRP_ENC_MEM, IPU_FS_PROC_FLOW2, + FS_PRP_ENC_DEST_SEL_MASK, FS_PRP_ENC_DEST_SEL_IRT_ENC }, + .sink = { IPUV3_CHANNEL_MEM_ROT_ENC, IPU_FS_PROC_FLOW1, + FS_PRPENC_ROT_SRC_SEL_MASK, FS_PRPENC_ROT_SRC_SEL_ENC }, + }, { + .src = { IPUV3_CHANNEL_IC_PRP_VF_MEM, IPU_FS_PROC_FLOW2, + FS_PRPVF_DEST_SEL_MASK, FS_PRPVF_DEST_SEL_IRT_VF }, + .sink = { IPUV3_CHANNEL_MEM_ROT_VF, IPU_FS_PROC_FLOW1, + FS_PRPVF_ROT_SRC_SEL_MASK, FS_PRPVF_ROT_SRC_SEL_VF }, + }, { + .src = { IPUV3_CHANNEL_IC_PP_MEM, IPU_FS_PROC_FLOW2, + FS_PP_DEST_SEL_MASK, FS_PP_DEST_SEL_IRT_PP }, + .sink = { IPUV3_CHANNEL_MEM_ROT_PP, IPU_FS_PROC_FLOW1, + FS_PP_ROT_SRC_SEL_MASK, FS_PP_ROT_SRC_SEL_PP }, + }, { + .src = { IPUV3_CHANNEL_CSI_DIRECT, 0 }, + .sink = { IPUV3_CHANNEL_CSI_VDI_PREV, IPU_FS_PROC_FLOW1, + FS_VDI_SRC_SEL_MASK, FS_VDI_SRC_SEL_CSI_DIRECT }, + }, +}; + +static const struct fsu_link_info *find_fsu_link_info(int src, int sink) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fsu_link_info); i++) { + if (src == fsu_link_info[i].src.chno && + sink == fsu_link_info[i].sink.chno) + return &fsu_link_info[i]; + } + + return NULL; +} + +/* + * Links a source channel to a sink channel in the FSU. + */ +int ipu_fsu_link(struct ipu_soc *ipu, int src_ch, int sink_ch) +{ + const struct fsu_link_info *link; + u32 src_reg, sink_reg; + unsigned long flags; + + link = find_fsu_link_info(src_ch, sink_ch); + if (!link) + return -EINVAL; + + spin_lock_irqsave(&ipu->lock, flags); + + if (link->src.mask) { + src_reg = ipu_cm_read(ipu, link->src.reg); + src_reg &= ~link->src.mask; + src_reg |= link->src.val; + ipu_cm_write(ipu, src_reg, link->src.reg); + } + + if (link->sink.mask) { + sink_reg = ipu_cm_read(ipu, link->sink.reg); + sink_reg &= ~link->sink.mask; + sink_reg |= link->sink.val; + ipu_cm_write(ipu, sink_reg, link->sink.reg); + } + + spin_unlock_irqrestore(&ipu->lock, flags); + return 0; +} +EXPORT_SYMBOL_GPL(ipu_fsu_link); + +/* + * Unlinks source and sink channels in the FSU. + */ +int ipu_fsu_unlink(struct ipu_soc *ipu, int src_ch, int sink_ch) +{ + const struct fsu_link_info *link; + u32 src_reg, sink_reg; + unsigned long flags; + + link = find_fsu_link_info(src_ch, sink_ch); + if (!link) + return -EINVAL; + + spin_lock_irqsave(&ipu->lock, flags); + + if (link->src.mask) { + src_reg = ipu_cm_read(ipu, link->src.reg); + src_reg &= ~link->src.mask; + ipu_cm_write(ipu, src_reg, link->src.reg); + } + + if (link->sink.mask) { + sink_reg = ipu_cm_read(ipu, link->sink.reg); + sink_reg &= ~link->sink.mask; + ipu_cm_write(ipu, sink_reg, link->sink.reg); + } + + spin_unlock_irqrestore(&ipu->lock, flags); + return 0; +} +EXPORT_SYMBOL_GPL(ipu_fsu_unlink); + +/* Link IDMAC channels in the FSU */ +int ipu_idmac_link(struct ipuv3_channel *src, struct ipuv3_channel *sink) +{ + return ipu_fsu_link(src->ipu, src->num, sink->num); +} +EXPORT_SYMBOL_GPL(ipu_idmac_link); + +/* Unlink IDMAC channels in the FSU */ +int ipu_idmac_unlink(struct ipuv3_channel *src, struct ipuv3_channel *sink) +{ + return ipu_fsu_unlink(src->ipu, src->num, sink->num); +} +EXPORT_SYMBOL_GPL(ipu_idmac_unlink); + struct ipu_devtype { const char *name; unsigned long cm_ofs; @@ -839,6 +970,20 @@ static int ipu_submodules_init(struct ipu_soc *ipu, goto err_ic; } + ret = ipu_vdi_init(ipu, dev, ipu_base + devtype->vdi_ofs, + IPU_CONF_VDI_EN | IPU_CONF_ISP_EN | + IPU_CONF_IC_INPUT); + if (ret) { + unit = "vdi"; + goto err_vdi; + } + + ret = ipu_image_convert_init(ipu, dev); + if (ret) { + unit = "image_convert"; + goto err_image_convert; + } + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, IPU_CONF_DI0_EN, ipu_clk); if (ret) { @@ -893,6 +1038,10 @@ err_dc: err_di_1: ipu_di_exit(ipu, 0); err_di_0: + ipu_image_convert_exit(ipu); +err_image_convert: + ipu_vdi_exit(ipu); +err_vdi: ipu_ic_exit(ipu); err_ic: ipu_csi_exit(ipu, 1); @@ -977,6 +1126,8 @@ static void ipu_submodules_exit(struct ipu_soc *ipu) ipu_dc_exit(ipu); ipu_di_exit(ipu, 1); ipu_di_exit(ipu, 0); + ipu_image_convert_exit(ipu); + ipu_vdi_exit(ipu); ipu_ic_exit(ipu); ipu_csi_exit(ipu, 1); ipu_csi_exit(ipu, 0); @@ -1213,8 +1364,6 @@ EXPORT_SYMBOL_GPL(ipu_dump); static int ipu_probe(struct platform_device *pdev) { - const struct of_device_id *of_id = - of_match_device(imx_ipu_dt_ids, &pdev->dev); struct device_node *np = pdev->dev.of_node; struct ipu_soc *ipu; struct resource *res; @@ -1222,7 +1371,9 @@ static int ipu_probe(struct platform_device *pdev) int i, ret, irq_sync, irq_err; const struct ipu_devtype *devtype; - devtype = of_id->data; + devtype = of_device_get_match_data(&pdev->dev); + if (!devtype) + return -EINVAL; irq_sync = platform_get_irq(pdev, 0); irq_err = platform_get_irq(pdev, 1); |