diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-13 09:37:02 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-13 09:37:02 -0700 |
commit | fd5c32d80884268a381ed0e67cccef0b3d37750b (patch) | |
tree | e5f8844e8c5aa5a7f7dec265d765d3b31cca8be5 /drivers/media/platform | |
parent | 647412daeb454b6dad12a6c6961ab90aac9e5d29 (diff) | |
parent | c386e0797d26a32e354daf4480c5d40165db66a1 (diff) | |
download | linux-fd5c32d80884268a381ed0e67cccef0b3d37750b.tar.bz2 |
Merge tag 'media/v5.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- the usbvision driver was dropped from staging
- the Zoran driver were re-added at staging. It gained lots of
improvements, and was converted to use videobuf2 API
- a new virtual driver (vidtv) was added in order to allow testing the
digital TV framework and APIs
- the media uAPI documentation gained a glossary with commonly used
terms, helping to simplify some parts of the docs
- more cleanups at the atomisp driver
- Mediatek VPU gained support for MT8183
- added support for codecs with supports doing colorspace conversion
(CSC)
- support for CSC API was added at vivid and rksip1 drivers
- added a helper core support and uAPI for better supporting H.264
codecs
- added support for Renesas R8A774E1
- use the new SPDX GFDL-1.1-no-invariants-or-later license on media
uAPI docs, instead of a license text
- Venus driver has gained VP9 codec support
- lots of other cleanups and driver improvements
* tag 'media/v5.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (555 commits)
media: dvb-frontends/drxk_hard.c: fix uninitialized variable warning
media: tvp7002: fix uninitialized variable warning
media: s5k5baf: drop 'data' field in struct s5k5baf_fw
media: dt-bindings: media: venus: Add an optional power domain for perf voting
media: rcar-vin: rcar-dma: Fix setting VNIS_REG for RAW8 formats
media: staging: rkisp1: uapi: Do not use BIT() macro
media: v4l2-mem2mem: Fix spurious v4l2_m2m_buf_done
media: usbtv: Fix refcounting mixup
media: zoran.rst: place it at the right place this time
media: add Zoran cardlist
media: admin-guide: update cardlists
media: siano: rename a duplicated card string
media: zoran: move documentation file to the right place
media: atomisp: fixes build breakage for ISP2400 due to a cleanup
media: zoran: fix mixed case on vars
media: zoran: get rid of an unused var
media: zoran: use upper case for card types
media: zoran: fix sparse warnings
media: zoran: fix smatch warning
media: zoran: update TODO
...
Diffstat (limited to 'drivers/media/platform')
113 files changed, 3014 insertions, 1596 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index c57ee78fa99d..a3cb104956d5 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -256,13 +256,14 @@ config VIDEO_MEDIATEK_VCODEC select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU + select MTK_SCP help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats This driver rely on VPU driver to communicate with VPU. - To compile this driver as a module, choose M here: the - module will be called mtk-vcodec + To compile this driver as modules, choose M here: the + modules will be called mtk-vcodec-dec and mtk-vcodec-enc. config VIDEO_MEM2MEM_DEINTERLACE tristate "Deinterlace support" @@ -426,8 +427,8 @@ config VIDEO_RENESAS_FCP help This is a driver for the Renesas Frame Compression Processor (FCP). The FCP is a companion module of video processing modules in the - Renesas R-Car Gen3 SoCs. It handles memory access for the codec, - VSP and FDP modules. + Renesas R-Car Gen3 and RZ/G2 SoCs. It handles memory access for + the codec, VSP and FDP modules. To compile this driver as a module, choose M here: the module will be called rcar-fcp. diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 7d98db1d9b52..c46a79eace98 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -1597,7 +1597,6 @@ static int aspeed_video_setup_video(struct aspeed_video *video) video_set_drvdata(vdev, video); rc = video_register_device(vdev, VFL_TYPE_VIDEO, 0); if (rc) { - vb2_queue_release(vbq); v4l2_ctrl_handler_free(&video->ctrl_handler); v4l2_device_unregister(v4l2_dev); @@ -1737,9 +1736,7 @@ static int aspeed_video_remove(struct platform_device *pdev) clk_unprepare(video->vclk); clk_unprepare(video->eclk); - video_unregister_device(&video->vdev); - - vb2_queue_release(&video->queue); + vb2_video_unregister_device(&video->vdev); v4l2_ctrl_handler_free(&video->ctrl_handler); diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b021604eceaa..bf75927bac4e 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1101,7 +1101,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) break; case CODA_960: coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); - /* fallthrough */ + fallthrough; case CODA_HX4: case CODA_7541: coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | @@ -1141,7 +1141,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; break; } - /* fallthrough */ + fallthrough; case CODA_960: value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3ab3d976d8ca..87a2c706f747 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -808,7 +808,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; break; } - /* else fall through */ + fallthrough; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_YUV422P: @@ -1015,7 +1015,7 @@ static int coda_g_selection(struct file *file, void *fh, case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: rsel = &r; - /* fallthrough */ + fallthrough; case V4L2_SEL_TGT_CROP: if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || ctx->inst_type == CODA_INST_DECODER) @@ -1024,7 +1024,7 @@ static int coda_g_selection(struct file *file, void *fh, case V4L2_SEL_TGT_COMPOSE_BOUNDS: case V4L2_SEL_TGT_COMPOSE_PADDED: rsel = &r; - /* fallthrough */ + fallthrough; case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_COMPOSE_DEFAULT: if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || @@ -1074,7 +1074,7 @@ static int coda_s_selection(struct file *file, void *fh, return 0; } - /* else fall through */ + fallthrough; case V4L2_SEL_TGT_NATIVE_SIZE: case V4L2_SEL_TGT_COMPOSE: return coda_g_selection(file, fh, s); @@ -1937,9 +1937,6 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, buf->blob.size = size; buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob); - if (!buf->dentry) - dev_warn(dev->dev, - "failed to create debugfs entry %s\n", name); } return 0; @@ -2628,7 +2625,7 @@ static int coda_open(struct file *file) */ if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; - /* fallthrough */ + fallthrough; case CODA_HX4: case CODA_7541: ctx->reg_idx = 0; @@ -3211,8 +3208,6 @@ static int coda_probe(struct platform_device *pdev) ida_init(&dev->ida); dev->debugfs_root = debugfs_create_dir("coda", NULL); - if (!dev->debugfs_root) - dev_warn(&pdev->dev, "failed to create debugfs root\n"); /* allocate auxiliary per-device buffers for the BIT processor */ if (dev->devtype->product == CODA_DX6) { @@ -3269,6 +3264,8 @@ static int coda_probe(struct platform_device *pdev) return 0; err_alloc_workqueue: + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); destroy_workqueue(dev->workqueue); err_v4l2_register: v4l2_device_unregister(&dev->v4l2_dev); diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index e7a4b06e6dfe..6000a4e789ad 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -495,17 +495,6 @@ static int fimc_capture_open(struct file *file) ret = fimc_pipeline_call(ve, open, &ve->vdev.entity, true); - if (ret == 0 && vc->user_subdev_api && vc->inh_sensor_ctrls) { - /* - * Recreate controls of the the video node to drop - * any controls inherited from the sensor subdev. - */ - fimc_ctrls_delete(vc->ctx); - - ret = fimc_ctrls_create(vc->ctx); - if (ret == 0) - vc->inh_sensor_ctrls = false; - } if (ret == 0) ve->vdev.entity.use_count++; @@ -1246,8 +1235,11 @@ static int fimc_cap_streamoff(struct file *file, void *priv, if (ret < 0) return ret; - media_pipeline_stop(&vc->ve.vdev.entity); - vc->streaming = false; + if (vc->streaming) { + media_pipeline_stop(&vc->ve.vdev.entity); + vc->streaming = false; + } + return 0; } @@ -1279,7 +1271,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh, case V4L2_SEL_TGT_COMPOSE_DEFAULT: case V4L2_SEL_TGT_COMPOSE_BOUNDS: f = &ctx->d_frame; - /* fall through */ + fallthrough; case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: s->r.left = 0; @@ -1290,7 +1282,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh, case V4L2_SEL_TGT_COMPOSE: f = &ctx->d_frame; - /* fall through */ + fallthrough; case V4L2_SEL_TGT_CROP: s->r.left = f->offs_h; s->r.top = f->offs_v; @@ -1398,7 +1390,7 @@ static int fimc_link_setup(struct media_entity *entity, vc->input = sd->grp_id; - if (vc->user_subdev_api || vc->inh_sensor_ctrls) + if (vc->user_subdev_api) return 0; /* Inherit V4L2 controls from the image sensor subdev. */ @@ -1601,7 +1593,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_COMPOSE_BOUNDS: f = &ctx->d_frame; - /* fall through */ + fallthrough; case V4L2_SEL_TGT_CROP_BOUNDS: r->width = f->o_width; r->height = f->o_height; @@ -1888,6 +1880,7 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc) return ret; sd->entity.ops = &fimc_sd_media_ops; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; sd->internal_ops = &fimc_capture_sd_internal_ops; v4l2_set_subdevdata(sd, fimc); return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index cde60fbb23a8..08d1f39a914c 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -954,9 +954,11 @@ static int fimc_probe(struct platform_device *pdev) spin_lock_init(&fimc->slock); mutex_init(&fimc->lock); - fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node); - if (IS_ERR(fimc->sysreg)) - return PTR_ERR(fimc->sysreg); + if (fimc->variant->has_isp_wb) { + fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node); + if (IS_ERR(fimc->sysreg)) + return PTR_ERR(fimc->sysreg); + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); fimc->regs = devm_ioremap_resource(dev, res); @@ -1110,67 +1112,8 @@ static int fimc_remove(struct platform_device *pdev) return 0; } -/* Image pixel limits, similar across several FIMC HW revisions. */ -static const struct fimc_pix_limit s5p_pix_limit[4] = { - [0] = { - .scaler_en_w = 3264, - .scaler_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [1] = { - .scaler_en_w = 4224, - .scaler_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [2] = { - .scaler_en_w = 1920, - .scaler_dis_w = 8192, - .out_rot_en_w = 1280, - .out_rot_dis_w = 1920, - }, -}; - -static const struct fimc_variant fimc0_variant_s5pv210 = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .pix_limit = &s5p_pix_limit[1], -}; - -static const struct fimc_variant fimc1_variant_s5pv210 = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 1, - .min_vsize_align = 1, - .pix_limit = &s5p_pix_limit[2], -}; - -static const struct fimc_variant fimc2_variant_s5pv210 = { - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .pix_limit = &s5p_pix_limit[2], -}; - /* S5PV210, S5PC110 */ static const struct fimc_drvdata fimc_drvdata_s5pv210 = { - .variant = { - [0] = &fimc0_variant_s5pv210, - [1] = &fimc1_variant_s5pv210, - [2] = &fimc2_variant_s5pv210, - }, .num_entities = 3, .lclk_frequency = 166000000UL, .out_buf_count = 4, diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index d130f664a60b..e4a56232907a 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -296,11 +296,8 @@ struct fimc_m2m_device { * @buf_index: index for managing the output DMA buffers * @frame_count: the frame counter for statistics * @reqbufs_count: the number of buffers requested in REQBUFS ioctl - * @input_index: input (camera sensor) index * @input: capture input type, grp_id of the attached subdev * @user_subdev_api: true if subdevs are not configured by the host driver - * @inh_sensor_ctrls: a flag indicating v4l2 controls are inherited from - * an image sensor subdev */ struct fimc_vid_cap { struct fimc_ctx *ctx; @@ -319,10 +316,8 @@ struct fimc_vid_cap { unsigned int frame_count; unsigned int reqbufs_count; bool streaming; - int input_index; u32 input; bool user_subdev_api; - bool inh_sensor_ctrls; }; /** diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index a474014f0a0f..019bb47df915 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -756,18 +756,12 @@ static void fimc_is_debugfs_remove(struct fimc_is *is) is->debugfs_entry = NULL; } -static int fimc_is_debugfs_create(struct fimc_is *is) +static void fimc_is_debugfs_create(struct fimc_is *is) { - struct dentry *dentry; - is->debugfs_entry = debugfs_create_dir("fimc_is", NULL); - dentry = debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry, - is, &fimc_is_fops); - if (!dentry) - fimc_is_debugfs_remove(is); - - return is->debugfs_entry == NULL ? -EIO : 0; + debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry, is, + &fimc_is_fops); } static int fimc_is_runtime_resume(struct device *dev); @@ -853,9 +847,7 @@ static int fimc_is_probe(struct platform_device *pdev) if (ret < 0) goto err_pm; - ret = fimc_is_debugfs_create(is); - if (ret < 0) - goto err_sd; + fimc_is_debugfs_create(is); ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME); if (ret < 0) @@ -868,7 +860,6 @@ static int fimc_is_probe(struct platform_device *pdev) err_dfs: fimc_is_debugfs_remove(is); -err_sd: fimc_is_unregister_subdevs(is); err_pm: pm_runtime_put_noidle(dev); diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index cde0d254ec1c..a77c49b18511 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -305,8 +305,10 @@ static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on) if (on) { ret = pm_runtime_get_sync(&is->pdev->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put(&is->pdev->dev); return ret; + } set_bit(IS_ST_PWR_ON, &is->state); ret = fimc_is_start_firmware(is); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 9c666f663ab4..fdd0d369b192 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -471,7 +471,7 @@ static int fimc_lite_open(struct file *file) set_bit(ST_FLITE_IN_USE, &fimc->state); ret = pm_runtime_get_sync(&fimc->pdev->dev); if (ret < 0) - goto unlock; + goto err_pm; ret = v4l2_fh_open(file); if (ret < 0) diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c index 5ce2bdebd424..8764999a5fd7 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -606,6 +606,11 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, switch (source->fimc_bus_type) { case FIMC_BUS_TYPE_ITU_601: case FIMC_BUS_TYPE_ITU_656: + if (fimc_fmt_is_user_defined(f->fmt->color)) { + cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; + break; + } + for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { if (vc->ci_fmt.code == pix_desc[i].pixelcode) { cfg = pix_desc[i].cisrcfmt; @@ -707,10 +712,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A; + if (vid_cap->ci_fmt.code == MEDIA_BUS_FMT_JPEG_1X8) + cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; break; case FIMC_BUS_TYPE_LCD_WRITEBACK_A: cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; - /* fall through */ + fallthrough; case FIMC_BUS_TYPE_ISP_WRITEBACK: if (fimc->variant->has_isp_wb) cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 16dd660137a8..e636c33e847b 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -19,6 +19,7 @@ #include <linux/of_platform.h> #include <linux/of_device.h> #include <linux/of_graph.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/types.h> @@ -92,7 +93,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p, switch (sd->grp_id) { case GRP_ID_SENSOR: sensor = sd; - /* fall through */ + fallthrough; case GRP_ID_FIMC_IS_SENSOR: p->subdevs[IDX_SENSOR] = sd; break; @@ -289,11 +290,26 @@ static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on) { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP }, }; struct fimc_pipeline *p = to_fimc_pipeline(ep); - struct fimc_md *fmd = entity_to_fimc_mdev(&p->subdevs[IDX_CSIS]->entity); enum fimc_subdev_index sd_id; int i, ret = 0; if (p->subdevs[IDX_SENSOR] == NULL) { + struct fimc_md *fmd; + struct v4l2_subdev *sd = p->subdevs[IDX_CSIS]; + + if (!sd) + sd = p->subdevs[IDX_FIMC]; + + if (!sd) { + /* + * If neither CSIS nor FIMC was set up, + * it's impossible to have any sensors + */ + return -ENODEV; + } + + fmd = entity_to_fimc_mdev(&sd->entity); + if (!fmd->user_subdev_api) { /* * Sensor must be already discovered if we @@ -379,21 +395,15 @@ static void fimc_md_pipelines_free(struct fimc_md *fmd) } } -/* Parse port node and register as a sub-device any sensor specified there. */ -static int fimc_md_parse_port_node(struct fimc_md *fmd, - struct device_node *port, - unsigned int index) +static int fimc_md_parse_one_endpoint(struct fimc_md *fmd, + struct device_node *ep) { + int index = fmd->num_sensors; struct fimc_source_info *pd = &fmd->sensor[index].pdata; - struct device_node *rem, *ep, *np; + struct device_node *rem, *np; struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 }; int ret; - /* Assume here a port node can have only one endpoint node. */ - ep = of_get_next_child(port, NULL); - if (!ep) - return 0; - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &endpoint); if (ret) { of_node_put(ep); @@ -467,13 +477,28 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, return 0; } +/* Parse port node and register as a sub-device any sensor specified there. */ +static int fimc_md_parse_port_node(struct fimc_md *fmd, + struct device_node *port) +{ + struct device_node *ep; + int ret; + + for_each_child_of_node(port, ep) { + ret = fimc_md_parse_one_endpoint(fmd, ep); + if (ret < 0) + return ret; + } + + return 0; +} + /* Register all SoC external sub-devices */ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct device_node *parent = fmd->pdev->dev.of_node; struct device_node *ports = NULL; struct device_node *node; - int index = 0; int ret; /* @@ -484,8 +509,10 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) return -ENXIO; ret = pm_runtime_get_sync(fmd->pmf); - if (ret < 0) + if (ret < 0) { + pm_runtime_put(fmd->pmf); return ret; + } fmd->num_sensors = 0; @@ -500,13 +527,12 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) if (!port) continue; - ret = fimc_md_parse_port_node(fmd, port, index); + ret = fimc_md_parse_port_node(fmd, port); of_node_put(port); if (ret < 0) { of_node_put(node); goto cleanup; } - index++; } /* Attach sensors listed in the parallel-ports node */ @@ -515,12 +541,11 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) goto rpm_put; for_each_child_of_node(ports, node) { - ret = fimc_md_parse_port_node(fmd, node, index); + ret = fimc_md_parse_port_node(fmd, node); if (ret < 0) { of_node_put(node); goto cleanup; } - index++; } of_node_put(ports); @@ -1254,28 +1279,6 @@ static ssize_t fimc_md_sysfs_store(struct device *dev, static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, fimc_md_sysfs_show, fimc_md_sysfs_store); -static int fimc_md_get_pinctrl(struct fimc_md *fmd) -{ - struct device *dev = &fmd->pdev->dev; - struct fimc_pinctrl *pctl = &fmd->pinctl; - - pctl->pinctrl = devm_pinctrl_get(dev); - if (IS_ERR(pctl->pinctrl)) - return PTR_ERR(pctl->pinctrl); - - pctl->state_default = pinctrl_lookup_state(pctl->pinctrl, - PINCTRL_STATE_DEFAULT); - if (IS_ERR(pctl->state_default)) - return PTR_ERR(pctl->state_default); - - pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl, - PINCTRL_STATE_IDLE); - if (IS_ERR(pctl->state_idle)) - return PTR_ERR(pctl->state_idle); - - return 0; -} - static int cam_clk_prepare(struct clk_hw *hw) { struct cam_clk *camclk = to_cam_clk(hw); @@ -1431,6 +1434,7 @@ static int fimc_md_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct v4l2_device *v4l2_dev; + struct pinctrl *pinctrl; struct fimc_md *fmd; int ret; @@ -1467,8 +1471,9 @@ static int fimc_md_probe(struct platform_device *pdev) if (ret) goto err_v4l2dev; - ret = fimc_md_get_pinctrl(fmd); - if (ret < 0) { + pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); if (ret != EPROBE_DEFER) dev_err(dev, "Failed to get pinctrl: %d\n", ret); goto err_clk; diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 4b8f9ac52ebc..9447fafe23c6 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -27,8 +27,6 @@ #define FIMC_IS_OF_NODE_NAME "fimc-is" #define CSIS_OF_NODE_NAME "csis" -#define PINCTRL_STATE_IDLE "idle" - #define FIMC_MAX_SENSORS 4 #define FIMC_MAX_CAMCLKS 2 #define DEFAULT_SENSOR_CLK_FREQ 24000000U @@ -109,9 +107,6 @@ struct cam_clk { * @media_dev: top level media device * @v4l2_dev: top level v4l2_device holding up the subdevs * @pdev: platform device this media device is hooked up into - * @pinctrl: camera port pinctrl handle - * @state_default: pinctrl default state handle - * @state_idle: pinctrl idle state handle * @cam_clk_provider: CAMCLK clock provider structure * @user_subdev_api: true if subdevs are not configured by the host driver * @slock: spinlock protecting @sensor array @@ -131,12 +126,6 @@ struct fimc_md { struct v4l2_device v4l2_dev; struct platform_device *pdev; - struct fimc_pinctrl { - struct pinctrl *pinctrl; - struct pinctrl_state *state_default; - struct pinctrl_state *state_idle; - } pinctl; - struct cam_clk_provider { struct clk *clks[FIMC_MAX_CAMCLKS]; struct clk_onecell_data clk_data; diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 540151bbf58f..1aac167abb17 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -510,8 +510,10 @@ static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable) if (enable) { s5pcsis_clear_counters(state); ret = pm_runtime_get_sync(&state->pdev->dev); - if (ret && ret != 1) + if (ret && ret != 1) { + pm_runtime_put_noidle(&state->pdev->dev); return ret; + } } mutex_lock(&state->lock); diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 84633a3b8475..4f2a0f992905 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -32,7 +32,7 @@ #define VIU_VERSION "0.5.1" /* Allow building this driver with COMPILE_TEST */ -#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE) +#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE) && !defined(CONFIG_M68K) #define out_be32(v, a) iowrite32be(a, (void __iomem *)v) #define in_be32(a) ioread32be((void __iomem *)a) #endif diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index 58b9915ac7a4..00f623d62c96 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -497,6 +497,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); if (cam == NULL) goto out; + pci_set_drvdata(pdev, cam); cam->pdev = pdev; mcam = &cam->mcam; mcam->chip_id = MCAM_CAFE; @@ -592,8 +593,7 @@ static void cafe_shutdown(struct cafe_camera *cam) static void cafe_pci_remove(struct pci_dev *pdev) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct cafe_camera *cam = to_cam(v4l2_dev); + struct cafe_camera *cam = pci_get_drvdata(pdev); if (cam == NULL) { printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev); @@ -609,8 +609,7 @@ static void cafe_pci_remove(struct pci_dev *pdev) */ static int __maybe_unused cafe_pci_suspend(struct device *dev) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); - struct cafe_camera *cam = to_cam(v4l2_dev); + struct cafe_camera *cam = dev_get_drvdata(dev); mccic_suspend(&cam->mcam); return 0; @@ -619,8 +618,7 @@ static int __maybe_unused cafe_pci_suspend(struct device *dev) static int __maybe_unused cafe_pci_resume(struct device *dev) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); - struct cafe_camera *cam = to_cam(v4l2_dev); + struct cafe_camera *cam = dev_get_drvdata(dev); cafe_ctlr_init(&cam->mcam); return mccic_resume(&cam->mcam); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 3d4242b8182b..c012fd2e1d29 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -24,6 +24,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/videodev2.h> +#include <linux/pm_runtime.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> @@ -388,7 +389,7 @@ static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime) dma_free_coherent(cam->dev, cam->dma_buf_size, cam->dma_bufs[0], cam->dma_handles[0]); cam->nbufs = 0; - /* fall-through */ + fallthrough; case 0: cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); return -ENOMEM; @@ -438,9 +439,9 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam) /* * Copy data out to user space in the vmalloc case */ -static void mcam_frame_tasklet(unsigned long data) +static void mcam_frame_tasklet(struct tasklet_struct *t) { - struct mcam_camera *cam = (struct mcam_camera *) data; + struct mcam_camera *cam = from_tasklet(cam, t, s_tasklet); int i; unsigned long flags; struct mcam_vb_buffer *buf; @@ -895,30 +896,6 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam) /* ---------------------------------------------------------------------- */ /* - * Controller clocks. - */ -static void mcam_clk_enable(struct mcam_camera *mcam) -{ - unsigned int i; - - for (i = 0; i < NR_MCAM_CLK; i++) { - if (!IS_ERR(mcam->clk[i])) - clk_prepare_enable(mcam->clk[i]); - } -} - -static void mcam_clk_disable(struct mcam_camera *mcam) -{ - int i; - - for (i = NR_MCAM_CLK - 1; i >= 0; i--) { - if (!IS_ERR(mcam->clk[i])) - clk_disable_unprepare(mcam->clk[i]); - } -} - -/* ---------------------------------------------------------------------- */ -/* * Master sensor clock. */ static int mclk_prepare(struct clk_hw *hw) @@ -1323,8 +1300,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam) break; case B_vmalloc: #ifdef MCAM_MODE_VMALLOC - tasklet_init(&cam->s_tasklet, mcam_frame_tasklet, - (unsigned long) cam); + tasklet_setup(&cam->s_tasklet, mcam_frame_tasklet); vq->ops = &mcam_vb2_ops; vq->mem_ops = &vb2_vmalloc_memops; cam->dma_setup = mcam_ctlr_dma_vmalloc; @@ -1633,7 +1609,7 @@ static int mcam_v4l_open(struct file *filp) ret = sensor_call(cam, core, s_power, 1); if (ret) goto out; - mcam_clk_enable(cam); + pm_runtime_get_sync(cam->dev); __mcam_cam_reset(cam); mcam_set_config_needed(cam, 1); } @@ -1656,7 +1632,7 @@ static int mcam_v4l_release(struct file *filp) if (last_open) { mcam_disable_mipi(cam); sensor_call(cam, core, s_power, 0); - mcam_clk_disable(cam); + pm_runtime_put(cam->dev); if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) mcam_free_dma_bufs(cam); } @@ -1977,7 +1953,6 @@ void mccic_suspend(struct mcam_camera *cam) mcam_ctlr_stop_dma(cam); sensor_call(cam, core, s_power, 0); - mcam_clk_disable(cam); cam->state = cstate; } mutex_unlock(&cam->s_mutex); @@ -1990,7 +1965,6 @@ int mccic_resume(struct mcam_camera *cam) mutex_lock(&cam->s_mutex); if (!list_empty(&cam->vdev.fh_list)) { - mcam_clk_enable(cam); ret = sensor_call(cam, core, s_power, 1); if (ret) { mutex_unlock(&cam->s_mutex); diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 92b92255dac6..cd902b180669 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -20,6 +20,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/io.h> #include <linux/list.h> #include <linux/pm.h> @@ -47,49 +48,6 @@ static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam) } /* - * A silly little infrastructure so we can keep track of our devices. - * Chances are that we will never have more than one of them, but - * the Armada 610 *does* have two controllers... - */ - -static LIST_HEAD(mmpcam_devices); -static struct mutex mmpcam_devices_lock; - -static void mmpcam_add_device(struct mmp_camera *cam) -{ - mutex_lock(&mmpcam_devices_lock); - list_add(&cam->devlist, &mmpcam_devices); - mutex_unlock(&mmpcam_devices_lock); -} - -static void mmpcam_remove_device(struct mmp_camera *cam) -{ - mutex_lock(&mmpcam_devices_lock); - list_del(&cam->devlist); - mutex_unlock(&mmpcam_devices_lock); -} - -/* - * Platform dev remove passes us a platform_device, and there's - * no handy unused drvdata to stash a backpointer in. So just - * dig it out of our list. - */ -static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev) -{ - struct mmp_camera *cam; - - mutex_lock(&mmpcam_devices_lock); - list_for_each_entry(cam, &mmpcam_devices, devlist) { - if (cam->pdev == pdev) { - mutex_unlock(&mmpcam_devices_lock); - return cam; - } - } - mutex_unlock(&mmpcam_devices_lock); - return NULL; -} - -/* * calc the dphy register values * There are three dphy registers being used. * dphy[0] - CSI2_DPHY3 @@ -227,6 +185,7 @@ static int mmpcam_probe(struct platform_device *pdev) cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL); if (cam == NULL) return -ENOMEM; + platform_set_drvdata(pdev, cam); cam->pdev = pdev; INIT_LIST_HEAD(&cam->devlist); @@ -313,11 +272,11 @@ static int mmpcam_probe(struct platform_device *pdev) cam->irq = res->start; ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED, "mmp-camera", mcam); - if (ret == 0) { - mmpcam_add_device(cam); - return 0; - } + if (ret) + goto out; + pm_runtime_enable(&pdev->dev); + return 0; out: fwnode_handle_put(mcam->asd.match.fwnode); mccic_shutdown(mcam); @@ -330,14 +289,14 @@ static int mmpcam_remove(struct mmp_camera *cam) { struct mcam_camera *mcam = &cam->mcam; - mmpcam_remove_device(cam); mccic_shutdown(mcam); + pm_runtime_force_suspend(mcam->dev); return 0; } static int mmpcam_platform_remove(struct platform_device *pdev) { - struct mmp_camera *cam = mmpcam_find_device(pdev); + struct mmp_camera *cam = platform_get_drvdata(pdev); if (cam == NULL) return -ENODEV; @@ -347,26 +306,57 @@ static int mmpcam_platform_remove(struct platform_device *pdev) /* * Suspend/resume support. */ -#ifdef CONFIG_PM -static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state) +static int mmpcam_runtime_resume(struct device *dev) +{ + struct mmp_camera *cam = dev_get_drvdata(dev); + struct mcam_camera *mcam = &cam->mcam; + unsigned int i; + + for (i = 0; i < NR_MCAM_CLK; i++) { + if (!IS_ERR(mcam->clk[i])) + clk_prepare_enable(mcam->clk[i]); + } + + return 0; +} + +static int mmpcam_runtime_suspend(struct device *dev) +{ + struct mmp_camera *cam = dev_get_drvdata(dev); + struct mcam_camera *mcam = &cam->mcam; + int i; + + for (i = NR_MCAM_CLK - 1; i >= 0; i--) { + if (!IS_ERR(mcam->clk[i])) + clk_disable_unprepare(mcam->clk[i]); + } + + return 0; +} + +static int __maybe_unused mmpcam_suspend(struct device *dev) { - struct mmp_camera *cam = mmpcam_find_device(pdev); + struct mmp_camera *cam = dev_get_drvdata(dev); - if (state.event != PM_EVENT_SUSPEND) - return 0; - mccic_suspend(&cam->mcam); + if (!pm_runtime_suspended(dev)) + mccic_suspend(&cam->mcam); return 0; } -static int mmpcam_resume(struct platform_device *pdev) +static int __maybe_unused mmpcam_resume(struct device *dev) { - struct mmp_camera *cam = mmpcam_find_device(pdev); + struct mmp_camera *cam = dev_get_drvdata(dev); - return mccic_resume(&cam->mcam); + if (!pm_runtime_suspended(dev)) + return mccic_resume(&cam->mcam); + return 0; } -#endif +static const struct dev_pm_ops mmpcam_pm_ops = { + SET_RUNTIME_PM_OPS(mmpcam_runtime_suspend, mmpcam_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(mmpcam_suspend, mmpcam_resume) +}; static const struct of_device_id mmpcam_of_match[] = { { .compatible = "marvell,mmp2-ccic", }, @@ -377,32 +367,11 @@ MODULE_DEVICE_TABLE(of, mmpcam_of_match); static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, .remove = mmpcam_platform_remove, -#ifdef CONFIG_PM - .suspend = mmpcam_suspend, - .resume = mmpcam_resume, -#endif .driver = { .name = "mmp-camera", .of_match_table = of_match_ptr(mmpcam_of_match), + .pm = &mmpcam_pm_ops, } }; - -static int __init mmpcam_init_module(void) -{ - mutex_init(&mmpcam_devices_lock); - return platform_driver_register(&mmpcam_driver); -} - -static void __exit mmpcam_exit_module(void) -{ - platform_driver_unregister(&mmpcam_driver); - /* - * platform_driver_unregister() should have emptied the list - */ - if (!list_empty(&mmpcam_devices)) - printk(KERN_ERR "mmp_camera leaving devices behind\n"); -} - -module_init(mmpcam_init_module); -module_exit(mmpcam_exit_module); +module_platform_driver(mmpcam_driver); diff --git a/drivers/media/platform/mtk-jpeg/Makefile b/drivers/media/platform/mtk-jpeg/Makefile index 92a4fc046bfe..76c33aad0f3f 100644 --- a/drivers/media/platform/mtk-jpeg/Makefile +++ b/drivers/media/platform/mtk-jpeg/Makefile @@ -1,3 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -mtk_jpeg-objs := mtk_jpeg_core.o mtk_jpeg_hw.o mtk_jpeg_parse.o +mtk_jpeg-objs := mtk_jpeg_core.o \ + mtk_jpeg_dec_hw.o \ + mtk_jpeg_dec_parse.o \ + mtk_jpeg_enc_hw.o obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 61fed1e35a00..227245ccaedc 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -3,6 +3,7 @@ * Copyright (c) 2016 MediaTek Inc. * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> * Rick Chang <rick.chang@mediatek.com> + * Xia Jiang <xia.jiang@mediatek.com> */ #include <linux/clk.h> @@ -23,15 +24,64 @@ #include <media/videobuf2-dma-contig.h> #include <soc/mediatek/smi.h> -#include "mtk_jpeg_hw.h" +#include "mtk_jpeg_enc_hw.h" +#include "mtk_jpeg_dec_hw.h" #include "mtk_jpeg_core.h" -#include "mtk_jpeg_parse.h" +#include "mtk_jpeg_dec_parse.h" -static struct mtk_jpeg_fmt mtk_jpeg_formats[] = { +static struct mtk_jpeg_fmt mtk_jpeg_enc_formats[] = { { .fourcc = V4L2_PIX_FMT_JPEG, .colplanes = 1, - .flags = MTK_JPEG_FMT_FLAG_DEC_OUTPUT, + .flags = MTK_JPEG_FMT_FLAG_CAPTURE, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .hw_format = JPEG_ENC_YUV_FORMAT_NV12, + .h_sample = {4, 4}, + .v_sample = {4, 2}, + .colplanes = 2, + .h_align = 4, + .v_align = 4, + .flags = MTK_JPEG_FMT_FLAG_OUTPUT, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .hw_format = JEPG_ENC_YUV_FORMAT_NV21, + .h_sample = {4, 4}, + .v_sample = {4, 2}, + .colplanes = 2, + .h_align = 4, + .v_align = 4, + .flags = MTK_JPEG_FMT_FLAG_OUTPUT, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .hw_format = JPEG_ENC_YUV_FORMAT_YUYV, + .h_sample = {8}, + .v_sample = {4}, + .colplanes = 1, + .h_align = 5, + .v_align = 3, + .flags = MTK_JPEG_FMT_FLAG_OUTPUT, + }, + { + .fourcc = V4L2_PIX_FMT_YVYU, + .hw_format = JPEG_ENC_YUV_FORMAT_YVYU, + .h_sample = {8}, + .v_sample = {4}, + .colplanes = 1, + .h_align = 5, + .v_align = 3, + .flags = MTK_JPEG_FMT_FLAG_OUTPUT, + }, +}; + +static struct mtk_jpeg_fmt mtk_jpeg_dec_formats[] = { + { + .fourcc = V4L2_PIX_FMT_JPEG, + .colplanes = 1, + .flags = MTK_JPEG_FMT_FLAG_OUTPUT, }, { .fourcc = V4L2_PIX_FMT_YUV420M, @@ -40,7 +90,7 @@ static struct mtk_jpeg_fmt mtk_jpeg_formats[] = { .colplanes = 3, .h_align = 5, .v_align = 4, - .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE, + .flags = MTK_JPEG_FMT_FLAG_CAPTURE, }, { .fourcc = V4L2_PIX_FMT_YUV422M, @@ -49,27 +99,27 @@ static struct mtk_jpeg_fmt mtk_jpeg_formats[] = { .colplanes = 3, .h_align = 5, .v_align = 3, - .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE, + .flags = MTK_JPEG_FMT_FLAG_CAPTURE, }, }; -#define MTK_JPEG_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_formats) - -enum { - MTK_JPEG_BUF_FLAGS_INIT = 0, - MTK_JPEG_BUF_FLAGS_LAST_FRAME = 1, -}; +#define MTK_JPEG_ENC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_enc_formats) +#define MTK_JPEG_DEC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_dec_formats) struct mtk_jpeg_src_buf { struct vb2_v4l2_buffer b; struct list_head list; - int flags; struct mtk_jpeg_dec_param dec_param; }; static int debug; module_param(debug, int, 0644); +static inline struct mtk_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct mtk_jpeg_ctx, ctrl_hdl); +} + static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh) { return container_of(fh, struct mtk_jpeg_ctx, fh); @@ -86,14 +136,61 @@ static int mtk_jpeg_querycap(struct file *file, void *priv, { struct mtk_jpeg_dev *jpeg = video_drvdata(file); - strscpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver)); - strscpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card)); + strscpy(cap->driver, jpeg->variant->dev_name, sizeof(cap->driver)); + strscpy(cap->card, jpeg->variant->dev_name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(jpeg->dev)); return 0; } +static int vidioc_jpeg_enc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_jpeg_ctx *ctx = ctrl_to_ctx(ctrl); + + switch (ctrl->id) { + case V4L2_CID_JPEG_RESTART_INTERVAL: + ctx->restart_interval = ctrl->val; + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + ctx->enc_quality = ctrl->val; + break; + case V4L2_CID_JPEG_ACTIVE_MARKER: + ctx->enable_exif = ctrl->val & V4L2_JPEG_ACTIVE_MARKER_APP1; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops mtk_jpeg_enc_ctrl_ops = { + .s_ctrl = vidioc_jpeg_enc_s_ctrl, +}; + +static int mtk_jpeg_enc_ctrls_setup(struct mtk_jpeg_ctx *ctx) +{ + const struct v4l2_ctrl_ops *ops = &mtk_jpeg_enc_ctrl_ops; + struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl; + + v4l2_ctrl_handler_init(handler, 3); + + v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, + 1, 0); + v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_COMPRESSION_QUALITY, 48, + 100, 1, 90); + v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_ACTIVE_MARKER, 0, + V4L2_JPEG_ACTIVE_MARKER_APP1, 0, 0); + + if (handler->error) { + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + return handler->error; + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); + + return 0; +} + static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n, struct v4l2_fmtdesc *f, u32 type) { @@ -118,15 +215,23 @@ static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n, static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f, - MTK_JPEG_FMT_FLAG_DEC_CAPTURE); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + + return mtk_jpeg_enum_fmt(jpeg->variant->formats, + jpeg->variant->num_formats, f, + MTK_JPEG_FMT_FLAG_CAPTURE); } static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f, - MTK_JPEG_FMT_FLAG_DEC_OUTPUT); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + + return mtk_jpeg_enum_fmt(jpeg->variant->formats, + jpeg->variant->num_formats, f, + MTK_JPEG_FMT_FLAG_OUTPUT); } static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx, @@ -137,126 +242,63 @@ static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx, return &ctx->cap_q; } -static struct mtk_jpeg_fmt *mtk_jpeg_find_format(struct mtk_jpeg_ctx *ctx, - u32 pixelformat, - unsigned int fmt_type) +static struct mtk_jpeg_fmt * +mtk_jpeg_find_format(struct mtk_jpeg_fmt *mtk_jpeg_formats, int num_formats, + u32 pixelformat, unsigned int fmt_type) { - unsigned int k, fmt_flag; - - fmt_flag = (fmt_type == MTK_JPEG_FMT_TYPE_OUTPUT) ? - MTK_JPEG_FMT_FLAG_DEC_OUTPUT : - MTK_JPEG_FMT_FLAG_DEC_CAPTURE; + unsigned int k; + struct mtk_jpeg_fmt *fmt; - for (k = 0; k < MTK_JPEG_NUM_FORMATS; k++) { - struct mtk_jpeg_fmt *fmt = &mtk_jpeg_formats[k]; + for (k = 0; k < num_formats; k++) { + fmt = &mtk_jpeg_formats[k]; - if (fmt->fourcc == pixelformat && fmt->flags & fmt_flag) + if (fmt->fourcc == pixelformat && fmt->flags & fmt_type) return fmt; } return NULL; } -static void mtk_jpeg_bound_align_image(u32 *w, unsigned int wmin, - unsigned int wmax, unsigned int walign, - u32 *h, unsigned int hmin, - unsigned int hmax, unsigned int halign) +static int mtk_jpeg_try_fmt_mplane(struct v4l2_pix_format_mplane *pix_mp, + struct mtk_jpeg_fmt *fmt) { - int width, height, w_step, h_step; - - width = *w; - height = *h; - w_step = 1 << walign; - h_step = 1 << halign; - - v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0); - if (*w < width && (*w + w_step) <= wmax) - *w += w_step; - if (*h < height && (*h + h_step) <= hmax) - *h += h_step; -} - -static void mtk_jpeg_adjust_fmt_mplane(struct mtk_jpeg_ctx *ctx, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct mtk_jpeg_q_data *q_data; - int i; - - q_data = mtk_jpeg_get_q_data(ctx, f->type); - - pix_mp->width = q_data->w; - pix_mp->height = q_data->h; - pix_mp->pixelformat = q_data->fmt->fourcc; - pix_mp->num_planes = q_data->fmt->colplanes; - - for (i = 0; i < pix_mp->num_planes; i++) { - pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i]; - pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i]; - } -} - -static int mtk_jpeg_try_fmt_mplane(struct v4l2_format *f, - struct mtk_jpeg_fmt *fmt, - struct mtk_jpeg_ctx *ctx, int q_type) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct mtk_jpeg_dev *jpeg = ctx->jpeg; int i; - memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); pix_mp->field = V4L2_FIELD_NONE; - if (ctx->state != MTK_JPEG_INIT) { - mtk_jpeg_adjust_fmt_mplane(ctx, f); - goto end; - } - pix_mp->num_planes = fmt->colplanes; pix_mp->pixelformat = fmt->fourcc; - if (q_type == MTK_JPEG_FMT_TYPE_OUTPUT) { + if (fmt->fourcc == V4L2_PIX_FMT_JPEG) { struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0]; - mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH, - MTK_JPEG_MAX_WIDTH, 0, - &pix_mp->height, MTK_JPEG_MIN_HEIGHT, - MTK_JPEG_MAX_HEIGHT, 0); + pix_mp->height = clamp(pix_mp->height, MTK_JPEG_MIN_HEIGHT, + MTK_JPEG_MAX_HEIGHT); + pix_mp->width = clamp(pix_mp->width, MTK_JPEG_MIN_WIDTH, + MTK_JPEG_MAX_WIDTH); - memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); pfmt->bytesperline = 0; /* Source size must be aligned to 128 */ - pfmt->sizeimage = mtk_jpeg_align(pfmt->sizeimage, 128); + pfmt->sizeimage = round_up(pfmt->sizeimage, 128); if (pfmt->sizeimage == 0) pfmt->sizeimage = MTK_JPEG_DEFAULT_SIZEIMAGE; - goto end; + return 0; } - /* type is MTK_JPEG_FMT_TYPE_CAPTURE */ - mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH, - MTK_JPEG_MAX_WIDTH, fmt->h_align, - &pix_mp->height, MTK_JPEG_MIN_HEIGHT, - MTK_JPEG_MAX_HEIGHT, fmt->v_align); + /* other fourcc */ + pix_mp->height = clamp(round_up(pix_mp->height, fmt->v_align), + MTK_JPEG_MIN_HEIGHT, MTK_JPEG_MAX_HEIGHT); + pix_mp->width = clamp(round_up(pix_mp->width, fmt->h_align), + MTK_JPEG_MIN_WIDTH, MTK_JPEG_MAX_WIDTH); for (i = 0; i < fmt->colplanes; i++) { struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i]; u32 stride = pix_mp->width * fmt->h_sample[i] / 4; u32 h = pix_mp->height * fmt->v_sample[i] / 4; - memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); pfmt->bytesperline = stride; pfmt->sizeimage = stride * h; } -end: - v4l2_dbg(2, debug, &jpeg->v4l2_dev, "wxh:%ux%u\n", - pix_mp->width, pix_mp->height); - for (i = 0; i < pix_mp->num_planes; i++) { - v4l2_dbg(2, debug, &jpeg->v4l2_dev, - "plane[%d] bpl=%u, size=%u\n", - i, - pix_mp->plane_fmt[i].bytesperline, - pix_mp->plane_fmt[i].sizeimage); - } return 0; } @@ -276,16 +318,15 @@ static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv, q_data = mtk_jpeg_get_q_data(ctx, f->type); - memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); - pix_mp->width = q_data->w; - pix_mp->height = q_data->h; + pix_mp->width = q_data->pix_mp.width; + pix_mp->height = q_data->pix_mp.height; pix_mp->field = V4L2_FIELD_NONE; pix_mp->pixelformat = q_data->fmt->fourcc; pix_mp->num_planes = q_data->fmt->colplanes; - pix_mp->colorspace = ctx->colorspace; - pix_mp->ycbcr_enc = ctx->ycbcr_enc; - pix_mp->xfer_func = ctx->xfer_func; - pix_mp->quantization = ctx->quantization; + pix_mp->colorspace = q_data->pix_mp.colorspace; + pix_mp->ycbcr_enc = q_data->pix_mp.ycbcr_enc; + pix_mp->xfer_func = q_data->pix_mp.xfer_func; + pix_mp->quantization = q_data->pix_mp.quantization; v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) g_fmt:%c%c%c%c wxh:%ux%u\n", f->type, @@ -298,9 +339,8 @@ static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv, for (i = 0; i < pix_mp->num_planes; i++) { struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i]; - pfmt->bytesperline = q_data->bytesperline[i]; - pfmt->sizeimage = q_data->sizeimage[i]; - memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); + pfmt->bytesperline = q_data->pix_mp.plane_fmt[i].bytesperline; + pfmt->sizeimage = q_data->pix_mp.plane_fmt[i].sizeimage; v4l2_dbg(1, debug, &jpeg->v4l2_dev, "plane[%d] bpl=%u, size=%u\n", @@ -315,10 +355,13 @@ static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_dev *jpeg = ctx->jpeg; struct mtk_jpeg_fmt *fmt; - fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat, - MTK_JPEG_FMT_TYPE_CAPTURE); + fmt = mtk_jpeg_find_format(jpeg->variant->formats, + jpeg->variant->num_formats, + f->fmt.pix_mp.pixelformat, + MTK_JPEG_FMT_FLAG_CAPTURE); if (!fmt) fmt = ctx->cap_q.fmt; @@ -329,17 +372,25 @@ static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv, (fmt->fourcc >> 16 & 0xff), (fmt->fourcc >> 24 & 0xff)); - return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_CAPTURE); + if (ctx->state != MTK_JPEG_INIT) { + mtk_jpeg_g_fmt_vid_mplane(file, priv, f); + return 0; + } + + return mtk_jpeg_try_fmt_mplane(&f->fmt.pix_mp, fmt); } static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_dev *jpeg = ctx->jpeg; struct mtk_jpeg_fmt *fmt; - fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat, - MTK_JPEG_FMT_TYPE_OUTPUT); + fmt = mtk_jpeg_find_format(jpeg->variant->formats, + jpeg->variant->num_formats, + f->fmt.pix_mp.pixelformat, + MTK_JPEG_FMT_FLAG_OUTPUT); if (!fmt) fmt = ctx->out_q.fmt; @@ -350,17 +401,21 @@ static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv, (fmt->fourcc >> 16 & 0xff), (fmt->fourcc >> 24 & 0xff)); - return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_OUTPUT); + if (ctx->state != MTK_JPEG_INIT) { + mtk_jpeg_g_fmt_vid_mplane(file, priv, f); + return 0; + } + + return mtk_jpeg_try_fmt_mplane(&f->fmt.pix_mp, fmt); } static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx, - struct v4l2_format *f) + struct v4l2_format *f, unsigned int fmt_type) { struct vb2_queue *vq; struct mtk_jpeg_q_data *q_data = NULL; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; struct mtk_jpeg_dev *jpeg = ctx->jpeg; - unsigned int f_type; int i; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); @@ -374,16 +429,17 @@ static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx, return -EBUSY; } - f_type = V4L2_TYPE_IS_OUTPUT(f->type) ? - MTK_JPEG_FMT_TYPE_OUTPUT : MTK_JPEG_FMT_TYPE_CAPTURE; - - q_data->fmt = mtk_jpeg_find_format(ctx, pix_mp->pixelformat, f_type); - q_data->w = pix_mp->width; - q_data->h = pix_mp->height; - ctx->colorspace = pix_mp->colorspace; - ctx->ycbcr_enc = pix_mp->ycbcr_enc; - ctx->xfer_func = pix_mp->xfer_func; - ctx->quantization = pix_mp->quantization; + q_data->fmt = mtk_jpeg_find_format(jpeg->variant->formats, + jpeg->variant->num_formats, + pix_mp->pixelformat, fmt_type); + q_data->pix_mp.width = pix_mp->width; + q_data->pix_mp.height = pix_mp->height; + q_data->enc_crop_rect.width = pix_mp->width; + q_data->enc_crop_rect.height = pix_mp->height; + q_data->pix_mp.colorspace = V4L2_COLORSPACE_SRGB; + q_data->pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_601; + q_data->pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB; + q_data->pix_mp.quantization = V4L2_QUANTIZATION_FULL_RANGE; v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) s_fmt:%c%c%c%c wxh:%ux%u\n", f->type, @@ -391,15 +447,18 @@ static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx, (q_data->fmt->fourcc >> 8 & 0xff), (q_data->fmt->fourcc >> 16 & 0xff), (q_data->fmt->fourcc >> 24 & 0xff), - q_data->w, q_data->h); + q_data->pix_mp.width, q_data->pix_mp.height); for (i = 0; i < q_data->fmt->colplanes; i++) { - q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline; - q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage; + q_data->pix_mp.plane_fmt[i].bytesperline = + pix_mp->plane_fmt[i].bytesperline; + q_data->pix_mp.plane_fmt[i].sizeimage = + pix_mp->plane_fmt[i].sizeimage; v4l2_dbg(1, debug, &jpeg->v4l2_dev, "plane[%d] bpl=%u, size=%u\n", - i, q_data->bytesperline[i], q_data->sizeimage[i]); + i, q_data->pix_mp.plane_fmt[i].bytesperline, + q_data->pix_mp.plane_fmt[i].sizeimage); } return 0; @@ -414,7 +473,8 @@ static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv, if (ret) return ret; - return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f); + return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f, + MTK_JPEG_FMT_FLAG_OUTPUT); } static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv, @@ -426,7 +486,8 @@ static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv, if (ret) return ret; - return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f); + return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f, + MTK_JPEG_FMT_FLAG_CAPTURE); } static void mtk_jpeg_queue_src_chg_event(struct mtk_jpeg_ctx *ctx) @@ -446,13 +507,38 @@ static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh, switch (sub->type) { case V4L2_EVENT_SOURCE_CHANGE: return v4l2_src_change_event_subscribe(fh, sub); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static int mtk_jpeg_enc_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + s->r = ctx->out_q.enc_crop_rect; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r.width = ctx->out_q.pix_mp.width; + s->r.height = ctx->out_q.pix_mp.height; + s->r.left = 0; + s->r.top = 0; + break; default: return -EINVAL; } + return 0; } -static int mtk_jpeg_g_selection(struct file *file, void *priv, - struct v4l2_selection *s) +static int mtk_jpeg_dec_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) { struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); @@ -462,15 +548,15 @@ static int mtk_jpeg_g_selection(struct file *file, void *priv, switch (s->target) { case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_COMPOSE_DEFAULT: - s->r.width = ctx->out_q.w; - s->r.height = ctx->out_q.h; + s->r.width = ctx->out_q.pix_mp.width; + s->r.height = ctx->out_q.pix_mp.height; s->r.left = 0; s->r.top = 0; break; case V4L2_SEL_TGT_COMPOSE_BOUNDS: case V4L2_SEL_TGT_COMPOSE_PADDED: - s->r.width = ctx->cap_q.w; - s->r.height = ctx->cap_q.h; + s->r.width = ctx->cap_q.pix_mp.width; + s->r.height = ctx->cap_q.pix_mp.height; s->r.left = 0; s->r.top = 0; break; @@ -480,53 +566,57 @@ static int mtk_jpeg_g_selection(struct file *file, void *priv, return 0; } -static int mtk_jpeg_s_selection(struct file *file, void *priv, - struct v4l2_selection *s) +static int mtk_jpeg_enc_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) { struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; switch (s->target) { - case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_CROP: s->r.left = 0; s->r.top = 0; - s->r.width = ctx->out_q.w; - s->r.height = ctx->out_q.h; + s->r.width = min(s->r.width, ctx->out_q.pix_mp.width); + s->r.height = min(s->r.height, ctx->out_q.pix_mp.height); + ctx->out_q.enc_crop_rect = s->r; break; default: return -EINVAL; } + return 0; } -static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct v4l2_fh *fh = file->private_data; - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); - struct vb2_queue *vq; - struct vb2_buffer *vb; - struct mtk_jpeg_src_buf *jpeg_src_buf; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - goto end; +static const struct v4l2_ioctl_ops mtk_jpeg_enc_ioctl_ops = { + .vidioc_querycap = mtk_jpeg_querycap, + .vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = mtk_jpeg_enum_fmt_vid_out, + .vidioc_try_fmt_vid_cap_mplane = mtk_jpeg_try_fmt_vid_cap_mplane, + .vidioc_try_fmt_vid_out_mplane = mtk_jpeg_try_fmt_vid_out_mplane, + .vidioc_g_fmt_vid_cap_mplane = mtk_jpeg_g_fmt_vid_mplane, + .vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane, + .vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_subscribe_event = mtk_jpeg_subscribe_event, + .vidioc_g_selection = mtk_jpeg_enc_g_selection, + .vidioc_s_selection = mtk_jpeg_enc_s_selection, - vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type); - if (buf->index >= vq->num_buffers) { - dev_err(ctx->jpeg->dev, "buffer index out of range\n"); - return -EINVAL; - } + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - vb = vb2_get_buffer(vq, buf->index); - jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb); - jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ? - MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT; -end: - return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf); -} + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; -static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = { +static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = { .vidioc_querycap = mtk_jpeg_querycap, .vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap, .vidioc_enum_fmt_vid_out = mtk_jpeg_enum_fmt_vid_out, @@ -536,10 +626,9 @@ static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = { .vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane, .vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane, .vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane, - .vidioc_qbuf = mtk_jpeg_qbuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, .vidioc_subscribe_event = mtk_jpeg_subscribe_event, - .vidioc_g_selection = mtk_jpeg_g_selection, - .vidioc_s_selection = mtk_jpeg_s_selection, + .vidioc_g_selection = mtk_jpeg_dec_g_selection, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, @@ -571,9 +660,16 @@ static int mtk_jpeg_queue_setup(struct vb2_queue *q, if (!q_data) return -EINVAL; + if (*num_planes) { + for (i = 0; i < *num_planes; i++) + if (sizes[i] < q_data->pix_mp.plane_fmt[i].sizeimage) + return -EINVAL; + return 0; + } + *num_planes = q_data->fmt->colplanes; for (i = 0; i < q_data->fmt->colplanes; i++) { - sizes[i] = q_data->sizeimage[i]; + sizes[i] = q_data->pix_mp.plane_fmt[i].sizeimage; v4l2_dbg(1, debug, &jpeg->v4l2_dev, "sizeimage[%d]=%u\n", i, sizes[i]); } @@ -585,14 +681,22 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb) { struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct mtk_jpeg_q_data *q_data = NULL; + struct v4l2_plane_pix_format plane_fmt = {}; int i; q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type); if (!q_data) return -EINVAL; - for (i = 0; i < q_data->fmt->colplanes; i++) - vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); + for (i = 0; i < q_data->fmt->colplanes; i++) { + plane_fmt = q_data->pix_mp.plane_fmt[i]; + if (ctx->enable_exif && + q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG) + vb2_set_plane_payload(vb, i, plane_fmt.sizeimage + + MTK_JPEG_MAX_EXIF_SIZE); + else + vb2_set_plane_payload(vb, i, plane_fmt.sizeimage); + } return 0; } @@ -604,14 +708,17 @@ static bool mtk_jpeg_check_resolution_change(struct mtk_jpeg_ctx *ctx, struct mtk_jpeg_q_data *q_data; q_data = &ctx->out_q; - if (q_data->w != param->pic_w || q_data->h != param->pic_h) { + if (q_data->pix_mp.width != param->pic_w || + q_data->pix_mp.height != param->pic_h) { v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Picture size change\n"); return true; } q_data = &ctx->cap_q; - if (q_data->fmt != mtk_jpeg_find_format(ctx, param->dst_fourcc, - MTK_JPEG_FMT_TYPE_CAPTURE)) { + if (q_data->fmt != + mtk_jpeg_find_format(jpeg->variant->formats, + jpeg->variant->num_formats, param->dst_fourcc, + MTK_JPEG_FMT_FLAG_CAPTURE)) { v4l2_dbg(1, debug, &jpeg->v4l2_dev, "format change\n"); return true; } @@ -626,19 +733,20 @@ static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx, int i; q_data = &ctx->out_q; - q_data->w = param->pic_w; - q_data->h = param->pic_h; + q_data->pix_mp.width = param->pic_w; + q_data->pix_mp.height = param->pic_h; q_data = &ctx->cap_q; - q_data->w = param->dec_w; - q_data->h = param->dec_h; - q_data->fmt = mtk_jpeg_find_format(ctx, + q_data->pix_mp.width = param->dec_w; + q_data->pix_mp.height = param->dec_h; + q_data->fmt = mtk_jpeg_find_format(jpeg->variant->formats, + jpeg->variant->num_formats, param->dst_fourcc, - MTK_JPEG_FMT_TYPE_CAPTURE); + MTK_JPEG_FMT_FLAG_CAPTURE); for (i = 0; i < q_data->fmt->colplanes; i++) { - q_data->bytesperline[i] = param->mem_stride[i]; - q_data->sizeimage[i] = param->comp_size[i]; + q_data->pix_mp.plane_fmt[i].bytesperline = param->mem_stride[i]; + q_data->pix_mp.plane_fmt[i].sizeimage = param->comp_size[i]; } v4l2_dbg(1, debug, &jpeg->v4l2_dev, @@ -651,7 +759,18 @@ static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx, param->dec_w, param->dec_h); } -static void mtk_jpeg_buf_queue(struct vb2_buffer *vb) +static void mtk_jpeg_enc_buf_queue(struct vb2_buffer *vb) +{ + struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + + v4l2_dbg(2, debug, &jpeg->v4l2_dev, "(%d) buf_q id=%d, vb=%p\n", + vb->vb2_queue->type, vb->index, vb); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb)); +} + +static void mtk_jpeg_dec_buf_queue(struct vb2_buffer *vb) { struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct mtk_jpeg_dec_param *param; @@ -669,10 +788,6 @@ static void mtk_jpeg_buf_queue(struct vb2_buffer *vb) param = &jpeg_src_buf->dec_param; memset(param, 0, sizeof(*param)); - if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) { - v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Got eos\n"); - goto end; - } header_valid = mtk_jpeg_parse(param, (u8 *)vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); if (!header_valid) { @@ -703,24 +818,16 @@ static struct vb2_v4l2_buffer *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx, return v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); } -static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) +static void mtk_jpeg_enc_stop_streaming(struct vb2_queue *q) { struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q); struct vb2_v4l2_buffer *vb; - int ret = 0; - ret = pm_runtime_get_sync(ctx->jpeg->dev); - if (ret < 0) - goto err; - - return 0; -err: while ((vb = mtk_jpeg_buf_remove(ctx, q->type))) - v4l2_m2m_buf_done(vb, VB2_BUF_STATE_QUEUED); - return ret; + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); } -static void mtk_jpeg_stop_streaming(struct vb2_queue *q) +static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q) { struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q); struct vb2_v4l2_buffer *vb; @@ -744,18 +851,24 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q) while ((vb = mtk_jpeg_buf_remove(ctx, q->type))) v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); - - pm_runtime_put_sync(ctx->jpeg->dev); } -static const struct vb2_ops mtk_jpeg_qops = { +static const struct vb2_ops mtk_jpeg_dec_qops = { + .queue_setup = mtk_jpeg_queue_setup, + .buf_prepare = mtk_jpeg_buf_prepare, + .buf_queue = mtk_jpeg_dec_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .stop_streaming = mtk_jpeg_dec_stop_streaming, +}; + +static const struct vb2_ops mtk_jpeg_enc_qops = { .queue_setup = mtk_jpeg_queue_setup, .buf_prepare = mtk_jpeg_buf_prepare, - .buf_queue = mtk_jpeg_buf_queue, + .buf_queue = mtk_jpeg_enc_buf_queue, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, - .start_streaming = mtk_jpeg_start_streaming, - .stop_streaming = mtk_jpeg_stop_streaming, + .stop_streaming = mtk_jpeg_enc_stop_streaming, }; static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx, @@ -764,8 +877,8 @@ static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx, { bs->str_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); bs->end_addr = bs->str_addr + - mtk_jpeg_align(vb2_get_plane_payload(src_buf, 0), 16); - bs->size = mtk_jpeg_align(vb2_plane_size(src_buf, 0), 128); + round_up(vb2_get_plane_payload(src_buf, 0), 16); + bs->size = round_up(vb2_plane_size(src_buf, 0), 128); } static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx, @@ -795,7 +908,49 @@ static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx, return 0; } -static void mtk_jpeg_device_run(void *priv) +static void mtk_jpeg_enc_device_run(void *priv) +{ + struct mtk_jpeg_ctx *ctx = priv; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; + unsigned long flags; + int ret; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + ret = pm_runtime_get_sync(jpeg->dev); + if (ret < 0) + goto enc_end; + + schedule_delayed_work(&jpeg->job_timeout_work, + msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); + + spin_lock_irqsave(&jpeg->hw_lock, flags); + + /* + * Resetting the hardware every frame is to ensure that all the + * registers are cleared. This is a hardware requirement. + */ + mtk_jpeg_enc_reset(jpeg->reg_base); + + mtk_jpeg_set_enc_src(ctx, jpeg->reg_base, &src_buf->vb2_buf); + mtk_jpeg_set_enc_dst(ctx, jpeg->reg_base, &dst_buf->vb2_buf); + mtk_jpeg_set_enc_params(ctx, jpeg->reg_base); + mtk_jpeg_enc_start(jpeg->reg_base); + spin_unlock_irqrestore(&jpeg->hw_lock, flags); + return; + +enc_end: + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); +} + +static void mtk_jpeg_dec_device_run(void *priv) { struct mtk_jpeg_ctx *ctx = priv; struct mtk_jpeg_dev *jpeg = ctx->jpeg; @@ -805,19 +960,12 @@ static void mtk_jpeg_device_run(void *priv) struct mtk_jpeg_src_buf *jpeg_src_buf; struct mtk_jpeg_bs bs; struct mtk_jpeg_fb fb; - int i; + int ret; src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf); - if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) { - for (i = 0; i < dst_buf->vb2_buf.num_planes; i++) - vb2_set_plane_payload(&dst_buf->vb2_buf, i, 0); - buf_state = VB2_BUF_STATE_DONE; - goto dec_end; - } - if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) { mtk_jpeg_queue_src_chg_event(ctx); ctx->state = MTK_JPEG_SOURCE_CHANGE; @@ -825,16 +973,23 @@ static void mtk_jpeg_device_run(void *priv) return; } + ret = pm_runtime_get_sync(jpeg->dev); + if (ret < 0) + goto dec_end; + + schedule_delayed_work(&jpeg->job_timeout_work, + msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC)); + mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs); if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb)) goto dec_end; spin_lock_irqsave(&jpeg->hw_lock, flags); - mtk_jpeg_dec_reset(jpeg->dec_reg_base); - mtk_jpeg_dec_set_config(jpeg->dec_reg_base, + mtk_jpeg_dec_reset(jpeg->reg_base); + mtk_jpeg_dec_set_config(jpeg->reg_base, &jpeg_src_buf->dec_param, &bs, &fb); - mtk_jpeg_dec_start(jpeg->dec_reg_base); + mtk_jpeg_dec_start(jpeg->reg_base); spin_unlock_irqrestore(&jpeg->hw_lock, flags); return; @@ -846,29 +1001,34 @@ dec_end: v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); } -static int mtk_jpeg_job_ready(void *priv) +static int mtk_jpeg_dec_job_ready(void *priv) { struct mtk_jpeg_ctx *ctx = priv; return (ctx->state == MTK_JPEG_RUNNING) ? 1 : 0; } -static const struct v4l2_m2m_ops mtk_jpeg_m2m_ops = { - .device_run = mtk_jpeg_device_run, - .job_ready = mtk_jpeg_job_ready, +static const struct v4l2_m2m_ops mtk_jpeg_enc_m2m_ops = { + .device_run = mtk_jpeg_enc_device_run, +}; + +static const struct v4l2_m2m_ops mtk_jpeg_dec_m2m_ops = { + .device_run = mtk_jpeg_dec_device_run, + .job_ready = mtk_jpeg_dec_job_ready, }; static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { struct mtk_jpeg_ctx *ctx = priv; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; src_vq->io_modes = VB2_DMABUF | VB2_MMAP; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf); - src_vq->ops = &mtk_jpeg_qops; + src_vq->ops = jpeg->variant->qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->jpeg->lock; @@ -881,7 +1041,7 @@ static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->ops = &mtk_jpeg_qops; + dst_vq->ops = jpeg->variant->qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->jpeg->lock; @@ -898,17 +1058,68 @@ static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg) ret = mtk_smi_larb_get(jpeg->larb); if (ret) dev_err(jpeg->dev, "mtk_smi_larb_get larbvdec fail %d\n", ret); - clk_prepare_enable(jpeg->clk_jdec_smi); - clk_prepare_enable(jpeg->clk_jdec); + + ret = clk_bulk_prepare_enable(jpeg->variant->num_clks, + jpeg->variant->clks); + if (ret) + dev_err(jpeg->dev, "Failed to open jpeg clk: %d\n", ret); } static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg) { - clk_disable_unprepare(jpeg->clk_jdec); - clk_disable_unprepare(jpeg->clk_jdec_smi); + clk_bulk_disable_unprepare(jpeg->variant->num_clks, + jpeg->variant->clks); mtk_smi_larb_put(jpeg->larb); } +static irqreturn_t mtk_jpeg_enc_done(struct mtk_jpeg_dev *jpeg) +{ + struct mtk_jpeg_ctx *ctx; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; + u32 result_size; + + ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + if (!ctx) { + v4l2_err(&jpeg->v4l2_dev, "Context is NULL\n"); + return IRQ_HANDLED; + } + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + result_size = mtk_jpeg_enc_get_file_size(jpeg->reg_base); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, result_size); + + buf_state = VB2_BUF_STATE_DONE; + + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + pm_runtime_put(ctx->jpeg->dev); + return IRQ_HANDLED; +} + +static irqreturn_t mtk_jpeg_enc_irq(int irq, void *priv) +{ + struct mtk_jpeg_dev *jpeg = priv; + u32 irq_status; + irqreturn_t ret = IRQ_NONE; + + cancel_delayed_work(&jpeg->job_timeout_work); + + irq_status = readl(jpeg->reg_base + JPEG_ENC_INT_STS) & + JPEG_ENC_INT_STATUS_MASK_ALLIRQ; + if (irq_status) + writel(0, jpeg->reg_base + JPEG_ENC_INT_STS); + + if (!(irq_status & JPEG_ENC_INT_STATUS_DONE)) + return ret; + + ret = mtk_jpeg_enc_done(jpeg); + return ret; +} + static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) { struct mtk_jpeg_dev *jpeg = priv; @@ -920,7 +1131,9 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) u32 dec_ret; int i; - dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base); + cancel_delayed_work(&jpeg->job_timeout_work); + + dec_ret = mtk_jpeg_dec_get_int_status(jpeg->reg_base); dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret); ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); if (!ctx) { @@ -933,7 +1146,7 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf); if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW) - mtk_jpeg_dec_reset(jpeg->dec_reg_base); + mtk_jpeg_dec_reset(jpeg->reg_base); if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) { dev_err(jpeg->dev, "decode failed\n"); @@ -950,39 +1163,42 @@ dec_end: v4l2_m2m_buf_done(src_buf, buf_state); v4l2_m2m_buf_done(dst_buf, buf_state); v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + pm_runtime_put(ctx->jpeg->dev); return IRQ_HANDLED; } static void mtk_jpeg_set_default_params(struct mtk_jpeg_ctx *ctx) { struct mtk_jpeg_q_data *q = &ctx->out_q; - int i; + struct mtk_jpeg_dev *jpeg = ctx->jpeg; - ctx->colorspace = V4L2_COLORSPACE_JPEG, - ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - ctx->quantization = V4L2_QUANTIZATION_DEFAULT; - ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; + ctx->fh.ctrl_handler = &ctx->ctrl_hdl; + q->pix_mp.colorspace = V4L2_COLORSPACE_SRGB; + q->pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_601; + q->pix_mp.quantization = V4L2_QUANTIZATION_FULL_RANGE; + q->pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB; - q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG, - MTK_JPEG_FMT_TYPE_OUTPUT); - q->w = MTK_JPEG_MIN_WIDTH; - q->h = MTK_JPEG_MIN_HEIGHT; - q->bytesperline[0] = 0; - q->sizeimage[0] = MTK_JPEG_DEFAULT_SIZEIMAGE; + q->fmt = mtk_jpeg_find_format(jpeg->variant->formats, + jpeg->variant->num_formats, + jpeg->variant->out_q_default_fourcc, + MTK_JPEG_FMT_FLAG_OUTPUT); + q->pix_mp.width = MTK_JPEG_MIN_WIDTH; + q->pix_mp.height = MTK_JPEG_MIN_HEIGHT; + mtk_jpeg_try_fmt_mplane(&q->pix_mp, q->fmt); q = &ctx->cap_q; - q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_YUV420M, - MTK_JPEG_FMT_TYPE_CAPTURE); - q->w = MTK_JPEG_MIN_WIDTH; - q->h = MTK_JPEG_MIN_HEIGHT; - - for (i = 0; i < q->fmt->colplanes; i++) { - u32 stride = q->w * q->fmt->h_sample[i] / 4; - u32 h = q->h * q->fmt->v_sample[i] / 4; - - q->bytesperline[i] = stride; - q->sizeimage[i] = stride * h; - } + q->fmt = mtk_jpeg_find_format(jpeg->variant->formats, + jpeg->variant->num_formats, + jpeg->variant->cap_q_default_fourcc, + MTK_JPEG_FMT_FLAG_CAPTURE); + q->pix_mp.colorspace = V4L2_COLORSPACE_SRGB; + q->pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_601; + q->pix_mp.quantization = V4L2_QUANTIZATION_FULL_RANGE; + q->pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB; + q->pix_mp.width = MTK_JPEG_MIN_WIDTH; + q->pix_mp.height = MTK_JPEG_MIN_HEIGHT; + + mtk_jpeg_try_fmt_mplane(&q->pix_mp, q->fmt); } static int mtk_jpeg_open(struct file *file) @@ -1013,6 +1229,15 @@ static int mtk_jpeg_open(struct file *file) goto error; } + if (jpeg->variant->cap_q_default_fourcc == V4L2_PIX_FMT_JPEG) { + ret = mtk_jpeg_enc_ctrls_setup(ctx); + if (ret) { + v4l2_err(&jpeg->v4l2_dev, "Failed to setup jpeg enc controls\n"); + goto error; + } + } else { + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 0); + } mtk_jpeg_set_default_params(ctx); mutex_unlock(&jpeg->lock); return 0; @@ -1033,6 +1258,7 @@ static int mtk_jpeg_release(struct file *file) mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -1049,10 +1275,20 @@ static const struct v4l2_file_operations mtk_jpeg_fops = { .mmap = v4l2_m2m_fop_mmap, }; +static struct clk_bulk_data mt8173_jpeg_dec_clocks[] = { + { .id = "jpgdec-smi" }, + { .id = "jpgdec" }, +}; + +static struct clk_bulk_data mtk_jpeg_clocks[] = { + { .id = "jpgenc" }, +}; + static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg) { struct device_node *node; struct platform_device *pdev; + int ret; node = of_parse_phandle(jpeg->dev->of_node, "mediatek,larb", 0); if (!node) @@ -1066,19 +1302,40 @@ static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg) jpeg->larb = &pdev->dev; - jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec"); - if (IS_ERR(jpeg->clk_jdec)) - return PTR_ERR(jpeg->clk_jdec); + ret = devm_clk_bulk_get(jpeg->dev, jpeg->variant->num_clks, + jpeg->variant->clks); + if (ret) { + dev_err(&pdev->dev, "failed to get jpeg clock:%d\n", ret); + return ret; + } - jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi"); - return PTR_ERR_OR_ZERO(jpeg->clk_jdec_smi); + return 0; } +static void mtk_jpeg_job_timeout_work(struct work_struct *work) +{ + struct mtk_jpeg_dev *jpeg = container_of(work, struct mtk_jpeg_dev, + job_timeout_work.work); + struct mtk_jpeg_ctx *ctx; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + + ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + jpeg->variant->hw_reset(jpeg->reg_base); + + pm_runtime_put(jpeg->dev); + + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); +} static int mtk_jpeg_probe(struct platform_device *pdev) { struct mtk_jpeg_dev *jpeg; struct resource *res; - int dec_irq; + int jpeg_irq; int ret; jpeg = devm_kzalloc(&pdev->dev, sizeof(*jpeg), GFP_KERNEL); @@ -1088,28 +1345,27 @@ static int mtk_jpeg_probe(struct platform_device *pdev) mutex_init(&jpeg->lock); spin_lock_init(&jpeg->hw_lock); jpeg->dev = &pdev->dev; + jpeg->variant = of_device_get_match_data(jpeg->dev); + INIT_DELAYED_WORK(&jpeg->job_timeout_work, mtk_jpeg_job_timeout_work); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(jpeg->dec_reg_base)) { - ret = PTR_ERR(jpeg->dec_reg_base); + jpeg->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(jpeg->reg_base)) { + ret = PTR_ERR(jpeg->reg_base); return ret; } - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - dec_irq = platform_get_irq(pdev, 0); - if (!res || dec_irq < 0) { - dev_err(&pdev->dev, "Failed to get dec_irq %d.\n", dec_irq); - ret = -EINVAL; - return ret; + jpeg_irq = platform_get_irq(pdev, 0); + if (jpeg_irq < 0) { + dev_err(&pdev->dev, "Failed to get jpeg_irq %d.\n", jpeg_irq); + return jpeg_irq; } - ret = devm_request_irq(&pdev->dev, dec_irq, mtk_jpeg_dec_irq, 0, - pdev->name, jpeg); + ret = devm_request_irq(&pdev->dev, jpeg_irq, + jpeg->variant->irq_handler, 0, pdev->name, jpeg); if (ret) { - dev_err(&pdev->dev, "Failed to request dec_irq %d (%d)\n", - dec_irq, ret); - ret = -EINVAL; + dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n", + jpeg_irq, ret); goto err_req_irq; } @@ -1126,40 +1382,42 @@ static int mtk_jpeg_probe(struct platform_device *pdev) goto err_dev_register; } - jpeg->m2m_dev = v4l2_m2m_init(&mtk_jpeg_m2m_ops); + jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops); + if (IS_ERR(jpeg->m2m_dev)) { v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n"); ret = PTR_ERR(jpeg->m2m_dev); goto err_m2m_init; } - jpeg->dec_vdev = video_device_alloc(); - if (!jpeg->dec_vdev) { + jpeg->vdev = video_device_alloc(); + if (!jpeg->vdev) { ret = -ENOMEM; - goto err_dec_vdev_alloc; + goto err_vfd_jpeg_alloc; } - snprintf(jpeg->dec_vdev->name, sizeof(jpeg->dec_vdev->name), - "%s-dec", MTK_JPEG_NAME); - jpeg->dec_vdev->fops = &mtk_jpeg_fops; - jpeg->dec_vdev->ioctl_ops = &mtk_jpeg_ioctl_ops; - jpeg->dec_vdev->minor = -1; - jpeg->dec_vdev->release = video_device_release; - jpeg->dec_vdev->lock = &jpeg->lock; - jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev; - jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M; - jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_M2M_MPLANE; - - ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_VIDEO, 3); + snprintf(jpeg->vdev->name, sizeof(jpeg->vdev->name), + "%s", jpeg->variant->dev_name); + jpeg->vdev->fops = &mtk_jpeg_fops; + jpeg->vdev->ioctl_ops = jpeg->variant->ioctl_ops; + jpeg->vdev->minor = -1; + jpeg->vdev->release = video_device_release; + jpeg->vdev->lock = &jpeg->lock; + jpeg->vdev->v4l2_dev = &jpeg->v4l2_dev; + jpeg->vdev->vfl_dir = VFL_DIR_M2M; + jpeg->vdev->device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; + + ret = video_register_device(jpeg->vdev, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); - goto err_dec_vdev_register; + goto err_vfd_jpeg_register; } - video_set_drvdata(jpeg->dec_vdev, jpeg); + video_set_drvdata(jpeg->vdev, jpeg); v4l2_info(&jpeg->v4l2_dev, - "decoder device registered as /dev/video%d (%d,%d)\n", - jpeg->dec_vdev->num, VIDEO_MAJOR, jpeg->dec_vdev->minor); + "%s device registered as /dev/video%d (%d,%d)\n", + jpeg->variant->dev_name, jpeg->vdev->num, + VIDEO_MAJOR, jpeg->vdev->minor); platform_set_drvdata(pdev, jpeg); @@ -1167,10 +1425,10 @@ static int mtk_jpeg_probe(struct platform_device *pdev) return 0; -err_dec_vdev_register: - video_device_release(jpeg->dec_vdev); +err_vfd_jpeg_register: + video_device_release(jpeg->vdev); -err_dec_vdev_alloc: +err_vfd_jpeg_alloc: v4l2_m2m_release(jpeg->m2m_dev); err_m2m_init: @@ -1190,8 +1448,8 @@ static int mtk_jpeg_remove(struct platform_device *pdev) struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); - video_unregister_device(jpeg->dec_vdev); - video_device_release(jpeg->dec_vdev); + video_unregister_device(jpeg->vdev); + video_device_release(jpeg->vdev); v4l2_m2m_release(jpeg->m2m_dev); v4l2_device_unregister(&jpeg->v4l2_dev); @@ -1202,7 +1460,6 @@ static __maybe_unused int mtk_jpeg_pm_suspend(struct device *dev) { struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev); - mtk_jpeg_dec_reset(jpeg->dec_reg_base); mtk_jpeg_clk_off(jpeg); return 0; @@ -1213,31 +1470,28 @@ static __maybe_unused int mtk_jpeg_pm_resume(struct device *dev) struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev); mtk_jpeg_clk_on(jpeg); - mtk_jpeg_dec_reset(jpeg->dec_reg_base); return 0; } static __maybe_unused int mtk_jpeg_suspend(struct device *dev) { - int ret; - - if (pm_runtime_suspended(dev)) - return 0; + struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev); - ret = mtk_jpeg_pm_suspend(dev); - return ret; + v4l2_m2m_suspend(jpeg->m2m_dev); + return pm_runtime_force_suspend(dev); } static __maybe_unused int mtk_jpeg_resume(struct device *dev) { + struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev); int ret; - if (pm_runtime_suspended(dev)) - return 0; - - ret = mtk_jpeg_pm_resume(dev); + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + v4l2_m2m_resume(jpeg->m2m_dev); return ret; } @@ -1246,14 +1500,48 @@ static const struct dev_pm_ops mtk_jpeg_pm_ops = { SET_RUNTIME_PM_OPS(mtk_jpeg_pm_suspend, mtk_jpeg_pm_resume, NULL) }; +static const struct mtk_jpeg_variant mt8173_jpeg_drvdata = { + .clks = mt8173_jpeg_dec_clocks, + .num_clks = ARRAY_SIZE(mt8173_jpeg_dec_clocks), + .formats = mtk_jpeg_dec_formats, + .num_formats = MTK_JPEG_DEC_NUM_FORMATS, + .qops = &mtk_jpeg_dec_qops, + .irq_handler = mtk_jpeg_dec_irq, + .hw_reset = mtk_jpeg_dec_reset, + .m2m_ops = &mtk_jpeg_dec_m2m_ops, + .dev_name = "mtk-jpeg-dec", + .ioctl_ops = &mtk_jpeg_dec_ioctl_ops, + .out_q_default_fourcc = V4L2_PIX_FMT_JPEG, + .cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M, +}; + +static const struct mtk_jpeg_variant mtk_jpeg_drvdata = { + .clks = mtk_jpeg_clocks, + .num_clks = ARRAY_SIZE(mtk_jpeg_clocks), + .formats = mtk_jpeg_enc_formats, + .num_formats = MTK_JPEG_ENC_NUM_FORMATS, + .qops = &mtk_jpeg_enc_qops, + .irq_handler = mtk_jpeg_enc_irq, + .hw_reset = mtk_jpeg_enc_reset, + .m2m_ops = &mtk_jpeg_enc_m2m_ops, + .dev_name = "mtk-jpeg-enc", + .ioctl_ops = &mtk_jpeg_enc_ioctl_ops, + .out_q_default_fourcc = V4L2_PIX_FMT_YUYV, + .cap_q_default_fourcc = V4L2_PIX_FMT_JPEG, +}; + static const struct of_device_id mtk_jpeg_match[] = { { .compatible = "mediatek,mt8173-jpgdec", - .data = NULL, + .data = &mt8173_jpeg_drvdata, }, { .compatible = "mediatek,mt2701-jpgdec", - .data = NULL, + .data = &mt8173_jpeg_drvdata, + }, + { + .compatible = "mediatek,mtk-jpgenc", + .data = &mtk_jpeg_drvdata, }, {}, }; diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h index 999bd1427809..68e634f02e00 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h @@ -3,6 +3,7 @@ * Copyright (c) 2016 MediaTek Inc. * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> * Rick Chang <rick.chang@mediatek.com> + * Xia Jiang <xia.jiang@mediatek.com> */ #ifndef _MTK_JPEG_CORE_H @@ -15,19 +16,28 @@ #define MTK_JPEG_NAME "mtk-jpeg" -#define MTK_JPEG_FMT_FLAG_DEC_OUTPUT BIT(0) -#define MTK_JPEG_FMT_FLAG_DEC_CAPTURE BIT(1) +#define MTK_JPEG_COMP_MAX 3 -#define MTK_JPEG_FMT_TYPE_OUTPUT 1 -#define MTK_JPEG_FMT_TYPE_CAPTURE 2 +#define MTK_JPEG_FMT_FLAG_OUTPUT BIT(0) +#define MTK_JPEG_FMT_FLAG_CAPTURE BIT(1) -#define MTK_JPEG_MIN_WIDTH 32 -#define MTK_JPEG_MIN_HEIGHT 32 -#define MTK_JPEG_MAX_WIDTH 8192 -#define MTK_JPEG_MAX_HEIGHT 8192 +#define MTK_JPEG_MIN_WIDTH 32U +#define MTK_JPEG_MIN_HEIGHT 32U +#define MTK_JPEG_MAX_WIDTH 65535U +#define MTK_JPEG_MAX_HEIGHT 65535U #define MTK_JPEG_DEFAULT_SIZEIMAGE (1 * 1024 * 1024) +#define MTK_JPEG_HW_TIMEOUT_MSEC 1000 + +#define MTK_JPEG_MAX_EXIF_SIZE (64 * 1024) + +/** + * enum mtk_jpeg_ctx_state - states of the context state machine + * @MTK_JPEG_INIT: current state is initialized + * @MTK_JPEG_RUNNING: current state is running + * @MTK_JPEG_SOURCE_CHANGE: current state is source resolution change + */ enum mtk_jpeg_ctx_state { MTK_JPEG_INIT = 0, MTK_JPEG_RUNNING, @@ -35,6 +45,36 @@ enum mtk_jpeg_ctx_state { }; /** + * mtk_jpeg_variant - mtk jpeg driver variant + * @clks: clock names + * @num_clks: numbers of clock + * @format: jpeg driver's internal color format + * @num_format: number of format + * @qops: the callback of jpeg vb2_ops + * @irq_handler: jpeg irq handler callback + * @hw_reset: jpeg hardware reset callback + * @m2m_ops: the callback of jpeg v4l2_m2m_ops + * @dev_name: jpeg device name + * @ioctl_ops: the callback of jpeg v4l2_ioctl_ops + * @out_q_default_fourcc: output queue default fourcc + * @cap_q_default_fourcc: capture queue default fourcc + */ +struct mtk_jpeg_variant { + struct clk_bulk_data *clks; + int num_clks; + struct mtk_jpeg_fmt *formats; + int num_formats; + const struct vb2_ops *qops; + irqreturn_t (*irq_handler)(int irq, void *priv); + void (*hw_reset)(void __iomem *base); + const struct v4l2_m2m_ops *m2m_ops; + const char *dev_name; + const struct v4l2_ioctl_ops *ioctl_ops; + u32 out_q_default_fourcc; + u32 cap_q_default_fourcc; +}; + +/** * struct mt_jpeg - JPEG IP abstraction * @lock: the mutex protecting this structure * @hw_lock: spinlock protecting the hw device resource @@ -43,11 +83,11 @@ enum mtk_jpeg_ctx_state { * @v4l2_dev: v4l2 device for mem2mem mode * @m2m_dev: v4l2 mem2mem device data * @alloc_ctx: videobuf2 memory allocator's context - * @dec_vdev: video device node for decoder mem2mem mode - * @dec_reg_base: JPEG registers mapping - * @clk_jdec: JPEG hw working clock - * @clk_jdec_smi: JPEG SMI bus clock + * @vdev: video device node for jpeg mem2mem mode + * @reg_base: JPEG registers mapping * @larb: SMI device + * @job_timeout_work: IRQ timeout structure + * @variant: driver variant to be used */ struct mtk_jpeg_dev { struct mutex lock; @@ -57,16 +97,17 @@ struct mtk_jpeg_dev { struct v4l2_device v4l2_dev; struct v4l2_m2m_dev *m2m_dev; void *alloc_ctx; - struct video_device *dec_vdev; - void __iomem *dec_reg_base; - struct clk *clk_jdec; - struct clk *clk_jdec_smi; + struct video_device *vdev; + void __iomem *reg_base; struct device *larb; + struct delayed_work job_timeout_work; + const struct mtk_jpeg_variant *variant; }; /** * struct jpeg_fmt - driver's internal color format data * @fourcc: the fourcc code, 0 if not applicable + * @hw_format: hardware format value * @h_sample: horizontal sample count of plane in 4 * 4 pixel image * @v_sample: vertical sample count of plane in 4 * 4 pixel image * @colplanes: number of color planes (1 for packed formats) @@ -76,6 +117,7 @@ struct mtk_jpeg_dev { */ struct mtk_jpeg_fmt { u32 fourcc; + u32 hw_format; int h_sample[VIDEO_MAX_PLANES]; int v_sample[VIDEO_MAX_PLANES]; int colplanes; @@ -87,18 +129,13 @@ struct mtk_jpeg_fmt { /** * mtk_jpeg_q_data - parameters of one queue * @fmt: driver-specific format of this queue - * @w: image width - * @h: image height - * @bytesperline: distance in bytes between the leftmost pixels in two adjacent - * lines - * @sizeimage: image buffer size in bytes + * @pix_mp: multiplanar format + * @enc_crop_rect: jpeg encoder crop information */ struct mtk_jpeg_q_data { struct mtk_jpeg_fmt *fmt; - u32 w; - u32 h; - u32 bytesperline[VIDEO_MAX_PLANES]; - u32 sizeimage[VIDEO_MAX_PLANES]; + struct v4l2_pix_format_mplane pix_mp; + struct v4l2_rect enc_crop_rect; }; /** @@ -107,13 +144,11 @@ struct mtk_jpeg_q_data { * @out_q: source (output) queue information * @cap_q: destination (capture) queue queue information * @fh: V4L2 file handle - * @dec_param parameters for HW decoding * @state: state of the context - * @header_valid: set if header has been parsed and valid - * @colorspace: enum v4l2_colorspace; supplemental to pixelformat - * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding - * @quantization: enum v4l2_quantization, colorspace quantization - * @xfer_func: enum v4l2_xfer_func, colorspace transfer function + * @enable_exif: enable exif mode of jpeg encoder + * @enc_quality: jpeg encoder quality + * @restart_interval: jpeg encoder restart interval + * @ctrl_hdl: controls handler */ struct mtk_jpeg_ctx { struct mtk_jpeg_dev *jpeg; @@ -121,11 +156,10 @@ struct mtk_jpeg_ctx { struct mtk_jpeg_q_data cap_q; struct v4l2_fh fh; enum mtk_jpeg_ctx_state state; - - enum v4l2_colorspace colorspace; - enum v4l2_ycbcr_encoding ycbcr_enc; - enum v4l2_quantization quantization; - enum v4l2_xfer_func xfer_func; + bool enable_exif; + u8 enc_quality; + u8 restart_interval; + struct v4l2_ctrl_handler ctrl_hdl; }; #endif /* _MTK_JPEG_CORE_H */ diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.c index ddf0dfa78e20..afbbfd5d02bc 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <media/videobuf2-core.h> -#include "mtk_jpeg_hw.h" +#include "mtk_jpeg_dec_hw.h" #define MTK_JPEG_DUNUM_MASK(val) (((val) - 1) & 0x3) @@ -153,10 +153,10 @@ static int mtk_jpeg_calc_dst_size(struct mtk_jpeg_dec_param *param) param->sampling_w[i]; /* output format is 420/422 */ param->comp_w[i] = padding_w >> brz_w[i]; - param->comp_w[i] = mtk_jpeg_align(param->comp_w[i], - MTK_JPEG_DCTSIZE); - param->img_stride[i] = i ? mtk_jpeg_align(param->comp_w[i], 16) - : mtk_jpeg_align(param->comp_w[i], 32); + param->comp_w[i] = round_up(param->comp_w[i], + MTK_JPEG_DCTSIZE); + param->img_stride[i] = i ? round_up(param->comp_w[i], 16) + : round_up(param->comp_w[i], 32); ds_row_h[i] = (MTK_JPEG_DCTSIZE * param->sampling_h[i]); } param->dec_w = param->img_stride[0]; diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.h index 9c6584eaad99..fa0d45fd7c34 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.h @@ -3,15 +3,16 @@ * Copyright (c) 2016 MediaTek Inc. * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> * Rick Chang <rick.chang@mediatek.com> + * Xia Jiang <xia.jiang@mediatek.com> */ -#ifndef _MTK_JPEG_HW_H -#define _MTK_JPEG_HW_H +#ifndef _MTK_JPEG_DEC_HW_H +#define _MTK_JPEG_DEC_HW_H #include <media/videobuf2-core.h> #include "mtk_jpeg_core.h" -#include "mtk_jpeg_reg.h" +#include "mtk_jpeg_dec_reg.h" enum { MTK_JPEG_DEC_RESULT_EOF_DONE = 0, @@ -54,11 +55,6 @@ struct mtk_jpeg_dec_param { u8 uv_brz_w; }; -static inline u32 mtk_jpeg_align(u32 val, u32 align) -{ - return (val + align - 1) & ~(align - 1); -} - struct mtk_jpeg_bs { dma_addr_t str_addr; dma_addr_t end_addr; diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.c index f862d38f3af7..b95c45791c29 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.c @@ -8,7 +8,7 @@ #include <linux/kernel.h> #include <linux/videodev2.h> -#include "mtk_jpeg_parse.h" +#include "mtk_jpeg_dec_parse.h" #define TEM 0x01 #define SOF0 0xc0 diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.h index 0a48eeabaff2..2918f15811f8 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.h @@ -8,7 +8,7 @@ #ifndef _MTK_JPEG_PARSE_H #define _MTK_JPEG_PARSE_H -#include "mtk_jpeg_hw.h" +#include "mtk_jpeg_dec_hw.h" bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, u32 src_size); diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_reg.h index 94db04e9cdb6..21ec8f96797f 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_reg.h @@ -8,7 +8,6 @@ #ifndef _MTK_JPEG_REG_H #define _MTK_JPEG_REG_H -#define MTK_JPEG_COMP_MAX 3 #define MTK_JPEG_BLOCK_MAX 10 #define MTK_JPEG_DCTSIZE 8 @@ -20,29 +19,29 @@ #define BIT_INQST_MASK_ALLIRQ 0x37 #define JPGDEC_REG_RESET 0x0090 -#define JPGDEC_REG_BRZ_FACTOR 0x00F8 -#define JPGDEC_REG_DU_NUM 0x00FC +#define JPGDEC_REG_BRZ_FACTOR 0x00f8 +#define JPGDEC_REG_DU_NUM 0x00fc #define JPGDEC_REG_DEST_ADDR0_Y 0x0140 #define JPGDEC_REG_DEST_ADDR0_U 0x0144 #define JPGDEC_REG_DEST_ADDR0_V 0x0148 -#define JPGDEC_REG_DEST_ADDR1_Y 0x014C +#define JPGDEC_REG_DEST_ADDR1_Y 0x014c #define JPGDEC_REG_DEST_ADDR1_U 0x0150 #define JPGDEC_REG_DEST_ADDR1_V 0x0154 #define JPGDEC_REG_STRIDE_Y 0x0158 -#define JPGDEC_REG_STRIDE_UV 0x015C +#define JPGDEC_REG_STRIDE_UV 0x015c #define JPGDEC_REG_IMG_STRIDE_Y 0x0160 #define JPGDEC_REG_IMG_STRIDE_UV 0x0164 -#define JPGDEC_REG_WDMA_CTRL 0x016C +#define JPGDEC_REG_WDMA_CTRL 0x016c #define JPGDEC_REG_PAUSE_MCU_NUM 0x0170 -#define JPGDEC_REG_OPERATION_MODE 0x017C +#define JPGDEC_REG_OPERATION_MODE 0x017c #define JPGDEC_REG_FILE_ADDR 0x0200 -#define JPGDEC_REG_COMP_ID 0x020C +#define JPGDEC_REG_COMP_ID 0x020c #define JPGDEC_REG_TOTAL_MCU_NUM 0x0210 #define JPGDEC_REG_COMP0_DATA_UNIT_NUM 0x0224 -#define JPGDEC_REG_DU_CTRL 0x023C +#define JPGDEC_REG_DU_CTRL 0x023c #define JPGDEC_REG_TRIG 0x0240 #define JPGDEC_REG_FILE_BRP 0x0248 -#define JPGDEC_REG_FILE_TOTAL_SIZE 0x024C +#define JPGDEC_REG_FILE_TOTAL_SIZE 0x024c #define JPGDEC_REG_QT_ID 0x0270 #define JPGDEC_REG_INTERRUPT_STATUS 0x0274 #define JPGDEC_REG_STATUS 0x0278 diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.c new file mode 100644 index 000000000000..1cf037bf72dd --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019 MediaTek Inc. + * Author: Xia Jiang <xia.jiang@mediatek.com> + * + */ + +#include <linux/io.h> +#include <linux/kernel.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "mtk_jpeg_enc_hw.h" + +static const struct mtk_jpeg_enc_qlt mtk_jpeg_enc_quality[] = { + {.quality_param = 34, .hardware_value = JPEG_ENC_QUALITY_Q34}, + {.quality_param = 39, .hardware_value = JPEG_ENC_QUALITY_Q39}, + {.quality_param = 48, .hardware_value = JPEG_ENC_QUALITY_Q48}, + {.quality_param = 60, .hardware_value = JPEG_ENC_QUALITY_Q60}, + {.quality_param = 64, .hardware_value = JPEG_ENC_QUALITY_Q64}, + {.quality_param = 68, .hardware_value = JPEG_ENC_QUALITY_Q68}, + {.quality_param = 74, .hardware_value = JPEG_ENC_QUALITY_Q74}, + {.quality_param = 80, .hardware_value = JPEG_ENC_QUALITY_Q80}, + {.quality_param = 82, .hardware_value = JPEG_ENC_QUALITY_Q82}, + {.quality_param = 84, .hardware_value = JPEG_ENC_QUALITY_Q84}, + {.quality_param = 87, .hardware_value = JPEG_ENC_QUALITY_Q87}, + {.quality_param = 90, .hardware_value = JPEG_ENC_QUALITY_Q90}, + {.quality_param = 92, .hardware_value = JPEG_ENC_QUALITY_Q92}, + {.quality_param = 95, .hardware_value = JPEG_ENC_QUALITY_Q95}, + {.quality_param = 97, .hardware_value = JPEG_ENC_QUALITY_Q97}, +}; + +void mtk_jpeg_enc_reset(void __iomem *base) +{ + writel(0, base + JPEG_ENC_RSTB); + writel(JPEG_ENC_RESET_BIT, base + JPEG_ENC_RSTB); + writel(0, base + JPEG_ENC_CODEC_SEL); +} + +u32 mtk_jpeg_enc_get_file_size(void __iomem *base) +{ + return readl(base + JPEG_ENC_DMA_ADDR0) - + readl(base + JPEG_ENC_DST_ADDR0); +} + +void mtk_jpeg_enc_start(void __iomem *base) +{ + u32 value; + + value = readl(base + JPEG_ENC_CTRL); + value |= JPEG_ENC_CTRL_INT_EN_BIT | JPEG_ENC_CTRL_ENABLE_BIT; + writel(value, base + JPEG_ENC_CTRL); +} + +void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base, + struct vb2_buffer *src_buf) +{ + int i; + dma_addr_t dma_addr; + + for (i = 0; i < src_buf->num_planes; i++) { + dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, i) + + src_buf->planes[i].data_offset; + if (!i) + writel(dma_addr, base + JPEG_ENC_SRC_LUMA_ADDR); + else + writel(dma_addr, base + JPEG_ENC_SRC_CHROMA_ADDR); + } +} + +void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base, + struct vb2_buffer *dst_buf) +{ + dma_addr_t dma_addr; + size_t size; + u32 dma_addr_offset; + u32 dma_addr_offsetmask; + + dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + dma_addr_offset = ctx->enable_exif ? MTK_JPEG_MAX_EXIF_SIZE : 0; + dma_addr_offsetmask = dma_addr & JPEG_ENC_DST_ADDR_OFFSET_MASK; + size = vb2_plane_size(dst_buf, 0); + + writel(dma_addr_offset & ~0xf, base + JPEG_ENC_OFFSET_ADDR); + writel(dma_addr_offsetmask & 0xf, base + JPEG_ENC_BYTE_OFFSET_MASK); + writel(dma_addr & ~0xf, base + JPEG_ENC_DST_ADDR0); + writel((dma_addr + size) & ~0xf, base + JPEG_ENC_STALL_ADDR0); +} + +void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base) +{ + u32 value; + u32 width = ctx->out_q.enc_crop_rect.width; + u32 height = ctx->out_q.enc_crop_rect.height; + u32 enc_format = ctx->out_q.fmt->fourcc; + u32 bytesperline = ctx->out_q.pix_mp.plane_fmt[0].bytesperline; + u32 blk_num; + u32 img_stride; + u32 mem_stride; + u32 i, enc_quality; + + value = width << 16 | height; + writel(value, base + JPEG_ENC_IMG_SIZE); + + if (enc_format == V4L2_PIX_FMT_NV12M || + enc_format == V4L2_PIX_FMT_NV21M) + /* + * Total 8 x 8 block number of luma and chroma. + * The number of blocks is counted from 0. + */ + blk_num = DIV_ROUND_UP(width, 16) * + DIV_ROUND_UP(height, 16) * 6 - 1; + else + blk_num = DIV_ROUND_UP(width, 16) * + DIV_ROUND_UP(height, 8) * 4 - 1; + writel(blk_num, base + JPEG_ENC_BLK_NUM); + + if (enc_format == V4L2_PIX_FMT_NV12M || + enc_format == V4L2_PIX_FMT_NV21M) { + /* 4:2:0 */ + img_stride = round_up(width, 16); + mem_stride = bytesperline; + } else { + /* 4:2:2 */ + img_stride = round_up(width * 2, 32); + mem_stride = img_stride; + } + writel(img_stride, base + JPEG_ENC_IMG_STRIDE); + writel(mem_stride, base + JPEG_ENC_STRIDE); + + enc_quality = mtk_jpeg_enc_quality[0].hardware_value; + for (i = 0; i < ARRAY_SIZE(mtk_jpeg_enc_quality); i++) { + if (ctx->enc_quality <= mtk_jpeg_enc_quality[i].quality_param) { + enc_quality = mtk_jpeg_enc_quality[i].hardware_value; + break; + } + } + writel(enc_quality, base + JPEG_ENC_QUALITY); + + value = readl(base + JPEG_ENC_CTRL); + value &= ~JPEG_ENC_CTRL_YUV_FORMAT_MASK; + value |= (ctx->out_q.fmt->hw_format & 3) << 3; + if (ctx->enable_exif) + value |= JPEG_ENC_CTRL_FILE_FORMAT_BIT; + else + value &= ~JPEG_ENC_CTRL_FILE_FORMAT_BIT; + if (ctx->restart_interval) + value |= JPEG_ENC_CTRL_RESTART_EN_BIT; + else + value &= ~JPEG_ENC_CTRL_RESTART_EN_BIT; + writel(value, base + JPEG_ENC_CTRL); + + writel(ctx->restart_interval, base + JPEG_ENC_RST_MCU_NUM); +} diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.h new file mode 100644 index 000000000000..61c60e4e58ea --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019 MediaTek Inc. + * Author: Xia Jiang <xia.jiang@mediatek.com> + * + */ + +#ifndef _MTK_JPEG_ENC_HW_H +#define _MTK_JPEG_ENC_HW_H + +#include <media/videobuf2-core.h> + +#include "mtk_jpeg_core.h" + +#define JPEG_ENC_INT_STATUS_DONE BIT(0) +#define JPEG_ENC_INT_STATUS_MASK_ALLIRQ 0x13 + +#define JPEG_ENC_DST_ADDR_OFFSET_MASK GENMASK(3, 0) + +#define JPEG_ENC_CTRL_YUV_FORMAT_MASK 0x18 +#define JPEG_ENC_CTRL_RESTART_EN_BIT BIT(10) +#define JPEG_ENC_CTRL_FILE_FORMAT_BIT BIT(5) +#define JPEG_ENC_CTRL_INT_EN_BIT BIT(2) +#define JPEG_ENC_CTRL_ENABLE_BIT BIT(0) +#define JPEG_ENC_RESET_BIT BIT(0) + +#define JPEG_ENC_YUV_FORMAT_YUYV 0 +#define JPEG_ENC_YUV_FORMAT_YVYU 1 +#define JPEG_ENC_YUV_FORMAT_NV12 2 +#define JEPG_ENC_YUV_FORMAT_NV21 3 + +#define JPEG_ENC_QUALITY_Q60 0x0 +#define JPEG_ENC_QUALITY_Q80 0x1 +#define JPEG_ENC_QUALITY_Q90 0x2 +#define JPEG_ENC_QUALITY_Q95 0x3 +#define JPEG_ENC_QUALITY_Q39 0x4 +#define JPEG_ENC_QUALITY_Q68 0x5 +#define JPEG_ENC_QUALITY_Q84 0x6 +#define JPEG_ENC_QUALITY_Q92 0x7 +#define JPEG_ENC_QUALITY_Q48 0x8 +#define JPEG_ENC_QUALITY_Q74 0xa +#define JPEG_ENC_QUALITY_Q87 0xb +#define JPEG_ENC_QUALITY_Q34 0xc +#define JPEG_ENC_QUALITY_Q64 0xe +#define JPEG_ENC_QUALITY_Q82 0xf +#define JPEG_ENC_QUALITY_Q97 0x10 + +#define JPEG_ENC_RSTB 0x100 +#define JPEG_ENC_CTRL 0x104 +#define JPEG_ENC_QUALITY 0x108 +#define JPEG_ENC_BLK_NUM 0x10C +#define JPEG_ENC_BLK_CNT 0x110 +#define JPEG_ENC_INT_STS 0x11c +#define JPEG_ENC_DST_ADDR0 0x120 +#define JPEG_ENC_DMA_ADDR0 0x124 +#define JPEG_ENC_STALL_ADDR0 0x128 +#define JPEG_ENC_OFFSET_ADDR 0x138 +#define JPEG_ENC_RST_MCU_NUM 0x150 +#define JPEG_ENC_IMG_SIZE 0x154 +#define JPEG_ENC_DEBUG_INFO0 0x160 +#define JPEG_ENC_DEBUG_INFO1 0x164 +#define JPEG_ENC_TOTAL_CYCLE 0x168 +#define JPEG_ENC_BYTE_OFFSET_MASK 0x16c +#define JPEG_ENC_SRC_LUMA_ADDR 0x170 +#define JPEG_ENC_SRC_CHROMA_ADDR 0x174 +#define JPEG_ENC_STRIDE 0x178 +#define JPEG_ENC_IMG_STRIDE 0x17c +#define JPEG_ENC_DCM_CTRL 0x300 +#define JPEG_ENC_CODEC_SEL 0x314 +#define JPEG_ENC_ULTRA_THRES 0x318 + +/** + * struct mtk_jpeg_enc_qlt - JPEG encoder quality data + * @quality_param: quality value + * @hardware_value: hardware value of quality + */ +struct mtk_jpeg_enc_qlt { + u8 quality_param; + u8 hardware_value; +}; + +void mtk_jpeg_enc_reset(void __iomem *base); +u32 mtk_jpeg_enc_get_file_size(void __iomem *base); +void mtk_jpeg_enc_start(void __iomem *enc_reg_base); +void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base, + struct vb2_buffer *src_buf); +void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base, + struct vb2_buffer *dst_buf); +void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base); + +#endif /* _MTK_JPEG_ENC_HW_H */ diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index f96c8b3bf861..976aa1f4829b 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -94,7 +94,7 @@ static void mtk_mdp_reset_handler(void *priv) void mtk_mdp_register_component(struct mtk_mdp_dev *mdp, struct mtk_mdp_comp *comp) { - list_add(&mdp->comp_list, &comp->node); + list_add(&comp->node, &mdp->comp_list); } void mtk_mdp_unregister_component(struct mtk_mdp_dev *mdp, diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 37b94b555fa1..f679c6e1a3e9 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -13,7 +13,6 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ mtk_vcodec_dec.o \ mtk_vcodec_dec_pm.o \ - mtk-vcodec-enc-y := venc/venc_vp8_if.o \ venc/venc_h264_if.o \ mtk_vcodec_enc.o \ @@ -24,6 +23,5 @@ mtk-vcodec-enc-y := venc/venc_vp8_if.o \ mtk-vcodec-common-y := mtk_vcodec_intr.o \ - mtk_vcodec_util.o\ - -ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu + mtk_vcodec_util.o \ + mtk_vcodec_fw.o diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 0f3e710aed4e..c768a587a944 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -194,8 +194,7 @@ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx) vb->vb2_buf.index, dstbuf->queued_in_vb2); v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); - } else if ((dstbuf->queued_in_vb2 == false) && - (dstbuf->queued_in_v4l2 == true)) { + } else if (!dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2) { /* * If buffer in v4l2 driver but not in vb2 queue yet, * and we get this buffer from free_list, it means @@ -448,7 +447,7 @@ static void mtk_vdec_worker(struct work_struct *work) mutex_unlock(&ctx->lock); } v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - } else if (res_chg == false) { + } else if (!res_chg) { /* * we only return src buffer with VB2_BUF_STATE_DONE * when decode success without resolution change @@ -1156,7 +1155,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); mutex_lock(&ctx->lock); - if (buf->used == false) { + if (!buf->used) { v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); buf->queued_in_vb2 = true; buf->queued_in_v4l2 = true; @@ -1525,10 +1524,8 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->dev = &ctx->dev->plat_dev->dev; ret = vb2_queue_init(dst_vq); - if (ret) { - vb2_queue_release(src_vq); + if (ret) mtk_v4l2_err("Failed to initialize videobuf2 queue(capture)"); - } return ret; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 97a1b6664c20..d14bc208ea5e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -20,7 +20,7 @@ #include "mtk_vcodec_dec_pm.h" #include "mtk_vcodec_intr.h" #include "mtk_vcodec_util.h" -#include "mtk_vpu.h" +#include "mtk_vcodec_fw.h" #define VDEC_HW_ACTIVE 0x10 #define VDEC_IRQ_CFG 0x11 @@ -77,22 +77,6 @@ static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv) return IRQ_HANDLED; } -static void mtk_vcodec_dec_reset_handler(void *priv) -{ - struct mtk_vcodec_dev *dev = priv; - struct mtk_vcodec_ctx *ctx; - - mtk_v4l2_err("Watchdog timeout!!"); - - mutex_lock(&dev->dev_mutex); - list_for_each_entry(ctx, &dev->ctx_list, list) { - ctx->state = MTK_STATE_ABORT; - mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ERROR", - ctx->id); - } - mutex_unlock(&dev->dev_mutex); -} - static int fops_vcodec_open(struct file *file) { struct mtk_vcodec_dev *dev = video_drvdata(file); @@ -144,21 +128,20 @@ static int fops_vcodec_open(struct file *file) if (v4l2_fh_is_singular(&ctx->fh)) { mtk_vcodec_dec_pw_on(&dev->pm); /* - * vpu_load_firmware checks if it was loaded already and - * does nothing in that case + * Does nothing if firmware was already loaded. */ - ret = vpu_load_firmware(dev->vpu_plat_dev); + ret = mtk_vcodec_fw_load_firmware(dev->fw_handler); if (ret < 0) { /* * Return 0 if downloading firmware successfully, * otherwise it is failed */ - mtk_v4l2_err("vpu_load_firmware failed!"); + mtk_v4l2_err("failed to load firmware!"); goto err_load_fw; } dev->dec_capability = - vpu_get_vdec_hw_capa(dev->vpu_plat_dev); + mtk_vcodec_fw_get_vdec_capa(dev->fw_handler); mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability); } @@ -228,6 +211,8 @@ static int mtk_vcodec_probe(struct platform_device *pdev) struct mtk_vcodec_dev *dev; struct video_device *vfd_dec; struct resource *res; + phandle rproc_phandle; + enum mtk_vcodec_fw_type fw_type; int i, ret; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -237,19 +222,33 @@ static int mtk_vcodec_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dev->ctx_list); dev->plat_dev = pdev; - dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev); - if (dev->vpu_plat_dev == NULL) { - mtk_v4l2_err("[VPU] vpu device in not ready"); - return -EPROBE_DEFER; + if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu", + &rproc_phandle)) { + fw_type = VPU; + } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp", + &rproc_phandle)) { + fw_type = SCP; + } else { + mtk_v4l2_err("Could not get vdec IPI device"); + return -ENODEV; + } + if (!pdev->dev.dma_parms) { + pdev->dev.dma_parms = devm_kzalloc(&pdev->dev, + sizeof(*pdev->dev.dma_parms), + GFP_KERNEL); + if (!pdev->dev.dma_parms) + return -ENOMEM; } + dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); - vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_dec_reset_handler, - dev, VPU_RST_DEC); + dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_DEC); + if (IS_ERR(dev->fw_handler)) + return PTR_ERR(dev->fw_handler); ret = mtk_vcodec_init_dec_pm(dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to get mt vcodec clock source"); - return ret; + goto err_dec_pm; } for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) { @@ -269,6 +268,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } dev->dec_irq = platform_get_irq(pdev, 0); + irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN); ret = devm_request_irq(&pdev->dev, dev->dec_irq, mtk_vcodec_dec_irq_handler, 0, pdev->name, dev); if (ret) { @@ -278,7 +278,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev) goto err_res; } - disable_irq(dev->dec_irq); mutex_init(&dev->dec_mutex); mutex_init(&dev->dev_mutex); spin_lock_init(&dev->irqlock); @@ -352,6 +351,8 @@ err_dec_alloc: v4l2_device_unregister(&dev->v4l2_dev); err_res: mtk_vcodec_release_dec_pm(dev); +err_dec_pm: + mtk_vcodec_fw_release(dev->fw_handler); return ret; } @@ -376,6 +377,7 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev) v4l2_device_unregister(&dev->v4l2_dev); mtk_vcodec_release_dec_pm(dev); + mtk_vcodec_fw_release(dev->fw_handler); return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index 5a6ec8fb52da..36dfe3fc056a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -12,7 +12,6 @@ #include "mtk_vcodec_dec_pm.h" #include "mtk_vcodec_util.h" -#include "mtk_vpu.h" int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 9fd56dee7fd1..3dd010cba23e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -300,6 +300,40 @@ struct mtk_vcodec_ctx { }; +enum mtk_chip { + MTK_MT8173, + MTK_MT8183, +}; + +/** + * struct mtk_vcodec_enc_pdata - compatible data for each IC + * + * @chip: chip this encoder is compatible with + * + * @uses_ext: whether the encoder uses the extended firmware messaging format + * @has_lt_irq: whether the encoder uses the LT irq + * @min_birate: minimum supported encoding bitrate + * @max_bitrate: maximum supported encoding bitrate + * @capture_formats: array of supported capture formats + * @num_capture_formats: number of entries in capture_formats + * @output_formats: array of supported output formats + * @num_output_formats: number of entries in output_formats + */ +struct mtk_vcodec_enc_pdata { + enum mtk_chip chip; + + bool uses_ext; + bool has_lt_irq; + unsigned long min_bitrate; + unsigned long max_bitrate; + const struct mtk_video_fmt *capture_formats; + size_t num_capture_formats; + const struct mtk_video_fmt *output_formats; + size_t num_output_formats; +}; + +#define MTK_ENC_CTX_IS_EXT(ctx) ((ctx)->dev->venc_pdata->uses_ext) + /** * struct mtk_vcodec_dev - driver data * @v4l2_dev: V4L2 device to register video devices for. @@ -309,13 +343,13 @@ struct mtk_vcodec_ctx { * @m2m_dev_dec: m2m device for decoder * @m2m_dev_enc: m2m device for encoder. * @plat_dev: platform device - * @vpu_plat_dev: mtk vpu platform device * @ctx_list: list of struct mtk_vcodec_ctx * @irqlock: protect data access by irq handler and work thread * @curr_ctx: The context that is waiting for codec hardware * * @reg_base: Mapped address of MTK Vcodec registers. * + * @fw_handler: used to communicate with the firmware. * @id_counter: used to identify current opened instance * * @encode_workqueue: encode work queue @@ -344,11 +378,13 @@ struct mtk_vcodec_dev { struct v4l2_m2m_dev *m2m_dev_dec; struct v4l2_m2m_dev *m2m_dev_enc; struct platform_device *plat_dev; - struct platform_device *vpu_plat_dev; struct list_head ctx_list; spinlock_t irqlock; struct mtk_vcodec_ctx *curr_ctx; void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE]; + const struct mtk_vcodec_enc_pdata *venc_pdata; + + struct mtk_vcodec_fw *fw_handler; unsigned long id_counter; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index d469ff6464b2..21de1431cfcb 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -23,58 +23,15 @@ #define DFT_CFG_WIDTH MTK_VENC_MIN_W #define DFT_CFG_HEIGHT MTK_VENC_MIN_H #define MTK_MAX_CTRLS_HINT 20 -#define OUT_FMT_IDX 0 -#define CAP_FMT_IDX 4 +#define MTK_DEFAULT_FRAMERATE_NUM 1001 +#define MTK_DEFAULT_FRAMERATE_DENOM 30000 static void mtk_venc_worker(struct work_struct *work); -static const struct mtk_video_fmt mtk_video_formats[] = { - { - .fourcc = V4L2_PIX_FMT_NV12M, - .type = MTK_FMT_FRAME, - .num_planes = 2, - }, - { - .fourcc = V4L2_PIX_FMT_NV21M, - .type = MTK_FMT_FRAME, - .num_planes = 2, - }, - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .type = MTK_FMT_FRAME, - .num_planes = 3, - }, - { - .fourcc = V4L2_PIX_FMT_YVU420M, - .type = MTK_FMT_FRAME, - .num_planes = 3, - }, - { - .fourcc = V4L2_PIX_FMT_H264, - .type = MTK_FMT_ENC, - .num_planes = 1, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .type = MTK_FMT_ENC, - .num_planes = 1, - }, -}; - -#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) - -static const struct mtk_codec_framesizes mtk_venc_framesizes[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16, - MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16, - MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 }, - }, +static const struct v4l2_frmsize_stepwise mtk_venc_framesizes = { + MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16, + MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16, }; #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_venc_framesizes) @@ -156,59 +113,77 @@ static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = { .s_ctrl = vidioc_venc_s_ctrl, }; -static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, + const struct mtk_video_fmt *formats, + size_t num_formats) +{ + if (f->index >= num_formats) + return -EINVAL; + + f->pixelformat = formats[f->index].fourcc; + memset(f->reserved, 0, sizeof(f->reserved)); + + return 0; +} + +static const struct mtk_video_fmt * +mtk_venc_find_format(u32 fourcc, const struct mtk_vcodec_enc_pdata *pdata) { const struct mtk_video_fmt *fmt; - int i, j = 0; - - for (i = 0; i < NUM_FORMATS; ++i) { - if (output_queue && mtk_video_formats[i].type != MTK_FMT_FRAME) - continue; - if (!output_queue && mtk_video_formats[i].type != MTK_FMT_ENC) - continue; - - if (j == f->index) { - fmt = &mtk_video_formats[i]; - f->pixelformat = fmt->fourcc; - memset(f->reserved, 0, sizeof(f->reserved)); - return 0; - } - ++j; + unsigned int k; + + for (k = 0; k < pdata->num_capture_formats; k++) { + fmt = &pdata->capture_formats[k]; + if (fmt->fourcc == fourcc) + return fmt; + } + + for (k = 0; k < pdata->num_output_formats; k++) { + fmt = &pdata->output_formats[k]; + if (fmt->fourcc == fourcc) + return fmt; } - return -EINVAL; + return NULL; } static int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { - int i = 0; + const struct mtk_video_fmt *fmt; if (fsize->index != 0) return -EINVAL; - for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) { - if (fsize->pixel_format != mtk_venc_framesizes[i].fourcc) - continue; + fmt = mtk_venc_find_format(fsize->pixel_format, + fh_to_ctx(fh)->dev->venc_pdata); + if (!fmt) + return -EINVAL; - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = mtk_venc_framesizes[i].stepwise; - return 0; - } + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = mtk_venc_framesizes; - return -EINVAL; + return 0; } static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, false); + const struct mtk_vcodec_enc_pdata *pdata = + fh_to_ctx(priv)->dev->venc_pdata; + + return vidioc_enum_fmt(f, pdata->capture_formats, + pdata->num_capture_formats); } static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, true); + const struct mtk_vcodec_enc_pdata *pdata = + fh_to_ctx(priv)->dev->venc_pdata; + + return vidioc_enum_fmt(f, pdata->output_formats, + pdata->num_output_formats); } static int vidioc_venc_querycap(struct file *file, void *priv, @@ -225,14 +200,18 @@ static int vidioc_venc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct v4l2_fract *timeperframe = &a->parm.output.timeperframe; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; - ctx->enc_params.framerate_num = - a->parm.output.timeperframe.denominator; - ctx->enc_params.framerate_denom = - a->parm.output.timeperframe.numerator; + if (timeperframe->numerator == 0 || timeperframe->denominator == 0) { + timeperframe->numerator = MTK_DEFAULT_FRAMERATE_NUM; + timeperframe->denominator = MTK_DEFAULT_FRAMERATE_DENOM; + } + + ctx->enc_params.framerate_num = timeperframe->denominator; + ctx->enc_params.framerate_denom = timeperframe->numerator; ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE; a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; @@ -266,20 +245,6 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx, return &ctx->q_data[MTK_Q_DATA_DST]; } -static const struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) -{ - const struct mtk_video_fmt *fmt; - unsigned int k; - - for (k = 0; k < NUM_FORMATS; k++) { - fmt = &mtk_video_formats[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) - return fmt; - } - - return NULL; -} - /* V4L2 specification suggests the driver corrects the format struct if any of * the dimensions is unsupported */ @@ -332,12 +297,14 @@ static int vidioc_try_fmt(struct v4l2_format *f, pix_fmt_mp->num_planes = fmt->num_planes; pix_fmt_mp->plane_fmt[0].sizeimage = - pix_fmt_mp->width * pix_fmt_mp->height; + pix_fmt_mp->width * pix_fmt_mp->height + + ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16); pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; if (pix_fmt_mp->num_planes == 2) { pix_fmt_mp->plane_fmt[1].sizeimage = - (pix_fmt_mp->width * pix_fmt_mp->height) / 2; + (pix_fmt_mp->width * pix_fmt_mp->height) / 2 + + (ALIGN(pix_fmt_mp->width, 16) * 16); pix_fmt_mp->plane_fmt[2].sizeimage = 0; pix_fmt_mp->plane_fmt[1].bytesperline = pix_fmt_mp->width; @@ -345,7 +312,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, } else if (pix_fmt_mp->num_planes == 3) { pix_fmt_mp->plane_fmt[1].sizeimage = pix_fmt_mp->plane_fmt[2].sizeimage = - (pix_fmt_mp->width * pix_fmt_mp->height) / 4; + (pix_fmt_mp->width * pix_fmt_mp->height) / 4 + + ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16); pix_fmt_mp->plane_fmt[1].bytesperline = pix_fmt_mp->plane_fmt[2].bytesperline = pix_fmt_mp->width / 2; @@ -414,6 +382,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; struct mtk_q_data *q_data; int i, ret; @@ -436,10 +405,10 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, return -EINVAL; } - fmt = mtk_venc_find_format(f); + fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; - fmt = mtk_venc_find_format(f); + fmt = &ctx->dev->venc_pdata->capture_formats[0]; + f->fmt.pix.pixelformat = fmt->fourcc; } q_data->fmt = fmt; @@ -476,6 +445,7 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, struct v4l2_format *f) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; struct mtk_q_data *q_data; int ret, i; @@ -499,10 +469,10 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, return -EINVAL; } - fmt = mtk_venc_find_format(f); + fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; - fmt = mtk_venc_find_format(f); + fmt = &ctx->dev->venc_pdata->output_formats[0]; + f->fmt.pix.pixelformat = fmt->fourcc; } pix_fmt_mp->height = clamp(pix_fmt_mp->height, @@ -580,11 +550,12 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, { const struct mtk_video_fmt *fmt; struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; - fmt = mtk_venc_find_format(f); + fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; - fmt = mtk_venc_find_format(f); + fmt = &ctx->dev->venc_pdata->capture_formats[0]; + f->fmt.pix.pixelformat = fmt->fourcc; } f->fmt.pix_mp.colorspace = ctx->colorspace; f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc; @@ -598,11 +569,13 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; - fmt = mtk_venc_find_format(f); + fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); if (!fmt) { - f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; - fmt = mtk_venc_find_format(f); + fmt = &ctx->dev->venc_pdata->output_formats[0]; + f->fmt.pix.pixelformat = fmt->fourcc; } if (!f->fmt.pix_mp.colorspace) { f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; @@ -918,8 +891,17 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) ctx->state = MTK_STATE_FREE; } +static int vb2ops_venc_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + static const struct vb2_ops mtk_venc_vb2_ops = { .queue_setup = vb2ops_venc_queue_setup, + .buf_out_validate = vb2ops_venc_buf_out_validate, .buf_prepare = vb2ops_venc_buf_prepare, .buf_queue = vb2ops_venc_buf_queue, .wait_prepare = vb2_ops_wait_prepare, @@ -1187,7 +1169,7 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->coded_height = DFT_CFG_HEIGHT; q_data->field = V4L2_FIELD_NONE; - q_data->fmt = &mtk_video_formats[OUT_FMT_IDX]; + q_data->fmt = &ctx->dev->venc_pdata->output_formats[0]; v4l_bound_align_image(&q_data->coded_width, MTK_VENC_MIN_W, @@ -1216,12 +1198,14 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx) memset(q_data, 0, sizeof(struct mtk_q_data)); q_data->coded_width = DFT_CFG_WIDTH; q_data->coded_height = DFT_CFG_HEIGHT; - q_data->fmt = &mtk_video_formats[CAP_FMT_IDX]; + q_data->fmt = &ctx->dev->venc_pdata->capture_formats[0]; q_data->field = V4L2_FIELD_NONE; ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = DFT_CFG_WIDTH * DFT_CFG_HEIGHT; ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = 0; + ctx->enc_params.framerate_num = MTK_DEFAULT_FRAMERATE_NUM; + ctx->enc_params.framerate_denom = MTK_DEFAULT_FRAMERATE_DENOM; } int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) @@ -1231,8 +1215,11 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT); + v4l2_ctrl_new_std(handler, ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 1, 1, 1, 1); v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE, - 1, 4000000, 1, 4000000); + ctx->dev->venc_pdata->min_bitrate, + ctx->dev->venc_pdata->max_bitrate, 1, 4000000); v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 1, 0); v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index 4d31f1ed113f..dcfa2c2d4def 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -21,11 +21,55 @@ #include "mtk_vcodec_enc_pm.h" #include "mtk_vcodec_intr.h" #include "mtk_vcodec_util.h" -#include "mtk_vpu.h" +#include "mtk_vcodec_fw.h" module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR); module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR); +static const struct mtk_video_fmt mtk_video_formats_output_mt8173[] = { + { + .fourcc = V4L2_PIX_FMT_NV12M, + .type = MTK_FMT_FRAME, + .num_planes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .type = MTK_FMT_FRAME, + .num_planes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .type = MTK_FMT_FRAME, + .num_planes = 3, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420M, + .type = MTK_FMT_FRAME, + .num_planes = 3, + }, +}; + +static const struct mtk_video_fmt mtk_video_formats_capture_mt8173[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .type = MTK_FMT_ENC, + .num_planes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .type = MTK_FMT_ENC, + .num_planes = 1, + }, +}; + +static const struct mtk_video_fmt mtk_video_formats_capture_mt8183[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .type = MTK_FMT_ENC, + .num_planes = 1, + }, +}; + /* Wake up context wait_queue */ static void wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason) { @@ -101,22 +145,6 @@ static irqreturn_t mtk_vcodec_enc_lt_irq_handler(int irq, void *priv) return IRQ_HANDLED; } -static void mtk_vcodec_enc_reset_handler(void *priv) -{ - struct mtk_vcodec_dev *dev = priv; - struct mtk_vcodec_ctx *ctx; - - mtk_v4l2_debug(0, "Watchdog timeout!!"); - - mutex_lock(&dev->dev_mutex); - list_for_each_entry(ctx, &dev->ctx_list, list) { - ctx->state = MTK_STATE_ABORT; - mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT", - ctx->id); - } - mutex_unlock(&dev->dev_mutex); -} - static int fops_vcodec_open(struct file *file) { struct mtk_vcodec_dev *dev = video_drvdata(file); @@ -159,10 +187,10 @@ static int fops_vcodec_open(struct file *file) if (v4l2_fh_is_singular(&ctx->fh)) { /* - * vpu_load_firmware checks if it was loaded already and + * load fireware to checks if it was loaded already and * does nothing in that case */ - ret = vpu_load_firmware(dev->vpu_plat_dev); + ret = mtk_vcodec_fw_load_firmware(dev->fw_handler); if (ret < 0) { /* * Return 0 if downloading firmware successfully, @@ -173,7 +201,7 @@ static int fops_vcodec_open(struct file *file) } dev->enc_capability = - vpu_get_venc_hw_capa(dev->vpu_plat_dev); + mtk_vcodec_fw_get_venc_capa(dev->fw_handler); mtk_v4l2_debug(0, "encoder capability %x", dev->enc_capability); } @@ -235,7 +263,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev) struct mtk_vcodec_dev *dev; struct video_device *vfd_enc; struct resource *res; - int i, j, ret; + phandle rproc_phandle; + enum mtk_vcodec_fw_type fw_type; + int ret; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -244,30 +274,43 @@ static int mtk_vcodec_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dev->ctx_list); dev->plat_dev = pdev; - dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev); - if (dev->vpu_plat_dev == NULL) { - mtk_v4l2_err("[VPU] vpu device in not ready"); - return -EPROBE_DEFER; + if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu", + &rproc_phandle)) { + fw_type = VPU; + } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp", + &rproc_phandle)) { + fw_type = SCP; + } else { + mtk_v4l2_err("Could not get venc IPI device"); + return -ENODEV; } + if (!pdev->dev.dma_parms) { + pdev->dev.dma_parms = devm_kzalloc(&pdev->dev, + sizeof(*pdev->dev.dma_parms), + GFP_KERNEL); + if (!pdev->dev.dma_parms) + return -ENOMEM; + } + dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); - vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_enc_reset_handler, - dev, VPU_RST_ENC); + dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_ENC); + if (IS_ERR(dev->fw_handler)) + return PTR_ERR(dev->fw_handler); + dev->venc_pdata = of_device_get_match_data(&pdev->dev); ret = mtk_vcodec_init_enc_pm(dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to get mt vcodec clock source!"); - return ret; + goto err_enc_pm; } - for (i = VENC_SYS, j = 0; i < NUM_MAX_VCODEC_REG_BASE; i++, j++) { - res = platform_get_resource(pdev, IORESOURCE_MEM, j); - dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR((__force void *)dev->reg_base[i])) { - ret = PTR_ERR((__force void *)dev->reg_base[i]); - goto err_res; - } - mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[i]); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->reg_base[VENC_SYS] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR((__force void *)dev->reg_base[VENC_SYS])) { + ret = PTR_ERR((__force void *)dev->reg_base[VENC_SYS]); + goto err_res; } + mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[VENC_SYS]); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { @@ -277,6 +320,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } dev->enc_irq = platform_get_irq(pdev, 0); + irq_set_status_flags(dev->enc_irq, IRQ_NOAUTOEN); ret = devm_request_irq(&pdev->dev, dev->enc_irq, mtk_vcodec_enc_irq_handler, 0, pdev->name, dev); @@ -288,20 +332,30 @@ static int mtk_vcodec_probe(struct platform_device *pdev) goto err_res; } - dev->enc_lt_irq = platform_get_irq(pdev, 1); - ret = devm_request_irq(&pdev->dev, - dev->enc_lt_irq, mtk_vcodec_enc_lt_irq_handler, - 0, pdev->name, dev); - if (ret) { - dev_err(&pdev->dev, - "Failed to install dev->enc_lt_irq %d (%d)", - dev->enc_lt_irq, ret); - ret = -EINVAL; - goto err_res; + if (dev->venc_pdata->has_lt_irq) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + dev->reg_base[VENC_LT_SYS] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR((__force void *)dev->reg_base[VENC_LT_SYS])) { + ret = PTR_ERR((__force void *)dev->reg_base[VENC_LT_SYS]); + goto err_res; + } + mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[VENC_LT_SYS]); + + dev->enc_lt_irq = platform_get_irq(pdev, 1); + irq_set_status_flags(dev->enc_lt_irq, IRQ_NOAUTOEN); + ret = devm_request_irq(&pdev->dev, + dev->enc_lt_irq, + mtk_vcodec_enc_lt_irq_handler, + 0, pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, + "Failed to install dev->enc_lt_irq %d (%d)", + dev->enc_lt_irq, ret); + ret = -EINVAL; + goto err_res; + } } - disable_irq(dev->enc_irq); - disable_irq(dev->enc_lt_irq); /* VENC_LT */ mutex_init(&dev->enc_mutex); mutex_init(&dev->dev_mutex); spin_lock_init(&dev->irqlock); @@ -377,11 +431,38 @@ err_enc_alloc: v4l2_device_unregister(&dev->v4l2_dev); err_res: mtk_vcodec_release_enc_pm(dev); +err_enc_pm: + mtk_vcodec_fw_release(dev->fw_handler); return ret; } +static const struct mtk_vcodec_enc_pdata mt8173_pdata = { + .chip = MTK_MT8173, + .has_lt_irq = true, + .capture_formats = mtk_video_formats_capture_mt8173, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8173), + .output_formats = mtk_video_formats_output_mt8173, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), + .min_bitrate = 1, + .max_bitrate = 4000000, +}; + +static const struct mtk_vcodec_enc_pdata mt8183_pdata = { + .chip = MTK_MT8183, + .has_lt_irq = false, + .uses_ext = true, + .capture_formats = mtk_video_formats_capture_mt8183, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8183), + /* MT8183 supports the same output formats as MT8173 */ + .output_formats = mtk_video_formats_output_mt8173, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), + .min_bitrate = 64, + .max_bitrate = 40000000, +}; + static const struct of_device_id mtk_vcodec_enc_match[] = { - {.compatible = "mediatek,mt8173-vcodec-enc",}, + {.compatible = "mediatek,mt8173-vcodec-enc", .data = &mt8173_pdata}, + {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata}, {}, }; MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match); @@ -401,6 +482,7 @@ static int mtk_vcodec_enc_remove(struct platform_device *pdev) v4l2_device_unregister(&dev->v4l2_dev); mtk_vcodec_release_enc_pm(dev); + mtk_vcodec_fw_release(dev->fw_handler); return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c index 3e2bfded79a6..ee22902aaa71 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c @@ -12,8 +12,6 @@ #include "mtk_vcodec_enc_pm.h" #include "mtk_vcodec_util.h" -#include "mtk_vpu.h" - int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c new file mode 100644 index 000000000000..6c2a2568d844 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "mtk_vcodec_fw.h" +#include "mtk_vcodec_util.h" +#include "mtk_vcodec_drv.h" + +struct mtk_vcodec_fw_ops { + int (*load_firmware)(struct mtk_vcodec_fw *fw); + unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw); + unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw); + void * (*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr); + int (*ipi_register)(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, const char *name, void *priv); + int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf, + unsigned int len, unsigned int wait); +}; + +struct mtk_vcodec_fw { + enum mtk_vcodec_fw_type type; + const struct mtk_vcodec_fw_ops *ops; + struct platform_device *pdev; + struct mtk_scp *scp; +}; + +static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw) +{ + return vpu_load_firmware(fw->pdev); +} + +static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw) +{ + return vpu_get_vdec_hw_capa(fw->pdev); +} + +static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw) +{ + return vpu_get_venc_hw_capa(fw->pdev); +} + +static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw, + u32 dtcm_dmem_addr) +{ + return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr); +} + +static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, + const char *name, void *priv) +{ + /* + * The handler we receive takes a void * as its first argument. We + * cannot change this because it needs to be passed down to the rproc + * subsystem when SCP is used. VPU takes a const argument, which is + * more constrained, so the conversion below is safe. + */ + ipi_handler_t handler_const = (ipi_handler_t)handler; + + return vpu_ipi_register(fw->pdev, id, handler_const, name, priv); +} + +static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, + unsigned int len, unsigned int wait) +{ + return vpu_ipi_send(fw->pdev, id, buf, len); +} + +static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = { + .load_firmware = mtk_vcodec_vpu_load_firmware, + .get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa, + .get_venc_capa = mtk_vcodec_vpu_get_venc_capa, + .map_dm_addr = mtk_vcodec_vpu_map_dm_addr, + .ipi_register = mtk_vcodec_vpu_set_ipi_register, + .ipi_send = mtk_vcodec_vpu_ipi_send, +}; + +static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw) +{ + return rproc_boot(scp_get_rproc(fw->scp)); +} + +static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw) +{ + return scp_get_vdec_hw_capa(fw->scp); +} + +static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw) +{ + return scp_get_venc_hw_capa(fw->scp); +} + +static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw, + u32 dtcm_dmem_addr) +{ + return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr); +} + +static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, + const char *name, void *priv) +{ + return scp_ipi_register(fw->scp, id, handler, priv); +} + +static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, + unsigned int len, unsigned int wait) +{ + return scp_ipi_send(fw->scp, id, buf, len, wait); +} + +static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = { + .load_firmware = mtk_vcodec_scp_load_firmware, + .get_vdec_capa = mtk_vcodec_scp_get_vdec_capa, + .get_venc_capa = mtk_vcodec_scp_get_venc_capa, + .map_dm_addr = mtk_vcodec_vpu_scp_dm_addr, + .ipi_register = mtk_vcodec_scp_set_ipi_register, + .ipi_send = mtk_vcodec_scp_ipi_send, +}; + +static void mtk_vcodec_reset_handler(void *priv) +{ + struct mtk_vcodec_dev *dev = priv; + struct mtk_vcodec_ctx *ctx; + + mtk_v4l2_err("Watchdog timeout!!"); + + mutex_lock(&dev->dev_mutex); + list_for_each_entry(ctx, &dev->ctx_list, list) { + ctx->state = MTK_STATE_ABORT; + mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT", + ctx->id); + } + mutex_unlock(&dev->dev_mutex); +} + +struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev, + enum mtk_vcodec_fw_type type, + enum rst_id rst_id) +{ + const struct mtk_vcodec_fw_ops *ops; + struct mtk_vcodec_fw *fw; + struct platform_device *fw_pdev = NULL; + struct mtk_scp *scp = NULL; + + switch (type) { + case VPU: + ops = &mtk_vcodec_vpu_msg; + fw_pdev = vpu_get_plat_device(dev->plat_dev); + if (!fw_pdev) { + mtk_v4l2_err("firmware device is not ready"); + return ERR_PTR(-EINVAL); + } + vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_reset_handler, + dev, rst_id); + break; + case SCP: + ops = &mtk_vcodec_rproc_msg; + scp = scp_get(dev->plat_dev); + if (!scp) { + mtk_v4l2_err("could not get vdec scp handle"); + return ERR_PTR(-EPROBE_DEFER); + } + break; + default: + mtk_v4l2_err("invalid vcodec fw type"); + return ERR_PTR(-EINVAL); + } + + fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL); + if (!fw) + return ERR_PTR(-EINVAL); + + fw->type = type; + fw->ops = ops; + fw->pdev = fw_pdev; + fw->scp = scp; + + return fw; +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_select); + +void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw) +{ + switch (fw->type) { + case VPU: + put_device(&fw->pdev->dev); + break; + case SCP: + scp_put(fw->scp); + break; + } +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_release); + +int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw) +{ + return fw->ops->load_firmware(fw); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_load_firmware); + +unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw) +{ + return fw->ops->get_vdec_capa(fw); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_vdec_capa); + +unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw) +{ + return fw->ops->get_venc_capa(fw); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_venc_capa); + +void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr) +{ + return fw->ops->map_dm_addr(fw, mem_addr); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_map_dm_addr); + +int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, + const char *name, void *priv) +{ + return fw->ops->ipi_register(fw, id, handler, name, priv); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_register); + +int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, + unsigned int len, unsigned int wait) +{ + return fw->ops->ipi_send(fw, id, buf, len, wait); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h new file mode 100644 index 000000000000..fadbbe6ba6cd --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _MTK_VCODEC_FW_H_ +#define _MTK_VCODEC_FW_H_ + +#include <linux/remoteproc.h> +#include <linux/remoteproc/mtk_scp.h> + +#include "../mtk-vpu/mtk_vpu.h" + +struct mtk_vcodec_dev; + +enum mtk_vcodec_fw_type { + VPU, + SCP, +}; + +struct mtk_vcodec_fw; + +typedef void (*mtk_vcodec_ipi_handler) (void *data, + unsigned int len, void *priv); + +struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev, + enum mtk_vcodec_fw_type type, + enum rst_id rst_id); +void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw); + +int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw); +unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw); +unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw); +void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr); +int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id, + mtk_vcodec_ipi_handler handler, + const char *name, void *priv); +int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, + void *buf, unsigned int len, unsigned int wait); + +#endif /* _MTK_VCODEC_FW_H_ */ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c index d48f542db1a9..ac5973b6735f 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c @@ -9,7 +9,6 @@ #include "mtk_vcodec_drv.h" #include "mtk_vcodec_util.h" -#include "mtk_vpu.h" /* For encoder, this will enable logs in venc/*/ bool mtk_vcodec_dbg; diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index 50048c170b99..40d6e6c5ac7a 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -281,7 +281,6 @@ static int vdec_h264_init(struct mtk_vcodec_ctx *ctx) inst->ctx = ctx; inst->vpu.id = IPI_VDEC_H264; - inst->vpu.dev = ctx->dev->vpu_plat_dev; inst->vpu.ctx = ctx; err = vpu_dec_init(&inst->vpu); diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index 6011fdd60a22..e5393f841080 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -400,7 +400,6 @@ static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx) inst->ctx = ctx; inst->vpu.id = IPI_VDEC_VP8; - inst->vpu.dev = ctx->dev->vpu_plat_dev; inst->vpu.ctx = ctx; err = vpu_dec_init(&inst->vpu); diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index 257a5b5ad212..5ea153a68522 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -795,7 +795,6 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx) inst->ctx = ctx; inst->vpu.id = IPI_VDEC_VP9; - inst->vpu.dev = ctx->dev->vpu_plat_dev; inst->vpu.ctx = ctx; if (vpu_dec_init(&inst->vpu)) { @@ -960,7 +959,7 @@ static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs, goto DECODE_ERROR; } - if (vp9_decode_end_proc(inst) != true) { + if (!vp9_decode_end_proc(inst)) { mtk_vcodec_err(inst, "vp9_decode_end_proc"); ret = -EINVAL; goto DECODE_ERROR; diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h index ceb4db4cb3be..e913f963b7db 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h @@ -7,8 +7,6 @@ #ifndef _VDEC_DRV_BASE_ #define _VDEC_DRV_BASE_ -#include "mtk_vcodec_drv.h" - #include "vdec_drv_if.h" struct vdec_common_if { diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 2e43dd4486e0..b18743b906ea 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -13,7 +13,6 @@ #include "mtk_vcodec_dec.h" #include "vdec_drv_base.h" #include "mtk_vcodec_dec_pm.h" -#include "mtk_vpu.h" int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 948a12fd9d46..58b0e6fa8fd2 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -8,6 +8,7 @@ #include "mtk_vcodec_util.h" #include "vdec_ipi_msg.h" #include "vdec_vpu_if.h" +#include "mtk_vcodec_fw.h" static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) { @@ -18,7 +19,8 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) /* mapping VPU address to kernel virtual address */ /* the content in vsi is initialized to 0 in VPU */ - vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr); + vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler, + msg->vpu_inst_addr); vpu->inst_addr = msg->vpu_inst_addr; mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr); @@ -34,7 +36,7 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) * This function runs in interrupt context and it means there's an IPI MSG * from VPU. */ -static void vpu_dec_ipi_handler(const void *data, unsigned int len, void *priv) +static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) { const struct vdec_vpu_ipi_ack *msg = data; struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) @@ -74,7 +76,8 @@ static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len) vpu->failure = 0; vpu->signaled = 0; - err = vpu_ipi_send(vpu->dev, vpu->id, msg, len); + err = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg, + len, 2000); if (err) { mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d", vpu->id, *(uint32_t *)msg, err); @@ -110,7 +113,8 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu) init_waitqueue_head(&vpu->wq); vpu->handler = vpu_dec_ipi_handler; - err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, "vdec", NULL); + err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id, + vpu->handler, "vdec", NULL); if (err != 0) { mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err); return err; diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h index f779b0676fbd..85224eb7e34b 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -7,11 +7,13 @@ #ifndef _VDEC_VPU_IF_H_ #define _VDEC_VPU_IF_H_ -#include "mtk_vpu.h" +#include "mtk_vcodec_fw.h" + +struct mtk_vcodec_ctx; /** * struct vdec_vpu_inst - VPU instance for video codec - * @ipi_id : ipi id for each decoder + * @id : ipi msg id for each decoder * @vsi : driver structure allocated by VPU side and shared to AP side * for control and info share * @failure : VPU execution result status, 0: success, others: fail @@ -23,15 +25,14 @@ * @handler : ipi handler for each decoder */ struct vdec_vpu_inst { - enum ipi_id id; + int id; void *vsi; int32_t failure; uint32_t inst_addr; unsigned int signaled; struct mtk_vcodec_ctx *ctx; - struct platform_device *dev; wait_queue_head_t wq; - ipi_handler_t handler; + mtk_vcodec_ipi_handler handler; }; /** diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index b9624f8df0e9..d0123dfc5f93 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c @@ -18,7 +18,6 @@ #include "../venc_drv_base.h" #include "../venc_ipi_msg.h" #include "../venc_vpu_if.h" -#include "mtk_vpu.h" static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc}; @@ -26,6 +25,16 @@ static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc}; #define VENC_PIC_BITSTREAM_BYTE_CNT 0x0098 /* + * enum venc_h264_frame_type - h264 encoder output bitstream frame type + */ +enum venc_h264_frame_type { + VENC_H264_IDR_FRM, + VENC_H264_I_FRM, + VENC_H264_P_FRM, + VENC_H264_B_FRM, +}; + +/* * enum venc_h264_vpu_work_buf - h264 encoder buffer index */ enum venc_h264_vpu_work_buf { @@ -139,6 +148,7 @@ struct venc_h264_inst { struct mtk_vcodec_mem pps_buf; bool work_buf_allocated; unsigned int frm_cnt; + unsigned int skip_frm_cnt; unsigned int prepend_hdr; struct venc_vpu_inst vpu_inst; struct venc_h264_vsi *vsi; @@ -257,8 +267,11 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst) */ inst->work_bufs[i].size = wb[i].size; if (i == VENC_H264_VPU_WORK_BUF_SKIP_FRAME) { - inst->work_bufs[i].va = vpu_mapping_dm_addr( - inst->vpu_inst.dev, wb[i].vpua); + struct mtk_vcodec_fw *handler; + + handler = inst->vpu_inst.ctx->dev->fw_handler; + inst->work_bufs[i].va = + mtk_vcodec_fw_map_dm_addr(handler, wb[i].vpua); inst->work_bufs[i].dma_addr = 0; } else { ret = mtk_vcodec_mem_alloc(inst->ctx, @@ -275,10 +288,12 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst) * setting in VPU side. */ if (i == VENC_H264_VPU_WORK_BUF_RC_CODE) { + struct mtk_vcodec_fw *handler; void *tmp_va; - tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev, - wb[i].vpua); + handler = inst->vpu_inst.ctx->dev->fw_handler; + tmp_va = mtk_vcodec_fw_map_dm_addr(handler, + wb[i].vpua); memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size); } @@ -323,6 +338,22 @@ static unsigned int h264_enc_wait_venc_done(struct venc_h264_inst *inst) return irq_status; } +static int h264_frame_type(struct venc_h264_inst *inst) +{ + if ((inst->vsi->config.gop_size != 0 && + (inst->frm_cnt % inst->vsi->config.gop_size) == 0) || + (inst->frm_cnt == 0 && inst->vsi->config.gop_size == 0)) { + /* IDR frame */ + return VENC_H264_IDR_FRM; + } else if ((inst->vsi->config.intra_period != 0 && + (inst->frm_cnt % inst->vsi->config.intra_period) == 0) || + (inst->frm_cnt == 0 && inst->vsi->config.intra_period == 0)) { + /* I frame */ + return VENC_H264_I_FRM; + } else { + return VENC_H264_P_FRM; /* Note: B frames are not supported */ + } +} static int h264_encode_sps(struct venc_h264_inst *inst, struct mtk_vcodec_mem *bs_buf, unsigned int *bs_size) @@ -333,7 +364,7 @@ static int h264_encode_sps(struct venc_h264_inst *inst, mtk_vcodec_debug_enter(inst); ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL, - bs_buf, bs_size); + bs_buf, bs_size, NULL); if (ret) return ret; @@ -360,7 +391,7 @@ static int h264_encode_pps(struct venc_h264_inst *inst, mtk_vcodec_debug_enter(inst); ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL, - bs_buf, bs_size); + bs_buf, bs_size, NULL); if (ret) return ret; @@ -406,11 +437,18 @@ static int h264_encode_frame(struct venc_h264_inst *inst, { int ret = 0; unsigned int irq_status; + struct venc_frame_info frame_info; mtk_vcodec_debug_enter(inst); - + mtk_vcodec_debug(inst, "frm_cnt = %d\n ", inst->frm_cnt); + frame_info.frm_count = inst->frm_cnt; + frame_info.skip_frm_count = inst->skip_frm_cnt; + frame_info.frm_type = h264_frame_type(inst); + mtk_vcodec_debug(inst, "frm_count = %d,skip_frm_count =%d,frm_type=%d.\n", + frame_info.frm_count, frame_info.skip_frm_count, + frame_info.frm_type); ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf, - bs_buf, bs_size); + bs_buf, bs_size, &frame_info); if (ret) return ret; @@ -424,6 +462,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst, inst->work_bufs[VENC_H264_VPU_WORK_BUF_SKIP_FRAME].va, *bs_size); ++inst->frm_cnt; + ++inst->skip_frm_cnt; return ret; } @@ -460,6 +499,7 @@ static void h264_encode_filler(struct venc_h264_inst *inst, void *buf, static int h264_enc_init(struct mtk_vcodec_ctx *ctx) { + const bool is_ext = MTK_ENC_CTX_IS_EXT(ctx); int ret = 0; struct venc_h264_inst *inst; @@ -469,8 +509,7 @@ static int h264_enc_init(struct mtk_vcodec_ctx *ctx) inst->ctx = ctx; inst->vpu_inst.ctx = ctx; - inst->vpu_inst.dev = ctx->dev->vpu_plat_dev; - inst->vpu_inst.id = IPI_VENC_H264; + inst->vpu_inst.id = is_ext ? SCP_IPI_VENC_H264 : IPI_VENC_H264; inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS); mtk_vcodec_debug_enter(inst); @@ -626,7 +665,12 @@ static int h264_enc_set_param(void *handle, inst->prepend_hdr = 1; mtk_vcodec_debug(inst, "set prepend header mode"); break; - + case VENC_SET_PARAM_FORCE_INTRA: + case VENC_SET_PARAM_GOP_SIZE: + case VENC_SET_PARAM_INTRA_PERIOD: + inst->frm_cnt = 0; + inst->skip_frm_cnt = 0; + fallthrough; default: ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm); break; diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index 8d36f0362efe..11abb191ada5 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c @@ -17,7 +17,6 @@ #include "../venc_drv_base.h" #include "../venc_ipi_msg.h" #include "../venc_vpu_if.h" -#include "mtk_vpu.h" #define VENC_BITSTREAM_FRAME_SIZE 0x0098 #define VENC_BITSTREAM_HEADER_LEN 0x00e8 @@ -190,10 +189,12 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst) if (i == VENC_VP8_VPU_WORK_BUF_RC_CODE || i == VENC_VP8_VPU_WORK_BUF_RC_CODE2 || i == VENC_VP8_VPU_WORK_BUF_RC_CODE3) { + struct mtk_vcodec_fw *handler; void *tmp_va; - tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev, - wb[i].vpua); + handler = inst->vpu_inst.ctx->dev->fw_handler; + tmp_va = mtk_vcodec_fw_map_dm_addr(handler, + wb[i].vpua); memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size); } wb[i].iova = inst->work_bufs[i].dma_addr; @@ -301,7 +302,8 @@ static int vp8_enc_encode_frame(struct venc_vp8_inst *inst, mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt); - ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size); + ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size, + NULL); if (ret) return ret; @@ -334,7 +336,6 @@ static int vp8_enc_init(struct mtk_vcodec_ctx *ctx) inst->ctx = ctx; inst->vpu_inst.ctx = ctx; - inst->vpu_inst.dev = ctx->dev->vpu_plat_dev; inst->vpu_inst.id = IPI_VENC_VP8; inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_LT_SYS); diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c index c6bb82ac2dcd..ce0bce811615 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c @@ -15,7 +15,6 @@ #include "mtk_vcodec_enc.h" #include "mtk_vcodec_enc_pm.h" -#include "mtk_vpu.h" int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mtk-vcodec/venc_drv_if.h index 52fc9cc812fc..0b04a1020873 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.h @@ -92,6 +92,19 @@ struct venc_enc_param { unsigned int gop_size; }; +/** + * struct venc_frame_info - per-frame information to pass to the firmware. + * + * @frm_count: sequential number for this frame + * @skip_frm_count: number of frames skipped so far while decoding + * @frm_type: type of the frame, from enum venc_h264_frame_type + */ +struct venc_frame_info { + unsigned int frm_count; /* per frame update */ + unsigned int skip_frm_count; /* per frame update */ + unsigned int frm_type; /* per frame update */ +}; + /* * struct venc_frm_buf - frame buffer information used in venc_if_encode() * @fb_addr: plane frame buffer addresses diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h index 28ee04ca6241..2feb0365179f 100644 --- a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h @@ -62,6 +62,11 @@ struct venc_ap_ipi_msg_set_param { uint32_t data[8]; }; +struct venc_ap_ipi_msg_set_param_ext { + struct venc_ap_ipi_msg_set_param base; + uint32_t data_ext[24]; +}; + /** * struct venc_ap_ipi_msg_enc - AP to VPU enc cmd structure * @msg_id: message id (AP_IPIMSG_XXX_ENC_ENCODE) @@ -83,6 +88,19 @@ struct venc_ap_ipi_msg_enc { }; /** + * struct venc_ap_ipi_msg_enc_ext - AP to SCP extended enc cmd structure + * + * @base: base msg structure + * @data_item: number of items in the data array + * @data[8]: data array to store the set parameters + */ +struct venc_ap_ipi_msg_enc_ext { + struct venc_ap_ipi_msg_enc base; + uint32_t data_item; + uint32_t data[32]; +}; + +/** * struct venc_ap_ipi_msg_deinit - AP to VPU deinit cmd structure * @msg_id: message id (AP_IPIMSG_XXX_ENC_DEINIT) * @vpu_inst_addr: VPU encoder instance addr @@ -120,16 +138,17 @@ struct venc_vpu_ipi_msg_common { * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *) * @vpu_inst_addr: VPU encoder instance addr * (struct venc_vp8_vsi/venc_h264_vsi *) - * @reserved: reserved for future use. vpu is running in 32bit. Without - * this reserved field, if kernel run in 64bit. this struct size - * will be different between kernel and vpu + * @venc_abi_version: ABI version of the firmware. Kernel can use it to + * ensure that it is compatible with the firmware. + * For MT8173 the value of this field is undefined and + * should not be used. */ struct venc_vpu_ipi_msg_init { uint32_t msg_id; uint32_t status; uint64_t venc_inst; uint32_t vpu_inst_addr; - uint32_t reserved; + uint32_t venc_abi_version; }; /** diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c index 9540709c1905..be6d8790a41e 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c @@ -4,7 +4,8 @@ * Author: PoChun Lin <pochun.lin@mediatek.com> */ -#include "mtk_vpu.h" +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_fw.h" #include "venc_ipi_msg.h" #include "venc_vpu_if.h" @@ -13,7 +14,25 @@ static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data) const struct venc_vpu_ipi_msg_init *msg = data; vpu->inst_addr = msg->vpu_inst_addr; - vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr); + vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler, + msg->vpu_inst_addr); + + /* Firmware version field value is unspecified on MT8173. */ + if (vpu->ctx->dev->venc_pdata->chip == MTK_MT8173) + return; + + /* Check firmware version. */ + mtk_vcodec_debug(vpu, "firmware version: 0x%x\n", + msg->venc_abi_version); + switch (msg->venc_abi_version) { + case 1: + break; + default: + mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n", + msg->venc_abi_version); + vpu->failure = 1; + break; + } } static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data) @@ -25,7 +44,7 @@ static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data) vpu->is_key_frm = msg->is_key_frm; } -static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv) +static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv) { const struct venc_vpu_ipi_msg_common *msg = data; struct venc_vpu_inst *vpu = @@ -34,6 +53,11 @@ static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv) mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d", msg->msg_id, vpu, msg->status); + vpu->signaled = 1; + vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK); + if (vpu->failure) + goto failure; + switch (msg->msg_id) { case VPU_IPIMSG_ENC_INIT_DONE: handle_enc_init_msg(vpu, data); @@ -50,9 +74,7 @@ static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv) break; } - vpu->signaled = 1; - vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK); - +failure: mtk_vcodec_debug_leave(vpu); } @@ -63,12 +85,13 @@ static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg, mtk_vcodec_debug_enter(vpu); - if (!vpu->dev) { + if (!vpu->ctx->dev->fw_handler) { mtk_vcodec_err(vpu, "inst dev is NULL"); return -EINVAL; } - status = vpu_ipi_send(vpu->dev, vpu->id, msg, len); + status = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg, + len, 2000); if (status) { mtk_vcodec_err(vpu, "vpu_ipi_send msg_id %x len %d fail %d", *(uint32_t *)msg, len, status); @@ -93,8 +116,9 @@ int vpu_enc_init(struct venc_vpu_inst *vpu) vpu->signaled = 0; vpu->failure = 0; - status = vpu_ipi_register(vpu->dev, vpu->id, vpu_enc_ipi_handler, - NULL, NULL); + status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id, + vpu_enc_ipi_handler, "venc", NULL); + if (status) { mtk_vcodec_err(vpu, "vpu_ipi_register fail %d", status); return -EINVAL; @@ -113,49 +137,81 @@ int vpu_enc_init(struct venc_vpu_inst *vpu) return 0; } +static unsigned int venc_enc_param_crop_right(struct venc_vpu_inst *vpu, + struct venc_enc_param *enc_prm) +{ + unsigned int img_crop_right = enc_prm->buf_width - enc_prm->width; + + return img_crop_right % 16; +} + +static unsigned int venc_enc_param_crop_bottom(struct venc_enc_param *enc_prm) +{ + return round_up(enc_prm->height, 16) - enc_prm->height; +} + +static unsigned int venc_enc_param_num_mb(struct venc_enc_param *enc_prm) +{ + return DIV_ROUND_UP(enc_prm->width, 16) * + DIV_ROUND_UP(enc_prm->height, 16); +} + int vpu_enc_set_param(struct venc_vpu_inst *vpu, enum venc_set_param_type id, struct venc_enc_param *enc_param) { - struct venc_ap_ipi_msg_set_param out; + const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx); + size_t msg_size = is_ext ? + sizeof(struct venc_ap_ipi_msg_set_param_ext) : + sizeof(struct venc_ap_ipi_msg_set_param); + struct venc_ap_ipi_msg_set_param_ext out; mtk_vcodec_debug(vpu, "id %d ->", id); memset(&out, 0, sizeof(out)); - out.msg_id = AP_IPIMSG_ENC_SET_PARAM; - out.vpu_inst_addr = vpu->inst_addr; - out.param_id = id; + out.base.msg_id = AP_IPIMSG_ENC_SET_PARAM; + out.base.vpu_inst_addr = vpu->inst_addr; + out.base.param_id = id; switch (id) { case VENC_SET_PARAM_ENC: - out.data_item = 0; + if (is_ext) { + out.base.data_item = 3; + out.base.data[0] = + venc_enc_param_crop_right(vpu, enc_param); + out.base.data[1] = + venc_enc_param_crop_bottom(enc_param); + out.base.data[2] = venc_enc_param_num_mb(enc_param); + } else { + out.base.data_item = 0; + } break; case VENC_SET_PARAM_FORCE_INTRA: - out.data_item = 0; + out.base.data_item = 0; break; case VENC_SET_PARAM_ADJUST_BITRATE: - out.data_item = 1; - out.data[0] = enc_param->bitrate; + out.base.data_item = 1; + out.base.data[0] = enc_param->bitrate; break; case VENC_SET_PARAM_ADJUST_FRAMERATE: - out.data_item = 1; - out.data[0] = enc_param->frm_rate; + out.base.data_item = 1; + out.base.data[0] = enc_param->frm_rate; break; case VENC_SET_PARAM_GOP_SIZE: - out.data_item = 1; - out.data[0] = enc_param->gop_size; + out.base.data_item = 1; + out.base.data[0] = enc_param->gop_size; break; case VENC_SET_PARAM_INTRA_PERIOD: - out.data_item = 1; - out.data[0] = enc_param->intra_period; + out.base.data_item = 1; + out.base.data[0] = enc_param->intra_period; break; case VENC_SET_PARAM_SKIP_FRAME: - out.data_item = 0; + out.base.data_item = 0; break; default: mtk_vcodec_err(vpu, "id %d not supported", id); return -EINVAL; } - if (vpu_enc_send_msg(vpu, &out, sizeof(out))) { + if (vpu_enc_send_msg(vpu, &out, msg_size)) { mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_SET_PARAM %d fail", id); return -EINVAL; @@ -169,33 +225,44 @@ int vpu_enc_set_param(struct venc_vpu_inst *vpu, int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, - unsigned int *bs_size) + unsigned int *bs_size, + struct venc_frame_info *frame_info) { - struct venc_ap_ipi_msg_enc out; + const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx); + size_t msg_size = is_ext ? + sizeof(struct venc_ap_ipi_msg_enc_ext) : + sizeof(struct venc_ap_ipi_msg_enc); + struct venc_ap_ipi_msg_enc_ext out; mtk_vcodec_debug(vpu, "bs_mode %d ->", bs_mode); memset(&out, 0, sizeof(out)); - out.msg_id = AP_IPIMSG_ENC_ENCODE; - out.vpu_inst_addr = vpu->inst_addr; - out.bs_mode = bs_mode; + out.base.msg_id = AP_IPIMSG_ENC_ENCODE; + out.base.vpu_inst_addr = vpu->inst_addr; + out.base.bs_mode = bs_mode; if (frm_buf) { if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) && (frm_buf->fb_addr[1].dma_addr % 16 == 0) && (frm_buf->fb_addr[2].dma_addr % 16 == 0)) { - out.input_addr[0] = frm_buf->fb_addr[0].dma_addr; - out.input_addr[1] = frm_buf->fb_addr[1].dma_addr; - out.input_addr[2] = frm_buf->fb_addr[2].dma_addr; + out.base.input_addr[0] = frm_buf->fb_addr[0].dma_addr; + out.base.input_addr[1] = frm_buf->fb_addr[1].dma_addr; + out.base.input_addr[2] = frm_buf->fb_addr[2].dma_addr; } else { mtk_vcodec_err(vpu, "dma_addr not align to 16"); return -EINVAL; } } if (bs_buf) { - out.bs_addr = bs_buf->dma_addr; - out.bs_size = bs_buf->size; + out.base.bs_addr = bs_buf->dma_addr; + out.base.bs_size = bs_buf->size; } - if (vpu_enc_send_msg(vpu, &out, sizeof(out))) { + if (is_ext && frame_info) { + out.data_item = 3; + out.data[0] = frame_info->frm_count; + out.data[1] = frame_info->skip_frm_count; + out.data[2] = frame_info->frm_type; + } + if (vpu_enc_send_msg(vpu, &out, msg_size)) { mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_ENCODE %d fail", bs_mode); return -EINVAL; diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h index ba301a138a5a..f9be9cab7ff7 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h @@ -7,7 +7,7 @@ #ifndef _VENC_VPU_IF_H_ #define _VENC_VPU_IF_H_ -#include "mtk_vpu.h" +#include "mtk_vcodec_fw.h" #include "venc_drv_if.h" /* @@ -34,9 +34,8 @@ struct venc_vpu_inst { int is_key_frm; unsigned int inst_addr; void *vsi; - enum ipi_id id; + int id; struct mtk_vcodec_ctx *ctx; - struct platform_device *dev; }; int vpu_enc_init(struct venc_vpu_inst *vpu); @@ -46,7 +45,8 @@ int vpu_enc_set_param(struct venc_vpu_inst *vpu, int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, - unsigned int *bs_size); + unsigned int *bs_size, + struct venc_frame_info *frame_info); int vpu_enc_deinit(struct venc_vpu_inst *vpu); #endif diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index d30c08983f56..36cb9b6131f7 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -849,10 +849,6 @@ static int mtk_vpu_probe(struct platform_device *pdev) #ifdef CONFIG_DEBUG_FS vpu_debugfs = debugfs_create_file("mtk_vpu", S_IRUGO, NULL, (void *)dev, &vpu_debug_fops); - if (!vpu_debugfs) { - ret = -ENOMEM; - goto cleanup_ipi; - } #endif /* Set PTCM to 96K and DTCM to 32K */ @@ -910,7 +906,6 @@ remove_debugfs: of_reserved_mem_device_release(dev); #ifdef CONFIG_DEBUG_FS debugfs_remove(vpu_debugfs); -cleanup_ipi: #endif memset(vpu->ipi_desc, 0, sizeof(struct vpu_ipi_desc) * IPI_MAX); vpu_mutex_destroy: diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index df78df59da45..08a5473b5610 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -852,8 +852,11 @@ static int emmaprp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcdev); irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto rel_vdev; + } + ret = devm_request_irq(&pdev->dev, irq, emmaprp_irq, 0, dev_name(&pdev->dev), pcdev); if (ret) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index b91e472ee764..b1fc4518e275 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -142,7 +142,7 @@ static struct isp_reg isp_reg_list[] = { * readback the same register, in this case the revision register. * * See this link for reference: - * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html + * https://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html */ void omap3isp_flush(struct isp_device *isp) { @@ -2328,8 +2328,10 @@ static int isp_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, i); isp->mmio_base[map_idx] = devm_ioremap_resource(isp->dev, mem); - if (IS_ERR(isp->mmio_base[map_idx])) - return PTR_ERR(isp->mmio_base[map_idx]); + if (IS_ERR(isp->mmio_base[map_idx])) { + ret = PTR_ERR(isp->mmio_base[map_idx]); + goto error; + } } ret = isp_get_clocks(isp); diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 1ac9aef70dff..8811d6dd4ee7 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -703,7 +703,7 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) * requested. */ format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB; - /* Fall-through */ + fallthrough; case V4L2_FIELD_INTERLACED_TB: case V4L2_FIELD_INTERLACED_BT: /* Interlaced orders are only supported at the CCDC output. */ diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 6dce33f35041..e47520fcb93c 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -605,42 +605,6 @@ static const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc( return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); } -static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg, - unsigned int flags) -{ - unsigned long common_flags; - bool hsync = true, vsync = true, pclk, data, mode; - bool mipi_lanes, mipi_clock; - - common_flags = cfg->flags & flags; - - switch (cfg->type) { - case V4L2_MBUS_PARALLEL: - hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_LOW); - vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_VSYNC_ACTIVE_LOW); - /* fall through */ - case V4L2_MBUS_BT656: - pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_PCLK_SAMPLE_FALLING); - data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_LOW); - mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); - return (!hsync || !vsync || !pclk || !data || !mode) ? - 0 : common_flags; - case V4L2_MBUS_CSI2_DPHY: - mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; - mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); - return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; - default: - WARN_ON(1); - return -EINVAL; - } - return 0; -} - /** * struct pxa_camera_format_xlate - match between host and sensor formats * @code: code of a sensor provided format @@ -1186,9 +1150,9 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) clk_disable_unprepare(pcdev->clk); } -static void pxa_camera_eof(unsigned long arg) +static void pxa_camera_eof(struct tasklet_struct *t) { - struct pxa_camera_dev *pcdev = (struct pxa_camera_dev *)arg; + struct pxa_camera_dev *pcdev = from_tasklet(pcdev, t, task_eof); unsigned long cifr; struct pxa_buffer *buf; @@ -1231,31 +1195,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) return IRQ_HANDLED; } -static int test_platform_param(struct pxa_camera_dev *pcdev, - unsigned char buswidth, unsigned long *flags) -{ - /* - * Platform specified synchronization and pixel clock polarities are - * only a recommendation and are only used during probing. The PXA270 - * quick capture interface supports both. - */ - *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? - V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_LOW | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_VSYNC_ACTIVE_LOW | - V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_PCLK_SAMPLE_FALLING; - - /* If requested data width is supported by the platform, use it */ - if ((1 << (buswidth - 1)) & pcdev->width_flags) - return 0; - - return -EINVAL; -} - static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev, unsigned long flags, __u32 pixfmt) { @@ -1598,99 +1537,78 @@ static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) */ static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) { + unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample; struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc; - unsigned long bus_flags, common_flags; + int mbus_config; int ret; - ret = test_platform_param(pcdev, - pcdev->current_fmt->host_fmt->bits_per_sample, - &bus_flags); - if (ret < 0) - return ret; - - ret = sensor_call(pcdev, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = pxa_mbus_config_compatible(&cfg, - bus_flags); - if (!common_flags) { - dev_warn(pcdev_to_dev(pcdev), - "Flags incompatible: camera 0x%x, host 0x%lx\n", - cfg.flags, bus_flags); - return -EINVAL; - } - } else if (ret != -ENOIOCTLCMD) { - return ret; - } else { - common_flags = bus_flags; + if (!((1 << (bus_width - 1)) & pcdev->width_flags)) { + dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u", + bus_width); + return -EINVAL; } pcdev->channels = 1; /* Make choices, based on platform preferences */ - if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { - if (pcdev->platform_flags & PXA_CAMERA_HSP) - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; - } + mbus_config = 0; + if (pcdev->platform_flags & PXA_CAMERA_MASTER) + mbus_config |= V4L2_MBUS_MASTER; + else + mbus_config |= V4L2_MBUS_SLAVE; - if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { - if (pcdev->platform_flags & PXA_CAMERA_VSP) - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; - } + if (pcdev->platform_flags & PXA_CAMERA_HSP) + mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH; + else + mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW; - if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && - (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { - if (pcdev->platform_flags & PXA_CAMERA_PCP) - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; - else - common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; - } + if (pcdev->platform_flags & PXA_CAMERA_VSP) + mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH; + else + mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW; - cfg.flags = common_flags; - ret = sensor_call(pcdev, video, s_mbus_config, &cfg); + if (pcdev->platform_flags & PXA_CAMERA_PCP) + mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING; + else + mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING; + mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH; + + cfg.flags = mbus_config; + ret = sensor_call(pcdev, pad, set_mbus_config, 0, &cfg); if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_dbg(pcdev_to_dev(pcdev), - "camera s_mbus_config(0x%lx) returned %d\n", - common_flags, ret); + dev_err(pcdev_to_dev(pcdev), + "Failed to call set_mbus_config: %d\n", ret); return ret; } - pxa_camera_setup_cicr(pcdev, common_flags, pixfmt); - - return 0; -} - -static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev, - unsigned char buswidth) -{ - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - unsigned long bus_flags, common_flags; - int ret = test_platform_param(pcdev, buswidth, &bus_flags); - - if (ret < 0) - return ret; + /* + * If the requested media bus configuration has not been fully applied + * make sure it is supported by the platform. + * + * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering + * roles should match. + */ + if (cfg.flags != mbus_config) { + unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER | + V4L2_MBUS_SLAVE); + if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER | + V4L2_MBUS_SLAVE))) { + dev_err(pcdev_to_dev(pcdev), + "Unsupported mbus configuration: bus mastering\n"); + return -EINVAL; + } - ret = sensor_call(pcdev, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = pxa_mbus_config_compatible(&cfg, - bus_flags); - if (!common_flags) { - dev_warn(pcdev_to_dev(pcdev), - "Flags incompatible: camera 0x%x, host 0x%lx\n", - cfg.flags, bus_flags); + if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) { + dev_err(pcdev_to_dev(pcdev), + "Unsupported mbus configuration: DATA_ACTIVE_LOW\n"); return -EINVAL; } - } else if (ret == -ENOIOCTLCMD) { - ret = 0; } - return ret; + pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt); + + return 0; } static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = { @@ -1738,11 +1656,6 @@ static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev, return 0; } - /* This also checks support for the requested bits-per-sample */ - ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample); - if (ret < 0) - return 0; - switch (code.code) { case MEDIA_BUS_FMT_UYVY8_2X8: formats++; @@ -2478,7 +2391,7 @@ static int pxa_camera_probe(struct platform_device *pdev) goto exit_free_dma; } - tasklet_init(&pcdev->task_eof, pxa_camera_eof, (unsigned long)pcdev); + tasklet_setup(&pcdev->task_eof, pxa_camera_eof); pxa_camera_activate(pcdev); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 03ef9c5f4774..85b24054f35e 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -176,8 +176,10 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on) int ret; ret = pm_runtime_get_sync(dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_sync(dev); return ret; + } ret = csiphy_set_clock_rates(csiphy); if (ret < 0) { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index fc31c2c169cd..b7d2293a5004 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -2205,14 +2205,6 @@ static const struct camss_video_ops camss_vfe_video_ops = { .flush_buffers = vfe_flush_buffers, }; -void msm_vfe_stop_streaming(struct vfe_device *vfe) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vfe->line); i++) - msm_video_stop_streaming(&vfe->line[i].video_out); -} - /* * msm_vfe_register_entities - Register subdev node for VFE module * @vfe: VFE device diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 0d10071ae881..a90b0d2cc6de 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -178,8 +178,6 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe); void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id); void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id); -void msm_vfe_stop_streaming(struct vfe_device *vfe); - extern const struct vfe_hw_ops vfe_ops_4_1; extern const struct vfe_hw_ops vfe_ops_4_7; diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index cdbd6dba1122..114c3ae4a4ab 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -18,6 +18,12 @@ #include "camss-video.h" #include "camss.h" +#define CAMSS_FRAME_MIN_WIDTH 1 +#define CAMSS_FRAME_MAX_WIDTH 8191 +#define CAMSS_FRAME_MIN_HEIGHT 1 +#define CAMSS_FRAME_MAX_HEIGHT_RDI 8191 +#define CAMSS_FRAME_MAX_HEIGHT_PIX 4096 + struct fract { u8 numerator; u8 denominator; @@ -529,17 +535,16 @@ static int video_querycap(struct file *file, void *fh, return 0; } -static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +/* + * Returns the index in the video->formats[] array of the element which + * has the "ndx"th unique value of pixelformat field. + * If not found (no more unique pixelformat's) returns -EINVAL. + */ +static int video_get_unique_pixelformat_by_index(struct camss_video *video, + int ndx) { - struct camss_video *video = video_drvdata(file); int i, j, k; - if (f->type != video->type) - return -EINVAL; - - if (f->index >= video->nformats) - return -EINVAL; - /* find index "i" of "k"th unique pixelformat in formats array */ k = -1; for (i = 0; i < video->nformats; i++) { @@ -552,11 +557,53 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) if (j == i) k++; - if (k == f->index) - break; + if (k == ndx) + return i; + } + + return -EINVAL; +} + +/* + * Returns the index in the video->formats[] array of the element which + * has code equal to mcode. + * If not found returns -EINVAL. + */ +static int video_get_pixelformat_by_mbus_code(struct camss_video *video, + u32 mcode) +{ + int i; + + for (i = 0; i < video->nformats; i++) { + if (video->formats[i].code == mcode) + return i; + } + + return -EINVAL; +} + +static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct camss_video *video = video_drvdata(file); + int i; + + if (f->type != video->type) + return -EINVAL; + + if (f->index >= video->nformats) + return -EINVAL; + + if (f->mbus_code) { + /* Each entry in formats[] table has unique mbus_code */ + if (f->index > 0) + return -EINVAL; + + i = video_get_pixelformat_by_mbus_code(video, f->mbus_code); + } else { + i = video_get_unique_pixelformat_by_index(video, f->index); } - if (k < f->index) + if (i < 0) return -EINVAL; f->pixelformat = video->formats[i].pixelformat; @@ -564,6 +611,36 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) return 0; } +static int video_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct camss_video *video = video_drvdata(file); + int i; + + if (fsize->index) + return -EINVAL; + + /* Only accept pixel format present in the formats[] table */ + for (i = 0; i < video->nformats; i++) { + if (video->formats[i].pixelformat == fsize->pixel_format) + break; + } + + if (i == video->nformats) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = CAMSS_FRAME_MIN_WIDTH; + fsize->stepwise.max_width = CAMSS_FRAME_MAX_WIDTH; + fsize->stepwise.min_height = CAMSS_FRAME_MIN_HEIGHT; + fsize->stepwise.max_height = (video->line_based) ? + CAMSS_FRAME_MAX_HEIGHT_PIX : CAMSS_FRAME_MAX_HEIGHT_RDI; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + + return 0; +} + static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f) { struct camss_video *video = video_drvdata(file); @@ -593,7 +670,7 @@ static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) 1, 65528); sizeimage[i] = clamp_t(u32, p->sizeimage, bytesperline[i], - bytesperline[i] * 4096); + bytesperline[i] * CAMSS_FRAME_MAX_HEIGHT_PIX); } for (j = 0; j < video->nformats; j++) @@ -610,8 +687,8 @@ static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) memset(pix_mp, 0, sizeof(*pix_mp)); pix_mp->pixelformat = fi->pixelformat; - pix_mp->width = clamp_t(u32, width, 1, 8191); - pix_mp->height = clamp_t(u32, height, 1, 8191); + pix_mp->width = clamp_t(u32, width, 1, CAMSS_FRAME_MAX_WIDTH); + pix_mp->height = clamp_t(u32, height, 1, CAMSS_FRAME_MAX_HEIGHT_RDI); pix_mp->num_planes = fi->planes; for (i = 0; i < pix_mp->num_planes; i++) { bpl = pix_mp->width / fi->hsub[i].numerator * @@ -637,7 +714,7 @@ static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f) 1, 65528); p->sizeimage = clamp_t(u32, p->sizeimage, p->bytesperline, - p->bytesperline * 4096); + p->bytesperline * CAMSS_FRAME_MAX_HEIGHT_PIX); lines = p->sizeimage / p->bytesperline; if (p->bytesperline < bytesperline[i]) @@ -704,6 +781,7 @@ static int video_s_input(struct file *file, void *fh, unsigned int input) static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { .vidioc_querycap = video_querycap, .vidioc_enum_fmt_vid_cap = video_enum_fmt, + .vidioc_enum_framesizes = video_enum_framesizes, .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, @@ -879,7 +957,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, if (ret < 0) { dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n", ret); - goto error_media_init; + goto error_vb2_init; } mutex_init(&video->lock); @@ -911,8 +989,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, } vdev->fops = &msm_vid_fops; - vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING + | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; vdev->ioctl_ops = &msm_vid_ioctl_ops; vdev->release = msm_video_release; vdev->v4l2_dev = v4l2_dev; @@ -936,23 +1014,15 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, error_video_register: media_entity_cleanup(&vdev->entity); mutex_destroy(&video->lock); -error_media_init: - vb2_queue_release(&video->vb2_q); error_vb2_init: mutex_destroy(&video->q_lock); return ret; } -void msm_video_stop_streaming(struct camss_video *video) -{ - if (vb2_is_streaming(&video->vb2_q)) - vb2_queue_release(&video->vb2_q); -} - void msm_video_unregister(struct camss_video *video) { atomic_inc(&video->camss->ref_count); - video_unregister_device(&video->vdev); + vb2_video_unregister_device(&video->vdev); atomic_dec(&video->camss->ref_count); } diff --git a/drivers/media/platform/qcom/camss/camss-video.h b/drivers/media/platform/qcom/camss/camss-video.h index aa35e8cc6fd5..bdbae8424140 100644 --- a/drivers/media/platform/qcom/camss/camss-video.h +++ b/drivers/media/platform/qcom/camss/camss-video.h @@ -52,8 +52,6 @@ struct camss_video { unsigned int nformats; }; -void msm_video_stop_streaming(struct camss_video *video); - int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, const char *name, int is_pix); diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 2483641799df..9186881afc98 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -974,13 +974,8 @@ void camss_delete(struct camss *camss) */ static int camss_remove(struct platform_device *pdev) { - unsigned int i; - struct camss *camss = platform_get_drvdata(pdev); - for (i = 0; i < camss->vfe_num; i++) - msm_vfe_stop_streaming(&camss->vfe[i]); - v4l2_async_notifier_unregister(&camss->notifier); v4l2_async_notifier_cleanup(&camss->notifier); camss_unregister_entities(camss); diff --git a/drivers/media/platform/qcom/venus/Makefile b/drivers/media/platform/qcom/venus/Makefile index 64af0bc1edae..dfc636865709 100644 --- a/drivers/media/platform/qcom/venus/Makefile +++ b/drivers/media/platform/qcom/venus/Makefile @@ -3,7 +3,7 @@ venus-core-objs += core.o helpers.o firmware.o \ hfi_venus.o hfi_msgs.o hfi_cmds.o hfi.o \ - hfi_parser.o pm_helpers.o + hfi_parser.o pm_helpers.o dbgfs.o venus-dec-objs += vdec.o vdec_ctrls.o venus-enc-objs += venc.o venc_ctrls.o diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 203c6538044f..6103aaf43987 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -6,6 +6,7 @@ #include <linux/init.h> #include <linux/interconnect.h> #include <linux/ioctl.h> +#include <linux/delay.h> #include <linux/list.h> #include <linux/module.h> #include <linux/of_device.h> @@ -40,13 +41,7 @@ static void venus_event_notify(struct venus_core *core, u32 event) mutex_unlock(&core->lock); disable_irq_nosync(core->irq); - - /* - * Delay recovery to ensure venus has completed any pending cache - * operations. Without this sleep, we see device reset when firmware is - * unloaded after a system error. - */ - schedule_delayed_work(&core->work, msecs_to_jiffies(100)); + schedule_delayed_work(&core->work, msecs_to_jiffies(10)); } static const struct hfi_core_ops venus_core_ops = { @@ -59,23 +54,29 @@ static void venus_sys_error_handler(struct work_struct *work) container_of(work, struct venus_core, work.work); int ret = 0; - dev_warn(core->dev, "system error has occurred, starting recovery!\n"); - pm_runtime_get_sync(core->dev); hfi_core_deinit(core, true); - hfi_destroy(core); + + dev_warn(core->dev, "system error has occurred, starting recovery!\n"); + mutex_lock(&core->lock); + + while (pm_runtime_active(core->dev_dec) || pm_runtime_active(core->dev_enc)) + msleep(10); + venus_shutdown(core); pm_runtime_put_sync(core->dev); - ret |= hfi_create(core, &venus_core_ops); + while (core->pmdomains[0] && pm_runtime_active(core->pmdomains[0])) + usleep_range(1000, 1500); + + hfi_reinit(core); pm_runtime_get_sync(core->dev); ret |= venus_boot(core); - ret |= hfi_core_resume(core, true); enable_irq(core->irq); @@ -224,15 +225,9 @@ static int venus_probe(struct platform_device *pdev) ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); if (ret) - return ret; + goto err_core_put; - if (!dev->dma_parms) { - dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), - GFP_KERNEL); - if (!dev->dma_parms) - return -ENOMEM; - } - dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + dma_set_max_seg_size(dev, UINT_MAX); INIT_LIST_HEAD(&core->instances); mutex_init(&core->lock); @@ -242,11 +237,11 @@ static int venus_probe(struct platform_device *pdev) IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "venus", core); if (ret) - return ret; + goto err_core_put; ret = hfi_create(core, &venus_core_ops); if (ret) - return ret; + goto err_core_put; pm_runtime_enable(dev); @@ -287,8 +282,12 @@ static int venus_probe(struct platform_device *pdev) goto err_core_deinit; ret = pm_runtime_put_sync(dev); - if (ret) + if (ret) { + pm_runtime_get_noresume(dev); goto err_dev_unregister; + } + + venus_dbgfs_init(core); return 0; @@ -299,9 +298,13 @@ err_core_deinit: err_venus_shutdown: venus_shutdown(core); err_runtime_disable: + pm_runtime_put_noidle(dev); pm_runtime_set_suspended(dev); pm_runtime_disable(dev); hfi_destroy(core); +err_core_put: + if (core->pm_ops->core_put) + core->pm_ops->core_put(dev); return ret; } @@ -337,6 +340,7 @@ static int venus_remove(struct platform_device *pdev) v4l2_device_unregister(&core->v4l2_dev); mutex_destroy(&core->pm_lock); mutex_destroy(&core->lock); + venus_dbgfs_deinit(core); return ret; } @@ -520,6 +524,7 @@ static const struct venus_resources sdm845_res_v2 = { .vcodec_clks_num = 2, .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains_num = 3, + .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 2, .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_4XX, @@ -527,6 +532,10 @@ static const struct venus_resources sdm845_res_v2 = { .vmem_size = 0, .vmem_addr = 0, .dma_mask = 0xe0000000 - 1, + .cp_start = 0, + .cp_size = 0x70800000, + .cp_nonpixel_start = 0x1000000, + .cp_nonpixel_size = 0x24800000, .fwname = "qcom/venus-5.2/venus.mdt", }; @@ -565,6 +574,7 @@ static const struct venus_resources sc7180_res = { .vcodec_clks_num = 2, .vcodec_pmdomains = { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, + .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 1, .hfi_version = HFI_VERSION_4XX, .vmem_id = VIDC_RESOURCE_NONE, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 7118612673c9..7b79a33dc9d6 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -12,12 +12,20 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> +#include "dbgfs.h" #include "hfi.h" +#define VDBGL "VenusLow : " +#define VDBGM "VenusMed : " +#define VDBGH "VenusHigh: " +#define VDBGFW "VenusFW : " + #define VIDC_CLKS_NUM_MAX 4 #define VIDC_VCODEC_CLKS_NUM_MAX 2 #define VIDC_PMDOMAINS_NUM_MAX 3 +extern int venus_fw_debug; + struct freq_tbl { unsigned int load; unsigned long freq; @@ -62,12 +70,17 @@ struct venus_resources { unsigned int vcodec_clks_num; const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; unsigned int vcodec_pmdomains_num; + const char **opp_pmdomain; unsigned int vcodec_num; enum hfi_version hfi_version; u32 max_load; unsigned int vmem_id; u32 vmem_size; u32 vmem_addr; + u32 cp_start; + u32 cp_size; + u32 cp_nonpixel_start; + u32 cp_nonpixel_size; const char *fwname; }; @@ -136,6 +149,7 @@ struct venus_caps { * @priv: a private filed for HFI operations * @ops: the core HFI operations * @work: a delayed work for handling system fatal error + * @root: debugfs root directory */ struct venus_core { void __iomem *base; @@ -145,8 +159,12 @@ struct venus_core { struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; struct icc_path *video_path; struct icc_path *cpucfg_path; + struct opp_table *opp_table; + bool has_opp_table; struct device_link *pd_dl_venus; struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + struct device_link *opp_dl_venus; + struct device *opp_pmdomain; struct video_device *vdev_dec; struct video_device *vdev_enc; struct v4l2_device v4l2_dev; @@ -185,6 +203,7 @@ struct venus_core { unsigned int codecs_count; unsigned int core0_usage_count; unsigned int core1_usage_count; + struct dentry *root; }; struct vdec_controls { @@ -201,6 +220,8 @@ struct venc_controls { u32 bitrate; u32 bitrate_peak; u32 rc_enable; + u32 const_quality; + u32 frame_skip_mode; u32 h264_i_period; u32 h264_entropy_mode; @@ -222,17 +243,8 @@ struct venc_controls { u32 header_mode; - struct { - u32 mpeg4; - u32 h264; - u32 vpx; - u32 hevc; - } profile; - struct { - u32 mpeg4; - u32 h264; - u32 hevc; - } level; + u32 profile; + u32 level; }; struct venus_buffer { diff --git a/drivers/media/platform/qcom/venus/dbgfs.c b/drivers/media/platform/qcom/venus/dbgfs.c new file mode 100644 index 000000000000..52de47f2ca88 --- /dev/null +++ b/drivers/media/platform/qcom/venus/dbgfs.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020 Linaro Ltd. + */ + +#include <linux/debugfs.h> + +#include "core.h" + +void venus_dbgfs_init(struct venus_core *core) +{ + core->root = debugfs_create_dir("venus", NULL); + debugfs_create_x32("fw_level", 0644, core->root, &venus_fw_debug); +} + +void venus_dbgfs_deinit(struct venus_core *core) +{ + debugfs_remove_recursive(core->root); +} diff --git a/drivers/media/platform/qcom/venus/dbgfs.h b/drivers/media/platform/qcom/venus/dbgfs.h new file mode 100644 index 000000000000..b7b621a8472f --- /dev/null +++ b/drivers/media/platform/qcom/venus/dbgfs.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2020 Linaro Ltd. */ + +#ifndef __VENUS_DBGFS_H__ +#define __VENUS_DBGFS_H__ + +struct venus_core; + +void venus_dbgfs_init(struct venus_core *core); +void venus_dbgfs_deinit(struct venus_core *core); + +#endif diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 8801a6a7543d..1db64a854b88 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -181,6 +181,7 @@ static int venus_shutdown_no_tz(struct venus_core *core) int venus_boot(struct venus_core *core) { struct device *dev = core->dev; + const struct venus_resources *res = core->res; phys_addr_t mem_phys; size_t mem_size; int ret; @@ -200,7 +201,23 @@ int venus_boot(struct venus_core *core) else ret = venus_boot_no_tz(core, mem_phys, mem_size); - return ret; + if (ret) + return ret; + + if (core->use_tz && res->cp_size) { + ret = qcom_scm_mem_protect_video_var(res->cp_start, + res->cp_size, + res->cp_nonpixel_start, + res->cp_nonpixel_size); + if (ret) { + qcom_scm_pas_shutdown(VENUS_PAS_ID); + dev_err(dev, "set virtual address ranges fail (%d)\n", + ret); + return ret; + } + } + + return 0; } int venus_shutdown(struct venus_core *core) diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 0143af7822b2..50439eb1ffea 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -6,6 +6,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/kernel.h> #include <media/videobuf2-dma-sg.h> #include <media/v4l2-mem2mem.h> #include <asm/div64.h> @@ -396,7 +397,7 @@ put_ts_metadata(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf) } if (slot == -1) { - dev_dbg(inst->core->dev, "%s: no free slot\n", __func__); + dev_dbg(inst->core->dev, VDBGL "no free slot\n"); return; } @@ -582,6 +583,244 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type, } EXPORT_SYMBOL_GPL(venus_helper_get_bufreq); +struct id_mapping { + u32 hfi_id; + u32 v4l2_id; +}; + +static const struct id_mapping mpeg4_profiles[] = { + { HFI_MPEG4_PROFILE_SIMPLE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE }, + { HFI_MPEG4_PROFILE_ADVANCEDSIMPLE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE }, +}; + +static const struct id_mapping mpeg4_levels[] = { + { HFI_MPEG4_LEVEL_0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 }, + { HFI_MPEG4_LEVEL_0b, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B }, + { HFI_MPEG4_LEVEL_1, V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 }, + { HFI_MPEG4_LEVEL_2, V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 }, + { HFI_MPEG4_LEVEL_3, V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 }, + { HFI_MPEG4_LEVEL_4, V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 }, + { HFI_MPEG4_LEVEL_5, V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 }, +}; + +static const struct id_mapping mpeg2_profiles[] = { + { HFI_MPEG2_PROFILE_SIMPLE, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE }, + { HFI_MPEG2_PROFILE_MAIN, V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN }, + { HFI_MPEG2_PROFILE_SNR, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE }, + { HFI_MPEG2_PROFILE_SPATIAL, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE }, + { HFI_MPEG2_PROFILE_HIGH, V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH }, +}; + +static const struct id_mapping mpeg2_levels[] = { + { HFI_MPEG2_LEVEL_LL, V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW }, + { HFI_MPEG2_LEVEL_ML, V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN }, + { HFI_MPEG2_LEVEL_H14, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440 }, + { HFI_MPEG2_LEVEL_HL, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH }, +}; + +static const struct id_mapping h264_profiles[] = { + { HFI_H264_PROFILE_BASELINE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE }, + { HFI_H264_PROFILE_MAIN, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN }, + { HFI_H264_PROFILE_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH }, + { HFI_H264_PROFILE_STEREO_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH }, + { HFI_H264_PROFILE_MULTIVIEW_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH }, + { HFI_H264_PROFILE_CONSTRAINED_BASE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE }, + { HFI_H264_PROFILE_CONSTRAINED_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH }, +}; + +static const struct id_mapping h264_levels[] = { + { HFI_H264_LEVEL_1, V4L2_MPEG_VIDEO_H264_LEVEL_1_0 }, + { HFI_H264_LEVEL_1b, V4L2_MPEG_VIDEO_H264_LEVEL_1B }, + { HFI_H264_LEVEL_11, V4L2_MPEG_VIDEO_H264_LEVEL_1_1 }, + { HFI_H264_LEVEL_12, V4L2_MPEG_VIDEO_H264_LEVEL_1_2 }, + { HFI_H264_LEVEL_13, V4L2_MPEG_VIDEO_H264_LEVEL_1_3 }, + { HFI_H264_LEVEL_2, V4L2_MPEG_VIDEO_H264_LEVEL_2_0 }, + { HFI_H264_LEVEL_21, V4L2_MPEG_VIDEO_H264_LEVEL_2_1 }, + { HFI_H264_LEVEL_22, V4L2_MPEG_VIDEO_H264_LEVEL_2_2 }, + { HFI_H264_LEVEL_3, V4L2_MPEG_VIDEO_H264_LEVEL_3_0 }, + { HFI_H264_LEVEL_31, V4L2_MPEG_VIDEO_H264_LEVEL_3_1 }, + { HFI_H264_LEVEL_32, V4L2_MPEG_VIDEO_H264_LEVEL_3_2 }, + { HFI_H264_LEVEL_4, V4L2_MPEG_VIDEO_H264_LEVEL_4_0 }, + { HFI_H264_LEVEL_41, V4L2_MPEG_VIDEO_H264_LEVEL_4_1 }, + { HFI_H264_LEVEL_42, V4L2_MPEG_VIDEO_H264_LEVEL_4_2 }, + { HFI_H264_LEVEL_5, V4L2_MPEG_VIDEO_H264_LEVEL_5_0 }, + { HFI_H264_LEVEL_51, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 }, + { HFI_H264_LEVEL_52, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 }, +}; + +static const struct id_mapping hevc_profiles[] = { + { HFI_HEVC_PROFILE_MAIN, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN }, + { HFI_HEVC_PROFILE_MAIN_STILL_PIC, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE }, + { HFI_HEVC_PROFILE_MAIN10, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10 }, +}; + +static const struct id_mapping hevc_levels[] = { + { HFI_HEVC_LEVEL_1, V4L2_MPEG_VIDEO_HEVC_LEVEL_1 }, + { HFI_HEVC_LEVEL_2, V4L2_MPEG_VIDEO_HEVC_LEVEL_2 }, + { HFI_HEVC_LEVEL_21, V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 }, + { HFI_HEVC_LEVEL_3, V4L2_MPEG_VIDEO_HEVC_LEVEL_3 }, + { HFI_HEVC_LEVEL_31, V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 }, + { HFI_HEVC_LEVEL_4, V4L2_MPEG_VIDEO_HEVC_LEVEL_4 }, + { HFI_HEVC_LEVEL_41, V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 }, + { HFI_HEVC_LEVEL_5, V4L2_MPEG_VIDEO_HEVC_LEVEL_5 }, + { HFI_HEVC_LEVEL_51, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 }, + { HFI_HEVC_LEVEL_52, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 }, + { HFI_HEVC_LEVEL_6, V4L2_MPEG_VIDEO_HEVC_LEVEL_6 }, + { HFI_HEVC_LEVEL_61, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 }, + { HFI_HEVC_LEVEL_62, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 }, +}; + +static const struct id_mapping vp8_profiles[] = { + { HFI_VPX_PROFILE_VERSION_0, V4L2_MPEG_VIDEO_VP8_PROFILE_0 }, + { HFI_VPX_PROFILE_VERSION_1, V4L2_MPEG_VIDEO_VP8_PROFILE_1 }, + { HFI_VPX_PROFILE_VERSION_2, V4L2_MPEG_VIDEO_VP8_PROFILE_2 }, + { HFI_VPX_PROFILE_VERSION_3, V4L2_MPEG_VIDEO_VP8_PROFILE_3 }, +}; + +static const struct id_mapping vp9_profiles[] = { + { HFI_VP9_PROFILE_P0, V4L2_MPEG_VIDEO_VP9_PROFILE_0 }, + { HFI_VP9_PROFILE_P2_10B, V4L2_MPEG_VIDEO_VP9_PROFILE_2 }, +}; + +static const struct id_mapping vp9_levels[] = { + { HFI_VP9_LEVEL_1, V4L2_MPEG_VIDEO_VP9_LEVEL_1_0 }, + { HFI_VP9_LEVEL_11, V4L2_MPEG_VIDEO_VP9_LEVEL_1_1 }, + { HFI_VP9_LEVEL_2, V4L2_MPEG_VIDEO_VP9_LEVEL_2_0}, + { HFI_VP9_LEVEL_21, V4L2_MPEG_VIDEO_VP9_LEVEL_2_1 }, + { HFI_VP9_LEVEL_3, V4L2_MPEG_VIDEO_VP9_LEVEL_3_0}, + { HFI_VP9_LEVEL_31, V4L2_MPEG_VIDEO_VP9_LEVEL_3_1 }, + { HFI_VP9_LEVEL_4, V4L2_MPEG_VIDEO_VP9_LEVEL_4_0 }, + { HFI_VP9_LEVEL_41, V4L2_MPEG_VIDEO_VP9_LEVEL_4_1 }, + { HFI_VP9_LEVEL_5, V4L2_MPEG_VIDEO_VP9_LEVEL_5_0 }, + { HFI_VP9_LEVEL_51, V4L2_MPEG_VIDEO_VP9_LEVEL_5_1 }, + { HFI_VP9_LEVEL_6, V4L2_MPEG_VIDEO_VP9_LEVEL_6_0 }, + { HFI_VP9_LEVEL_61, V4L2_MPEG_VIDEO_VP9_LEVEL_6_1 }, +}; + +static u32 find_v4l2_id(u32 hfi_id, const struct id_mapping *array, unsigned int array_sz) +{ + unsigned int i; + + if (!array || !array_sz) + return 0; + + for (i = 0; i < array_sz; i++) + if (hfi_id == array[i].hfi_id) + return array[i].v4l2_id; + + return 0; +} + +static u32 find_hfi_id(u32 v4l2_id, const struct id_mapping *array, unsigned int array_sz) +{ + unsigned int i; + + if (!array || !array_sz) + return 0; + + for (i = 0; i < array_sz; i++) + if (v4l2_id == array[i].v4l2_id) + return array[i].hfi_id; + + return 0; +} + +static void +v4l2_id_profile_level(u32 hfi_codec, struct hfi_profile_level *pl, u32 *profile, u32 *level) +{ + u32 hfi_pf = pl->profile; + u32 hfi_lvl = pl->level; + + switch (hfi_codec) { + case HFI_VIDEO_CODEC_H264: + *profile = find_v4l2_id(hfi_pf, h264_profiles, ARRAY_SIZE(h264_profiles)); + *level = find_v4l2_id(hfi_lvl, h264_levels, ARRAY_SIZE(h264_levels)); + break; + case HFI_VIDEO_CODEC_MPEG2: + *profile = find_v4l2_id(hfi_pf, mpeg2_profiles, ARRAY_SIZE(mpeg2_profiles)); + *level = find_v4l2_id(hfi_lvl, mpeg2_levels, ARRAY_SIZE(mpeg2_levels)); + break; + case HFI_VIDEO_CODEC_MPEG4: + *profile = find_v4l2_id(hfi_pf, mpeg4_profiles, ARRAY_SIZE(mpeg4_profiles)); + *level = find_v4l2_id(hfi_lvl, mpeg4_levels, ARRAY_SIZE(mpeg4_levels)); + break; + case HFI_VIDEO_CODEC_VP8: + *profile = find_v4l2_id(hfi_pf, vp8_profiles, ARRAY_SIZE(vp8_profiles)); + *level = 0; + break; + case HFI_VIDEO_CODEC_VP9: + *profile = find_v4l2_id(hfi_pf, vp9_profiles, ARRAY_SIZE(vp9_profiles)); + *level = find_v4l2_id(hfi_lvl, vp9_levels, ARRAY_SIZE(vp9_levels)); + break; + case HFI_VIDEO_CODEC_HEVC: + *profile = find_v4l2_id(hfi_pf, hevc_profiles, ARRAY_SIZE(hevc_profiles)); + *level = find_v4l2_id(hfi_lvl, hevc_levels, ARRAY_SIZE(hevc_levels)); + break; + default: + break; + } +} + +static void +hfi_id_profile_level(u32 hfi_codec, u32 v4l2_pf, u32 v4l2_lvl, struct hfi_profile_level *pl) +{ + switch (hfi_codec) { + case HFI_VIDEO_CODEC_H264: + pl->profile = find_hfi_id(v4l2_pf, h264_profiles, ARRAY_SIZE(h264_profiles)); + pl->level = find_hfi_id(v4l2_lvl, h264_levels, ARRAY_SIZE(h264_levels)); + break; + case HFI_VIDEO_CODEC_MPEG2: + pl->profile = find_hfi_id(v4l2_pf, mpeg2_profiles, ARRAY_SIZE(mpeg2_profiles)); + pl->level = find_hfi_id(v4l2_lvl, mpeg2_levels, ARRAY_SIZE(mpeg2_levels)); + break; + case HFI_VIDEO_CODEC_MPEG4: + pl->profile = find_hfi_id(v4l2_pf, mpeg4_profiles, ARRAY_SIZE(mpeg4_profiles)); + pl->level = find_hfi_id(v4l2_lvl, mpeg4_levels, ARRAY_SIZE(mpeg4_levels)); + break; + case HFI_VIDEO_CODEC_VP8: + pl->profile = find_hfi_id(v4l2_pf, vp8_profiles, ARRAY_SIZE(vp8_profiles)); + pl->level = 0; + break; + case HFI_VIDEO_CODEC_VP9: + pl->profile = find_hfi_id(v4l2_pf, vp9_profiles, ARRAY_SIZE(vp9_profiles)); + pl->level = find_hfi_id(v4l2_lvl, vp9_levels, ARRAY_SIZE(vp9_levels)); + break; + case HFI_VIDEO_CODEC_HEVC: + pl->profile = find_hfi_id(v4l2_pf, hevc_profiles, ARRAY_SIZE(hevc_profiles)); + pl->level = find_hfi_id(v4l2_lvl, hevc_levels, ARRAY_SIZE(hevc_levels)); + break; + default: + break; + } +} + +int venus_helper_get_profile_level(struct venus_inst *inst, u32 *profile, u32 *level) +{ + const u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; + union hfi_get_property hprop; + int ret; + + ret = hfi_session_get_property(inst, ptype, &hprop); + if (ret) + return ret; + + v4l2_id_profile_level(inst->hfi_codec, &hprop.profile_level, profile, level); + + return 0; +} +EXPORT_SYMBOL_GPL(venus_helper_get_profile_level); + +int venus_helper_set_profile_level(struct venus_inst *inst, u32 profile, u32 level) +{ + const u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; + struct hfi_profile_level pl; + + hfi_id_profile_level(inst->hfi_codec, profile, level, &pl); + + return hfi_session_set_property(inst, ptype, &pl); +} +EXPORT_SYMBOL_GPL(venus_helper_set_profile_level); + static u32 get_framesize_raw_nv12(u32 width, u32 height) { u32 y_stride, uv_stride, y_plane; diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 8fbbda12a4fe..a4a0562bc83f 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -61,4 +61,6 @@ int venus_helper_process_initial_cap_bufs(struct venus_inst *inst); int venus_helper_process_initial_out_bufs(struct venus_inst *inst); void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us, struct vb2_v4l2_buffer *vbuf); +int venus_helper_get_profile_level(struct venus_inst *inst, u32 *profile, u32 *level); +int venus_helper_set_profile_level(struct venus_inst *inst, u32 profile, u32 level); #endif diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index a211eb93e0f9..a59022adb14c 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -517,3 +517,8 @@ void hfi_destroy(struct venus_core *core) { venus_hfi_destroy(core); } + +void hfi_reinit(struct venus_core *core) +{ + venus_hfi_queues_reinit(core); +} diff --git a/drivers/media/platform/qcom/venus/hfi.h b/drivers/media/platform/qcom/venus/hfi.h index 62c315291484..f25d412d6553 100644 --- a/drivers/media/platform/qcom/venus/hfi.h +++ b/drivers/media/platform/qcom/venus/hfi.h @@ -145,6 +145,7 @@ struct hfi_ops { int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops); void hfi_destroy(struct venus_core *core); +void hfi_reinit(struct venus_core *core); int hfi_core_init(struct venus_core *core); int hfi_core_deinit(struct venus_core *core, bool blocking); diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index c67e412f8201..7022368c1e63 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -640,6 +640,7 @@ static int pkt_session_set_property_1x(struct hfi_session_set_property_pkt *pkt, case HFI_RATE_CONTROL_CBR_VFR: case HFI_RATE_CONTROL_VBR_CFR: case HFI_RATE_CONTROL_VBR_VFR: + case HFI_RATE_CONTROL_CQ: break; default: ret = -EINVAL; @@ -1218,6 +1219,37 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, return 0; } +static int +pkt_session_set_property_6xx(struct hfi_session_set_property_pkt *pkt, + void *cookie, u32 ptype, void *pdata) +{ + void *prop_data; + + if (!pkt || !cookie || !pdata) + return -EINVAL; + + prop_data = &pkt->data[1]; + + pkt->shdr.hdr.size = sizeof(*pkt); + pkt->shdr.hdr.pkt_type = HFI_CMD_SESSION_SET_PROPERTY; + pkt->shdr.session_id = hash32_ptr(cookie); + pkt->num_properties = 1; + pkt->data[0] = ptype; + + switch (ptype) { + case HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY: { + struct hfi_heic_frame_quality *in = pdata, *cq = prop_data; + + cq->frame_quality = in->frame_quality; + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cq); + break; + } default: + return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata); + } + + return 0; +} + int pkt_session_get_property(struct hfi_session_get_property_pkt *pkt, void *cookie, u32 ptype) { @@ -1236,7 +1268,10 @@ int pkt_session_set_property(struct hfi_session_set_property_pkt *pkt, if (hfi_ver == HFI_VERSION_3XX) return pkt_session_set_property_3xx(pkt, cookie, ptype, pdata); - return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata); + if (hfi_ver == HFI_VERSION_4XX) + return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata); + + return pkt_session_set_property_6xx(pkt, cookie, ptype, pdata); } void pkt_set_version(enum hfi_version version) diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index f6613df1d16b..60ee2479f7a6 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -231,6 +231,7 @@ #define HFI_RATE_CONTROL_VBR_CFR 0x1000003 #define HFI_RATE_CONTROL_CBR_VFR 0x1000004 #define HFI_RATE_CONTROL_CBR_CFR 0x1000005 +#define HFI_RATE_CONTROL_CQ 0x1000008 #define HFI_VIDEO_CODEC_H264 0x00000002 #define HFI_VIDEO_CODEC_H263 0x00000004 @@ -363,6 +364,24 @@ #define HFI_HEVC_TIER_MAIN 0x1 #define HFI_HEVC_TIER_HIGH0 0x2 +/* VP9 Profile 0, 8-bit */ +#define HFI_VP9_PROFILE_P0 0x00000001 +/* VP9 Profile 2, 10-bit */ +#define HFI_VP9_PROFILE_P2_10B 0x00000004 + +#define HFI_VP9_LEVEL_1 0x00000001 +#define HFI_VP9_LEVEL_11 0x00000002 +#define HFI_VP9_LEVEL_2 0x00000004 +#define HFI_VP9_LEVEL_21 0x00000008 +#define HFI_VP9_LEVEL_3 0x00000010 +#define HFI_VP9_LEVEL_31 0x00000020 +#define HFI_VP9_LEVEL_4 0x00000040 +#define HFI_VP9_LEVEL_41 0x00000080 +#define HFI_VP9_LEVEL_5 0x00000100 +#define HFI_VP9_LEVEL_51 0x00000200 +#define HFI_VP9_LEVEL_6 0x00000400 +#define HFI_VP9_LEVEL_61 0x00000800 + #define HFI_BUFFER_INPUT 0x1 #define HFI_BUFFER_OUTPUT 0x2 #define HFI_BUFFER_OUTPUT2 0x3 @@ -504,6 +523,7 @@ #define HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER 0x200600b #define HFI_PROPERTY_CONFIG_VENC_LTRPERIOD 0x200600c #define HFI_PROPERTY_CONFIG_VENC_PERF_MODE 0x200600e +#define HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY 0x2006014 /* * HFI_PROPERTY_PARAM_VPE_COMMON_START @@ -520,7 +540,8 @@ enum hfi_version { HFI_VERSION_1XX, HFI_VERSION_3XX, - HFI_VERSION_4XX + HFI_VERSION_4XX, + HFI_VERSION_6XX, }; struct hfi_buffer_info { @@ -725,6 +746,11 @@ struct hfi_quality_vs_speed { u32 quality_vs_speed; }; +struct hfi_heic_frame_quality { + u32 frame_quality; + u32 reserved[3]; +}; + struct hfi_quantization { u32 qp_i; u32 qp_p; diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 279a9d6fe737..06a1908ca225 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -138,7 +138,7 @@ static void event_sys_error(struct venus_core *core, u32 event, struct hfi_msg_event_notify_pkt *pkt) { if (pkt) - dev_dbg(core->dev, + dev_dbg(core->dev, VDBGH "sys error (session id:%x, data1:%x, data2:%x)\n", pkt->shdr.session_id, pkt->event_data1, pkt->event_data2); @@ -152,7 +152,7 @@ event_session_error(struct venus_core *core, struct venus_inst *inst, { struct device *dev = core->dev; - dev_dbg(dev, "session error: event id:%x, session id:%x\n", + dev_dbg(dev, VDBGH "session error: event id:%x, session id:%x\n", pkt->event_data1, pkt->shdr.session_id); if (!inst) @@ -247,7 +247,7 @@ sys_get_prop_image_version(struct device *dev, /* bad packet */ return; - dev_dbg(dev, "F/W version: %s\n", (u8 *)&pkt->data[1]); + dev_dbg(dev, VDBGL "F/W version: %s\n", (u8 *)&pkt->data[1]); } static void hfi_sys_property_info(struct venus_core *core, @@ -257,7 +257,7 @@ static void hfi_sys_property_info(struct venus_core *core, struct device *dev = core->dev; if (!pkt->num_properties) { - dev_dbg(dev, "%s: no properties\n", __func__); + dev_dbg(dev, VDBGL "no properties\n"); return; } @@ -266,7 +266,7 @@ static void hfi_sys_property_info(struct venus_core *core, sys_get_prop_image_version(dev, pkt); break; default: - dev_dbg(dev, "%s: unknown property data\n", __func__); + dev_dbg(dev, VDBGL "unknown property data\n"); break; } } @@ -297,7 +297,7 @@ static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst, static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst, void *packet) { - dev_dbg(core->dev, "sys idle\n"); + dev_dbg(core->dev, VDBGL "sys idle\n"); } static void hfi_sys_pc_prepare_done(struct venus_core *core, @@ -305,7 +305,8 @@ static void hfi_sys_pc_prepare_done(struct venus_core *core, { struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet; - dev_dbg(core->dev, "pc prepare done (error %x)\n", pkt->error_type); + dev_dbg(core->dev, VDBGL "pc prepare done (error %x)\n", + pkt->error_type); } static unsigned int @@ -387,8 +388,7 @@ static void hfi_session_prop_info(struct venus_core *core, case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: break; default: - dev_dbg(dev, "%s: unknown property id:%x\n", __func__, - pkt->data[0]); + dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->data[0]); return; } diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index 7f515a4b9bd1..363ee2a65453 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -239,6 +239,9 @@ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf, parser_init(inst, &codecs, &domain); + core->codecs_count = 0; + memset(core->caps, 0, sizeof(core->caps)); + while (words_count) { data = word + 1; diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 0d8855014ab3..4be4a75ddcb6 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -130,7 +130,7 @@ struct venus_hfi_device { }; static bool venus_pkt_debug; -static int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL; +int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL; static bool venus_sys_idle_indicator; static bool venus_fw_low_power_mode = true; static int venus_hw_rsp_timeout = 1000; @@ -477,7 +477,7 @@ static u32 venus_hwversion(struct venus_hfi_device *hdev) minor = minor >> WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT; step = ver & WRAPPER_HW_VERSION_STEP_VERSION_MASK; - dev_dbg(dev, "venus hw version %x.%x.%x\n", major, minor, step); + dev_dbg(dev, VDBGL "venus hw version %x.%x.%x\n", major, minor, step); return major; } @@ -906,7 +906,7 @@ static void venus_flush_debug_queue(struct venus_hfi_device *hdev) if (pkt->hdr.pkt_type != HFI_MSG_SYS_COV) { struct hfi_msg_sys_debug_pkt *pkt = packet; - dev_dbg(dev, "%s", pkt->msg_data); + dev_dbg(dev, VDBGFW "%s", pkt->msg_data); } } } @@ -986,13 +986,6 @@ static void venus_process_msg_sys_error(struct venus_hfi_device *hdev, venus_set_state(hdev, VENUS_STATE_DEINIT); - /* - * Once SYS_ERROR received from HW, it is safe to halt the AXI. - * With SYS_ERROR, Venus FW may have crashed and HW might be - * active and causing unnecessary transactions. Hence it is - * safe to stop all AXI transactions from venus subsystem. - */ - venus_halt_axi(hdev); venus_sfr_print(hdev); } @@ -1009,10 +1002,6 @@ static irqreturn_t venus_isr_thread(struct venus_core *core) res = hdev->core->res; pkt = hdev->pkt_buf; - if (hdev->irq_status & WRAPPER_INTR_STATUS_A2HWD_MASK) { - venus_sfr_print(hdev); - hfi_process_watchdog_timeout(core); - } while (!venus_iface_msgq_read(hdev, pkt)) { msg_ret = hfi_process_msg_packet(core, pkt); @@ -1133,6 +1122,10 @@ static int venus_session_init(struct venus_inst *inst, u32 session_type, struct hfi_session_init_pkt pkt; int ret; + ret = venus_sys_set_debug(hdev, venus_fw_debug); + if (ret) + goto err; + ret = pkt_session_init(&pkt, inst, session_type, codec); if (ret) goto err; @@ -1614,3 +1607,54 @@ err_kfree: core->ops = NULL; return ret; } + +void venus_hfi_queues_reinit(struct venus_core *core) +{ + struct venus_hfi_device *hdev = to_hfi_priv(core); + struct hfi_queue_table_header *tbl_hdr; + struct iface_queue *queue; + struct hfi_sfr *sfr; + unsigned int i; + + mutex_lock(&hdev->lock); + + for (i = 0; i < IFACEQ_NUM; i++) { + queue = &hdev->queues[i]; + queue->qhdr = + IFACEQ_GET_QHDR_START_ADDR(hdev->ifaceq_table.kva, i); + + venus_set_qhdr_defaults(queue->qhdr); + + queue->qhdr->start_addr = queue->qmem.da; + + if (i == IFACEQ_CMD_IDX) + queue->qhdr->type |= HFI_HOST_TO_CTRL_CMD_Q; + else if (i == IFACEQ_MSG_IDX) + queue->qhdr->type |= HFI_CTRL_TO_HOST_MSG_Q; + else if (i == IFACEQ_DBG_IDX) + queue->qhdr->type |= HFI_CTRL_TO_HOST_DBG_Q; + } + + tbl_hdr = hdev->ifaceq_table.kva; + tbl_hdr->version = 0; + tbl_hdr->size = IFACEQ_TABLE_SIZE; + tbl_hdr->qhdr0_offset = sizeof(struct hfi_queue_table_header); + tbl_hdr->qhdr_size = sizeof(struct hfi_queue_header); + tbl_hdr->num_q = IFACEQ_NUM; + tbl_hdr->num_active_q = IFACEQ_NUM; + + /* + * Set receive request to zero on debug queue as there is no + * need of interrupt from video hardware for debug messages + */ + queue = &hdev->queues[IFACEQ_DBG_IDX]; + queue->qhdr->rx_req = 0; + + sfr = hdev->sfr.kva; + sfr->buf_size = ALIGNED_SFR_SIZE; + + /* ensure table and queue header structs are settled in memory */ + wmb(); + + mutex_unlock(&hdev->lock); +} diff --git a/drivers/media/platform/qcom/venus/hfi_venus.h b/drivers/media/platform/qcom/venus/hfi_venus.h index 57154832090e..1b656ef2bf07 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.h +++ b/drivers/media/platform/qcom/venus/hfi_venus.h @@ -10,5 +10,6 @@ struct venus_core; void venus_hfi_destroy(struct venus_core *core); int venus_hfi_create(struct venus_core *core); +void venus_hfi_queues_reinit(struct venus_core *core); #endif diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 531e7a41658f..57877eacecf0 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -9,6 +9,7 @@ #include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/pm_domain.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/types.h> #include <media/v4l2-mem2mem.h> @@ -66,10 +67,9 @@ static void core_clks_disable(struct venus_core *core) static int core_clks_set_rate(struct venus_core *core, unsigned long freq) { - struct clk *clk = core->clks[0]; int ret; - ret = clk_set_rate(clk, freq); + ret = dev_pm_opp_set_rate(core->dev, freq); if (ret) return ret; @@ -212,7 +212,7 @@ static int load_scale_bw(struct venus_core *core) } mutex_unlock(&core->lock); - dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n", + dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n", total_avg, total_peak); return icc_set_bw(core->video_path, total_avg, total_peak); @@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on) static int vcodec_domains_get(struct device *dev) { + int ret; + struct opp_table *opp_table; + struct device **opp_virt_dev; struct venus_core *core = dev_get_drvdata(dev); const struct venus_resources *res = core->res; struct device *pd; unsigned int i; if (!res->vcodec_pmdomains_num) - return -ENODEV; + goto skip_pmdomains; for (i = 0; i < res->vcodec_pmdomains_num; i++) { pd = dev_pm_domain_attach_by_name(dev, @@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev) if (!core->pd_dl_venus) return -ENODEV; +skip_pmdomains: + if (!core->has_opp_table) + return 0; + + /* Attach the power domain for setting performance state */ + opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); + if (IS_ERR(opp_table)) { + ret = PTR_ERR(opp_table); + goto opp_attach_err; + } + + core->opp_pmdomain = *opp_virt_dev; + core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain, + DL_FLAG_RPM_ACTIVE | + DL_FLAG_PM_RUNTIME | + DL_FLAG_STATELESS); + if (!core->opp_dl_venus) { + ret = -ENODEV; + goto opp_dl_add_err; + } + return 0; + +opp_dl_add_err: + dev_pm_domain_detach(core->opp_pmdomain, true); +opp_attach_err: + if (core->pd_dl_venus) { + device_link_del(core->pd_dl_venus); + for (i = 0; i < res->vcodec_pmdomains_num; i++) { + if (IS_ERR_OR_NULL(core->pmdomains[i])) + continue; + dev_pm_domain_detach(core->pmdomains[i], true); + } + } + return ret; } static void vcodec_domains_put(struct device *dev) @@ -777,7 +814,7 @@ static void vcodec_domains_put(struct device *dev) unsigned int i; if (!res->vcodec_pmdomains_num) - return; + goto skip_pmdomains; if (core->pd_dl_venus) device_link_del(core->pd_dl_venus); @@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev) continue; dev_pm_domain_detach(core->pmdomains[i], true); } + +skip_pmdomains: + if (!core->has_opp_table) + return; + + if (core->opp_dl_venus) + device_link_del(core->opp_dl_venus); + + dev_pm_domain_detach(core->opp_pmdomain, true); } static int core_get_v4(struct device *dev) @@ -815,19 +861,46 @@ static int core_get_v4(struct device *dev) if (legacy_binding) return 0; + core->opp_table = dev_pm_opp_set_clkname(dev, "core"); + if (IS_ERR(core->opp_table)) + return PTR_ERR(core->opp_table); + + if (core->res->opp_pmdomain) { + ret = dev_pm_opp_of_add_table(dev); + if (!ret) { + core->has_opp_table = true; + } else if (ret != -ENODEV) { + dev_err(dev, "invalid OPP table in device tree\n"); + dev_pm_opp_put_clkname(core->opp_table); + return ret; + } + } + ret = vcodec_domains_get(dev); - if (ret) + if (ret) { + if (core->has_opp_table) + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_clkname(core->opp_table); return ret; + } return 0; } static void core_put_v4(struct device *dev) { + struct venus_core *core = dev_get_drvdata(dev); + if (legacy_binding) return; vcodec_domains_put(dev); + + if (core->has_opp_table) + dev_pm_opp_of_remove_table(dev); + if (core->opp_table) + dev_pm_opp_put_clkname(core->opp_table); + } static int core_power_v4(struct device *dev, int on) @@ -835,10 +908,15 @@ static int core_power_v4(struct device *dev, int on) struct venus_core *core = dev_get_drvdata(dev); int ret = 0; - if (on == POWER_ON) + if (on == POWER_ON) { ret = core_clks_enable(core); - else + } else { + /* Drop the performance state vote */ + if (core->opp_pmdomain) + dev_pm_opp_set_rate(dev, 0); + core_clks_disable(core); + } return ret; } diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 7c4c483d5438..ea13170a6a2c 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -225,7 +225,7 @@ static int vdec_check_src_change(struct venus_inst *inst) if (!(inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) || !inst->reconfig) - dev_dbg(inst->core->dev, "%s: wrong state\n", __func__); + dev_dbg(inst->core->dev, VDBGH "wrong state\n"); done: return 0; @@ -1072,7 +1072,7 @@ static int vdec_stop_capture(struct venus_inst *inst) switch (inst->codec_state) { case VENUS_DEC_STATE_DECODING: ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true); - /* fallthrough */ + fallthrough; case VENUS_DEC_STATE_DRAIN: vdec_cancel_dst_buffers(inst); inst->codec_state = VENUS_DEC_STATE_STOPPED; @@ -1088,8 +1088,6 @@ static int vdec_stop_capture(struct venus_inst *inst) break; } - INIT_LIST_HEAD(&inst->registeredbufs); - return ret; } @@ -1189,6 +1187,14 @@ static int vdec_buf_init(struct vb2_buffer *vb) static void vdec_buf_cleanup(struct vb2_buffer *vb) { struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct venus_buffer *buf = to_venus_buffer(vbuf); + + mutex_lock(&inst->lock); + if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + if (!list_empty(&inst->registeredbufs)) + list_del_init(&buf->reg_list); + mutex_unlock(&inst->lock); inst->buf_count--; if (!inst->buf_count) @@ -1310,7 +1316,7 @@ static void vdec_event_change(struct venus_inst *inst, if (inst->bit_depth != ev_data->bit_depth) inst->bit_depth = ev_data->bit_depth; - dev_dbg(dev, "event %s sufficient resources (%ux%u)\n", + dev_dbg(dev, VDBGM "event %s sufficient resources (%ux%u)\n", sufficient ? "" : "not", ev_data->width, ev_data->height); if (sufficient) { @@ -1344,7 +1350,7 @@ static void vdec_event_change(struct venus_inst *inst, ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, false); if (ret) - dev_dbg(dev, "flush output error %d\n", ret); + dev_dbg(dev, VDBGH "flush output error %d\n", ret); } inst->reconfig = true; @@ -1453,13 +1459,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->allow_zero_bytesused = 1; dst_vq->min_buffers_needed = 0; dst_vq->dev = inst->core->dev; - ret = vb2_queue_init(dst_vq); - if (ret) { - vb2_queue_release(src_vq); - return ret; - } - - return 0; + return vb2_queue_init(dst_vq); } static int vdec_open(struct file *file) diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c index 3a963cbd342a..974110b75b93 100644 --- a/drivers/media/platform/qcom/venus/vdec_ctrls.c +++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c @@ -22,10 +22,12 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: ctr->profile = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: ctr->level = ctrl->val; break; default: @@ -40,25 +42,26 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) struct venus_inst *inst = ctrl_to_inst(ctrl); struct vdec_controls *ctr = &inst->controls.dec; struct hfi_buffer_requirements bufreq; - union hfi_get_property hprop; enum hfi_version ver = inst->core->res->hfi_version; - u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; + u32 profile, level; int ret; switch (ctrl->id) { case V4L2_CID_MPEG_VIDEO_H264_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: - ret = hfi_session_get_property(inst, ptype, &hprop); + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + ret = venus_helper_get_profile_level(inst, &profile, &level); if (!ret) - ctr->profile = hprop.profile_level.profile; + ctr->profile = profile; ctrl->val = ctr->profile; break; case V4L2_CID_MPEG_VIDEO_H264_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - ret = hfi_session_get_property(inst, ptype, &hprop); + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: + ret = venus_helper_get_profile_level(inst, &profile, &level); if (!ret) - ctr->level = hprop.profile_level.level; + ctr->level = level; ctrl->val = ctr->level; break; case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: @@ -86,7 +89,7 @@ int vdec_ctrl_init(struct venus_inst *inst) struct v4l2_ctrl *ctrl; int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 7); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 9); if (ret) return ret; @@ -133,6 +136,20 @@ int vdec_ctrl_init(struct venus_inst *inst) if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + V4L2_MPEG_VIDEO_VP9_PROFILE_3, + 0, V4L2_MPEG_VIDEO_VP9_PROFILE_0); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + V4L2_MPEG_VIDEO_VP9_LEVEL_6_2, + 0, V4L2_MPEG_VIDEO_VP9_LEVEL_1_0); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, 0, 1, 1, 0); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 513bbc07f7bc..f8b1484e7dcd 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -113,80 +113,6 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) static int venc_v4l2_to_hfi(int id, int value) { switch (id) { - case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - switch (value) { - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0: - default: - return HFI_MPEG4_LEVEL_0; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B: - return HFI_MPEG4_LEVEL_0b; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1: - return HFI_MPEG4_LEVEL_1; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2: - return HFI_MPEG4_LEVEL_2; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3: - return HFI_MPEG4_LEVEL_3; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4: - return HFI_MPEG4_LEVEL_4; - case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5: - return HFI_MPEG4_LEVEL_5; - } - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: - switch (value) { - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: - default: - return HFI_MPEG4_PROFILE_SIMPLE; - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: - return HFI_MPEG4_PROFILE_ADVANCEDSIMPLE; - } - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - switch (value) { - case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: - return HFI_H264_PROFILE_BASELINE; - case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: - return HFI_H264_PROFILE_CONSTRAINED_BASE; - case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: - return HFI_H264_PROFILE_MAIN; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: - default: - return HFI_H264_PROFILE_HIGH; - } - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - switch (value) { - case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: - return HFI_H264_LEVEL_1; - case V4L2_MPEG_VIDEO_H264_LEVEL_1B: - return HFI_H264_LEVEL_1b; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: - return HFI_H264_LEVEL_11; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: - return HFI_H264_LEVEL_12; - case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: - return HFI_H264_LEVEL_13; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: - return HFI_H264_LEVEL_2; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: - return HFI_H264_LEVEL_21; - case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: - return HFI_H264_LEVEL_22; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: - return HFI_H264_LEVEL_3; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: - return HFI_H264_LEVEL_31; - case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: - return HFI_H264_LEVEL_32; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: - return HFI_H264_LEVEL_4; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: - return HFI_H264_LEVEL_41; - case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: - return HFI_H264_LEVEL_42; - case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: - default: - return HFI_H264_LEVEL_5; - case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: - return HFI_H264_LEVEL_51; - } case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: switch (value) { case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC: @@ -195,18 +121,6 @@ static int venc_v4l2_to_hfi(int id, int value) case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC: return HFI_H264_ENTROPY_CABAC; } - case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: - switch (value) { - case 0: - default: - return HFI_VPX_PROFILE_VERSION_0; - case 1: - return HFI_VPX_PROFILE_VERSION_1; - case 2: - return HFI_VPX_PROFILE_VERSION_2; - case 3: - return HFI_VPX_PROFILE_VERSION_3; - } case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: switch (value) { case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: @@ -217,46 +131,6 @@ static int venc_v4l2_to_hfi(int id, int value) case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: return HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY; } - case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: - switch (value) { - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: - default: - return HFI_HEVC_PROFILE_MAIN; - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: - return HFI_HEVC_PROFILE_MAIN_STILL_PIC; - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: - return HFI_HEVC_PROFILE_MAIN10; - } - case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: - switch (value) { - case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: - default: - return HFI_HEVC_LEVEL_1; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: - return HFI_HEVC_LEVEL_2; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: - return HFI_HEVC_LEVEL_21; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: - return HFI_HEVC_LEVEL_3; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: - return HFI_HEVC_LEVEL_31; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: - return HFI_HEVC_LEVEL_4; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: - return HFI_HEVC_LEVEL_41; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: - return HFI_HEVC_LEVEL_5; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: - return HFI_HEVC_LEVEL_51; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: - return HFI_HEVC_LEVEL_52; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6: - return HFI_HEVC_LEVEL_6; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1: - return HFI_HEVC_LEVEL_61; - case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2: - return HFI_HEVC_LEVEL_62; - } } return 0; @@ -584,6 +458,7 @@ static int venc_enum_frameintervals(struct file *file, void *fh, { struct venus_inst *inst = to_inst(file); const struct venus_format *fmt; + unsigned int framerate_factor = 1; fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; @@ -608,12 +483,17 @@ static int venc_enum_frameintervals(struct file *file, void *fh, fival->height < frame_height_min(inst)) return -EINVAL; + if (IS_V1(inst->core)) { + /* framerate is reported in 1/65535 fps unit */ + framerate_factor = (1 << 16); + } + fival->stepwise.min.numerator = 1; - fival->stepwise.min.denominator = frate_max(inst); + fival->stepwise.min.denominator = frate_max(inst) / framerate_factor; fival->stepwise.max.numerator = 1; - fival->stepwise.max.denominator = frate_min(inst); + fival->stepwise.max.denominator = frate_min(inst) / framerate_factor; fival->stepwise.step.numerator = 1; - fival->stepwise.step.denominator = frate_max(inst); + fival->stepwise.step.denominator = frate_max(inst) / framerate_factor; return 0; } @@ -651,13 +531,12 @@ static int venc_set_properties(struct venus_inst *inst) { struct venc_controls *ctr = &inst->controls.enc; struct hfi_intra_period intra_period; - struct hfi_profile_level pl; struct hfi_framerate frate; struct hfi_bitrate brate; struct hfi_idr_period idrp; struct hfi_quantization quant; struct hfi_quantization_range quant_range; - u32 ptype, rate_control, bitrate, profile = 0, level = 0; + u32 ptype, rate_control, bitrate; int ret; ret = venus_helper_set_work_mode(inst, VIDC_WORK_MODE_2); @@ -739,15 +618,29 @@ static int venc_set_properties(struct venus_inst *inst) if (!ctr->rc_enable) rate_control = HFI_RATE_CONTROL_OFF; else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) - rate_control = HFI_RATE_CONTROL_VBR_CFR; - else - rate_control = HFI_RATE_CONTROL_CBR_CFR; + rate_control = ctr->frame_skip_mode ? HFI_RATE_CONTROL_VBR_VFR : + HFI_RATE_CONTROL_VBR_CFR; + else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + rate_control = ctr->frame_skip_mode ? HFI_RATE_CONTROL_CBR_VFR : + HFI_RATE_CONTROL_CBR_CFR; + else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + rate_control = HFI_RATE_CONTROL_CQ; ptype = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL; ret = hfi_session_set_property(inst, ptype, &rate_control); if (ret) return ret; + if (rate_control == HFI_RATE_CONTROL_CQ && ctr->const_quality) { + struct hfi_heic_frame_quality quality = {}; + + ptype = HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY; + quality.frame_quality = ctr->const_quality; + ret = hfi_session_set_property(inst, ptype, &quality); + if (ret) + return ret; + } + if (!ctr->bitrate) bitrate = 64000; else @@ -791,35 +684,7 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; - if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) { - profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_PROFILE, - ctr->profile.h264); - level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_LEVEL, - ctr->level.h264); - } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) { - profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_VP8_PROFILE, - ctr->profile.vpx); - level = 0; - } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_MPEG4) { - profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, - ctr->profile.mpeg4); - level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, - ctr->level.mpeg4); - } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H263) { - profile = 0; - level = 0; - } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { - profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, - ctr->profile.hevc); - level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, - ctr->level.hevc); - } - - ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; - pl.profile = profile; - pl.level = level; - - ret = hfi_session_set_property(inst, ptype, &pl); + ret = venus_helper_set_profile_level(inst, ctr->profile, ctr->level); if (ret) return ret; @@ -1129,13 +994,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->allow_zero_bytesused = 1; dst_vq->min_buffers_needed = 1; dst_vq->dev = inst->core->dev; - ret = vb2_queue_init(dst_vq); - if (ret) { - vb2_queue_release(src_vq); - return ret; - } - - return 0; + return vb2_queue_init(dst_vq); } static void venc_inst_init(struct venus_inst *inst) diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 8362dde7949e..0708b3b89d0c 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -103,25 +103,15 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) ctr->h264_entropy_mode = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: - ctr->profile.mpeg4 = ctrl->val; - break; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - ctr->profile.h264 = ctrl->val; - break; case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: - ctr->profile.hevc = ctrl->val; - break; case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: - ctr->profile.vpx = ctrl->val; + ctr->profile = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - ctr->level.mpeg4 = ctrl->val; - break; case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - ctr->level.h264 = ctrl->val; - break; case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: - ctr->level.hevc = ctrl->val; + ctr->level = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ctr->h264_i_qp = ctrl->val; @@ -202,6 +192,12 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: ctr->rc_enable = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY: + ctr->const_quality = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: + ctr->frame_skip_mode = ctrl->val; + break; default: return -EINVAL; } @@ -217,7 +213,7 @@ int venc_ctrl_init(struct venus_inst *inst) { int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 31); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 33); if (ret) return ret; @@ -225,7 +221,8 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_MPEG_VIDEO_BITRATE_MODE, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, ~((1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | - (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)), + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)), V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, @@ -357,6 +354,16 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, 0, 100, 1, 0); + + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + ~((1 << V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + (1 << V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT)), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED); + ret = inst->ctrl_handler.error; if (ret) goto err; diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c index 5c6b00737fe7..5c03318ae07b 100644 --- a/drivers/media/platform/rcar-fcp.c +++ b/drivers/media/platform/rcar-fcp.c @@ -22,7 +22,6 @@ struct rcar_fcp_device { struct list_head list; struct device *dev; - struct device_dma_parameters dma_parms; }; static LIST_HEAD(fcp_devices); @@ -103,8 +102,10 @@ int rcar_fcp_enable(struct rcar_fcp_device *fcp) return 0; ret = pm_runtime_get_sync(fcp->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(fcp->dev); return ret; + } return 0; } @@ -138,8 +139,7 @@ static int rcar_fcp_probe(struct platform_device *pdev) fcp->dev = &pdev->dev; - fcp->dev->dma_parms = &fcp->dma_parms; - dma_set_max_seg_size(fcp->dev, DMA_BIT_MASK(32)); + dma_set_max_seg_size(fcp->dev, UINT_MAX); pm_runtime_enable(&pdev->dev); diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig index ca0d906dce2f..030312d862e7 100644 --- a/drivers/media/platform/rcar-vin/Kconfig +++ b/drivers/media/platform/rcar-vin/Kconfig @@ -9,7 +9,7 @@ config VIDEO_RCAR_CSI2 select V4L2_FWNODE help Support for Renesas R-Car MIPI CSI-2 receiver. - Supports R-Car Gen3 SoCs. + Supports R-Car Gen3 and RZ/G2 SoCs. To compile this driver as a module, choose M here: the module will be called rcar-csi2. @@ -24,7 +24,7 @@ config VIDEO_RCAR_VIN select V4L2_FWNODE help Support for Renesas R-Car Video Input (VIN) driver. - Supports R-Car Gen2 and Gen3 SoCs. + Supports R-Car Gen{2,3} and RZ/G{1,2} SoCs. To compile this driver as a module, choose M here: the module will be called rcar-vin. diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 7440c8965d27..34d003e0e9b9 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -243,7 +243,6 @@ static struct rvin_group *rvin_group_data; static void rvin_group_cleanup(struct rvin_group *group) { - media_device_unregister(&group->mdev); media_device_cleanup(&group->mdev); mutex_destroy(&group->lock); } @@ -253,7 +252,6 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin) struct media_device *mdev = &group->mdev; const struct of_device_id *match; struct device_node *np; - int ret; mutex_init(&group->lock); @@ -278,11 +276,7 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin) media_device_init(mdev); - ret = media_device_register(&group->mdev); - if (ret) - rvin_group_cleanup(group); - - return ret; + return 0; } static void rvin_group_release(struct kref *kref) @@ -626,12 +620,11 @@ static int rvin_parallel_parse_v4l2(struct device *dev, switch (vin->parallel->mbus_type) { case V4L2_MBUS_PARALLEL: - vin_dbg(vin, "Found PARALLEL media bus\n"); - vin->parallel->mbus_flags = vep->bus.parallel.flags; - break; case V4L2_MBUS_BT656: - vin_dbg(vin, "Found BT656 media bus\n"); - vin->parallel->mbus_flags = 0; + vin_dbg(vin, "Found %s media bus\n", + vin->parallel->mbus_type == V4L2_MBUS_PARALLEL ? + "PARALLEL" : "BT656"); + vin->parallel->bus = vep->bus.parallel; break; default: vin_err(vin, "Unknown media bus type\n"); @@ -682,6 +675,10 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) unsigned int i; int ret; + ret = media_device_register(&vin->group->mdev); + if (ret) + return ret; + ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); if (ret) { vin_err(vin, "Failed to register subdev nodes\n"); @@ -762,6 +759,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, } mutex_unlock(&vin->group->lock); + + media_device_unregister(&vin->group->mdev); } static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, @@ -944,6 +943,42 @@ static const struct rvin_info rcar_info_gen2 = { .max_height = 2048, }; +static const struct rvin_group_route rcar_info_r8a774e1_routes[] = { + { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) }, + { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) }, + { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) }, + { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) }, + { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) }, + { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) }, + { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) }, + { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) }, + { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) }, + { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) }, + { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) }, + { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) }, + { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) }, + { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) }, + { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) }, + { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) }, + { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) }, + { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) }, + { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) }, + { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) }, + { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) }, + { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) }, + { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) }, + { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) }, + { /* Sentinel */ } +}; + +static const struct rvin_info rcar_info_r8a774e1 = { + .model = RCAR_GEN3, + .use_mc = true, + .max_width = 4096, + .max_height = 4096, + .routes = rcar_info_r8a774e1_routes, +}; + static const struct rvin_group_route rcar_info_r8a7795_routes[] = { { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) }, { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) }, @@ -1221,6 +1256,10 @@ static const struct of_device_id rvin_of_id_table[] = { .data = &rcar_info_r8a77990, }, { + .compatible = "renesas,vin-r8a774e1", + .data = &rcar_info_r8a774e1, + }, + { .compatible = "renesas,vin-r8a7778", .data = &rcar_info_m1, }, @@ -1370,12 +1409,8 @@ static int rcar_vin_remove(struct platform_device *pdev) v4l2_async_notifier_cleanup(&vin->notifier); if (vin->info->use_mc) { - mutex_lock(&vin->group->lock); - if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { - v4l2_async_notifier_unregister(&vin->group->notifier); - v4l2_async_notifier_cleanup(&vin->group->notifier); - } - mutex_unlock(&vin->group->lock); + v4l2_async_notifier_unregister(&vin->group->notifier); + v4l2_async_notifier_cleanup(&vin->group->notifier); rvin_group_put(vin); } diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index c6cc4f473a07..79f229756805 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -320,6 +320,9 @@ static const struct rcar_csi2_format rcar_csi2_formats[] = { { .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 }, { .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 }, { .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .datatype = 0x2a, .bpp = 8 }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .datatype = 0x2a, .bpp = 8 }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .datatype = 0x2a, .bpp = 8 }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .datatype = 0x2a, .bpp = 8 }, }; @@ -362,8 +365,8 @@ struct rcar_csi2 { struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; struct v4l2_async_notifier notifier; - struct v4l2_async_subdev asd; struct v4l2_subdev *remote; + unsigned int remote_pad; struct v4l2_mbus_framefmt mf; @@ -409,13 +412,14 @@ static void rcsi2_exit_standby(struct rcar_csi2 *priv) reset_control_deassert(priv->rstc); } -static int rcsi2_wait_phy_start(struct rcar_csi2 *priv) +static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, + unsigned int lanes) { unsigned int timeout; /* Wait for the clock and data lanes to enter LP-11 state. */ for (timeout = 0; timeout <= 20; timeout++) { - const u32 lane_mask = (1 << priv->lanes) - 1; + const u32 lane_mask = (1 << lanes) - 1; if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) @@ -447,7 +451,8 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) return 0; } -static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) +static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, + unsigned int lanes) { struct v4l2_subdev *source; struct v4l2_ctrl *ctrl; @@ -472,15 +477,64 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) * bps = link_freq * 2 */ mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; - do_div(mbps, priv->lanes * 1000000); + do_div(mbps, lanes * 1000000); return mbps; } +static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, + unsigned int *lanes) +{ + struct v4l2_mbus_config mbus_config = { 0 }; + unsigned int num_lanes = UINT_MAX; + int ret; + + *lanes = priv->lanes; + + ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config, + priv->remote_pad, &mbus_config); + if (ret == -ENOIOCTLCMD) { + dev_dbg(priv->dev, "No remote mbus configuration available\n"); + return 0; + } + + if (ret) { + dev_err(priv->dev, "Failed to get remote mbus configuration\n"); + return ret; + } + + if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) { + dev_err(priv->dev, "Unsupported media bus type %u\n", + mbus_config.type); + return -EINVAL; + } + + if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE) + num_lanes = 1; + else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE) + num_lanes = 2; + else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE) + num_lanes = 3; + else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE) + num_lanes = 4; + + if (num_lanes > priv->lanes) { + dev_err(priv->dev, + "Unsupported mbus config: too many data lanes %u\n", + num_lanes); + return -EINVAL; + } + + *lanes = num_lanes; + + return 0; +} + static int rcsi2_start_receiver(struct rcar_csi2 *priv) { const struct rcar_csi2_format *format; u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0; + unsigned int lanes; unsigned int i; int mbps, ret; @@ -522,10 +576,18 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) fld |= FLD_FLD_NUM(1); } + /* + * Get the number of active data lanes inspecting the remote mbus + * configuration. + */ + ret = rcsi2_get_active_lanes(priv, &lanes); + if (ret) + return ret; + phycnt = PHYCNT_ENABLECLK; - phycnt |= (1 << priv->lanes) - 1; + phycnt |= (1 << lanes) - 1; - mbps = rcsi2_calc_mbps(priv, format->bpp); + mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); if (mbps < 0) return mbps; @@ -572,7 +634,7 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv) rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); - ret = rcsi2_wait_phy_start(priv); + ret = rcsi2_wait_phy_start(priv, lanes); if (ret) return ret; @@ -749,6 +811,7 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, } priv->remote = subdev; + priv->remote_pad = pad; dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); @@ -811,6 +874,8 @@ static int rcsi2_parse_v4l2(struct rcar_csi2 *priv, static int rcsi2_parse_dt(struct rcar_csi2 *priv) { + struct v4l2_async_subdev *asd; + struct fwnode_handle *fwnode; struct device_node *ep; struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; int ret; @@ -834,24 +899,19 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv) return ret; } - priv->asd.match.fwnode = - fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep)); - priv->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - + fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep)); of_node_put(ep); - v4l2_async_notifier_init(&priv->notifier); - - ret = v4l2_async_notifier_add_subdev(&priv->notifier, &priv->asd); - if (ret) { - fwnode_handle_put(priv->asd.match.fwnode); - return ret; - } + dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode)); + v4l2_async_notifier_init(&priv->notifier); priv->notifier.ops = &rcar_csi2_notify_ops; - dev_dbg(priv->dev, "Found '%pOF'\n", - to_of_node(priv->asd.match.fwnode)); + asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, fwnode, + sizeof(*asd)); + fwnode_handle_put(fwnode); + if (IS_ERR(asd)) + return PTR_ERR(asd); ret = v4l2_async_subdev_notifier_register(&priv->subdev, &priv->notifier); @@ -1091,6 +1151,10 @@ static const struct of_device_id rcar_csi2_of_table[] = { .data = &rcar_csi2_info_r8a77990, }, { + .compatible = "renesas,r8a774e1-csi2", + .data = &rcar_csi2_info_r8a7795, + }, + { .compatible = "renesas,r8a7795-csi2", .data = &rcar_csi2_info_r8a7795, }, diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index a5dbb90c5210..692dea300b0d 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -125,6 +125,7 @@ #define VNDMR2_VPS (1 << 30) #define VNDMR2_HPS (1 << 29) #define VNDMR2_CES (1 << 28) +#define VNDMR2_YDS (1 << 22) #define VNDMR2_FTEV (1 << 17) #define VNDMR2_VLV(n) ((n & 0xf) << 12) @@ -598,8 +599,16 @@ void rvin_crop_scale_comp(struct rvin_dev *vin) /* For RAW8 format bpp is 1, but the hardware process RAW8 * format in 2 pixel unit hence configure VNIS_REG as stride / 2. */ - if (vin->format.pixelformat == V4L2_PIX_FMT_SRGGB8) + switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: stride /= 2; + break; + default: + break; + } rvin_write(vin, stride, VNIS_REG); } @@ -683,6 +692,9 @@ static int rvin_setup(struct rvin_dev *vin) input_is_yuv = true; break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: vnmc |= VNMC_INF_RAW8; break; @@ -698,16 +710,26 @@ static int rvin_setup(struct rvin_dev *vin) if (!vin->is_csi) { /* Hsync Signal Polarity Select */ - if (!(vin->parallel->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) + if (!(vin->parallel->bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_HPS; /* Vsync Signal Polarity Select */ - if (!(vin->parallel->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) + if (!(vin->parallel->bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_VPS; /* Data Enable Polarity Select */ - if (vin->parallel->mbus_flags & V4L2_MBUS_DATA_ENABLE_LOW) + if (vin->parallel->bus.flags & V4L2_MBUS_DATA_ENABLE_LOW) dmr2 |= VNDMR2_CES; + + switch (vin->mbus_code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + if (vin->parallel->bus.bus_width == 8 && + vin->parallel->bus.data_shift == 8) + dmr2 |= VNDMR2_YDS; + break; + default: + break; + } } /* @@ -747,6 +769,9 @@ static int rvin_setup(struct rvin_dev *vin) case V4L2_PIX_FMT_ABGR32: dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB; break; + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: dmr = 0; break; @@ -1124,6 +1149,18 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, case MEDIA_BUS_FMT_UYVY10_2X10: case MEDIA_BUS_FMT_RGB888_1X24: break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8) + return -EPIPE; + break; case MEDIA_BUS_FMT_SRGGB8_1X8: if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8) return -EPIPE; @@ -1409,8 +1446,10 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) int ret; ret = pm_runtime_get_sync(vin->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(vin->dev); return ret; + } /* Make register writes take effect immediately. */ vnmc = rvin_read(vin, VNMC_REG); diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 0e066bba747e..3e7a3ae2a6b9 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -67,6 +67,18 @@ static const struct rvin_video_format rvin_formats[] = { .bpp = 4, }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .bpp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .bpp = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .bpp = 1, + }, + { .fourcc = V4L2_PIX_FMT_SRGGB8, .bpp = 1, }, @@ -366,6 +378,21 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, case MEDIA_BUS_FMT_UYVY10_2X10: case MEDIA_BUS_FMT_RGB888_1X24: break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SBGGR8; + return 0; + case MEDIA_BUS_FMT_SGBRG8_1X8: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SGBRG8; + return 0; + case MEDIA_BUS_FMT_SGRBG8_1X8: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SGRBG8; + return 0; case MEDIA_BUS_FMT_SRGGB8_1X8: if (f->index) return -EINVAL; @@ -844,8 +871,10 @@ static int rvin_open(struct file *file) int ret; ret = pm_runtime_get_sync(vin->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(vin->dev); return ret; + } ret = mutex_lock_interruptible(&vin->lock); if (ret) diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index c19d077ce1cb..8396e0e45478 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -19,6 +19,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> #include <media/videobuf2-v4l2.h> /* Number of HW buffers */ @@ -92,7 +93,7 @@ struct rvin_video_format { * @asd: sub-device descriptor for async framework * @subdev: subdevice matched using async framework * @mbus_type: media bus type - * @mbus_flags: media bus configuration flags + * @bus: media bus parallel configuration * @source_pad: source pad of remote subdevice * @sink_pad: sink pad of remote subdevice * @@ -102,7 +103,7 @@ struct rvin_parallel_entity { struct v4l2_subdev *subdev; enum v4l2_mbus_type mbus_type; - unsigned int mbus_flags; + struct v4l2_fwnode_bus_parallel bus; unsigned int source_pad; unsigned int sink_pad; diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 3d2451ac347d..f318cd4b8086 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -185,7 +185,6 @@ struct rcar_drif_frame_buf { /* OF graph endpoint's V4L2 async data */ struct rcar_drif_graph_ep { struct v4l2_subdev *subdev; /* Async matched subdev */ - struct v4l2_async_subdev asd; /* Async sub-device descriptor */ }; /* DMA buffer */ @@ -1109,12 +1108,6 @@ static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier, struct rcar_drif_sdr *sdr = container_of(notifier, struct rcar_drif_sdr, notifier); - if (sdr->ep.asd.match.fwnode != - of_fwnode_handle(subdev->dev->of_node)) { - rdrif_err(sdr, "subdev %s cannot bind\n", subdev->name); - return -EINVAL; - } - v4l2_set_subdev_hostdata(subdev, sdr); sdr->ep.subdev = subdev; rdrif_dbg(sdr, "bound asd %s\n", subdev->name); @@ -1218,7 +1211,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr) { struct v4l2_async_notifier *notifier = &sdr->notifier; struct fwnode_handle *fwnode, *ep; - int ret; + struct v4l2_async_subdev *asd; v4l2_async_notifier_init(notifier); @@ -1227,26 +1220,21 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr) if (!ep) return 0; + /* Get the endpoint properties */ + rcar_drif_get_ep_properties(sdr, ep); + fwnode = fwnode_graph_get_remote_port_parent(ep); + fwnode_handle_put(ep); if (!fwnode) { dev_warn(sdr->dev, "bad remote port parent\n"); - fwnode_handle_put(ep); return -EINVAL; } - sdr->ep.asd.match.fwnode = fwnode; - sdr->ep.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - ret = v4l2_async_notifier_add_subdev(notifier, &sdr->ep.asd); - if (ret) { - fwnode_handle_put(fwnode); - return ret; - } - - /* Get the endpoint properties */ - rcar_drif_get_ep_properties(sdr, ep); - + asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode, + sizeof(*asd)); fwnode_handle_put(fwnode); - fwnode_handle_put(ep); + if (IS_ERR(asd)) + return PTR_ERR(asd); return 0; } diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index f7d71a6a7970..4a633ad0e8fa 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -405,7 +405,7 @@ static int ceu_hw_config(struct ceu_device *ceudev) /* Non-swapped planar image capture mode. */ case V4L2_PIX_FMT_NV16: cdocr |= CEU_CDOCR_NO_DOWSAMPLE; - /* fall-through */ + fallthrough; case V4L2_PIX_FMT_NV12: if (mbus_fmt->swapped) camcr = mbus_fmt->fmt_order_swap; @@ -419,7 +419,7 @@ static int ceu_hw_config(struct ceu_device *ceudev) /* Swapped planar image capture mode. */ case V4L2_PIX_FMT_NV61: cdocr |= CEU_CDOCR_NO_DOWSAMPLE; - /* fall-through */ + fallthrough; case V4L2_PIX_FMT_NV21: if (mbus_fmt->swapped) camcr = mbus_fmt->fmt_order; diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index 36b821ccc1db..bf9a75b75083 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -81,6 +81,7 @@ static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count) ret = pm_runtime_get_sync(rga->dev); if (ret < 0) { + pm_runtime_put_noidle(rga->dev); rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED); return ret; } diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index 92f43c0cbc0c..422fd549e9c8 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -464,7 +464,7 @@ static int s3c_camif_probe(struct platform_device *pdev) ret = camif_media_dev_init(camif); if (ret < 0) - goto err_alloc; + goto err_pm; ret = camif_register_sensor(camif); if (ret < 0) @@ -498,10 +498,9 @@ err_sens: media_device_unregister(&camif->media_dev); media_device_cleanup(&camif->media_dev); camif_unregister_media_entities(camif); -err_alloc: +err_pm: pm_runtime_put(dev); pm_runtime_disable(dev); -err_pm: camif_clk_put(camif); err_clk: s3c_camif_unregister_subdev(camif); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 912fe0c5ab18..acc2217dd7e9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -262,6 +262,12 @@ static struct mfc_control controls[] = { .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED, }, { + .id = V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .maximum = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .default_value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + }, + { .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Fixed Target Bit Enable", @@ -1849,6 +1855,7 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) p->seq_hdr_mode = ctrl->val; break; case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: p->frame_skip_mode = ctrl->val; break; case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 7d52431c2c83..62d2320a7218 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -79,8 +79,10 @@ int s5p_mfc_power_on(void) int i, ret = 0; ret = pm_runtime_get_sync(pm->device); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(pm->device); return ret; + } /* clock control */ for (i = 0; i < pm->num_clocks; i++) { diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c index 77ca7517fa3e..2b270093009c 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-debug.c +++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c @@ -637,35 +637,18 @@ DEFINE_SHOW_ATTRIBUTE(last_nodes_raw); DEFINE_SHOW_ATTRIBUTE(last_request); DEFINE_SHOW_ATTRIBUTE(perf); -int bdisp_debugfs_create(struct bdisp_dev *bdisp) +void bdisp_debugfs_create(struct bdisp_dev *bdisp) { char dirname[16]; snprintf(dirname, sizeof(dirname), "%s%d", BDISP_NAME, bdisp->id); bdisp->dbg.debugfs_entry = debugfs_create_dir(dirname, NULL); - if (!bdisp->dbg.debugfs_entry) - goto err; - if (!bdisp_dbg_create_entry(regs)) - goto err; - - if (!bdisp_dbg_create_entry(last_nodes)) - goto err; - - if (!bdisp_dbg_create_entry(last_nodes_raw)) - goto err; - - if (!bdisp_dbg_create_entry(last_request)) - goto err; - - if (!bdisp_dbg_create_entry(perf)) - goto err; - - return 0; - -err: - bdisp_debugfs_remove(bdisp); - return -ENOMEM; + bdisp_dbg_create_entry(regs); + bdisp_dbg_create_entry(last_nodes); + bdisp_dbg_create_entry(last_nodes_raw); + bdisp_dbg_create_entry(last_request); + bdisp_dbg_create_entry(perf); } void bdisp_debugfs_remove(struct bdisp_dev *bdisp) diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index af2d5eb782ce..060ca85f64d5 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -1360,18 +1360,14 @@ static int bdisp_probe(struct platform_device *pdev) } /* Debug */ - ret = bdisp_debugfs_create(bdisp); - if (ret) { - dev_err(dev, "failed to create debugfs\n"); - goto err_v4l2; - } + bdisp_debugfs_create(bdisp); /* Power management */ pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); if (ret < 0) { dev_err(dev, "failed to set PM\n"); - goto err_dbg; + goto err_pm; } /* Filters */ @@ -1399,9 +1395,7 @@ err_filter: bdisp_hw_free_filters(bdisp->dev); err_pm: pm_runtime_put(dev); -err_dbg: bdisp_debugfs_remove(bdisp); -err_v4l2: v4l2_device_unregister(&bdisp->v4l2_dev); err_clk: if (!IS_ERR(bdisp->clock)) diff --git a/drivers/media/platform/sti/bdisp/bdisp.h b/drivers/media/platform/sti/bdisp/bdisp.h index e309cde379ca..3fb009d24791 100644 --- a/drivers/media/platform/sti/bdisp/bdisp.h +++ b/drivers/media/platform/sti/bdisp/bdisp.h @@ -209,6 +209,6 @@ int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp); int bdisp_hw_update(struct bdisp_ctx *ctx); void bdisp_debugfs_remove(struct bdisp_dev *bdisp); -int bdisp_debugfs_create(struct bdisp_dev *bdisp); +void bdisp_debugfs_create(struct bdisp_dev *bdisp); void bdisp_dbg_perf_begin(struct bdisp_dev *bdisp); void bdisp_dbg_perf_end(struct bdisp_dev *bdisp); diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 5baada4f65e5..dbe7788083a4 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -77,9 +77,9 @@ static void c8sectpfe_timer_interrupt(struct timer_list *t) add_timer(&fei->timer); } -static void channel_swdemux_tsklet(unsigned long data) +static void channel_swdemux_tsklet(struct tasklet_struct *t) { - struct channel_info *channel = (struct channel_info *)data; + struct channel_info *channel = from_tasklet(channel, t, tsklet); struct c8sectpfei *fei; unsigned long wp, rp; int pos, num_packets, n, size; @@ -208,8 +208,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) dev_dbg(fei->dev, "Starting channel=%p\n", channel); - tasklet_init(&channel->tsklet, channel_swdemux_tsklet, - (unsigned long) channel); + tasklet_setup(&channel->tsklet, channel_swdemux_tsklet); /* Reset the internal inputblock sram pointers */ writel(channel->fifo, @@ -638,8 +637,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSRP_TP(0)); /* initialize tasklet */ - tasklet_init(&tsin->tsklet, channel_swdemux_tsklet, - (unsigned long) tsin); + tasklet_setup(&tsin->tsklet, channel_swdemux_tsklet); return 0; diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c index 2503224eeee5..c691b3d81549 100644 --- a/drivers/media/platform/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/sti/delta/delta-v4l2.c @@ -954,8 +954,10 @@ static void delta_run_work(struct work_struct *work) /* enable the hardware */ if (!dec->pm) { ret = delta_get_sync(ctx); - if (ret) + if (ret) { + delta_put_autosuspend(ctx); goto err; + } } /* decode this access unit */ diff --git a/drivers/media/platform/sti/hva/hva-debugfs.c b/drivers/media/platform/sti/hva/hva-debugfs.c index 7d12a5b5d914..a86a07b6fbc7 100644 --- a/drivers/media/platform/sti/hva/hva-debugfs.c +++ b/drivers/media/platform/sti/hva/hva-debugfs.c @@ -337,25 +337,11 @@ DEFINE_SHOW_ATTRIBUTE(regs); void hva_debugfs_create(struct hva_dev *hva) { hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL); - if (!hva->dbg.debugfs_entry) - goto err; - if (!hva_dbg_create_entry(device)) - goto err; - - if (!hva_dbg_create_entry(encoders)) - goto err; - - if (!hva_dbg_create_entry(last)) - goto err; - - if (!hva_dbg_create_entry(regs)) - goto err; - - return; - -err: - hva_debugfs_remove(hva); + hva_dbg_create_entry(device); + hva_dbg_create_entry(encoders); + hva_dbg_create_entry(last); + hva_dbg_create_entry(regs); } void hva_debugfs_remove(struct hva_dev *hva) diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c index 401aaafa1710..43f279e2a6a3 100644 --- a/drivers/media/platform/sti/hva/hva-hw.c +++ b/drivers/media/platform/sti/hva/hva-hw.c @@ -272,6 +272,7 @@ static unsigned long int hva_hw_get_ip_version(struct hva_dev *hva) if (pm_runtime_get_sync(dev) < 0) { dev_err(dev, "%s failed to get pm_runtime\n", HVA_PREFIX); + pm_runtime_put_noidle(dev); mutex_unlock(&hva->protect_mutex); return -EFAULT; } @@ -388,7 +389,7 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) ret = pm_runtime_get_sync(dev); if (ret < 0) { dev_err(dev, "%s failed to set PM\n", HVA_PREFIX); - goto err_clk; + goto err_pm; } /* check IP hardware version */ @@ -553,6 +554,7 @@ void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s) if (pm_runtime_get_sync(dev) < 0) { seq_puts(s, "Cannot wake up IP\n"); + pm_runtime_put_noidle(dev); mutex_unlock(&hva->protect_mutex); return; } diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index b8931490b83b..fd1c41cba52f 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -733,7 +733,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret < 0) { dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n", __func__, ret); - goto err_release_buffers; + goto err_pm_put; } ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); @@ -837,8 +837,6 @@ err_media_pipeline_stop: err_pm_put: pm_runtime_put(dcmi->dev); - -err_release_buffers: spin_lock_irq(&dcmi->irqlock); /* * Return all buffers to vb2 in QUEUED state. diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index 5319eb1ab309..d226ecadff8e 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -287,6 +287,7 @@ static int sun4i_csi_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&csi->notifier); v4l2_async_notifier_cleanup(&csi->notifier); + vb2_video_unregister_device(&csi->vdev); media_device_unregister(&csi->mdev); sun4i_csi_dma_unregister(csi); media_device_cleanup(&csi->mdev); diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index 3278746246aa..2c39cd7f2862 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -431,7 +431,7 @@ int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq) ret = v4l2_device_register(csi->dev, &csi->v4l); if (ret) { dev_err(csi->dev, "Couldn't register the v4l2 device\n"); - goto err_free_queue; + goto err_free_mutex; } ret = devm_request_irq(csi->dev, irq, sun4i_csi_irq, 0, @@ -446,9 +446,6 @@ int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq) err_unregister_device: v4l2_device_unregister(&csi->v4l); -err_free_queue: - vb2_queue_release(q); - err_free_mutex: mutex_destroy(&csi->lock); return ret; @@ -457,6 +454,5 @@ err_free_mutex: void sun4i_csi_dma_unregister(struct sun4i_csi *csi) { v4l2_device_unregister(&csi->v4l); - vb2_queue_release(&csi->queue); mutex_destroy(&csi->lock); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index d9648b2810b9..b55de9ab64d8 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -660,13 +660,11 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, if (ret < 0) { v4l2_err(&csi->v4l2_dev, "video_register_device failed: %d\n", ret); - goto release_vb2; + goto clean_entity; } return 0; -release_vb2: - vb2_queue_release(&video->vb2_vidq); clean_entity: media_entity_cleanup(&video->vdev.entity); mutex_destroy(&video->lock); @@ -675,8 +673,7 @@ clean_entity: void sun6i_video_cleanup(struct sun6i_video *video) { - video_unregister_device(&video->vdev); + vb2_video_unregister_device(&video->vdev); media_entity_cleanup(&video->vdev.entity); - vb2_queue_release(&video->vb2_vidq); mutex_destroy(&video->lock); } diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index 94f505d3cbad..3f81dd17755c 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -747,11 +747,8 @@ static int rotate_probe(struct platform_device *pdev) dev->dev = &pdev->dev; irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(dev->dev, "Failed to get IRQ\n"); - + if (irq <= 0) return irq; - } ret = devm_request_irq(dev->dev, irq, rotate_irq, 0, dev_name(dev->dev), dev); diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 346f8212791c..779dd74b82d0 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2475,6 +2475,8 @@ static int vpe_runtime_get(struct platform_device *pdev) r = pm_runtime_get_sync(&pdev->dev); WARN_ON(r < 0); + if (r) + pm_runtime_put_noidle(&pdev->dev); return r < 0 ? r : 0; } diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index c650e45bb0ad..dc62533cf32c 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -562,7 +562,12 @@ int vsp1_device_get(struct vsp1_device *vsp1) int ret; ret = pm_runtime_get_sync(vsp1->dev); - return ret < 0 ? ret : 0; + if (ret < 0) { + pm_runtime_put_noidle(vsp1->dev); + return ret; + } + + return 0; } /* @@ -845,12 +850,12 @@ static int vsp1_probe(struct platform_device *pdev) /* Configure device parameters based on the version register. */ pm_runtime_enable(&pdev->dev); - ret = pm_runtime_get_sync(&pdev->dev); + ret = vsp1_device_get(vsp1); if (ret < 0) goto done; vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION); - pm_runtime_put_sync(&pdev->dev); + vsp1_device_put(vsp1); for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) == |