imx-vdoa.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * i.MX6 Video Data Order Adapter (VDOA)
  3. *
  4. * Copyright (C) 2014 Philipp Zabel
  5. * Copyright (C) 2016 Pengutronix, Michael Tretter <kernel@pengutronix.de>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2, as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include <linux/clk.h>
  17. #include <linux/device.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/module.h>
  20. #include <linux/dma-mapping.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/videodev2.h>
  23. #include <linux/slab.h>
  24. #include "imx-vdoa.h"
  25. #define VDOA_NAME "imx-vdoa"
  26. #define VDOAC 0x00
  27. #define VDOASRR 0x04
  28. #define VDOAIE 0x08
  29. #define VDOAIST 0x0c
  30. #define VDOAFP 0x10
  31. #define VDOAIEBA00 0x14
  32. #define VDOAIEBA01 0x18
  33. #define VDOAIEBA02 0x1c
  34. #define VDOAIEBA10 0x20
  35. #define VDOAIEBA11 0x24
  36. #define VDOAIEBA12 0x28
  37. #define VDOASL 0x2c
  38. #define VDOAIUBO 0x30
  39. #define VDOAVEBA0 0x34
  40. #define VDOAVEBA1 0x38
  41. #define VDOAVEBA2 0x3c
  42. #define VDOAVUBO 0x40
  43. #define VDOASR 0x44
  44. #define VDOAC_ISEL BIT(6)
  45. #define VDOAC_PFS BIT(5)
  46. #define VDOAC_SO BIT(4)
  47. #define VDOAC_SYNC BIT(3)
  48. #define VDOAC_NF BIT(2)
  49. #define VDOAC_BNDM_MASK 0x3
  50. #define VDOAC_BAND_HEIGHT_8 0x0
  51. #define VDOAC_BAND_HEIGHT_16 0x1
  52. #define VDOAC_BAND_HEIGHT_32 0x2
  53. #define VDOASRR_START BIT(1)
  54. #define VDOASRR_SWRST BIT(0)
  55. #define VDOAIE_EITERR BIT(1)
  56. #define VDOAIE_EIEOT BIT(0)
  57. #define VDOAIST_TERR BIT(1)
  58. #define VDOAIST_EOT BIT(0)
  59. #define VDOAFP_FH_MASK (0x1fff << 16)
  60. #define VDOAFP_FW_MASK (0x3fff)
  61. #define VDOASL_VSLY_MASK (0x3fff << 16)
  62. #define VDOASL_ISLY_MASK (0x7fff)
  63. #define VDOASR_ERRW BIT(4)
  64. #define VDOASR_EOB BIT(3)
  65. #define VDOASR_CURRENT_FRAME (0x3 << 1)
  66. #define VDOASR_CURRENT_BUFFER BIT(1)
  67. enum {
  68. V4L2_M2M_SRC = 0,
  69. V4L2_M2M_DST = 1,
  70. };
  71. struct vdoa_data {
  72. struct vdoa_ctx *curr_ctx;
  73. struct device *dev;
  74. struct clk *vdoa_clk;
  75. void __iomem *regs;
  76. };
  77. struct vdoa_q_data {
  78. unsigned int width;
  79. unsigned int height;
  80. unsigned int bytesperline;
  81. unsigned int sizeimage;
  82. u32 pixelformat;
  83. };
  84. struct vdoa_ctx {
  85. struct vdoa_data *vdoa;
  86. struct completion completion;
  87. struct vdoa_q_data q_data[2];
  88. unsigned int submitted_job;
  89. unsigned int completed_job;
  90. };
  91. static irqreturn_t vdoa_irq_handler(int irq, void *data)
  92. {
  93. struct vdoa_data *vdoa = data;
  94. struct vdoa_ctx *curr_ctx;
  95. u32 val;
  96. /* Disable interrupts */
  97. writel(0, vdoa->regs + VDOAIE);
  98. curr_ctx = vdoa->curr_ctx;
  99. if (!curr_ctx) {
  100. dev_warn(vdoa->dev,
  101. "Instance released before the end of transaction\n");
  102. return IRQ_HANDLED;
  103. }
  104. val = readl(vdoa->regs + VDOAIST);
  105. writel(val, vdoa->regs + VDOAIST);
  106. if (val & VDOAIST_TERR) {
  107. val = readl(vdoa->regs + VDOASR) & VDOASR_ERRW;
  108. dev_err(vdoa->dev, "AXI %s error\n", val ? "write" : "read");
  109. } else if (!(val & VDOAIST_EOT)) {
  110. dev_warn(vdoa->dev, "Spurious interrupt\n");
  111. }
  112. curr_ctx->completed_job++;
  113. complete(&curr_ctx->completion);
  114. return IRQ_HANDLED;
  115. }
  116. int vdoa_wait_for_completion(struct vdoa_ctx *ctx)
  117. {
  118. struct vdoa_data *vdoa = ctx->vdoa;
  119. if (ctx->submitted_job == ctx->completed_job)
  120. return 0;
  121. if (!wait_for_completion_timeout(&ctx->completion,
  122. msecs_to_jiffies(300))) {
  123. dev_err(vdoa->dev,
  124. "Timeout waiting for transfer result\n");
  125. return -ETIMEDOUT;
  126. }
  127. return 0;
  128. }
  129. EXPORT_SYMBOL(vdoa_wait_for_completion);
  130. void vdoa_device_run(struct vdoa_ctx *ctx, dma_addr_t dst, dma_addr_t src)
  131. {
  132. struct vdoa_q_data *src_q_data, *dst_q_data;
  133. struct vdoa_data *vdoa = ctx->vdoa;
  134. u32 val;
  135. if (vdoa->curr_ctx)
  136. vdoa_wait_for_completion(vdoa->curr_ctx);
  137. vdoa->curr_ctx = ctx;
  138. reinit_completion(&ctx->completion);
  139. ctx->submitted_job++;
  140. src_q_data = &ctx->q_data[V4L2_M2M_SRC];
  141. dst_q_data = &ctx->q_data[V4L2_M2M_DST];
  142. /* Progressive, no sync, 1 frame per run */
  143. if (dst_q_data->pixelformat == V4L2_PIX_FMT_YUYV)
  144. val = VDOAC_PFS;
  145. else
  146. val = 0;
  147. writel(val, vdoa->regs + VDOAC);
  148. writel(dst_q_data->height << 16 | dst_q_data->width,
  149. vdoa->regs + VDOAFP);
  150. val = dst;
  151. writel(val, vdoa->regs + VDOAIEBA00);
  152. writel(src_q_data->bytesperline << 16 | dst_q_data->bytesperline,
  153. vdoa->regs + VDOASL);
  154. if (dst_q_data->pixelformat == V4L2_PIX_FMT_NV12 ||
  155. dst_q_data->pixelformat == V4L2_PIX_FMT_NV21)
  156. val = dst_q_data->bytesperline * dst_q_data->height;
  157. else
  158. val = 0;
  159. writel(val, vdoa->regs + VDOAIUBO);
  160. val = src;
  161. writel(val, vdoa->regs + VDOAVEBA0);
  162. val = round_up(src_q_data->bytesperline * src_q_data->height, 4096);
  163. writel(val, vdoa->regs + VDOAVUBO);
  164. /* Enable interrupts and start transfer */
  165. writel(VDOAIE_EITERR | VDOAIE_EIEOT, vdoa->regs + VDOAIE);
  166. writel(VDOASRR_START, vdoa->regs + VDOASRR);
  167. }
  168. EXPORT_SYMBOL(vdoa_device_run);
  169. struct vdoa_ctx *vdoa_context_create(struct vdoa_data *vdoa)
  170. {
  171. struct vdoa_ctx *ctx;
  172. int err;
  173. ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
  174. if (!ctx)
  175. return NULL;
  176. err = clk_prepare_enable(vdoa->vdoa_clk);
  177. if (err) {
  178. kfree(ctx);
  179. return NULL;
  180. }
  181. init_completion(&ctx->completion);
  182. ctx->vdoa = vdoa;
  183. return ctx;
  184. }
  185. EXPORT_SYMBOL(vdoa_context_create);
  186. void vdoa_context_destroy(struct vdoa_ctx *ctx)
  187. {
  188. struct vdoa_data *vdoa = ctx->vdoa;
  189. if (vdoa->curr_ctx == ctx) {
  190. vdoa_wait_for_completion(vdoa->curr_ctx);
  191. vdoa->curr_ctx = NULL;
  192. }
  193. clk_disable_unprepare(vdoa->vdoa_clk);
  194. kfree(ctx);
  195. }
  196. EXPORT_SYMBOL(vdoa_context_destroy);
  197. int vdoa_context_configure(struct vdoa_ctx *ctx,
  198. unsigned int width, unsigned int height,
  199. u32 pixelformat)
  200. {
  201. struct vdoa_q_data *src_q_data;
  202. struct vdoa_q_data *dst_q_data;
  203. if (width < 16 || width > 8192 || width % 16 != 0 ||
  204. height < 16 || height > 4096 || height % 16 != 0)
  205. return -EINVAL;
  206. if (pixelformat != V4L2_PIX_FMT_YUYV &&
  207. pixelformat != V4L2_PIX_FMT_NV12)
  208. return -EINVAL;
  209. /* If no context is passed, only check if the format is valid */
  210. if (!ctx)
  211. return 0;
  212. src_q_data = &ctx->q_data[V4L2_M2M_SRC];
  213. dst_q_data = &ctx->q_data[V4L2_M2M_DST];
  214. src_q_data->width = width;
  215. src_q_data->height = height;
  216. src_q_data->bytesperline = width;
  217. src_q_data->sizeimage =
  218. round_up(src_q_data->bytesperline * height, 4096) +
  219. src_q_data->bytesperline * height / 2;
  220. dst_q_data->width = width;
  221. dst_q_data->height = height;
  222. dst_q_data->pixelformat = pixelformat;
  223. switch (pixelformat) {
  224. case V4L2_PIX_FMT_YUYV:
  225. dst_q_data->bytesperline = width * 2;
  226. dst_q_data->sizeimage = dst_q_data->bytesperline * height;
  227. break;
  228. case V4L2_PIX_FMT_NV12:
  229. default:
  230. dst_q_data->bytesperline = width;
  231. dst_q_data->sizeimage =
  232. dst_q_data->bytesperline * height * 3 / 2;
  233. break;
  234. }
  235. return 0;
  236. }
  237. EXPORT_SYMBOL(vdoa_context_configure);
  238. static int vdoa_probe(struct platform_device *pdev)
  239. {
  240. struct vdoa_data *vdoa;
  241. struct resource *res;
  242. int ret;
  243. dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
  244. vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL);
  245. if (!vdoa)
  246. return -ENOMEM;
  247. vdoa->dev = &pdev->dev;
  248. vdoa->vdoa_clk = devm_clk_get(vdoa->dev, NULL);
  249. if (IS_ERR(vdoa->vdoa_clk)) {
  250. dev_err(vdoa->dev, "Failed to get clock\n");
  251. return PTR_ERR(vdoa->vdoa_clk);
  252. }
  253. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  254. vdoa->regs = devm_ioremap_resource(vdoa->dev, res);
  255. if (IS_ERR(vdoa->regs))
  256. return PTR_ERR(vdoa->regs);
  257. res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  258. if (!res)
  259. return -EINVAL;
  260. ret = devm_request_threaded_irq(&pdev->dev, res->start, NULL,
  261. vdoa_irq_handler, IRQF_ONESHOT,
  262. "vdoa", vdoa);
  263. if (ret < 0) {
  264. dev_err(vdoa->dev, "Failed to get irq\n");
  265. return ret;
  266. }
  267. platform_set_drvdata(pdev, vdoa);
  268. return 0;
  269. }
  270. static int vdoa_remove(struct platform_device *pdev)
  271. {
  272. return 0;
  273. }
  274. static const struct of_device_id vdoa_dt_ids[] = {
  275. { .compatible = "fsl,imx6q-vdoa" },
  276. {}
  277. };
  278. MODULE_DEVICE_TABLE(of, vdoa_dt_ids);
  279. static struct platform_driver vdoa_driver = {
  280. .probe = vdoa_probe,
  281. .remove = vdoa_remove,
  282. .driver = {
  283. .name = VDOA_NAME,
  284. .of_match_table = vdoa_dt_ids,
  285. },
  286. };
  287. module_platform_driver(vdoa_driver);
  288. MODULE_DESCRIPTION("Video Data Order Adapter");
  289. MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>");
  290. MODULE_ALIAS("platform:imx-vdoa");
  291. MODULE_LICENSE("GPL");