diff options
Diffstat (limited to 'drivers/gpu/ipu-v3')
-rw-r--r-- | drivers/gpu/ipu-v3/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 43 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-cpmem.c | 78 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-dc.c | 61 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-dp.c | 15 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-image-convert.c | 7 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-pre.c | 289 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prg.c | 424 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prv.h | 27 |
9 files changed, 870 insertions, 76 deletions
diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile index 5f961416c4ee..1ab9bceee755 100644 --- a/drivers/gpu/ipu-v3/Makefile +++ b/drivers/gpu/ipu-v3/Makefile @@ -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 diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 8368e6f766ee..7aefccec31b1 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -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"); diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index 4b2b67113d92..114160dfc3ad 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -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); diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c index 659475c1e44a..7a4b8362dda8 100644 --- a/drivers/gpu/ipu-v3/ipu-dc.c +++ b/drivers/gpu/ipu-v3/ipu-dc.c @@ -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); diff --git a/drivers/gpu/ipu-v3/ipu-dp.c b/drivers/gpu/ipu-v3/ipu-dp.c index 98686edbcdbb..9b2b3fa479c4 100644 --- a/drivers/gpu/ipu-v3/ipu-dp.c +++ b/drivers/gpu/ipu-v3/ipu-dp.c @@ -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); } diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c index 805b6fa7b5f4..524a717ab28e 100644 --- a/drivers/gpu/ipu-v3/ipu-image-convert.c +++ b/drivers/gpu/ipu-v3/ipu-image-convert.c @@ -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); } diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c new file mode 100644 index 000000000000..c55563379e2e --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-pre.c @@ -0,0 +1,289 @@ +/* + * 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, + }, +}; diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c new file mode 100644 index 000000000000..caca57febbd6 --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-prg.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2016-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/mfd/syscon.h> +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <video/imx-ipu-v3.h> + +#include "ipu-prv.h" + +#define IPU_PRG_CTL 0x00 +#define IPU_PRG_CTL_BYPASS(i) (1 << (0 + i)) +#define IPU_PRG_CTL_SOFT_ARID_MASK 0x3 +#define IPU_PRG_CTL_SOFT_ARID_SHIFT(i) (8 + i * 2) +#define IPU_PRG_CTL_SOFT_ARID(i, v) ((v & 0x3) << (8 + 2 * i)) +#define IPU_PRG_CTL_SO(i) (1 << (16 + i)) +#define IPU_PRG_CTL_VFLIP(i) (1 << (19 + i)) +#define IPU_PRG_CTL_BLOCK_MODE(i) (1 << (22 + i)) +#define IPU_PRG_CTL_CNT_LOAD_EN(i) (1 << (25 + i)) +#define IPU_PRG_CTL_SOFTRST (1 << 30) +#define IPU_PRG_CTL_SHADOW_EN (1 << 31) + +#define IPU_PRG_STATUS 0x04 +#define IPU_PRG_STATUS_BUFFER0_READY(i) (1 << (0 + i * 2)) +#define IPU_PRG_STATUS_BUFFER1_READY(i) (1 << (1 + i * 2)) + +#define IPU_PRG_QOS 0x08 +#define IPU_PRG_QOS_ARID_MASK 0xf +#define IPU_PRG_QOS_ARID_SHIFT(i) (0 + i * 4) + +#define IPU_PRG_REG_UPDATE 0x0c +#define IPU_PRG_REG_UPDATE_REG_UPDATE (1 << 0) + +#define IPU_PRG_STRIDE(i) (0x10 + i * 0x4) +#define IPU_PRG_STRIDE_STRIDE_MASK 0x3fff + +#define IPU_PRG_CROP_LINE 0x1c + +#define IPU_PRG_THD 0x20 + +#define IPU_PRG_BADDR(i) (0x24 + i * 0x4) + +#define IPU_PRG_OFFSET(i) (0x30 + i * 0x4) + +#define IPU_PRG_ILO(i) (0x3c + i * 0x4) + +#define IPU_PRG_HEIGHT(i) (0x48 + i * 0x4) +#define IPU_PRG_HEIGHT_PRE_HEIGHT_MASK 0xfff +#define IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT 0 +#define IPU_PRG_HEIGHT_IPU_HEIGHT_MASK 0xfff +#define IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT 16 + +struct ipu_prg_channel { + bool enabled; + int used_pre; +}; + +struct ipu_prg { + struct list_head list; + struct device *dev; + int id; + + void __iomem *regs; + struct clk *clk_ipg, *clk_axi; + struct regmap *iomuxc_gpr; + struct ipu_pre *pres[3]; + + struct ipu_prg_channel chan[3]; +}; + +static DEFINE_MUTEX(ipu_prg_list_mutex); +static LIST_HEAD(ipu_prg_list); + +struct ipu_prg * +ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id) +{ + struct device_node *prg_node = of_parse_phandle(dev->of_node, + name, 0); + struct ipu_prg *prg; + + mutex_lock(&ipu_prg_list_mutex); + list_for_each_entry(prg, &ipu_prg_list, list) { + if (prg_node == prg->dev->of_node) { + mutex_unlock(&ipu_prg_list_mutex); + device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE); + prg->id = ipu_id; + return prg; + } + } + mutex_unlock(&ipu_prg_list_mutex); + + return NULL; +} + +int ipu_prg_max_active_channels(void) +{ + return ipu_pre_get_available_count(); +} +EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels); + +bool ipu_prg_present(struct ipu_soc *ipu) +{ + if (ipu->prg_priv) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(ipu_prg_present); + +bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format, + uint64_t modifier) +{ + const struct drm_format_info *info = drm_format_info(format); + + if (info->num_planes != 1) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(ipu_prg_format_supported); + +int ipu_prg_enable(struct ipu_soc *ipu) +{ + struct ipu_prg *prg = ipu->prg_priv; + int ret; + + if (!prg) + return 0; + + ret = clk_prepare_enable(prg->clk_axi); + if (ret) + goto fail_disable_ipg; + + return 0; + +fail_disable_ipg: + clk_disable_unprepare(prg->clk_ipg); + + return ret; +} +EXPORT_SYMBOL_GPL(ipu_prg_enable); + +void ipu_prg_disable(struct ipu_soc *ipu) +{ + struct ipu_prg *prg = ipu->prg_priv; + + if (!prg) + return; + + clk_disable_unprepare(prg->clk_axi); +} +EXPORT_SYMBOL_GPL(ipu_prg_disable); + +/* + * The channel configuartion functions below are not thread safe, as they + * must be only called from the atomic commit path in the DRM driver, which + * is properly serialized. + */ +static int ipu_prg_ipu_to_prg_chan(int ipu_chan) +{ + /* + * This isn't clearly documented in the RM, but IPU to PRG channel + * assignment is fixed, as only with this mapping the control signals + * match up. + */ + switch (ipu_chan) { + case IPUV3_CHANNEL_MEM_BG_SYNC: + return 0; + case IPUV3_CHANNEL_MEM_FG_SYNC: + return 1; + case IPUV3_CHANNEL_MEM_DC_SYNC: + return 2; + default: + return -EINVAL; + } +} + +static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan) +{ + int i, ret; + + /* channel 0 is special as it is hardwired to one of the PREs */ + if (prg_chan == 0) { + ret = ipu_pre_get(prg->pres[0]); + if (ret) + goto fail; + prg->chan[prg_chan].used_pre = 0; + return 0; + } + + for (i = 1; i < 3; i++) { + ret = ipu_pre_get(prg->pres[i]); + if (!ret) { + u32 val, mux; + int shift; + + prg->chan[prg_chan].used_pre = i; + + /* configure the PRE to PRG channel mux */ + shift = (i == 1) ? 12 : 14; + mux = (prg->id << 1) | (prg_chan - 1); + regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5, + 0x3 << shift, mux << shift); + + /* check other mux, must not point to same channel */ + shift = (i == 1) ? 14 : 12; + regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val); + if (((val >> shift) & 0x3) == mux) { + regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5, + 0x3 << shift, + (mux ^ 0x1) << shift); + } + + return 0; + } + } + +fail: + dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan); + return ret; +} + +static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan) +{ + struct ipu_prg_channel *chan = &prg->chan[prg_chan]; + + ipu_pre_put(prg->pres[chan->used_pre]); + chan->used_pre = -1; +} + +void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan) +{ + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num); + struct ipu_prg *prg = ipu_chan->ipu->prg_priv; + struct ipu_prg_channel *chan = &prg->chan[prg_chan]; + u32 val; + + if (!chan->enabled || prg_chan < 0) + return; + + clk_prepare_enable(prg->clk_ipg); + + val = readl(prg->regs + IPU_PRG_CTL); + val |= IPU_PRG_CTL_BYPASS(prg_chan); + writel(val, prg->regs + IPU_PRG_CTL); + + val = IPU_PRG_REG_UPDATE_REG_UPDATE; + writel(val, prg->regs + IPU_PRG_REG_UPDATE); + + clk_disable_unprepare(prg->clk_ipg); + + ipu_prg_put_pre(prg, prg_chan); + + chan->enabled = false; +} +EXPORT_SYMBOL_GPL(ipu_prg_channel_disable); + +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) +{ + int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num); + struct ipu_prg *prg = ipu_chan->ipu->prg_priv; + struct ipu_prg_channel *chan = &prg->chan[prg_chan]; + u32 val; + int ret; + + if (prg_chan < 0) + return prg_chan; + + if (chan->enabled) { + ipu_pre_update(prg->pres[chan->used_pre], *eba); + return 0; + } + + ret = ipu_prg_get_pre(prg, prg_chan); + if (ret) + return ret; + + ipu_pre_configure(prg->pres[chan->used_pre], + width, height, stride, format, *eba); + + + ret = clk_prepare_enable(prg->clk_ipg); + if (ret) { + ipu_prg_put_pre(prg, prg_chan); + return ret; + } + + val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK; + writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan)); + + val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) << + IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) | + ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) << + IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT); + writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan)); + + val = ipu_pre_get_baddr(prg->pres[chan->used_pre]); + *eba = val; + writel(val, prg->regs + IPU_PRG_BADDR(prg_chan)); + + val = readl(prg->regs + IPU_PRG_CTL); + /* counter load enable */ + val |= IPU_PRG_CTL_CNT_LOAD_EN(prg_chan); + /* config AXI ID */ + val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK << + IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan)); + val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id); + /* enable channel */ + val &= ~IPU_PRG_CTL_BYPASS(prg_chan); + writel(val, prg->regs + IPU_PRG_CTL); + + val = IPU_PRG_REG_UPDATE_REG_UPDATE; + writel(val, prg->regs + IPU_PRG_REG_UPDATE); + + clk_disable_unprepare(prg->clk_ipg); + + chan->enabled = true; + return 0; +} +EXPORT_SYMBOL_GPL(ipu_prg_channel_configure); + +static int ipu_prg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct ipu_prg *prg; + u32 val; + int i, ret; + + prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL); + if (!prg) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + prg->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(prg->regs)) + return PTR_ERR(prg->regs); + + + prg->clk_ipg = devm_clk_get(dev, "ipg"); + if (IS_ERR(prg->clk_ipg)) + return PTR_ERR(prg->clk_ipg); + + prg->clk_axi = devm_clk_get(dev, "axi"); + if (IS_ERR(prg->clk_axi)) + return PTR_ERR(prg->clk_axi); + + prg->iomuxc_gpr = + syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (IS_ERR(prg->iomuxc_gpr)) + return PTR_ERR(prg->iomuxc_gpr); + + for (i = 0; i < 3; i++) { + prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i); + if (!prg->pres[i]) + return -EPROBE_DEFER; + } + + ret = clk_prepare_enable(prg->clk_ipg); + if (ret) + return ret; + + /* init to free running mode */ + val = readl(prg->regs + IPU_PRG_CTL); + val |= IPU_PRG_CTL_SHADOW_EN; + writel(val, prg->regs + IPU_PRG_CTL); + + /* disable address threshold */ + writel(0xffffffff, prg->regs + IPU_PRG_THD); + + clk_disable_unprepare(prg->clk_ipg); + + prg->dev = dev; + platform_set_drvdata(pdev, prg); + mutex_lock(&ipu_prg_list_mutex); + list_add(&prg->list, &ipu_prg_list); + mutex_unlock(&ipu_prg_list_mutex); + + return 0; +} + +static int ipu_prg_remove(struct platform_device *pdev) +{ + struct ipu_prg *prg = platform_get_drvdata(pdev); + + mutex_lock(&ipu_prg_list_mutex); + list_del(&prg->list); + mutex_unlock(&ipu_prg_list_mutex); + + return 0; +} + +static const struct of_device_id ipu_prg_dt_ids[] = { + { .compatible = "fsl,imx6qp-prg", }, + { /* sentinel */ }, +}; + +struct platform_driver ipu_prg_drv = { + .probe = ipu_prg_probe, + .remove = ipu_prg_remove, + .driver = { + .name = "imx-ipu-prg", + .of_match_table = ipu_prg_dt_ids, + }, +}; diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index 22e47b68b14a..ca2a223a0d1e 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -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__ */ |