brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · c3561fc Raw
347 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * i.MX6 Video Data Order Adapter (VDOA)4 *5 * Copyright (C) 2014 Philipp Zabel6 * Copyright (C) 2016 Pengutronix, Michael Tretter <kernel@pengutronix.de>7 */8 9#include <linux/clk.h>10#include <linux/device.h>11#include <linux/interrupt.h>12#include <linux/module.h>13#include <linux/mod_devicetable.h>14#include <linux/dma-mapping.h>15#include <linux/platform_device.h>16#include <linux/videodev2.h>17#include <linux/slab.h>18 19#include "imx-vdoa.h"20 21#define VDOA_NAME "imx-vdoa"22 23#define VDOAC		0x0024#define VDOASRR		0x0425#define VDOAIE		0x0826#define VDOAIST		0x0c27#define VDOAFP		0x1028#define VDOAIEBA00	0x1429#define VDOAIEBA01	0x1830#define VDOAIEBA02	0x1c31#define VDOAIEBA10	0x2032#define VDOAIEBA11	0x2433#define VDOAIEBA12	0x2834#define VDOASL		0x2c35#define VDOAIUBO	0x3036#define VDOAVEBA0	0x3437#define VDOAVEBA1	0x3838#define VDOAVEBA2	0x3c39#define VDOAVUBO	0x4040#define VDOASR		0x4441 42#define VDOAC_ISEL		BIT(6)43#define VDOAC_PFS		BIT(5)44#define VDOAC_SO		BIT(4)45#define VDOAC_SYNC		BIT(3)46#define VDOAC_NF		BIT(2)47#define VDOAC_BNDM_MASK		0x348#define VDOAC_BAND_HEIGHT_8	0x049#define VDOAC_BAND_HEIGHT_16	0x150#define VDOAC_BAND_HEIGHT_32	0x251 52#define VDOASRR_START		BIT(1)53#define VDOASRR_SWRST		BIT(0)54 55#define VDOAIE_EITERR		BIT(1)56#define VDOAIE_EIEOT		BIT(0)57 58#define VDOAIST_TERR		BIT(1)59#define VDOAIST_EOT		BIT(0)60 61#define VDOAFP_FH_MASK		(0x1fff << 16)62#define VDOAFP_FW_MASK		(0x3fff)63 64#define VDOASL_VSLY_MASK	(0x3fff << 16)65#define VDOASL_ISLY_MASK	(0x7fff)66 67#define VDOASR_ERRW		BIT(4)68#define VDOASR_EOB		BIT(3)69#define VDOASR_CURRENT_FRAME	(0x3 << 1)70#define VDOASR_CURRENT_BUFFER	BIT(1)71 72enum {73	V4L2_M2M_SRC = 0,74	V4L2_M2M_DST = 1,75};76 77struct vdoa_data {78	struct vdoa_ctx		*curr_ctx;79	struct device		*dev;80	struct clk		*vdoa_clk;81	void __iomem		*regs;82};83 84struct vdoa_q_data {85	unsigned int	width;86	unsigned int	height;87	unsigned int	bytesperline;88	unsigned int	sizeimage;89	u32		pixelformat;90};91 92struct vdoa_ctx {93	struct vdoa_data	*vdoa;94	struct completion	completion;95	struct vdoa_q_data	q_data[2];96	unsigned int		submitted_job;97	unsigned int		completed_job;98};99 100static irqreturn_t vdoa_irq_handler(int irq, void *data)101{102	struct vdoa_data *vdoa = data;103	struct vdoa_ctx *curr_ctx;104	u32 val;105 106	/* Disable interrupts */107	writel(0, vdoa->regs + VDOAIE);108 109	curr_ctx = vdoa->curr_ctx;110	if (!curr_ctx) {111		dev_warn(vdoa->dev,112			"Instance released before the end of transaction\n");113		return IRQ_HANDLED;114	}115 116	val = readl(vdoa->regs + VDOAIST);117	writel(val, vdoa->regs + VDOAIST);118	if (val & VDOAIST_TERR) {119		val = readl(vdoa->regs + VDOASR) & VDOASR_ERRW;120		dev_err(vdoa->dev, "AXI %s error\n", val ? "write" : "read");121	} else if (!(val & VDOAIST_EOT)) {122		dev_warn(vdoa->dev, "Spurious interrupt\n");123	}124	curr_ctx->completed_job++;125	complete(&curr_ctx->completion);126 127	return IRQ_HANDLED;128}129 130int vdoa_wait_for_completion(struct vdoa_ctx *ctx)131{132	struct vdoa_data *vdoa = ctx->vdoa;133 134	if (ctx->submitted_job == ctx->completed_job)135		return 0;136 137	if (!wait_for_completion_timeout(&ctx->completion,138					 msecs_to_jiffies(300))) {139		dev_err(vdoa->dev,140			"Timeout waiting for transfer result\n");141		return -ETIMEDOUT;142	}143 144	return 0;145}146EXPORT_SYMBOL(vdoa_wait_for_completion);147 148void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src)149{150	struct vdoa_q_data *src_q_data, *dst_q_data;151	struct vdoa_data *vdoa = ctx->vdoa;152	u32 val;153 154	if (vdoa->curr_ctx)155		vdoa_wait_for_completion(vdoa->curr_ctx);156 157	vdoa->curr_ctx = ctx;158 159	reinit_completion(&ctx->completion);160	ctx->submitted_job++;161 162	src_q_data = &ctx->q_data[V4L2_M2M_SRC];163	dst_q_data = &ctx->q_data[V4L2_M2M_DST];164 165	/* Progressive, no sync, 1 frame per run */166	if (dst_q_data->pixelformat == V4L2_PIX_FMT_YUYV)167		val = VDOAC_PFS;168	else169		val = 0;170	writel(val, vdoa->regs + VDOAC);171 172	writel(dst_q_data->height << 16 | dst_q_data->width,173	       vdoa->regs + VDOAFP);174 175	val = dst;176	writel(val, vdoa->regs + VDOAIEBA00);177 178	writel(src_q_data->bytesperline << 16 | dst_q_data->bytesperline,179	       vdoa->regs + VDOASL);180 181	if (dst_q_data->pixelformat == V4L2_PIX_FMT_NV12 ||182	    dst_q_data->pixelformat == V4L2_PIX_FMT_NV21)183		val = dst_q_data->bytesperline * dst_q_data->height;184	else185		val = 0;186	writel(val, vdoa->regs + VDOAIUBO);187 188	val = src;189	writel(val, vdoa->regs + VDOAVEBA0);190	val = round_up(src_q_data->bytesperline * src_q_data->height, 4096);191	writel(val, vdoa->regs + VDOAVUBO);192 193	/* Enable interrupts and start transfer */194	writel(VDOAIE_EITERR | VDOAIE_EIEOT, vdoa->regs + VDOAIE);195	writel(VDOASRR_START, vdoa->regs + VDOASRR);196}197EXPORT_SYMBOL(vdoa_device_run);198 199struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa)200{201	struct vdoa_ctx *ctx;202	int err;203 204	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);205	if (!ctx)206		return NULL;207 208	err = clk_prepare_enable(vdoa->vdoa_clk);209	if (err) {210		kfree(ctx);211		return NULL;212	}213 214	init_completion(&ctx->completion);215	ctx->vdoa = vdoa;216 217	return ctx;218}219EXPORT_SYMBOL(vdoa_context_create);220 221void vdoa_context_destroy(struct vdoa_ctx *ctx)222{223	struct vdoa_data *vdoa = ctx->vdoa;224 225	if (vdoa->curr_ctx == ctx) {226		vdoa_wait_for_completion(vdoa->curr_ctx);227		vdoa->curr_ctx = NULL;228	}229 230	clk_disable_unprepare(vdoa->vdoa_clk);231	kfree(ctx);232}233EXPORT_SYMBOL(vdoa_context_destroy);234 235int vdoa_context_configure(struct vdoa_ctx *ctx,236			   unsigned int width, unsigned int height,237			   u32 pixelformat)238{239	struct vdoa_q_data *src_q_data;240	struct vdoa_q_data *dst_q_data;241 242	if (width < 16 || width  > 8192 || width % 16 != 0 ||243	    height < 16 || height > 4096 || height % 16 != 0)244		return -EINVAL;245 246	if (pixelformat != V4L2_PIX_FMT_YUYV &&247	    pixelformat != V4L2_PIX_FMT_NV12)248		return -EINVAL;249 250	/* If no context is passed, only check if the format is valid */251	if (!ctx)252		return 0;253 254	src_q_data = &ctx->q_data[V4L2_M2M_SRC];255	dst_q_data = &ctx->q_data[V4L2_M2M_DST];256 257	src_q_data->width = width;258	src_q_data->height = height;259	src_q_data->bytesperline = width;260	src_q_data->sizeimage =261		round_up(src_q_data->bytesperline * height, 4096) +262		src_q_data->bytesperline * height / 2;263 264	dst_q_data->width = width;265	dst_q_data->height = height;266	dst_q_data->pixelformat = pixelformat;267	switch (pixelformat) {268	case V4L2_PIX_FMT_YUYV:269		dst_q_data->bytesperline = width * 2;270		dst_q_data->sizeimage = dst_q_data->bytesperline * height;271		break;272	case V4L2_PIX_FMT_NV12:273	default:274		dst_q_data->bytesperline = width;275		dst_q_data->sizeimage =276			dst_q_data->bytesperline * height * 3 / 2;277		break;278	}279 280	return 0;281}282EXPORT_SYMBOL(vdoa_context_configure);283 284static int vdoa_probe(struct platform_device *pdev)285{286	struct vdoa_data *vdoa;287	int ret;288 289	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));290	if (ret) {291		dev_err(&pdev->dev, "DMA enable failed\n");292		return ret;293	}294 295	vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL);296	if (!vdoa)297		return -ENOMEM;298 299	vdoa->dev = &pdev->dev;300 301	vdoa->vdoa_clk = devm_clk_get(vdoa->dev, NULL);302	if (IS_ERR(vdoa->vdoa_clk)) {303		dev_err(vdoa->dev, "Failed to get clock\n");304		return PTR_ERR(vdoa->vdoa_clk);305	}306 307	vdoa->regs = devm_platform_ioremap_resource(pdev, 0);308	if (IS_ERR(vdoa->regs))309		return PTR_ERR(vdoa->regs);310 311	ret = platform_get_irq(pdev, 0);312	if (ret < 0)313		return ret;314	ret = devm_request_threaded_irq(&pdev->dev, ret, NULL,315					vdoa_irq_handler, IRQF_ONESHOT,316					"vdoa", vdoa);317	if (ret < 0) {318		dev_err(vdoa->dev, "Failed to get irq\n");319		return ret;320	}321 322	platform_set_drvdata(pdev, vdoa);323 324	return 0;325}326 327static const struct of_device_id vdoa_dt_ids[] = {328	{ .compatible = "fsl,imx6q-vdoa" },329	{}330};331MODULE_DEVICE_TABLE(of, vdoa_dt_ids);332 333static struct platform_driver vdoa_driver = {334	.probe		= vdoa_probe,335	.driver		= {336		.name	= VDOA_NAME,337		.of_match_table = vdoa_dt_ids,338	},339};340 341module_platform_driver(vdoa_driver);342 343MODULE_DESCRIPTION("Video Data Order Adapter");344MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>");345MODULE_ALIAS("platform:imx-vdoa");346MODULE_LICENSE("GPL");347