diff options
Diffstat (limited to 'drivers/gpu/ipu-v3')
-rw-r--r-- | drivers/gpu/ipu-v3/Kconfig | 4 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 4 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-cpmem.c | 3 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-csi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-ic.c | 1 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-pre.c | 32 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prg.c | 87 | ||||
-rw-r--r-- | drivers/gpu/ipu-v3/ipu-prv.h | 4 |
8 files changed, 105 insertions, 32 deletions
diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/ipu-v3/Kconfig index 87a20b3dcf7a..fe6f8c5b4445 100644 --- a/drivers/gpu/ipu-v3/Kconfig +++ b/drivers/gpu/ipu-v3/Kconfig @@ -1,7 +1,9 @@ config IMX_IPUV3_CORE tristate "IPUv3 core support" - depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM + depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM || COMPILE_TEST depends on DRM || !DRM # if DRM=m, this can't be 'y' + select BITREVERSE + select GENERIC_ALLOCATOR if DRM select GENERIC_IRQ_CHIP help Choose this if you have a i.MX5/6 system and want to use the Image diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 658fa2d3e40c..48685cddbad1 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1089,7 +1089,7 @@ static void ipu_irq_handler(struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; + static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; chained_irq_enter(chip, desc); @@ -1102,7 +1102,7 @@ static void ipu_err_irq_handler(struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); - const int int_reg[] = { 4, 5, 8, 9}; + static const int int_reg[] = { 4, 5, 8, 9}; chained_irq_enter(chip, desc); diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index 1cb82f445f91..9f2d9ec42add 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -12,6 +12,7 @@ #include <linux/types.h> #include <linux/bitrev.h> #include <linux/io.h> +#include <linux/sizes.h> #include <drm/drm_fourcc.h> #include "ipu-prv.h" @@ -787,12 +788,14 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_GREY: 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: + case V4L2_PIX_FMT_Y16: offset = image->rect.left * 2 + image->rect.top * pix->bytesperline; break; diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 24e12b87a0cb..caa05b0702e1 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -288,6 +288,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_Y10_1X10: cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; cfg->mipi_dt = MIPI_DT_RAW10; cfg->data_width = IPU_CSI_DATA_WIDTH_10; @@ -296,6 +297,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_Y12_1X12: cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; cfg->mipi_dt = MIPI_DT_RAW12; cfg->data_width = IPU_CSI_DATA_WIDTH_12; diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c index 321eb983c2f5..67cc820253a9 100644 --- a/drivers/gpu/ipu-v3/ipu-ic.c +++ b/drivers/gpu/ipu-v3/ipu-ic.c @@ -17,6 +17,7 @@ #include <linux/bitrev.h> #include <linux/io.h> #include <linux/err.h> +#include <linux/sizes.h> #include "ipu-prv.h" /* IC Register Offsets */ diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c index c860a7997cb5..0f70e8847540 100644 --- a/drivers/gpu/ipu-v3/ipu-pre.c +++ b/drivers/gpu/ipu-v3/ipu-pre.c @@ -49,6 +49,10 @@ #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_TPR_CTRL_TILE_FORMAT_16_BIT (1 << 0) +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SPLIT_BUF (1 << 4) +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF (1 << 5) +#define IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED (1 << 6) #define IPU_PRE_PREFETCH_ENG_CTRL 0x080 #define IPU_PRE_PREF_ENG_CTRL_PREFETCH_EN (1 << 0) @@ -125,11 +129,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index) if (pre_node == pre->dev->of_node) { mutex_unlock(&ipu_pre_list_mutex); device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE); + of_node_put(pre_node); return pre; } } mutex_unlock(&ipu_pre_list_mutex); + of_node_put(pre_node); + return NULL; } @@ -147,7 +154,7 @@ int ipu_pre_get(struct ipu_pre *pre) 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; + IPU_PRE_CTRL_SDW_UPDATE; writel(val, pre->regs + IPU_PRE_CTRL); pre->in_use = true; @@ -163,14 +170,17 @@ void ipu_pre_put(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) + uint64_t modifier, unsigned int bufaddr) { const struct drm_format_info *info = drm_format_info(format); u32 active_bpp = info->cpp[0] >> 1; u32 val; /* calculate safe window for ctrl register updates */ - pre->safe_window_end = height - 2; + if (modifier == DRM_FORMAT_MOD_LINEAR) + pre->safe_window_end = height - 2; + else + pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1; writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF); writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF); @@ -203,9 +213,25 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width, writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR); + val = readl(pre->regs + IPU_PRE_TPR_CTRL); + val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK; + if (modifier != DRM_FORMAT_MOD_LINEAR) { + /* only support single buffer formats for now */ + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF; + if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED) + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED; + if (info->cpp[0] == 2) + val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT; + } + writel(val, pre->regs + IPU_PRE_TPR_CTRL); + val = readl(pre->regs + IPU_PRE_CTRL); val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE | IPU_PRE_CTRL_SDW_UPDATE; + if (modifier == DRM_FORMAT_MOD_LINEAR) + val &= ~IPU_PRE_CTRL_BLOCK_EN; + else + val |= IPU_PRE_CTRL_BLOCK_EN; writel(val, pre->regs + IPU_PRE_CTRL); } diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c index 0013ca9f72c8..97b99500153d 100644 --- a/drivers/gpu/ipu-v3/ipu-prg.c +++ b/drivers/gpu/ipu-v3/ipu-prg.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <video/imx-ipu-v3.h> @@ -101,11 +102,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id) mutex_unlock(&ipu_prg_list_mutex); device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE); prg->id = ipu_id; + of_node_put(prg_node); return prg; } } mutex_unlock(&ipu_prg_list_mutex); + of_node_put(prg_node); + return NULL; } @@ -132,28 +136,25 @@ bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format, if (info->num_planes != 1) return false; - return true; + switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + case DRM_FORMAT_MOD_VIVANTE_TILED: + case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: + return true; + default: + return false; + } } 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; + return pm_runtime_get_sync(prg->dev); } EXPORT_SYMBOL_GPL(ipu_prg_enable); @@ -164,7 +165,7 @@ void ipu_prg_disable(struct ipu_soc *ipu) if (!prg) return; - clk_disable_unprepare(prg->clk_axi); + pm_runtime_put(prg->dev); } EXPORT_SYMBOL_GPL(ipu_prg_disable); @@ -255,7 +256,7 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan) if (!chan->enabled || prg_chan < 0) return; - clk_prepare_enable(prg->clk_ipg); + pm_runtime_get_sync(prg->dev); val = readl(prg->regs + IPU_PRG_CTL); val |= IPU_PRG_CTL_BYPASS(prg_chan); @@ -264,7 +265,7 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan) val = IPU_PRG_REG_UPDATE_REG_UPDATE; writel(val, prg->regs + IPU_PRG_REG_UPDATE); - clk_disable_unprepare(prg->clk_ipg); + pm_runtime_put(prg->dev); ipu_prg_put_pre(prg, prg_chan); @@ -275,7 +276,7 @@ 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) + u32 format, uint64_t modifier, unsigned long *eba) { int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num); struct ipu_prg *prg = ipu_chan->ipu->prg_priv; @@ -296,14 +297,10 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, return ret; ipu_pre_configure(prg->pres[chan->used_pre], - width, height, stride, format, *eba); + width, height, stride, format, modifier, *eba); - ret = clk_prepare_enable(prg->clk_ipg); - if (ret) { - ipu_prg_put_pre(prg, prg_chan); - return ret; - } + pm_runtime_get_sync(prg->dev); val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK; writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan)); @@ -336,7 +333,7 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan, (val & IPU_PRG_STATUS_BUFFER1_READY(prg_chan)), 5, 1000); - clk_disable_unprepare(prg->clk_ipg); + pm_runtime_put(prg->dev); chan->enabled = true; return 0; @@ -384,6 +381,12 @@ static int ipu_prg_probe(struct platform_device *pdev) if (ret) return ret; + ret = clk_prepare_enable(prg->clk_axi); + if (ret) { + clk_disable_unprepare(prg->clk_ipg); + return ret; + } + /* init to free running mode */ val = readl(prg->regs + IPU_PRG_CTL); val |= IPU_PRG_CTL_SHADOW_EN; @@ -392,7 +395,8 @@ static int ipu_prg_probe(struct platform_device *pdev) /* disable address threshold */ writel(0xffffffff, prg->regs + IPU_PRG_THD); - clk_disable_unprepare(prg->clk_ipg); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); prg->dev = dev; platform_set_drvdata(pdev, prg); @@ -414,6 +418,40 @@ static int ipu_prg_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int prg_suspend(struct device *dev) +{ + struct ipu_prg *prg = dev_get_drvdata(dev); + + clk_disable_unprepare(prg->clk_axi); + clk_disable_unprepare(prg->clk_ipg); + + return 0; +} + +static int prg_resume(struct device *dev) +{ + struct ipu_prg *prg = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(prg->clk_ipg); + if (ret) + return ret; + + ret = clk_prepare_enable(prg->clk_axi); + if (ret) { + clk_disable_unprepare(prg->clk_ipg); + return ret; + } + + return 0; +} +#endif + +static const struct dev_pm_ops prg_pm_ops = { + SET_RUNTIME_PM_OPS(prg_suspend, prg_resume, NULL) +}; + static const struct of_device_id ipu_prg_dt_ids[] = { { .compatible = "fsl,imx6qp-prg", }, { /* sentinel */ }, @@ -424,6 +462,7 @@ struct platform_driver ipu_prg_drv = { .remove = ipu_prg_remove, .driver = { .name = "imx-ipu-prg", + .pm = &prg_pm_ops, .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 ac4b8d658500..d6beee99b6b8 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -269,8 +269,8 @@ 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); + unsigned int height, unsigned int stride, u32 format, + uint64_t modifier, 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, |