0084-media-starfive-Add-video-driver.patch 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. From 70a588f7daefe34697ccd04fa6ac3a6d4b63be88 Mon Sep 17 00:00:00 2001
  2. From: Jack Zhu <[email protected]>
  3. Date: Fri, 12 May 2023 18:28:42 +0800
  4. Subject: [PATCH 084/122] media: starfive: Add video driver
  5. Add video driver for StarFive Camera Subsystem.
  6. Signed-off-by: Jack Zhu <[email protected]>
  7. ---
  8. drivers/media/platform/starfive/Makefile | 3 +-
  9. drivers/media/platform/starfive/stf_video.c | 864 ++++++++++++++++++++
  10. drivers/media/platform/starfive/stf_video.h | 95 +++
  11. 3 files changed, 961 insertions(+), 1 deletion(-)
  12. create mode 100644 drivers/media/platform/starfive/stf_video.c
  13. create mode 100644 drivers/media/platform/starfive/stf_video.h
  14. --- a/drivers/media/platform/starfive/Makefile
  15. +++ b/drivers/media/platform/starfive/Makefile
  16. @@ -4,6 +4,7 @@
  17. #
  18. starfive-camss-objs += \
  19. - stf_camss.o
  20. + stf_camss.o \
  21. + stf_video.o
  22. obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o \
  23. --- /dev/null
  24. +++ b/drivers/media/platform/starfive/stf_video.c
  25. @@ -0,0 +1,864 @@
  26. +// SPDX-License-Identifier: GPL-2.0
  27. +/*
  28. + * stf_video.c
  29. + *
  30. + * StarFive Camera Subsystem - V4L2 device node
  31. + *
  32. + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
  33. + */
  34. +
  35. +#include <media/media-entity.h>
  36. +#include <media/v4l2-ctrls.h>
  37. +#include <media/v4l2-event.h>
  38. +#include <media/v4l2-mc.h>
  39. +#include <media/videobuf2-dma-contig.h>
  40. +
  41. +#include "stf_camss.h"
  42. +#include "stf_video.h"
  43. +
  44. +static const struct stfcamss_format_info formats_pix_wr[] = {
  45. + { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 1,
  46. + { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  47. + { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 1,
  48. + { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  49. + { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 1,
  50. + { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  51. + { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 1,
  52. + { { 1, 1 } }, { { 1, 1 } }, { 10 } },
  53. +};
  54. +
  55. +static const struct stfcamss_format_info formats_pix_isp[] = {
  56. + { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1,
  57. + { { 1, 1 } }, { { 2, 3 } }, { 8 } },
  58. +};
  59. +
  60. +/* -----------------------------------------------------------------------------
  61. + * Helper functions
  62. + */
  63. +
  64. +static int video_find_format(u32 code, u32 pixelformat,
  65. + const struct stfcamss_format_info *formats,
  66. + unsigned int nformats)
  67. +{
  68. + int i;
  69. +
  70. + for (i = 0; i < nformats; i++) {
  71. + if (formats[i].code == code &&
  72. + formats[i].pixelformat == pixelformat)
  73. + return i;
  74. + }
  75. +
  76. + for (i = 0; i < nformats; i++)
  77. + if (formats[i].code == code)
  78. + return i;
  79. +
  80. + for (i = 0; i < nformats; i++)
  81. + if (formats[i].pixelformat == pixelformat)
  82. + return i;
  83. +
  84. + return -EINVAL;
  85. +}
  86. +
  87. +static int __video_try_fmt(struct stfcamss_video *video, struct v4l2_format *f)
  88. +{
  89. + struct v4l2_pix_format *pix;
  90. + const struct stfcamss_format_info *fi;
  91. + u32 width, height;
  92. + u32 bpl;
  93. + int i;
  94. +
  95. + pix = &f->fmt.pix;
  96. +
  97. + for (i = 0; i < video->nformats; i++)
  98. + if (pix->pixelformat == video->formats[i].pixelformat)
  99. + break;
  100. +
  101. + if (i == video->nformats)
  102. + i = 0; /* default format */
  103. +
  104. + fi = &video->formats[i];
  105. + width = pix->width;
  106. + height = pix->height;
  107. +
  108. + memset(pix, 0, sizeof(*pix));
  109. +
  110. + pix->pixelformat = fi->pixelformat;
  111. + pix->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
  112. + STFCAMSS_FRAME_MAX_WIDTH);
  113. + pix->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
  114. + STFCAMSS_FRAME_MAX_HEIGHT);
  115. + bpl = pix->width / fi->hsub[0].numerator *
  116. + fi->hsub[0].denominator * fi->bpp[0] / 8;
  117. + bpl = ALIGN(bpl, video->bpl_alignment);
  118. + pix->bytesperline = bpl;
  119. + pix->sizeimage = pix->height / fi->vsub[0].numerator *
  120. + fi->vsub[0].denominator * bpl;
  121. +
  122. + pix->field = V4L2_FIELD_NONE;
  123. + pix->colorspace = V4L2_COLORSPACE_SRGB;
  124. + pix->flags = 0;
  125. + pix->ycbcr_enc =
  126. + V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
  127. + pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
  128. + pix->colorspace,
  129. + pix->ycbcr_enc);
  130. + pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
  131. +
  132. + return 0;
  133. +}
  134. +
  135. +static int stf_video_init_format(struct stfcamss_video *video)
  136. +{
  137. + int ret;
  138. + struct v4l2_format format = {
  139. + .type = video->type,
  140. + .fmt.pix = {
  141. + .width = 1920,
  142. + .height = 1080,
  143. + .pixelformat = V4L2_PIX_FMT_RGB565,
  144. + },
  145. + };
  146. +
  147. + ret = __video_try_fmt(video, &format);
  148. +
  149. + if (ret < 0)
  150. + return ret;
  151. +
  152. + video->active_fmt = format;
  153. +
  154. + return 0;
  155. +}
  156. +
  157. +/* -----------------------------------------------------------------------------
  158. + * Video queue operations
  159. + */
  160. +
  161. +static int video_queue_setup(struct vb2_queue *q,
  162. + unsigned int *num_buffers,
  163. + unsigned int *num_planes,
  164. + unsigned int sizes[],
  165. + struct device *alloc_devs[])
  166. +{
  167. + struct stfcamss_video *video = vb2_get_drv_priv(q);
  168. + const struct v4l2_pix_format *format = &video->active_fmt.fmt.pix;
  169. +
  170. + if (*num_planes) {
  171. + if (*num_planes != 1)
  172. + return -EINVAL;
  173. +
  174. + if (sizes[0] < format->sizeimage)
  175. + return -EINVAL;
  176. + }
  177. +
  178. + *num_planes = 1;
  179. + sizes[0] = format->sizeimage;
  180. + if (!sizes[0])
  181. + dev_err(video->stfcamss->dev,
  182. + "%s: error size is zero!!!\n", __func__);
  183. +
  184. + dev_dbg(video->stfcamss->dev, "planes = %d, size = %d\n",
  185. + *num_planes, sizes[0]);
  186. +
  187. + return 0;
  188. +}
  189. +
  190. +static int video_buf_init(struct vb2_buffer *vb)
  191. +{
  192. + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
  193. + struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
  194. + struct stfcamss_buffer *buffer =
  195. + container_of(vbuf, struct stfcamss_buffer, vb);
  196. + const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix;
  197. + dma_addr_t *paddr;
  198. +
  199. + buffer->sizeimage = 0;
  200. +
  201. + paddr = vb2_plane_cookie(vb, 0);
  202. + buffer->sizeimage = vb2_plane_size(vb, 0);
  203. + buffer->addr[0] = *paddr;
  204. + if (fmt->pixelformat == V4L2_PIX_FMT_NV12 ||
  205. + fmt->pixelformat == V4L2_PIX_FMT_NV21 ||
  206. + fmt->pixelformat == V4L2_PIX_FMT_NV16 ||
  207. + fmt->pixelformat == V4L2_PIX_FMT_NV61)
  208. + buffer->addr[1] =
  209. + buffer->addr[0] + fmt->bytesperline * fmt->height;
  210. +
  211. + return 0;
  212. +}
  213. +
  214. +static int video_buf_prepare(struct vb2_buffer *vb)
  215. +{
  216. + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
  217. + struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
  218. + const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix;
  219. +
  220. + if (fmt->sizeimage > vb2_plane_size(vb, 0)) {
  221. + dev_err(video->stfcamss->dev,
  222. + "sizeimage = %d, plane size = %d\n",
  223. + fmt->sizeimage, (unsigned int)vb2_plane_size(vb, 0));
  224. + return -EINVAL;
  225. + }
  226. + vb2_set_plane_payload(vb, 0, fmt->sizeimage);
  227. +
  228. + vbuf->field = V4L2_FIELD_NONE;
  229. +
  230. + return 0;
  231. +}
  232. +
  233. +static void video_buf_queue(struct vb2_buffer *vb)
  234. +{
  235. + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
  236. + struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
  237. + struct stfcamss_buffer *buffer =
  238. + container_of(vbuf, struct stfcamss_buffer, vb);
  239. +
  240. + video->ops->queue_buffer(video, buffer);
  241. +}
  242. +
  243. +/*
  244. + * video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
  245. + * @mbus: v4l2_mbus_framefmt format (input)
  246. + * @pix: v4l2_pix_format_mplane format (output)
  247. + * @f: a pointer to formats array element to be used for the conversion
  248. + * @alignment: bytesperline alignment value
  249. + *
  250. + * Fill the output pix structure with information from the input mbus format.
  251. + *
  252. + * Return 0 on success or a negative error code otherwise
  253. + */
  254. +static int video_mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
  255. + struct v4l2_pix_format *pix,
  256. + const struct stfcamss_format_info *f,
  257. + unsigned int alignment)
  258. +{
  259. + u32 bytesperline;
  260. +
  261. + memset(pix, 0, sizeof(*pix));
  262. + v4l2_fill_pix_format(pix, mbus);
  263. + pix->pixelformat = f->pixelformat;
  264. + bytesperline = pix->width / f->hsub[0].numerator *
  265. + f->hsub[0].denominator * f->bpp[0] / 8;
  266. + bytesperline = ALIGN(bytesperline, alignment);
  267. + pix->bytesperline = bytesperline;
  268. + pix->sizeimage = pix->height / f->vsub[0].numerator *
  269. + f->vsub[0].denominator * bytesperline;
  270. + return 0;
  271. +}
  272. +
  273. +static struct v4l2_subdev *video_remote_subdev(struct stfcamss_video *video,
  274. + u32 *pad)
  275. +{
  276. + struct media_pad *remote;
  277. +
  278. + remote = media_pad_remote_pad_first(&video->pad);
  279. +
  280. + if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
  281. + return NULL;
  282. +
  283. + if (pad)
  284. + *pad = remote->index;
  285. +
  286. + return media_entity_to_v4l2_subdev(remote->entity);
  287. +}
  288. +
  289. +static int video_get_subdev_format(struct stfcamss_video *video,
  290. + struct v4l2_format *format)
  291. +{
  292. + struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix;
  293. + struct v4l2_subdev_format fmt;
  294. + struct v4l2_subdev *subdev;
  295. + u32 pixelformat;
  296. + u32 pad;
  297. + int ret;
  298. +
  299. + subdev = video_remote_subdev(video, &pad);
  300. + if (!subdev)
  301. + return -EPIPE;
  302. +
  303. + fmt.pad = pad;
  304. + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
  305. +
  306. + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
  307. + if (ret)
  308. + return ret;
  309. +
  310. + pixelformat = pix->pixelformat;
  311. + ret = video_find_format(fmt.format.code, pixelformat,
  312. + video->formats, video->nformats);
  313. + if (ret < 0)
  314. + return ret;
  315. +
  316. + format->type = video->type;
  317. +
  318. + return video_mbus_to_pix(&fmt.format, &format->fmt.pix,
  319. + &video->formats[ret], video->bpl_alignment);
  320. +}
  321. +
  322. +static int video_check_format(struct stfcamss_video *video)
  323. +{
  324. + struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix;
  325. + struct v4l2_format format;
  326. + struct v4l2_pix_format *sd_pix = &format.fmt.pix;
  327. + int ret;
  328. +
  329. + sd_pix->pixelformat = pix->pixelformat;
  330. + ret = video_get_subdev_format(video, &format);
  331. + if (ret < 0)
  332. + return ret;
  333. +
  334. + if (pix->pixelformat != sd_pix->pixelformat ||
  335. + pix->height > sd_pix->height ||
  336. + pix->width > sd_pix->width ||
  337. + pix->field != format.fmt.pix.field) {
  338. + dev_err(video->stfcamss->dev,
  339. + "%s, not match:\n"
  340. + "0x%x 0x%x\n0x%x 0x%x\n0x%x 0x%x\n",
  341. + __func__,
  342. + pix->pixelformat, sd_pix->pixelformat,
  343. + pix->height, sd_pix->height,
  344. + pix->field, format.fmt.pix.field);
  345. + return -EPIPE;
  346. + }
  347. +
  348. + return 0;
  349. +}
  350. +
  351. +static int video_start_streaming(struct vb2_queue *q, unsigned int count)
  352. +{
  353. + struct stfcamss_video *video = vb2_get_drv_priv(q);
  354. + struct video_device *vdev = &video->vdev;
  355. + struct media_entity *entity;
  356. + struct media_pad *pad;
  357. + struct v4l2_subdev *subdev;
  358. + int ret;
  359. +
  360. + ret = video_device_pipeline_start(vdev, &video->stfcamss->pipe);
  361. + if (ret < 0) {
  362. + dev_err(video->stfcamss->dev,
  363. + "Failed to media_pipeline_start: %d\n", ret);
  364. + return ret;
  365. + }
  366. +
  367. + ret = video_check_format(video);
  368. + if (ret < 0)
  369. + goto error;
  370. + entity = &vdev->entity;
  371. + while (1) {
  372. + pad = &entity->pads[0];
  373. + if (!(pad->flags & MEDIA_PAD_FL_SINK))
  374. + break;
  375. +
  376. + pad = media_pad_remote_pad_first(pad);
  377. + if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
  378. + break;
  379. +
  380. + entity = pad->entity;
  381. + subdev = media_entity_to_v4l2_subdev(entity);
  382. +
  383. + ret = v4l2_subdev_call(subdev, video, s_stream, 1);
  384. + if (ret < 0 && ret != -ENOIOCTLCMD)
  385. + goto error;
  386. + }
  387. + return 0;
  388. +
  389. +error:
  390. + video_device_pipeline_stop(vdev);
  391. + video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
  392. + return ret;
  393. +}
  394. +
  395. +static void video_stop_streaming(struct vb2_queue *q)
  396. +{
  397. + struct stfcamss_video *video = vb2_get_drv_priv(q);
  398. + struct video_device *vdev = &video->vdev;
  399. + struct media_entity *entity;
  400. + struct media_pad *pad;
  401. + struct v4l2_subdev *subdev;
  402. +
  403. + entity = &vdev->entity;
  404. + while (1) {
  405. + pad = &entity->pads[0];
  406. + if (!(pad->flags & MEDIA_PAD_FL_SINK))
  407. + break;
  408. +
  409. + pad = media_pad_remote_pad_first(pad);
  410. + if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
  411. + break;
  412. +
  413. + entity = pad->entity;
  414. + subdev = media_entity_to_v4l2_subdev(entity);
  415. +
  416. + v4l2_subdev_call(subdev, video, s_stream, 0);
  417. + }
  418. +
  419. + video_device_pipeline_stop(vdev);
  420. + video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
  421. +}
  422. +
  423. +static const struct vb2_ops stf_video_vb2_q_ops = {
  424. + .queue_setup = video_queue_setup,
  425. + .wait_prepare = vb2_ops_wait_prepare,
  426. + .wait_finish = vb2_ops_wait_finish,
  427. + .buf_init = video_buf_init,
  428. + .buf_prepare = video_buf_prepare,
  429. + .buf_queue = video_buf_queue,
  430. + .start_streaming = video_start_streaming,
  431. + .stop_streaming = video_stop_streaming,
  432. +};
  433. +
  434. +/* -----------------------------------------------------------------------------
  435. + * V4L2 ioctls
  436. + */
  437. +
  438. +static int video_querycap(struct file *file, void *fh,
  439. + struct v4l2_capability *cap)
  440. +{
  441. + struct stfcamss_video *video = video_drvdata(file);
  442. +
  443. + strscpy(cap->driver, "stf camss", sizeof(cap->driver));
  444. + strscpy(cap->card, "Starfive Camera Subsystem", sizeof(cap->card));
  445. + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
  446. + dev_name(video->stfcamss->dev));
  447. + return 0;
  448. +}
  449. +
  450. +static int video_get_pfmt_by_index(struct stfcamss_video *video, int ndx)
  451. +{
  452. + int i, j, k;
  453. +
  454. + /* find index "i" of "k"th unique pixelformat in formats array */
  455. + k = -1;
  456. + for (i = 0; i < video->nformats; i++) {
  457. + for (j = 0; j < i; j++) {
  458. + if (video->formats[i].pixelformat ==
  459. + video->formats[j].pixelformat)
  460. + break;
  461. + }
  462. +
  463. + if (j == i)
  464. + k++;
  465. +
  466. + if (k == ndx)
  467. + return i;
  468. + }
  469. +
  470. + return -EINVAL;
  471. +}
  472. +
  473. +static int video_get_pfmt_by_mcode(struct stfcamss_video *video, u32 mcode)
  474. +{
  475. + int i;
  476. +
  477. + for (i = 0; i < video->nformats; i++) {
  478. + if (video->formats[i].code == mcode)
  479. + return i;
  480. + }
  481. +
  482. + return -EINVAL;
  483. +}
  484. +
  485. +static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
  486. +{
  487. + struct stfcamss_video *video = video_drvdata(file);
  488. + int i;
  489. +
  490. + if (f->type != video->type)
  491. + return -EINVAL;
  492. + if (f->index >= video->nformats)
  493. + return -EINVAL;
  494. +
  495. + if (f->mbus_code) {
  496. + /* Each entry in formats[] table has unique mbus_code */
  497. + if (f->index > 0)
  498. + return -EINVAL;
  499. +
  500. + i = video_get_pfmt_by_mcode(video, f->mbus_code);
  501. + } else {
  502. + i = video_get_pfmt_by_index(video, f->index);
  503. + }
  504. +
  505. + if (i < 0)
  506. + return -EINVAL;
  507. +
  508. + f->pixelformat = video->formats[i].pixelformat;
  509. +
  510. + return 0;
  511. +}
  512. +
  513. +static int video_enum_framesizes(struct file *file, void *fh,
  514. + struct v4l2_frmsizeenum *fsize)
  515. +{
  516. + struct stfcamss_video *video = video_drvdata(file);
  517. + int i;
  518. +
  519. + if (fsize->index)
  520. + return -EINVAL;
  521. +
  522. + for (i = 0; i < video->nformats; i++) {
  523. + if (video->formats[i].pixelformat == fsize->pixel_format)
  524. + break;
  525. + }
  526. +
  527. + if (i == video->nformats)
  528. + return -EINVAL;
  529. +
  530. + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
  531. + fsize->stepwise.min_width = STFCAMSS_FRAME_MIN_WIDTH;
  532. + fsize->stepwise.max_width = STFCAMSS_FRAME_MAX_WIDTH;
  533. + fsize->stepwise.min_height = STFCAMSS_FRAME_MIN_HEIGHT;
  534. + fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT;
  535. + fsize->stepwise.step_width = 1;
  536. + fsize->stepwise.step_height = 1;
  537. +
  538. + return 0;
  539. +}
  540. +
  541. +static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
  542. +{
  543. + struct stfcamss_video *video = video_drvdata(file);
  544. +
  545. + *f = video->active_fmt;
  546. +
  547. + return 0;
  548. +}
  549. +
  550. +static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
  551. +{
  552. + struct stfcamss_video *video = video_drvdata(file);
  553. + int ret;
  554. +
  555. + if (vb2_is_busy(&video->vb2_q))
  556. + return -EBUSY;
  557. +
  558. + ret = __video_try_fmt(video, f);
  559. + if (ret < 0)
  560. + return ret;
  561. +
  562. + video->active_fmt = *f;
  563. +
  564. + return 0;
  565. +}
  566. +
  567. +static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
  568. +{
  569. + struct stfcamss_video *video = video_drvdata(file);
  570. +
  571. + return __video_try_fmt(video, f);
  572. +}
  573. +
  574. +static int video_enum_input(struct file *file, void *fh,
  575. + struct v4l2_input *input)
  576. +{
  577. + if (input->index > 0)
  578. + return -EINVAL;
  579. +
  580. + strscpy(input->name, "camera", sizeof(input->name));
  581. + input->type = V4L2_INPUT_TYPE_CAMERA;
  582. +
  583. + return 0;
  584. +}
  585. +
  586. +static int video_g_input(struct file *file, void *fh, unsigned int *input)
  587. +{
  588. + *input = 0;
  589. +
  590. + return 0;
  591. +}
  592. +
  593. +static int video_s_input(struct file *file, void *fh, unsigned int input)
  594. +{
  595. + return input == 0 ? 0 : -EINVAL;
  596. +}
  597. +
  598. +static int video_g_parm(struct file *file, void *priv,
  599. + struct v4l2_streamparm *p)
  600. +{
  601. + struct stfcamss_video *video = video_drvdata(file);
  602. + struct video_device *vdev = &video->vdev;
  603. + struct media_entity *entity;
  604. + struct v4l2_subdev *subdev;
  605. + struct media_pad *pad;
  606. + int ret, is_support = 0;
  607. +
  608. + entity = &vdev->entity;
  609. + while (1) {
  610. + pad = &entity->pads[0];
  611. + if (!(pad->flags & MEDIA_PAD_FL_SINK))
  612. + break;
  613. +
  614. + pad = media_pad_remote_pad_first(pad);
  615. + if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
  616. + break;
  617. +
  618. + entity = pad->entity;
  619. + subdev = media_entity_to_v4l2_subdev(entity);
  620. +
  621. + ret = v4l2_g_parm_cap(vdev, subdev, p);
  622. + if (ret < 0 && ret != -ENOIOCTLCMD)
  623. + break;
  624. + if (!ret)
  625. + is_support = 1;
  626. + }
  627. +
  628. + return is_support ? 0 : ret;
  629. +}
  630. +
  631. +static int video_s_parm(struct file *file, void *priv,
  632. + struct v4l2_streamparm *p)
  633. +{
  634. + struct stfcamss_video *video = video_drvdata(file);
  635. + struct video_device *vdev = &video->vdev;
  636. + struct media_entity *entity;
  637. + struct v4l2_subdev *subdev;
  638. + struct media_pad *pad;
  639. + struct v4l2_streamparm tmp_p;
  640. + int ret, is_support = 0;
  641. +
  642. + entity = &vdev->entity;
  643. + while (1) {
  644. + pad = &entity->pads[0];
  645. + if (!(pad->flags & MEDIA_PAD_FL_SINK))
  646. + break;
  647. +
  648. + pad = media_pad_remote_pad_first(pad);
  649. + if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
  650. + break;
  651. +
  652. + entity = pad->entity;
  653. + subdev = media_entity_to_v4l2_subdev(entity);
  654. +
  655. + tmp_p = *p;
  656. + ret = v4l2_s_parm_cap(vdev, subdev, &tmp_p);
  657. + if (ret < 0 && ret != -ENOIOCTLCMD)
  658. + break;
  659. + if (!ret) {
  660. + is_support = 1;
  661. + *p = tmp_p;
  662. + }
  663. + }
  664. +
  665. + return is_support ? 0 : ret;
  666. +}
  667. +
  668. +static const struct v4l2_ioctl_ops stf_vid_vin_ioctl_ops = {
  669. + .vidioc_querycap = video_querycap,
  670. + .vidioc_enum_fmt_vid_cap = video_enum_fmt,
  671. + .vidioc_enum_fmt_vid_out = video_enum_fmt,
  672. + .vidioc_enum_framesizes = video_enum_framesizes,
  673. + .vidioc_g_fmt_vid_cap = video_g_fmt,
  674. + .vidioc_s_fmt_vid_cap = video_s_fmt,
  675. + .vidioc_try_fmt_vid_cap = video_try_fmt,
  676. + .vidioc_g_fmt_vid_out = video_g_fmt,
  677. + .vidioc_s_fmt_vid_out = video_s_fmt,
  678. + .vidioc_try_fmt_vid_out = video_try_fmt,
  679. + .vidioc_reqbufs = vb2_ioctl_reqbufs,
  680. + .vidioc_querybuf = vb2_ioctl_querybuf,
  681. + .vidioc_qbuf = vb2_ioctl_qbuf,
  682. + .vidioc_expbuf = vb2_ioctl_expbuf,
  683. + .vidioc_dqbuf = vb2_ioctl_dqbuf,
  684. + .vidioc_create_bufs = vb2_ioctl_create_bufs,
  685. + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
  686. + .vidioc_streamon = vb2_ioctl_streamon,
  687. + .vidioc_streamoff = vb2_ioctl_streamoff,
  688. + .vidioc_enum_input = video_enum_input,
  689. + .vidioc_g_input = video_g_input,
  690. + .vidioc_s_input = video_s_input,
  691. + .vidioc_g_parm = video_g_parm,
  692. + .vidioc_s_parm = video_s_parm,
  693. +};
  694. +
  695. +static const struct v4l2_ioctl_ops stf_vid_isp_ioctl_ops = {
  696. + .vidioc_querycap = video_querycap,
  697. + .vidioc_enum_fmt_vid_cap = video_enum_fmt,
  698. + .vidioc_enum_fmt_vid_out = video_enum_fmt,
  699. + .vidioc_enum_framesizes = video_enum_framesizes,
  700. + .vidioc_g_fmt_vid_cap = video_g_fmt,
  701. + .vidioc_s_fmt_vid_cap = video_s_fmt,
  702. + .vidioc_try_fmt_vid_cap = video_try_fmt,
  703. + .vidioc_g_fmt_vid_out = video_g_fmt,
  704. + .vidioc_s_fmt_vid_out = video_s_fmt,
  705. + .vidioc_try_fmt_vid_out = video_try_fmt,
  706. + .vidioc_reqbufs = vb2_ioctl_reqbufs,
  707. + .vidioc_querybuf = vb2_ioctl_querybuf,
  708. + .vidioc_qbuf = vb2_ioctl_qbuf,
  709. + .vidioc_expbuf = vb2_ioctl_expbuf,
  710. + .vidioc_dqbuf = vb2_ioctl_dqbuf,
  711. + .vidioc_create_bufs = vb2_ioctl_create_bufs,
  712. + .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
  713. + .vidioc_streamon = vb2_ioctl_streamon,
  714. + .vidioc_streamoff = vb2_ioctl_streamoff,
  715. + .vidioc_enum_input = video_enum_input,
  716. + .vidioc_g_input = video_g_input,
  717. + .vidioc_s_input = video_s_input,
  718. + .vidioc_g_parm = video_g_parm,
  719. + .vidioc_s_parm = video_s_parm,
  720. +};
  721. +
  722. +/* -----------------------------------------------------------------------------
  723. + * V4L2 file operations
  724. + */
  725. +
  726. +static int video_open(struct file *file)
  727. +{
  728. + struct video_device *vdev = video_devdata(file);
  729. + struct stfcamss_video *video = video_drvdata(file);
  730. + struct v4l2_fh *vfh;
  731. + int ret;
  732. +
  733. + mutex_lock(&video->lock);
  734. +
  735. + vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
  736. + if (!vfh) {
  737. + ret = -ENOMEM;
  738. + goto error_alloc;
  739. + }
  740. +
  741. + v4l2_fh_init(vfh, vdev);
  742. + v4l2_fh_add(vfh);
  743. +
  744. + file->private_data = vfh;
  745. +
  746. + ret = v4l2_pipeline_pm_get(&vdev->entity);
  747. + if (ret < 0) {
  748. + dev_err(video->stfcamss->dev,
  749. + "Failed to power up pipeline: %d\n", ret);
  750. + goto error_pm_use;
  751. + }
  752. + mutex_unlock(&video->lock);
  753. +
  754. + return 0;
  755. +
  756. +error_pm_use:
  757. + v4l2_fh_release(file);
  758. +error_alloc:
  759. + mutex_unlock(&video->lock);
  760. + return ret;
  761. +}
  762. +
  763. +static int video_release(struct file *file)
  764. +{
  765. + struct video_device *vdev = video_devdata(file);
  766. +
  767. + vb2_fop_release(file);
  768. + v4l2_pipeline_pm_put(&vdev->entity);
  769. + file->private_data = NULL;
  770. +
  771. + return 0;
  772. +}
  773. +
  774. +static const struct v4l2_file_operations stf_vid_fops = {
  775. + .owner = THIS_MODULE,
  776. + .unlocked_ioctl = video_ioctl2,
  777. + .open = video_open,
  778. + .release = video_release,
  779. + .poll = vb2_fop_poll,
  780. + .mmap = vb2_fop_mmap,
  781. + .read = vb2_fop_read,
  782. +};
  783. +
  784. +/* -----------------------------------------------------------------------------
  785. + * STFCAMSS video core
  786. + */
  787. +
  788. +static void stf_video_release(struct video_device *vdev)
  789. +{
  790. + struct stfcamss_video *video = video_get_drvdata(vdev);
  791. +
  792. + media_entity_cleanup(&vdev->entity);
  793. +
  794. + mutex_destroy(&video->q_lock);
  795. + mutex_destroy(&video->lock);
  796. +}
  797. +
  798. +int stf_video_register(struct stfcamss_video *video,
  799. + struct v4l2_device *v4l2_dev, const char *name)
  800. +{
  801. + struct video_device *vdev;
  802. + struct vb2_queue *q;
  803. + struct media_pad *pad = &video->pad;
  804. + int ret;
  805. +
  806. + vdev = &video->vdev;
  807. +
  808. + mutex_init(&video->q_lock);
  809. +
  810. + q = &video->vb2_q;
  811. + q->drv_priv = video;
  812. + q->mem_ops = &vb2_dma_contig_memops;
  813. + q->ops = &stf_video_vb2_q_ops;
  814. + q->type = video->type;
  815. + q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
  816. + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
  817. + q->buf_struct_size = sizeof(struct stfcamss_buffer);
  818. + q->dev = video->stfcamss->dev;
  819. + q->lock = &video->q_lock;
  820. + q->min_buffers_needed = STFCAMSS_MIN_BUFFERS;
  821. + ret = vb2_queue_init(q);
  822. + if (ret < 0) {
  823. + dev_err(video->stfcamss->dev,
  824. + "Failed to init vb2 queue: %d\n", ret);
  825. + goto err_vb2_init;
  826. + }
  827. +
  828. + pad->flags = MEDIA_PAD_FL_SINK;
  829. + ret = media_entity_pads_init(&vdev->entity, 1, pad);
  830. + if (ret < 0) {
  831. + dev_err(video->stfcamss->dev,
  832. + "Failed to init video entity: %d\n", ret);
  833. + goto err_vb2_init;
  834. + }
  835. +
  836. + mutex_init(&video->lock);
  837. +
  838. + if (video->id == STF_V_LINE_WR) {
  839. + video->formats = formats_pix_wr;
  840. + video->nformats = ARRAY_SIZE(formats_pix_wr);
  841. + video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
  842. + vdev->ioctl_ops = &stf_vid_vin_ioctl_ops;
  843. + } else {
  844. + video->formats = formats_pix_isp;
  845. + video->nformats = ARRAY_SIZE(formats_pix_isp);
  846. + video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
  847. + vdev->ioctl_ops = &stf_vid_isp_ioctl_ops;
  848. + }
  849. +
  850. + ret = stf_video_init_format(video);
  851. + if (ret < 0) {
  852. + dev_err(video->stfcamss->dev,
  853. + "Failed to init format: %d\n", ret);
  854. + goto err_vid_init_format;
  855. + }
  856. +
  857. + vdev->fops = &stf_vid_fops;
  858. + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE;
  859. + vdev->vfl_dir = VFL_DIR_RX;
  860. + vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
  861. + vdev->release = stf_video_release;
  862. + vdev->v4l2_dev = v4l2_dev;
  863. + vdev->queue = &video->vb2_q;
  864. + vdev->lock = &video->lock;
  865. + strscpy(vdev->name, name, sizeof(vdev->name));
  866. +
  867. + ret = video_register_device(vdev, VFL_TYPE_VIDEO, video->id);
  868. + if (ret < 0) {
  869. + dev_err(video->stfcamss->dev,
  870. + "Failed to register video device: %d\n", ret);
  871. + goto err_vid_reg;
  872. + }
  873. +
  874. + video_set_drvdata(vdev, video);
  875. + return 0;
  876. +
  877. +err_vid_reg:
  878. +err_vid_init_format:
  879. + media_entity_cleanup(&vdev->entity);
  880. + mutex_destroy(&video->lock);
  881. +err_vb2_init:
  882. + mutex_destroy(&video->q_lock);
  883. + return ret;
  884. +}
  885. +
  886. +void stf_video_unregister(struct stfcamss_video *video)
  887. +{
  888. + vb2_video_unregister_device(&video->vdev);
  889. +}
  890. --- /dev/null
  891. +++ b/drivers/media/platform/starfive/stf_video.h
  892. @@ -0,0 +1,95 @@
  893. +/* SPDX-License-Identifier: GPL-2.0 */
  894. +/*
  895. + * stf_video.h
  896. + *
  897. + * StarFive Camera Subsystem - V4L2 device node
  898. + *
  899. + * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
  900. + */
  901. +
  902. +#ifndef STF_VIDEO_H
  903. +#define STF_VIDEO_H
  904. +
  905. +#include <linux/mutex.h>
  906. +#include <linux/videodev2.h>
  907. +#include <media/v4l2-dev.h>
  908. +#include <media/v4l2-fh.h>
  909. +#include <media/v4l2-ioctl.h>
  910. +#include <media/videobuf2-v4l2.h>
  911. +
  912. +#define STFCAMSS_FRAME_MIN_WIDTH 64
  913. +#define STFCAMSS_FRAME_MAX_WIDTH 1920
  914. +#define STFCAMSS_FRAME_MIN_HEIGHT 64
  915. +#define STFCAMSS_FRAME_MAX_HEIGHT 1080
  916. +#define STFCAMSS_FRAME_WIDTH_ALIGN_8 8
  917. +#define STFCAMSS_FRAME_WIDTH_ALIGN_128 128
  918. +#define STFCAMSS_MIN_BUFFERS 2
  919. +
  920. +#define STFCAMSS_MAX_ENTITY_NAME_LEN 27
  921. +
  922. +enum stf_v_line_id {
  923. + STF_V_LINE_WR = 0,
  924. + STF_V_LINE_ISP,
  925. + STF_V_LINE_MAX,
  926. +};
  927. +
  928. +struct stfcamss_buffer {
  929. + struct vb2_v4l2_buffer vb;
  930. + dma_addr_t addr[3];
  931. + struct list_head queue;
  932. + int sizeimage;
  933. +};
  934. +
  935. +struct fract {
  936. + u8 numerator;
  937. + u8 denominator;
  938. +};
  939. +
  940. +/*
  941. + * struct stfcamss_format_info - ISP media bus format information
  942. + * @code: V4L2 media bus format code
  943. + * @pixelformat: V4L2 pixel format FCC identifier
  944. + * @planes: Number of planes
  945. + * @hsub: Horizontal subsampling (for each plane)
  946. + * @vsub: Vertical subsampling (for each plane)
  947. + * @bpp: Bits per pixel when stored in memory (for each plane)
  948. + */
  949. +struct stfcamss_format_info {
  950. + u32 code;
  951. + u32 pixelformat;
  952. + u8 planes;
  953. + struct fract hsub[3];
  954. + struct fract vsub[3];
  955. + u8 bpp[3];
  956. +};
  957. +
  958. +struct stfcamss_video {
  959. + struct stfcamss *stfcamss;
  960. + u8 id;
  961. + struct vb2_queue vb2_q;
  962. + struct video_device vdev;
  963. + struct media_pad pad;
  964. + struct media_pipeline pipe;
  965. + struct v4l2_format active_fmt;
  966. + enum v4l2_buf_type type;
  967. + const struct stfcamss_video_ops *ops;
  968. + struct mutex lock; /* serialize device access */
  969. + struct mutex q_lock; /* protects the queue */
  970. + unsigned int bpl_alignment;
  971. + const struct stfcamss_format_info *formats;
  972. + unsigned int nformats;
  973. +};
  974. +
  975. +struct stfcamss_video_ops {
  976. + int (*queue_buffer)(struct stfcamss_video *vid,
  977. + struct stfcamss_buffer *buf);
  978. + int (*flush_buffers)(struct stfcamss_video *vid,
  979. + enum vb2_buffer_state state);
  980. +};
  981. +
  982. +int stf_video_register(struct stfcamss_video *video,
  983. + struct v4l2_device *v4l2_dev, const char *name);
  984. +
  985. +void stf_video_unregister(struct stfcamss_video *video);
  986. +
  987. +#endif /* STF_VIDEO_H */