Commit 33d5f513 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'imx-drm-next-2017-03-17' of git://git.pengutronix.de/git/pza/linux into drm-next

imx-drm PRE/PRG support, deferred plane disabling, separate alpha support

- Initial support for the Prefetch Resolve Engine/Gasket on i.MX6QP,
  improving linear scanout buffer memory bandwidth utilization. This
  will in the future grow reordering support and allow direct scanout
  of Vivante tiled renderbuffers from the GPU.
- Deferred plane disabling gets rid of some busy waiting in the atomic
  plane disable and crtc disable paths that lead to wait_for_vblank
  timeouts.
- Add support for RGBA formats with a separate alpha plane, that can
  reduce memory bandwidth utilization for mostly transparent overlay
  planes by skipping color reads for completely transparent regions.
- Allow moving an active overlay plane without enforcing a modeset.
- Add 8-bit and 16-bit bayer formats to ipu_cpmem_set_image.
- Set the base address in ipu_cpmem_set_image even for invalid formats
  to increase robustness against errors.
- Use drm_plane_helper_check_state in plane atomic_check.
- Some cleanup.

* tag 'imx-drm-next-2017-03-17' of git://git.pengutronix.de/git/pza/linux: (22 commits)
  drm/imx: Remove unneeded definition for structure imx_drm_component
  drm/imx: use PRG/PRE when possible
  drm/imx: enable/disable PRG on CRTC enable/disable
  gpu: ipu-v3: only set non-zero AXI ID for IC when PRG is absent
  gpu: ipu-v3: hook up PRG unit
  gpu: ipu-v3: document valid IPUv3 compatibles and extend for i.MX6 QuadPlus
  gpu: ipu-v3: add driver for Prefetch Resolve Gasket
  gpu: ipu-v3: add DT binding for the Prefetch Resolve Gasket
  gpu: ipu-v3: add driver for Prefetch Resolve Engine
  gpu: ipu-v3: add DT binding for the Prefetch Resolve Engine
  drm/imx: ipuv3-plane: add support for separate alpha planes
  drm/imx: extend drm_plane_state_to_eba for separate channel support
  gpu: ipu-v3: add support for separate alpha channels
  drm: add RGB formats with separate alpha plane
  drm/imx: add deferred plane disabling
  drm/imx: don't wait for vblank and stop calling cleanup_planes in commit_tail
  gpu: ipu-v3: add unsynchronised DP channel disabling
  gpu: ipu-v3: remove IRQ dance on DC channel disable
  gpu: ipu-cpmem: add bayer formats to ipu_cpmem_set_image
  gpu: ipu-cpmem: set image base address even for incorrect formats
  ...
parents b7d6c8db 7d5ed292
......@@ -21,13 +21,19 @@ Freescale i.MX IPUv3
====================
Required properties:
- compatible: Should be "fsl,<chip>-ipu"
- compatible: Should be "fsl,<chip>-ipu" where <chip> is one of
- imx51
- imx53
- imx6q
- imx6qp
- reg: should be register base and length as documented in the
datasheet
- interrupts: Should contain sync interrupt and error interrupt,
in this order.
- resets: phandle pointing to the system reset controller and
reset line index, see reset/fsl,imx-src.txt for details
Additional required properties for fsl,imx6qp-ipu:
- fsl,prg: phandle to prg node associated with this IPU instance
Optional properties:
- port@[0-3]: Port nodes with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt.
......@@ -53,6 +59,57 @@ ipu: ipu@18000000 {
};
};
Freescale i.MX PRE (Prefetch Resolve Engine)
============================================
Required properties:
- compatible: should be "fsl,imx6qp-pre"
- reg: should be register base and length as documented in the
datasheet
- clocks : phandle to the PRE axi clock input, as described
in Documentation/devicetree/bindings/clock/clock-bindings.txt and
Documentation/devicetree/bindings/clock/imx6q-clock.txt.
- clock-names: should be "axi"
- interrupts: should contain the PRE interrupt
- fsl,iram: phandle pointing to the mmio-sram device node, that should be
used for the PRE SRAM double buffer.
example:
pre@21c8000 {
compatible = "fsl,imx6qp-pre";
reg = <0x021c8000 0x1000>;
interrupts = <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>;
clocks = <&clks IMX6QDL_CLK_PRE0>;
clock-names = "axi";
fsl,iram = <&ocram2>;
};
Freescale i.MX PRG (Prefetch Resolve Gasket)
============================================
Required properties:
- compatible: should be "fsl,imx6qp-prg"
- reg: should be register base and length as documented in the
datasheet
- clocks : phandles to the PRG ipg and axi clock inputs, as described
in Documentation/devicetree/bindings/clock/clock-bindings.txt and
Documentation/devicetree/bindings/clock/imx6q-clock.txt.
- clock-names: should be "ipg" and "axi"
- fsl,pres: phandles to the PRE units attached to this PRG, with the fixed
PRE as the first entry and the muxable PREs following.
example:
prg@21cc000 {
compatible = "fsl,imx6qp-prg";
reg = <0x021cc000 0x1000>;
clocks = <&clks IMX6QDL_CLK_PRG0_APB>,
<&clks IMX6QDL_CLK_PRG0_AXI>;
clock-names = "ipg", "axi";
fsl,pres = <&pre1>, <&pre2>, <&pre3>;
};
Parallel display support
========================
......
......@@ -132,6 +132,8 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_XBGR8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_RGBX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_BGRX8888, .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_RGB565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_BGR565_A8, .depth = 24, .num_planes = 2, .cpp = { 2, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_XRGB2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_XBGR2101010, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_RGBX1010102, .depth = 30, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
......@@ -144,6 +146,12 @@ const struct drm_format_info *__drm_format_info(u32 format)
{ .format = DRM_FORMAT_ABGR8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_RGBA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_BGRA8888, .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_RGB888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_BGR888_A8, .depth = 32, .num_planes = 2, .cpp = { 3, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_XRGB8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_XBGR8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_RGBX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_BGRX8888_A8, .depth = 32, .num_planes = 2, .cpp = { 4, 1, 0 }, .hsub = 1, .vsub = 1 },
{ .format = DRM_FORMAT_YUV410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 },
{ .format = DRM_FORMAT_YVU410, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 4 },
{ .format = DRM_FORMAT_YUV411, .depth = 0, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 4, .vsub = 1 },
......
......@@ -30,14 +30,10 @@
#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
#include "ipuv3-plane.h"
#define MAX_CRTC 4
struct imx_drm_component {
struct device_node *of_node;
struct list_head list;
};
struct imx_drm_device {
struct drm_device *drm;
unsigned int pipes;
......@@ -109,6 +105,11 @@ static int imx_drm_atomic_check(struct drm_device *dev,
if (ret)
return ret;
/* Assign PRG/PRE channels and check if all constrains are satisfied. */
ret = ipu_planes_assign_pre(dev, state);
if (ret)
return ret;
return ret;
}
......@@ -122,6 +123,10 @@ static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_plane *plane;
struct drm_plane_state *old_plane_state;
bool plane_disabling = false;
int i;
drm_atomic_helper_commit_modeset_disables(dev, state);
......@@ -131,11 +136,20 @@ static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_commit_modeset_enables(dev, state);
drm_atomic_helper_commit_hw_done(state);
for_each_plane_in_state(state, plane, old_plane_state, i) {
if (drm_atomic_plane_disabling(old_plane_state, plane->state))
plane_disabling = true;
}
if (plane_disabling) {
drm_atomic_helper_wait_for_vblanks(dev, state);
drm_atomic_helper_wait_for_vblanks(dev, state);
for_each_plane_in_state(state, plane, old_plane_state, i)
ipu_plane_disable_deferred(plane);
drm_atomic_helper_cleanup_planes(dev, state);
}
drm_atomic_helper_commit_hw_done(state);
}
static const struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
......
......@@ -39,4 +39,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
void imx_drm_connector_destroy(struct drm_connector *connector);
void imx_drm_encoder_destroy(struct drm_encoder *encoder);
int ipu_planes_assign_pre(struct drm_device *dev,
struct drm_atomic_state *state);
#endif /* _IMX_DRM_H_ */
......@@ -55,11 +55,32 @@ static void ipu_crtc_enable(struct drm_crtc *crtc)
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
ipu_prg_enable(ipu);
ipu_dc_enable(ipu);
ipu_dc_enable_channel(ipu_crtc->dc);
ipu_di_enable(ipu_crtc->di);
}
static void ipu_crtc_disable_planes(struct ipu_crtc *ipu_crtc,
struct drm_crtc_state *old_crtc_state)
{
bool disable_partial = false;
bool disable_full = false;
struct drm_plane *plane;
drm_atomic_crtc_state_for_each_plane(plane, old_crtc_state) {
if (plane == &ipu_crtc->plane[0]->base)
disable_full = true;
if (&ipu_crtc->plane[1] && plane == &ipu_crtc->plane[1]->base)
disable_partial = true;
}
if (disable_partial)
ipu_plane_disable(ipu_crtc->plane[1], true);
if (disable_full)
ipu_plane_disable(ipu_crtc->plane[0], false);
}
static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state)
{
......@@ -73,8 +94,9 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
* attached IDMACs will be left in undefined state, possibly hanging
* the IPU or even system.
*/
drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
ipu_crtc_disable_planes(ipu_crtc, old_crtc_state);
ipu_dc_disable(ipu);
ipu_prg_disable(ipu);
spin_lock_irq(&crtc->dev->event_lock);
if (crtc->state->event) {
......
This diff is collapsed.
......@@ -18,11 +18,14 @@ struct ipu_plane {
struct ipu_soc *ipu;
struct ipuv3_channel *ipu_ch;
struct ipuv3_channel *alpha_ch;
struct dmfc_channel *dmfc;
struct ipu_dp *dp;
int dma;
int dp_flow;
bool disabling;
};
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
......@@ -42,4 +45,7 @@ void ipu_plane_put_resources(struct ipu_plane *plane);
int ipu_plane_irq(struct ipu_plane *plane);
void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
void ipu_plane_disable_deferred(struct drm_plane *plane);
#endif
......@@ -2,4 +2,4 @@ obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o
imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-image-convert.o \
ipu-smfc.o ipu-vdi.o
ipu-pre.o ipu-prg.o ipu-smfc.o ipu-vdi.o
......@@ -51,15 +51,17 @@ int ipu_get_num(struct ipu_soc *ipu)
}
EXPORT_SYMBOL_GPL(ipu_get_num);
void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync)
{
u32 val;
val = ipu_cm_read(ipu, IPU_SRM_PRI2);
val |= 0x8;
val &= ~DP_S_SRM_MODE_MASK;
val |= sync ? DP_S_SRM_MODE_NEXT_FRAME :
DP_S_SRM_MODE_NOW;
ipu_cm_write(ipu, val, IPU_SRM_PRI2);
}
EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
EXPORT_SYMBOL_GPL(ipu_srm_dp_update);
enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
{
......@@ -81,6 +83,12 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_RGB565_A8:
case DRM_FORMAT_BGR565_A8:
case DRM_FORMAT_RGB888_A8:
case DRM_FORMAT_BGR888_A8:
case DRM_FORMAT_RGBX8888_A8:
case DRM_FORMAT_BGRX8888_A8:
return IPUV3_COLORSPACE_RGB;
case DRM_FORMAT_YUYV:
case DRM_FORMAT_UYVY:
......@@ -931,6 +939,7 @@ static const struct of_device_id imx_ipu_dt_ids[] = {
{ .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
{ .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
{ .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
{ .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6q, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
......@@ -1390,11 +1399,19 @@ static int ipu_probe(struct platform_device *pdev)
if (!ipu)
return -ENODEV;
ipu->id = of_alias_get_id(np, "ipu");
if (of_device_is_compatible(np, "fsl,imx6qp-ipu")) {
ipu->prg_priv = ipu_prg_lookup_by_phandle(&pdev->dev,
"fsl,prg", ipu->id);
if (!ipu->prg_priv)
return -EPROBE_DEFER;
}
for (i = 0; i < 64; i++)
ipu->channel[i].ipu = ipu;
ipu->devtype = devtype;
ipu->ipu_type = devtype->type;
ipu->id = of_alias_get_id(np, "ipu");
spin_lock_init(&ipu->lock);
mutex_init(&ipu->channel_lock);
......@@ -1520,7 +1537,23 @@ static struct platform_driver imx_ipu_driver = {
.remove = ipu_remove,
};
module_platform_driver(imx_ipu_driver);
static struct platform_driver * const drivers[] = {
&ipu_pre_drv,
&ipu_prg_drv,
&imx_ipu_driver,
};
static int __init imx_ipu_init(void)
{
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(imx_ipu_init);
static void __exit imx_ipu_exit(void)
{
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(imx_ipu_exit);
MODULE_ALIAS("platform:imx-ipuv3");
MODULE_DESCRIPTION("i.MX IPU v3 driver");
......
......@@ -537,6 +537,43 @@ static const struct ipu_rgb def_bgra_16 = {
#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \
(pix->width * y) + (x))
#define NUM_ALPHA_CHANNELS 7
/* See Table 37-12. Alpha channels mapping. */
static int ipu_channel_albm(int ch_num)
{
switch (ch_num) {
case IPUV3_CHANNEL_G_MEM_IC_PRP_VF: return 0;
case IPUV3_CHANNEL_G_MEM_IC_PP: return 1;
case IPUV3_CHANNEL_MEM_FG_SYNC: return 2;
case IPUV3_CHANNEL_MEM_FG_ASYNC: return 3;
case IPUV3_CHANNEL_MEM_BG_SYNC: return 4;
case IPUV3_CHANNEL_MEM_BG_ASYNC: return 5;
case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB: return 6;
default:
return -EINVAL;
}
}
static void ipu_cpmem_set_separate_alpha(struct ipuv3_channel *ch)
{
struct ipu_soc *ipu = ch->ipu;
int albm;
u32 val;
albm = ipu_channel_albm(ch->num);
if (albm < 0)
return;
ipu_ch_param_write_field(ch, IPU_FIELD_ALU, 1);
ipu_ch_param_write_field(ch, IPU_FIELD_ALBM, albm);
ipu_ch_param_write_field(ch, IPU_FIELD_CRE, 1);
val = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
val |= BIT(ch->num);
ipu_idmac_write(ipu, val, IDMAC_SEP_ALPHA);
}
int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
{
switch (drm_fourcc) {
......@@ -599,22 +636,28 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
break;
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBX8888_A8:
ipu_cpmem_set_format_rgb(ch, &def_rgbx_32);
break;
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRX8888_A8:
ipu_cpmem_set_format_rgb(ch, &def_bgrx_32);
break;
case DRM_FORMAT_BGR888:
case DRM_FORMAT_BGR888_A8:
ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
break;
case DRM_FORMAT_RGB888:
case DRM_FORMAT_RGB888_A8:
ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
break;
case DRM_FORMAT_RGB565:
case DRM_FORMAT_RGB565_A8:
ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
break;
case DRM_FORMAT_BGR565:
case DRM_FORMAT_BGR565_A8:
ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
break;
case DRM_FORMAT_ARGB1555:
......@@ -636,6 +679,20 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
return -EINVAL;
}
switch (drm_fourcc) {
case DRM_FORMAT_RGB565_A8:
case DRM_FORMAT_BGR565_A8:
case DRM_FORMAT_RGB888_A8:
case DRM_FORMAT_BGR888_A8:
case DRM_FORMAT_RGBX8888_A8:
case DRM_FORMAT_BGRX8888_A8:
ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
ipu_cpmem_set_separate_alpha(ch);
break;
default:
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
......@@ -644,6 +701,7 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
{
struct v4l2_pix_format *pix = &image->pix;
int offset, u_offset, v_offset;
int ret = 0;
pr_debug("%s: resolution: %dx%d stride: %d\n",
__func__, pix->width, pix->height,
......@@ -719,14 +777,30 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
offset = image->rect.left * 3 +
image->rect.top * pix->bytesperline;
break;
case V4L2_PIX_FMT_SBGGR8:
case V4L2_PIX_FMT_SGBRG8:
case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8:
offset = image->rect.left + image->rect.top * pix->bytesperline;
break;
case V4L2_PIX_FMT_SBGGR16:
case V4L2_PIX_FMT_SGBRG16:
case V4L2_PIX_FMT_SGRBG16:
case V4L2_PIX_FMT_SRGGB16:
offset = image->rect.left * 2 +
image->rect.top * pix->bytesperline;
break;
default:
return -EINVAL;
/* This should not happen */
WARN_ON(1);
offset = 0;
ret = -EINVAL;
}
ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
return 0;
return ret;
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
......
......@@ -112,8 +112,6 @@ struct ipu_dc_priv {
struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
struct mutex mutex;
struct completion comp;
int dc_irq;
int dp_irq;
int use_count;
};
......@@ -262,47 +260,13 @@ void ipu_dc_enable_channel(struct ipu_dc *dc)
}
EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
static irqreturn_t dc_irq_handler(int irq, void *dev_id)
{
struct ipu_dc *dc = dev_id;
u32 reg;
reg = readl(dc->base + DC_WR_CH_CONF);
reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
writel(reg, dc->base + DC_WR_CH_CONF);
/* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */
complete(&dc->priv->comp);
return IRQ_HANDLED;
}
void ipu_dc_disable_channel(struct ipu_dc *dc)
{
struct ipu_dc_priv *priv = dc->priv;
int irq;
unsigned long ret;
u32 val;
/* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */
if (dc->chno == 1)
irq = priv->dc_irq;
else if (dc->chno == 5)
irq = priv->dp_irq;
else
return;
init_completion(&priv->comp);
enable_irq(irq);
ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50));
disable_irq(irq);
if (ret == 0) {
dev_warn(priv->dev, "DC stop timeout after 50 ms\n");
val = readl(dc->base + DC_WR_CH_CONF);
val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
writel(val, dc->base + DC_WR_CH_CONF);
}
val = readl(dc->base + DC_WR_CH_CONF);
val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
writel(val, dc->base + DC_WR_CH_CONF);
}
EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
......@@ -389,7 +353,7 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
struct ipu_dc_priv *priv;
static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
0x78, 0, 0x94, 0xb4};
int i, ret;
int i;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
......@@ -410,23 +374,6 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
priv->channels[i].base = priv->dc_reg + channel_offsets[i];
}
priv->dc_irq = ipu_map_irq(ipu, IPU_IRQ_DC_FC_1);
if (!priv->dc_irq)
return -EINVAL;
ret = devm_request_irq(dev, priv->dc_irq, dc_irq_handler, 0, NULL,
&priv->channels[1]);
if (ret < 0)
return ret;
disable_irq(priv->dc_irq);
priv->dp_irq = ipu_map_irq(ipu, IPU_IRQ_DP_SF_END);
if (!priv->dp_irq)
return -EINVAL;
ret = devm_request_irq(dev, priv->dp_irq, dc_irq_handler, 0, NULL,
&priv->channels[5]);
if (ret < 0)
return ret;
disable_irq(priv->dp_irq);
writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
DC_WR_CH_CONF_PROG_DI_ID,
priv->channels[1].base + DC_WR_CH_CONF);
......
......@@ -112,7 +112,7 @@ int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
}
ipu_srm_dp_sync_update(priv->ipu);
ipu_srm_dp_update(priv->ipu, true);
mutex_unlock(&priv->mutex);
......@@ -127,7 +127,7 @@ int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
ipu_srm_dp_sync_update(priv->ipu);
ipu_srm_dp_update(priv->ipu, true);
return 0;
}
......@@ -207,7 +207,7 @@ int ipu_dp_setup_channel(struct ipu_dp *dp,
flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
}
ipu_srm_dp_sync_update(priv->ipu);
ipu_srm_dp_update(priv->ipu, true);
mutex_unlock(&priv->mutex);
......@@ -247,7 +247,7 @@ int ipu_dp_enable_channel(struct ipu_dp *dp)
reg |= DP_COM_CONF_FG_EN;
writel(reg, flow->base + DP_COM_CONF);
ipu_srm_dp_sync_update(priv->ipu);
ipu_srm_dp_update(priv->ipu, true);
mutex_unlock(&priv->mutex);
......@@ -255,7 +255,7 @@ int ipu_dp_enable_channel(struct ipu_dp *dp)
}
EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
void ipu_dp_disable_channel(struct ipu_dp *dp)
void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
{
struct ipu_flow *flow = to_flow(dp);
struct ipu_dp_priv *priv = flow->priv;
......@@ -275,10 +275,7 @@ void ipu_dp_disable_channel(struct ipu_dp *dp)
writel(reg, flow->base + DP_COM_CONF);
writel(0, flow->base + DP_FG_POS);
ipu_srm_dp_sync_update(priv->ipu);
if (ipu_idmac_channel_busy(priv->ipu, IPUV3_CHANNEL_MEM_BG_SYNC))
ipu_wait_interrupt(priv->ipu, IPU_IRQ_DP_SF_END, 50);
ipu_srm_dp_update(priv->ipu, sync);
mutex_unlock(&priv->mutex);
}
......
......@@ -671,7 +671,12 @@ static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
ipu_ic_task_idma_init(chan->ic, channel, width, height,
burst_size, rot_mode);
ipu_cpmem_set_axi_id(channel, 1);
/*
* Setting a non-zero AXI ID collides with the PRG AXI snooping, so
* only do this when there is no PRG present.
*/
if (!channel->ipu->prg_priv)
ipu_cpmem_set_axi_id(channel, 1);
ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
}
......
/*
* Copyright (c) 2017 Lucas Stach, Pengutronix
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <drm/drm_fourcc.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <video/imx-ipu-v3.h>
#include "ipu-prv.h"
#define IPU_PRE_MAX_WIDTH 2048
#define IPU_PRE_NUM_SCANLINES 8
#define IPU_PRE_CTRL 0x000
#define IPU_PRE_CTRL_SET 0x004
#define IPU_PRE_CTRL_ENABLE (1 << 0)
#define IPU_PRE_CTRL_BLOCK_EN (1 << 1)
#define IPU_PRE_CTRL_BLOCK_16 (1 << 2)
#define IPU_PRE_CTRL_SDW_UPDATE (1 << 4)
#define IPU_PRE_CTRL_VFLIP (1 << 5)
#define IPU_PRE_CTRL_SO (1 << 6)
#define IPU_PRE_CTRL_INTERLACED_FIELD (1 << 7)
#define IPU_PRE_CTRL_HANDSHAKE_EN (1 << 8)
#define IPU_PRE_CTRL_HANDSHAKE_LINE_NUM(v) ((v & 0x3) << 9)
#define IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN (1 << 11)
#define IPU_PRE_CTRL_EN_REPEAT (1 << 28)
#define IPU_PRE_CTRL_TPR_REST_SEL (1 << 29)
#define IPU_PRE_CTRL_CLKGATE (1 << 30)
#define IPU_PRE_CTRL_SFTRST (1 << 31)
#define IPU_PRE_CUR_BUF 0x030
#define IPU_PRE_NEXT_BUF 0x040
#define IPU_PRE_TPR_CTRL 0x070
#define IPU_PRE_TPR_CTRL_TILE_FORMAT(v) ((v & 0xff) << 0)
#define IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK 0xff
#define IPU_PRE_PREFETCH_ENG_CTRL 0x080
#define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0)
#define IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(v) ((v & 0x7) << 1)
#define IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
#define IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(v) ((v & 0x7) << 8)
#define IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS (1 << 11)
#define IPU_PRE_PREF_ENG_CTRL_FIELD_INVERSE (1 << 12)
#define IPU_PRE_PREF_ENG_CTRL_PARTIAL_UV_SWAP (1 << 14)
#define IPU_PRE_PREF_ENG_CTRL_TPR_COOR_OFFSET_EN (1 << 15)
#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE 0x0a0
#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(v) ((v & 0xffff) << 0)
#define IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(v) ((v & 0xffff) << 16)
#define IPU_PRE_PREFETCH_ENG_PITCH 0x0d0
#define IPU_PRE_PREFETCH_ENG_PITCH_Y(v) ((v & 0xffff) << 0)
#define IPU_PRE_PREFETCH_ENG_PITCH_UV(v) ((v & 0xffff) << 16)
#define IPU_PRE_STORE_ENG_CTRL 0x110
#define IPU_PRE_STORE_ENG_CTRL_STORE_EN (1 << 0)
#define IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(v) ((v & 0x7) << 1)
#define IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(v) ((v & 0x3) << 4)
#define IPU_PRE_STORE_ENG_SIZE 0x130
#define IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(v) ((v & 0xffff) << 0)
#define IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(v) ((v & 0xffff) << 16)
#define IPU_PRE_STORE_ENG_PITCH 0x140
#define IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(v) ((v & 0xffff) << 0)
#define IPU_PRE_STORE_ENG_ADDR 0x150
struct ipu_pre {
struct list_head list;
struct device *dev;
void __iomem *regs;
struct clk *clk_axi;
struct gen_pool *iram;
dma_addr_t buffer_paddr;
void *buffer_virt;
bool in_use;
};
static DEFINE_MUTEX(ipu_pre_list_mutex);
static LIST_HEAD(ipu_pre_list);
static int available_pres;
int ipu_pre_get_available_count(void)
{
return available_pres;
}
struct ipu_pre *
ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
{
struct device_node *pre_node = of_parse_phandle(dev->of_node,
name, index);
struct ipu_pre *pre;
mutex_lock(&ipu_pre_list_mutex);
list_for_each_entry(pre, &ipu_pre_list, list) {
if (pre_node == pre->dev->of_node) {
mutex_unlock(&ipu_pre_list_mutex);
device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE);
return pre;
}
}
mutex_unlock(&ipu_pre_list_mutex);
return NULL;
}
int ipu_pre_get(struct ipu_pre *pre)
{
u32 val;
if (pre->in_use)
return -EBUSY;
clk_prepare_enable(pre->clk_axi);
/* first get the engine out of reset and remove clock gating */
writel(0, pre->regs + IPU_PRE_CTRL);
/* init defaults that should be applied to all streams */
val = IPU_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN |
IPU_PRE_CTRL_HANDSHAKE_EN |
IPU_PRE_CTRL_TPR_REST_SEL |
IPU_PRE_CTRL_BLOCK_16 | IPU_PRE_CTRL_SDW_UPDATE;
writel(val, pre->regs + IPU_PRE_CTRL);
pre->in_use = true;
return 0;
}
void ipu_pre_put(struct ipu_pre *pre)
{
u32 val;
val = IPU_PRE_CTRL_SFTRST | IPU_PRE_CTRL_CLKGATE;
writel(val, pre->regs + IPU_PRE_CTRL);
clk_disable_unprepare(pre->clk_axi);
pre->in_use = false;
}
void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
unsigned int height, unsigned int stride, u32 format,
unsigned int bufaddr)
{
const struct drm_format_info *info = drm_format_info(format);
u32 active_bpp = info->cpp[0] >> 1;
u32 val;
writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
IPU_PRE_PREF_ENG_CTRL_RD_NUM_BYTES(4) |
IPU_PRE_PREF_ENG_CTRL_SHIFT_BYPASS |
IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN;
writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_CTRL);
val = IPU_PRE_PREFETCH_ENG_INPUT_SIZE_WIDTH(width) |
IPU_PRE_PREFETCH_ENG_INPUT_SIZE_HEIGHT(height);
writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_INPUT_SIZE);
val = IPU_PRE_PREFETCH_ENG_PITCH_Y(stride);
writel(val, pre->regs + IPU_PRE_PREFETCH_ENG_PITCH);
val = IPU_PRE_STORE_ENG_CTRL_OUTPUT_ACTIVE_BPP(active_bpp) |
IPU_PRE_STORE_ENG_CTRL_WR_NUM_BYTES(4) |
IPU_PRE_STORE_ENG_CTRL_STORE_EN;
writel(val, pre->regs + IPU_PRE_STORE_ENG_CTRL);
val = IPU_PRE_STORE_ENG_SIZE_INPUT_WIDTH(width) |
IPU_PRE_STORE_ENG_SIZE_INPUT_HEIGHT(height);
writel(val, pre->regs + IPU_PRE_STORE_ENG_SIZE);
val = IPU_PRE_STORE_ENG_PITCH_OUT_PITCH(stride);
writel(val, pre->regs + IPU_PRE_STORE_ENG_PITCH);
writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
val = readl(pre->regs + IPU_PRE_CTRL);
val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
IPU_PRE_CTRL_SDW_UPDATE;
writel(val, pre->regs + IPU_PRE_CTRL);
}
void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
{
writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
}
u32 ipu_pre_get_baddr(struct ipu_pre *pre)
{
return (u32)pre->buffer_paddr;
}
static int ipu_pre_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct ipu_pre *pre;
pre = devm_kzalloc(dev, sizeof(*pre), GFP_KERNEL);
if (!pre)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pre->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pre->regs))
return PTR_ERR(pre->regs);
pre->clk_axi = devm_clk_get(dev, "axi");
if (IS_ERR(pre->clk_axi))
return PTR_ERR(pre->clk_axi);
pre->iram = of_gen_pool_get(dev->of_node, "fsl,iram", 0);
if (!pre->iram)
return -EPROBE_DEFER;
/*
* Allocate IRAM buffer with maximum size. This could be made dynamic,
* but as there is no other user of this IRAM region and we can fit all
* max sized buffers into it, there is no need yet.
*/
pre->buffer_virt = gen_pool_dma_alloc(pre->iram, IPU_PRE_MAX_WIDTH *
IPU_PRE_NUM_SCANLINES * 4,
&pre->buffer_paddr);
if (!pre->buffer_virt)
return -ENOMEM;
pre->dev = dev;
platform_set_drvdata(pdev, pre);
mutex_lock(&ipu_pre_list_mutex);
list_add(&pre->list, &ipu_pre_list);
available_pres++;
mutex_unlock(&ipu_pre_list_mutex);
return 0;
}
static int ipu_pre_remove(struct platform_device *pdev)
{
struct ipu_pre *pre = platform_get_drvdata(pdev);
mutex_lock(&ipu_pre_list_mutex);
list_del(&pre->list);
available_pres--;
mutex_unlock(&ipu_pre_list_mutex);
if (pre->buffer_virt)
gen_pool_free(pre->iram, (unsigned long)pre->buffer_virt,
IPU_PRE_MAX_WIDTH * IPU_PRE_NUM_SCANLINES * 4);
return 0;
}
static const struct of_device_id ipu_pre_dt_ids[] = {
{ .compatible = "fsl,imx6qp-pre", },
{ /* sentinel */ },
};
struct platform_driver ipu_pre_drv = {
.probe = ipu_pre_probe,
.remove = ipu_pre_remove,
.driver = {
.name = "imx-ipu-pre",
.of_match_table = ipu_pre_dt_ids,
},
};
This diff is collapsed.
......@@ -75,6 +75,11 @@ struct ipu_soc;
#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n))
#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n))
/* SRM_PRI2 */
#define DP_S_SRM_MODE_MASK (0x3 << 3)
#define DP_S_SRM_MODE_NOW (0x3 << 3)
#define DP_S_SRM_MODE_NEXT_FRAME (0x1 << 3)
/* FS_PROC_FLOW1 */
#define FS_PRPENC_ROT_SRC_SEL_MASK (0xf << 0)
#define FS_PRPENC_ROT_SRC_SEL_ENC (0x7 << 0)
......@@ -168,6 +173,8 @@ struct ipu_ic_priv;
struct ipu_vdi;
struct ipu_image_convert_priv;
struct ipu_smfc_priv;
struct ipu_pre;
struct ipu_prg;
struct ipu_devtype;
......@@ -202,6 +209,7 @@ struct ipu_soc {
struct ipu_vdi *vdi_priv;
struct ipu_image_convert_priv *image_convert_priv;
struct ipu_smfc_priv *smfc_priv;
struct ipu_prg *prg_priv;
};
static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
......@@ -215,7 +223,7 @@ static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
writel(value, ipu->idmac_reg + offset);
}
void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
void ipu_srm_dp_update(struct ipu_soc *ipu, bool sync);
int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
......@@ -259,4 +267,21 @@ void ipu_cpmem_exit(struct ipu_soc *ipu);
int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base);
void ipu_smfc_exit(struct ipu_soc *ipu);
struct ipu_pre *ipu_pre_lookup_by_phandle(struct device *dev, const char *name,
int index);
int ipu_pre_get_available_count(void);
int ipu_pre_get(struct ipu_pre *pre);
void ipu_pre_put(struct ipu_pre *pre);
u32 ipu_pre_get_baddr(struct ipu_pre *pre);
void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
unsigned int height,
unsigned int stride, u32 format, unsigned int bufaddr);
void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
int ipu_id);
extern struct platform_driver ipu_pre_drv;
extern struct platform_driver ipu_prg_drv;
#endif /* __IPU_PRV_H__ */
......@@ -113,6 +113,20 @@ extern "C" {
#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
/*
* 2 plane RGB + A
* index 0 = RGB plane, same format as the corresponding non _A8 format has
* index 1 = A plane, [7:0] A
*/
#define DRM_FORMAT_XRGB8888_A8 fourcc_code('X', 'R', 'A', '8')
#define DRM_FORMAT_XBGR8888_A8 fourcc_code('X', 'B', 'A', '8')
#define DRM_FORMAT_RGBX8888_A8 fourcc_code('R', 'X', 'A', '8')
#define DRM_FORMAT_BGRX8888_A8 fourcc_code('B', 'X', 'A', '8')
#define DRM_FORMAT_RGB888_A8 fourcc_code('R', '8', 'A', '8')
#define DRM_FORMAT_BGR888_A8 fourcc_code('B', '8', 'A', '8')
#define DRM_FORMAT_RGB565_A8 fourcc_code('R', '5', 'A', '8')
#define DRM_FORMAT_BGR565_A8 fourcc_code('B', '5', 'A', '8')
/*
* 2 plane YCbCr
* index 0 = Y plane, [7:0] Y
......
......@@ -161,6 +161,28 @@ enum ipu_channel_irq {
#define IPUV3_CHANNEL_MEM_BG_ASYNC_ALPHA 52
#define IPUV3_NUM_CHANNELS 64
static inline int ipu_channel_alpha_channel(int ch_num)
{
switch (ch_num) {
case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
return IPUV3_CHANNEL_G_MEM_IC_PRP_VF_ALPHA;
case IPUV3_CHANNEL_G_MEM_IC_PP:
return IPUV3_CHANNEL_G_MEM_IC_PP_ALPHA;
case IPUV3_CHANNEL_MEM_FG_SYNC:
return IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA;
case IPUV3_CHANNEL_MEM_FG_ASYNC:
return IPUV3_CHANNEL_MEM_FG_ASYNC_ALPHA;
case IPUV3_CHANNEL_MEM_BG_SYNC:
return IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA;
case IPUV3_CHANNEL_MEM_BG_ASYNC:
return IPUV3_CHANNEL_MEM_BG_ASYNC_ALPHA;
case IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB:
return IPUV3_CHANNEL_MEM_VDI_PLANE1_COMB_ALPHA;
default:
return -EINVAL;
}
}
int ipu_map_irq(struct ipu_soc *ipu, int irq);
int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
enum ipu_channel_irq irq);
......@@ -300,7 +322,7 @@ struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow);
void ipu_dp_put(struct ipu_dp *);
int ipu_dp_enable(struct ipu_soc *ipu);
int ipu_dp_enable_channel(struct ipu_dp *dp);
void ipu_dp_disable_channel(struct ipu_dp *dp);
void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync);
void ipu_dp_disable(struct ipu_soc *ipu);
int ipu_dp_setup_channel(struct ipu_dp *dp,
enum ipu_color_space in, enum ipu_color_space out);
......@@ -308,6 +330,21 @@ int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
bool bg_chan);
/*
* IPU Prefetch Resolve Gasket (prg) functions
*/
int ipu_prg_max_active_channels(void);
bool ipu_prg_present(struct ipu_soc *ipu);
bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
uint64_t modifier);
int ipu_prg_enable(struct ipu_soc *ipu);
void ipu_prg_disable(struct ipu_soc *ipu);
void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan);
int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
unsigned int axi_id, unsigned int width,
unsigned int height, unsigned int stride,
u32 format, unsigned long *eba);
/*
* IPU CMOS Sensor Interface (csi) functions
*/
......
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