From 37f49e37ab4cb5d0bc4c60eb5c6d4dd57db767bb Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:44:59 +0000 Subject: [PATCH] gmac get mac form eeprom --- kernel/drivers/staging/media/imx/imx-media-capture.c | 278 +++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 198 insertions(+), 80 deletions(-) diff --git a/kernel/drivers/staging/media/imx/imx-media-capture.c b/kernel/drivers/staging/media/imx/imx-media-capture.c index 81a3370..b2f2cb3 100644 --- a/kernel/drivers/staging/media/imx/imx-media-capture.c +++ b/kernel/drivers/staging/media/imx/imx-media-capture.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Video Capture Subdev for Freescale i.MX5/6 SOC * * Copyright (c) 2012-2016 Mentor Graphics 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. */ #include <linux/delay.h> #include <linux/fs.h> @@ -29,6 +25,8 @@ #include <video/imx-ipu-v3.h> #include <media/imx.h> #include "imx-media.h" + +#define IMX_CAPTURE_NAME "imx-capture" struct capture_priv { struct imx_media_video_dev vdev; @@ -73,8 +71,8 @@ { struct capture_priv *priv = video_drvdata(file); - strlcpy(cap->driver, "imx-media-capture", sizeof(cap->driver)); - strlcpy(cap->card, "imx-media-capture", sizeof(cap->card)); + strscpy(cap->driver, IMX_CAPTURE_NAME, sizeof(cap->driver)); + strscpy(cap->card, IMX_CAPTURE_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", priv->src_sd->name); @@ -93,11 +91,11 @@ }; int ret; - cc = imx_media_find_format(fsize->pixel_format, CS_SEL_ANY, true); + cc = imx_media_find_pixel_format(fsize->pixel_format, PIXFMT_SEL_ANY); if (!cc) return -EINVAL; - fse.code = cc->codes[0]; + fse.code = cc->codes ? cc->codes[0] : 0; ret = v4l2_subdev_call(priv->src_sd, pad, enum_frame_size, NULL, &fse); if (ret) @@ -135,11 +133,11 @@ }; int ret; - cc = imx_media_find_format(fival->pixel_format, CS_SEL_ANY, true); + cc = imx_media_find_pixel_format(fival->pixel_format, PIXFMT_SEL_ANY); if (!cc) return -EINVAL; - fie.code = cc->codes[0]; + fie.code = cc->codes ? cc->codes[0] : 0; ret = v4l2_subdev_call(priv->src_sd, pad, enum_frame_interval, NULL, &fie); @@ -169,17 +167,19 @@ return ret; } - cc_src = imx_media_find_ipu_format(fmt_src.format.code, CS_SEL_ANY); + cc_src = imx_media_find_ipu_format(fmt_src.format.code, + PIXFMT_SEL_YUV_RGB); if (cc_src) { - u32 cs_sel = (cc_src->cs == IPUV3_COLORSPACE_YUV) ? - CS_SEL_YUV : CS_SEL_RGB; + enum imx_pixfmt_sel fmt_sel = + (cc_src->cs == IPUV3_COLORSPACE_YUV) ? + PIXFMT_SEL_YUV : PIXFMT_SEL_RGB; - ret = imx_media_enum_format(&fourcc, f->index, cs_sel); + ret = imx_media_enum_pixel_formats(&fourcc, f->index, fmt_sel); if (ret) return ret; } else { cc_src = imx_media_find_mbus_format(fmt_src.format.code, - CS_SEL_ANY, true); + PIXFMT_SEL_ANY); if (WARN_ON(!cc_src)) return -EINVAL; @@ -203,12 +203,72 @@ return 0; } +static int __capture_try_fmt_vid_cap(struct capture_priv *priv, + struct v4l2_subdev_format *fmt_src, + struct v4l2_format *f, + const struct imx_media_pixfmt **retcc, + struct v4l2_rect *compose) +{ + const struct imx_media_pixfmt *cc, *cc_src; + + cc_src = imx_media_find_ipu_format(fmt_src->format.code, + PIXFMT_SEL_YUV_RGB); + if (cc_src) { + enum imx_pixfmt_sel fmt_sel; + u32 fourcc; + + fmt_sel = (cc_src->cs == IPUV3_COLORSPACE_YUV) ? + PIXFMT_SEL_YUV : PIXFMT_SEL_RGB; + fourcc = f->fmt.pix.pixelformat; + + cc = imx_media_find_pixel_format(fourcc, fmt_sel); + if (!cc) { + imx_media_enum_pixel_formats(&fourcc, 0, fmt_sel); + cc = imx_media_find_pixel_format(fourcc, fmt_sel); + } + } else { + cc_src = imx_media_find_mbus_format(fmt_src->format.code, + PIXFMT_SEL_ANY); + if (WARN_ON(!cc_src)) + return -EINVAL; + + cc = cc_src; + } + + /* allow IDMAC interweave but enforce field order from source */ + if (V4L2_FIELD_IS_INTERLACED(f->fmt.pix.field)) { + switch (fmt_src->format.field) { + case V4L2_FIELD_SEQ_TB: + fmt_src->format.field = V4L2_FIELD_INTERLACED_TB; + break; + case V4L2_FIELD_SEQ_BT: + fmt_src->format.field = V4L2_FIELD_INTERLACED_BT; + break; + default: + break; + } + } + + imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, &fmt_src->format, cc); + + if (retcc) + *retcc = cc; + + if (compose) { + compose->left = 0; + compose->top = 0; + compose->width = fmt_src->format.width; + compose->height = fmt_src->format.height; + } + + return 0; +} + static int capture_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { struct capture_priv *priv = video_drvdata(file); struct v4l2_subdev_format fmt_src; - const struct imx_media_pixfmt *cc, *cc_src; int ret; fmt_src.pad = priv->src_sd_pad; @@ -217,37 +277,14 @@ if (ret) return ret; - cc_src = imx_media_find_ipu_format(fmt_src.format.code, CS_SEL_ANY); - if (cc_src) { - u32 fourcc, cs_sel; - - cs_sel = (cc_src->cs == IPUV3_COLORSPACE_YUV) ? - CS_SEL_YUV : CS_SEL_RGB; - fourcc = f->fmt.pix.pixelformat; - - cc = imx_media_find_format(fourcc, cs_sel, false); - if (!cc) { - imx_media_enum_format(&fourcc, 0, cs_sel); - cc = imx_media_find_format(fourcc, cs_sel, false); - } - } else { - cc_src = imx_media_find_mbus_format(fmt_src.format.code, - CS_SEL_ANY, true); - if (WARN_ON(!cc_src)) - return -EINVAL; - - cc = cc_src; - } - - imx_media_mbus_fmt_to_pix_fmt(&f->fmt.pix, &fmt_src.format, cc); - - return 0; + return __capture_try_fmt_vid_cap(priv, &fmt_src, f, NULL, NULL); } static int capture_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { struct capture_priv *priv = video_drvdata(file); + struct v4l2_subdev_format fmt_src; int ret; if (vb2_is_busy(&priv->q)) { @@ -255,13 +292,18 @@ return -EBUSY; } - ret = capture_try_fmt_vid_cap(file, priv, f); + fmt_src.pad = priv->src_sd_pad; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src); + if (ret) + return ret; + + ret = __capture_try_fmt_vid_cap(priv, &fmt_src, f, &priv->vdev.cc, + &priv->vdev.compose); if (ret) return ret; priv->vdev.fmt.fmt.pix = f->fmt.pix; - priv->vdev.cc = imx_media_find_format(f->fmt.pix.pixelformat, - CS_SEL_ANY, true); return 0; } @@ -288,6 +330,36 @@ return -EBUSY; return v4l2_subdev_call(priv->src_sd, video, s_std, std); +} + +static int capture_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct capture_priv *priv = video_drvdata(file); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + /* The compose rectangle is fixed to the source format. */ + s->r = priv->vdev.compose; + break; + case V4L2_SEL_TGT_COMPOSE_PADDED: + /* + * The hardware writes with a configurable but fixed DMA burst + * size. If the source format width is not burst size aligned, + * the written frame contains padding to the right. + */ + s->r.left = 0; + s->r.top = 0; + s->r.width = priv->vdev.fmt.fmt.pix.width; + s->r.height = priv->vdev.fmt.fmt.pix.height; + break; + default: + return -EINVAL; + } + + return 0; } static int capture_g_parm(struct file *file, void *fh, @@ -335,6 +407,21 @@ return 0; } +static int capture_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_IMX_FRAME_INTERVAL_ERROR: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + static const struct v4l2_ioctl_ops capture_ioctl_ops = { .vidioc_querycap = vidioc_querycap, @@ -350,6 +437,8 @@ .vidioc_g_std = capture_g_std, .vidioc_s_std = capture_s_std, + .vidioc_g_selection = capture_g_selection, + .vidioc_g_parm = capture_g_parm, .vidioc_s_parm = capture_s_parm, @@ -362,6 +451,9 @@ .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_subscribe_event = capture_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /* @@ -441,12 +533,45 @@ spin_unlock_irqrestore(&priv->q_lock, flags); } +static int capture_validate_fmt(struct capture_priv *priv) +{ + struct v4l2_subdev_format fmt_src; + const struct imx_media_pixfmt *cc; + struct v4l2_rect compose; + struct v4l2_format f; + int ret; + + fmt_src.pad = priv->src_sd_pad; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(priv->src_sd, pad, get_fmt, NULL, &fmt_src); + if (ret) + return ret; + + v4l2_fill_pix_format(&f.fmt.pix, &fmt_src.format); + + ret = __capture_try_fmt_vid_cap(priv, &fmt_src, &f, &cc, &compose); + if (ret) + return ret; + + return (priv->vdev.fmt.fmt.pix.width != f.fmt.pix.width || + priv->vdev.fmt.fmt.pix.height != f.fmt.pix.height || + priv->vdev.cc->cs != cc->cs || + priv->vdev.compose.width != compose.width || + priv->vdev.compose.height != compose.height) ? -EPIPE : 0; +} + static int capture_start_streaming(struct vb2_queue *vq, unsigned int count) { struct capture_priv *priv = vb2_get_drv_priv(vq); struct imx_media_buffer *buf, *tmp; unsigned long flags; int ret; + + ret = capture_validate_fmt(priv); + if (ret) { + v4l2_err(priv->src_sd, "capture format not valid\n"); + goto return_bufs; + } ret = imx_media_pipeline_set_stream(priv->md, &priv->src_sd->entity, true); @@ -473,6 +598,7 @@ { struct capture_priv *priv = vb2_get_drv_priv(vq); struct imx_media_buffer *frame; + struct imx_media_buffer *tmp; unsigned long flags; int ret; @@ -487,9 +613,7 @@ /* release all active buffers */ spin_lock_irqsave(&priv->q_lock, flags); - while (!list_empty(&priv->ready_q)) { - frame = list_entry(priv->ready_q.next, - struct imx_media_buffer, list); + list_for_each_entry_safe(frame, tmp, &priv->ready_q, list) { list_del(&frame->list); vb2_buffer_done(&frame->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); } @@ -523,7 +647,7 @@ if (ret) v4l2_err(priv->src_sd, "v4l2_fh_open failed\n"); - ret = v4l2_pipeline_pm_use(&vfd->entity, 1); + ret = v4l2_pipeline_pm_get(&vfd->entity); if (ret) v4l2_fh_release(file); @@ -536,7 +660,6 @@ struct capture_priv *priv = video_drvdata(file); struct video_device *vfd = priv->vdev.vfd; struct vb2_queue *vq = &priv->q; - int ret = 0; mutex_lock(&priv->mutex); @@ -545,11 +668,11 @@ vq->owner = NULL; } - v4l2_pipeline_pm_use(&vfd->entity, 0); + v4l2_pipeline_pm_put(&vfd->entity); v4l2_fh_release(file); mutex_unlock(&priv->mutex); - return ret; + return 0; } static const struct v4l2_file_operations capture_fops = { @@ -570,19 +693,6 @@ .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, }; - -void imx_media_capture_device_set_format(struct imx_media_video_dev *vdev, - struct v4l2_pix_format *pix) -{ - struct capture_priv *priv = to_capture_priv(vdev); - - mutex_lock(&priv->mutex); - priv->vdev.fmt.fmt.pix = *pix; - priv->vdev.cc = imx_media_find_format(pix->pixelformat, CS_SEL_ANY, - true); - mutex_unlock(&priv->mutex); -} -EXPORT_SYMBOL_GPL(imx_media_capture_device_set_format); struct imx_media_buffer * imx_media_capture_device_next_buf(struct imx_media_video_dev *vdev) @@ -625,17 +735,18 @@ { struct capture_priv *priv = to_capture_priv(vdev); struct v4l2_subdev *sd = priv->src_sd; + struct v4l2_device *v4l2_dev = sd->v4l2_dev; struct video_device *vfd = vdev->vfd; struct vb2_queue *vq = &priv->q; struct v4l2_subdev_format fmt_src; int ret; /* get media device */ - priv->md = dev_get_drvdata(sd->v4l2_dev->dev); + priv->md = container_of(v4l2_dev->mdev, struct imx_media_dev, md); - vfd->v4l2_dev = sd->v4l2_dev; + vfd->v4l2_dev = v4l2_dev; - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(sd, "Failed to register video device\n"); return ret; @@ -660,13 +771,6 @@ INIT_LIST_HEAD(&priv->ready_q); - priv->vdev_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, &priv->vdev_pad); - if (ret) { - v4l2_err(sd, "failed to init dev pad\n"); - goto unreg; - } - /* create the link from the src_sd devnode pad to device node */ ret = media_create_pad_link(&sd->entity, priv->src_sd_pad, &vfd->entity, 0, 0); @@ -687,13 +791,18 @@ vdev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; imx_media_mbus_fmt_to_pix_fmt(&vdev->fmt.fmt.pix, &fmt_src.format, NULL); - vdev->cc = imx_media_find_format(vdev->fmt.fmt.pix.pixelformat, - CS_SEL_ANY, false); + vdev->compose.width = fmt_src.format.width; + vdev->compose.height = fmt_src.format.height; + vdev->cc = imx_media_find_pixel_format(vdev->fmt.fmt.pix.pixelformat, + PIXFMT_SEL_ANY); v4l2_info(sd, "Registered %s as /dev/%s\n", vfd->name, video_device_node_name(vfd)); vfd->ctrl_handler = &priv->ctrl_hdlr; + + /* add vdev to the video device list */ + imx_media_add_video_device(priv->md, vdev); return 0; unreg: @@ -719,18 +828,20 @@ EXPORT_SYMBOL_GPL(imx_media_capture_device_unregister); struct imx_media_video_dev * -imx_media_capture_device_init(struct v4l2_subdev *src_sd, int pad) +imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd, + int pad) { struct capture_priv *priv; struct video_device *vfd; + int ret; - priv = devm_kzalloc(src_sd->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return ERR_PTR(-ENOMEM); priv->src_sd = src_sd; priv->src_sd_pad = pad; - priv->dev = src_sd->dev; + priv->dev = dev; mutex_init(&priv->mutex); spin_lock_init(&priv->q_lock); @@ -747,6 +858,13 @@ vfd->queue = &priv->q; priv->vdev.vfd = vfd; + priv->vdev_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, &priv->vdev_pad); + if (ret) { + video_device_release(vfd); + return ERR_PTR(ret); + } + INIT_LIST_HEAD(&priv->vdev.list); video_set_drvdata(vfd, priv); -- Gitblit v1.6.2