diff options
Diffstat (limited to 'drivers/gpu/ipu-v3/ipu-common.c')
| -rw-r--r-- | drivers/gpu/ipu-v3/ipu-common.c | 180 |
1 files changed, 41 insertions, 139 deletions
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 960d816ad7f7..333f36e0a715 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1,16 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that 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 <linux/module.h> #include <linux/export.h> @@ -27,7 +18,7 @@ #include <linux/irq.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/of_graph.h> #include <drm/drm_fourcc.h> @@ -122,11 +113,19 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: return IPUV3_COLORSPACE_YUV; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_BGRA32: + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_RGBA32: + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - case V4L2_PIX_FMT_RGB565: return IPUV3_COLORSPACE_RGB; default: return IPUV3_COLORSPACE_UNKNOWN; @@ -134,71 +133,6 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) } EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); -bool ipu_pixelformat_is_planar(u32 pixelformat) -{ - switch (pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - return true; - } - - return false; -} -EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar); - -enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code) -{ - switch (mbus_code & 0xf000) { - case 0x1000: - return IPUV3_COLORSPACE_RGB; - case 0x2000: - return IPUV3_COLORSPACE_YUV; - default: - return IPUV3_COLORSPACE_UNKNOWN; - } -} -EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace); - -int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat) -{ - switch (pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - /* - * for the planar YUV formats, the stride passed to - * cpmem must be the stride in bytes of the Y plane. - * And all the planar YUV formats have an 8-bit - * Y component. - */ - return (8 * pixel_stride) >> 3; - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_UYVY: - return (16 * pixel_stride) >> 3; - case V4L2_PIX_FMT_BGR24: - case V4L2_PIX_FMT_RGB24: - return (24 * pixel_stride) >> 3; - case V4L2_PIX_FMT_BGR32: - case V4L2_PIX_FMT_RGB32: - return (32 * pixel_stride) >> 3; - default: - break; - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(ipu_stride_to_bytes); - int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees, bool hflip, bool vflip) { @@ -231,38 +165,6 @@ int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees, } EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode); -int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode, - bool hflip, bool vflip) -{ - u32 r90, vf, hf; - - r90 = ((u32)mode >> 2) & 0x1; - hf = ((u32)mode >> 1) & 0x1; - vf = ((u32)mode >> 0) & 0x1; - hf ^= (u32)hflip; - vf ^= (u32)vflip; - - switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) { - case IPU_ROTATE_NONE: - *degrees = 0; - break; - case IPU_ROTATE_90_RIGHT: - *degrees = 90; - break; - case IPU_ROTATE_180: - *degrees = 180; - break; - case IPU_ROTATE_90_LEFT: - *degrees = 270; - break; - default: - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees); - struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) { struct ipuv3_channel *channel; @@ -405,6 +307,14 @@ int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts) return -EINVAL; } + /* + * IPUv3EX / i.MX51 has a different register layout, and on IPUv3M / + * i.MX53 channel arbitration locking doesn't seem to work properly. + * Allow enabling the lock feature on IPUv3H / i.MX6 only. + */ + if (bursts && ipu->ipu_type != IPUV3H) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) { if (channel->num == idmac_lock_en_info[i].chnum) break; @@ -574,12 +484,6 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel) } EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel); -bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno) -{ - return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno)); -} -EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy); - int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms) { struct ipu_soc *ipu = channel->ipu; @@ -886,8 +790,8 @@ static struct ipu_devtype ipu_type_imx51 = { .cpmem_ofs = 0x1f000000, .srm_ofs = 0x1f040000, .tpm_ofs = 0x1f060000, - .csi0_ofs = 0x1f030000, - .csi1_ofs = 0x1f038000, + .csi0_ofs = 0x1e030000, + .csi1_ofs = 0x1e038000, .ic_ofs = 0x1e020000, .disp0_ofs = 0x1e040000, .disp1_ofs = 0x1e048000, @@ -902,8 +806,8 @@ static struct ipu_devtype ipu_type_imx53 = { .cpmem_ofs = 0x07000000, .srm_ofs = 0x07040000, .tpm_ofs = 0x07060000, - .csi0_ofs = 0x07030000, - .csi1_ofs = 0x07038000, + .csi0_ofs = 0x06030000, + .csi1_ofs = 0x06038000, .ic_ofs = 0x06020000, .disp0_ofs = 0x06040000, .disp1_ofs = 0x06048000, @@ -1061,19 +965,16 @@ err_cpmem: static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs) { unsigned long status; - int i, bit, irq; + int i, bit; for (i = 0; i < num_regs; i++) { status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i])); status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i])); - for_each_set_bit(bit, &status, 32) { - irq = irq_linear_revmap(ipu->domain, - regs[i] * 32 + bit); - if (irq) - generic_handle_irq(irq); - } + for_each_set_bit(bit, &status, 32) + generic_handle_domain_irq(ipu->domain, + regs[i] * 32 + bit); } } @@ -1081,7 +982,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); @@ -1094,7 +995,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); @@ -1107,7 +1008,7 @@ int ipu_map_irq(struct ipu_soc *ipu, int irq) { int virq; - virq = irq_linear_revmap(ipu->domain, irq); + virq = irq_find_mapping(ipu->domain, irq); if (!virq) virq = irq_create_mapping(ipu->domain, irq); @@ -1217,8 +1118,8 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) of_node = of_graph_get_port_by_id(dev->of_node, i); if (!of_node) { dev_info(dev, - "no port@%d node in %s, not using %s%d\n", - i, dev->of_node->full_name, + "no port@%d node in %pOF, not using %s%d\n", + i, dev->of_node, (i / 2) ? "DI" : "CSI", i % 2); continue; } @@ -1226,6 +1127,7 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) pdev = platform_device_alloc(reg->name, id++); if (!pdev) { ret = -ENOMEM; + of_node_put(of_node); goto err_register; } @@ -1267,8 +1169,8 @@ static int ipu_irq_init(struct ipu_soc *ipu) }; int ret, i; - ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS, - &irq_generic_chip_ops, ipu); + ipu->domain = irq_domain_create_linear(of_fwnode_handle(ipu->dev->of_node), IPU_NUM_IRQS, + &irq_generic_chip_ops, ipu); if (!ipu->domain) { dev_err(ipu->dev, "failed to add irq domain\n"); return -ENODEV; @@ -1317,7 +1219,7 @@ static void ipu_irq_exit(struct ipu_soc *ipu) /* TODO: remove irq_domain_generic_chips */ for (i = 0; i < IPU_NUM_IRQS; i++) { - irq = irq_linear_revmap(ipu->domain, i); + irq = irq_find_mapping(ipu->domain, i); if (irq) irq_dispose_mapping(irq); } @@ -1393,6 +1295,8 @@ static int ipu_probe(struct platform_device *pdev) return -ENODEV; ipu->id = of_alias_get_id(np, "ipu"); + if (ipu->id < 0) + ipu->id = 0; if (of_device_is_compatible(np, "fsl,imx6qp-ipu") && IS_ENABLED(CONFIG_DRM)) { @@ -1508,7 +1412,7 @@ out_failed_reset: return ret; } -static int ipu_remove(struct platform_device *pdev) +static void ipu_remove(struct platform_device *pdev) { struct ipu_soc *ipu = platform_get_drvdata(pdev); @@ -1517,8 +1421,6 @@ static int ipu_remove(struct platform_device *pdev) ipu_irq_exit(ipu); clk_disable_unprepare(ipu->clk); - - return 0; } static struct platform_driver imx_ipu_driver = { |
