diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-03 19:29:28 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-03 19:29:28 -0700 |
commit | 12b68040a5e468068fd7f4af1150eab8f6e96235 (patch) | |
tree | 02b059a281615f4592a2d197c02a67ca110444fa /drivers | |
parent | 80dc75932ff231b05e0adbf5054bf4c9f0fb468c (diff) | |
parent | 485ade76c95ac5ccaa52fee9d712471c9211b989 (diff) | |
download | linux-12b68040a5e468068fd7f4af1150eab8f6e96235.tar.bz2 |
Merge tag 'media/v5.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- New driver for Semi AR0521 sensor
- rkisp1 CSI code was split into a separate file
- sun6i has gained support for the A31 MIPI CSI-2 controller
- sun8i has gained support for the A83T MIPI CSI-2 controller
- vimc driver got support for virtual lens
- HEVC uAPI has gained its final form and got added to public headers
- hantro and cedrus got updates on H-265 support
- stkwebcam was promoted from staging
- atomisp staging driver got cleanups on its hmm and kmap related logic
- ov5640 gained support for more modes and got some rework
- imx7-media-csi staging driver got several improvements related to mc
API support
- uvcvideo now handles better power line control
- mediatec vcodec gained support for new hardware and got some codec
updates
- Lots of other bug fixes, improvements and cleanups.
* tag 'media/v5.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (446 commits)
media: hantro: Remove dedicated control documentation
hantro: Remove incorrect HEVC SPS validation
media: cedrus: hevc: Add check for invalid timestamp
media: sunxi: sun6i_mipi_csi2.c/sun8i_a83t_mipi_csi2.c: clarify error handling
media: uvcvideo: Fix invalid pointer in uvc_ctrl_init_ctrl()
media: Documentation: mc-core: Fix typo
media: videodev2.h.rst.exceptions: add missing exceptions
media: vimc: wrong pointer is used with PTR_ERR
media: rkisp1: debug: Add dump file in debugfs for MI main path registers
media: rkisp1: Make the internal CSI-2 receiver optional
media: rkisp1: Add infrastructure to support ISP features
media: rkisp1: Support the ISP parallel input
media: dt-bindings: media: rkisp1: Add port for parallel interface
media: rkisp1: Use fwnode_graph_for_each_endpoint
media: rkisp1: csi: Plumb the CSI RX subdev
media: rkisp1: csi: Implement a V4L2 subdev for the CSI receiver
media: rkisp1: isp: Disallow multiple active sources
media: rkisp1: isp: Rename rkisp1_get_remote_source()
media: rkisp1: isp: Constify various local variables
media: rkisp1: isp: Fix whitespace issues
...
Diffstat (limited to 'drivers')
313 files changed, 12087 insertions, 7200 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index 8bf91b5a7d0e..41a79293ee02 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -1309,8 +1309,11 @@ static int cec_config_log_addr(struct cec_adapter *adap, * we assume that something is really weird and that it is not a * good idea to try and claim this logical address. */ - if (i == max_retries) + if (i == max_retries) { + dprintk(0, "polling for LA %u failed with tx_status=0x%04x\n", + log_addr, msg.tx_status); return 0; + } /* * Message not acknowledged, so this logical diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 8c8d8fc5e63e..3b583ed4da9d 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -217,6 +217,10 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Fizz", "0000:00:02.0", "Port B" }, /* Google Brask */ { "Google", "Brask", "0000:00:02.0", "Port B" }, + /* Google Moli */ + { "Google", "Moli", "0000:00:02.0", "Port B" }, + /* Google Kinox */ + { "Google", "Kinox", "0000:00:02.0", "Port B" }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 7607b516a7c4..9b7bcdce6e44 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -266,6 +266,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XYUV32: case V4L2_PIX_FMT_VUYA32: case V4L2_PIX_FMT_VUYX32: + case V4L2_PIX_FMT_YUVA32: + case V4L2_PIX_FMT_YUVX32: tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV420M: @@ -412,6 +414,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XYUV32: case V4L2_PIX_FMT_VUYA32: case V4L2_PIX_FMT_VUYX32: + case V4L2_PIX_FMT_YUVA32: + case V4L2_PIX_FMT_YUVX32: case V4L2_PIX_FMT_HSV32: tpg->twopixelsize[0] = 2 * 4; break; @@ -1376,9 +1380,11 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 3] = b_v; break; case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_YUVX32: alpha = 0; fallthrough; case V4L2_PIX_FMT_RGBA32: + case V4L2_PIX_FMT_YUVA32: buf[0][offset] = r_y_h; buf[0][offset + 1] = g_u_s; buf[0][offset + 2] = b_v; @@ -2402,6 +2408,44 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg, ((params->sav_eav_f ^ vact) << 1) | (hact ^ vact ^ params->sav_eav_f); } + if (tpg->insert_hdmi_video_guard_band) { + unsigned int i; + + switch (tpg->fourcc) { + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB24: + for (i = 0; i < 3 * 4; i += 3) { + vbuf[i] = 0xab; + vbuf[i + 1] = 0x55; + vbuf[i + 2] = 0xab; + } + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_BGRA32: + for (i = 0; i < 4 * 4; i += 4) { + vbuf[i] = 0x00; + vbuf[i + 1] = 0xab; + vbuf[i + 2] = 0x55; + vbuf[i + 3] = 0xab; + } + break; + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_RGBA32: + for (i = 0; i < 4 * 4; i += 4) { + vbuf[i] = 0xab; + vbuf[i + 1] = 0x55; + vbuf[i + 2] = 0xab; + vbuf[i + 3] = 0x00; + } + break; + } + } } static void tpg_fill_plane_pattern(const struct tpg_data *tpg, diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 075d24ebf44c..f26cb8586bd4 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -638,6 +638,18 @@ int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp, } EXPORT_SYMBOL_GPL(vb2_find_timestamp); +struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp) +{ + unsigned int i; + + for (i = 0; i < q->num_buffers; i++) + if (q->bufs[i]->copied_timestamp && + q->bufs[i]->timestamp == timestamp) + return vb2_get_buffer(q, i); + return NULL; +} +EXPORT_SYMBOL_GPL(vb2_find_buffer); + /* * vb2_querybuf() - query video buffer information * @q: videobuf queue diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 2b20aa6c37b1..7806d4b81716 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -34,6 +34,19 @@ config VIDEO_APTINA_PLL config VIDEO_CCS_PLL tristate +config VIDEO_AR0521 + tristate "ON Semiconductor AR0521 sensor support" + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the ON Semiconductor + AR0521 camera. + + To compile this driver as a module, choose M here: the + module will be called ar0521. + config VIDEO_HI556 tristate "Hynix Hi-556 sensor support" depends on I2C && VIDEO_DEV @@ -75,8 +88,10 @@ config VIDEO_HI847 config VIDEO_IMX208 tristate "Sony IMX208 sensor support" - depends on I2C && VIDEO_DEV && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_DEV depends on MEDIA_CAMERA_SUPPORT + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a Video4Linux2 sensor driver for the Sony IMX208 camera. @@ -1178,6 +1193,7 @@ config VIDEO_ISL7998X depends on OF_GPIO select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE help Support for Intersil ISL7998x analog to MIPI-CSI2 or BT.656 decoder. diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 3e1696963e7f..0a2933103dd9 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o obj-$(CONFIG_VIDEO_AK7375) += ak7375.o obj-$(CONFIG_VIDEO_AK881X) += ak881x.o obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o +obj-$(CONFIG_VIDEO_AR0521) += ar0521.o obj-$(CONFIG_VIDEO_BT819) += bt819.o obj-$(CONFIG_VIDEO_BT856) += bt856.o obj-$(CONFIG_VIDEO_BT866) += bt866.o diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index e3a57c178c6b..5fde5243722d 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -43,6 +43,7 @@ #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f #define ADV7182_REG_INPUT_VIDSEL 0x0002 +#define ADV7182_REG_INPUT_RESERVED BIT(2) #define ADV7180_REG_OUTPUT_CONTROL 0x0003 #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 @@ -1060,7 +1061,9 @@ static int adv7182_init(struct adv7180_state *state) static int adv7182_set_std(struct adv7180_state *state, unsigned int std) { - return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4); + /* Failing to set the reserved bit can result in increased video noise */ + return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, + (std << 4) | ADV7182_REG_INPUT_RESERVED); } enum adv7182_input_type { diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 31bac06d46b5..d75eb3d8be5a 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -417,7 +417,7 @@ int adv748x_write_block(struct adv748x_state *state, int client_page, static inline struct v4l2_subdev *adv748x_get_remote_sd(struct media_pad *pad) { - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad) return NULL; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index bb0c8fc6d383..497419a5cfdd 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2505,9 +2505,8 @@ static void adv76xx_log_infoframes(struct v4l2_subdev *sd) union hdmi_infoframe frame; struct i2c_client *client = v4l2_get_subdevdata(sd); - if (adv76xx_read_infoframe(sd, i, &frame)) - return; - hdmi_infoframe_log(KERN_INFO, &client->dev, &frame); + if (!adv76xx_read_infoframe(sd, i, &frame)) + hdmi_infoframe_log(KERN_INFO, &client->dev, &frame); } } diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c new file mode 100644 index 000000000000..c7bdfc69b9be --- /dev/null +++ b/drivers/media/i2c/ar0521.c @@ -0,0 +1,1061 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Sieć Badawcza Łukasiewicz + * - Przemysłowy Instytut Automatyki i Pomiarów PIAP + * Written by Krzysztof Hałasa + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +/* External clock (extclk) frequencies */ +#define AR0521_EXTCLK_MIN (10 * 1000 * 1000) +#define AR0521_EXTCLK_MAX (48 * 1000 * 1000) + +/* PLL and PLL2 */ +#define AR0521_PLL_MIN (320 * 1000 * 1000) +#define AR0521_PLL_MAX (1280 * 1000 * 1000) + +/* Effective pixel clocks, the registers may be DDR */ +#define AR0521_PIXEL_CLOCK_RATE (184 * 1000 * 1000) +#define AR0521_PIXEL_CLOCK_MIN (168 * 1000 * 1000) +#define AR0521_PIXEL_CLOCK_MAX (414 * 1000 * 1000) + +#define AR0521_WIDTH_MIN 8u +#define AR0521_WIDTH_MAX 2608u +#define AR0521_HEIGHT_MIN 8u +#define AR0521_HEIGHT_MAX 1958u + +#define AR0521_WIDTH_BLANKING_MIN 572u +#define AR0521_HEIGHT_BLANKING_MIN 38u /* must be even */ +#define AR0521_TOTAL_WIDTH_MIN 2968u + +/* AR0521 registers */ +#define AR0521_REG_VT_PIX_CLK_DIV 0x0300 +#define AR0521_REG_FRAME_LENGTH_LINES 0x0340 + +#define AR0521_REG_CHIP_ID 0x3000 +#define AR0521_REG_COARSE_INTEGRATION_TIME 0x3012 +#define AR0521_REG_ROW_SPEED 0x3016 +#define AR0521_REG_EXTRA_DELAY 0x3018 +#define AR0521_REG_RESET 0x301A +#define AR0521_REG_RESET_DEFAULTS 0x0238 +#define AR0521_REG_RESET_GROUP_PARAM_HOLD 0x8000 +#define AR0521_REG_RESET_STREAM BIT(2) +#define AR0521_REG_RESET_RESTART BIT(1) +#define AR0521_REG_RESET_INIT BIT(0) + +#define AR0521_REG_GREEN1_GAIN 0x3056 +#define AR0521_REG_BLUE_GAIN 0x3058 +#define AR0521_REG_RED_GAIN 0x305A +#define AR0521_REG_GREEN2_GAIN 0x305C +#define AR0521_REG_GLOBAL_GAIN 0x305E + +#define AR0521_REG_HISPI_TEST_MODE 0x3066 +#define AR0521_REG_HISPI_TEST_MODE_LP11 0x0004 + +#define AR0521_REG_TEST_PATTERN_MODE 0x3070 + +#define AR0521_REG_SERIAL_FORMAT 0x31AE +#define AR0521_REG_SERIAL_FORMAT_MIPI 0x0200 + +#define AR0521_REG_HISPI_CONTROL_STATUS 0x31C6 +#define AR0521_REG_HISPI_CONTROL_STATUS_FRAMER_TEST_MODE_ENABLE 0x80 + +#define be cpu_to_be16 + +static const char * const ar0521_supply_names[] = { + "vdd_io", /* I/O (1.8V) supply */ + "vdd", /* Core, PLL and MIPI (1.2V) supply */ + "vaa", /* Analog (2.7V) supply */ +}; + +struct ar0521_ctrls { + struct v4l2_ctrl_handler handler; + struct { + struct v4l2_ctrl *gain; + struct v4l2_ctrl *red_balance; + struct v4l2_ctrl *blue_balance; + }; + struct { + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + }; + struct v4l2_ctrl *pixrate; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *test_pattern; +}; + +struct ar0521_dev { + struct i2c_client *i2c_client; + struct v4l2_subdev sd; + struct media_pad pad; + struct clk *extclk; + u32 extclk_freq; + + struct regulator *supplies[ARRAY_SIZE(ar0521_supply_names)]; + struct gpio_desc *reset_gpio; + + /* lock to protect all members below */ + struct mutex lock; + + struct v4l2_mbus_framefmt fmt; + struct ar0521_ctrls ctrls; + unsigned int lane_count; + u16 total_width; + u16 total_height; + u16 pll_pre; + u16 pll_mult; + u16 pll_pre2; + u16 pll_mult2; + bool streaming; +}; + +static inline struct ar0521_dev *to_ar0521_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ar0521_dev, sd); +} + +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct ar0521_dev, + ctrls.handler)->sd; +} + +static u32 div64_round(u64 v, u32 d) +{ + return div_u64(v + (d >> 1), d); +} + +static u32 div64_round_up(u64 v, u32 d) +{ + return div_u64(v + d - 1, d); +} + +/* Data must be BE16, the first value is the register address */ +static int ar0521_write_regs(struct ar0521_dev *sensor, const __be16 *data, + unsigned int count) +{ + struct i2c_client *client = sensor->i2c_client; + struct i2c_msg msg; + int ret; + + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = (u8 *)data; + msg.len = count * sizeof(*data); + + ret = i2c_transfer(client->adapter, &msg, 1); + + if (ret < 0) { + v4l2_err(&sensor->sd, "%s: I2C write error\n", __func__); + return ret; + } + + return 0; +} + +static int ar0521_write_reg(struct ar0521_dev *sensor, u16 reg, u16 val) +{ + __be16 buf[2] = {be(reg), be(val)}; + + return ar0521_write_regs(sensor, buf, 2); +} + +static int ar0521_set_geometry(struct ar0521_dev *sensor) +{ + /* All dimensions are unsigned 12-bit integers */ + u16 x = (AR0521_WIDTH_MAX - sensor->fmt.width) / 2; + u16 y = ((AR0521_HEIGHT_MAX - sensor->fmt.height) / 2) & ~1; + __be16 regs[] = { + be(AR0521_REG_FRAME_LENGTH_LINES), + be(sensor->total_height), + be(sensor->total_width), + be(x), + be(y), + be(x + sensor->fmt.width - 1), + be(y + sensor->fmt.height - 1), + be(sensor->fmt.width), + be(sensor->fmt.height) + }; + + return ar0521_write_regs(sensor, regs, ARRAY_SIZE(regs)); +} + +static int ar0521_set_gains(struct ar0521_dev *sensor) +{ + int green = sensor->ctrls.gain->val; + int red = max(green + sensor->ctrls.red_balance->val, 0); + int blue = max(green + sensor->ctrls.blue_balance->val, 0); + unsigned int gain = min(red, min(green, blue)); + unsigned int analog = min(gain, 64u); /* range is 0 - 127 */ + __be16 regs[5]; + + red = min(red - analog + 64, 511u); + green = min(green - analog + 64, 511u); + blue = min(blue - analog + 64, 511u); + regs[0] = be(AR0521_REG_GREEN1_GAIN); + regs[1] = be(green << 7 | analog); + regs[2] = be(blue << 7 | analog); + regs[3] = be(red << 7 | analog); + regs[4] = be(green << 7 | analog); + + return ar0521_write_regs(sensor, regs, ARRAY_SIZE(regs)); +} + +static u32 calc_pll(struct ar0521_dev *sensor, int num, u32 freq, u16 *pre_ptr, + u16 *mult_ptr) +{ + u16 pre = 1, mult = 1, new_pre; + u32 pll = AR0521_PLL_MAX + 1; + + for (new_pre = 1; new_pre < 64; new_pre++) { + u32 new_pll; + u32 new_mult = div64_round_up((u64)freq * new_pre, + sensor->extclk_freq); + + if (new_mult < 32) + continue; /* Minimum value */ + if (new_mult > 254) + break; /* Maximum, larger pre won't work either */ + if (sensor->extclk_freq * (u64)new_mult < AR0521_PLL_MIN * + new_pre) + continue; + if (sensor->extclk_freq * (u64)new_mult > AR0521_PLL_MAX * + new_pre) + break; /* Larger pre won't work either */ + new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult, + new_pre); + if (new_pll < pll) { + pll = new_pll; + pre = new_pre; + mult = new_mult; + } + } + + pll = div64_round(sensor->extclk_freq * (u64)mult, pre); + *pre_ptr = pre; + *mult_ptr = mult; + return pll; +} + +#define DIV 4 +static void ar0521_calc_mode(struct ar0521_dev *sensor) +{ + unsigned int speed_mod = 4 / sensor->lane_count; /* 1 with 4 DDR lanes */ + u16 total_width = max(sensor->fmt.width + AR0521_WIDTH_BLANKING_MIN, + AR0521_TOTAL_WIDTH_MIN); + u16 total_height = sensor->fmt.height + AR0521_HEIGHT_BLANKING_MIN; + + /* Calculate approximate pixel clock first */ + u64 pix_clk = AR0521_PIXEL_CLOCK_RATE; + + /* PLL1 drives pixel clock - dual rate */ + pix_clk = calc_pll(sensor, 1, pix_clk * (DIV / 2), &sensor->pll_pre, + &sensor->pll_mult); + pix_clk = div64_round(pix_clk, (DIV / 2)); + calc_pll(sensor, 2, pix_clk * (DIV / 2) * speed_mod, &sensor->pll_pre2, + &sensor->pll_mult2); + + sensor->total_width = total_width; + sensor->total_height = total_height; +} + +static int ar0521_write_mode(struct ar0521_dev *sensor) +{ + __be16 pll_regs[] = { + be(AR0521_REG_VT_PIX_CLK_DIV), + /* 0x300 */ be(4), /* vt_pix_clk_div = number of bits / 2 */ + /* 0x302 */ be(1), /* vt_sys_clk_div */ + /* 0x304 */ be((sensor->pll_pre2 << 8) | sensor->pll_pre), + /* 0x306 */ be((sensor->pll_mult2 << 8) | sensor->pll_mult), + /* 0x308 */ be(8), /* op_pix_clk_div = 2 * vt_pix_clk_div */ + /* 0x30A */ be(1) /* op_sys_clk_div */ + }; + int ret; + + /* Stop streaming for just a moment */ + ret = ar0521_write_reg(sensor, AR0521_REG_RESET, + AR0521_REG_RESET_DEFAULTS); + if (ret) + return ret; + + ret = ar0521_set_geometry(sensor); + if (ret) + return ret; + + ret = ar0521_write_regs(sensor, pll_regs, ARRAY_SIZE(pll_regs)); + if (ret) + return ret; + + ret = ar0521_write_reg(sensor, AR0521_REG_COARSE_INTEGRATION_TIME, + sensor->ctrls.exposure->val); + if (ret) + return ret; + + ret = ar0521_write_reg(sensor, AR0521_REG_RESET, + AR0521_REG_RESET_DEFAULTS | + AR0521_REG_RESET_STREAM); + if (ret) + return ret; + + ret = ar0521_write_reg(sensor, AR0521_REG_TEST_PATTERN_MODE, + sensor->ctrls.test_pattern->val); + return ret; +} + +static int ar0521_set_stream(struct ar0521_dev *sensor, bool on) +{ + int ret; + + if (on) { + ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev); + if (ret < 0) + return ret; + + ar0521_calc_mode(sensor); + ret = ar0521_write_mode(sensor); + if (ret) + goto err; + + ret = ar0521_set_gains(sensor); + if (ret) + goto err; + + /* Exit LP-11 mode on clock and data lanes */ + ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_CONTROL_STATUS, + 0); + if (ret) + goto err; + + /* Start streaming */ + ret = ar0521_write_reg(sensor, AR0521_REG_RESET, + AR0521_REG_RESET_DEFAULTS | + AR0521_REG_RESET_STREAM); + if (ret) + goto err; + + return 0; + +err: + pm_runtime_put(&sensor->i2c_client->dev); + return ret; + + } else { + /* + * Reset gain, the sensor may produce all white pixels without + * this + */ + ret = ar0521_write_reg(sensor, AR0521_REG_GLOBAL_GAIN, 0x2000); + if (ret) + return ret; + + /* Stop streaming */ + ret = ar0521_write_reg(sensor, AR0521_REG_RESET, + AR0521_REG_RESET_DEFAULTS); + if (ret) + return ret; + + pm_runtime_put(&sensor->i2c_client->dev); + return 0; + } +} + +static void ar0521_adj_fmt(struct v4l2_mbus_framefmt *fmt) +{ + fmt->width = clamp(ALIGN(fmt->width, 4), AR0521_WIDTH_MIN, + AR0521_WIDTH_MAX); + fmt->height = clamp(ALIGN(fmt->height, 4), AR0521_HEIGHT_MIN, + AR0521_HEIGHT_MAX); + fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int ar0521_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct ar0521_dev *sensor = to_ar0521_dev(sd); + struct v4l2_mbus_framefmt *fmt; + + mutex_lock(&sensor->lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 0 + /* pad */); + else + fmt = &sensor->fmt; + + format->format = *fmt; + + mutex_unlock(&sensor->lock); + return 0; +} + +static int ar0521_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct ar0521_dev *sensor = to_ar0521_dev(sd); + int ret = 0; + + ar0521_adj_fmt(&format->format); + + mutex_lock(&sensor->lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(sd, sd_state, 0 /* pad */); + *fmt = format->format; + } else { + sensor->fmt = format->format; + ar0521_calc_mode(sensor); + } + + mutex_unlock(&sensor->lock); + return ret; +} + +static int ar0521_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct ar0521_dev *sensor = to_ar0521_dev(sd); + int ret; + + /* v4l2_ctrl_lock() locks our own mutex */ + + switch (ctrl->id) { + case V4L2_CID_HBLANK: + case V4L2_CID_VBLANK: + sensor->total_width = sensor->fmt.width + + sensor->ctrls.hblank->val; + sensor->total_height = sensor->fmt.width + + sensor->ctrls.vblank->val; + break; + default: + ret = -EINVAL; + break; + } + + /* access the sensor only if it's powered up */ + if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_HBLANK: + case V4L2_CID_VBLANK: + ret = ar0521_set_geometry(sensor); + break; + case V4L2_CID_GAIN: + case V4L2_CID_RED_BALANCE: + case V4L2_CID_BLUE_BALANCE: + ret = ar0521_set_gains(sensor); + break; + case V4L2_CID_EXPOSURE: + ret = ar0521_write_reg(sensor, + AR0521_REG_COARSE_INTEGRATION_TIME, + ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = ar0521_write_reg(sensor, AR0521_REG_TEST_PATTERN_MODE, + ctrl->val); + break; + } + + pm_runtime_put(&sensor->i2c_client->dev); + return ret; +} + +static const struct v4l2_ctrl_ops ar0521_ctrl_ops = { + .s_ctrl = ar0521_s_ctrl, +}; + +static const char * const test_pattern_menu[] = { + "Disabled", + "Solid color", + "Color bars", + "Faded color bars" +}; + +static int ar0521_init_controls(struct ar0521_dev *sensor) +{ + const struct v4l2_ctrl_ops *ops = &ar0521_ctrl_ops; + struct ar0521_ctrls *ctrls = &sensor->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + int ret; + + v4l2_ctrl_handler_init(hdl, 32); + + /* We can use our own mutex for the ctrl lock */ + hdl->lock = &sensor->lock; + + /* Manual gain */ + ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 511, 1, 0); + ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, + -512, 511, 1, 0); + ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, + -512, 511, 1, 0); + v4l2_ctrl_cluster(3, &ctrls->gain); + + ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, + AR0521_WIDTH_BLANKING_MIN, 4094, 1, + AR0521_WIDTH_BLANKING_MIN); + ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, + AR0521_HEIGHT_BLANKING_MIN, 4094, 2, + AR0521_HEIGHT_BLANKING_MIN); + v4l2_ctrl_cluster(2, &ctrls->hblank); + + /* Read-only */ + ctrls->pixrate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, + AR0521_PIXEL_CLOCK_MIN, + AR0521_PIXEL_CLOCK_MAX, 1, + AR0521_PIXEL_CLOCK_RATE); + + /* Manual exposure time */ + ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0, + 65535, 1, 360); + + ctrls->test_pattern = v4l2_ctrl_new_std_menu_items(hdl, ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(test_pattern_menu) - 1, + 0, 0, test_pattern_menu); + + if (hdl->error) { + ret = hdl->error; + goto free_ctrls; + } + + sensor->sd.ctrl_handler = hdl; + return 0; + +free_ctrls: + v4l2_ctrl_handler_free(hdl); + return ret; +} + +#define REGS_ENTRY(a) {(a), ARRAY_SIZE(a)} +#define REGS(...) REGS_ENTRY(((const __be16[]){__VA_ARGS__})) + +static const struct initial_reg { + const __be16 *data; /* data[0] is register address */ + unsigned int count; +} initial_regs[] = { + REGS(be(0x0112), be(0x0808)), /* 8-bit/8-bit mode */ + + /* PEDESTAL+2 :+2 is a workaround for 10bit mode +0.5 rounding */ + REGS(be(0x301E), be(0x00AA)), + + /* corrections_recommended_bayer */ + REGS(be(0x3042), + be(0x0004), /* 3042: RNC: enable b/w rnc mode */ + be(0x4580)), /* 3044: RNC: enable row noise correction */ + + REGS(be(0x30D2), + be(0x0000), /* 30D2: CRM/CC: enable crm on Visible and CC rows */ + be(0x0000), /* 30D4: CC: CC enabled with 16 samples per column */ + /* 30D6: CC: bw mode enabled/12 bit data resolution/bw mode */ + be(0x2FFF)), + + REGS(be(0x30DA), + be(0x0FFF), /* 30DA: CC: column correction clip level 2 is 0 */ + be(0x0FFF), /* 30DC: CC: column correction clip level 3 is 0 */ + be(0x0000)), /* 30DE: CC: Group FPN correction */ + + /* RNC: rnc scaling factor = * 54 / 64 (32 / 38 * 64 = 53.9) */ + REGS(be(0x30EE), be(0x1136)), + REGS(be(0x30FA), be(0xFD00)), /* GPIO0 = flash, GPIO1 = shutter */ + REGS(be(0x3120), be(0x0005)), /* p1 dither enabled for 10bit mode */ + REGS(be(0x3172), be(0x0206)), /* txlo clk divider options */ + /* FDOC:fdoc settings with fdoc every frame turned of */ + REGS(be(0x3180), be(0x9434)), + + REGS(be(0x31B0), + be(0x008B), /* 31B0: frame_preamble - FIXME check WRT lanes# */ + be(0x0050)), /* 31B2: line_preamble - FIXME check WRT lanes# */ + + /* don't use continuous clock mode while shut down */ + REGS(be(0x31BC), be(0x068C)), + REGS(be(0x31E0), be(0x0781)), /* Fuse/2DDC: enable 2ddc */ + + /* analog_setup_recommended_10bit */ + REGS(be(0x341A), be(0x4735)), /* Samp&Hold pulse in ADC */ + REGS(be(0x3420), be(0x4735)), /* Samp&Hold pulse in ADC */ + REGS(be(0x3426), be(0x8A1A)), /* ADC offset distribution pulse */ + REGS(be(0x342A), be(0x0018)), /* pulse_config */ + + /* pixel_timing_recommended */ + REGS(be(0x3D00), + /* 3D00 */ be(0x043E), be(0x4760), be(0xFFFF), be(0xFFFF), + /* 3D08 */ be(0x8000), be(0x0510), be(0xAF08), be(0x0252), + /* 3D10 */ be(0x486F), be(0x5D5D), be(0x8056), be(0x8313), + /* 3D18 */ be(0x0087), be(0x6A48), be(0x6982), be(0x0280), + /* 3D20 */ be(0x8359), be(0x8D02), be(0x8020), be(0x4882), + /* 3D28 */ be(0x4269), be(0x6A95), be(0x5988), be(0x5A83), + /* 3D30 */ be(0x5885), be(0x6280), be(0x6289), be(0x6097), + /* 3D38 */ be(0x5782), be(0x605C), be(0xBF18), be(0x0961), + /* 3D40 */ be(0x5080), be(0x2090), be(0x4390), be(0x4382), + /* 3D48 */ be(0x5F8A), be(0x5D5D), be(0x9C63), be(0x8063), + /* 3D50 */ be(0xA960), be(0x9757), be(0x8260), be(0x5CFF), + /* 3D58 */ be(0xBF10), be(0x1681), be(0x0802), be(0x8000), + /* 3D60 */ be(0x141C), be(0x6000), be(0x6022), be(0x4D80), + /* 3D68 */ be(0x5C97), be(0x6A69), be(0xAC6F), be(0x4645), + /* 3D70 */ be(0x4400), be(0x0513), be(0x8069), be(0x6AC6), + /* 3D78 */ be(0x5F95), be(0x5F70), be(0x8040), be(0x4A81), + /* 3D80 */ be(0x0300), be(0xE703), be(0x0088), be(0x4A83), + /* 3D88 */ be(0x40FF), be(0xFFFF), be(0xFD70), be(0x8040), + /* 3D90 */ be(0x4A85), be(0x4FA8), be(0x4F8C), be(0x0070), + /* 3D98 */ be(0xBE47), be(0x8847), be(0xBC78), be(0x6B89), + /* 3DA0 */ be(0x6A80), be(0x6986), be(0x6B8E), be(0x6B80), + /* 3DA8 */ be(0x6980), be(0x6A88), be(0x7C9F), be(0x866B), + /* 3DB0 */ be(0x8765), be(0x46FF), be(0xE365), be(0xA679), + /* 3DB8 */ be(0x4A40), be(0x4580), be(0x44BC), be(0x7000), + /* 3DC0 */ be(0x8040), be(0x0802), be(0x10EF), be(0x0104), + /* 3DC8 */ be(0x3860), be(0x5D5D), be(0x5682), be(0x1300), + /* 3DD0 */ be(0x8648), be(0x8202), be(0x8082), be(0x598A), + /* 3DD8 */ be(0x0280), be(0x2048), be(0x3060), be(0x8042), + /* 3DE0 */ be(0x9259), be(0x865A), be(0x8258), be(0x8562), + /* 3DE8 */ be(0x8062), be(0x8560), be(0x9257), be(0x8221), + /* 3DF0 */ be(0x10FF), be(0xB757), be(0x9361), be(0x1019), + /* 3DF8 */ be(0x8020), be(0x9043), be(0x8E43), be(0x845F), + /* 3E00 */ be(0x835D), be(0x805D), be(0x8163), be(0x8063), + /* 3E08 */ be(0xA060), be(0x9157), be(0x8260), be(0x5CFF), + /* 3E10 */ be(0xFFFF), be(0xFFE5), be(0x1016), be(0x2048), + /* 3E18 */ be(0x0802), be(0x1C60), be(0x0014), be(0x0060), + /* 3E20 */ be(0x2205), be(0x8120), be(0x908F), be(0x6A80), + /* 3E28 */ be(0x6982), be(0x5F9F), be(0x6F46), be(0x4544), + /* 3E30 */ be(0x0005), be(0x8013), be(0x8069), be(0x6A80), + /* 3E38 */ be(0x7000), be(0x0000), be(0x0000), be(0x0000), + /* 3E40 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E48 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E50 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E58 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E60 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E68 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E70 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E78 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E80 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E88 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E90 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3E98 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3EA0 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3EA8 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000), + /* 3EB0 */ be(0x0000), be(0x0000), be(0x0000)), + + REGS(be(0x3EB6), be(0x004C)), /* ECL */ + + REGS(be(0x3EBA), + be(0xAAAD), /* 3EBA */ + be(0x0086)), /* 3EBC: Bias currents for FSC/ECL */ + + REGS(be(0x3EC0), + be(0x1E00), /* 3EC0: SFbin/SH mode settings */ + be(0x100A), /* 3EC2: CLK divider for ramp for 10 bit 400MH */ + /* 3EC4: FSC clamps for HDR mode and adc comp power down co */ + be(0x3300), + be(0xEA44), /* 3EC6: VLN and clk gating controls */ + be(0x6F6F), /* 3EC8: Txl0 and Txlo1 settings for normal mode */ + be(0x2F4A), /* 3ECA: CDAC/Txlo2/RSTGHI/RSTGLO settings */ + be(0x0506), /* 3ECC: RSTDHI/RSTDLO/CDAC/TXHI settings */ + /* 3ECE: Ramp buffer settings and Booster enable (bits 0-5) */ + be(0x203B), + be(0x13F0), /* 3ED0: TXLO from atest/sf bin settings */ + be(0xA53D), /* 3ED2: Ramp offset */ + be(0x862F), /* 3ED4: TXLO open loop/row driver settings */ + be(0x4081), /* 3ED6: Txlatch fr cfpn rows/vln bias */ + be(0x8003), /* 3ED8: Ramp step setting for 10 bit 400 Mhz */ + be(0xA580), /* 3EDA: Ramp Offset */ + be(0xC000), /* 3EDC: over range for rst and under range for sig */ + be(0xC103)), /* 3EDE: over range for sig and col dec clk settings */ + + /* corrections_recommended_bayer */ + REGS(be(0x3F00), + be(0x0017), /* 3F00: BM_T0 */ + be(0x02DD), /* 3F02: BM_T1 */ + /* 3F04: if Ana_gain less than 2, use noise_floor0, multipl */ + be(0x0020), + /* 3F06: if Ana_gain between 4 and 7, use noise_floor2 and */ + be(0x0040), + /* 3F08: if Ana_gain between 4 and 7, use noise_floor2 and */ + be(0x0070), + /* 3F0A: Define noise_floor0(low address) and noise_floor1 */ + be(0x0101), + be(0x0302)), /* 3F0C: Define noise_floor2 and noise_floor3 */ + + REGS(be(0x3F10), + be(0x0505), /* 3F10: single k factor 0 */ + be(0x0505), /* 3F12: single k factor 1 */ + be(0x0505), /* 3F14: single k factor 2 */ + be(0x01FF), /* 3F16: cross factor 0 */ + be(0x01FF), /* 3F18: cross factor 1 */ + be(0x01FF), /* 3F1A: cross factor 2 */ + be(0x0022)), /* 3F1E */ + + /* GTH_THRES_RTN: 4max,4min filtered out of every 46 samples and */ + REGS(be(0x3F2C), be(0x442E)), + + REGS(be(0x3F3E), + be(0x0000), /* 3F3E: Switch ADC from 12 bit to 10 bit mode */ + be(0x1511), /* 3F40: couple k factor 0 */ + be(0x1511), /* 3F42: couple k factor 1 */ + be(0x0707)), /* 3F44: couple k factor 2 */ +}; + +static int ar0521_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ar0521_dev *sensor = to_ar0521_dev(sd); + int i; + + clk_disable_unprepare(sensor->extclk); + + if (sensor->reset_gpio) + gpiod_set_value(sensor->reset_gpio, 1); /* assert RESET signal */ + + for (i = ARRAY_SIZE(ar0521_supply_names) - 1; i >= 0; i--) { + if (sensor->supplies[i]) + regulator_disable(sensor->supplies[i]); + } + return 0; +} + +static int ar0521_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ar0521_dev *sensor = to_ar0521_dev(sd); + unsigned int cnt; + int ret; + + for (cnt = 0; cnt < ARRAY_SIZE(ar0521_supply_names); cnt++) + if (sensor->supplies[cnt]) { + ret = regulator_enable(sensor->supplies[cnt]); + if (ret < 0) + goto off; + + usleep_range(1000, 1500); /* min 1 ms */ + } + + ret = clk_prepare_enable(sensor->extclk); + if (ret < 0) { + v4l2_err(&sensor->sd, "error enabling sensor clock\n"); + goto off; + } + usleep_range(1000, 1500); /* min 1 ms */ + + if (sensor->reset_gpio) + /* deassert RESET signal */ + gpiod_set_value(sensor->reset_gpio, 0); + usleep_range(4500, 5000); /* min 45000 clocks */ + + for (cnt = 0; cnt < ARRAY_SIZE(initial_regs); cnt++) + if (ar0521_write_regs(sensor, initial_regs[cnt].data, + initial_regs[cnt].count)) + goto off; + + ret = ar0521_write_reg(sensor, AR0521_REG_SERIAL_FORMAT, + AR0521_REG_SERIAL_FORMAT_MIPI | + sensor->lane_count); + if (ret) + goto off; + + /* set MIPI test mode - disabled for now */ + ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_TEST_MODE, + ((0x40 << sensor->lane_count) - 0x40) | + AR0521_REG_HISPI_TEST_MODE_LP11); + if (ret) + goto off; + + ret = ar0521_write_reg(sensor, AR0521_REG_ROW_SPEED, 0x110 | + 4 / sensor->lane_count); + if (ret) + goto off; + + return 0; +off: + ar0521_power_off(dev); + return ret; +} + +static int ar0521_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct ar0521_dev *sensor = to_ar0521_dev(sd); + + if (code->index) + return -EINVAL; + + code->code = sensor->fmt.code; + return 0; +} + +static int ar0521_pre_streamon(struct v4l2_subdev *sd, u32 flags) +{ + struct ar0521_dev *sensor = to_ar0521_dev(sd); + int ret; + + if (!(flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP)) + return -EACCES; + + ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev); + if (ret < 0) + return ret; + + /* Set LP-11 on clock and data lanes */ + ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_CONTROL_STATUS, + AR0521_REG_HISPI_CONTROL_STATUS_FRAMER_TEST_MODE_ENABLE); + if (ret) + goto err; + + /* Start streaming LP-11 */ + ret = ar0521_write_reg(sensor, AR0521_REG_RESET, + AR0521_REG_RESET_DEFAULTS | + AR0521_REG_RESET_STREAM); + if (ret) + goto err; + return 0; + +err: + pm_runtime_put(&sensor->i2c_client->dev); + return ret; +} + +static int ar0521_post_streamoff(struct v4l2_subdev *sd) +{ + struct ar0521_dev *sensor = to_ar0521_dev(sd); + + pm_runtime_put(&sensor->i2c_client->dev); + return 0; +} + +static int ar0521_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ar0521_dev *sensor = to_ar0521_dev(sd); + int ret; + + mutex_lock(&sensor->lock); + + ret = ar0521_set_stream(sensor, enable); + if (!ret) + sensor->streaming = enable; + + mutex_unlock(&sensor->lock); + return ret; +} + +static const struct v4l2_subdev_core_ops ar0521_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, +}; + +static const struct v4l2_subdev_video_ops ar0521_video_ops = { + .s_stream = ar0521_s_stream, + .pre_streamon = ar0521_pre_streamon, + .post_streamoff = ar0521_post_streamoff, +}; + +static const struct v4l2_subdev_pad_ops ar0521_pad_ops = { + .enum_mbus_code = ar0521_enum_mbus_code, + .get_fmt = ar0521_get_fmt, + .set_fmt = ar0521_set_fmt, +}; + +static const struct v4l2_subdev_ops ar0521_subdev_ops = { + .core = &ar0521_core_ops, + .video = &ar0521_video_ops, + .pad = &ar0521_pad_ops, +}; + +static int __maybe_unused ar0521_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ar0521_dev *sensor = to_ar0521_dev(sd); + + if (sensor->streaming) + ar0521_set_stream(sensor, 0); + + return 0; +} + +static int __maybe_unused ar0521_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ar0521_dev *sensor = to_ar0521_dev(sd); + + if (sensor->streaming) + return ar0521_set_stream(sensor, 1); + + return 0; +} + +static int ar0521_probe(struct i2c_client *client) +{ + struct v4l2_fwnode_endpoint ep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct device *dev = &client->dev; + struct fwnode_handle *endpoint; + struct ar0521_dev *sensor; + unsigned int cnt; + int ret; + + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->i2c_client = client; + sensor->fmt.width = AR0521_WIDTH_MAX; + sensor->fmt.height = AR0521_HEIGHT_MAX; + + endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!endpoint) { + dev_err(dev, "endpoint node not found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_parse(endpoint, &ep); + fwnode_handle_put(endpoint); + if (ret) { + dev_err(dev, "could not parse endpoint\n"); + return ret; + } + + if (ep.bus_type != V4L2_MBUS_CSI2_DPHY) { + dev_err(dev, "invalid bus type, must be MIPI CSI2\n"); + return -EINVAL; + } + + sensor->lane_count = ep.bus.mipi_csi2.num_data_lanes; + switch (sensor->lane_count) { + case 1: + case 2: + case 4: + break; + default: + dev_err(dev, "invalid number of MIPI data lanes\n"); + return -EINVAL; + } + + /* Get master clock (extclk) */ + sensor->extclk = devm_clk_get(dev, "extclk"); + if (IS_ERR(sensor->extclk)) { + dev_err(dev, "failed to get extclk\n"); + return PTR_ERR(sensor->extclk); + } + + sensor->extclk_freq = clk_get_rate(sensor->extclk); + + if (sensor->extclk_freq < AR0521_EXTCLK_MIN || + sensor->extclk_freq > AR0521_EXTCLK_MAX) { + dev_err(dev, "extclk frequency out of range: %u Hz\n", + sensor->extclk_freq); + return -EINVAL; + } + + /* Request optional reset pin (usually active low) and assert it */ + sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + + v4l2_i2c_subdev_init(&sensor->sd, client, &ar0521_subdev_ops); + + sensor->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) + return ret; + + for (cnt = 0; cnt < ARRAY_SIZE(ar0521_supply_names); cnt++) { + struct regulator *supply = devm_regulator_get(dev, + ar0521_supply_names[cnt]); + + if (IS_ERR(supply)) { + dev_info(dev, "no %s regulator found: %li\n", + ar0521_supply_names[cnt], PTR_ERR(supply)); + return PTR_ERR(supply); + } + sensor->supplies[cnt] = supply; + } + + mutex_init(&sensor->lock); + + ret = ar0521_init_controls(sensor); + if (ret) + goto entity_cleanup; + + ar0521_adj_fmt(&sensor->fmt); + + ret = v4l2_async_register_subdev(&sensor->sd); + if (ret) + goto free_ctrls; + + /* Turn on the device and enable runtime PM */ + ret = ar0521_power_on(&client->dev); + if (ret) + goto disable; + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + return 0; + +disable: + v4l2_async_unregister_subdev(&sensor->sd); + media_entity_cleanup(&sensor->sd.entity); +free_ctrls: + v4l2_ctrl_handler_free(&sensor->ctrls.handler); +entity_cleanup: + media_entity_cleanup(&sensor->sd.entity); + mutex_destroy(&sensor->lock); + return ret; +} + +static int ar0521_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ar0521_dev *sensor = to_ar0521_dev(sd); + + v4l2_async_unregister_subdev(&sensor->sd); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->ctrls.handler); + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ar0521_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + mutex_destroy(&sensor->lock); + return 0; +} + +static const struct dev_pm_ops ar0521_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ar0521_suspend, ar0521_resume) + SET_RUNTIME_PM_OPS(ar0521_power_off, ar0521_power_on, NULL) +}; +static const struct of_device_id ar0521_dt_ids[] = { + {.compatible = "onnn,ar0521"}, + {} +}; +MODULE_DEVICE_TABLE(of, ar0521_dt_ids); + +static struct i2c_driver ar0521_i2c_driver = { + .driver = { + .name = "ar0521", + .pm = &ar0521_pm_ops, + .of_match_table = ar0521_dt_ids, + }, + .probe_new = ar0521_probe, + .remove = ar0521_remove, +}; + +module_i2c_driver(ar0521_i2c_driver); + +MODULE_DESCRIPTION("AR0521 MIPI Camera subdev driver"); +MODULE_AUTHOR("Krzysztof Hałasa <khalasa@piap.pl>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index cbce8b88dbcf..1fd4dc6e4726 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -623,12 +623,22 @@ static int mt9p031_get_selection(struct v4l2_subdev *subdev, { struct mt9p031 *mt9p031 = to_mt9p031(subdev); - if (sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left = MT9P031_COLUMN_START_MIN; + sel->r.top = MT9P031_ROW_START_MIN; + sel->r.width = MT9P031_WINDOW_WIDTH_MAX; + sel->r.height = MT9P031_WINDOW_HEIGHT_MAX; + return 0; - sel->r = *__mt9p031_get_pad_crop(mt9p031, sd_state, sel->pad, - sel->which); - return 0; + case V4L2_SEL_TGT_CROP: + sel->r = *__mt9p031_get_pad_crop(mt9p031, sd_state, + sel->pad, sel->which); + return 0; + + default: + return -EINVAL; + } } static int mt9p031_set_selection(struct v4l2_subdev *subdev, @@ -682,6 +692,37 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev, return 0; } +static int mt9p031_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) +{ + struct mt9p031 *mt9p031 = to_mt9p031(subdev); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + const int which = sd_state == NULL ? V4L2_SUBDEV_FORMAT_ACTIVE : + V4L2_SUBDEV_FORMAT_TRY; + + crop = __mt9p031_get_pad_crop(mt9p031, sd_state, 0, which); + v4l2_subdev_get_try_crop(subdev, sd_state, 0); + crop->left = MT9P031_COLUMN_START_DEF; + crop->top = MT9P031_ROW_START_DEF; + crop->width = MT9P031_WINDOW_WIDTH_DEF; + crop->height = MT9P031_WINDOW_HEIGHT_DEF; + + format = __mt9p031_get_pad_format(mt9p031, sd_state, 0, which); + + if (mt9p031->model == MT9P031_MODEL_MONOCHROME) + format->code = MEDIA_BUS_FMT_Y12_1X12; + else + format->code = MEDIA_BUS_FMT_SGRBG12_1X12; + + format->width = MT9P031_WINDOW_WIDTH_DEF; + format->height = MT9P031_WINDOW_HEIGHT_DEF; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + /* ----------------------------------------------------------------------------- * V4L2 subdev control operations */ @@ -980,28 +1021,6 @@ static int mt9p031_registered(struct v4l2_subdev *subdev) static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) { - struct mt9p031 *mt9p031 = to_mt9p031(subdev); - struct v4l2_mbus_framefmt *format; - struct v4l2_rect *crop; - - crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0); - crop->left = MT9P031_COLUMN_START_DEF; - crop->top = MT9P031_ROW_START_DEF; - crop->width = MT9P031_WINDOW_WIDTH_DEF; - crop->height = MT9P031_WINDOW_HEIGHT_DEF; - - format = v4l2_subdev_get_try_format(subdev, fh->state, 0); - - if (mt9p031->model == MT9P031_MODEL_MONOCHROME) - format->code = MEDIA_BUS_FMT_Y12_1X12; - else - format->code = MEDIA_BUS_FMT_SGRBG12_1X12; - - format->width = MT9P031_WINDOW_WIDTH_DEF; - format->height = MT9P031_WINDOW_HEIGHT_DEF; - format->field = V4L2_FIELD_NONE; - format->colorspace = V4L2_COLORSPACE_SRGB; - return mt9p031_set_power(subdev, 1); } @@ -1019,6 +1038,7 @@ static const struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = { }; static const struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = { + .init_cfg = mt9p031_init_cfg, .enum_mbus_code = mt9p031_enum_mbus_code, .enum_frame_size = mt9p031_enum_frame_size, .get_fmt = mt9p031_get_format, @@ -1166,20 +1186,9 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - mt9p031->crop.width = MT9P031_WINDOW_WIDTH_DEF; - mt9p031->crop.height = MT9P031_WINDOW_HEIGHT_DEF; - mt9p031->crop.left = MT9P031_COLUMN_START_DEF; - mt9p031->crop.top = MT9P031_ROW_START_DEF; - - if (mt9p031->model == MT9P031_MODEL_MONOCHROME) - mt9p031->format.code = MEDIA_BUS_FMT_Y12_1X12; - else - mt9p031->format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - - mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF; - mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF; - mt9p031->format.field = V4L2_FIELD_NONE; - mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; + ret = mt9p031_init_cfg(&mt9p031->subdev, NULL); + if (ret) + goto done; mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); @@ -1214,6 +1223,7 @@ static int mt9p031_remove(struct i2c_client *client) } static const struct i2c_device_id mt9p031_id[] = { + { "mt9p006", MT9P031_MODEL_COLOR }, { "mt9p031", MT9P031_MODEL_COLOR }, { "mt9p031m", MT9P031_MODEL_MONOCHROME }, { } @@ -1222,6 +1232,7 @@ MODULE_DEVICE_TABLE(i2c, mt9p031_id); #if IS_ENABLED(CONFIG_OF) static const struct of_device_id mt9p031_of_match[] = { + { .compatible = "aptina,mt9p006", }, { .compatible = "aptina,mt9p031", }, { .compatible = "aptina,mt9p031m", }, { /* sentinel */ }, diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index db5a19babe67..502f0b62e950 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -29,8 +29,21 @@ #define OV5640_XCLK_MIN 6000000 #define OV5640_XCLK_MAX 54000000 +#define OV5640_NATIVE_WIDTH 2624 +#define OV5640_NATIVE_HEIGHT 1964 +#define OV5640_PIXEL_ARRAY_TOP 14 +#define OV5640_PIXEL_ARRAY_LEFT 16 +#define OV5640_PIXEL_ARRAY_WIDTH 2592 +#define OV5640_PIXEL_ARRAY_HEIGHT 1944 + +/* FIXME: not documented. */ +#define OV5640_MIN_VBLANK 24 +#define OV5640_MAX_VTS 3375 + #define OV5640_DEFAULT_SLAVE_ID 0x3c +#define OV5640_LINK_RATE_MAX 490000000U + #define OV5640_REG_SYS_RESET02 0x3002 #define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 #define OV5640_REG_SYS_CTRL0 0x3008 @@ -59,10 +72,16 @@ #define OV5640_REG_AEC_PK_MANUAL 0x3503 #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a #define OV5640_REG_AEC_PK_VTS 0x350c +#define OV5640_REG_TIMING_HS 0x3800 +#define OV5640_REG_TIMING_VS 0x3802 +#define OV5640_REG_TIMING_HW 0x3804 +#define OV5640_REG_TIMING_VH 0x3806 #define OV5640_REG_TIMING_DVPHO 0x3808 #define OV5640_REG_TIMING_DVPVO 0x380a #define OV5640_REG_TIMING_HTS 0x380c #define OV5640_REG_TIMING_VTS 0x380e +#define OV5640_REG_TIMING_HOFFS 0x3810 +#define OV5640_REG_TIMING_VOFFS 0x3812 #define OV5640_REG_TIMING_TC_REG20 0x3820 #define OV5640_REG_TIMING_TC_REG21 0x3821 #define OV5640_REG_AEC_CTRL00 0x3a00 @@ -88,6 +107,7 @@ #define OV5640_REG_POLARITY_CTRL00 0x4740 #define OV5640_REG_MIPI_CTRL00 0x4800 #define OV5640_REG_DEBUG_MODE 0x4814 +#define OV5640_REG_PCLK_PERIOD 0x4837 #define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f #define OV5640_REG_PRE_ISP_TEST_SET1 0x503d #define OV5640_REG_SDE_CTRL0 0x5580 @@ -118,6 +138,47 @@ enum ov5640_frame_rate { OV5640_NUM_FRAMERATES, }; +enum ov5640_pixel_rate_id { + OV5640_PIXEL_RATE_168M, + OV5640_PIXEL_RATE_148M, + OV5640_PIXEL_RATE_124M, + OV5640_PIXEL_RATE_96M, + OV5640_PIXEL_RATE_48M, + OV5640_NUM_PIXEL_RATES, +}; + +/* + * The chip manual suggests 24/48/96/192 MHz pixel clocks. + * + * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for + * full resolution mode @15 FPS. + */ +static const u32 ov5640_pixel_rates[] = { + [OV5640_PIXEL_RATE_168M] = 168000000, + [OV5640_PIXEL_RATE_148M] = 148000000, + [OV5640_PIXEL_RATE_124M] = 124000000, + [OV5640_PIXEL_RATE_96M] = 96000000, + [OV5640_PIXEL_RATE_48M] = 48000000, +}; + +/* + * MIPI CSI-2 link frequencies. + * + * Derived from the above defined pixel rate for bpp = (8, 16, 24) and + * data_lanes = (1, 2) + * + * link_freq = (pixel_rate * bpp) / (2 * data_lanes) + */ +static const s64 ov5640_csi2_link_freqs[] = { + 992000000, 888000000, 768000000, 744000000, 672000000, 672000000, + 592000000, 592000000, 576000000, 576000000, 496000000, 496000000, + 384000000, 384000000, 384000000, 336000000, 296000000, 288000000, + 248000000, 192000000, 192000000, 192000000, 96000000, +}; + +/* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */ +#define OV5640_DEFAULT_LINK_FREQ 13 + enum ov5640_format_mux { OV5640_FMT_MUX_YUV422 = 0, OV5640_FMT_MUX_RGB, @@ -130,20 +191,145 @@ enum ov5640_format_mux { struct ov5640_pixfmt { u32 code; u32 colorspace; + u8 bpp; + u8 ctrl00; + enum ov5640_format_mux mux; +}; + +static const struct ov5640_pixfmt ov5640_dvp_formats[] = { + { + /* YUV422, YUYV */ + .code = MEDIA_BUS_FMT_JPEG_1X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .bpp = 16, + .ctrl00 = 0x30, + .mux = OV5640_FMT_MUX_YUV422, + }, { + /* YUV422, UYVY */ + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 16, + .ctrl00 = 0x3f, + .mux = OV5640_FMT_MUX_YUV422, + }, { + /* YUV422, YUYV */ + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 16, + .ctrl00 = 0x30, + .mux = OV5640_FMT_MUX_YUV422, + }, { + /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 16, + .ctrl00 = 0x6f, + .mux = OV5640_FMT_MUX_RGB, + }, { + /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 16, + .ctrl00 = 0x61, + .mux = OV5640_FMT_MUX_RGB, + }, { + /* Raw, BGBG... / GRGR... */ + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x00, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, { + /* Raw bayer, GBGB... / RGRG... */ + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x01, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, { + /* Raw bayer, GRGR... / BGBG... */ + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x02, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, { + /* Raw bayer, RGRG... / GBGB... */ + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x03, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, + { /* sentinel */ } }; -static const struct ov5640_pixfmt ov5640_formats[] = { - { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, }, - { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, }, - { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, }, +static const struct ov5640_pixfmt ov5640_csi2_formats[] = { + { + /* YUV422, YUYV */ + .code = MEDIA_BUS_FMT_JPEG_1X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .bpp = 16, + .ctrl00 = 0x30, + .mux = OV5640_FMT_MUX_YUV422, + }, { + /* YUV422, UYVY */ + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 16, + .ctrl00 = 0x3f, + .mux = OV5640_FMT_MUX_YUV422, + }, { + /* YUV422, YUYV */ + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 16, + .ctrl00 = 0x30, + .mux = OV5640_FMT_MUX_YUV422, + }, { + /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ + .code = MEDIA_BUS_FMT_RGB565_1X16, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 16, + .ctrl00 = 0x6f, + .mux = OV5640_FMT_MUX_RGB, + }, { + /* BGR888: RGB */ + .code = MEDIA_BUS_FMT_BGR888_1X24, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 24, + .ctrl00 = 0x23, + .mux = OV5640_FMT_MUX_RGB, + }, { + /* Raw, BGBG... / GRGR... */ + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x00, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, { + /* Raw bayer, GBGB... / RGRG... */ + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x01, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, { + /* Raw bayer, GRGR... / BGBG... */ + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x02, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, { + /* Raw bayer, RGRG... / GBGB... */ + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .bpp = 8, + .ctrl00 = 0x03, + .mux = OV5640_FMT_MUX_RAW_DPC, + }, + { /* sentinel */ } }; /* @@ -186,21 +372,42 @@ struct reg_value { u32 delay_ms; }; +struct ov5640_timings { + /* Analog crop rectangle. */ + struct v4l2_rect analog_crop; + /* Visibile crop: from analog crop top-left corner. */ + struct v4l2_rect crop; + /* Total pixels per line: width + fixed hblank. */ + u32 htot; + /* Default vertical blanking: frame height = height + vblank. */ + u32 vblank_def; +}; + struct ov5640_mode_info { enum ov5640_mode_id id; enum ov5640_downsize_mode dn_mode; - u32 hact; - u32 htot; - u32 vact; - u32 vtot; + enum ov5640_pixel_rate_id pixel_rate; + + unsigned int width; + unsigned int height; + + struct ov5640_timings dvp_timings; + struct ov5640_timings csi2_timings; + const struct reg_value *reg_data; u32 reg_data_size; + + /* Used by s_frame_interval only. */ u32 max_fps; + u32 def_fps; }; struct ov5640_ctrls { struct v4l2_ctrl_handler handler; struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; struct { struct v4l2_ctrl *auto_exp; struct v4l2_ctrl *exposure; @@ -249,6 +456,7 @@ struct ov5640_dev { const struct ov5640_mode_info *last_mode; enum ov5640_frame_rate current_fr; struct v4l2_fract frame_interval; + s64 current_link_freq; struct ov5640_ctrls ctrls; @@ -270,6 +478,40 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) ctrls.handler)->sd; } +static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor) +{ + return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY; +} + +static inline const struct ov5640_pixfmt * +ov5640_formats(struct ov5640_dev *sensor) +{ + return ov5640_is_csi2(sensor) ? ov5640_csi2_formats + : ov5640_dvp_formats; +} + +static const struct ov5640_pixfmt * +ov5640_code_to_pixfmt(struct ov5640_dev *sensor, u32 code) +{ + const struct ov5640_pixfmt *formats = ov5640_formats(sensor); + unsigned int i; + + for (i = 0; formats[i].code; ++i) { + if (formats[i].code == code) + return &formats[i]; + } + + return &formats[0]; +} + +static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code) +{ + const struct ov5640_pixfmt *format = ov5640_code_to_pixfmt(sensor, + code); + + return format->bpp; +} + /* * FIXME: all of these register tables are likely filled with * entries that set the register to their power-on default values, @@ -278,7 +520,19 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) * over i2c. */ /* YUV422 UYVY VGA@30fps */ -static const struct reg_value ov5640_init_setting_30fps_VGA[] = { + +static const struct v4l2_mbus_framefmt ov5640_default_fmt = { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .width = 640, + .height = 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB), + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB), + .field = V4L2_FIELD_NONE, +}; + +static const struct reg_value ov5640_init_setting[] = { {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, @@ -294,11 +548,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, @@ -362,72 +612,11 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, }; -static const struct reg_value ov5640_setting_VGA_640_480[] = { - {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, - {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, - {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -}; - -static const struct reg_value ov5640_setting_XGA_1024_768[] = { - {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, - {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, - {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -}; - -static const struct reg_value ov5640_setting_QVGA_320_240[] = { - {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, - {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, - {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -}; - -static const struct reg_value ov5640_setting_QQVGA_160_120[] = { +static const struct reg_value ov5640_setting_low_res[] = { {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, @@ -437,72 +626,11 @@ static const struct reg_value ov5640_setting_QQVGA_160_120[] = { {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, }; -static const struct reg_value ov5640_setting_QCIF_176_144[] = { - {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, - {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, - {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -}; - -static const struct reg_value ov5640_setting_NTSC_720_480[] = { - {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, - {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, - {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -}; - -static const struct reg_value ov5640_setting_PAL_720_576[] = { - {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, - {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, - {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, - {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, - {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, -}; - static const struct reg_value ov5640_setting_720P_1280_720[] = { {0x3c07, 0x07, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, @@ -517,11 +645,7 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x11, 0, 0}, - {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, @@ -532,9 +656,6 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, - {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, - {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, @@ -548,11 +669,7 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x11, 0, 0}, - {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, - {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, - {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, - {0x3810, 0x00, 0, 0}, - {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, @@ -563,67 +680,462 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, }; -/* power-on sensor init reg table */ -static const struct ov5640_mode_info ov5640_mode_init_data = { - 0, SUBSAMPLING, 640, 1896, 480, 984, - ov5640_init_setting_30fps_VGA, - ARRAY_SIZE(ov5640_init_setting_30fps_VGA), - OV5640_30_FPS, +static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = { + { + /* 160x120 */ + .id = OV5640_MODE_QQVGA_160_120, + .dn_mode = SUBSAMPLING, + .pixel_rate = OV5640_PIXEL_RATE_48M, + .width = 160, + .height = 120, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = 2624, + .height = 1944, + }, + .crop = { + .left = 16, + .top = 6, + .width = 160, + .height = 120, + }, + .htot = 1896, + .vblank_def = 864, + }, + .csi2_timings = { + /* Feed the full valid pixel array to the ISP. */ + .analog_crop = { + .left = OV5640_PIXEL_ARRAY_LEFT, + .top = OV5640_PIXEL_ARRAY_TOP, + .width = OV5640_PIXEL_ARRAY_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + }, + /* Maintain a minimum processing margin. */ + .crop = { + .left = 2, + .top = 4, + .width = 160, + .height = 120, + }, + .htot = 1600, + .vblank_def = 878, + }, + .reg_data = ov5640_setting_low_res, + .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 176x144 */ + .id = OV5640_MODE_QCIF_176_144, + .dn_mode = SUBSAMPLING, + .pixel_rate = OV5640_PIXEL_RATE_48M, + .width = 176, + .height = 144, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = 2624, + .height = 1944, + }, + .crop = { + .left = 16, + .top = 6, + .width = 176, + .height = 144, + }, + .htot = 1896, + .vblank_def = 840, + }, + .csi2_timings = { + /* Feed the full valid pixel array to the ISP. */ + .analog_crop = { + .left = OV5640_PIXEL_ARRAY_LEFT, + .top = OV5640_PIXEL_ARRAY_TOP, + .width = OV5640_PIXEL_ARRAY_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + }, + /* Maintain a minimum processing margin. */ + .crop = { + .left = 2, + .top = 4, + .width = 176, + .height = 144, + }, + .htot = 1600, + .vblank_def = 854, + }, + .reg_data = ov5640_setting_low_res, + .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 320x240 */ + .id = OV5640_MODE_QVGA_320_240, + .dn_mode = SUBSAMPLING, + .width = 320, + .height = 240, + .pixel_rate = OV5640_PIXEL_RATE_48M, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = 2624, + .height = 1944, + }, + .crop = { + .left = 16, + .top = 6, + .width = 320, + .height = 240, + }, + .htot = 1896, + .vblank_def = 744, + }, + .csi2_timings = { + /* Feed the full valid pixel array to the ISP. */ + .analog_crop = { + .left = OV5640_PIXEL_ARRAY_LEFT, + .top = OV5640_PIXEL_ARRAY_TOP, + .width = OV5640_PIXEL_ARRAY_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + }, + /* Maintain a minimum processing margin. */ + .crop = { + .left = 2, + .top = 4, + .width = 320, + .height = 240, + }, + .htot = 1600, + .vblank_def = 760, + }, + .reg_data = ov5640_setting_low_res, + .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 640x480 */ + .id = OV5640_MODE_VGA_640_480, + .dn_mode = SUBSAMPLING, + .pixel_rate = OV5640_PIXEL_RATE_48M, + .width = 640, + .height = 480, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = 2624, + .height = 1944, + }, + .crop = { + .left = 16, + .top = 6, + .width = 640, + .height = 480, + }, + .htot = 1896, + .vblank_def = 600, + }, + .csi2_timings = { + /* Feed the full valid pixel array to the ISP. */ + .analog_crop = { + .left = OV5640_PIXEL_ARRAY_LEFT, + .top = OV5640_PIXEL_ARRAY_TOP, + .width = OV5640_PIXEL_ARRAY_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + }, + /* Maintain a minimum processing margin. */ + .crop = { + .left = 2, + .top = 4, + .width = 640, + .height = 480, + }, + .htot = 1600, + .vblank_def = 520, + }, + .reg_data = ov5640_setting_low_res, + .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), + .max_fps = OV5640_60_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 720x480 */ + .id = OV5640_MODE_NTSC_720_480, + .dn_mode = SUBSAMPLING, + .width = 720, + .height = 480, + .pixel_rate = OV5640_PIXEL_RATE_96M, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = 2624, + .height = 1944, + }, + .crop = { + .left = 56, + .top = 60, + .width = 720, + .height = 480, + }, + .htot = 1896, + .vblank_def = 504, + }, + .csi2_timings = { + /* Feed the full valid pixel array to the ISP. */ + .analog_crop = { + .left = OV5640_PIXEL_ARRAY_LEFT, + .top = OV5640_PIXEL_ARRAY_TOP, + .width = OV5640_PIXEL_ARRAY_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + }, + .crop = { + .left = 56, + .top = 60, + .width = 720, + .height = 480, + }, + .htot = 1896, + .vblank_def = 1206, + }, + .reg_data = ov5640_setting_low_res, + .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 720x576 */ + .id = OV5640_MODE_PAL_720_576, + .dn_mode = SUBSAMPLING, + .width = 720, + .height = 576, + .pixel_rate = OV5640_PIXEL_RATE_96M, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = 2624, + .height = 1944, + }, + .crop = { + .left = 56, + .top = 6, + .width = 720, + .height = 576, + }, + .htot = 1896, + .vblank_def = 408, + }, + .csi2_timings = { + /* Feed the full valid pixel array to the ISP. */ + .analog_crop = { + .left = OV5640_PIXEL_ARRAY_LEFT, + .top = OV5640_PIXEL_ARRAY_TOP, + .width = OV5640_PIXEL_ARRAY_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + }, + .crop = { + .left = 56, + .top = 6, + .width = 720, + .height = 576, + }, + .htot = 1896, + .vblank_def = 1110, + }, + .reg_data = ov5640_setting_low_res, + .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 1024x768 */ + .id = OV5640_MODE_XGA_1024_768, + .dn_mode = SUBSAMPLING, + .pixel_rate = OV5640_PIXEL_RATE_96M, + .width = 1024, + .height = 768, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = 2624, + .height = 1944, + }, + .crop = { + .left = 16, + .top = 6, + .width = 1024, + .height = 768, + }, + .htot = 1896, + .vblank_def = 312, + }, + .csi2_timings = { + .analog_crop = { + .left = 0, + .top = 4, + .width = OV5640_NATIVE_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + }, + .crop = { + .left = 16, + .top = 6, + .width = 1024, + .height = 768, + }, + .htot = 1896, + .vblank_def = 918, + }, + .reg_data = ov5640_setting_low_res, + .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 1280x720 */ + .id = OV5640_MODE_720P_1280_720, + .dn_mode = SUBSAMPLING, + .pixel_rate = OV5640_PIXEL_RATE_124M, + .width = 1280, + .height = 720, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 250, + .width = 2624, + .height = 1456, + }, + .crop = { + .left = 16, + .top = 4, + .width = 1280, + .height = 720, + }, + .htot = 1892, + .vblank_def = 20, + }, + .csi2_timings = { + .analog_crop = { + .left = 0, + .top = 250, + .width = 2624, + .height = 1456, + }, + .crop = { + .left = 16, + .top = 4, + .width = 1280, + .height = 720, + }, + .htot = 1600, + .vblank_def = 560, + }, + .reg_data = ov5640_setting_720P_1280_720, + .reg_data_size = ARRAY_SIZE(ov5640_setting_720P_1280_720), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 1920x1080 */ + .id = OV5640_MODE_1080P_1920_1080, + .dn_mode = SCALING, + .pixel_rate = OV5640_PIXEL_RATE_148M, + .width = 1920, + .height = 1080, + .dvp_timings = { + .analog_crop = { + .left = 336, + .top = 434, + .width = 1952, + .height = 1088, + }, + .crop = { + .left = 16, + .top = 4, + .width = 1920, + .height = 1080, + }, + .htot = 2500, + .vblank_def = 40, + }, + .csi2_timings = { + /* Crop the full valid pixel array in the center. */ + .analog_crop = { + .left = 336, + .top = 434, + .width = 1952, + .height = 1088, + }, + /* Maintain a larger processing margins. */ + .crop = { + .left = 16, + .top = 4, + .width = 1920, + .height = 1080, + }, + .htot = 2234, + .vblank_def = 24, + }, + .reg_data = ov5640_setting_1080P_1920_1080, + .reg_data_size = ARRAY_SIZE(ov5640_setting_1080P_1920_1080), + .max_fps = OV5640_30_FPS, + .def_fps = OV5640_30_FPS + }, { + /* 2592x1944 */ + .id = OV5640_MODE_QSXGA_2592_1944, + .dn_mode = SCALING, + .pixel_rate = OV5640_PIXEL_RATE_168M, + .width = OV5640_PIXEL_ARRAY_WIDTH, + .height = OV5640_PIXEL_ARRAY_HEIGHT, + .dvp_timings = { + .analog_crop = { + .left = 0, + .top = 0, + .width = 2624, + .height = 1952, + }, + .crop = { + .left = 16, + .top = 4, + .width = 2592, + .height = 1944, + }, + .htot = 2844, + .vblank_def = 24, + }, + .csi2_timings = { + /* Give more processing margin to full resolution. */ + .analog_crop = { + .left = 0, + .top = 0, + .width = OV5640_NATIVE_WIDTH, + .height = 1952, + }, + .crop = { + .left = 16, + .top = 4, + .width = 2592, + .height = 1944, + }, + .htot = 2844, + .vblank_def = 24, + }, + .reg_data = ov5640_setting_QSXGA_2592_1944, + .reg_data_size = ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), + .max_fps = OV5640_15_FPS, + .def_fps = OV5640_15_FPS + }, }; -static const struct ov5640_mode_info -ov5640_mode_data[OV5640_NUM_MODES] = { - {OV5640_MODE_QQVGA_160_120, SUBSAMPLING, - 160, 1896, 120, 984, - ov5640_setting_QQVGA_160_120, - ARRAY_SIZE(ov5640_setting_QQVGA_160_120), - OV5640_30_FPS}, - {OV5640_MODE_QCIF_176_144, SUBSAMPLING, - 176, 1896, 144, 984, - ov5640_setting_QCIF_176_144, - ARRAY_SIZE(ov5640_setting_QCIF_176_144), - OV5640_30_FPS}, - {OV5640_MODE_QVGA_320_240, SUBSAMPLING, - 320, 1896, 240, 984, - ov5640_setting_QVGA_320_240, - ARRAY_SIZE(ov5640_setting_QVGA_320_240), - OV5640_30_FPS}, - {OV5640_MODE_VGA_640_480, SUBSAMPLING, - 640, 1896, 480, 1080, - ov5640_setting_VGA_640_480, - ARRAY_SIZE(ov5640_setting_VGA_640_480), - OV5640_60_FPS}, - {OV5640_MODE_NTSC_720_480, SUBSAMPLING, - 720, 1896, 480, 984, - ov5640_setting_NTSC_720_480, - ARRAY_SIZE(ov5640_setting_NTSC_720_480), - OV5640_30_FPS}, - {OV5640_MODE_PAL_720_576, SUBSAMPLING, - 720, 1896, 576, 984, - ov5640_setting_PAL_720_576, - ARRAY_SIZE(ov5640_setting_PAL_720_576), - OV5640_30_FPS}, - {OV5640_MODE_XGA_1024_768, SUBSAMPLING, - 1024, 1896, 768, 1080, - ov5640_setting_XGA_1024_768, - ARRAY_SIZE(ov5640_setting_XGA_1024_768), - OV5640_30_FPS}, - {OV5640_MODE_720P_1280_720, SUBSAMPLING, - 1280, 1892, 720, 740, - ov5640_setting_720P_1280_720, - ARRAY_SIZE(ov5640_setting_720P_1280_720), - OV5640_30_FPS}, - {OV5640_MODE_1080P_1920_1080, SCALING, - 1920, 2500, 1080, 1120, - ov5640_setting_1080P_1920_1080, - ARRAY_SIZE(ov5640_setting_1080P_1920_1080), - OV5640_30_FPS}, - {OV5640_MODE_QSXGA_2592_1944, SCALING, - 2592, 2844, 1944, 1968, - ov5640_setting_QSXGA_2592_1944, - ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), - OV5640_15_FPS}, -}; +static const struct ov5640_timings * +ov5640_timings(const struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) +{ + if (ov5640_is_csi2(sensor)) + return &mode->csi2_timings; + + return &mode->dvp_timings; +} static int ov5640_init_slave_id(struct ov5640_dev *sensor) { @@ -797,20 +1309,10 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, * +-----+-----+ * +------------> PCLK * - * This is deviating from the datasheet at least for the register - * 0x3108, since it's said here that the PCLK would be clocked from - * the PLL. - * - * There seems to be also (unverified) constraints: + * There seems to be also constraints: * - the PLL pre-divider output rate should be in the 4-27MHz range * - the PLL multiplier output rate should be in the 500-1000MHz range * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG - * - * In the two latter cases, these constraints are met since our - * factors are hardcoded. If we were to change that, we would need to - * take this into account. The only varying parts are the PLL - * multiplier and the system clock divider, which are shared between - * all these clocks so won't cause any issue. */ /* @@ -830,13 +1332,6 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, #define OV5640_SYSDIV_MAX 16 /* - * Hardcode these values for scaler and non-scaler modes. - * FIXME: to be re-calcualted for 1 data lanes setups - */ -#define OV5640_MIPI_DIV_PCLK 2 -#define OV5640_MIPI_DIV_SCLK 1 - -/* * This is supposed to be ranging from 1 to 2, but the value is always * set to 2 in the vendor kernels. */ @@ -945,70 +1440,83 @@ out: /* * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values * for the MIPI CSI-2 output. - * - * @rate: The requested bandwidth per lane in bytes per second. - * 'Bandwidth Per Lane' is calculated as: - * bpl = HTOT * VTOT * FPS * bpp / num_lanes; - * - * This function use the requested bandwidth to calculate: - * - sample_rate = bpl / (bpp / num_lanes); - * = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes); - * - * - mipi_sclk = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR) - * - * with these fixed parameters: - * PLL_RDIV = 2; - * BIT_DIVIDER = 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5); - * PCLK_DIV = 1; - * - * The MIPI clock generation differs for modes that use the scaler and modes - * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI - * BIT CLk, and thus: - * - * - mipi_sclk = bpl / MIPI_DIV / 2; - * MIPI_DIV = 1; - * - * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated - * from the pixel clock, and thus: - * - * - sample_rate = bpl / (bpp / num_lanes); - * = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes); - * = bpl / (4 * MIPI_DIV / num_lanes); - * - MIPI_DIV = bpp / (4 * num_lanes); - * - * FIXME: this have been tested with 16bpp and 2 lanes setup only. - * MIPI_DIV is fixed to value 2, but it -might- be changed according to the - * above formula for setups with 1 lane or image formats with different bpp. - * - * FIXME: this deviates from the sensor manual documentation which is quite - * thin on the MIPI clock tree generation part. */ -static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor, - unsigned long rate) +static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) { - const struct ov5640_mode_info *mode = sensor->current_mode; + u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div; u8 prediv, mult, sysdiv; - u8 mipi_div; + unsigned long link_freq; + unsigned long sysclk; + u8 pclk_period; + u32 sample_rate; + u32 num_lanes; int ret; + /* Use the link freq computed at ov5640_update_pixel_rate() time. */ + link_freq = sensor->current_link_freq; + /* - * 1280x720 is reported to use 'SUBSAMPLING' only, - * but according to the sensor manual it goes through the - * scaler before subsampling. + * - mipi_div - Additional divider for the MIPI lane clock. + * + * Higher link frequencies would make sysclk > 1GHz. + * Keep the sysclk low and do not divide in the MIPI domain. */ - if (mode->dn_mode == SCALING || - (mode->id == OV5640_MODE_720P_1280_720)) - mipi_div = OV5640_MIPI_DIV_SCLK; + if (link_freq > OV5640_LINK_RATE_MAX) + mipi_div = 1; else - mipi_div = OV5640_MIPI_DIV_PCLK; + mipi_div = 2; - ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv); + sysclk = link_freq * mipi_div; + ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv); - ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, - 0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT); + /* + * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio. + * + * - root_div = 2 (fixed) + * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5 + * - pclk_div = 1 (fixed) + * - p_div = (2 lanes ? mipi_div : 2 * mipi_div) + * + * This results in the following MIPI_SCLK depending on the number + * of lanes: + * + * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK + * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK + */ + root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2; + bit_div = OV5640_PLL_CTRL0_MIPI_MODE_8BIT; + pclk_div = ilog2(OV5640_PCLK_ROOT_DIV); - ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, - 0xff, sysdiv << 4 | mipi_div); + /* + * Scaler clock: + * - YUV: PCLK >= 2 * SCLK + * - RAW or JPEG: PCLK >= SCLK + * - sclk2x_div = sclk_div / 2 + */ + sclk_div = ilog2(OV5640_SCLK_ROOT_DIV); + sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV); + + /* + * Set the pixel clock period expressed in ns with 1-bit decimal + * (0x01=0.5ns). + * + * The register is very briefly documented. In the OV5645 datasheet it + * is described as (2 * pclk period), and from testing it seems the + * actual definition is 2 * 8-bit sample period. + * + * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2 + */ + num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; + sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16; + pclk_period = 2000000000UL / sample_rate; + + /* Program the clock tree registers. */ + ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div); + if (ret) + return ret; + + ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff, + (sysdiv << 4) | mipi_div); if (ret) return ret; @@ -1016,13 +1524,29 @@ static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor, if (ret) return ret; - ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, - 0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv); + ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f, + root_div | prediv); if (ret) return ret; - return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, - 0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS); + ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, + (pclk_div << 4) | (sclk2x_div << 2) | sclk_div); + if (ret) + return ret; + + return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period); +} + +static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) +{ + const struct ov5640_mode_info *mode = sensor->current_mode; + const struct ov5640_timings *timings = &mode->dvp_timings; + u32 rate; + + rate = timings->htot * (timings->crop.height + timings->vblank_def); + rate *= ov5640_framerates[sensor->current_fr]; + + return rate; } static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, @@ -1042,11 +1566,16 @@ static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, return _rate / *pll_rdiv / *bit_div / *pclk_div; } -static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) +static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor) { u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; + u32 rate; int ret; + rate = ov5640_calc_pixel_rate(sensor); + rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code); + rate /= sensor->ep.bus.parallel.bus_width; + ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, &bit_div, &pclk_div); @@ -1098,17 +1627,20 @@ static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, if (ret < 0) return ret; - ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact); + ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width); if (ret < 0) return ret; - return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); + return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height); } /* download ov5640 settings to sensor through i2c */ static int ov5640_set_timings(struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) { + const struct ov5640_timings *timings; + const struct v4l2_rect *analog_crop; + const struct v4l2_rect *crop; int ret; if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { @@ -1117,32 +1649,68 @@ static int ov5640_set_timings(struct ov5640_dev *sensor, return ret; } - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); + timings = ov5640_timings(sensor, mode); + analog_crop = &timings->analog_crop; + crop = &timings->crop; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS, + analog_crop->left); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS, + analog_crop->top); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW, + analog_crop->left + analog_crop->width - 1); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH, + analog_crop->top + analog_crop->height - 1); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height); if (ret < 0) return ret; - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact); + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot); if (ret < 0) return ret; - ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot); + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, + mode->height + timings->vblank_def); if (ret < 0) return ret; - return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); + return 0; } -static int ov5640_load_regs(struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode) +static void ov5640_load_regs(struct ov5640_dev *sensor, + const struct reg_value *regs, unsigned int regnum) { - const struct reg_value *regs = mode->reg_data; unsigned int i; u32 delay_ms; u16 reg_addr; u8 mask, val; int ret = 0; - for (i = 0; i < mode->reg_data_size; ++i, ++regs) { + for (i = 0; i < regnum; ++i, ++regs) { delay_ms = regs->delay_ms; reg_addr = regs->reg_addr; val = regs->val; @@ -1151,7 +1719,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, /* remain in power down mode for DVP */ if (regs->reg_addr == OV5640_REG_SYS_CTRL0 && val == OV5640_REG_SYS_CTRL0_SW_PWUP && - sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY) + !ov5640_is_csi2(sensor)) continue; if (mask) @@ -1164,8 +1732,6 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, if (delay_ms) usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); } - - return ov5640_set_timings(sensor, mode); } static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) @@ -1550,37 +2116,22 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) } static const struct ov5640_mode_info * -ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, - int width, int height, bool nearest) +ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest) { const struct ov5640_mode_info *mode; mode = v4l2_find_nearest_size(ov5640_mode_data, ARRAY_SIZE(ov5640_mode_data), - hact, vact, - width, height); + width, height, width, height); if (!mode || - (!nearest && (mode->hact != width || mode->vact != height))) - return NULL; - - /* Check to see if the current mode exceeds the max frame rate */ - if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps]) + (!nearest && + (mode->width != width || mode->height != height))) return NULL; return mode; } -static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) -{ - u64 rate; - - rate = sensor->current_mode->vtot * sensor->current_mode->htot; - rate *= ov5640_framerates[sensor->current_fr]; - - return rate; -} - /* * sensor changes between scaling and subsampling, go through * exposure calculation @@ -1628,7 +2179,8 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, return ret; /* Write capture setting */ - ret = ov5640_load_regs(sensor, mode); + ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); + ret = ov5640_set_timings(sensor, mode); if (ret < 0) return ret; @@ -1752,7 +2304,8 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor, return -EINVAL; /* Write capture setting */ - return ov5640_load_regs(sensor, mode); + ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); + return ov5640_set_timings(sensor, mode); } static int ov5640_set_mode(struct ov5640_dev *sensor) @@ -1762,7 +2315,6 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) enum ov5640_downsize_mode dn_mode, orig_dn_mode; bool auto_gain = sensor->ctrls.auto_gain->val == 1; bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; - unsigned long rate; int ret; dn_mode = mode->dn_mode; @@ -1781,19 +2333,10 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) goto restore_auto_gain; } - /* - * All the formats we support have 16 bits per pixel, seems to require - * the same rate than YUV, so we can just use 16 bpp all the time. - */ - rate = ov5640_calc_pixel_rate(sensor) * 16; - if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) { - rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes; - ret = ov5640_set_mipi_pclk(sensor, rate); - } else { - rate = rate / sensor->ep.bus.parallel.bus_width; - ret = ov5640_set_dvp_pclk(sensor, rate); - } - + if (ov5640_is_csi2(sensor)) + ret = ov5640_set_mipi_pclk(sensor); + else + ret = ov5640_set_dvp_pclk(sensor); if (ret < 0) return 0; @@ -1860,10 +2403,8 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) int ret; /* first load the initial register values */ - ret = ov5640_load_regs(sensor, &ov5640_mode_init_data); - if (ret < 0) - return ret; - sensor->last_mode = &ov5640_mode_init_data; + ov5640_load_regs(sensor, ov5640_init_setting, + ARRAY_SIZE(ov5640_init_setting)); ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | @@ -2224,7 +2765,7 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, fi->denominator = best_fps; find_mode: - mode = ov5640_find_mode(sensor, rate, width, height, false); + mode = ov5640_find_mode(sensor, width, height, false); return mode ? rate : -EINVAL; } @@ -2260,25 +2801,34 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, { struct ov5640_dev *sensor = to_ov5640_dev(sd); const struct ov5640_mode_info *mode; - int i; + const struct ov5640_pixfmt *pixfmt; + unsigned int bpp; - mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); + mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true); if (!mode) return -EINVAL; - fmt->width = mode->hact; - fmt->height = mode->vact; + + pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code); + bpp = pixfmt->bpp; + + /* + * Adjust mode according to bpp: + * - 8bpp modes work for resolution >= 1280x720 + * - 24bpp modes work resolution < 1280x720 + */ + if (bpp == 8 && mode->width < 1280) + mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720]; + else if (bpp == 24 && mode->width > 1024) + mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768]; + + fmt->width = mode->width; + fmt->height = mode->height; if (new_mode) *new_mode = mode; - for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++) - if (ov5640_formats[i].code == fmt->code) - break; - if (i >= ARRAY_SIZE(ov5640_formats)) - i = 0; - - fmt->code = ov5640_formats[i].code; - fmt->colorspace = ov5640_formats[i].colorspace; + fmt->code = pixfmt->code; + fmt->colorspace = pixfmt->colorspace; fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); @@ -2286,6 +2836,107 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, return 0; } +static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) +{ + const struct ov5640_mode_info *mode = sensor->current_mode; + enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; + struct v4l2_mbus_framefmt *fmt = &sensor->fmt; + const struct ov5640_timings *timings; + s32 exposure_val, exposure_max; + unsigned int hblank; + unsigned int i = 0; + u32 pixel_rate; + s64 link_freq; + u32 num_lanes; + u32 vblank; + u32 bpp; + + /* + * Update the pixel rate control value. + * + * For DVP mode, maintain the pixel rate calculation using fixed FPS. + */ + if (!ov5640_is_csi2(sensor)) { + __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, + ov5640_calc_pixel_rate(sensor)); + + return 0; + } + + /* + * The MIPI CSI-2 link frequency should comply with the CSI-2 + * specification and be lower than 1GHz. + * + * Start from the suggested pixel_rate for the current mode and + * progressively slow it down if it exceeds 1GHz. + */ + num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; + bpp = ov5640_code_to_bpp(sensor, fmt->code); + do { + pixel_rate = ov5640_pixel_rates[pixel_rate_id]; + link_freq = pixel_rate * bpp / (2 * num_lanes); + } while (link_freq >= 1000000000U && + ++pixel_rate_id < OV5640_NUM_PIXEL_RATES); + + sensor->current_link_freq = link_freq; + + /* + * Higher link rates require the clock tree to be programmed with + * 'mipi_div' = 1; this has the effect of halving the actual output + * pixel rate in the MIPI domain. + * + * Adjust the pixel rate and link frequency control value to report it + * correctly to userspace. + */ + if (link_freq > OV5640_LINK_RATE_MAX) { + pixel_rate /= 2; + link_freq /= 2; + } + + for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) { + if (ov5640_csi2_link_freqs[i] == link_freq) + break; + } + WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs)); + + __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate); + __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i); + + timings = ov5640_timings(sensor, mode); + hblank = timings->htot - mode->width; + __v4l2_ctrl_modify_range(sensor->ctrls.hblank, + hblank, hblank, 1, hblank); + + vblank = timings->vblank_def; + + if (sensor->current_fr != mode->def_fps) { + /* + * Compute the vertical blanking according to the framerate + * configured with s_frame_interval. + */ + int fie_num = sensor->frame_interval.numerator; + int fie_denom = sensor->frame_interval.denominator; + + vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) - + mode->height; + } + + __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK, + OV5640_MAX_VTS - mode->height, 1, vblank); + __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank); + + exposure_max = timings->crop.height + vblank - 4; + exposure_val = clamp_t(s32, sensor->ctrls.exposure->val, + sensor->ctrls.exposure->minimum, + exposure_max); + + __v4l2_ctrl_modify_range(sensor->ctrls.exposure, + sensor->ctrls.exposure->minimum, + exposure_max, 1, exposure_val); + + return 0; +} + static int ov5640_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -2316,6 +2967,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, } if (new_mode != sensor->current_mode) { + sensor->current_fr = new_mode->def_fps; sensor->current_mode = new_mode; sensor->pending_mode_change = true; } @@ -2325,80 +2977,70 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, /* update format even if code is unchanged, resolution might change */ sensor->fmt = *mbus_fmt; - __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, - ov5640_calc_pixel_rate(sensor)); + ov5640_update_pixel_rate(sensor); + out: mutex_unlock(&sensor->lock); return ret; } +static int ov5640_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + struct ov5640_dev *sensor = to_ov5640_dev(sd); + const struct ov5640_mode_info *mode = sensor->current_mode; + const struct ov5640_timings *timings; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: { + mutex_lock(&sensor->lock); + timings = ov5640_timings(sensor, mode); + sel->r = timings->analog_crop; + mutex_unlock(&sensor->lock); + + return 0; + } + + case V4L2_SEL_TGT_NATIVE_SIZE: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = OV5640_NATIVE_WIDTH; + sel->r.height = OV5640_NATIVE_HEIGHT; + + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = OV5640_PIXEL_ARRAY_TOP; + sel->r.left = OV5640_PIXEL_ARRAY_LEFT; + sel->r.width = OV5640_PIXEL_ARRAY_WIDTH; + sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT; + + return 0; + } + + return -EINVAL; +} + static int ov5640_set_framefmt(struct ov5640_dev *sensor, struct v4l2_mbus_framefmt *format) { + bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8; + const struct ov5640_pixfmt *pixfmt; int ret = 0; - bool is_jpeg = false; - u8 fmt, mux; - switch (format->code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - case MEDIA_BUS_FMT_UYVY8_2X8: - /* YUV422, UYVY */ - fmt = 0x3f; - mux = OV5640_FMT_MUX_YUV422; - break; - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YUYV8_2X8: - /* YUV422, YUYV */ - fmt = 0x30; - mux = OV5640_FMT_MUX_YUV422; - break; - case MEDIA_BUS_FMT_RGB565_2X8_LE: - /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ - fmt = 0x6F; - mux = OV5640_FMT_MUX_RGB; - break; - case MEDIA_BUS_FMT_RGB565_2X8_BE: - /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ - fmt = 0x61; - mux = OV5640_FMT_MUX_RGB; - break; - case MEDIA_BUS_FMT_JPEG_1X8: - /* YUV422, YUYV */ - fmt = 0x30; - mux = OV5640_FMT_MUX_YUV422; - is_jpeg = true; - break; - case MEDIA_BUS_FMT_SBGGR8_1X8: - /* Raw, BGBG... / GRGR... */ - fmt = 0x00; - mux = OV5640_FMT_MUX_RAW_DPC; - break; - case MEDIA_BUS_FMT_SGBRG8_1X8: - /* Raw bayer, GBGB... / RGRG... */ - fmt = 0x01; - mux = OV5640_FMT_MUX_RAW_DPC; - break; - case MEDIA_BUS_FMT_SGRBG8_1X8: - /* Raw bayer, GRGR... / BGBG... */ - fmt = 0x02; - mux = OV5640_FMT_MUX_RAW_DPC; - break; - case MEDIA_BUS_FMT_SRGGB8_1X8: - /* Raw bayer, RGRG... / GBGB... */ - fmt = 0x03; - mux = OV5640_FMT_MUX_RAW_DPC; - break; - default: - return -EINVAL; - } + pixfmt = ov5640_code_to_pixfmt(sensor, format->code); /* FORMAT CONTROL00: YUV and RGB formatting */ - ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); + ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, + pixfmt->ctrl00); if (ret) return ret; /* FORMAT MUX CONTROL: ISP YUV or RGB */ - ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); + ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, + pixfmt->mux); if (ret) return ret; @@ -2655,6 +3297,15 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) (BIT(2) | BIT(1)) : 0); } +static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value) +{ + const struct ov5640_mode_info *mode = sensor->current_mode; + + /* Update the VTOT timing register value. */ + return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, + mode->height + value); +} + static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); @@ -2685,10 +3336,25 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = ctrl_to_sd(ctrl); struct ov5640_dev *sensor = to_ov5640_dev(sd); + const struct ov5640_mode_info *mode = sensor->current_mode; + const struct ov5640_timings *timings; + unsigned int exp_max; int ret; /* v4l2_ctrl_lock() locks our own mutex */ + switch (ctrl->id) { + case V4L2_CID_VBLANK: + /* Update the exposure range to the newly programmed vblank. */ + timings = ov5640_timings(sensor, mode); + exp_max = mode->height + ctrl->val - 4; + __v4l2_ctrl_modify_range(sensor->ctrls.exposure, + sensor->ctrls.exposure->minimum, + exp_max, sensor->ctrls.exposure->step, + timings->vblank_def); + break; + } + /* * If the device is not powered up by the host driver do * not apply any controls to H/W at this time. Instead @@ -2728,6 +3394,9 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_VFLIP: ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); break; + case V4L2_CID_VBLANK: + ret = ov5640_set_ctrl_vblank(sensor, ctrl->val); + break; default: ret = -EINVAL; break; @@ -2743,9 +3412,14 @@ static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { static int ov5640_init_controls(struct ov5640_dev *sensor) { + const struct ov5640_mode_info *mode = sensor->current_mode; const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; struct ov5640_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *hdl = &ctrls->handler; + struct v4l2_fwnode_device_properties props; + const struct ov5640_timings *timings; + unsigned int max_vblank; + unsigned int hblank; int ret; v4l2_ctrl_handler_init(hdl, 32); @@ -2755,8 +3429,25 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) /* Clock related controls */ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, - 0, INT_MAX, 1, - ov5640_calc_pixel_rate(sensor)); + ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1], + ov5640_pixel_rates[0], 1, + ov5640_pixel_rates[mode->pixel_rate]); + + ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(ov5640_csi2_link_freqs) - 1, + OV5640_DEFAULT_LINK_FREQ, + ov5640_csi2_link_freqs); + + timings = ov5640_timings(sensor, mode); + hblank = timings->htot - mode->width; + ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank, + hblank, 1, hblank); + + max_vblank = OV5640_MAX_VTS - mode->height; + ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, + OV5640_MIN_VBLANK, max_vblank, + 1, timings->vblank_def); /* Auto/manual white balance */ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, @@ -2805,7 +3496,20 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) goto free_ctrls; } + ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props); + if (ret) + goto free_ctrls; + + if (props.rotation == 180) + sensor->upside_down = true; + + ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props); + if (ret) + goto free_ctrls; + ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; @@ -2825,16 +3529,29 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { + struct ov5640_dev *sensor = to_ov5640_dev(sd); + u32 bpp = ov5640_code_to_bpp(sensor, fse->code); + unsigned int index = fse->index; + if (fse->pad != 0) return -EINVAL; - if (fse->index >= OV5640_NUM_MODES) + if (!bpp) + return -EINVAL; + + /* Only low-resolution modes are supported for 24bpp formats. */ + if (bpp == 24 && index >= OV5640_MODE_720P_1280_720) + return -EINVAL; + + /* FIXME: Low resolution modes don't work in 8bpp formats. */ + if (bpp == 8) + index += OV5640_MODE_720P_1280_720; + + if (index >= OV5640_NUM_MODES) return -EINVAL; - fse->min_width = - ov5640_mode_data[fse->index].hact; + fse->min_width = ov5640_mode_data[index].width; fse->max_width = fse->min_width; - fse->min_height = - ov5640_mode_data[fse->index].vact; + fse->min_height = ov5640_mode_data[index].height; fse->max_height = fse->min_height; return 0; @@ -2898,20 +3615,25 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, mode = sensor->current_mode; frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, - mode->hact, mode->vact); + mode->width, + mode->height); if (frame_rate < 0) { /* Always return a valid frame interval value */ fi->interval = sensor->frame_interval; goto out; } - mode = ov5640_find_mode(sensor, frame_rate, mode->hact, - mode->vact, true); + mode = ov5640_find_mode(sensor, mode->width, mode->height, true); if (!mode) { ret = -EINVAL; goto out; } + if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) { + ret = -EINVAL; + goto out; + } + if (mode != sensor->current_mode || frame_rate != sensor->current_fr) { sensor->current_fr = frame_rate; @@ -2919,8 +3641,7 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, sensor->current_mode = mode; sensor->pending_mode_change = true; - __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, - ov5640_calc_pixel_rate(sensor)); + ov5640_update_pixel_rate(sensor); } out: mutex_unlock(&sensor->lock); @@ -2931,12 +3652,23 @@ static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - if (code->pad != 0) - return -EINVAL; - if (code->index >= ARRAY_SIZE(ov5640_formats)) + struct ov5640_dev *sensor = to_ov5640_dev(sd); + const struct ov5640_pixfmt *formats; + unsigned int num_formats; + + if (ov5640_is_csi2(sensor)) { + formats = ov5640_csi2_formats; + num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1; + } else { + formats = ov5640_dvp_formats; + num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1; + } + + if (code->index >= num_formats) return -EINVAL; - code->code = ov5640_formats[code->index].code; + code->code = formats[code->index].code; + return 0; } @@ -2961,7 +3693,7 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) sensor->pending_fmt_change = false; } - if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) + if (ov5640_is_csi2(sensor)) ret = ov5640_set_stream_mipi(sensor, enable); else ret = ov5640_set_stream_dvp(sensor, enable); @@ -2974,6 +3706,23 @@ out: return ret; } +static int ov5640_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_get_try_format(sd, state, 0); + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0); + + *fmt = ov5640_default_fmt; + + crop->left = OV5640_PIXEL_ARRAY_LEFT; + crop->top = OV5640_PIXEL_ARRAY_TOP; + crop->width = OV5640_PIXEL_ARRAY_WIDTH; + crop->height = OV5640_PIXEL_ARRAY_HEIGHT; + + return 0; +} + static const struct v4l2_subdev_core_ops ov5640_core_ops = { .s_power = ov5640_s_power, .log_status = v4l2_ctrl_subdev_log_status, @@ -2988,9 +3737,11 @@ static const struct v4l2_subdev_video_ops ov5640_video_ops = { }; static const struct v4l2_subdev_pad_ops ov5640_pad_ops = { + .init_cfg = ov5640_init_cfg, .enum_mbus_code = ov5640_enum_mbus_code, .get_fmt = ov5640_get_fmt, .set_fmt = ov5640_set_fmt, + .get_selection = ov5640_get_selection, .enum_frame_size = ov5640_enum_frame_size, .enum_frame_interval = ov5640_enum_frame_interval, }; @@ -3046,8 +3797,6 @@ static int ov5640_probe(struct i2c_client *client) struct device *dev = &client->dev; struct fwnode_handle *endpoint; struct ov5640_dev *sensor; - struct v4l2_mbus_framefmt *fmt; - u32 rotation; int ret; sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); @@ -3060,40 +3809,17 @@ static int ov5640_probe(struct i2c_client *client) * default init sequence initialize sensor to * YUV422 UYVY VGA@30fps */ - fmt = &sensor->fmt; - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); - fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); - fmt->width = 640; - fmt->height = 480; - fmt->field = V4L2_FIELD_NONE; + sensor->fmt = ov5640_default_fmt; sensor->frame_interval.numerator = 1; sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; sensor->current_fr = OV5640_30_FPS; sensor->current_mode = &ov5640_mode_data[OV5640_MODE_VGA_640_480]; sensor->last_mode = sensor->current_mode; + sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ; sensor->ae_target = 52; - /* optional indication of physical rotation of sensor */ - ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation", - &rotation); - if (!ret) { - switch (rotation) { - case 180: - sensor->upside_down = true; - fallthrough; - case 0: - break; - default: - dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n", - rotation); - } - } - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); if (!endpoint) { diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 117ff5403312..82a9b2de7735 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -127,11 +127,16 @@ #define OV5693_LINK_FREQ_419_2MHZ 419200000 #define OV5693_PIXEL_RATE 167680000 -/* Miscellaneous */ -#define OV5693_NUM_SUPPLIES 2 - #define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd) +static const char * const ov5693_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital circuit power */ +}; + +#define OV5693_NUM_SUPPLIES ARRAY_SIZE(ov5693_supply_names) + struct ov5693_reg { u32 reg; u8 val; @@ -152,7 +157,7 @@ struct ov5693_device { struct gpio_desc *reset; struct gpio_desc *powerdown; struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES]; - struct clk *clk; + struct clk *xvclk; struct ov5693_mode { struct v4l2_rect crop; @@ -352,11 +357,6 @@ static const s64 link_freq_menu_items[] = { OV5693_LINK_FREQ_419_2MHZ }; -static const char * const ov5693_supply_names[] = { - "avdd", - "dovdd", -}; - static const char * const ov5693_test_pattern_menu[] = { "Disabled", "Random Data", @@ -794,7 +794,7 @@ static void ov5693_sensor_powerdown(struct ov5693_device *ov5693) regulator_bulk_disable(OV5693_NUM_SUPPLIES, ov5693->supplies); - clk_disable_unprepare(ov5693->clk); + clk_disable_unprepare(ov5693->xvclk); } static int ov5693_sensor_powerup(struct ov5693_device *ov5693) @@ -804,7 +804,7 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693) gpiod_set_value_cansleep(ov5693->reset, 1); gpiod_set_value_cansleep(ov5693->powerdown, 1); - ret = clk_prepare_enable(ov5693->clk); + ret = clk_prepare_enable(ov5693->xvclk); if (ret) { dev_err(ov5693->dev, "Failed to enable clk\n"); goto fail_power; @@ -1390,7 +1390,7 @@ out_free_bus_cfg: static int ov5693_probe(struct i2c_client *client) { struct ov5693_device *ov5693; - u32 clk_rate; + u32 xvclk_rate; int ret = 0; ov5693 = devm_kzalloc(&client->dev, sizeof(*ov5693), GFP_KERNEL); @@ -1408,16 +1408,28 @@ static int ov5693_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops); - ov5693->clk = devm_clk_get(&client->dev, "xvclk"); - if (IS_ERR(ov5693->clk)) { - dev_err(&client->dev, "Error getting clock\n"); - return PTR_ERR(ov5693->clk); + ov5693->xvclk = devm_clk_get_optional(&client->dev, "xvclk"); + if (IS_ERR(ov5693->xvclk)) + return dev_err_probe(&client->dev, PTR_ERR(ov5693->xvclk), + "failed to get xvclk: %ld\n", + PTR_ERR(ov5693->xvclk)); + + if (ov5693->xvclk) { + xvclk_rate = clk_get_rate(ov5693->xvclk); + } else { + ret = fwnode_property_read_u32(dev_fwnode(&client->dev), + "clock-frequency", + &xvclk_rate); + + if (ret) { + dev_err(&client->dev, "can't get clock frequency"); + return ret; + } } - clk_rate = clk_get_rate(ov5693->clk); - if (clk_rate != OV5693_XVCLK_FREQ) + if (xvclk_rate != OV5693_XVCLK_FREQ) dev_warn(&client->dev, "Found clk freq %u, expected %u\n", - clk_rate, OV5693_XVCLK_FREQ); + xvclk_rate, OV5693_XVCLK_FREQ); ret = ov5693_configure_gpios(ov5693); if (ret) @@ -1521,10 +1533,17 @@ static const struct acpi_device_id ov5693_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); +static const struct of_device_id ov5693_of_match[] = { + { .compatible = "ovti,ov5693", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov5693_of_match); + static struct i2c_driver ov5693_driver = { .driver = { .name = "ov5693", .acpi_match_table = ov5693_acpi_match, + .of_match_table = ov5693_of_match, .pm = &ov5693_pm_ops, }, .probe_new = ov5693_probe, diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 0e7be15bc20a..1bd797c7926b 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -934,6 +934,8 @@ static int ov7251_set_power_on(struct device *dev) ARRAY_SIZE(ov7251_global_init_setting)); if (ret < 0) { dev_err(ov7251->dev, "error during global init\n"); + gpiod_set_value_cansleep(ov7251->enable_gpio, 0); + clk_disable_unprepare(ov7251->xclk); ov7251_regulators_disable(ov7251); return ret; } @@ -1340,7 +1342,7 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) if (enable) { ret = pm_runtime_get_sync(ov7251->dev); if (ret < 0) - goto unlock_out; + goto err_power_down; ret = ov7251_pll_configure(ov7251); if (ret) { @@ -1372,12 +1374,11 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) pm_runtime_put(ov7251->dev); } -unlock_out: mutex_unlock(&ov7251->lock); return ret; err_power_down: - pm_runtime_put_noidle(ov7251->dev); + pm_runtime_put(ov7251->dev); mutex_unlock(&ov7251->lock); return ret; } diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index ef976d085d72..16cc547976dd 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -50,6 +50,7 @@ /* Bits definition for MIPID02_MODE_REG2 */ #define MODE_HSYNC_ACTIVE_HIGH BIT(1) #define MODE_VSYNC_ACTIVE_HIGH BIT(2) +#define MODE_PCLK_SAMPLE_RISING BIT(3) /* Bits definition for MIPID02_DATA_SELECTION_CTRL */ #define SELECTION_MANUAL_DATA BIT(2) #define SELECTION_MANUAL_WIDTH BIT(3) @@ -61,9 +62,12 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, - MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24, + MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24, MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, - MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_JPEG_1X8 }; @@ -130,9 +134,15 @@ static int bpp_from_code(__u32 code) case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: return 12; + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YVYU8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_VYUY8_1X16: + case MEDIA_BUS_FMT_RGB565_1X16: case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_RGB565_2X8_LE: case MEDIA_BUS_FMT_RGB565_2X8_BE: return 16; @@ -161,12 +171,18 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: return 0x2c; + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_YVYU8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_VYUY8_1X16: case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: return 0x1e; case MEDIA_BUS_FMT_BGR888_1X24: return 0x24; + case MEDIA_BUS_FMT_RGB565_1X16: case MEDIA_BUS_FMT_RGB565_2X8_LE: case MEDIA_BUS_FMT_RGB565_2X8_BE: return 0x22; @@ -201,8 +217,16 @@ static __u32 get_fmt_code(__u32 code) static __u32 serial_to_parallel_code(__u32 serial) { + if (serial == MEDIA_BUS_FMT_RGB565_1X16) + return MEDIA_BUS_FMT_RGB565_2X8_LE; + if (serial == MEDIA_BUS_FMT_YUYV8_1X16) + return MEDIA_BUS_FMT_YUYV8_2X8; + if (serial == MEDIA_BUS_FMT_YVYU8_1X16) + return MEDIA_BUS_FMT_YVYU8_2X8; if (serial == MEDIA_BUS_FMT_UYVY8_1X16) return MEDIA_BUS_FMT_UYVY8_2X8; + if (serial == MEDIA_BUS_FMT_VYUY8_1X16) + return MEDIA_BUS_FMT_VYUY8_2X8; if (serial == MEDIA_BUS_FMT_BGR888_1X24) return MEDIA_BUS_FMT_BGR888_3X8; @@ -494,6 +518,8 @@ static int mipid02_configure_from_tx(struct mipid02_dev *bridge) bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH; if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH; + if (ep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + bridge->r.mode_reg2 |= MODE_PCLK_SAMPLE_RISING; return 0; } diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 8fafce26d62f..0de7acdf58a7 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2798,6 +2798,7 @@ err_free_mutex: cancel_delayed_work(&state->delayed_work_enable_hpd); mutex_destroy(&state->page_lock); mutex_destroy(&state->lock); + tda1997x_set_power(state, 0); err_free_state: kfree(state); dev_err(&client->dev, "%s failed: %d\n", __func__, ret); diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 65472438444b..93a980c4e899 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1285,7 +1285,7 @@ static int tvp5150_disable_all_input_links(struct tvp5150 *decoder) int err; for (i = 0; i < TVP5150_NUM_PADS - 1; i++) { - connector_pad = media_entity_remote_pad(&decoder->pads[i]); + connector_pad = media_pad_remote_pad_first(&decoder->pads[i]); if (!connector_pad) continue; diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 11f5207f73aa..afd1bd7ff7b6 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -9,6 +9,7 @@ */ #include <linux/bitmap.h> +#include <linux/list.h> #include <linux/property.h> #include <linux/slab.h> #include <media/media-entity.h> @@ -449,7 +450,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity, bitmap_zero(active, entity->num_pads); bitmap_fill(has_no_links, entity->num_pads); - list_for_each_entry(link, &entity->links, list) { + for_each_media_entity_data_link(entity, link) { struct media_pad *pad = link->sink->entity == entity ? link->sink : link->source; @@ -888,7 +889,7 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink) { struct media_link *link; - list_for_each_entry(link, &source->entity->links, list) { + for_each_media_entity_data_link(source->entity, link) { if (link->source->entity == source->entity && link->source->index == source->index && link->sink->entity == sink->entity && @@ -900,11 +901,11 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink) } EXPORT_SYMBOL_GPL(media_entity_find_link); -struct media_pad *media_entity_remote_pad(const struct media_pad *pad) +struct media_pad *media_pad_remote_pad_first(const struct media_pad *pad) { struct media_link *link; - list_for_each_entry(link, &pad->entity->links, list) { + for_each_media_entity_data_link(pad->entity, link) { if (!(link->flags & MEDIA_LNK_FL_ENABLED)) continue; @@ -918,7 +919,77 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad) return NULL; } -EXPORT_SYMBOL_GPL(media_entity_remote_pad); +EXPORT_SYMBOL_GPL(media_pad_remote_pad_first); + +struct media_pad * +media_entity_remote_pad_unique(const struct media_entity *entity, + unsigned int type) +{ + struct media_pad *pad = NULL; + struct media_link *link; + + list_for_each_entry(link, &entity->links, list) { + struct media_pad *local_pad; + struct media_pad *remote_pad; + + if (((link->flags & MEDIA_LNK_FL_LINK_TYPE) != + MEDIA_LNK_FL_DATA_LINK) || + !(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + if (type == MEDIA_PAD_FL_SOURCE) { + local_pad = link->sink; + remote_pad = link->source; + } else { + local_pad = link->source; + remote_pad = link->sink; + } + + if (local_pad->entity == entity) { + if (pad) + return ERR_PTR(-ENOTUNIQ); + + pad = remote_pad; + } + } + + if (!pad) + return ERR_PTR(-ENOLINK); + + return pad; +} +EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique); + +struct media_pad *media_pad_remote_pad_unique(const struct media_pad *pad) +{ + struct media_pad *found_pad = NULL; + struct media_link *link; + + list_for_each_entry(link, &pad->entity->links, list) { + struct media_pad *remote_pad; + + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + if (link->sink == pad) + remote_pad = link->source; + else if (link->source == pad) + remote_pad = link->sink; + else + continue; + + if (found_pad) + return ERR_PTR(-ENOTUNIQ); + + found_pad = remote_pad; + } + + if (!found_pad) + return ERR_PTR(-ENOLINK); + + return found_pad; +} +EXPORT_SYMBOL_GPL(media_pad_remote_pad_unique); static void media_interface_init(struct media_device *mdev, struct media_interface *intf, @@ -1051,3 +1122,18 @@ struct media_link *media_create_ancillary_link(struct media_entity *primary, return link; } EXPORT_SYMBOL_GPL(media_create_ancillary_link); + +struct media_link *__media_entity_next_link(struct media_entity *entity, + struct media_link *link, + unsigned long link_type) +{ + link = link ? list_next_entry(link, list) + : list_first_entry(&entity->links, typeof(*link), list); + + list_for_each_entry_from(link, &entity->links, list) + if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == link_type) + return link; + + return NULL; +} +EXPORT_SYMBOL_GPL(__media_entity_next_link); diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index 76e5a504df8c..d3358643fb7d 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -180,7 +180,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd) */ cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000); - /* Setup the Video and and Aux/Audio PLLs */ + /* Setup the Video and Aux/Audio PLLs */ cx18_av_init(cx); /* set video to auto-detect */ diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 89d4d5a3ba34..52be42f9a7fa 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -618,12 +618,24 @@ EXPORT_SYMBOL(cx88_reset); static inline unsigned int norm_swidth(v4l2_std_id norm) { - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; + if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) + return 754; + + if (norm & V4L2_STD_PAL_Nc) + return 745; + + return 922; } static inline unsigned int norm_hdelay(v4l2_std_id norm) { - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186; + if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) + return 135; + + if (norm & V4L2_STD_PAL_Nc) + return 149; + + return 186; } static inline unsigned int norm_vdelay(v4l2_std_id norm) @@ -636,7 +648,7 @@ static inline unsigned int norm_fsc8(v4l2_std_id norm) if (norm & V4L2_STD_PAL_M) return 28604892; // 3.575611 MHz - if (norm & (V4L2_STD_PAL_Nc)) + if (norm & V4L2_STD_PAL_Nc) return 28656448; // 3.582056 MHz if (norm & V4L2_STD_NTSC) // All NTSC/M and variants @@ -841,8 +853,8 @@ static int set_tvaudio(struct cx88_core *core) } else if (V4L2_STD_SECAM_DK & norm) { core->tvaudio = WW_DK; - } else if ((V4L2_STD_NTSC_M & norm) || - (V4L2_STD_PAL_M & norm)) { + } else if ((V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL_Nc) & + norm) { core->tvaudio = WW_BTSC; } else if (V4L2_STD_NTSC_M_JP & norm) { diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 377991095aba..ee20813c33ff 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Marcus Metzler <mocm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "ddbridge.h" diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.h b/drivers/media/pci/ddbridge/ddbridge-ci.h index cc98656af349..41cd97e52aa1 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.h +++ b/drivers/media/pci/ddbridge/ddbridge-ci.h @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Marcus Metzler <mocm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DDBRIDGE_CI_H__ diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 92fe051c672f..fe833f39698a 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Marcus Metzler <mocm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.c b/drivers/media/pci/ddbridge/ddbridge-hw.c index f9c91bdbd041..d7d9cd0dad23 100644 --- a/drivers/media/pci/ddbridge/ddbridge-hw.c +++ b/drivers/media/pci/ddbridge/ddbridge-hw.c @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "ddbridge.h" diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.h b/drivers/media/pci/ddbridge/ddbridge-hw.h index e34bd94c266b..934f296f48c0 100644 --- a/drivers/media/pci/ddbridge/ddbridge-hw.h +++ b/drivers/media/pci/ddbridge/ddbridge-hw.h @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DDBRIDGE_HW_H_ @@ -40,4 +31,4 @@ struct ddb_device_id { const struct ddb_info *get_ddb_info(u16 vendor, u16 device, u16 subvendor, u16 subdevice); -#endif /* _DDBRIDGE_HW_H */ +#endif /* _DDBRIDGE_HW_H_ */ diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.c b/drivers/media/pci/ddbridge/ddbridge-i2c.c index aafa6030c8cc..c894be180446 100644 --- a/drivers/media/pci/ddbridge/ddbridge-i2c.c +++ b/drivers/media/pci/ddbridge/ddbridge-i2c.c @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.h b/drivers/media/pci/ddbridge/ddbridge-i2c.h index 90830f7b1638..48555d41aa48 100644 --- a/drivers/media/pci/ddbridge/ddbridge-i2c.h +++ b/drivers/media/pci/ddbridge/ddbridge-i2c.h @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DDBRIDGE_I2C_H__ diff --git a/drivers/media/pci/ddbridge/ddbridge-io.h b/drivers/media/pci/ddbridge/ddbridge-io.h index 1a5b31b52494..991246cecee2 100644 --- a/drivers/media/pci/ddbridge/ddbridge-io.h +++ b/drivers/media/pci/ddbridge/ddbridge-io.h @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DDBRIDGE_IO_H__ diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c index 25d0d6745b52..91733ab9f58c 100644 --- a/drivers/media/pci/ddbridge/ddbridge-main.c +++ b/drivers/media/pci/ddbridge/ddbridge-main.c @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/media/pci/ddbridge/ddbridge-max.c b/drivers/media/pci/ddbridge/ddbridge-max.c index 576dd2318e4d..0582b86bb869 100644 --- a/drivers/media/pci/ddbridge/ddbridge-max.c +++ b/drivers/media/pci/ddbridge/ddbridge-max.c @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> diff --git a/drivers/media/pci/ddbridge/ddbridge-max.h b/drivers/media/pci/ddbridge/ddbridge-max.h index 6543dfc77138..da1553fe8695 100644 --- a/drivers/media/pci/ddbridge/ddbridge-max.h +++ b/drivers/media/pci/ddbridge/ddbridge-max.h @@ -5,15 +5,6 @@ * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DDBRIDGE_MAX_H_ @@ -27,4 +18,4 @@ int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm); int ddb_fe_attach_mxl5xx(struct ddb_input *input); int ddb_fe_attach_mci(struct ddb_input *input, u32 type); -#endif /* _DDBRIDGE_MAX_H */ +#endif /* _DDBRIDGE_MAX_H_ */ diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.c b/drivers/media/pci/ddbridge/ddbridge-mci.c index 97384ae9ad27..a006cb0fa199 100644 --- a/drivers/media/pci/ddbridge/ddbridge-mci.c +++ b/drivers/media/pci/ddbridge/ddbridge-mci.c @@ -5,15 +5,6 @@ * Copyright (C) 2017-2018 Digital Devices GmbH * Ralph Metzler <rjkm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "ddbridge.h" diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.h b/drivers/media/pci/ddbridge/ddbridge-mci.h index 24241111c634..d9799fbf59d4 100644 --- a/drivers/media/pci/ddbridge/ddbridge-mci.h +++ b/drivers/media/pci/ddbridge/ddbridge-mci.h @@ -5,15 +5,6 @@ * Copyright (C) 2017-2018 Digital Devices GmbH * Marcus Metzler <mocm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DDBRIDGE_MCI_H_ diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h index 2942a7f35099..42256fc9695d 100644 --- a/drivers/media/pci/ddbridge/ddbridge-regs.h +++ b/drivers/media/pci/ddbridge/ddbridge-regs.h @@ -3,15 +3,6 @@ * ddbridge-regs.h: Digital Devices PCIe bridge driver * * Copyright (C) 2010-2017 Digital Devices GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DDBRIDGE_REGS_H__ diff --git a/drivers/media/pci/ddbridge/ddbridge-sx8.c b/drivers/media/pci/ddbridge/ddbridge-sx8.c index 374fcee94960..c8de8d283f85 100644 --- a/drivers/media/pci/ddbridge/ddbridge-sx8.c +++ b/drivers/media/pci/ddbridge/ddbridge-sx8.c @@ -5,15 +5,6 @@ * Copyright (C) 2018 Digital Devices GmbH * Marcus Metzler <mocm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "ddbridge.h" diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index b834449e78f8..f3699dbd193f 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -4,15 +4,6 @@ * * Copyright (C) 2010-2017 Digital Devices GmbH * Ralph Metzler <rmetzler@digitaldevices.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DDBRIDGE_H_ @@ -379,4 +370,4 @@ void ddb_unmap(struct ddb *dev); int ddb_exit_ddbridge(int stage, int error); int ddb_init_ddbridge(void); -#endif /* DDBRIDGE_H */ +#endif /* _DDBRIDGE_H_ */ diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index dbdbdb648a0d..a3fe547b7fce 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1323,7 +1323,7 @@ static int cio2_video_link_validate(struct media_link *link) struct v4l2_subdev_format source_fmt; int ret; - if (!media_entity_remote_pad(entity->pads)) { + if (!media_pad_remote_pad_first(entity->pads)) { dev_info(dev, "video node %s pad not connected\n", vd->name); return -ENOTCONN; } diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index 5526bcc7a9bd..965d285a9240 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -801,7 +801,7 @@ int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen) if (buflen < 128) return -ENOMEM; - /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */ + /* Assumption: Hauppauge eeprom is at 0xa0 on bus 0 */ /* TODO: Pull the details from the boards struct */ return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg), ®[0], 128, buf); diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index a96e170ab04e..118b922c08c3 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" - depends on PCI && VIDEO_DEV && VIRT_TO_BUS && I2C + depends on PCI && VIDEO_DEV && I2C depends on STA2X11 || COMPILE_TEST select GPIOLIB if MEDIA_SUBDRV_AUTOSELECT select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c index 5cae73e6fb9c..560ff1ddcc83 100644 --- a/drivers/media/pci/tw5864/tw5864-core.c +++ b/drivers/media/pci/tw5864/tw5864-core.c @@ -254,9 +254,9 @@ static int tw5864_initdev(struct pci_dev *pci_dev, /* pci init */ dev->pci = pci_dev; - err = pci_enable_device(pci_dev); + err = pcim_enable_device(pci_dev); if (err) { - dev_err(&dev->pci->dev, "pci_enable_device() failed\n"); + dev_err(&dev->pci->dev, "pcim_enable_device() failed\n"); goto unreg_v4l2; } @@ -265,21 +265,16 @@ static int tw5864_initdev(struct pci_dev *pci_dev, err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { dev_err(&dev->pci->dev, "32 bit PCI DMA is not supported\n"); - goto disable_pci; + goto unreg_v4l2; } /* get mmio */ - err = pci_request_regions(pci_dev, dev->name); + err = pcim_iomap_regions(pci_dev, BIT(0), dev->name); if (err) { dev_err(&dev->pci->dev, "Cannot request regions for MMIO\n"); - goto disable_pci; - } - dev->mmio = pci_ioremap_bar(pci_dev, 0); - if (!dev->mmio) { - err = -EIO; - dev_err(&dev->pci->dev, "can't ioremap() MMIO memory\n"); - goto release_mmio; + goto unreg_v4l2; } + dev->mmio = pcim_iomap_table(pci_dev)[0]; spin_lock_init(&dev->slock); @@ -291,7 +286,7 @@ static int tw5864_initdev(struct pci_dev *pci_dev, err = tw5864_video_init(dev, video_nr); if (err) - goto unmap_mmio; + goto unreg_v4l2; /* get irq */ err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw5864_isr, @@ -308,12 +303,6 @@ static int tw5864_initdev(struct pci_dev *pci_dev, fini_video: tw5864_video_fini(dev); -unmap_mmio: - iounmap(dev->mmio); -release_mmio: - pci_release_regions(pci_dev); -disable_pci: - pci_disable_device(pci_dev); unreg_v4l2: v4l2_device_unregister(&dev->v4l2_dev); return err; @@ -331,11 +320,6 @@ static void tw5864_finidev(struct pci_dev *pci_dev) /* unregister */ tw5864_video_fini(dev); - /* release resources */ - iounmap(dev->mmio); - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); - v4l2_device_unregister(&dev->v4l2_dev); } diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index 6676e069b515..c53099c958ca 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -315,13 +315,6 @@ static int tw686x_probe(struct pci_dev *pci_dev, spin_lock_init(&dev->lock); - err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED, - dev->name, dev); - if (err < 0) { - dev_err(&pci_dev->dev, "unable to request interrupt\n"); - goto iounmap; - } - timer_setup(&dev->dma_delay_timer, tw686x_dma_delay, 0); /* @@ -333,18 +326,26 @@ static int tw686x_probe(struct pci_dev *pci_dev, err = tw686x_video_init(dev); if (err) { dev_err(&pci_dev->dev, "can't register video\n"); - goto free_irq; + goto iounmap; } err = tw686x_audio_init(dev); if (err) dev_warn(&pci_dev->dev, "can't register audio\n"); + err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED, + dev->name, dev); + if (err < 0) { + dev_err(&pci_dev->dev, "unable to request interrupt\n"); + goto tw686x_free; + } + pci_set_drvdata(pci_dev, dev); return 0; -free_irq: - free_irq(pci_dev->irq, dev); +tw686x_free: + tw686x_video_free(dev); + tw686x_audio_free(dev); iounmap: pci_iounmap(pci_dev, dev->mmio); free_region: diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 6344a479119f..3ebf7a2c95f0 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -1280,8 +1280,10 @@ int tw686x_video_init(struct tw686x_dev *dev) video_set_drvdata(vdev, vc); err = video_register_device(vdev, VFL_TYPE_VIDEO, -1); - if (err < 0) + if (err < 0) { + video_device_release(vdev); goto error; + } vc->num = vdev->num; } diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 3c02aa2a54aa..9e64041cc1c1 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -63,6 +63,7 @@ struct vdec_t { bool is_source_changed; u32 source_change; u32 drain; + bool aborting; }; static const struct vpu_format vdec_formats[] = { @@ -104,7 +105,6 @@ static const struct vpu_format vdec_formats[] = { .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION }, { .pixfmt = V4L2_PIX_FMT_MPEG2, @@ -178,16 +178,6 @@ static int vdec_ctrl_init(struct vpu_inst *inst) return 0; } -static void vdec_set_last_buffer_dequeued(struct vpu_inst *inst) -{ - struct vdec_t *vdec = inst->priv; - - if (vdec->eos_received) { - if (!vpu_set_last_buffer_dequeued(inst)) - vdec->eos_received--; - } -} - static void vdec_handle_resolution_change(struct vpu_inst *inst) { struct vdec_t *vdec = inst->priv; @@ -234,6 +224,21 @@ static int vdec_update_state(struct vpu_inst *inst, enum vpu_codec_state state, return 0; } +static void vdec_set_last_buffer_dequeued(struct vpu_inst *inst) +{ + struct vdec_t *vdec = inst->priv; + + if (inst->state == VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) + return; + + if (vdec->eos_received) { + if (!vpu_set_last_buffer_dequeued(inst)) { + vdec->eos_received--; + vdec_update_state(inst, VPU_CODEC_STATE_DRAIN, 0); + } + } +} + static int vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { strscpy(cap->driver, "amphion-vpu", sizeof(cap->driver)); @@ -493,6 +498,8 @@ static int vdec_drain(struct vpu_inst *inst) static int vdec_cmd_start(struct vpu_inst *inst) { + struct vdec_t *vdec = inst->priv; + switch (inst->state) { case VPU_CODEC_STATE_STARTED: case VPU_CODEC_STATE_DRAIN: @@ -503,6 +510,8 @@ static int vdec_cmd_start(struct vpu_inst *inst) break; } vpu_process_capture_buffer(inst); + if (vdec->eos_received) + vdec_set_last_buffer_dequeued(inst); return 0; } @@ -731,6 +740,7 @@ static void vdec_stop_done(struct vpu_inst *inst) vdec->eos_received = 0; vdec->is_source_changed = false; vdec->source_change = 0; + inst->total_input_count = 0; vpu_inst_unlock(inst); } @@ -939,6 +949,9 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb if (inst->state != VPU_CODEC_STATE_ACTIVE) return -EINVAL; + if (vdec->aborting) + return -EINVAL; + if (!vdec->req_frame_count) return -EINVAL; @@ -1048,6 +1061,8 @@ static void vdec_clear_slots(struct vpu_inst *inst) vpu_buf = vdec->slots[i]; vbuf = &vpu_buf->m2m_buf.vb; + vpu_trace(inst->dev, "clear slot %d\n", i); + vdec_response_fs_release(inst, i, vpu_buf->tag); vdec_recycle_buffer(inst, vbuf); vdec->slots[i]->state = VPU_BUF_STATE_IDLE; vdec->slots[i] = NULL; @@ -1203,7 +1218,6 @@ static void vdec_event_eos(struct vpu_inst *inst) vdec->eos_received++; vdec->fixed_fmt = false; inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP; - vdec_update_state(inst, VPU_CODEC_STATE_DRAIN, 0); vdec_set_last_buffer_dequeued(inst); vpu_inst_unlock(inst); } @@ -1310,6 +1324,8 @@ static void vdec_abort(struct vpu_inst *inst) int ret; vpu_trace(inst->dev, "[%d] state = %d\n", inst->id, inst->state); + + vdec->aborting = true; vpu_iface_add_scode(inst, SCODE_PADDING_ABORT); vdec->params.end_flag = 1; vpu_iface_set_decode_params(inst, &vdec->params, 1); @@ -1333,6 +1349,7 @@ static void vdec_abort(struct vpu_inst *inst) vdec->decoded_frame_count = 0; vdec->display_frame_count = 0; vdec->sequence = 0; + vdec->aborting = false; } static void vdec_stop(struct vpu_inst *inst, bool free) @@ -1369,8 +1386,7 @@ static void vdec_cleanup(struct vpu_inst *inst) return; vdec = inst->priv; - if (vdec) - vfree(vdec); + vfree(vdec); inst->priv = NULL; vfree(inst); } @@ -1480,10 +1496,10 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type) vdec_update_state(inst, VPU_CODEC_STATE_SEEK, 0); vdec->drain = 0; } else { - if (inst->state != VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) + if (inst->state != VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) { vdec_abort(inst); - - vdec->eos_received = 0; + vdec->eos_received = 0; + } vdec_clear_slots(inst); } diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 43d61d82f58c..461524dd1e44 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -919,8 +919,7 @@ static void venc_cleanup(struct vpu_inst *inst) return; venc = inst->priv; - if (venc) - vfree(venc); + vfree(venc); inst->priv = NULL; vfree(inst); } diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h index e56b96a7e5d3..f914de6ed81e 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -258,6 +258,7 @@ struct vpu_inst { struct vpu_format cap_format; u32 min_buffer_cap; u32 min_buffer_out; + u32 total_input_count; struct v4l2_rect crop; u32 colorspace; diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c index 9b39d77a178d..f4d7ca78a621 100644 --- a/drivers/media/platform/amphion/vpu_cmds.c +++ b/drivers/media/platform/amphion/vpu_cmds.c @@ -117,8 +117,7 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd) { if (!cmd) return; - if (cmd->pkt) - vfree(cmd->pkt); + vfree(cmd->pkt); vfree(cmd); } diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index 68ad183925fd..73faa50d2865 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -257,14 +257,8 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core) } list_add_tail(&core->list, &vpu->cores); - vpu_core_get_vpu(core); - if (vpu_iface_get_power_state(core)) - ret = vpu_core_restore(core); - if (ret) - goto error; - return 0; error: if (core->msg_buffer) { @@ -362,7 +356,10 @@ struct vpu_core *vpu_request_core(struct vpu_dev *vpu, enum vpu_core_type type) pm_runtime_resume_and_get(core->dev); if (core->state == VPU_CORE_DEINIT) { - ret = vpu_core_boot(core, true); + if (vpu_iface_get_power_state(core)) + ret = vpu_core_restore(core); + else + ret = vpu_core_boot(core, true); if (ret) { pm_runtime_put_sync(core->dev); mutex_unlock(&core->lock); @@ -455,8 +452,13 @@ int vpu_inst_unregister(struct vpu_inst *inst) } vpu_core_check_hang(core); if (core->state == VPU_CORE_HANG && !core->instance_mask) { + int err; + dev_info(core->dev, "reset hang core\n"); - if (!vpu_core_sw_reset(core)) { + mutex_unlock(&core->lock); + err = vpu_core_sw_reset(core); + mutex_lock(&core->lock); + if (!err) { core->state = VPU_CORE_ACTIVE; core->hang_mask = 0; } diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index da62bd718fb8..f72c8a506b22 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -27,7 +27,7 @@ struct print_buf_desc { u32 bytes; u32 read; u32 write; - char buffer[0]; + char buffer[]; }; static char *vb2_stat_name[] = { diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index f29c223eefce..f4a488bf9880 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -309,6 +309,7 @@ struct malone_padding_scode { struct malone_fmt_mapping { u32 pixelformat; enum vpu_malone_format malone_format; + u32 is_disabled; }; struct malone_scode_t { @@ -568,6 +569,8 @@ static enum vpu_malone_format vpu_malone_format_remap(u32 pixelformat) u32 i; for (i = 0; i < ARRAY_SIZE(fmt_mappings); i++) { + if (fmt_mappings[i].is_disabled) + continue; if (pixelformat == fmt_mappings[i].pixelformat) return fmt_mappings[i].malone_format; } @@ -575,6 +578,19 @@ static enum vpu_malone_format vpu_malone_format_remap(u32 pixelformat) return MALONE_FMT_NULL; } +bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt) +{ + if (!vpu_imx8q_check_fmt(type, pixelfmt)) + return false; + + if (pixelfmt == V4L2_PIX_FMT_NV12M_8L128 || pixelfmt == V4L2_PIX_FMT_NV12M_10BE_8L128) + return true; + if (vpu_malone_format_remap(pixelfmt) == MALONE_FMT_NULL) + return false; + + return true; +} + static void vpu_malone_set_stream_cfg(struct vpu_shared_addr *shared, u32 instance, enum vpu_malone_format malone_format) @@ -610,6 +626,8 @@ static int vpu_malone_set_params(struct vpu_shared_addr *shared, enum vpu_malone_format malone_format; malone_format = vpu_malone_format_remap(params->codec_format); + if (WARN_ON(malone_format == MALONE_FMT_NULL)) + return -EINVAL; iface->udata_buffer[instance].base = params->udata.base; iface->udata_buffer[instance].slot_size = params->udata.size; @@ -1296,6 +1314,8 @@ static int vpu_malone_insert_scode_vc1_l_seq(struct malone_scode_t *scode) int size = 0; u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN]; + if (scode->inst->total_input_count) + return 0; scode->need_data = 0; ret = vpu_malone_insert_scode_seq(scode, MALONE_CODEC_ID_VC1_SIMPLE, sizeof(rcv_seqhdr)); diff --git a/drivers/media/platform/amphion/vpu_malone.h b/drivers/media/platform/amphion/vpu_malone.h index e5a5cbe9843e..02a9d9530970 100644 --- a/drivers/media/platform/amphion/vpu_malone.h +++ b/drivers/media/platform/amphion/vpu_malone.h @@ -40,5 +40,6 @@ int vpu_malone_pre_cmd(struct vpu_shared_addr *shared, u32 instance); int vpu_malone_post_cmd(struct vpu_shared_addr *shared, u32 instance); int vpu_malone_init_instance(struct vpu_shared_addr *shared, u32 instance); u32 vpu_malone_get_max_instance_count(struct vpu_shared_addr *shared); +bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt); #endif diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c index d5850df8f1d5..d8247f36d84b 100644 --- a/drivers/media/platform/amphion/vpu_msgs.c +++ b/drivers/media/platform/amphion/vpu_msgs.c @@ -150,7 +150,12 @@ static void vpu_session_handle_eos(struct vpu_inst *inst, struct vpu_rpc_event * static void vpu_session_handle_error(struct vpu_inst *inst, struct vpu_rpc_event *pkt) { - dev_err(inst->dev, "unsupported stream\n"); + char *str = (char *)pkt->data; + + if (strlen(str)) + dev_err(inst->dev, "instance %d firmware error : %s\n", inst->id, str); + else + dev_err(inst->dev, "instance %d is unsupported stream\n", inst->id); call_void_vop(inst, event_notify, VPU_MSG_ID_UNSUPPORTED, NULL); vpu_v4l2_set_error(inst); } diff --git a/drivers/media/platform/amphion/vpu_rpc.c b/drivers/media/platform/amphion/vpu_rpc.c index 18a164766409..676f7da041bd 100644 --- a/drivers/media/platform/amphion/vpu_rpc.c +++ b/drivers/media/platform/amphion/vpu_rpc.c @@ -195,7 +195,7 @@ static struct vpu_iface_ops imx8q_rpc_ops[] = { }, [VPU_CORE_TYPE_DEC] = { .check_codec = vpu_imx8q_check_codec, - .check_fmt = vpu_imx8q_check_fmt, + .check_fmt = vpu_malone_check_fmt, .boot_core = vpu_imx8q_boot_core, .get_power_state = vpu_imx8q_get_power_state, .on_firmware_loaded = vpu_imx8q_on_firmware_loaded, diff --git a/drivers/media/platform/amphion/vpu_rpc.h b/drivers/media/platform/amphion/vpu_rpc.h index 25119e5e807e..7eb6f01e6ab5 100644 --- a/drivers/media/platform/amphion/vpu_rpc.h +++ b/drivers/media/platform/amphion/vpu_rpc.h @@ -312,11 +312,16 @@ static inline int vpu_iface_input_frame(struct vpu_inst *inst, struct vb2_buffer *vb) { struct vpu_iface_ops *ops = vpu_core_get_iface(inst->core); + int ret; if (!ops || !ops->input_frame) return -EINVAL; - return ops->input_frame(inst->core->iface, inst, vb); + ret = ops->input_frame(inst->core->iface, inst, vb); + if (ret < 0) + return ret; + inst->total_input_count++; + return ret; } static inline int vpu_iface_config_memory_resource(struct vpu_inst *inst, diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 446f07d09d0b..8a3eed957ae6 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -500,10 +500,12 @@ static int vpu_vb2_start_streaming(struct vb2_queue *q, unsigned int count) fmt->sizeimage[1], fmt->bytesperline[1], fmt->sizeimage[2], fmt->bytesperline[2], q->num_buffers); - call_void_vop(inst, start, q->type); vb2_clear_last_buffer_dequeued(q); + ret = call_vop(inst, start, q->type); + if (ret) + vpu_vb2_buffers_return(inst, q->type, VB2_BUF_STATE_QUEUED); - return 0; + return ret; } static void vpu_vb2_stop_streaming(struct vb2_queue *q) diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig index 83aebee0c8eb..f399dba62e17 100644 --- a/drivers/media/platform/atmel/Kconfig +++ b/drivers/media/platform/atmel/Kconfig @@ -20,12 +20,14 @@ config VIDEO_ATMEL_ISC config VIDEO_ATMEL_XISC tristate "ATMEL eXtended Image Sensor Controller (XISC) support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_DEV && COMMON_CLK depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select REGMAP_MMIO select V4L2_FWNODE select VIDEO_ATMEL_ISC_BASE + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This module makes the ATMEL eXtended Image Sensor Controller available as a v4l2 device. diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index 2f07a50035c8..9e5317a7d516 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -132,12 +132,9 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) return 0; } -static void isc_start_dma(struct isc_device *isc) +static void isc_crop_pfe(struct isc_device *isc) { struct regmap *regmap = isc->regmap; - u32 sizeimage = isc->fmt.fmt.pix.sizeimage; - u32 dctrl_dview; - dma_addr_t addr0; u32 h, w; h = isc->fmt.fmt.pix.height; @@ -172,6 +169,14 @@ static void isc_start_dma(struct isc_device *isc) regmap_update_bits(regmap, ISC_PFE_CFG0, ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN, ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN); +} + +static void isc_start_dma(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 sizeimage = isc->fmt.fmt.pix.sizeimage; + u32 dctrl_dview; + dma_addr_t addr0; addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0); @@ -369,6 +374,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) struct isc_buffer, list); list_del(&isc->cur_frm->list); + isc_crop_pfe(isc); isc_start_dma(isc); spin_unlock_irqrestore(&isc->dma_queue_lock, flags); @@ -1466,7 +1472,7 @@ static void isc_awb_work(struct work_struct *w) if (isc->stop) { mutex_unlock(&isc->awb_mutex); return; - }; + } isc_update_profile(isc); @@ -1525,10 +1531,6 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) else ctrls->awb = ISC_WB_NONE; - /* we did not configure ISC yet */ - if (!isc->config.sd_format) - break; - /* configure the controls with new values from v4l2 */ if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new) ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val; diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c index 83b175070c06..8b11aa8340d7 100644 --- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c @@ -591,11 +591,13 @@ static const struct dev_pm_ops microchip_xisc_dev_pm_ops = { SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL) }; +#if IS_ENABLED(CONFIG_OF) static const struct of_device_id microchip_xisc_of_match[] = { { .compatible = "microchip,sama7g5-isc" }, { } }; MODULE_DEVICE_TABLE(of, microchip_xisc_of_match); +#endif static struct platform_driver microchip_xisc_driver = { .probe = microchip_xisc_probe, diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index bc5b0a0168ec..87685a62a5c2 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1369,6 +1369,9 @@ static int mtk_jpeg_probe(struct platform_device *pdev) jpeg->vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; + if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL)) + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); + ret = video_register_device(jpeg->vdev, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h b/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h index 2cb8cecb3077..b810c96695c8 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h @@ -40,12 +40,14 @@ struct mdp_ipi_init { * @ipi_id : IPI_MDP * @ap_inst : AP mtk_mdp_vpu address * @vpu_inst_addr : VPU MDP instance address + * @padding : Alignment padding */ struct mdp_ipi_comm { uint32_t msg_id; uint32_t ipi_id; uint64_t ap_inst; uint32_t vpu_inst_addr; + uint32_t padding; }; /** diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c index 52e5d36aa912..7d194a476713 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c @@ -35,6 +35,44 @@ mtk_vdec_find_format(struct v4l2_format *f, return NULL; } +static bool mtk_vdec_get_cap_fmt(struct mtk_vcodec_ctx *ctx, int format_index) +{ + const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; + const struct mtk_video_fmt *fmt; + struct mtk_q_data *q_data; + int num_frame_count = 0, i; + bool ret = true; + + for (i = 0; i < *dec_pdata->num_formats; i++) { + if (dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME) + continue; + + num_frame_count++; + } + + if (num_frame_count == 1) + return true; + + fmt = &dec_pdata->vdec_formats[format_index]; + q_data = &ctx->q_data[MTK_Q_DATA_SRC]; + switch (q_data->fmt->fourcc) { + case V4L2_PIX_FMT_VP8_FRAME: + if (fmt->fourcc == V4L2_PIX_FMT_MM21) + ret = true; + break; + case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_VP9_FRAME: + if (fmt->fourcc == V4L2_PIX_FMT_MM21) + ret = false; + break; + default: + ret = true; + break; + } + + return ret; +} + static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, enum v4l2_buf_type type) { @@ -112,8 +150,6 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) { struct mtk_q_data *q_data; - ctx->dev->vdec_pdata->init_vdec_params(ctx); - ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; ctx->fh.m2m_ctx = ctx->m2m_ctx; ctx->fh.ctrl_handler = &ctx->ctrl_hdl; @@ -141,15 +177,6 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt; q_data->field = V4L2_FIELD_NONE; - ctx->max_width = MTK_VDEC_MAX_W; - ctx->max_height = MTK_VDEC_MAX_H; - - v4l_bound_align_image(&q_data->coded_width, - MTK_VDEC_MIN_W, - ctx->max_width, 4, - &q_data->coded_height, - MTK_VDEC_MIN_H, - ctx->max_height, 5, 6); q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; q_data->bytesperline[0] = q_data->coded_width; @@ -185,12 +212,34 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } +static int mtk_vcodec_dec_get_chip_name(void *priv) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + + if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec")) + return 8173; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec")) + return 8183; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec")) + return 8192; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec")) + return 8195; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec")) + return 8186; + else + return 8173; +} + static int vidioc_vdec_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strscpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info)); - strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card)); + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + int platform_name = mtk_vcodec_dec_get_chip_name(priv); + + strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); + snprintf(cap->card, sizeof(cap->card), "MT%d video decoder", platform_name); return 0; } @@ -198,6 +247,11 @@ static int vidioc_vdec_querycap(struct file *file, void *priv, static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh); + + if (ctx->dev->vdec_pdata->uses_stateless_api) + return v4l2_ctrl_subscribe_event(fh, sub); + switch (sub->type) { case V4L2_EVENT_EOS: return v4l2_event_subscribe(fh, sub, 2, NULL); @@ -212,13 +266,18 @@ static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + const struct v4l2_frmsize_stepwise *frmsize; pix_fmt_mp->field = V4L2_FIELD_NONE; - pix_fmt_mp->width = - clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, ctx->max_width); - pix_fmt_mp->height = - clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, ctx->max_height); + /* Always apply frame size constraints from the coded side */ + if (V4L2_TYPE_IS_OUTPUT(f->type)) + frmsize = &fmt->frmsize; + else + frmsize = &ctx->q_data[MTK_Q_DATA_SRC].fmt->frmsize; + + pix_fmt_mp->width = clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, frmsize->max_width); + pix_fmt_mp->height = clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, frmsize->max_height); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { pix_fmt_mp->num_planes = 1; @@ -234,18 +293,15 @@ static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, */ tmp_w = pix_fmt_mp->width; tmp_h = pix_fmt_mp->height; - v4l_bound_align_image(&pix_fmt_mp->width, - MTK_VDEC_MIN_W, - ctx->max_width, 6, - &pix_fmt_mp->height, - MTK_VDEC_MIN_H, - ctx->max_height, 6, 9); + v4l_bound_align_image(&pix_fmt_mp->width, MTK_VDEC_MIN_W, frmsize->max_width, 6, + &pix_fmt_mp->height, MTK_VDEC_MIN_H, frmsize->max_height, 6, + 9); if (pix_fmt_mp->width < tmp_w && - (pix_fmt_mp->width + 64) <= ctx->max_width) + (pix_fmt_mp->width + 64) <= frmsize->max_width) pix_fmt_mp->width += 64; if (pix_fmt_mp->height < tmp_h && - (pix_fmt_mp->height + 64) <= ctx->max_height) + (pix_fmt_mp->height + 64) <= frmsize->max_height) pix_fmt_mp->height += 64; mtk_v4l2_debug(0, @@ -435,13 +491,6 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, if (fmt == NULL) return -EINVAL; - if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) && - fmt->fourcc != V4L2_PIX_FMT_VP8_FRAME) { - mtk_v4l2_debug(3, "4K is enabled"); - ctx->max_width = VCODEC_DEC_4K_CODED_WIDTH; - ctx->max_height = VCODEC_DEC_4K_CODED_HEIGHT; - } - q_data->fmt = fmt; vidioc_try_fmt(ctx, f, q_data->fmt); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { @@ -526,15 +575,17 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, if (fsize->index != 0) return -EINVAL; - for (i = 0; i < *dec_pdata->num_framesizes; ++i) { - if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc) + for (i = 0; i < *dec_pdata->num_formats; i++) { + if (fsize->pixel_format != dec_pdata->vdec_formats[i].fourcc) continue; + /* Only coded formats have frame sizes set */ + if (!dec_pdata->vdec_formats[i].frmsize.max_width) + return -ENOTTY; + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise; + fsize->stepwise = dec_pdata->vdec_formats[i].frmsize; - fsize->stepwise.max_width = ctx->max_width; - fsize->stepwise.max_height = ctx->max_height; mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d", ctx->dev->dec_capability, fsize->stepwise.min_width, @@ -566,6 +617,9 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME) continue; + if (!output_queue && !mtk_vdec_get_cap_fmt(ctx, i)) + continue; + if (j == f->index) break; ++j; @@ -735,6 +789,7 @@ int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) mtk_v4l2_err("data will not fit into plane %d (%lu < %d)", i, vb2_plane_size(vb, i), q_data->sizeimage[i]); + return -EINVAL; } if (!V4L2_TYPE_IS_OUTPUT(vb->type)) vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); @@ -938,6 +993,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->dev->dev_mutex; src_vq->dev = &ctx->dev->plat_dev->dev; + src_vq->allow_cache_hints = 1; ret = vb2_queue_init(src_vq); if (ret) { @@ -953,6 +1009,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->dev->dev_mutex; dst_vq->dev = &ctx->dev->plat_dev->dev; + dst_vq->allow_cache_hints = 1; ret = vb2_queue_init(dst_vq); if (ret) diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c index 995e6e2fb1ab..e0b6ae9d6caa 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c @@ -208,9 +208,12 @@ static int fops_vcodec_open(struct file *file) dev->dec_capability = mtk_vcodec_fw_get_vdec_capa(dev->fw_handler); + mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability); } + ctx->dev->vdec_pdata->init_vdec_params(ctx); + list_add(&ctx->list, &dev->ctx_list); mutex_unlock(&dev->dev_mutex); @@ -386,8 +389,14 @@ static int mtk_vcodec_probe(struct platform_device *pdev) mtk_v4l2_err("Main device of_platform_populate failed."); goto err_reg_cont; } + } else { + set_bit(MTK_VDEC_CORE, dev->subdev_bitmap); } + atomic_set(&dev->dec_active_cnt, 0); + memset(dev->vdec_racing_info, 0, sizeof(dev->vdec_racing_info)); + mutex_init(&dev->dec_racing_info_mutex); + ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, -1); if (ret) { mtk_v4l2_err("Failed to register video device"); @@ -465,6 +474,10 @@ static const struct of_device_id mtk_vcodec_match[] = { .compatible = "mediatek,mt8186-vcodec-dec", .data = &mtk_vdec_single_core_pdata, }, + { + .compatible = "mediatek,mt8195-vcodec-dec", + .data = &mtk_lat_sig_core_pdata, + }, {}, }; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c index 14bed2bd4283..376db0e433d7 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c @@ -28,6 +28,10 @@ static const struct of_device_id mtk_vdec_hw_match[] = { .compatible = "mediatek,mtk-vcodec-core", .data = (void *)MTK_VDEC_CORE, }, + { + .compatible = "mediatek,mtk-vcodec-lat-soc", + .data = (void *)MTK_VDEC_LAT_SOC, + }, {}, }; MODULE_DEVICE_TABLE(of, mtk_vdec_hw_match); @@ -166,9 +170,11 @@ static int mtk_vdec_hw_probe(struct platform_device *pdev) subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS]; set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap); - ret = mtk_vdec_hw_init_irq(subdev_dev); - if (ret) - goto err; + if (IS_SUPPORT_VDEC_HW_IRQ(hw_idx)) { + ret = mtk_vdec_hw_init_irq(subdev_dev); + if (ret) + goto err; + } subdev_dev->reg_base[VDEC_HW_MISC] = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h index a63e4b1b81c3..36faa8d9d681 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h @@ -17,6 +17,8 @@ #define VDEC_IRQ_CLR 0x10 #define VDEC_IRQ_CFG_REG 0xa4 +#define IS_SUPPORT_VDEC_HW_IRQ(hw_idx) ((hw_idx) != MTK_VDEC_LAT_SOC) + /** * enum mtk_vdec_hw_reg_idx - subdev hardware register base index * @VDEC_HW_SYS : vdec soc register index diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c index 0fb7e5ba635b..4305e4eb9900 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c @@ -144,6 +144,34 @@ static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_i } } +static void mtk_vcodec_load_racing_info(struct mtk_vcodec_ctx *ctx) +{ + void __iomem *vdec_racing_addr; + int j; + + mutex_lock(&ctx->dev->dec_racing_info_mutex); + if (atomic_inc_return(&ctx->dev->dec_active_cnt) == 1) { + vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100; + for (j = 0; j < 132; j++) + writel(ctx->dev->vdec_racing_info[j], vdec_racing_addr + j * 4); + } + mutex_unlock(&ctx->dev->dec_racing_info_mutex); +} + +static void mtk_vcodec_record_racing_info(struct mtk_vcodec_ctx *ctx) +{ + void __iomem *vdec_racing_addr; + int j; + + mutex_lock(&ctx->dev->dec_racing_info_mutex); + if (atomic_dec_and_test(&ctx->dev->dec_active_cnt)) { + vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100; + for (j = 0; j < 132; j++) + ctx->dev->vdec_racing_info[j] = readl(vdec_racing_addr + j * 4); + } + mutex_unlock(&ctx->dev->dec_racing_info_mutex); +} + static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev, int hw_idx) { @@ -174,6 +202,14 @@ static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev, mtk_vcodec_dec_pw_on(pm); mtk_vcodec_dec_clock_on(pm); } + + if (hw_idx == MTK_VDEC_LAT0) { + pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC); + if (pm) { + mtk_vcodec_dec_pw_on(pm); + mtk_vcodec_dec_clock_on(pm); + } + } } static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, @@ -186,6 +222,14 @@ static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, mtk_vcodec_dec_clock_off(pm); mtk_vcodec_dec_pw_off(pm); } + + if (hw_idx == MTK_VDEC_LAT0) { + pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC); + if (pm) { + mtk_vcodec_dec_clock_off(pm); + mtk_vcodec_dec_pw_off(pm); + } + } } void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) @@ -198,11 +242,17 @@ void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx); mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx); + + if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability)) + mtk_vcodec_load_racing_info(ctx); } EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware); void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) { + if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability)) + mtk_vcodec_record_racing_info(ctx); + mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx); mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c index 9c7e6145cebb..035c86e7809f 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c @@ -17,18 +17,24 @@ static const struct mtk_video_fmt mtk_video_formats[] = { .type = MTK_FMT_DEC, .num_planes = 1, .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, }, { .fourcc = V4L2_PIX_FMT_VP8, .type = MTK_FMT_DEC, .num_planes = 1, .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, }, { .fourcc = V4L2_PIX_FMT_VP9, .type = MTK_FMT_DEC, .num_planes = 1, .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, }, { .fourcc = V4L2_PIX_FMT_MT21C, @@ -43,27 +49,6 @@ static const unsigned int num_supported_formats = #define DEFAULT_OUT_FMT_IDX 0 #define DEFAULT_CAP_FMT_IDX 3 -static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { - { - .fourcc = V4L2_PIX_FMT_H264, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, - { - .fourcc = V4L2_PIX_FMT_VP9, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, - }, -}; - -static const unsigned int num_supported_framesize = - ARRAY_SIZE(mtk_vdec_framesizes); - /* * This function tries to clean all display buffers, the buffers will return * in display order. @@ -618,8 +603,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { .num_formats = &num_supported_formats, .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_supported_framesize, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, .is_subdev_supported = false, diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c index 16d55785d84b..c45bd2599bb2 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c @@ -112,14 +112,12 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { #define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) static struct mtk_video_fmt mtk_video_formats[5]; -static struct mtk_codec_framesizes mtk_vdec_framesizes[3]; static struct mtk_video_fmt default_out_format; static struct mtk_video_fmt default_cap_format; static unsigned int num_formats; -static unsigned int num_framesizes; -static struct v4l2_frmsize_stepwise stepwise_fhd = { +static const struct v4l2_frmsize_stepwise stepwise_fhd = { .min_width = MTK_VDEC_MIN_W, .max_width = MTK_VDEC_MAX_W, .step_width = 16, @@ -348,7 +346,6 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, struct mtk_vcodec_dev *dev = ctx->dev; const struct mtk_vcodec_dec_pdata *pdata = dev->vdec_pdata; int count_formats = *pdata->num_formats; - int count_framesizes = *pdata->num_framesizes; switch (fourcc) { case V4L2_PIX_FMT_H264_SLICE: @@ -357,10 +354,15 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, mtk_video_formats[count_formats].fourcc = fourcc; mtk_video_formats[count_formats].type = MTK_FMT_DEC; mtk_video_formats[count_formats].num_planes = 1; - - mtk_vdec_framesizes[count_framesizes].fourcc = fourcc; - mtk_vdec_framesizes[count_framesizes].stepwise = stepwise_fhd; - num_framesizes++; + mtk_video_formats[count_formats].frmsize = stepwise_fhd; + + if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) && + fourcc != V4L2_PIX_FMT_VP8_FRAME) { + mtk_video_formats[count_formats].frmsize.max_width = + VCODEC_DEC_4K_CODED_WIDTH; + mtk_video_formats[count_formats].frmsize.max_height = + VCODEC_DEC_4K_CODED_HEIGHT; + } break; case V4L2_PIX_FMT_MM21: case V4L2_PIX_FMT_MT21C: @@ -374,15 +376,15 @@ static void mtk_vcodec_add_formats(unsigned int fourcc, } num_formats++; - mtk_v4l2_debug(3, "num_formats: %d num_frames:%d dec_capability: 0x%x", - count_formats, count_framesizes, ctx->dev->dec_capability); + mtk_v4l2_debug(3, "num_formats: %d dec_capability: 0x%x", + count_formats, ctx->dev->dec_capability); } static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx) { int cap_format_count = 0, out_format_count = 0; - if (num_formats && num_framesizes) + if (num_formats) return; if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MM21) { @@ -461,8 +463,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = { .num_formats = &num_formats, .default_out_fmt = &default_out_format, .default_cap_fmt = &default_cap_format, - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, @@ -481,8 +481,6 @@ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = { .num_formats = &num_formats, .default_out_fmt = &default_out_format, .default_cap_fmt = &default_cap_format, - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, @@ -500,8 +498,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = { .num_formats = &num_formats, .default_out_fmt = &default_out_format, .default_cap_fmt = &default_cap_format, - .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h index a29041a0b7e0..ef4584a46417 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h @@ -19,15 +19,14 @@ #include "mtk_vcodec_util.h" #include "vdec_msg_queue.h" -#define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv" #define MTK_VCODEC_DEC_NAME "mtk-vcodec-dec" #define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc" -#define MTK_PLATFORM_STR "platform:mt8173" #define MTK_VCODEC_MAX_PLANES 3 #define MTK_V4L2_BENCHMARK 0 #define WAIT_INTR_TIMEOUT_MS 1000 #define IS_VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE) +#define IS_VDEC_INNER_RACING(capability) ((capability) & MTK_VCODEC_INNER_RACING) /* * enum mtk_hw_reg_idx - MTK hw register base index @@ -104,6 +103,7 @@ enum mtk_vdec_hw_id { MTK_VDEC_CORE, MTK_VDEC_LAT0, MTK_VDEC_LAT1, + MTK_VDEC_LAT_SOC, MTK_VDEC_HW_MAX, }; @@ -125,15 +125,7 @@ struct mtk_video_fmt { enum mtk_fmt_type type; u32 num_planes; u32 flags; -}; - -/* - * struct mtk_codec_framesizes - Structure used to store information about - * framesizes - */ -struct mtk_codec_framesizes { - u32 fourcc; - struct v4l2_frmsize_stepwise stepwise; + struct v4l2_frmsize_stepwise frmsize; }; /* @@ -255,7 +247,7 @@ struct vdec_pic_info { * @param_change: indicate encode parameter type * @enc_params: encoding parameters * @dec_if: hooked decoder driver interface - * @enc_if: hoooked encoder driver interface + * @enc_if: hooked encoder driver interface * @drv_handle: driver handle for specific decode/encode instance * * @picinfo: store picture info after header parsing @@ -285,8 +277,6 @@ struct vdec_pic_info { * mtk_video_dec_buf. * @hw_id: hardware index used to identify different hardware. * - * @max_width: hardware supported max width - * @max_height: hardware supported max height * @msg_queue: msg queue used to store lat buffer information. */ struct mtk_vcodec_ctx { @@ -333,8 +323,6 @@ struct mtk_vcodec_ctx { struct mutex lock; int hw_id; - unsigned int max_width; - unsigned int max_height; struct vdec_msg_queue msg_queue; }; @@ -356,6 +344,7 @@ enum mtk_vdec_format_types { MTK_VDEC_FORMAT_H264_SLICE = 0x100, MTK_VDEC_FORMAT_VP8_FRAME = 0x200, MTK_VDEC_FORMAT_VP9_FRAME = 0x400, + MTK_VCODEC_INNER_RACING = 0x20000, }; /** @@ -373,9 +362,6 @@ enum mtk_vdec_format_types { * @default_out_fmt: default output buffer format * @default_cap_fmt: default capture buffer format * - * @vdec_framesizes: supported video decoder frame sizes - * @num_framesizes: count of video decoder frame sizes - * * @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core * * @is_subdev_supported: whether support parent-node architecture(subdev) @@ -398,9 +384,6 @@ struct mtk_vcodec_dec_pdata { const struct mtk_video_fmt *default_out_fmt; const struct mtk_video_fmt *default_cap_fmt; - const struct mtk_codec_framesizes *vdec_framesizes; - const int *num_framesizes; - enum mtk_vdec_hw_arch hw_arch; bool is_subdev_supported; @@ -477,6 +460,10 @@ struct mtk_vcodec_enc_pdata { * @subdev_dev: subdev hardware device * @subdev_prob_done: check whether all used hw device is prob done * @subdev_bitmap: used to record hardware is ready or not + * + * @dec_active_cnt: used to mark whether need to record register value + * @vdec_racing_info: record register value + * @dec_racing_info_mutex: mutex lock used for inner racing mode */ struct mtk_vcodec_dev { struct v4l2_device v4l2_dev; @@ -522,6 +509,11 @@ struct mtk_vcodec_dev { void *subdev_dev[MTK_VDEC_HW_MAX]; int (*subdev_prob_done)(struct mtk_vcodec_dev *vdec_dev); DECLARE_BITMAP(subdev_bitmap, MTK_VDEC_HW_MAX); + + atomic_t dec_active_cnt; + u32 vdec_racing_info[132]; + /* Protects access to vdec_racing_info data */ + struct mutex dec_racing_info_mutex; }; static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh) diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c index c21367038c34..25e816863597 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c @@ -50,6 +50,14 @@ static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl) int ret = 0; switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE_MODE val= %d", + ctrl->val); + if (ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) { + mtk_v4l2_err("Unsupported bitrate mode =%d", ctrl->val); + ret = -EINVAL; + } + break; case V4L2_CID_MPEG_VIDEO_BITRATE: mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d", ctrl->val); @@ -204,12 +212,32 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, pdata->num_output_formats); } +static int mtk_vcodec_enc_get_chip_name(void *priv) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + + if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-enc")) + return 8173; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-enc")) + return 8183; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-enc")) + return 8192; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-enc")) + return 8195; + else + return 8173; +} + static int vidioc_venc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strscpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info)); - strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card)); + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct device *dev = &ctx->dev->plat_dev->dev; + int platform_name = mtk_vcodec_enc_get_chip_name(priv); + + strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); + snprintf(cap->card, sizeof(cap->card), "MT%d video encoder", platform_name); return 0; } @@ -1373,6 +1401,9 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_VP8_PROFILE, V4L2_MPEG_VIDEO_VP8_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0); + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); if (handler->error) { diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c index ca628321d272..580ce979e2a3 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c @@ -51,7 +51,7 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, struct vb2_queue *vq; struct vb2_buffer *vb; struct vb2_v4l2_buffer *vb2_v4l2; - int index, vb2_index; + int index; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -62,8 +62,8 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, continue; } - vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); - if (vb2_index < 0) { + vb = vb2_find_buffer(vq, dpb->reference_ts); + if (!vb) { dev_err(&ctx->dev->plat_dev->dev, "Reference invalid: dpb_index(%d) reference_ts(%lld)", index, dpb->reference_ts); @@ -76,7 +76,6 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, else h264_dpb_info[index].reference_flag = 2; - vb = vq->bufs[vb2_index]; vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); h264_dpb_info[index].field = vb2_v4l2->field; diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c index 784d01f8bd50..4cc92700692b 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c @@ -633,6 +633,17 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, goto err_scp_decode; } + share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr + + inst->vsi->wdma_end_addr_offset; + share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; + share_info->nal_info = inst->vsi->dec.nal_info; + + if (IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) { + memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, + sizeof(share_info->h264_slice_params)); + vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + } + /* wait decoder done interrupt */ timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); @@ -646,18 +657,22 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr + inst->vsi->wdma_end_addr_offset; - share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; - share_info->nal_info = inst->vsi->dec.nal_info; vdec_msg_queue_update_ube_wptr(&lat_buf->ctx->msg_queue, share_info->trans_end); - memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, - sizeof(share_info->h264_slice_params)); - vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) { + memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, + sizeof(share_info->h264_slice_params)); + vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + } + mtk_vcodec_debug(inst, "dec num: %d lat crc: 0x%x 0x%x 0x%x", inst->slice_dec_num, + inst->vsi->dec.crc[0], inst->vsi->dec.crc[1], inst->vsi->dec.crc[2]); inst->slice_dec_num++; return 0; err_scp_decode: + if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) + vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf); err_free_fb_out: vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf); mtk_vcodec_err(inst, "slice dec number: %d err: %d", inst->slice_dec_num, err); diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c index eef102f3f4f3..e1fe2603e92e 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c @@ -237,7 +237,7 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst struct vb2_queue *vq; struct vb2_buffer *vb; u64 referenct_ts; - int index, vb2_index; + int index; frame_header = vdec_vp8_slice_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_VP8_FRAME); if (IS_ERR(frame_header)) @@ -246,8 +246,8 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); for (index = 0; index < 3; index++) { referenct_ts = vdec_vp8_slice_get_ref_by_ts(frame_header, index); - vb2_index = vb2_find_timestamp(vq, referenct_ts, 0); - if (vb2_index < 0) { + vb = vb2_find_buffer(vq, referenct_ts); + if (!vb) { if (!V4L2_VP8_FRAME_IS_KEY_FRAME(frame_header)) mtk_vcodec_err(inst, "reference invalid: index(%d) ts(%lld)", index, referenct_ts); @@ -256,7 +256,6 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst } inst->vsi->vp8_dpb_info[index].reference_flag = 1; - vb = vq->bufs[vb2_index]; inst->vsi->vp8_dpb_info[index].y_dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c index 023aba4ec2c4..fb1c36a3592d 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c @@ -439,6 +439,8 @@ struct vdec_vp9_slice_ref { * @init_vsi: vsi used for initialized VP9 instance * @vsi: vsi used for decoding/flush ... * @core_vsi: vsi used for Core stage + * + * @sc_pfc: per frame context single core * @counts_map: used map to counts_helper * @counts_helper: counts table according to newest kernel spec */ @@ -487,6 +489,7 @@ struct vdec_vp9_slice_instance { }; struct vdec_vp9_slice_vsi *core_vsi; + struct vdec_vp9_slice_pfc sc_pfc; struct vdec_vp9_slice_counts_map counts_map; struct v4l2_vp9_frame_symbol_counts counts_helper; }; @@ -523,13 +526,12 @@ static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance if (vdec_vp9_slice_default_frame_ctx) goto out; - frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_KERNEL); + frame_ctx = kmemdup(remote_frame_ctx, sizeof(*frame_ctx), GFP_KERNEL); if (!frame_ctx) { ret = -ENOMEM; goto out; } - memcpy(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx)); vdec_vp9_slice_default_frame_ctx = frame_ctx; out: @@ -689,7 +691,26 @@ static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2) int sbs = (mi_num + 7) >> 3; int offset = ((idx * sbs) >> tile_log2) << 3; - return offset < mi_num ? offset : mi_num; + return min(offset, mi_num); +} + +static +int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance) +{ + struct vb2_v4l2_buffer *src; + struct vb2_v4l2_buffer *dst; + + src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx); + if (!src) + return -EINVAL; + + dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx); + if (!dst) + return -EINVAL; + + v4l2_m2m_buf_copy_metadata(src, dst, true); + + return 0; } static int vdec_vp9_slice_setup_lat_from_src_buf(struct vdec_vp9_slice_instance *instance, @@ -1567,6 +1588,33 @@ static int vdec_vp9_slice_update_prob(struct vdec_vp9_slice_instance *instance, return 0; } +static int vdec_vp9_slice_update_single(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, "Frame %u Y_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[0], vsi->state.crc[1], + vsi->state.crc[2], vsi->state.crc[3]); + mtk_vcodec_debug(instance, "Frame %u C_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[4], vsi->state.crc[5], + vsi->state.crc[6], vsi->state.crc[7]); + + vdec_vp9_slice_update_prob(instance, vsi); + + instance->width = vsi->frame.uh.frame_width; + instance->height = vsi->frame.uh.frame_height; + instance->frame_type = vsi->frame.uh.frame_type; + instance->show_frame = vsi->frame.uh.show_frame; + + return 0; +} + static int vdec_vp9_slice_update_lat(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) @@ -1624,7 +1672,6 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst struct vdec_vp9_slice_reference *ref; int plane; int size; - int idx; int w; int h; int i; @@ -1667,15 +1714,16 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst */ for (i = 0; i < 3; i++) { ref = &vsi->frame.ref[i]; - idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0); - if (idx < 0) { + vb = vb2_find_buffer(vq, pfc->ref_idx[i]); + if (!vb) { ref->frame_width = w; ref->frame_height = h; memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); } else { + int idx = vb->index; + ref->frame_width = instance->dpb[idx].width; ref->frame_height = instance->dpb[idx].height; - vb = vq->bufs[idx]; vsi->ref[i].y.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); if (plane == 1) @@ -1690,6 +1738,40 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst return 0; } +static void vdec_vp9_slice_setup_single_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs, + struct vdec_fb *fb) +{ + int i; + + vsi->bs.buf.dma_addr = bs->dma_addr; + vsi->bs.buf.size = bs->size; + vsi->bs.frame.dma_addr = bs->dma_addr; + vsi->bs.frame.size = bs->size; + + for (i = 0; i < 2; i++) { + vsi->mv[i].dma_addr = instance->mv[i].dma_addr; + vsi->mv[i].size = instance->mv[i].size; + } + for (i = 0; i < 2; i++) { + vsi->seg[i].dma_addr = instance->seg[i].dma_addr; + vsi->seg[i].size = instance->seg[i].size; + } + vsi->tile.dma_addr = instance->tile.dma_addr; + vsi->tile.size = instance->tile.size; + vsi->prob.dma_addr = instance->prob.dma_addr; + vsi->prob.size = instance->prob.size; + vsi->counts.dma_addr = instance->counts.dma_addr; + vsi->counts.size = instance->counts.size; + + vsi->row_info.buf = 0; + vsi->row_info.size = 0; + + vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, fb, NULL); +} + static int vdec_vp9_slice_setup_core(struct vdec_vp9_slice_instance *instance, struct vdec_fb *fb, struct vdec_lat_buf *lat_buf, @@ -1716,6 +1798,43 @@ err: return ret; } +static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance, + struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_pfc(instance, pfc); + if (ret) + goto err; + + ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi); + if (ret) + goto err; + + vdec_vp9_slice_setup_single_buffer(instance, pfc, vsi, bs, fb); + vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); + + ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); + if (ret) + goto err; + + return 0; + +err: + return ret; +} + static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance, struct vdec_lat_buf *lat_buf, struct vdec_vp9_slice_pfc *pfc) @@ -1813,8 +1932,8 @@ static int vdec_vp9_slice_flush(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_vp9_slice_instance *instance = h_vdec; mtk_vcodec_debug(instance, "flush ...\n"); - - vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); + if (instance->ctx->dev->vdec_pdata->hw_arch != MTK_VDEC_PURE_SINGLE_CORE) + vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); return vpu_dec_reset(&instance->vpu); } @@ -1867,6 +1986,63 @@ static int vdec_vp9_slice_get_param(void *h_vdec, enum vdec_get_param_type type, return 0; } +static int vdec_vp9_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + struct vdec_vp9_slice_pfc *pfc = &instance->sc_pfc; + struct vdec_vp9_slice_vsi *vsi; + struct mtk_vcodec_ctx *ctx; + int ret; + + if (!instance || !instance->ctx) + return -EINVAL; + ctx = instance->ctx; + + /* bs NULL means flush decoder */ + if (!bs) + return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg); + + fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); + if (!fb) + return -EBUSY; + + vsi = &pfc->vsi; + + ret = vdec_vp9_slice_setup_single(instance, bs, fb, pfc); + if (ret) { + mtk_vcodec_err(instance, "Failed to setup VP9 single ret %d\n", ret); + return ret; + } + vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); + + ret = vpu_dec_start(&instance->vpu, NULL, 0); + if (ret) { + mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", ret); + return ret; + } + + ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 decode timeout %d\n", ret); + WRITE_ONCE(instance->vsi->state.timeout, 1); + } + + vpu_dec_end(&instance->vpu); + + vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0); + ret = vdec_vp9_slice_update_single(instance, pfc); + if (ret) { + mtk_vcodec_err(instance, "VP9 decode error: %d\n", ret); + return ret; + } + + instance->ctx->decoded_frame_cnt++; + return 0; +} + static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { @@ -1946,6 +2122,20 @@ static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, return 0; } +static int vdec_vp9_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + int ret; + + if (instance->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE) + ret = vdec_vp9_slice_single_decode(h_vdec, bs, fb, res_chg); + else + ret = vdec_vp9_slice_lat_decode(h_vdec, bs, fb, res_chg); + + return ret; +} + static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf) { struct vdec_vp9_slice_instance *instance; @@ -2024,7 +2214,7 @@ err: const struct vdec_common_if vdec_vp9_slice_lat_if = { .init = vdec_vp9_slice_init, - .decode = vdec_vp9_slice_lat_decode, + .decode = vdec_vp9_slice_decode, .get_param = vdec_vp9_slice_get_param, .deinit = vdec_vp9_slice_deinit, }; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c index 27b4b35039cf..f3807f03d880 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c @@ -47,7 +47,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) break; case V4L2_PIX_FMT_VP9_FRAME: ctx->dec_if = &vdec_vp9_slice_lat_if; - ctx->hw_id = MTK_VDEC_LAT0; + ctx->hw_id = IS_VDEC_LAT_ARCH(hw_arch) ? MTK_VDEC_LAT0 : MTK_VDEC_CORE; break; default: return -EINVAL; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c index 35f4d5583084..df309e8e9379 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c @@ -91,6 +91,11 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) (unsigned long)msg->ap_inst_addr; + if (!vpu) { + mtk_v4l2_err("ap_inst_addr is NULL, did the SCP hang or crash?"); + return; + } + mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id); vpu->failure = msg->status; diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c index 88f81a134ba0..204e474d57f7 100644 --- a/drivers/media/platform/nvidia/tegra-vde/h264.c +++ b/drivers/media/platform/nvidia/tegra-vde/h264.c @@ -659,20 +659,19 @@ static struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx, { const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; - int buf_idx = -1; + struct vb2_buffer *vb = NULL; if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - buf_idx = vb2_find_timestamp(cap_q, - dpb[dpb_idx].reference_ts, 0); + vb = vb2_find_buffer(cap_q, dpb[dpb_idx].reference_ts); /* * If a DPB entry is unused or invalid, address of current destination * buffer is returned. */ - if (buf_idx < 0) + if (!vb) return &dst->vb2_buf; - return vb2_get_buffer(cap_q, buf_idx); + return vb; } static int tegra_vde_validate_vb_size(struct tegra_ctx *ctx, diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c index 29c604b1b179..9418fcf740a8 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c @@ -79,6 +79,11 @@ void mxc_jpeg_enable_irq(void __iomem *reg, int slot) writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); } +void mxc_jpeg_disable_irq(void __iomem *reg, int slot) +{ + writel(0x0, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); +} + void mxc_jpeg_sw_reset(void __iomem *reg) { /* @@ -100,9 +105,6 @@ void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg) /* all markers and segments */ writel(0x3ff, reg + CAST_CFG_MODE); - - /* quality factor */ - writel(0x4b, reg + CAST_QUALITY); } void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg) @@ -114,6 +116,14 @@ void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg) writel(0x140, reg + CAST_MODE); } +void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality) +{ + dev_dbg(dev, "CAST Encoder Quality %d...\n", quality); + + /* quality factor */ + writel(quality, reg + CAST_QUALITY); +} + void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg) { dev_dbg(dev, "CAST Decoder GO...\n"); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h index d838e875616c..ecf3b6562ba2 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h @@ -53,10 +53,10 @@ #define CAST_REC_REGS_SEL CAST_STATUS4 #define CAST_LUMTH CAST_STATUS5 #define CAST_CHRTH CAST_STATUS6 -#define CAST_NOMFRSIZE_LO CAST_STATUS7 -#define CAST_NOMFRSIZE_HI CAST_STATUS8 -#define CAST_OFBSIZE_LO CAST_STATUS9 -#define CAST_OFBSIZE_HI CAST_STATUS10 +#define CAST_NOMFRSIZE_LO CAST_STATUS16 +#define CAST_NOMFRSIZE_HI CAST_STATUS17 +#define CAST_OFBSIZE_LO CAST_STATUS18 +#define CAST_OFBSIZE_HI CAST_STATUS19 #define MXC_MAX_SLOTS 1 /* TODO use all 4 slots*/ /* JPEG-Decoder Wrapper Slot Registers 0..3 */ @@ -119,12 +119,14 @@ int mxc_jpeg_enable(void __iomem *reg); void wait_frmdone(struct device *dev, void __iomem *reg); void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg); void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg); +void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality); void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg); int mxc_jpeg_get_slot(void __iomem *reg); u32 mxc_jpeg_get_offset(void __iomem *reg, int slot); void mxc_jpeg_enable_slot(void __iomem *reg, int slot); void mxc_jpeg_set_l_endian(void __iomem *reg, int le); void mxc_jpeg_enable_irq(void __iomem *reg, int slot); +void mxc_jpeg_disable_irq(void __iomem *reg, int slot); int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize); int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf, u16 w, u16 h); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index f36b512bae51..32fd04a3d8bb 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -389,7 +389,6 @@ static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n, if (i >= n) return -EINVAL; - strscpy(f->description, mxc_formats[i].name, sizeof(f->description)); f->pixelformat = mxc_formats[i].fourcc; return 0; @@ -520,6 +519,7 @@ static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg, GFP_ATOMIC); if (!cfg_stm) goto err; + memset(cfg_stm, 0, MXC_JPEG_MAX_CFG_STREAM); jpeg->slot_data[slot].cfg_stream_vaddr = cfg_stm; skip_alloc: @@ -558,6 +558,18 @@ static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg, jpeg->slot_data[slot].used = false; } +static void mxc_jpeg_check_and_set_last_buffer(struct mxc_jpeg_ctx *ctx, + struct vb2_v4l2_buffer *src_buf, + struct vb2_v4l2_buffer *dst_buf) +{ + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); + notify_eos(ctx); + ctx->header_parsed = false; + } +} + static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) { struct mxc_jpeg_dev *jpeg = priv; @@ -580,15 +592,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) dev_dbg(dev, "Irq %d on slot %d.\n", irq, slot); ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); - if (!ctx) { - dev_err(dev, - "Instance released before the end of transaction.\n"); - /* soft reset only resets internal state, not registers */ - mxc_jpeg_sw_reset(reg); - /* clear all interrupts */ - writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); + if (WARN_ON(!ctx)) goto job_unlock; - } if (slot != ctx->slot) { /* TODO investigate when adding multi-instance support */ @@ -624,6 +629,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) ctx->enc_state == MXC_JPEG_ENC_CONF) { ctx->enc_state = MXC_JPEG_ENCODING; dev_dbg(dev, "Encoder config finished. Start encoding...\n"); + mxc_jpeg_enc_set_quality(dev, reg, ctx->jpeg_quality); mxc_jpeg_enc_mode_go(dev, reg); goto job_unlock; } @@ -632,6 +638,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) dev_dbg(dev, "Decoder DHT cfg finished. Start decoding...\n"); goto job_unlock; } + if (jpeg->mode == MXC_JPEG_ENCODE) { payload = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR)); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); @@ -659,7 +666,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) buf_state = VB2_BUF_STATE_DONE; buffers_done: + mxc_jpeg_disable_irq(reg, ctx->slot); jpeg->slot_data[slot].used = false; /* unused, but don't free */ + mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf); 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); @@ -755,7 +764,13 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr, u32 fourcc, u16 w, u16 h) { - unsigned int offset = 0; + /* + * There is a hardware issue that first 128 bytes of configuration data + * can't be loaded correctly. + * To avoid this issue, we need to write the configuration from + * an offset which should be no less than 0x80 (128 bytes). + */ + unsigned int offset = 0x80; u8 *cfg = (u8 *)cfg_stream_vaddr; struct mxc_jpeg_sof *sof; struct mxc_jpeg_sos *sos; @@ -887,8 +902,8 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, jpeg->slot_data[slot].cfg_stream_size = mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr, q_data->fmt->fourcc, - q_data->w_adjusted, - q_data->h_adjusted); + q_data->w, + q_data->h); /* chain the config descriptor with the encoding descriptor */ cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN; @@ -970,7 +985,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, &q_data_cap->h_adjusted, q_data_cap->h_adjusted, /* adjust up */ MXC_JPEG_MAX_HEIGHT, - q_data_cap->fmt->v_align, + 0, 0); /* setup bytesperline/sizeimage for capture queue */ @@ -1027,6 +1042,7 @@ static void mxc_jpeg_device_run(void *priv) jpeg_src_buf->jpeg_parse_error = true; } if (jpeg_src_buf->jpeg_parse_error) { + mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf); v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); @@ -1077,45 +1093,33 @@ end: spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); } -static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx) -{ - struct vb2_queue *q; - - ctx->stopped = 1; - q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); - if (!list_empty(&q->done_list)) - return; - - q->last_buffer_dequeued = true; - wake_up(&q->done_wq); - ctx->stopped = 0; - ctx->header_parsed = false; -} - static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { struct v4l2_fh *fh = file->private_data; struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); - struct device *dev = ctx->mxc_jpeg->dev; int ret; ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); if (ret < 0) return ret; - if (cmd->cmd == V4L2_DEC_CMD_STOP) { - dev_dbg(dev, "Received V4L2_DEC_CMD_STOP"); - if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) { - /* No more src bufs, notify app EOS */ - notify_eos(ctx); - mxc_jpeg_set_last_buffer_dequeued(ctx); - } else { - /* will send EOS later*/ - ctx->stopping = 1; - } + if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx))) + return 0; + + ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, cmd); + if (ret < 0) + return ret; + + if (cmd->cmd == V4L2_DEC_CMD_STOP && + v4l2_m2m_has_stopped(fh->m2m_ctx)) { + notify_eos(ctx); + ctx->header_parsed = false; } + if (cmd->cmd == V4L2_DEC_CMD_START && + v4l2_m2m_has_stopped(fh->m2m_ctx)) + vb2_clear_last_buffer_dequeued(&fh->m2m_ctx->cap_q_ctx.q); return 0; } @@ -1124,24 +1128,27 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv, { struct v4l2_fh *fh = file->private_data; struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); - struct device *dev = ctx->mxc_jpeg->dev; int ret; ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); if (ret < 0) return ret; - if (cmd->cmd == V4L2_ENC_CMD_STOP) { - dev_dbg(dev, "Received V4L2_ENC_CMD_STOP"); - if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) { - /* No more src bufs, notify app EOS */ - notify_eos(ctx); - mxc_jpeg_set_last_buffer_dequeued(ctx); - } else { - /* will send EOS later*/ - ctx->stopping = 1; - } - } + if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx)) || + !vb2_is_streaming(v4l2_m2m_get_dst_vq(fh->m2m_ctx))) + return 0; + + ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, cmd); + if (ret < 0) + return 0; + + if (cmd->cmd == V4L2_ENC_CMD_STOP && + v4l2_m2m_has_stopped(fh->m2m_ctx)) + notify_eos(ctx); + + if (cmd->cmd == V4L2_ENC_CMD_START && + v4l2_m2m_has_stopped(fh->m2m_ctx)) + vb2_clear_last_buffer_dequeued(&fh->m2m_ctx->cap_q_ctx.q); return 0; } @@ -1154,18 +1161,30 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, { struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q); struct mxc_jpeg_q_data *q_data = NULL; + struct mxc_jpeg_q_data tmp_q; int i; q_data = mxc_jpeg_get_q_data(ctx, q->type); if (!q_data) return -EINVAL; + tmp_q.fmt = q_data->fmt; + tmp_q.w = q_data->w_adjusted; + tmp_q.h = q_data->h_adjusted; + for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) { + tmp_q.bytesperline[i] = q_data->bytesperline[i]; + tmp_q.sizeimage[i] = q_data->sizeimage[i]; + } + mxc_jpeg_sizeimage(&tmp_q); + for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) + tmp_q.sizeimage[i] = max(tmp_q.sizeimage[i], q_data->sizeimage[i]); + /* Handle CREATE_BUFS situation - *nplanes != 0 */ if (*nplanes) { if (*nplanes != q_data->fmt->colplanes) return -EINVAL; for (i = 0; i < *nplanes; i++) { - if (sizes[i] < q_data->sizeimage[i]) + if (sizes[i] < tmp_q.sizeimage[i]) return -EINVAL; } return 0; @@ -1174,7 +1193,7 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, /* Handle REQBUFS situation */ *nplanes = q_data->fmt->colplanes; for (i = 0; i < *nplanes; i++) - sizes[i] = q_data->sizeimage[i]; + sizes[i] = tmp_q.sizeimage[i]; return 0; } @@ -1185,6 +1204,8 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type); int ret; + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(q->type)) ctx->source_change = 0; dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); @@ -1216,11 +1237,15 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q) break; v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); } - pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev); - if (V4L2_TYPE_IS_OUTPUT(q->type)) { - ctx->stopping = 0; - ctx->stopped = 0; + + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + if (V4L2_TYPE_IS_OUTPUT(q->type) && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) { + notify_eos(ctx); + ctx->header_parsed = false; } + + pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev); } static int mxc_jpeg_valid_comp_id(struct device *dev, @@ -1374,11 +1399,6 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) } q_data_out->w = header.frame.width; q_data_out->h = header.frame.height; - if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) { - dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n", - header.frame.width, header.frame.height); - return -EINVAL; - } if (header.frame.width > MXC_JPEG_MAX_WIDTH || header.frame.height > MXC_JPEG_MAX_HEIGHT) { dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n", @@ -1424,6 +1444,20 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb) struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct mxc_jpeg_src_buf *jpeg_src_buf; + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && + vb2_is_streaming(vb->vb2_queue) && + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { + struct mxc_jpeg_q_data *q_data; + + q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type); + vbuf->field = V4L2_FIELD_NONE; + vbuf->sequence = q_data->sequence++; + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); + notify_eos(ctx); + ctx->header_parsed = false; + return; + } + if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) goto end; @@ -1472,24 +1506,11 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) return -EINVAL; } } - return 0; -} - -static void mxc_jpeg_buf_finish(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_queue *q = vb->vb2_queue; - - if (V4L2_TYPE_IS_OUTPUT(vb->type)) - return; - if (!ctx->stopped) - return; - if (list_empty(&q->done_list)) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - ctx->stopped = 0; - ctx->header_parsed = false; + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { + vb2_set_plane_payload(vb, 0, 0); + vb2_set_plane_payload(vb, 1, 0); } + return 0; } static const struct vb2_ops mxc_jpeg_qops = { @@ -1498,7 +1519,6 @@ static const struct vb2_ops mxc_jpeg_qops = { .wait_finish = vb2_ops_wait_finish, .buf_out_validate = mxc_jpeg_buf_out_validate, .buf_prepare = mxc_jpeg_buf_prepare, - .buf_finish = mxc_jpeg_buf_finish, .start_streaming = mxc_jpeg_start_streaming, .stop_streaming = mxc_jpeg_stop_streaming, .buf_queue = mxc_jpeg_buf_queue, @@ -1563,6 +1583,56 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx) } } +static int mxc_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mxc_jpeg_ctx *ctx = + container_of(ctrl->handler, struct mxc_jpeg_ctx, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + ctx->jpeg_quality = ctrl->val; + break; + default: + dev_err(ctx->mxc_jpeg->dev, "Invalid control, id = %d, val = %d\n", + ctrl->id, ctrl->val); + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops mxc_jpeg_ctrl_ops = { + .s_ctrl = mxc_jpeg_s_ctrl, +}; + +static void mxc_jpeg_encode_ctrls(struct mxc_jpeg_ctx *ctx) +{ + v4l2_ctrl_new_std(&ctx->ctrl_handler, &mxc_jpeg_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75); +} + +static int mxc_jpeg_ctrls_setup(struct mxc_jpeg_ctx *ctx) +{ + int err; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 2); + + if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) + mxc_jpeg_encode_ctrls(ctx); + + if (ctx->ctrl_handler.error) { + err = ctx->ctrl_handler.error; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; + } + + err = v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + if (err) + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; +} + static int mxc_jpeg_open(struct file *file) { struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); @@ -1594,6 +1664,12 @@ static int mxc_jpeg_open(struct file *file) goto error; } + ret = mxc_jpeg_ctrls_setup(ctx); + if (ret) { + dev_err(ctx->mxc_jpeg->dev, "failed to setup mxc jpeg controls\n"); + goto err_ctrls_setup; + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; mxc_jpeg_set_default_params(ctx); ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */ @@ -1605,6 +1681,8 @@ static int mxc_jpeg_open(struct file *file) return 0; +err_ctrls_setup: + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); error: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -1646,7 +1724,6 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, if (f->index) return -EINVAL; f->pixelformat = q_data->fmt->fourcc; - strscpy(f->description, q_data->fmt->name, sizeof(f->description)); return 0; } } @@ -1684,22 +1761,17 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm pix_mp->num_planes = fmt->colplanes; pix_mp->pixelformat = fmt->fourcc; - /* - * use MXC_JPEG_H_ALIGN instead of fmt->v_align, for vertical - * alignment, to loosen up the alignment to multiple of 8, - * otherwise NV12-1080p fails as 1080 is not a multiple of 16 - */ + pix_mp->width = w; + pix_mp->height = h; v4l_bound_align_image(&w, - MXC_JPEG_MIN_WIDTH, - w, /* adjust downwards*/ + w, /* adjust upwards*/ + MXC_JPEG_MAX_WIDTH, fmt->h_align, &h, - MXC_JPEG_MIN_HEIGHT, - h, /* adjust downwards*/ - MXC_JPEG_H_ALIGN, + h, /* adjust upwards*/ + MXC_JPEG_MAX_HEIGHT, + 0, 0); - pix_mp->width = w; /* negotiate the width */ - pix_mp->height = h; /* negotiate the height */ /* get user input into the tmp_q */ tmp_q.w = w; @@ -1825,35 +1897,19 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx, q_data->w_adjusted = q_data->w; q_data->h_adjusted = q_data->h; - if (jpeg->mode == MXC_JPEG_DECODE) { - /* - * align up the resolution for CAST IP, - * but leave the buffer resolution unchanged - */ - v4l_bound_align_image(&q_data->w_adjusted, - q_data->w_adjusted, /* adjust upwards */ - MXC_JPEG_MAX_WIDTH, - q_data->fmt->h_align, - &q_data->h_adjusted, - q_data->h_adjusted, /* adjust upwards */ - MXC_JPEG_MAX_HEIGHT, - q_data->fmt->v_align, - 0); - } else { - /* - * align down the resolution for CAST IP, - * but leave the buffer resolution unchanged - */ - v4l_bound_align_image(&q_data->w_adjusted, - MXC_JPEG_MIN_WIDTH, - q_data->w_adjusted, /* adjust downwards*/ - q_data->fmt->h_align, - &q_data->h_adjusted, - MXC_JPEG_MIN_HEIGHT, - q_data->h_adjusted, /* adjust downwards*/ - q_data->fmt->v_align, - 0); - } + /* + * align up the resolution for CAST IP, + * but leave the buffer resolution unchanged + */ + v4l_bound_align_image(&q_data->w_adjusted, + q_data->w_adjusted, /* adjust upwards */ + MXC_JPEG_MAX_WIDTH, + q_data->fmt->h_align, + &q_data->h_adjusted, + q_data->h_adjusted, /* adjust upwards */ + MXC_JPEG_MAX_HEIGHT, + q_data->fmt->v_align, + 0); for (i = 0; i < pix_mp->num_planes; i++) { q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline; @@ -1958,32 +2014,13 @@ static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh, return v4l2_event_subscribe(fh, sub, 0, NULL); case V4L2_EVENT_SOURCE_CHANGE: return v4l2_src_change_event_subscribe(fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); default: return -EINVAL; } } -static int mxc_jpeg_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct v4l2_fh *fh = file->private_data; - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); - struct device *dev = ctx->mxc_jpeg->dev; - int num_src_ready = v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx); - int ret; - - dev_dbg(dev, "DQBUF type=%d, index=%d", buf->type, buf->index); - if (ctx->stopping == 1 && num_src_ready == 0) { - /* No more src bufs, notify app EOS */ - notify_eos(ctx); - ctx->stopping = 0; - mxc_jpeg_set_last_buffer_dequeued(ctx); - } - - ret = v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf); - return ret; -} - static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { .vidioc_querycap = mxc_jpeg_querycap, .vidioc_enum_fmt_vid_cap = mxc_jpeg_enum_fmt_vid_cap, @@ -2007,7 +2044,7 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { .vidioc_encoder_cmd = mxc_jpeg_encoder_cmd, .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = mxc_jpeg_dqbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, @@ -2031,6 +2068,7 @@ static int mxc_jpeg_release(struct file *file) else dev_dbg(dev, "Release JPEG encoder instance on slot %d.", ctx->slot); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -2167,12 +2205,14 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->clk_ipg = devm_clk_get(dev, "ipg"); if (IS_ERR(jpeg->clk_ipg)) { dev_err(dev, "failed to get clock: ipg\n"); + ret = PTR_ERR(jpeg->clk_ipg); goto err_clk; } jpeg->clk_per = devm_clk_get(dev, "per"); if (IS_ERR(jpeg->clk_per)) { dev_err(dev, "failed to get clock: per\n"); + ret = PTR_ERR(jpeg->clk_per); goto err_clk; } diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index 760eaf5387a1..c508d41a906f 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -92,11 +92,11 @@ struct mxc_jpeg_ctx { struct mxc_jpeg_q_data cap_q; struct v4l2_fh fh; enum mxc_jpeg_enc_state enc_state; - unsigned int stopping; - unsigned int stopped; unsigned int slot; unsigned int source_change; bool header_parsed; + struct v4l2_ctrl_handler ctrl_handler; + u8 jpeg_quality; }; struct mxc_jpeg_slot_data { diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 80b1c021d14a..905072871ed2 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -46,6 +46,11 @@ /* Register map definition */ +/* CSIS version */ +#define MIPI_CSIS_VERSION 0x00 +#define MIPI_CSIS_VERSION_IMX7D 0x03030505 +#define MIPI_CSIS_VERSION_IMX8MP 0x03060301 + /* CSIS common control */ #define MIPI_CSIS_CMN_CTRL 0x04 #define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16) @@ -1155,6 +1160,32 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, return 0; } +static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); + struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0]; + + if (pad != CSIS_PAD_SOURCE) + return -EINVAL; + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL; + fd->num_entries = 1; + + memset(entry, 0, sizeof(*entry)); + + mutex_lock(&csis->lock); + + entry->flags = 0; + entry->pixelcode = csis->csis_fmt->code; + entry->bus.csi2.vc = 0; + entry->bus.csi2.dt = csis->csis_fmt->data_type; + + mutex_unlock(&csis->lock); + + return 0; +} + static int mipi_csis_log_status(struct v4l2_subdev *sd) { struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); @@ -1179,6 +1210,7 @@ static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { .enum_mbus_code = mipi_csis_enum_mbus_code, .get_fmt = mipi_csis_get_fmt, .set_fmt = mipi_csis_set_fmt, + .get_frame_desc = mipi_csis_get_frame_desc, }; static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { @@ -1378,6 +1410,13 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis) sd->dev = csis->dev; + sd->fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), + 1, 0, 0); + if (!sd->fwnode) { + dev_err(csis->dev, "Unable to retrieve endpoint for port@1\n"); + return -ENOENT; + } + csis->csis_fmt = &mipi_csis_formats[0]; mipi_csis_init_cfg(sd, NULL); @@ -1498,6 +1537,7 @@ cleanup: v4l2_async_unregister_subdev(&csis->sd); disable_clock: mipi_csis_clk_disable(csis); + fwnode_handle_put(csis->sd.fwnode); mutex_destroy(&csis->lock); return ret; @@ -1517,6 +1557,7 @@ static int mipi_csis_remove(struct platform_device *pdev) mipi_csis_runtime_suspend(&pdev->dev); mipi_csis_clk_disable(csis); media_entity_cleanup(&csis->sd.entity); + fwnode_handle_put(csis->sd.fwnode); mutex_destroy(&csis->lock); pm_runtime_set_suspended(&pdev->dev); diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index f993f349b66b..88f188e0f750 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -245,7 +245,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) } if (!csid->testgen.enabled && - !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) + !media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK])) return -ENOLINK; } @@ -518,7 +518,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value) struct csid_testgen_config *tg = &csid->testgen; /* If CSID is linked to CSIPHY, do not allow to enable test generator */ - if (value && media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) + if (value && media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK])) return -EBUSY; tg->enabled = !!value; @@ -666,7 +666,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, if (csid->num_supplies) { csid->supplies = devm_kmalloc_array(camss->dev, csid->num_supplies, - sizeof(csid->supplies), + sizeof(*csid->supplies), GFP_KERNEL); if (!csid->supplies) return -ENOMEM; @@ -729,7 +729,7 @@ static int csid_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { if (flags & MEDIA_LNK_FL_ENABLED) - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; if ((local->flags & MEDIA_PAD_FL_SINK) && diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 75fcfc627400..3f726a7237f5 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -693,7 +693,7 @@ static int csiphy_link_setup(struct media_entity *entity, struct csiphy_device *csiphy; struct csid_device *csid; - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; sd = media_entity_to_v4l2_subdev(entity); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 4ee11bb979cd..b713f5b86aba 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -812,7 +812,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) int ret; if (enable) { - if (!media_entity_remote_pad(&line->pads[MSM_ISPIF_PAD_SINK])) + if (!media_pad_remote_pad_first(&line->pads[MSM_ISPIF_PAD_SINK])) return -ENOLINK; /* Config */ @@ -1253,6 +1253,41 @@ static enum ispif_intf ispif_get_intf(enum vfe_line_id line_id) } /* + * ispif_get_vfe_id - Get VFE HW module id + * @entity: Pointer to VFE media entity structure + * @id: Return CSID HW module id here + */ +static void ispif_get_vfe_id(struct media_entity *entity, u8 *id) +{ + struct v4l2_subdev *sd; + struct vfe_line *line; + struct vfe_device *vfe; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + vfe = to_vfe(line); + + *id = vfe->id; +} + +/* + * ispif_get_vfe_line_id - Get VFE line id by media entity + * @entity: Pointer to VFE media entity structure + * @id: Return VFE line id here + */ +static void ispif_get_vfe_line_id(struct media_entity *entity, + enum vfe_line_id *id) +{ + struct v4l2_subdev *sd; + struct vfe_line *line; + + sd = media_entity_to_v4l2_subdev(entity); + line = v4l2_get_subdevdata(sd); + + *id = line->id; +} + +/* * ispif_link_setup - Setup ISPIF connections * @entity: Pointer to media entity structure * @local: Pointer to local pad @@ -1266,7 +1301,7 @@ static int ispif_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { if (flags & MEDIA_LNK_FL_ENABLED) { - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; if (local->flags & MEDIA_PAD_FL_SINK) { @@ -1285,8 +1320,8 @@ static int ispif_link_setup(struct media_entity *entity, sd = media_entity_to_v4l2_subdev(entity); line = v4l2_get_subdevdata(sd); - msm_vfe_get_vfe_id(remote->entity, &line->vfe_id); - msm_vfe_get_vfe_line_id(remote->entity, &id); + ispif_get_vfe_id(remote->entity, &line->vfe_id); + ispif_get_vfe_line_id(remote->entity, &id); line->interface = ispif_get_intf(id); } } diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 5b148e9f8134..a26e4a5d87b6 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -1423,40 +1423,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, } /* - * msm_vfe_get_vfe_id - Get VFE HW module id - * @entity: Pointer to VFE media entity structure - * @id: Return CSID HW module id here - */ -void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id) -{ - struct v4l2_subdev *sd; - struct vfe_line *line; - struct vfe_device *vfe; - - sd = media_entity_to_v4l2_subdev(entity); - line = v4l2_get_subdevdata(sd); - vfe = to_vfe(line); - - *id = vfe->id; -} - -/* - * msm_vfe_get_vfe_line_id - Get VFE line id by media entity - * @entity: Pointer to VFE media entity structure - * @id: Return VFE line id here - */ -void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id) -{ - struct v4l2_subdev *sd; - struct vfe_line *line; - - sd = media_entity_to_v4l2_subdev(entity); - line = v4l2_get_subdevdata(sd); - - *id = line->id; -} - -/* * vfe_link_setup - Setup VFE connections * @entity: Pointer to media entity structure * @local: Pointer to local pad @@ -1470,7 +1436,7 @@ static int vfe_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { if (flags & MEDIA_LNK_FL_ENABLED) - if (media_entity_remote_pad(local)) + if (media_pad_remote_pad_first(local)) return -EBUSY; return 0; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 0eba04eb9b77..cbc314c4e244 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -163,9 +163,6 @@ int msm_vfe_register_entities(struct vfe_device *vfe, 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); - /* * vfe_buf_add_pending - Add output buffer to list of pending * @output: VFE output diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 307bb1dc4589..290df04c4d02 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -328,7 +328,7 @@ static struct v4l2_subdev *video_remote_subdev(struct camss_video *video, { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_pad_remote_pad_first(&video->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -507,7 +507,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -543,7 +543,7 @@ static void video_stop_streaming(struct vb2_queue *q) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 79ad82e233cb..1118c40886d5 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -937,7 +937,7 @@ struct media_entity *camss_find_sensor(struct media_entity *entity) if (!(pad->flags & MEDIA_PAD_FL_SINK)) return NULL; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) return NULL; @@ -1452,19 +1452,31 @@ static const struct media_device_ops camss_media_ops = { static int camss_configure_pd(struct camss *camss) { - int nbr_pm_domains = 0; + struct device *dev = camss->dev; int last_pm_domain = 0; int i; int ret; - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) - nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; - else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) - nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; + camss->genpd_num = of_count_phandle_with_args(dev->of_node, + "power-domains", + "#power-domain-cells"); + if (camss->genpd_num < 0) { + dev_err(dev, "Power domains are not defined for camss\n"); + return camss->genpd_num; + } + + camss->genpd = devm_kmalloc_array(dev, camss->genpd_num, + sizeof(*camss->genpd), GFP_KERNEL); + if (!camss->genpd) + return -ENOMEM; + + camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num, + sizeof(*camss->genpd_link), + GFP_KERNEL); + if (!camss->genpd_link) + return -ENOMEM; - for (i = 0; i < nbr_pm_domains; i++) { + for (i = 0; i < camss->genpd_num; i++) { camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); if (IS_ERR(camss->genpd[i])) { ret = PTR_ERR(camss->genpd[i]); @@ -1529,7 +1541,7 @@ static int camss_probe(struct platform_device *pdev) struct camss *camss; int num_subdevs, ret; - camss = kzalloc(sizeof(*camss), GFP_KERNEL); + camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL); if (!camss) return -ENOMEM; @@ -1567,39 +1579,30 @@ static int camss_probe(struct platform_device *pdev) camss->csid_num = 4; camss->vfe_num = 4; } else { - ret = -EINVAL; - goto err_free; + return -EINVAL; } camss->csiphy = devm_kcalloc(dev, camss->csiphy_num, sizeof(*camss->csiphy), GFP_KERNEL); - if (!camss->csiphy) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->csiphy) + return -ENOMEM; camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid), GFP_KERNEL); - if (!camss->csid) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->csid) + return -ENOMEM; if (camss->version == CAMSS_8x16 || camss->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); - if (!camss->ispif) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->ispif) + return -ENOMEM; } camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe), GFP_KERNEL); - if (!camss->vfe) { - ret = -ENOMEM; - goto err_free; - } + if (!camss->vfe) + return -ENOMEM; v4l2_async_nf_init(&camss->notifier); @@ -1681,15 +1684,12 @@ err_register_entities: v4l2_device_unregister(&camss->v4l2_dev); err_cleanup: v4l2_async_nf_cleanup(&camss->notifier); -err_free: - kfree(camss); return ret; } void camss_delete(struct camss *camss) { - int nbr_pm_domains = 0; int i; v4l2_device_unregister(&camss->v4l2_dev); @@ -1698,19 +1698,10 @@ void camss_delete(struct camss *camss) pm_runtime_disable(camss->dev); - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) - nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; - else if (camss->version == CAMSS_845 || - camss->version == CAMSS_8250) - nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; - - for (i = 0; i < nbr_pm_domains; i++) { + for (i = 0; i < camss->genpd_num; i++) { device_link_del(camss->genpd_link[i]); dev_pm_domain_detach(camss->genpd[i], true); } - - kfree(camss); } /* diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index c9b3e0df5be8..0db80cadbbaa 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -69,9 +69,7 @@ struct resources_icc { enum pm_domain { PM_DOMAIN_VFE0 = 0, PM_DOMAIN_VFE1 = 1, - PM_DOMAIN_GEN1_COUNT = 2, /* CAMSS series of ISPs */ PM_DOMAIN_VFELITE = 2, /* VFELITE / TOP GDSC */ - PM_DOMAIN_GEN2_COUNT = 3, /* Titan series of ISPs */ }; enum camss_version { @@ -101,8 +99,9 @@ struct camss { int vfe_num; struct vfe_device *vfe; atomic_t ref_count; - struct device *genpd[PM_DOMAIN_GEN2_COUNT]; - struct device_link *genpd_link[PM_DOMAIN_GEN2_COUNT]; + int genpd_num; + struct device **genpd; + struct device_link **genpd_link; struct icc_path *icc_path[ICC_SM8250_COUNT]; struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT]; }; diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 877eca125803..990a1519f968 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -265,6 +265,19 @@ static void venus_assign_register_offsets(struct venus_core *core) } } +static irqreturn_t venus_isr_thread(int irq, void *dev_id) +{ + struct venus_core *core = dev_id; + irqreturn_t ret; + + ret = hfi_isr_thread(irq, dev_id); + + if (ret == IRQ_HANDLED && venus_fault_inject_ssr()) + hfi_core_trigger_ssr(core, HFI_TEST_SSR_SW_ERR_FATAL); + + return ret; +} + static int venus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -320,7 +333,7 @@ static int venus_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); init_waitqueue_head(&core->sys_err_done); - ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, hfi_isr_thread, + ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "venus", core); if (ret) @@ -832,6 +845,10 @@ static const struct reg_val sm7280_reg_preset[] = { { 0xb0088, 0 }, }; +static const struct hfi_ubwc_config sc7280_ubwc_config = { + 0, 0, {1, 1, 1, 0, 0, 0}, 8, 32, 14, 0, 0, {0, 0} +}; + static const struct venus_resources sc7280_res = { .freq_tbl = sc7280_freq_table, .freq_tbl_size = ARRAY_SIZE(sc7280_freq_table), @@ -841,6 +858,7 @@ static const struct venus_resources sc7280_res = { .bw_tbl_enc_size = ARRAY_SIZE(sc7280_bw_table_enc), .bw_tbl_dec = sc7280_bw_table_dec, .bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec), + .ubwc_conf = &sc7280_ubwc_config, .clks = {"core", "bus", "iface"}, .clks_num = 3, .vcodec0_clks = {"vcodec_core", "vcodec_bus"}, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index d33825553edc..32551c2602a9 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -16,6 +16,7 @@ #include "dbgfs.h" #include "hfi.h" #include "hfi_platform.h" +#include "hfi_helper.h" #define VDBGL "VenusLow : " #define VDBGM "VenusMed : " @@ -57,6 +58,7 @@ struct venus_resources { unsigned int bw_tbl_dec_size; const struct reg_val *reg_tbl; unsigned int reg_tbl_size; + const struct hfi_ubwc_config *ubwc_conf; const char * const clks[VIDC_CLKS_NUM_MAX]; unsigned int clks_num; const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; diff --git a/drivers/media/platform/qcom/venus/dbgfs.c b/drivers/media/platform/qcom/venus/dbgfs.c index 52de47f2ca88..726f4b730e69 100644 --- a/drivers/media/platform/qcom/venus/dbgfs.c +++ b/drivers/media/platform/qcom/venus/dbgfs.c @@ -4,13 +4,22 @@ */ #include <linux/debugfs.h> +#include <linux/fault-inject.h> #include "core.h" +#ifdef CONFIG_FAULT_INJECTION +DECLARE_FAULT_ATTR(venus_ssr_attr); +#endif + 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); + +#ifdef CONFIG_FAULT_INJECTION + fault_create_debugfs_attr("fail_ssr", core->root, &venus_ssr_attr); +#endif } void venus_dbgfs_deinit(struct venus_core *core) diff --git a/drivers/media/platform/qcom/venus/dbgfs.h b/drivers/media/platform/qcom/venus/dbgfs.h index b7b621a8472f..c87c1355d039 100644 --- a/drivers/media/platform/qcom/venus/dbgfs.h +++ b/drivers/media/platform/qcom/venus/dbgfs.h @@ -4,8 +4,21 @@ #ifndef __VENUS_DBGFS_H__ #define __VENUS_DBGFS_H__ +#include <linux/fault-inject.h> + struct venus_core; +#ifdef CONFIG_FAULT_INJECTION +extern struct fault_attr venus_ssr_attr; +static inline bool venus_fault_inject_ssr(void) +{ + return should_fail(&venus_ssr_attr, 1); +} +#else +static inline bool venus_fault_inject_ssr(void) { return false; } +#endif + + void venus_dbgfs_init(struct venus_core *core); void venus_dbgfs_deinit(struct venus_core *core); diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 5c1104379c49..60de4200375d 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -671,8 +671,7 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type, unsigned int i; int ret; - if (req) - memset(req, 0, sizeof(*req)); + memset(req, 0, sizeof(*req)); if (type == HFI_BUFFER_OUTPUT || type == HFI_BUFFER_OUTPUT2) req->count_min = inst->fw_min_cnt; @@ -694,8 +693,7 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type, if (hprop.bufreq[i].type != type) continue; - if (req) - memcpy(req, &hprop.bufreq[i], sizeof(*req)); + memcpy(req, &hprop.bufreq[i], sizeof(*req)); ret = 0; break; } diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 4ecd444050bb..930b743f225e 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -58,6 +58,15 @@ void pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, u32 mode) pkt->data[1] = mode; } +void pkt_sys_ubwc_config(struct hfi_sys_set_property_pkt *pkt, const struct hfi_ubwc_config *hfi) +{ + pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi); + pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG; + memcpy(&pkt->data[1], hfi, sizeof(*hfi)); +} + int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, u32 id, u32 size, u32 addr, void *cookie) { diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.h b/drivers/media/platform/qcom/venus/hfi_cmds.h index 327ed90a2788..99bc0b6db67c 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.h +++ b/drivers/media/platform/qcom/venus/hfi_cmds.h @@ -256,6 +256,7 @@ void pkt_sys_init(struct hfi_sys_init_pkt *pkt, u32 arch_type); void pkt_sys_pc_prep(struct hfi_sys_pc_prep_pkt *pkt); void pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, u32 enable); void pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, u32 enable); +void pkt_sys_ubwc_config(struct hfi_sys_set_property_pkt *pkt, const struct hfi_ubwc_config *hfi); int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, u32 id, u32 size, u32 addr, void *cookie); int pkt_sys_unset_resource(struct hfi_sys_release_resource_pkt *pkt, u32 id, diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index 2daa88e3df9f..d2d6719a2ba4 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -427,6 +427,7 @@ #define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 #define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 #define HFI_PROPERTY_SYS_CONFIG_COVERAGE 0x7 +#define HFI_PROPERTY_SYS_UBWC_CONFIG 0x8 /* * HFI_PROPERTY_PARAM_COMMON_START @@ -626,6 +627,25 @@ struct hfi_debug_config { u32 mode; }; +struct hfi_ubwc_config { + u32 size; + u32 packet_type; + struct { + u32 max_channel_override : 1; + u32 mal_length_override : 1; + u32 hb_override : 1; + u32 bank_swzl_level_override : 1; + u32 bank_spreading_override : 1; + u32 reserved : 27; + } override_bit_info; + u32 max_channels; + u32 mal_length; + u32 highest_bank_bit; + u32 bank_swzl_level; + u32 bank_spreading; + u32 reserved[2]; +}; + struct hfi_enable { u32 enable; }; diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index 5b8389b98299..6cf74b2bc5ae 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -234,6 +234,7 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst) const struct hfi_plat_caps *caps = NULL; u32 enc_codecs, dec_codecs, count = 0; unsigned int entries; + int ret; plat = hfi_platform_get(core->res->hfi_version); if (!plat) @@ -242,8 +243,9 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst) if (inst) return 0; - if (plat->codecs) - plat->codecs(&enc_codecs, &dec_codecs, &count); + ret = hfi_platform_get_codecs(core, &enc_codecs, &dec_codecs, &count); + if (ret) + return ret; if (plat->capabilities) caps = plat->capabilities(&entries); diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c index f16f8962273c..f07f554bc5fe 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.c +++ b/drivers/media/platform/qcom/venus/hfi_platform.c @@ -2,7 +2,9 @@ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include <linux/of_device.h> #include "hfi_platform.h" +#include "core.h" const struct hfi_platform *hfi_platform_get(enum hfi_version version) { @@ -66,3 +68,23 @@ hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_ return freq; } +int +hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs, u32 *count) +{ + const struct hfi_platform *plat; + + plat = hfi_platform_get(core->res->hfi_version); + if (!plat) + return -EINVAL; + + if (plat->codecs) + plat->codecs(enc_codecs, dec_codecs, count); + + if (of_device_is_compatible(core->dev->of_node, "qcom,sc7280-venus")) { + *enc_codecs &= ~HFI_VIDEO_CODEC_VP8; + *dec_codecs &= ~HFI_VIDEO_CODEC_VP8; + } + + return 0; +} + diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h index 1dcf4085928c..ec89a90a8129 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.h +++ b/drivers/media/platform/qcom/venus/hfi_platform.h @@ -66,4 +66,6 @@ unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 code u32 session_type); unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_type); +int hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs, + u32 *count); #endif diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 9a34662fea38..2ad40b3945b0 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -904,6 +904,24 @@ static int venus_sys_set_power_control(struct venus_hfi_device *hdev, return 0; } +static int venus_sys_set_ubwc_config(struct venus_hfi_device *hdev) +{ + struct hfi_sys_set_property_pkt *pkt; + u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE]; + const struct venus_resources *res = hdev->core->res; + int ret; + + pkt = (struct hfi_sys_set_property_pkt *)packet; + + pkt_sys_ubwc_config(pkt, res->ubwc_conf); + + ret = venus_iface_cmdq_write(hdev, pkt, false); + if (ret) + return ret; + + return 0; +} + static int venus_get_queue_size(struct venus_hfi_device *hdev, unsigned int index) { @@ -922,6 +940,7 @@ static int venus_get_queue_size(struct venus_hfi_device *hdev, static int venus_sys_set_default_properties(struct venus_hfi_device *hdev) { struct device *dev = hdev->core->dev; + const struct venus_resources *res = hdev->core->res; int ret; ret = venus_sys_set_debug(hdev, venus_fw_debug); @@ -945,6 +964,13 @@ static int venus_sys_set_default_properties(struct venus_hfi_device *hdev) dev_warn(dev, "setting hw power collapse ON failed (%d)\n", ret); + /* For specific venus core, it is mandatory to set the UBWC configuration */ + if (res->ubwc_conf) { + ret = venus_sys_set_ubwc_config(hdev); + if (ret) + dev_warn(dev, "setting ubwc config failed (%d)\n", ret); + } + return ret; } diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 49bdcfba010b..968a74234e92 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -845,7 +845,7 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags, continue; /* Get remote CSI-2, if any. */ - csi_pad = media_entity_remote_pad( + csi_pad = media_pad_remote_pad_first( &group->vin[i]->vdev.entity.pads[0]); if (!csi_pad) continue; @@ -1261,7 +1261,7 @@ static const struct rvin_info rcar_info_r8a77980 = { }; static const struct rvin_group_route rcar_info_r8a77990_routes[] = { - { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 }, + { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 }, { /* Sentinel */ } }; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c index fea8f00a9152..174aa6176f54 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c @@ -1313,7 +1313,7 @@ static int rcsi2_link_setup(struct media_entity *entity, channel = id % 4; if (flags & MEDIA_LNK_FL_ENABLED) { - if (media_entity_remote_pad(local)) { + if (media_pad_remote_pad_first(local)) { dev_dbg(priv->dev, "Each VC can only be routed to one output channel\n"); return -EINVAL; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 6644b498929d..8d37fbdc266a 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -1258,7 +1258,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) return ret == -ENOIOCTLCMD ? 0 : ret; } - pad = media_entity_remote_pad(&vin->pad); + pad = media_pad_remote_pad_first(&vin->pad); if (!pad) return -EPIPE; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index 2e2aa9d746ee..576059f9bbe3 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -1032,7 +1032,7 @@ static void rvin_notify(struct v4l2_subdev *sd, if (!vin) continue; - pad = media_entity_remote_pad(&vin->pad); + pad = media_pad_remote_pad_first(&vin->pad); if (!pad) continue; diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index 9a0982fa5c6b..3fec41f6e964 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -3,11 +3,6 @@ * R-Car Gen3 Digital Radio Interface (DRIF) driver * * Copyright (C) 2017 Renesas Electronics Corporation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /* @@ -1477,7 +1472,7 @@ MODULE_DEVICE_TABLE(of, rcar_drif_of_table); static struct platform_driver rcar_drif_driver = { .driver = { .name = RCAR_DRIF_DRV_NAME, - .of_match_table = of_match_ptr(rcar_drif_of_table), + .of_match_table = rcar_drif_of_table, .pm = &rcar_drif_pm_ops, }, .probe = rcar_drif_probe, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index a116a3362f9e..4c3bd2b1ca28 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -516,8 +516,8 @@ int vsp1_entity_link_setup(struct media_entity *entity, * higher than one for the data pipelines, except for the links to the HGO and * HGT that can be enabled in addition to a regular data link. When traversing * outgoing links this function ignores HGO and HGT entities and should thus be - * used in place of the generic media_entity_remote_pad() function to traverse - * data pipelines. + * used in place of the generic media_pad_remote_pad_first() function to + * traverse data pipelines. * * Return a pointer to the pad at the remote end of the first found enabled * link, or NULL if no enabled link has been found. diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index 51219b1b6ea9..e8e0ee5f2277 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -50,7 +50,7 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(local); + remote = media_pad_remote_pad_first(local); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; diff --git a/drivers/media/platform/rockchip/rkisp1/Kconfig b/drivers/media/platform/rockchip/rkisp1/Kconfig index dabd7e42c193..731c9acbf6ef 100644 --- a/drivers/media/platform/rockchip/rkisp1/Kconfig +++ b/drivers/media/platform/rockchip/rkisp1/Kconfig @@ -3,7 +3,7 @@ config VIDEO_ROCKCHIP_ISP1 tristate "Rockchip Image Signal Processing v1 Unit driver" depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV && OF - depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on ARCH_ROCKCHIP || ARCH_MXC || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/rockchip/rkisp1/Makefile b/drivers/media/platform/rockchip/rkisp1/Makefile index ab32a77db8f7..b3844c4f7623 100644 --- a/drivers/media/platform/rockchip/rkisp1/Makefile +++ b/drivers/media/platform/rockchip/rkisp1/Makefile @@ -1,10 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 +rockchip-isp1-y := rkisp1-capture.o \ + rkisp1-common.o \ + rkisp1-csi.o \ + rkisp1-dev.o \ + rkisp1-isp.o \ + rkisp1-resizer.o \ + rkisp1-stats.o \ + rkisp1-params.o + +rockchip-isp1-$(CONFIG_DEBUG_FS) += rkisp1-debug.o + obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o -rockchip-isp1-objs += rkisp1-capture.o \ - rkisp1-common.o \ - rkisp1-dev.o \ - rkisp1-isp.o \ - rkisp1-resizer.o \ - rkisp1-stats.o \ - rkisp1-params.o diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index fee2aaacb26b..d5904c96ff3f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -383,7 +383,7 @@ static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap) mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN | RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm, @@ -404,7 +404,7 @@ static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap) u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC); mi_imsc |= RKISP1_CIF_MI_FRAME(cap); - rkisp1_write(cap->rkisp1, mi_imsc, RKISP1_CIF_MI_IMSC); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_IMSC, mi_imsc); } static void rkisp1_mp_config(struct rkisp1_capture *cap) @@ -413,12 +413,12 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) struct rkisp1_device *rkisp1 = cap->rkisp1; u32 reg; - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), - cap->config->mi.y_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), - cap->config->mi.cb_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), - cap->config->mi.cr_size_init); + rkisp1_write(rkisp1, cap->config->mi.y_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y)); + rkisp1_write(rkisp1, cap->config->mi.cb_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB)); + rkisp1_write(rkisp1, cap->config->mi.cr_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); rkisp1_irq_frame_end_enable(cap); @@ -429,7 +429,7 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; else reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg); } rkisp1_mi_config_ctrl(cap); @@ -437,11 +437,11 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK; reg |= cap->pix.cfg->write_format; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg); reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg); } static void rkisp1_sp_config(struct rkisp1_capture *cap) @@ -450,16 +450,16 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) struct rkisp1_device *rkisp1 = cap->rkisp1; u32 mi_ctrl, reg; - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y), - cap->config->mi.y_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB), - cap->config->mi.cb_size_init); - rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR), - cap->config->mi.cr_size_init); + rkisp1_write(rkisp1, cap->config->mi.y_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y)); + rkisp1_write(rkisp1, cap->config->mi.cb_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB)); + rkisp1_write(rkisp1, cap->config->mi.cr_size_init, + rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); - rkisp1_write(rkisp1, pixm->width, RKISP1_CIF_MI_SP_Y_PIC_WIDTH); - rkisp1_write(rkisp1, pixm->height, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT); - rkisp1_write(rkisp1, cap->sp_y_stride, RKISP1_CIF_MI_SP_Y_LLENGTH); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride); rkisp1_irq_frame_end_enable(cap); @@ -470,7 +470,7 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; else reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP; - rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg); } rkisp1_mi_config_ctrl(cap); @@ -481,7 +481,7 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) RKISP1_MI_CTRL_SP_INPUT_YUV422 | cap->pix.cfg->output_format | RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE; - rkisp1_write(rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_mp_disable(struct rkisp1_capture *cap) @@ -490,7 +490,7 @@ static void rkisp1_mp_disable(struct rkisp1_capture *cap) mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE | RKISP1_CIF_MI_CTRL_RAW_ENABLE); - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_sp_disable(struct rkisp1_capture *cap) @@ -498,7 +498,7 @@ static void rkisp1_sp_disable(struct rkisp1_capture *cap) u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_mp_enable(struct rkisp1_capture *cap) @@ -514,7 +514,7 @@ static void rkisp1_mp_enable(struct rkisp1_capture *cap) else mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_sp_enable(struct rkisp1_capture *cap) @@ -522,15 +522,14 @@ static void rkisp1_sp_enable(struct rkisp1_capture *cap) u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL); mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE; - rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl); } static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap) { if (!cap->is_streaming) return; - rkisp1_write(cap->rkisp1, - RKISP1_CIF_MI_FRAME(cap), RKISP1_CIF_MI_ICR); + rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_ICR, RKISP1_CIF_MI_FRAME(cap)); cap->ops->disable(cap); } @@ -554,7 +553,7 @@ static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap) dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP | RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI; - rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl); } static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) @@ -562,7 +561,7 @@ static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap) u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL); dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP; - rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL); + rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl); } static const struct rkisp1_capture_ops rkisp1_capture_ops_mp = { @@ -628,9 +627,8 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap) buff_addr = cap->buf.next->buff_addr; - rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_Y], - cap->config->mi.y_base_ad_init); + rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init, + buff_addr[RKISP1_PLANE_Y]); /* * In order to support grey format we capture * YUV422 planar format from the camera and @@ -638,39 +636,36 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap) */ if (cap->pix.cfg->fourcc == V4L2_PIX_FMT_GREY) { rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cb_base_ad_init); + cap->config->mi.cb_base_ad_init, + cap->buf.dummy.dma_addr); rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cr_base_ad_init); + cap->config->mi.cr_base_ad_init, + cap->buf.dummy.dma_addr); } else { rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_CB], - cap->config->mi.cb_base_ad_init); + cap->config->mi.cb_base_ad_init, + buff_addr[RKISP1_PLANE_CB]); rkisp1_write(cap->rkisp1, - buff_addr[RKISP1_PLANE_CR], - cap->config->mi.cr_base_ad_init); + cap->config->mi.cr_base_ad_init, + buff_addr[RKISP1_PLANE_CR]); } } else { /* * Use the dummy space allocated by dma_alloc_coherent to * throw data if there is no available buffer. */ - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.y_base_ad_init); - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cb_base_ad_init); - rkisp1_write(cap->rkisp1, - cap->buf.dummy.dma_addr, - cap->config->mi.cr_base_ad_init); + rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init, + cap->buf.dummy.dma_addr); + rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init, + cap->buf.dummy.dma_addr); + rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init, + cap->buf.dummy.dma_addr); } /* Set plane offsets */ - rkisp1_write(cap->rkisp1, 0, cap->config->mi.y_offs_cnt_init); - rkisp1_write(cap->rkisp1, 0, cap->config->mi.cb_offs_cnt_init); - rkisp1_write(cap->rkisp1, 0, cap->config->mi.cr_offs_cnt_init); + rkisp1_write(cap->rkisp1, cap->config->mi.y_offs_cnt_init, 0); + rkisp1_write(cap->rkisp1, cap->config->mi.cb_offs_cnt_init, 0); + rkisp1_write(cap->rkisp1, cap->config->mi.cr_offs_cnt_init, 0); } /* @@ -710,7 +705,7 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx) if (!status) return IRQ_NONE; - rkisp1_write(rkisp1, status, RKISP1_CIF_MI_ICR); + rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, status); for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) { struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; @@ -888,8 +883,8 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) */ if (!other->is_streaming) { /* force cfg update */ - rkisp1_write(rkisp1, - RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT); + rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT, + RKISP1_CIF_MI_INIT_SOFT_UPD); rkisp1_set_next_buf(cap); } spin_unlock_irq(&cap->buf.lock); @@ -931,11 +926,8 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) * If the other capture is streaming, isp and sensor nodes shouldn't * be disabled, skip them. */ - if (rkisp1->pipe.streaming_count < 2) { - v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, - false); + if (rkisp1->pipe.streaming_count < 2) v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); - } v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, false); @@ -971,15 +963,8 @@ static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) if (ret) goto err_disable_rsz; - ret = v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream, - true); - if (ret) - goto err_disable_isp; - return 0; -err_disable_isp: - v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); err_disable_rsz: v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, false); @@ -1253,11 +1238,8 @@ static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh, static int rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct rkisp1_capture *cap_dev = video_drvdata(file); - struct rkisp1_device *rkisp1 = cap_dev->rkisp1; - - strscpy(cap->driver, rkisp1->dev->driver->name, sizeof(cap->driver)); - strscpy(cap->card, rkisp1->dev->driver->name, sizeof(cap->card)); + strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, RKISP1_DRIVER_NAME, sizeof(cap->card)); strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info)); return 0; @@ -1302,8 +1284,16 @@ static int rkisp1_capture_link_validate(struct media_link *link) if (sd_fmt.format.height != cap->pix.fmt.height || sd_fmt.format.width != cap->pix.fmt.width || - sd_fmt.format.code != fmt->mbus) + sd_fmt.format.code != fmt->mbus) { + dev_dbg(cap->rkisp1->dev, + "link '%s':%u -> '%s':%u not valid: 0x%04x/%ux%u != 0x%04x/%ux%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, + sd_fmt.format.code, sd_fmt.format.width, + sd_fmt.format.height, fmt->mbus, cap->pix.fmt.width, + cap->pix.fmt.height); return -EPIPE; + } return 0; } @@ -1326,8 +1316,12 @@ static const struct v4l2_file_operations rkisp1_fops = { static void rkisp1_unregister_capture(struct rkisp1_capture *cap) { + if (!video_is_registered(&cap->vnode.vdev)) + return; + media_entity_cleanup(&cap->vnode.vdev.entity); vb2_video_unregister_device(&cap->vnode.vdev); + mutex_destroy(&cap->vnode.vlock); } void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1) @@ -1381,27 +1375,31 @@ static int rkisp1_register_capture(struct rkisp1_capture *cap) if (ret) { dev_err(cap->rkisp1->dev, "vb2 queue init failed (err=%d)\n", ret); - return ret; + goto error; } vdev->queue = q; + ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); + if (ret) + goto error; + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(cap->rkisp1->dev, "failed to register %s, ret=%d\n", vdev->name, ret); - return ret; + goto error; } + v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name, vdev->num); - ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); - if (ret) { - video_unregister_device(vdev); - return ret; - } - return 0; + +error: + media_entity_cleanup(&vdev->entity); + mutex_destroy(&node->vlock); + return ret; } static void @@ -1436,26 +1434,21 @@ rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id) int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1) { - struct rkisp1_capture *cap; - unsigned int i, j; + unsigned int i; int ret; for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) { + struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; + rkisp1_capture_init(rkisp1, i); - cap = &rkisp1->capture_devs[i]; - cap->rkisp1 = rkisp1; + ret = rkisp1_register_capture(cap); - if (ret) - goto err_unreg_capture_devs; + if (ret) { + rkisp1_capture_devs_unregister(rkisp1); + return ret; + } } return 0; -err_unreg_capture_devs: - for (j = 0; j < i; j++) { - cap = &rkisp1->capture_devs[j]; - rkisp1_unregister_capture(cap); - } - - return ret; } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c index cf889666e166..f956b90a407a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c @@ -5,10 +5,153 @@ * Copyright (C) 2019 Collabora, Ltd. */ +#include <media/mipi-csi2.h> #include <media/v4l2-rect.h> #include "rkisp1-common.h" +static const struct rkisp1_mbus_info rkisp1_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .direction = RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW10, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 10, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW12, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 12, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_RGGB, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_BGGR, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GBRG, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .pixel_enc = V4L2_PIXEL_ENC_BAYER, + .mipi_dt = MIPI_CSI2_DT_RAW8, + .bayer_pat = RKISP1_RAW_GRBG, + .bus_width = 8, + .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, + }, { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .pixel_enc = V4L2_PIXEL_ENC_YUV, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, + .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, + .bus_width = 16, + .direction = RKISP1_ISP_SD_SINK, + }, +}; + +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index) +{ + if (index >= ARRAY_SIZE(rkisp1_formats)) + return NULL; + + return &rkisp1_formats[index]; +} + +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rkisp1_formats); i++) { + const struct rkisp1_mbus_info *fmt = &rkisp1_formats[i]; + + if (fmt->mbus_code == mbus_code) + return fmt; + } + + return NULL; +} + static const struct v4l2_rect rkisp1_sd_min_crop = { .width = RKISP1_ISP_MIN_WIDTH, .height = RKISP1_ISP_MIN_HEIGHT, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index d8fa3f1a5a85..8056997d5c29 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -23,18 +23,20 @@ #include "rkisp1-regs.h" +struct dentry; + /* - * flags on the 'direction' field in struct 'rkisp1_isp_mbus_info' that indicate + * flags on the 'direction' field in struct rkisp1_mbus_info' that indicate * on which pad the media bus format is supported */ -#define RKISP1_ISP_SD_SRC BIT(0) -#define RKISP1_ISP_SD_SINK BIT(1) +#define RKISP1_ISP_SD_SRC BIT(0) +#define RKISP1_ISP_SD_SINK BIT(1) /* min and max values for the widths and heights of the entities */ -#define RKISP1_ISP_MAX_WIDTH 4032 -#define RKISP1_ISP_MAX_HEIGHT 3024 -#define RKISP1_ISP_MIN_WIDTH 32 -#define RKISP1_ISP_MIN_HEIGHT 32 +#define RKISP1_ISP_MAX_WIDTH 4032 +#define RKISP1_ISP_MAX_HEIGHT 3024 +#define RKISP1_ISP_MIN_WIDTH 32 +#define RKISP1_ISP_MIN_HEIGHT 32 #define RKISP1_RSZ_MP_SRC_MAX_WIDTH 4416 #define RKISP1_RSZ_MP_SRC_MAX_HEIGHT 3312 @@ -44,20 +46,20 @@ #define RKISP1_RSZ_SRC_MIN_HEIGHT 16 /* the default width and height of all the entities */ -#define RKISP1_DEFAULT_WIDTH 800 -#define RKISP1_DEFAULT_HEIGHT 600 +#define RKISP1_DEFAULT_WIDTH 800 +#define RKISP1_DEFAULT_HEIGHT 600 -#define RKISP1_DRIVER_NAME "rkisp1" -#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME +#define RKISP1_DRIVER_NAME "rkisp1" +#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME /* maximum number of clocks */ -#define RKISP1_MAX_BUS_CLK 8 +#define RKISP1_MAX_BUS_CLK 8 /* a bitmask of the ready stats */ -#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \ - RKISP1_CIF_ISP_AFM_FIN | \ - RKISP1_CIF_ISP_EXP_END | \ - RKISP1_CIF_ISP_HIST_MEASURE_RDY) +#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \ + RKISP1_CIF_ISP_AFM_FIN | \ + RKISP1_CIF_ISP_EXP_END | \ + RKISP1_CIF_ISP_HIST_MEASURE_RDY) /* enum for the resizer pads */ enum rkisp1_rsz_pad { @@ -66,6 +68,13 @@ enum rkisp1_rsz_pad { RKISP1_RSZ_PAD_MAX }; +/* enum for the csi receiver pads */ +enum rkisp1_csi_pad { + RKISP1_CSI_PAD_SINK, + RKISP1_CSI_PAD_SRC, + RKISP1_CSI_PAD_NUM +}; + /* enum for the capture id */ enum rkisp1_stream_id { RKISP1_MAINPATH, @@ -90,25 +99,89 @@ enum rkisp1_isp_pad { }; /* + * enum rkisp1_feature - ISP features + * + * @RKISP1_FEATURE_MIPI_CSI2: The ISP has an internal MIPI CSI-2 receiver + * + * The ISP features are stored in a bitmask in &rkisp1_info.features and allow + * the driver to implement support for features present in some ISP versions + * only. + */ +enum rkisp1_feature { + RKISP1_FEATURE_MIPI_CSI2 = BIT(0), +}; + +/* + * struct rkisp1_info - Model-specific ISP Information + * + * @clks: array of ISP clock names + * @clk_size: number of entries in the @clks array + * @isrs: array of ISP interrupt descriptors + * @isr_size: number of entries in the @isrs array + * @isp_ver: ISP version + * @features: bitmask of rkisp1_feature features implemented by the ISP + * + * This structure contains information about the ISP specific to a particular + * ISP model, version, or integration in a particular SoC. + */ +struct rkisp1_info { + const char * const *clks; + unsigned int clk_size; + const struct rkisp1_isr_data *isrs; + unsigned int isr_size; + enum rkisp1_cif_isp_version isp_ver; + unsigned int features; +}; + +/* * struct rkisp1_sensor_async - A container for the v4l2_async_subdev to add to the notifier * of the v4l2-async API * * @asd: async_subdev variable for the sensor + * @index: index of the sensor (counting sensor found in DT) + * @source_ep: fwnode for the sensor source endpoint * @lanes: number of lanes * @mbus_type: type of bus (currently only CSI2 is supported) * @mbus_flags: media bus (V4L2_MBUS_*) flags * @sd: a pointer to v4l2_subdev struct of the sensor * @pixel_rate_ctrl: pixel rate of the sensor, used to initialize the phy - * @dphy: a pointer to the phy + * @port: port number (0: MIPI, 1: Parallel) */ struct rkisp1_sensor_async { struct v4l2_async_subdev asd; + unsigned int index; + struct fwnode_handle *source_ep; unsigned int lanes; enum v4l2_mbus_type mbus_type; unsigned int mbus_flags; struct v4l2_subdev *sd; struct v4l2_ctrl *pixel_rate_ctrl; + unsigned int port; +}; + +/* + * struct rkisp1_csi - CSI receiver subdev + * + * @rkisp1: pointer to the rkisp1 device + * @dphy: a pointer to the phy + * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) + * @sd: v4l2_subdev variable + * @pads: media pads + * @pad_cfg: configurations for the pads + * @sink_fmt: input format + * @lock: protects pad_cfg and sink_fmt + * @source: source in-use, set when starting streaming + */ +struct rkisp1_csi { + struct rkisp1_device *rkisp1; struct phy *dphy; + bool is_dphy_errctrl_disabled; + struct v4l2_subdev sd; + struct media_pad pads[RKISP1_CSI_PAD_NUM]; + struct v4l2_subdev_pad_config pad_cfg[RKISP1_CSI_PAD_NUM]; + const struct rkisp1_mbus_info *sink_fmt; + struct mutex lock; + struct v4l2_subdev *source; }; /* @@ -121,17 +194,16 @@ struct rkisp1_sensor_async { * @sink_fmt: input format * @src_fmt: output format * @ops_lock: ops serialization - * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt) * @frame_sequence: used to synchronize frame_id between video devices. */ struct rkisp1_isp { struct v4l2_subdev sd; + struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_ISP_PAD_MAX]; struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX]; - const struct rkisp1_isp_mbus_info *sink_fmt; - const struct rkisp1_isp_mbus_info *src_fmt; + const struct rkisp1_mbus_info *sink_fmt; + const struct rkisp1_mbus_info *src_fmt; struct mutex ops_lock; /* serialize the subdevice ops */ - bool is_dphy_errctrl_disabled; __u32 frame_sequence; }; @@ -313,6 +385,7 @@ struct rkisp1_params { * struct rkisp1_resizer - Resizer subdev * * @sd: v4l2_subdev variable + * @regs_base: base register address offset * @id: id of the resizer, one of RKISP1_SELFPATH, RKISP1_MAINPATH * @rkisp1: pointer to the rkisp1 device * @pads: media pads @@ -323,6 +396,7 @@ struct rkisp1_params { */ struct rkisp1_resizer { struct v4l2_subdev sd; + u32 regs_base; enum rkisp1_stream_id id; struct rkisp1_device *rkisp1; struct media_pad pads[RKISP1_RSZ_PAD_MAX]; @@ -373,7 +447,8 @@ struct rkisp1_debug { * @v4l2_dev: v4l2_device variable * @media_dev: media_device variable * @notifier: a notifier to register on the v4l2-async API to be notified on the sensor - * @active_sensor: sensor in-use, set when streaming on + * @source: source subdev in-use, set when starting streaming + * @csi: internal CSI-2 receiver * @isp: ISP sub-device * @resizer_devs: resizer sub-devices * @capture_devs: capture devices @@ -382,6 +457,7 @@ struct rkisp1_debug { * @pipe: media pipeline * @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices. * @debug: debug params to be exposed on debugfs + * @info: version-specific ISP information */ struct rkisp1_device { void __iomem *base_addr; @@ -391,7 +467,8 @@ struct rkisp1_device { struct v4l2_device v4l2_dev; struct media_device media_dev; struct v4l2_async_notifier notifier; - struct rkisp1_sensor_async *active_sensor; + struct v4l2_subdev *source; + struct rkisp1_csi csi; struct rkisp1_isp isp; struct rkisp1_resizer resizer_devs[2]; struct rkisp1_capture capture_devs[2]; @@ -400,11 +477,12 @@ struct rkisp1_device { struct media_pipeline pipe; struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */ struct rkisp1_debug debug; + const struct rkisp1_info *info; }; /* - * struct rkisp1_isp_mbus_info - ISP media bus info, Translates media bus code to hardware - * format values + * struct rkisp1_mbus_info - ISP media bus info, Translates media bus code to hardware + * format values * * @mbus_code: media bus code * @pixel_enc: pixel encoding @@ -414,7 +492,7 @@ struct rkisp1_device { * @bayer_pat: bayer pattern * @direction: a bitmask of the flags indicating on which pad the format is supported on */ -struct rkisp1_isp_mbus_info { +struct rkisp1_mbus_info { u32 mbus_code; enum v4l2_pixel_encoding pixel_enc; u32 mipi_dt; @@ -425,7 +503,7 @@ struct rkisp1_isp_mbus_info { }; static inline void -rkisp1_write(struct rkisp1_device *rkisp1, u32 val, unsigned int addr) +rkisp1_write(struct rkisp1_device *rkisp1, unsigned int addr, u32 val) { writel(val, rkisp1->base_addr + addr); } @@ -447,6 +525,13 @@ int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap, struct v4l2_subdev_mbus_code_enum *code); /* + * rkisp1_mbus_info_get_by_index - Retrieve the ith supported mbus info + * + * @index: index of the mbus info to fetch + */ +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index); + +/* * rkisp1_sd_adjust_crop_rect - adjust a rectangle to fit into another rectangle. * * @crop: rectangle to adjust. @@ -465,11 +550,11 @@ void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, const struct v4l2_mbus_framefmt *bounds); /* - * rkisp1_isp_mbus_info - get the isp info of the media bus code + * rkisp1_mbus_info_get_by_code - get the isp info of the media bus code * * @mbus_code: the media bus code */ -const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code); +const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code); /* rkisp1_params_configure - configure the params when stream starts. * This function is called by the isp entity upon stream starts. @@ -493,7 +578,7 @@ void rkisp1_params_disable(struct rkisp1_params *params); /* irq handlers */ irqreturn_t rkisp1_isp_isr(int irq, void *ctx); -irqreturn_t rkisp1_mipi_isr(int irq, void *ctx); +irqreturn_t rkisp1_csi_isr(int irq, void *ctx); irqreturn_t rkisp1_capture_isr(int irq, void *ctx); void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris); void rkisp1_params_isr(struct rkisp1_device *rkisp1); @@ -514,4 +599,16 @@ void rkisp1_stats_unregister(struct rkisp1_device *rkisp1); int rkisp1_params_register(struct rkisp1_device *rkisp1); void rkisp1_params_unregister(struct rkisp1_device *rkisp1); +#if IS_ENABLED(CONFIG_DEBUG_FS) +void rkisp1_debug_init(struct rkisp1_device *rkisp1); +void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1); +#else +static inline void rkisp1_debug_init(struct rkisp1_device *rkisp1) +{ +} +static inline void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1) +{ +} +#endif + #endif /* _RKISP1_COMMON_H */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c new file mode 100644 index 000000000000..d7acc94e10f8 --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - CSI-2 Receiver + * + * Copyright (C) 2019 Collabora, Ltd. + * Copyright (C) 2022 Ideas on Board + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/lockdep.h> +#include <linux/phy/phy.h> +#include <linux/phy/phy-mipi-dphy.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> + +#include "rkisp1-common.h" +#include "rkisp1-csi.h" + +#define RKISP1_CSI_DEV_NAME RKISP1_DRIVER_NAME "_csi" + +#define RKISP1_CSI_DEF_FMT MEDIA_BUS_FMT_SRGGB10_1X10 + +static inline struct rkisp1_csi *to_rkisp1_csi(struct v4l2_subdev *sd) +{ + return container_of(sd, struct rkisp1_csi, sd); +} + +static struct v4l2_mbus_framefmt * +rkisp1_csi_get_pad_fmt(struct rkisp1_csi *csi, + struct v4l2_subdev_state *sd_state, + unsigned int pad, u32 which) +{ + struct v4l2_subdev_state state = { + .pads = csi->pad_cfg + }; + + lockdep_assert_held(&csi->lock); + + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); + else + return v4l2_subdev_get_try_format(&csi->sd, &state, pad); +} + +int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, + struct rkisp1_sensor_async *s_asd, + unsigned int source_pad) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + int ret; + + s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, + V4L2_CID_PIXEL_RATE); + if (!s_asd->pixel_rate_ctrl) { + dev_err(rkisp1->dev, "No pixel rate control in subdev %s\n", + sd->name); + return -EINVAL; + } + + /* Create the link from the sensor to the CSI receiver. */ + ret = media_create_pad_link(&sd->entity, source_pad, + &csi->sd.entity, RKISP1_CSI_PAD_SINK, + !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0); + if (ret) { + dev_err(csi->rkisp1->dev, "failed to link src pad of %s\n", + sd->name); + return ret; + } + + return 0; +} + +static int rkisp1_csi_config(struct rkisp1_csi *csi, + const struct rkisp1_sensor_async *sensor) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + unsigned int lanes = sensor->lanes; + u32 mipi_ctrl; + + if (lanes < 1 || lanes > 4) + return -EINVAL; + + mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) | + RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) | + RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | + RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA; + + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, mipi_ctrl); + + /* V12 could also use a newer csi2-host, but we don't want that yet */ + if (rkisp1->info->isp_ver == RKISP1_V12) + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CSI0_CTRL0, 0); + + /* Configure Data Type and Virtual Channel */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL, + RKISP1_CIF_MIPI_DATA_SEL_DT(csi->sink_fmt->mipi_dt) | + RKISP1_CIF_MIPI_DATA_SEL_VC(0)); + + /* Clear MIPI interrupts */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0); + + /* + * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for + * isp bus may be dead when switch isp. + */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, + RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI | + RKISP1_CIF_MIPI_ERR_DPHY | + RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) | + RKISP1_CIF_MIPI_ADD_DATA_OVFLW); + + dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n" + " MIPI_IMG_DATA_SEL 0x%08x\n" + " MIPI_STATUS 0x%08x\n" + " MIPI_IMSC 0x%08x\n", + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS), + rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC)); + + return 0; +} + +static void rkisp1_csi_enable(struct rkisp1_csi *csi) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + u32 val; + + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, + val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA); +} + +static void rkisp1_csi_disable(struct rkisp1_csi *csi) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + u32 val; + + /* Mask and clear interrupts. */ + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, 0); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0); + + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, + val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA)); +} + +static int rkisp1_csi_start(struct rkisp1_csi *csi, + const struct rkisp1_sensor_async *sensor) +{ + struct rkisp1_device *rkisp1 = csi->rkisp1; + union phy_configure_opts opts; + struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; + s64 pixel_clock; + int ret; + + ret = rkisp1_csi_config(csi, sensor); + if (ret) + return ret; + + pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl); + if (!pixel_clock) { + dev_err(rkisp1->dev, "Invalid pixel rate value\n"); + return -EINVAL; + } + + phy_mipi_dphy_get_default_config(pixel_clock, csi->sink_fmt->bus_width, + sensor->lanes, cfg); + phy_set_mode(csi->dphy, PHY_MODE_MIPI_DPHY); + phy_configure(csi->dphy, &opts); + phy_power_on(csi->dphy); + + rkisp1_csi_enable(csi); + + /* + * CIF spec says to wait for sufficient time after enabling + * the MIPI interface and before starting the sensor output. + */ + usleep_range(1000, 1200); + + return 0; +} + +static void rkisp1_csi_stop(struct rkisp1_csi *csi) +{ + rkisp1_csi_disable(csi); + + phy_power_off(csi->dphy); +} + +irqreturn_t rkisp1_csi_isr(int irq, void *ctx) +{ + struct device *dev = ctx; + struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + u32 val, status; + + status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); + if (!status) + return IRQ_NONE; + + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, status); + + /* + * Disable DPHY errctrl interrupt, because this dphy + * erctrl signal is asserted until the next changes + * of line state. This time is may be too long and cpu + * is hold in this interrupt. + */ + if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, + val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f)); + rkisp1->csi.is_dphy_errctrl_disabled = true; + } + + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (status == RKISP1_CIF_MIPI_FRAME_END) { + /* + * Enable DPHY errctrl interrupt again, if mipi have receive + * the whole frame without any error. + */ + if (rkisp1->csi.is_dphy_errctrl_disabled) { + val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); + val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f); + rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, val); + rkisp1->csi.is_dphy_errctrl_disabled = false; + } + } else { + rkisp1->debug.mipi_error++; + } + + return IRQ_HANDLED; +} + +/* ---------------------------------------------------------------------------- + * Subdev pad operations + */ + +static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + unsigned int i; + int pos = 0; + + if (code->pad == RKISP1_CSI_PAD_SRC) { + const struct v4l2_mbus_framefmt *sink_fmt; + + if (code->index) + return -EINVAL; + + mutex_lock(&csi->lock); + + sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, + RKISP1_CSI_PAD_SINK, + code->which); + code->code = sink_fmt->code; + + mutex_unlock(&csi->lock); + + return 0; + } + + for (i = 0; ; i++) { + const struct rkisp1_mbus_info *fmt = + rkisp1_mbus_info_get_by_index(i); + + if (!fmt) + return -EINVAL; + + if (!(fmt->direction & RKISP1_ISP_SD_SINK)) + continue; + + if (code->index == pos) { + code->code = fmt->mbus_code; + return 0; + } + + pos++; + } + + return -EINVAL; +} + +static int rkisp1_csi_init_config(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + + sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, + RKISP1_CSI_PAD_SINK); + src_fmt = v4l2_subdev_get_try_format(sd, sd_state, + RKISP1_CSI_PAD_SRC); + + sink_fmt->width = RKISP1_DEFAULT_WIDTH; + sink_fmt->height = RKISP1_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = RKISP1_CSI_DEF_FMT; + + *src_fmt = *sink_fmt; + + return 0; +} + +static int rkisp1_csi_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + + mutex_lock(&csi->lock); + fmt->format = *rkisp1_csi_get_pad_fmt(csi, sd_state, fmt->pad, + fmt->which); + mutex_unlock(&csi->lock); + + return 0; +} + +static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + const struct rkisp1_mbus_info *mbus_info; + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + + /* The format on the source pad always matches the sink pad. */ + if (fmt->pad == RKISP1_CSI_PAD_SRC) + return rkisp1_csi_get_fmt(sd, sd_state, fmt); + + mutex_lock(&csi->lock); + + sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SINK, + fmt->which); + + sink_fmt->code = fmt->format.code; + + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); + if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { + sink_fmt->code = RKISP1_CSI_DEF_FMT; + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); + } + + sink_fmt->width = clamp_t(u32, fmt->format.width, + RKISP1_ISP_MIN_WIDTH, + RKISP1_ISP_MAX_WIDTH); + sink_fmt->height = clamp_t(u32, fmt->format.height, + RKISP1_ISP_MIN_HEIGHT, + RKISP1_ISP_MAX_HEIGHT); + + fmt->format = *sink_fmt; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + csi->sink_fmt = mbus_info; + + /* Propagate the format to the source pad. */ + src_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SRC, + fmt->which); + *src_fmt = *sink_fmt; + + mutex_unlock(&csi->lock); + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Subdev video operations + */ + +static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rkisp1_csi *csi = to_rkisp1_csi(sd); + struct rkisp1_device *rkisp1 = csi->rkisp1; + struct rkisp1_sensor_async *source_asd; + struct media_pad *source_pad; + struct v4l2_subdev *source; + int ret; + + if (!enable) { + v4l2_subdev_call(csi->source, video, s_stream, false); + + rkisp1_csi_stop(csi); + + return 0; + } + + source_pad = media_entity_remote_source_pad_unique(&sd->entity); + if (IS_ERR(source_pad)) { + dev_dbg(rkisp1->dev, "Failed to get source for CSI: %ld\n", + PTR_ERR(source_pad)); + return -EPIPE; + } + + source = media_entity_to_v4l2_subdev(source_pad->entity); + if (!source) { + /* This should really not happen, so is not worth a message. */ + return -EPIPE; + } + + source_asd = container_of(source->asd, struct rkisp1_sensor_async, asd); + if (source_asd->mbus_type != V4L2_MBUS_CSI2_DPHY) + return -EINVAL; + + mutex_lock(&csi->lock); + ret = rkisp1_csi_start(csi, source_asd); + mutex_unlock(&csi->lock); + if (ret) + return ret; + + ret = v4l2_subdev_call(source, video, s_stream, true); + if (ret) { + rkisp1_csi_stop(csi); + return ret; + } + + csi->source = source; + + return 0; +} + +/* ---------------------------------------------------------------------------- + * Registration + */ + +static const struct media_entity_operations rkisp1_csi_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = { + .s_stream = rkisp1_csi_s_stream, +}; + +static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = { + .enum_mbus_code = rkisp1_csi_enum_mbus_code, + .init_cfg = rkisp1_csi_init_config, + .get_fmt = rkisp1_csi_get_fmt, + .set_fmt = rkisp1_csi_set_fmt, +}; + +static const struct v4l2_subdev_ops rkisp1_csi_ops = { + .video = &rkisp1_csi_video_ops, + .pad = &rkisp1_csi_pad_ops, +}; + +int rkisp1_csi_register(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + struct v4l2_subdev_state state = {}; + struct media_pad *pads; + struct v4l2_subdev *sd; + int ret; + + csi->rkisp1 = rkisp1; + mutex_init(&csi->lock); + + sd = &csi->sd; + v4l2_subdev_init(sd, &rkisp1_csi_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->entity.ops = &rkisp1_csi_media_ops; + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->owner = THIS_MODULE; + strscpy(sd->name, RKISP1_CSI_DEV_NAME, sizeof(sd->name)); + + pads = csi->pads; + pads[RKISP1_CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + pads[RKISP1_CSI_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; + + csi->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_CSI_DEF_FMT); + + ret = media_entity_pads_init(&sd->entity, RKISP1_CSI_PAD_NUM, pads); + if (ret) + goto error; + + state.pads = csi->pad_cfg; + rkisp1_csi_init_config(sd, &state); + + ret = v4l2_device_register_subdev(&csi->rkisp1->v4l2_dev, sd); + if (ret) { + dev_err(sd->dev, "Failed to register csi receiver subdev\n"); + goto error; + } + + return 0; + +error: + media_entity_cleanup(&sd->entity); + mutex_destroy(&csi->lock); + csi->rkisp1 = NULL; + return ret; +} + +void rkisp1_csi_unregister(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + + if (!csi->rkisp1) + return; + + v4l2_device_unregister_subdev(&csi->sd); + media_entity_cleanup(&csi->sd.entity); + mutex_destroy(&csi->lock); +} + +int rkisp1_csi_init(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + + csi->rkisp1 = rkisp1; + + csi->dphy = devm_phy_get(rkisp1->dev, "dphy"); + if (IS_ERR(csi->dphy)) + return dev_err_probe(rkisp1->dev, PTR_ERR(csi->dphy), + "Couldn't get the MIPI D-PHY\n"); + + phy_init(csi->dphy); + + return 0; +} + +void rkisp1_csi_cleanup(struct rkisp1_device *rkisp1) +{ + struct rkisp1_csi *csi = &rkisp1->csi; + + phy_exit(csi->dphy); +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h new file mode 100644 index 000000000000..1f5f2af31a7d --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Rockchip ISP1 Driver - CSI-2 Receiver + * + * Copyright (C) 2019 Collabora, Ltd. + * Copyright (C) 2022 Ideas on Board + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ +#ifndef _RKISP1_CSI_H +#define _RKISP1_CSI_H + +struct rkisp1_csi; +struct rkisp1_device; +struct rkisp1_sensor_async; + +int rkisp1_csi_init(struct rkisp1_device *rkisp1); +void rkisp1_csi_cleanup(struct rkisp1_device *rkisp1); + +int rkisp1_csi_register(struct rkisp1_device *rkisp1); +void rkisp1_csi_unregister(struct rkisp1_device *rkisp1); + +int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd, + struct rkisp1_sensor_async *s_asd, + unsigned int source_pad); + +#endif /* _RKISP1_CSI_H */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c new file mode 100644 index 000000000000..71df3dc95e6f --- /dev/null +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Rockchip ISP1 Driver - Base driver + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd. + * Copyright (C) 2017 Rockchip Electronics Co., Ltd. + */ + +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/minmax.h> +#include <linux/pm_runtime.h> +#include <linux/seq_file.h> +#include <linux/string.h> + +#include "rkisp1-common.h" +#include "rkisp1-regs.h" + +struct rkisp1_debug_register { + u32 reg; + u32 shd; + const char * const name; +}; + +#define RKISP1_DEBUG_REG(name) { RKISP1_CIF_##name, 0, #name } +#define RKISP1_DEBUG_SHD_REG(name) { \ + RKISP1_CIF_##name, RKISP1_CIF_##name##_SHD, #name \ +} + +/* Keep this up-to-date when adding new registers. */ +#define RKISP1_MAX_REG_LENGTH 21 + +static int rkisp1_debug_dump_regs(struct rkisp1_device *rkisp1, + struct seq_file *m, unsigned int offset, + const struct rkisp1_debug_register *regs) +{ + const int width = RKISP1_MAX_REG_LENGTH; + u32 val, shd; + int ret; + + ret = pm_runtime_get_if_in_use(rkisp1->dev); + if (ret <= 0) + return ret ? : -ENODATA; + + for (; regs->name; ++regs) { + val = rkisp1_read(rkisp1, offset + regs->reg); + + if (regs->shd) { + shd = rkisp1_read(rkisp1, offset + regs->shd); + seq_printf(m, "%*s: 0x%08x/0x%08x\n", width, regs->name, + val, shd); + } else { + seq_printf(m, "%*s: 0x%08x\n", width, regs->name, val); + } + } + + pm_runtime_put(rkisp1->dev); + + return 0; +} + +static int rkisp1_debug_dump_core_regs_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_REG(VI_CCL), + RKISP1_DEBUG_REG(VI_ICCL), + RKISP1_DEBUG_REG(VI_IRCL), + RKISP1_DEBUG_REG(VI_DPCL), + RKISP1_DEBUG_REG(MI_CTRL), + RKISP1_DEBUG_REG(MI_BYTE_CNT), + RKISP1_DEBUG_REG(MI_CTRL_SHD), + RKISP1_DEBUG_REG(MI_RIS), + RKISP1_DEBUG_REG(MI_STATUS), + RKISP1_DEBUG_REG(MI_DMA_CTRL), + RKISP1_DEBUG_REG(MI_DMA_STATUS), + { /* Sentinel */ }, + }; + struct rkisp1_device *rkisp1 = m->private; + + return rkisp1_debug_dump_regs(rkisp1, m, 0, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_core_regs); + +static int rkisp1_debug_dump_isp_regs_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_REG(ISP_CTRL), + RKISP1_DEBUG_REG(ISP_ACQ_PROP), + RKISP1_DEBUG_REG(ISP_FLAGS_SHD), + RKISP1_DEBUG_REG(ISP_RIS), + RKISP1_DEBUG_REG(ISP_ERR), + { /* Sentinel */ }, + }; + struct rkisp1_device *rkisp1 = m->private; + + return rkisp1_debug_dump_regs(rkisp1, m, 0, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_isp_regs); + +static int rkisp1_debug_dump_rsz_regs_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_SHD_REG(RSZ_CTRL), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HY), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCB), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCR), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VY), + RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VC), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HY), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HC), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VY), + RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VC), + { /* Sentinel */ }, + }; + struct rkisp1_resizer *rsz = m->private; + + return rkisp1_debug_dump_regs(rsz->rkisp1, m, rsz->regs_base, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_rsz_regs); + +static int rkisp1_debug_dump_mi_mp_show(struct seq_file *m, void *p) +{ + static const struct rkisp1_debug_register registers[] = { + RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT), + RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT2), + RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_SHD), + RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT), + RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT), + RKISP1_DEBUG_REG(MI_MP_Y_SIZE_SHD), + RKISP1_DEBUG_REG(MI_MP_Y_OFFS_CNT_SHD), + { /* Sentinel */ }, + }; + struct rkisp1_device *rkisp1 = m->private; + + return rkisp1_debug_dump_regs(rkisp1, m, 0, registers); +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_mi_mp); + +#define RKISP1_DEBUG_DATA_COUNT_BINS 32 +#define RKISP1_DEBUG_DATA_COUNT_STEP (4096 / RKISP1_DEBUG_DATA_COUNT_BINS) + +static int rkisp1_debug_input_status_show(struct seq_file *m, void *p) +{ + struct rkisp1_device *rkisp1 = m->private; + u16 data_count[RKISP1_DEBUG_DATA_COUNT_BINS] = { }; + unsigned int hsync_count = 0; + unsigned int vsync_count = 0; + unsigned int i; + u32 data; + u32 val; + int ret; + + ret = pm_runtime_get_if_in_use(rkisp1->dev); + if (ret <= 0) + return ret ? : -ENODATA; + + /* Sample the ISP input port status 10000 times with a 1µs interval. */ + for (i = 0; i < 10000; ++i) { + val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_FLAGS_SHD); + + data = (val & RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK) + >> RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT; + data_count[data / RKISP1_DEBUG_DATA_COUNT_STEP]++; + + if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC) + hsync_count++; + if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC) + vsync_count++; + + udelay(1); + } + + pm_runtime_put(rkisp1->dev); + + seq_printf(m, "vsync: %u, hsync: %u\n", vsync_count, hsync_count); + seq_puts(m, "data:\n"); + for (i = 0; i < ARRAY_SIZE(data_count); ++i) + seq_printf(m, "- [%04u:%04u]: %u\n", + i * RKISP1_DEBUG_DATA_COUNT_STEP, + (i + 1) * RKISP1_DEBUG_DATA_COUNT_STEP - 1, + data_count[i]); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_input_status); + +void rkisp1_debug_init(struct rkisp1_device *rkisp1) +{ + struct rkisp1_debug *debug = &rkisp1->debug; + struct dentry *regs_dir; + + debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL); + + debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, + &debug->data_loss); + debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, + &debug->outform_size_error); + debugfs_create_ulong("img_stabilization_size_error", 0444, + debug->debugfs_dir, + &debug->img_stabilization_size_error); + debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir, + &debug->inform_size_error); + debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir, + &debug->irq_delay); + debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, + &debug->mipi_error); + debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir, + &debug->stats_error); + debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, + &debug->stop_timeout[RKISP1_SELFPATH]); + debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_MAINPATH]); + debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, + &debug->frame_drop[RKISP1_SELFPATH]); + debugfs_create_file("input_status", 0444, debug->debugfs_dir, rkisp1, + &rkisp1_debug_input_status_fops); + + regs_dir = debugfs_create_dir("regs", debug->debugfs_dir); + + debugfs_create_file("core", 0444, regs_dir, rkisp1, + &rkisp1_debug_dump_core_regs_fops); + debugfs_create_file("isp", 0444, regs_dir, rkisp1, + &rkisp1_debug_dump_isp_regs_fops); + debugfs_create_file("mrsz", 0444, regs_dir, + &rkisp1->resizer_devs[RKISP1_MAINPATH], + &rkisp1_debug_dump_rsz_regs_fops); + debugfs_create_file("srsz", 0444, regs_dir, + &rkisp1->resizer_devs[RKISP1_SELFPATH], + &rkisp1_debug_dump_rsz_regs_fops); + + debugfs_create_file("mi_mp", 0444, regs_dir, rkisp1, + &rkisp1_debug_dump_mi_mp_fops); +} + +void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1) +{ + debugfs_remove_recursive(rkisp1->debug.debugfs_dir); +} diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 3f5cfa7eb937..f2475c6235ea 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -9,18 +9,18 @@ */ #include <linux/clk.h> -#include <linux/debugfs.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_graph.h> #include <linux/of_platform.h> #include <linux/pinctrl/consumer.h> -#include <linux/phy/phy.h> -#include <linux/phy/phy-mipi-dphy.h> +#include <linux/pm_runtime.h> #include <media/v4l2-fwnode.h> +#include <media/v4l2-mc.h> #include "rkisp1-common.h" +#include "rkisp1-csi.h" /* * ISP Details @@ -68,18 +68,28 @@ * * Media Topology * -------------- - * +----------+ +----------+ - * | Sensor 2 | | Sensor X | - * ------------ ... ------------ - * | 0 | | 0 | - * +----------+ +----------+ +-----------+ - * \ | | params | - * \ | | (output) | - * +----------+ \ | +-----------+ - * | Sensor 1 | v v | - * ------------ +------+------+ | - * | 0 |----->| 0 | 1 |<---------+ - * +----------+ |------+------| + * + * +----------+ +----------+ + * | Sensor 1 | | Sensor X | + * ------------ ... ------------ + * | 0 | | 0 | + * +----------+ +----------+ + * | | + * \----\ /----/ + * | | + * v v + * +-------------+ + * | 0 | + * --------------- + * | CSI-2 RX | + * --------------- +-----------+ + * | 1 | | params | + * +-------------+ | (output) | + * | +-----------+ + * v | + * +------+------+ | + * | 0 | 1 |<---------+ + * |------+------| * | ISP | * |------+------| * +-------------| 2 | 3 |----------+ @@ -106,88 +116,10 @@ struct rkisp1_isr_data { irqreturn_t (*isr)(int irq, void *ctx); }; -struct rkisp1_match_data { - const char * const *clks; - unsigned int clk_size; - const struct rkisp1_isr_data *isrs; - unsigned int isr_size; - enum rkisp1_cif_isp_version isp_ver; -}; - /* ---------------------------------------------------------------------------- * Sensor DT bindings */ -static int rkisp1_create_links(struct rkisp1_device *rkisp1) -{ - struct media_entity *source, *sink; - unsigned int flags, source_pad; - struct v4l2_subdev *sd; - unsigned int i; - int ret; - - /* sensor links */ - flags = MEDIA_LNK_FL_ENABLED; - list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) { - if (sd == &rkisp1->isp.sd || - sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd || - sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd) - continue; - - ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode, - MEDIA_PAD_FL_SOURCE); - if (ret < 0) { - dev_err(rkisp1->dev, "failed to find src pad for %s\n", - sd->name); - return ret; - } - source_pad = ret; - - ret = media_create_pad_link(&sd->entity, source_pad, - &rkisp1->isp.sd.entity, - RKISP1_ISP_PAD_SINK_VIDEO, - flags); - if (ret) - return ret; - - flags = 0; - } - - flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; - - /* create ISP->RSZ->CAP links */ - for (i = 0; i < 2; i++) { - source = &rkisp1->isp.sd.entity; - sink = &rkisp1->resizer_devs[i].sd.entity; - ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO, - sink, RKISP1_RSZ_PAD_SINK, - MEDIA_LNK_FL_ENABLED); - if (ret) - return ret; - - source = sink; - sink = &rkisp1->capture_devs[i].vnode.vdev.entity; - ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC, - sink, 0, flags); - if (ret) - return ret; - } - - /* params links */ - source = &rkisp1->params.vnode.vdev.entity; - sink = &rkisp1->isp.sd.entity; - ret = media_create_pad_link(source, 0, sink, - RKISP1_ISP_PAD_SINK_PARAMS, flags); - if (ret) - return ret; - - /* 3A stats links */ - source = &rkisp1->isp.sd.entity; - sink = &rkisp1->stats.vnode.vdev.entity; - return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS, - sink, 0, flags); -} - static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) @@ -196,116 +128,171 @@ static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier, container_of(notifier, struct rkisp1_device, notifier); struct rkisp1_sensor_async *s_asd = container_of(asd, struct rkisp1_sensor_async, asd); + int source_pad; + int ret; - s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler, - V4L2_CID_PIXEL_RATE); s_asd->sd = sd; - s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy"); - if (IS_ERR(s_asd->dphy)) { - if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER) - dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n"); - return PTR_ERR(s_asd->dphy); + + source_pad = media_entity_get_fwnode_pad(&sd->entity, s_asd->source_ep, + MEDIA_PAD_FL_SOURCE); + if (source_pad < 0) { + dev_err(rkisp1->dev, "failed to find source pad for %s\n", + sd->name); + return source_pad; } - phy_init(s_asd->dphy); + if (s_asd->port == 0) + return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad); - return 0; -} - -static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) -{ - struct rkisp1_sensor_async *s_asd = - container_of(asd, struct rkisp1_sensor_async, asd); + ret = media_create_pad_link(&sd->entity, source_pad, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_VIDEO, + !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0); + if (ret) { + dev_err(rkisp1->dev, "failed to link source pad of %s\n", + sd->name); + return ret; + } - phy_exit(s_asd->dphy); + return 0; } static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier) { struct rkisp1_device *rkisp1 = container_of(notifier, struct rkisp1_device, notifier); - int ret; - ret = rkisp1_create_links(rkisp1); - if (ret) - return ret; - - ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); - if (ret) - return ret; + return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev); +} - dev_dbg(rkisp1->dev, "Async subdev notifier completed\n"); +static void rkisp1_subdev_notifier_destroy(struct v4l2_async_subdev *asd) +{ + struct rkisp1_sensor_async *rk_asd = + container_of(asd, struct rkisp1_sensor_async, asd); - return 0; + fwnode_handle_put(rk_asd->source_ep); } static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = { .bound = rkisp1_subdev_notifier_bound, - .unbind = rkisp1_subdev_notifier_unbind, .complete = rkisp1_subdev_notifier_complete, + .destroy = rkisp1_subdev_notifier_destroy, }; -static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1) +static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1) { struct v4l2_async_notifier *ntf = &rkisp1->notifier; - unsigned int next_id = 0; - int ret; + struct fwnode_handle *fwnode = dev_fwnode(rkisp1->dev); + struct fwnode_handle *ep; + unsigned int index = 0; + int ret = 0; v4l2_async_nf_init(ntf); - while (1) { - struct v4l2_fwnode_endpoint vep = { - .bus_type = V4L2_MBUS_CSI2_DPHY - }; + ntf->ops = &rkisp1_subdev_notifier_ops; + + fwnode_graph_for_each_endpoint(fwnode, ep) { + struct fwnode_handle *port; + struct v4l2_fwnode_endpoint vep = { }; struct rkisp1_sensor_async *rk_asd; - struct fwnode_handle *ep; + struct fwnode_handle *source; + u32 reg = 0; + + /* Select the bus type based on the port. */ + port = fwnode_get_parent(ep); + fwnode_property_read_u32(port, "reg", ®); + fwnode_handle_put(port); + + switch (reg) { + case 0: + /* MIPI CSI-2 port */ + if (!(rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)) { + dev_err(rkisp1->dev, + "internal CSI must be available for port 0\n"); + ret = -EINVAL; + break; + } + + vep.bus_type = V4L2_MBUS_CSI2_DPHY; + break; - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev), - 0, next_id, - FWNODE_GRAPH_ENDPOINT_NEXT); - if (!ep) + case 1: + /* + * Parallel port. The bus-type property in DT is + * mandatory for port 1, it will be used to determine if + * it's PARALLEL or BT656. + */ + vep.bus_type = V4L2_MBUS_UNKNOWN; break; + } + /* Parse the endpoint and validate the bus type. */ ret = v4l2_fwnode_endpoint_parse(ep, &vep); - if (ret) - goto err_parse; + if (ret) { + dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n", + ep); + break; + } - rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, - struct - rkisp1_sensor_async); + if (vep.base.port == 1) { + if (vep.bus_type != V4L2_MBUS_PARALLEL && + vep.bus_type != V4L2_MBUS_BT656) { + dev_err(rkisp1->dev, + "port 1 must be parallel or BT656\n"); + ret = -EINVAL; + break; + } + } + + /* Add the async subdev to the notifier. */ + source = fwnode_graph_get_remote_endpoint(ep); + if (!source) { + dev_err(rkisp1->dev, + "endpoint %pfw has no remote endpoint\n", + ep); + ret = -ENODEV; + break; + } + + rk_asd = v4l2_async_nf_add_fwnode(ntf, source, + struct rkisp1_sensor_async); if (IS_ERR(rk_asd)) { + fwnode_handle_put(source); ret = PTR_ERR(rk_asd); - goto err_parse; + break; } + rk_asd->index = index++; + rk_asd->source_ep = source; rk_asd->mbus_type = vep.bus_type; - rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; - rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; - - dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n", - vep.base.id, rk_asd->lanes); + rk_asd->port = vep.base.port; - next_id = vep.base.id + 1; + if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) { + rk_asd->mbus_flags = vep.bus.mipi_csi2.flags; + rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes; + } else { + rk_asd->mbus_flags = vep.bus.parallel.flags; + } - fwnode_handle_put(ep); + dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n", + vep.base.id, rk_asd->mbus_type, rk_asd->lanes); + } - continue; -err_parse: + if (ret) { fwnode_handle_put(ep); v4l2_async_nf_cleanup(ntf); return ret; } - if (next_id == 0) + if (!index) dev_dbg(rkisp1->dev, "no remote subdevice found\n"); - ntf->ops = &rkisp1_subdev_notifier_ops; + ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf); if (ret) { v4l2_async_nf_cleanup(ntf); return ret; } + return 0; } @@ -346,48 +333,110 @@ static const struct dev_pm_ops rkisp1_pm_ops = { * Core */ +static int rkisp1_create_links(struct rkisp1_device *rkisp1) +{ + unsigned int i; + int ret; + + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + /* Link the CSI receiver to the ISP. */ + ret = media_create_pad_link(&rkisp1->csi.sd.entity, + RKISP1_CSI_PAD_SRC, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_VIDEO, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + } + + /* create ISP->RSZ->CAP links */ + for (i = 0; i < 2; i++) { + struct media_entity *resizer = + &rkisp1->resizer_devs[i].sd.entity; + struct media_entity *capture = + &rkisp1->capture_devs[i].vnode.vdev.entity; + + ret = media_create_pad_link(&rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SOURCE_VIDEO, + resizer, RKISP1_RSZ_PAD_SINK, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + ret = media_create_pad_link(resizer, RKISP1_RSZ_PAD_SRC, + capture, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + return ret; + } + + /* params links */ + ret = media_create_pad_link(&rkisp1->params.vnode.vdev.entity, 0, + &rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SINK_PARAMS, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) + return ret; + + /* 3A stats links */ + return media_create_pad_link(&rkisp1->isp.sd.entity, + RKISP1_ISP_PAD_SOURCE_STATS, + &rkisp1->stats.vnode.vdev.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); +} + +static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) +{ + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + rkisp1_csi_unregister(rkisp1); + rkisp1_params_unregister(rkisp1); + rkisp1_stats_unregister(rkisp1); + rkisp1_capture_devs_unregister(rkisp1); + rkisp1_resizer_devs_unregister(rkisp1); + rkisp1_isp_unregister(rkisp1); +} + static int rkisp1_entities_register(struct rkisp1_device *rkisp1) { int ret; ret = rkisp1_isp_register(rkisp1); if (ret) - return ret; + goto error; ret = rkisp1_resizer_devs_register(rkisp1); if (ret) - goto err_unreg_isp_subdev; + goto error; ret = rkisp1_capture_devs_register(rkisp1); if (ret) - goto err_unreg_resizer_devs; + goto error; ret = rkisp1_stats_register(rkisp1); if (ret) - goto err_unreg_capture_devs; + goto error; ret = rkisp1_params_register(rkisp1); if (ret) - goto err_unreg_stats; + goto error; - ret = rkisp1_subdev_notifier(rkisp1); - if (ret) { - dev_err(rkisp1->dev, - "Failed to register subdev notifier(%d)\n", ret); - goto err_unreg_params; + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + ret = rkisp1_csi_register(rkisp1); + if (ret) + goto error; } + ret = rkisp1_create_links(rkisp1); + if (ret) + goto error; + return 0; -err_unreg_params: - rkisp1_params_unregister(rkisp1); -err_unreg_stats: - rkisp1_stats_unregister(rkisp1); -err_unreg_capture_devs: - rkisp1_capture_devs_unregister(rkisp1); -err_unreg_resizer_devs: - rkisp1_resizer_devs_unregister(rkisp1); -err_unreg_isp_subdev: - rkisp1_isp_unregister(rkisp1); + +error: + rkisp1_entities_unregister(rkisp1); return ret; } @@ -401,7 +450,7 @@ static irqreturn_t rkisp1_isr(int irq, void *ctx) */ rkisp1_capture_isr(irq, ctx); rkisp1_isp_isr(irq, ctx); - rkisp1_mipi_isr(irq, ctx); + rkisp1_csi_isr(irq, ctx); return IRQ_HANDLED; } @@ -416,15 +465,16 @@ static const char * const px30_isp_clks[] = { static const struct rkisp1_isr_data px30_isp_isrs[] = { { "isp", rkisp1_isp_isr }, { "mi", rkisp1_capture_isr }, - { "mipi", rkisp1_mipi_isr }, + { "mipi", rkisp1_csi_isr }, }; -static const struct rkisp1_match_data px30_isp_match_data = { +static const struct rkisp1_info px30_isp_info = { .clks = px30_isp_clks, .clk_size = ARRAY_SIZE(px30_isp_clks), .isrs = px30_isp_isrs, .isr_size = ARRAY_SIZE(px30_isp_isrs), .isp_ver = RKISP1_V12, + .features = RKISP1_FEATURE_MIPI_CSI2, }; static const char * const rk3399_isp_clks[] = { @@ -437,74 +487,45 @@ static const struct rkisp1_isr_data rk3399_isp_isrs[] = { { NULL, rkisp1_isr }, }; -static const struct rkisp1_match_data rk3399_isp_match_data = { +static const struct rkisp1_info rk3399_isp_info = { .clks = rk3399_isp_clks, .clk_size = ARRAY_SIZE(rk3399_isp_clks), .isrs = rk3399_isp_isrs, .isr_size = ARRAY_SIZE(rk3399_isp_isrs), .isp_ver = RKISP1_V10, + .features = RKISP1_FEATURE_MIPI_CSI2, }; static const struct of_device_id rkisp1_of_match[] = { { .compatible = "rockchip,px30-cif-isp", - .data = &px30_isp_match_data, + .data = &px30_isp_info, }, { .compatible = "rockchip,rk3399-cif-isp", - .data = &rk3399_isp_match_data, + .data = &rk3399_isp_info, }, {}, }; MODULE_DEVICE_TABLE(of, rkisp1_of_match); -static void rkisp1_debug_init(struct rkisp1_device *rkisp1) -{ - struct rkisp1_debug *debug = &rkisp1->debug; - - debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL); - debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, - &debug->data_loss); - debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, - &debug->outform_size_error); - debugfs_create_ulong("img_stabilization_size_error", 0444, - debug->debugfs_dir, - &debug->img_stabilization_size_error); - debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir, - &debug->inform_size_error); - debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir, - &debug->irq_delay); - debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir, - &debug->mipi_error); - debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir, - &debug->stats_error); - debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir, - &debug->stop_timeout[RKISP1_MAINPATH]); - debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir, - &debug->stop_timeout[RKISP1_SELFPATH]); - debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir, - &debug->frame_drop[RKISP1_MAINPATH]); - debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir, - &debug->frame_drop[RKISP1_SELFPATH]); -} - static int rkisp1_probe(struct platform_device *pdev) { - const struct rkisp1_match_data *match_data; + const struct rkisp1_info *info; struct device *dev = &pdev->dev; struct rkisp1_device *rkisp1; struct v4l2_device *v4l2_dev; unsigned int i; int ret, irq; - - match_data = of_device_get_match_data(&pdev->dev); - if (!match_data) - return -ENODEV; + u32 cif_id; rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL); if (!rkisp1) return -ENOMEM; + info = of_device_get_match_data(dev); + rkisp1->info = info; + dev_set_drvdata(dev, rkisp1); rkisp1->dev = dev; @@ -514,14 +535,14 @@ static int rkisp1_probe(struct platform_device *pdev) if (IS_ERR(rkisp1->base_addr)) return PTR_ERR(rkisp1->base_addr); - for (i = 0; i < match_data->isr_size; i++) { - irq = (match_data->isrs[i].name) ? - platform_get_irq_byname(pdev, match_data->isrs[i].name) : - platform_get_irq(pdev, i); + for (i = 0; i < info->isr_size; i++) { + irq = info->isrs[i].name + ? platform_get_irq_byname(pdev, info->isrs[i].name) + : platform_get_irq(pdev, i); if (irq < 0) return irq; - ret = devm_request_irq(dev, irq, match_data->isrs[i].isr, IRQF_SHARED, + ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED, dev_driver_string(dev), dev); if (ret) { dev_err(dev, "request irq failed: %d\n", ret); @@ -529,16 +550,25 @@ static int rkisp1_probe(struct platform_device *pdev) } } - for (i = 0; i < match_data->clk_size; i++) - rkisp1->clks[i].id = match_data->clks[i]; - ret = devm_clk_bulk_get(dev, match_data->clk_size, rkisp1->clks); + for (i = 0; i < info->clk_size; i++) + rkisp1->clks[i].id = info->clks[i]; + ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks); if (ret) return ret; - rkisp1->clk_size = match_data->clk_size; + rkisp1->clk_size = info->clk_size; pm_runtime_enable(&pdev->dev); - rkisp1->media_dev.hw_revision = match_data->isp_ver; + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + goto err_pm_runtime_disable; + + cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); + dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); + + pm_runtime_put(&pdev->dev); + + rkisp1->media_dev.hw_revision = info->isp_ver; strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME, sizeof(rkisp1->media_dev.model)); rkisp1->media_dev.dev = &pdev->dev; @@ -552,7 +582,7 @@ static int rkisp1_probe(struct platform_device *pdev) ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev); if (ret) - return ret; + goto err_pm_runtime_disable; ret = media_device_register(&rkisp1->media_dev); if (ret) { @@ -560,18 +590,34 @@ static int rkisp1_probe(struct platform_device *pdev) goto err_unreg_v4l2_dev; } + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + ret = rkisp1_csi_init(rkisp1); + if (ret) + goto err_unreg_media_dev; + } + ret = rkisp1_entities_register(rkisp1); if (ret) - goto err_unreg_media_dev; + goto err_cleanup_csi; + + ret = rkisp1_subdev_notifier_register(rkisp1); + if (ret) + goto err_unreg_entities; rkisp1_debug_init(rkisp1); return 0; +err_unreg_entities: + rkisp1_entities_unregister(rkisp1); +err_cleanup_csi: + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + rkisp1_csi_cleanup(rkisp1); err_unreg_media_dev: media_device_unregister(&rkisp1->media_dev); err_unreg_v4l2_dev: v4l2_device_unregister(&rkisp1->v4l2_dev); +err_pm_runtime_disable: pm_runtime_disable(&pdev->dev); return ret; } @@ -583,18 +629,16 @@ static int rkisp1_remove(struct platform_device *pdev) v4l2_async_nf_unregister(&rkisp1->notifier); v4l2_async_nf_cleanup(&rkisp1->notifier); - rkisp1_params_unregister(rkisp1); - rkisp1_stats_unregister(rkisp1); - rkisp1_capture_devs_unregister(rkisp1); - rkisp1_resizer_devs_unregister(rkisp1); - rkisp1_isp_unregister(rkisp1); + rkisp1_entities_unregister(rkisp1); + if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + rkisp1_csi_cleanup(rkisp1); + rkisp1_debug_cleanup(rkisp1); media_device_unregister(&rkisp1->media_dev); v4l2_device_unregister(&rkisp1->v4l2_dev); pm_runtime_disable(&pdev->dev); - debugfs_remove_recursive(rkisp1->debug.debugfs_dir); return 0; } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 4415c7248c2f..383a3ec83ca9 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -9,13 +9,10 @@ */ #include <linux/iopoll.h> -#include <linux/phy/phy.h> -#include <linux/phy/phy-mipi-dphy.h> #include <linux/pm_runtime.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> -#include <media/mipi-csi2.h> #include <media/v4l2-event.h> #include "rkisp1-common.h" @@ -56,158 +53,10 @@ * +---------------------------------------------------------+ */ -static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = { - { - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .direction = RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW10, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 10, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW12, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 12, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_RGGB, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_BGGR, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_GBRG, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, - .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = MIPI_CSI2_DT_RAW8, - .bayer_pat = RKISP1_RAW_GRBG, - .bus_width = 8, - .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, - }, { - .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, { - .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, - .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = MIPI_CSI2_DT_YUV422_8B, - .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, - .bus_width = 16, - .direction = RKISP1_ISP_SD_SINK, - }, -}; - /* ---------------------------------------------------------------------------- * Helpers */ -const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { - const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; - - if (fmt->mbus_code == mbus_code) - return fmt; - } - - return NULL; -} - -static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd) -{ - struct media_pad *local, *remote; - struct media_entity *sensor_me; - - local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO]; - remote = media_entity_remote_pad(local); - if (!remote) - return NULL; - - sensor_me = remote->entity; - return media_entity_to_v4l2_subdev(sensor_me); -} - static struct v4l2_mbus_framefmt * rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, struct v4l2_subdev_state *sd_state, @@ -215,7 +64,8 @@ rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp, { struct v4l2_subdev_state state = { .pads = isp->pad_cfg - }; + }; + if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad); else @@ -229,7 +79,8 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, { struct v4l2_subdev_state state = { .pads = isp->pad_cfg - }; + }; + if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad); else @@ -245,73 +96,73 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp, * This should only be called when configuring CIF * or at the frame end interrupt */ -static void rkisp1_config_ism(struct rkisp1_device *rkisp1) +static void rkisp1_config_ism(struct rkisp1_isp *isp) { - struct v4l2_rect *src_crop = - rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + const struct v4l2_rect *src_crop = + rkisp1_isp_get_pad_crop(isp, NULL, RKISP1_ISP_PAD_SOURCE_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE); - rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS); - rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS); - rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE); - rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_RECENTER, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DX, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DY, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_DISPLACE, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_OFFS, src_crop->left); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_OFFS, src_crop->top); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_SIZE, src_crop->width); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_SIZE, src_crop->height); /* IS(Image Stabilization) is always on, working as output crop */ - rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_CTRL, 1); val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD; - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); } /* * configure ISP blocks with input format, size...... */ -static int rkisp1_config_isp(struct rkisp1_device *rkisp1) -{ - u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0; - const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt; - struct rkisp1_sensor_async *sensor; - struct v4l2_mbus_framefmt *sink_frm; - struct v4l2_rect *sink_crop; +static int rkisp1_config_isp(struct rkisp1_isp *isp, + enum v4l2_mbus_type mbus_type, u32 mbus_flags) +{ + struct rkisp1_device *rkisp1 = isp->rkisp1; + u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, acq_prop = 0; + const struct rkisp1_mbus_info *sink_fmt = isp->sink_fmt; + const struct rkisp1_mbus_info *src_fmt = isp->src_fmt; + const struct v4l2_mbus_framefmt *sink_frm; + const struct v4l2_rect *sink_crop; - sensor = rkisp1->active_sensor; - sink_fmt = rkisp1->isp.sink_fmt; - src_fmt = rkisp1->isp.src_fmt; - sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + sink_frm = rkisp1_isp_get_pad_fmt(isp, NULL, RKISP1_ISP_PAD_SINK_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); - sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL, + sink_crop = rkisp1_isp_get_pad_crop(isp, NULL, RKISP1_ISP_PAD_SINK_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { acq_mult = 1; if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { - if (sensor->mbus_type == V4L2_MBUS_BT656) + if (mbus_type == V4L2_MBUS_BT656) isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656; else isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT; } else { - rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc), - RKISP1_CIF_ISP_DEMOSAIC); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_TH(0xc)); - if (sensor->mbus_type == V4L2_MBUS_BT656) + if (mbus_type == V4L2_MBUS_BT656) isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656; else isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601; } } else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) { acq_mult = 2; - if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { + if (mbus_type == V4L2_MBUS_CSI2_DPHY) { isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; } else { - if (sensor->mbus_type == V4L2_MBUS_BT656) + if (mbus_type == V4L2_MBUS_BT656) isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656; else isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601; @@ -321,50 +172,65 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1) } /* Set up input acquisition properties */ - if (sensor->mbus_type == V4L2_MBUS_BT656 || - sensor->mbus_type == V4L2_MBUS_PARALLEL) { - if (sensor->mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE; + if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL) { + if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE; + + switch (sink_fmt->bus_width) { + case 8: + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; + break; + case 10: + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; + break; + case 12: + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B; + break; + default: + dev_err(rkisp1->dev, "Invalid bus width %u\n", + sink_fmt->bus_width); + return -EINVAL; + } } - if (sensor->mbus_type == V4L2_MBUS_PARALLEL) { - if (sensor->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW; + if (mbus_type == V4L2_MBUS_PARALLEL) { + if (mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW; - if (sensor->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW; + if (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW; } - rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL); - rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq | + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, isp_ctrl); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_PROP, + acq_prop | sink_fmt->yuv_seq | RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) | - RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL, - RKISP1_CIF_ISP_ACQ_PROP); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES); + RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_NR_FRAMES, 0); /* Acquisition Size */ - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS); - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS); - rkisp1_write(rkisp1, - acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE); - rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_OFFS, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_OFFS, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_SIZE, + acq_mult * sink_frm->width); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_SIZE, sink_frm->height); /* ISP Out Area */ - rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS); - rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS); - rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE); - rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_OFFS, sink_crop->left); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_OFFS, sink_crop->top); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_SIZE, sink_crop->width); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_SIZE, sink_crop->height); irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START | RKISP1_CIF_ISP_PIC_SIZE_ERROR; - rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, irq_mask); if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) { rkisp1_params_disable(&rkisp1->params); } else { struct v4l2_mbus_framefmt *src_frm; - src_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL, + src_frm = rkisp1_isp_get_pad_fmt(isp, NULL, RKISP1_ISP_PAD_SINK_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, @@ -374,213 +240,117 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1) return 0; } -static int rkisp1_config_dvp(struct rkisp1_device *rkisp1) -{ - const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; - u32 val, input_sel; - - switch (sink_fmt->bus_width) { - case 8: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO; - break; - case 10: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO; - break; - case 12: - input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B; - break; - default: - dev_err(rkisp1->dev, "Invalid bus width\n"); - return -EINVAL; - } - - val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP); - rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP); - - return 0; -} - -static int rkisp1_config_mipi(struct rkisp1_device *rkisp1) -{ - const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt; - unsigned int lanes = rkisp1->active_sensor->lanes; - u32 mipi_ctrl; - - if (lanes < 1 || lanes > 4) - return -EINVAL; - - mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) | - RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) | - RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP | - RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA; - - rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL); - - /* V12 could also use a newer csi2-host, but we don't want that yet */ - if (rkisp1->media_dev.hw_revision == RKISP1_V12) - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_CSI0_CTRL0); - - /* Configure Data Type and Virtual Channel */ - rkisp1_write(rkisp1, - RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) | - RKISP1_CIF_MIPI_DATA_SEL_VC(0), - RKISP1_CIF_MIPI_IMG_DATA_SEL); - - /* Clear MIPI interrupts */ - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); - /* - * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for - * isp bus may be dead when switch isp. - */ - rkisp1_write(rkisp1, - RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI | - RKISP1_CIF_MIPI_ERR_DPHY | - RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) | - RKISP1_CIF_MIPI_ADD_DATA_OVFLW, - RKISP1_CIF_MIPI_IMSC); - - dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n" - " MIPI_IMG_DATA_SEL 0x%08x\n" - " MIPI_STATUS 0x%08x\n" - " MIPI_IMSC 0x%08x\n", - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS), - rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC)); - - return 0; -} - /* Configure MUX */ -static int rkisp1_config_path(struct rkisp1_device *rkisp1) +static void rkisp1_config_path(struct rkisp1_isp *isp, + enum v4l2_mbus_type mbus_type) { - struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL); - int ret = 0; - if (sensor->mbus_type == V4L2_MBUS_BT656 || - sensor->mbus_type == V4L2_MBUS_PARALLEL) { - ret = rkisp1_config_dvp(rkisp1); + if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL) dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL; - } else if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { - ret = rkisp1_config_mipi(rkisp1); + else if (mbus_type == V4L2_MBUS_CSI2_DPHY) dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI; - } - - rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL); - return ret; + rkisp1_write(rkisp1, RKISP1_CIF_VI_DPCL, dpcl); } /* Hardware configure Entry */ -static int rkisp1_config_cif(struct rkisp1_device *rkisp1) +static int rkisp1_config_cif(struct rkisp1_isp *isp, + enum v4l2_mbus_type mbus_type, u32 mbus_flags) { - u32 cif_id; int ret; - cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID); - dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id); - - ret = rkisp1_config_isp(rkisp1); + ret = rkisp1_config_isp(isp, mbus_type, mbus_flags); if (ret) return ret; - ret = rkisp1_config_path(rkisp1); - if (ret) - return ret; - rkisp1_config_ism(rkisp1); + + rkisp1_config_path(isp, mbus_type); + rkisp1_config_ism(isp); return 0; } -static void rkisp1_isp_stop(struct rkisp1_device *rkisp1) +static void rkisp1_isp_stop(struct rkisp1_isp *isp) { + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; /* * ISP(mi) stop in mi frame end -> Stop ISP(mipi) -> * Stop ISP(isp) ->wait for ISP isp off */ - /* stop and clear MI, MIPI, and ISP interrupts */ - rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR); - - rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR); - - rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC); - rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR); - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); - rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA), - RKISP1_CIF_MIPI_CTRL); + /* stop and clear MI and ISP interrupts */ + rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0); + + rkisp1_write(rkisp1, RKISP1_CIF_MI_IMSC, 0); + rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, ~0); + /* stop ISP */ val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE | RKISP1_CIF_ISP_CTRL_ISP_ENABLE); - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); - rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD, - RKISP1_CIF_ISP_CTRL); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, + val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS, val, val & RKISP1_CIF_ISP_OFF, 20, 100); - rkisp1_write(rkisp1, - RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST, - RKISP1_CIF_IRCL); - rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL); + rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, + RKISP1_CIF_VI_IRCL_MIPI_SW_RST | + RKISP1_CIF_VI_IRCL_ISP_SW_RST); + rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, 0x0); } -static void rkisp1_config_clk(struct rkisp1_device *rkisp1) +static void rkisp1_config_clk(struct rkisp1_isp *isp) { - u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK | - RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK | - RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK | - RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK | - RKISP1_CIF_ICCL_DCROP_CLK; + struct rkisp1_device *rkisp1 = isp->rkisp1; + + u32 val = RKISP1_CIF_VI_ICCL_ISP_CLK | RKISP1_CIF_VI_ICCL_CP_CLK | + RKISP1_CIF_VI_ICCL_MRSZ_CLK | RKISP1_CIF_VI_ICCL_SRSZ_CLK | + RKISP1_CIF_VI_ICCL_JPEG_CLK | RKISP1_CIF_VI_ICCL_MI_CLK | + RKISP1_CIF_VI_ICCL_IE_CLK | RKISP1_CIF_VI_ICCL_MIPI_CLK | + RKISP1_CIF_VI_ICCL_DCROP_CLK; - rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL); + rkisp1_write(rkisp1, RKISP1_CIF_VI_ICCL, val); /* ensure sp and mp can run at the same time in V12 */ - if (rkisp1->media_dev.hw_revision == RKISP1_V12) { + if (rkisp1->info->isp_ver == RKISP1_V12) { val = RKISP1_CIF_CLK_CTRL_MI_Y12 | RKISP1_CIF_CLK_CTRL_MI_SP | RKISP1_CIF_CLK_CTRL_MI_RAW0 | RKISP1_CIF_CLK_CTRL_MI_RAW1 | RKISP1_CIF_CLK_CTRL_MI_READ | RKISP1_CIF_CLK_CTRL_MI_RAWRD | RKISP1_CIF_CLK_CTRL_CP | RKISP1_CIF_CLK_CTRL_IE; - rkisp1_write(rkisp1, val, RKISP1_CIF_VI_ISP_CLK_CTRL_V12); + rkisp1_write(rkisp1, RKISP1_CIF_VI_ISP_CLK_CTRL_V12, val); } } -static void rkisp1_isp_start(struct rkisp1_device *rkisp1) +static void rkisp1_isp_start(struct rkisp1_isp *isp) { - struct rkisp1_sensor_async *sensor = rkisp1->active_sensor; + struct rkisp1_device *rkisp1 = isp->rkisp1; u32 val; - rkisp1_config_clk(rkisp1); + rkisp1_config_clk(isp); - /* Activate MIPI */ - if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL); - rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA, - RKISP1_CIF_MIPI_CTRL); - } /* Activate ISP */ val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD | RKISP1_CIF_ISP_CTRL_ISP_ENABLE | RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; - rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL); - - /* - * CIF spec says to wait for sufficient time after enabling - * the MIPI interface and before starting the sensor output. - */ - usleep_range(1000, 1200); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); } /* ---------------------------------------------------------------------------- * Subdev pad operations */ +static inline struct rkisp1_isp *to_rkisp1_isp(struct v4l2_subdev *sd) +{ + return container_of(sd, struct rkisp1_isp, sd); +} + static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -599,11 +369,12 @@ static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd, return 0; } - if (code->index >= ARRAY_SIZE(rkisp1_isp_formats)) - return -EINVAL; + for (i = 0; ; i++) { + const struct rkisp1_mbus_info *fmt = + rkisp1_mbus_info_get_by_index(i); - for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) { - const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i]; + if (!fmt) + return -EINVAL; if (fmt->direction & dir) pos++; @@ -625,7 +396,7 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; if (fse->pad == RKISP1_ISP_PAD_SINK_PARAMS || fse->pad == RKISP1_ISP_PAD_SOURCE_STATS) @@ -634,7 +405,7 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd, if (fse->index > 0) return -EINVAL; - mbus_info = rkisp1_isp_mbus_info_get(fse->code); + mbus_info = rkisp1_mbus_info_get_by_code(fse->code); if (!mbus_info) return -EINVAL; @@ -701,7 +472,7 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *src_fmt; const struct v4l2_rect *src_crop; @@ -711,10 +482,10 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, RKISP1_ISP_PAD_SOURCE_VIDEO, which); src_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); } if (which == V4L2_SUBDEV_FORMAT_ACTIVE) isp->src_fmt = mbus_info; @@ -771,7 +542,7 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp, struct v4l2_rect *r, unsigned int which) { struct v4l2_rect *sink_crop, *src_crop; - struct v4l2_mbus_framefmt *sink_fmt; + const struct v4l2_mbus_framefmt *sink_fmt; sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state, RKISP1_ISP_PAD_SINK_VIDEO, @@ -799,7 +570,7 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; @@ -807,10 +578,10 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, RKISP1_ISP_PAD_SINK_VIDEO, which); sink_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) { sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } if (which == V4L2_SUBDEV_FORMAT_ACTIVE) isp->sink_fmt = mbus_info; @@ -835,7 +606,7 @@ static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); mutex_lock(&isp->ops_lock); fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad, @@ -848,7 +619,7 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); mutex_lock(&isp->ops_lock); if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO) @@ -869,7 +640,7 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); int ret = 0; if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO && @@ -909,15 +680,13 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct rkisp1_device *rkisp1 = - container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); - struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd); + struct rkisp1_isp *isp = to_rkisp1_isp(sd); int ret = 0; if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, + dev_dbg(isp->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height); mutex_lock(&isp->ops_lock); if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) @@ -954,77 +723,62 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = { * Stream operations */ -static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp, - struct rkisp1_sensor_async *sensor) -{ - struct rkisp1_device *rkisp1 = - container_of(isp->sd.v4l2_dev, struct rkisp1_device, v4l2_dev); - union phy_configure_opts opts; - struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy; - s64 pixel_clock; - - if (!sensor->pixel_rate_ctrl) { - dev_warn(rkisp1->dev, "No pixel rate control in sensor subdev\n"); - return -EPIPE; - } - - pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl); - if (!pixel_clock) { - dev_err(rkisp1->dev, "Invalid pixel rate value\n"); - return -EINVAL; - } - - phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width, - sensor->lanes, cfg); - phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY); - phy_configure(sensor->dphy, &opts); - phy_power_on(sensor->dphy); - - return 0; -} - -static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor) -{ - phy_power_off(sensor->dphy); -} - static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) { - struct rkisp1_device *rkisp1 = - container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev); - struct rkisp1_isp *isp = &rkisp1->isp; - struct v4l2_subdev *sensor_sd; - int ret = 0; + struct rkisp1_isp *isp = to_rkisp1_isp(sd); + struct rkisp1_device *rkisp1 = isp->rkisp1; + struct media_pad *source_pad; + struct media_pad *sink_pad; + enum v4l2_mbus_type mbus_type; + u32 mbus_flags; + int ret; if (!enable) { - rkisp1_isp_stop(rkisp1); - rkisp1_mipi_csi2_stop(rkisp1->active_sensor); + v4l2_subdev_call(rkisp1->source, video, s_stream, false); + rkisp1_isp_stop(isp); return 0; } - sensor_sd = rkisp1_get_remote_sensor(sd); - if (!sensor_sd) { - dev_warn(rkisp1->dev, "No link between isp and sensor\n"); - return -ENODEV; + sink_pad = &isp->pads[RKISP1_ISP_PAD_SINK_VIDEO]; + source_pad = media_pad_remote_pad_unique(sink_pad); + if (IS_ERR(source_pad)) { + dev_dbg(rkisp1->dev, "Failed to get source for ISP: %ld\n", + PTR_ERR(source_pad)); + return -EPIPE; } - rkisp1->active_sensor = container_of(sensor_sd->asd, - struct rkisp1_sensor_async, asd); + rkisp1->source = media_entity_to_v4l2_subdev(source_pad->entity); + if (!rkisp1->source) { + /* This should really not happen, so is not worth a message. */ + return -EPIPE; + } - if (rkisp1->active_sensor->mbus_type != V4L2_MBUS_CSI2_DPHY) - return -EINVAL; + if (rkisp1->source == &rkisp1->csi.sd) { + mbus_type = V4L2_MBUS_CSI2_DPHY; + mbus_flags = 0; + } else { + const struct rkisp1_sensor_async *asd; - rkisp1->isp.frame_sequence = -1; + asd = container_of(rkisp1->source->asd, + struct rkisp1_sensor_async, asd); + + mbus_type = asd->mbus_type; + mbus_flags = asd->mbus_flags; + } + + isp->frame_sequence = -1; mutex_lock(&isp->ops_lock); - ret = rkisp1_config_cif(rkisp1); + ret = rkisp1_config_cif(isp, mbus_type, mbus_flags); if (ret) goto mutex_unlock; - ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor); - if (ret) - goto mutex_unlock; + rkisp1_isp_start(isp); - rkisp1_isp_start(rkisp1); + ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true); + if (ret) { + rkisp1_isp_stop(isp); + goto mutex_unlock; + } mutex_unlock: mutex_unlock(&isp->ops_lock); @@ -1067,12 +821,14 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1) { struct v4l2_subdev_state state = { .pads = rkisp1->isp.pad_cfg - }; + }; struct rkisp1_isp *isp = &rkisp1->isp; struct media_pad *pads = isp->pads; struct v4l2_subdev *sd = &isp->sd; int ret; + isp->rkisp1 = rkisp1; + v4l2_subdev_init(sd, &rkisp1_isp_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; sd->entity.ops = &rkisp1_isp_media_ops; @@ -1086,95 +842,54 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1) pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; - isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT); - isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT); + isp->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SINK_PAD_FMT); + isp->src_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SRC_PAD_FMT); mutex_init(&isp->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads); if (ret) - return ret; + goto error; ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd); if (ret) { dev_err(rkisp1->dev, "Failed to register isp subdev\n"); - goto err_cleanup_media_entity; + goto error; } rkisp1_isp_init_config(sd, &state); + return 0; -err_cleanup_media_entity: +error: media_entity_cleanup(&sd->entity); - + mutex_destroy(&isp->ops_lock); + isp->sd.v4l2_dev = NULL; return ret; } void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) { - struct v4l2_subdev *sd = &rkisp1->isp.sd; + struct rkisp1_isp *isp = &rkisp1->isp; - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); + if (!isp->sd.v4l2_dev) + return; + + v4l2_device_unregister_subdev(&isp->sd); + media_entity_cleanup(&isp->sd.entity); + mutex_destroy(&isp->ops_lock); } /* ---------------------------------------------------------------------------- * Interrupt handlers */ -irqreturn_t rkisp1_mipi_isr(int irq, void *ctx) -{ - struct device *dev = ctx; - struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); - u32 val, status; - - status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS); - if (!status) - return IRQ_NONE; - - rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR); - - /* - * Disable DPHY errctrl interrupt, because this dphy - * erctrl signal is asserted until the next changes - * of line state. This time is may be too long and cpu - * is hold in this interrupt. - */ - if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); - rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f), - RKISP1_CIF_MIPI_IMSC); - rkisp1->isp.is_dphy_errctrl_disabled = true; - } - - /* - * Enable DPHY errctrl interrupt again, if mipi have receive - * the whole frame without any error. - */ - if (status == RKISP1_CIF_MIPI_FRAME_END) { - /* - * Enable DPHY errctrl interrupt again, if mipi have receive - * the whole frame without any error. - */ - if (rkisp1->isp.is_dphy_errctrl_disabled) { - val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC); - val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f); - rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC); - rkisp1->isp.is_dphy_errctrl_disabled = false; - } - } else { - rkisp1->debug.mipi_error++; - } - - return IRQ_HANDLED; -} - static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) { struct v4l2_event event = { .type = V4L2_EVENT_FRAME_SYNC, }; - event.u.frame_sync.frame_sequence = isp->frame_sequence; + event.u.frame_sync.frame_sequence = isp->frame_sequence; v4l2_event_queue(isp->sd.devnode, &event); } @@ -1188,7 +903,7 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) if (!status) return IRQ_NONE; - rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, status); /* Vertical sync signal, starting generating new frame */ if (status & RKISP1_CIF_ISP_V_START) { @@ -1208,7 +923,7 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) rkisp1->debug.img_stabilization_size_error++; if (isp_err & RKISP1_CIF_ISP_ERR_OUTFORM_SIZE) rkisp1->debug.outform_size_error++; - rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ERR_CLR, isp_err); } else if (status & RKISP1_CIF_ISP_DATA_LOSS) { /* keep track of data_loss in debugfs */ rkisp1->debug.data_loss++; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 8f62f09e635f..9da7dc1bc690 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -37,7 +37,7 @@ rkisp1_param_set_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) u32 val; val = rkisp1_read(params->rkisp1, reg); - rkisp1_write(params->rkisp1, val | bit_mask, reg); + rkisp1_write(params->rkisp1, reg, val | bit_mask); } static inline void @@ -46,7 +46,7 @@ rkisp1_param_clear_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask) u32 val; val = rkisp1_read(params->rkisp1, reg); - rkisp1_write(params->rkisp1, val & ~bit_mask, reg); + rkisp1_write(params->rkisp1, reg, val & ~bit_mask); } /* ISP BP interface function */ @@ -60,35 +60,35 @@ static void rkisp1_dpcc_config(struct rkisp1_params *params, mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); mode &= RKISP1_CIF_ISP_DPCC_ENA; mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; - rkisp1_write(params->rkisp1, mode, RKISP1_CIF_ISP_DPCC_MODE); - rkisp1_write(params->rkisp1, arg->output_mode, - RKISP1_CIF_ISP_DPCC_OUTPUT_MODE); - rkisp1_write(params->rkisp1, arg->set_use, - RKISP1_CIF_ISP_DPCC_SET_USE); - - rkisp1_write(params->rkisp1, arg->methods[0].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_1); - rkisp1_write(params->rkisp1, arg->methods[1].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_2); - rkisp1_write(params->rkisp1, arg->methods[2].method, - RKISP1_CIF_ISP_DPCC_METHODS_SET_3); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE, mode); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_OUTPUT_MODE, + arg->output_mode); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_SET_USE, + arg->set_use); + + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_1, + arg->methods[0].method); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_2, + arg->methods[1].method); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_3, + arg->methods[2].method); for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { - rkisp1_write(params->rkisp1, arg->methods[i].line_thresh, - RKISP1_ISP_DPCC_LINE_THRESH(i)); - rkisp1_write(params->rkisp1, arg->methods[i].line_mad_fac, - RKISP1_ISP_DPCC_LINE_MAD_FAC(i)); - rkisp1_write(params->rkisp1, arg->methods[i].pg_fac, - RKISP1_ISP_DPCC_PG_FAC(i)); - rkisp1_write(params->rkisp1, arg->methods[i].rnd_thresh, - RKISP1_ISP_DPCC_RND_THRESH(i)); - rkisp1_write(params->rkisp1, arg->methods[i].rg_fac, - RKISP1_ISP_DPCC_RG_FAC(i)); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_THRESH(i), + arg->methods[i].line_thresh); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_MAD_FAC(i), + arg->methods[i].line_mad_fac); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_PG_FAC(i), + arg->methods[i].pg_fac); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RND_THRESH(i), + arg->methods[i].rnd_thresh); + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RG_FAC(i), + arg->methods[i].rg_fac); } - rkisp1_write(params->rkisp1, arg->rnd_offs, - RKISP1_CIF_ISP_DPCC_RND_OFFS); - rkisp1_write(params->rkisp1, arg->ro_limits, - RKISP1_CIF_ISP_DPCC_RO_LIMITS); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RND_OFFS, + arg->rnd_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RO_LIMITS, + arg->ro_limits); } /* ISP black level subtraction interface function */ @@ -107,44 +107,44 @@ static void rkisp1_bls_config(struct rkisp1_params *params, switch (params->raw_type) { case RKISP1_RAW_BGGR: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_A_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->b); break; case RKISP1_RAW_GBRG: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_B_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->b); break; case RKISP1_RAW_GRBG: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_D_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_C_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->b); break; case RKISP1_RAW_RGGB: - rkisp1_write(params->rkisp1, - pval->r, RKISP1_CIF_ISP_BLS_A_FIXED); - rkisp1_write(params->rkisp1, - pval->gr, RKISP1_CIF_ISP_BLS_B_FIXED); - rkisp1_write(params->rkisp1, - pval->gb, RKISP1_CIF_ISP_BLS_C_FIXED); - rkisp1_write(params->rkisp1, - pval->b, RKISP1_CIF_ISP_BLS_D_FIXED); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED, + pval->r); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED, + pval->gr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED, + pval->gb); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED, + pval->b); break; default: break; @@ -152,35 +152,35 @@ static void rkisp1_bls_config(struct rkisp1_params *params, } else { if (arg->en_windows & BIT(1)) { - rkisp1_write(params->rkisp1, arg->bls_window2.h_offs, - RKISP1_CIF_ISP_BLS_H2_START); - rkisp1_write(params->rkisp1, arg->bls_window2.h_size, - RKISP1_CIF_ISP_BLS_H2_STOP); - rkisp1_write(params->rkisp1, arg->bls_window2.v_offs, - RKISP1_CIF_ISP_BLS_V2_START); - rkisp1_write(params->rkisp1, arg->bls_window2.v_size, - RKISP1_CIF_ISP_BLS_V2_STOP); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_START, + arg->bls_window2.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_STOP, + arg->bls_window2.h_size); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_START, + arg->bls_window2.v_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_STOP, + arg->bls_window2.v_size); new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2; } if (arg->en_windows & BIT(0)) { - rkisp1_write(params->rkisp1, arg->bls_window1.h_offs, - RKISP1_CIF_ISP_BLS_H1_START); - rkisp1_write(params->rkisp1, arg->bls_window1.h_size, - RKISP1_CIF_ISP_BLS_H1_STOP); - rkisp1_write(params->rkisp1, arg->bls_window1.v_offs, - RKISP1_CIF_ISP_BLS_V1_START); - rkisp1_write(params->rkisp1, arg->bls_window1.v_size, - RKISP1_CIF_ISP_BLS_V1_STOP); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_START, + arg->bls_window1.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_STOP, + arg->bls_window1.h_size); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_START, + arg->bls_window1.v_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_STOP, + arg->bls_window1.v_size); new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1; } - rkisp1_write(params->rkisp1, arg->bls_samples, - RKISP1_CIF_ISP_BLS_SAMPLES); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_SAMPLES, + arg->bls_samples); new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED; } - rkisp1_write(params->rkisp1, new_control, RKISP1_CIF_ISP_BLS_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL, new_control); } /* ISP LS correction interface function */ @@ -196,14 +196,10 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, - RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { @@ -214,45 +210,45 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); } data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + data); } isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, isp_lsc_table_sel, - RKISP1_CIF_ISP_LSC_TABLE_SEL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, + isp_lsc_table_sel); } static void @@ -267,10 +263,10 @@ rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR); - rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { @@ -282,49 +278,49 @@ rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->r_data_tbl[i][j], pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->gr_data_tbl[i][j], pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->gb_data_tbl[i][j], pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( pconfig->b_data_tbl[i][j], pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); } data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + data); data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + data); } isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, isp_lsc_table_sel, - RKISP1_CIF_ISP_LSC_TABLE_SEL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, + isp_lsc_table_sel); } static void rkisp1_lsc_config(struct rkisp1_params *params, @@ -343,26 +339,26 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, /* program x size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], arg->x_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data); /* program x grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], arg->x_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data); /* program y size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], arg->y_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data); /* program y grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], arg->y_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, data, - RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data); } /* restore the lsc ctrl status */ @@ -383,28 +379,32 @@ static void rkisp1_flt_config(struct rkisp1_params *params, { u32 filt_mode; - rkisp1_write(params->rkisp1, - arg->thresh_bl0, RKISP1_CIF_ISP_FILT_THRESH_BL0); - rkisp1_write(params->rkisp1, - arg->thresh_bl1, RKISP1_CIF_ISP_FILT_THRESH_BL1); - rkisp1_write(params->rkisp1, - arg->thresh_sh0, RKISP1_CIF_ISP_FILT_THRESH_SH0); - rkisp1_write(params->rkisp1, - arg->thresh_sh1, RKISP1_CIF_ISP_FILT_THRESH_SH1); - rkisp1_write(params->rkisp1, arg->fac_bl0, RKISP1_CIF_ISP_FILT_FAC_BL0); - rkisp1_write(params->rkisp1, arg->fac_bl1, RKISP1_CIF_ISP_FILT_FAC_BL1); - rkisp1_write(params->rkisp1, arg->fac_mid, RKISP1_CIF_ISP_FILT_FAC_MID); - rkisp1_write(params->rkisp1, arg->fac_sh0, RKISP1_CIF_ISP_FILT_FAC_SH0); - rkisp1_write(params->rkisp1, arg->fac_sh1, RKISP1_CIF_ISP_FILT_FAC_SH1); - rkisp1_write(params->rkisp1, - arg->lum_weight, RKISP1_CIF_ISP_FILT_LUM_WEIGHT); - - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_BL0, + arg->thresh_bl0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_BL1, + arg->thresh_bl1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH0, + arg->thresh_sh0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH1, + arg->thresh_sh1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL0, + arg->fac_bl0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL1, + arg->fac_bl1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_MID, + arg->fac_mid); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH0, + arg->fac_sh0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH1, + arg->fac_sh1); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT, + arg->lum_weight); + + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE, (arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) | RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | - RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1), - RKISP1_CIF_ISP_FILT_MODE); + RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1)); /* avoid to override the old enable value */ filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE); @@ -414,7 +414,7 @@ static void rkisp1_flt_config(struct rkisp1_params *params, filt_mode |= RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) | RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) | RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1); - rkisp1_write(params->rkisp1, filt_mode, RKISP1_CIF_ISP_FILT_MODE); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE, filt_mode); } /* ISP demosaic interface function */ @@ -428,7 +428,7 @@ static int rkisp1_bdm_config(struct rkisp1_params *params, bdm_th &= RKISP1_CIF_ISP_DEMOSAIC_BYPASS; bdm_th |= arg->demosaic_th & ~RKISP1_CIF_ISP_DEMOSAIC_BYPASS; /* set demosaic threshold */ - rkisp1_write(params->rkisp1, bdm_th, RKISP1_CIF_ISP_DEMOSAIC); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DEMOSAIC, bdm_th); return 0; } @@ -438,18 +438,21 @@ static void rkisp1_sdg_config(struct rkisp1_params *params, { unsigned int i; - rkisp1_write(params->rkisp1, - arg->xa_pnts.gamma_dx0, RKISP1_CIF_ISP_GAMMA_DX_LO); - rkisp1_write(params->rkisp1, - arg->xa_pnts.gamma_dx1, RKISP1_CIF_ISP_GAMMA_DX_HI); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_DX_LO, + arg->xa_pnts.gamma_dx0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_DX_HI, + arg->xa_pnts.gamma_dx1); for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) { - rkisp1_write(params->rkisp1, arg->curve_r.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4); - rkisp1_write(params->rkisp1, arg->curve_g.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4); - rkisp1_write(params->rkisp1, arg->curve_b.gamma_y[i], - RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4, + arg->curve_r.gamma_y[i]); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4, + arg->curve_g.gamma_y[i]); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4, + arg->curve_b.gamma_y[i]); } } @@ -461,11 +464,13 @@ static void rkisp1_goc_config_v10(struct rkisp1_params *params, rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10, + arg->mode); for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; i++) - rkisp1_write(params->rkisp1, arg->gamma_y[i], - RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4, + arg->gamma_y[i]); } static void rkisp1_goc_config_v12(struct rkisp1_params *params, @@ -476,14 +481,15 @@ static void rkisp1_goc_config_v12(struct rkisp1_params *params, rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12, + arg->mode); for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12 / 2; i++) { value = RKISP1_CIF_ISP_GAMMA_VALUE_V12( arg->gamma_y[2 * i + 1], arg->gamma_y[2 * i]); - rkisp1_write(params->rkisp1, value, - RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4, value); } } @@ -495,11 +501,13 @@ static void rkisp1_ctk_config(struct rkisp1_params *params, for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) - rkisp1_write(params->rkisp1, arg->coeff[i][j], - RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++, + arg->coeff[i][j]); for (i = 0; i < 3; i++) - rkisp1_write(params->rkisp1, arg->ct_offset[i], - RKISP1_CIF_ISP_CT_OFFSET_R + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CT_OFFSET_R + i * 4, + arg->ct_offset[i]); } static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) @@ -508,19 +516,19 @@ static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en) return; /* Write back the default values. */ - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_0); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_1); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_2); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_3); - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_4); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_5); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_6); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_7); - rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_8); - - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_R); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_G); - rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_B); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_0, 0x80); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_1, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_2, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_3, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_4, 0x80); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_5, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_6, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_7, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_8, 0x80); + + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_R, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_G, 0); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_B, 0); } /* ISP White Balance Mode */ @@ -531,15 +539,15 @@ static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params, /* based on the mode,configure the awb module */ if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { /* Reference Cb and Cr */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_REF_V10, RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | - arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V10); + arg->awb_ref_cb); /* Yc Threshold */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V10, RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | - arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V10); + arg->min_c); } reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10); @@ -547,21 +555,21 @@ static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params, reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; else reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10, reg_val); /* window offset */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10); - rkisp1_write(params->rkisp1, - arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10, + arg->awb_wnd.v_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10, + arg->awb_wnd.h_offs); /* AWB window size */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10); - rkisp1_write(params->rkisp1, - arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10, + arg->awb_wnd.v_size); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10, + arg->awb_wnd.h_size); /* Number of frames */ - rkisp1_write(params->rkisp1, - arg->frames, RKISP1_CIF_ISP_AWB_FRAMES_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_FRAMES_V10, + arg->frames); } static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params, @@ -571,15 +579,15 @@ static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params, /* based on the mode,configure the awb module */ if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) { /* Reference Cb and Cr */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_REF_V12, RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) | - arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V12); + arg->awb_ref_cb); /* Yc Threshold */ - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V12, RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) | RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) | RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) | - arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V12); + arg->min_c); } reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12); @@ -589,18 +597,14 @@ static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params, reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN; reg_val &= ~RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12; reg_val |= RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(arg->frames); - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, reg_val); /* window offset */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_offs << 16 | - arg->awb_wnd.h_offs, - RKISP1_CIF_ISP_AWB_OFFS_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_OFFS_V12, + arg->awb_wnd.v_offs << 16 | arg->awb_wnd.h_offs); /* AWB window size */ - rkisp1_write(params->rkisp1, - arg->awb_wnd.v_size << 16 | - arg->awb_wnd.h_size, - RKISP1_CIF_ISP_AWB_SIZE_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_SIZE_V12, + arg->awb_wnd.v_size << 16 | arg->awb_wnd.h_size); } static void @@ -619,14 +623,15 @@ rkisp1_awb_meas_enable_v10(struct rkisp1_params *params, else reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10, + reg_val); /* Measurements require AWB block be active. */ rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } else { - rkisp1_write(params->rkisp1, - reg_val, RKISP1_CIF_ISP_AWB_PROP_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10, + reg_val); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } @@ -648,14 +653,15 @@ rkisp1_awb_meas_enable_v12(struct rkisp1_params *params, else reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN; - rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, + reg_val); /* Measurements require AWB block be active. */ rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } else { - rkisp1_write(params->rkisp1, - reg_val, RKISP1_CIF_ISP_AWB_PROP_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, + reg_val); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } @@ -665,26 +671,26 @@ static void rkisp1_awb_gain_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_awb_gain_config *arg) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V10, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | - arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V10); + arg->gain_green_b); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V10, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | - arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V10); + arg->gain_blue); } static void rkisp1_awb_gain_config_v12(struct rkisp1_params *params, const struct rkisp1_cif_isp_awb_gain_config *arg) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V12, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) | - arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V12); + arg->gain_green_b); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V12, RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) | - arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V12); + arg->gain_blue); } static void rkisp1_aec_config_v10(struct rkisp1_params *params, @@ -700,24 +706,22 @@ static void rkisp1_aec_config_v10(struct rkisp1_params *params, exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP; if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; - rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl); - rkisp1_write(params->rkisp1, - arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET_V10); - rkisp1_write(params->rkisp1, - arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_OFFSET_V10, + arg->meas_window.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_OFFSET_V10, + arg->meas_window.v_offs); block_hsize = arg->meas_window.h_size / RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 - 1; block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_EXP_ROW_NUM_V10 - 1; - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize), - RKISP1_CIF_ISP_EXP_H_SIZE_V10); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize), - RKISP1_CIF_ISP_EXP_V_SIZE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_SIZE_V10, + RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize)); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_SIZE_V10, + RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize)); } static void rkisp1_aec_config_v12(struct rkisp1_params *params, @@ -736,20 +740,18 @@ static void rkisp1_aec_config_v12(struct rkisp1_params *params, if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1) exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1; exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_WNDNUM_SET_V12(wnd_num_idx); - rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_OFFS_V12, RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(arg->meas_window.v_offs) | - RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs), - RKISP1_CIF_ISP_EXP_OFFS_V12); + RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs)); block_hsize = arg->meas_window.h_size / ae_wnd_num[wnd_num_idx] - 1; block_vsize = arg->meas_window.v_size / ae_wnd_num[wnd_num_idx] - 1; - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_SIZE_V12, RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(block_vsize) | - RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize), - RKISP1_CIF_ISP_EXP_SIZE_V12); + RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize)); } static void rkisp1_cproc_config(struct rkisp1_params *params, @@ -762,11 +764,12 @@ static void rkisp1_cproc_config(struct rkisp1_params *params, u32 effect = cur_ie_config->effect; u32 quantization = params->quantization; - rkisp1_write(params->rkisp1, arg->contrast, RKISP1_CIF_C_PROC_CONTRAST); - rkisp1_write(params->rkisp1, arg->hue, RKISP1_CIF_C_PROC_HUE); - rkisp1_write(params->rkisp1, arg->sat, RKISP1_CIF_C_PROC_SATURATION); - rkisp1_write(params->rkisp1, arg->brightness, - RKISP1_CIF_C_PROC_BRIGHTNESS); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_CONTRAST, + arg->contrast); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_HUE, arg->hue); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_SATURATION, arg->sat); + rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_BRIGHTNESS, + arg->brightness); if (quantization != V4L2_QUANTIZATION_FULL_RANGE || effect != V4L2_COLORFX_NONE) { @@ -802,31 +805,29 @@ static void rkisp1_hst_config_v10(struct rkisp1_params *params, hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10); hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10; hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(arg->histogram_predivider); - rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP_V10); - rkisp1_write(params->rkisp1, - arg->meas_window.h_offs, - RKISP1_CIF_ISP_HIST_H_OFFS_V10); - rkisp1_write(params->rkisp1, - arg->meas_window.v_offs, - RKISP1_CIF_ISP_HIST_V_OFFS_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10, hist_prop); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_OFFS_V10, + arg->meas_window.h_offs); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_OFFS_V10, + arg->meas_window.v_offs); block_hsize = arg->meas_window.h_size / RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 - 1; block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM_V10 - 1; - rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE_V10); - rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_SIZE_V10, + block_hsize); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_SIZE_V10, + block_vsize); weight = arg->hist_weight; for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4) - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0], - weight[1], - weight[2], - weight[3]), - hist_weight_regs[i]); + rkisp1_write(params->rkisp1, hist_weight_regs[i], + RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0], weight[1], + weight[2], weight[3])); - rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10, + weight[0] & 0x1F); } static void rkisp1_hst_config_v12(struct rkisp1_params *params, @@ -852,18 +853,16 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params, RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(0) | RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(1) | RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(arg->histogram_predivider); - rkisp1_write(params->rkisp1, hist_ctrl, RKISP1_CIF_ISP_HIST_CTRL_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_CTRL_V12, hist_ctrl); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_OFFS_V12, RKISP1_CIF_ISP_HIST_OFFS_SET_V12(arg->meas_window.h_offs, - arg->meas_window.v_offs), - RKISP1_CIF_ISP_HIST_OFFS_V12); + arg->meas_window.v_offs)); block_hsize = arg->meas_window.h_size / hist_wnd_num[wnd_num_idx] - 1; block_vsize = arg->meas_window.v_size / hist_wnd_num[wnd_num_idx] - 1; - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize), - RKISP1_CIF_ISP_HIST_SIZE_V12); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_SIZE_V12, + RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize)); for (i = 0; i < hist_wnd_num[wnd_num_idx]; i++) { for (j = 0; j < hist_wnd_num[wnd_num_idx]; j++) { @@ -879,12 +878,12 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params, weight15x15[4 * i + 1], weight15x15[4 * i + 2], weight15x15[4 * i + 3]); - rkisp1_write(params->rkisp1, value, - RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i, value); } value = RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(weight15x15[4 * i + 0], 0, 0, 0); - rkisp1_write(params->rkisp1, value, - RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i, + value); } static void @@ -938,22 +937,20 @@ static void rkisp1_afm_config_v10(struct rkisp1_params *params, RKISP1_CIF_ISP_AFM_ENA); for (i = 0; i < num_of_win; i++) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_LT_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | - RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_LT_A + i * 8); - rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs)); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + arg->afm_win[i].h_offs) | RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + - arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_RB_A + i * 8); + arg->afm_win[i].v_offs)); } - rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); - rkisp1_write(params->rkisp1, arg->var_shift, - RKISP1_CIF_ISP_AFM_VAR_SHIFT); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT, + arg->var_shift); /* restore afm status */ - rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, afm_ctrl); } static void rkisp1_afm_config_v12(struct rkisp1_params *params, @@ -970,29 +967,26 @@ static void rkisp1_afm_config_v12(struct rkisp1_params *params, RKISP1_CIF_ISP_AFM_ENA); for (i = 0; i < num_of_win; i++) { - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_LT_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) | - RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_LT_A + i * 8); - rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs)); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8, RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size + arg->afm_win[i].h_offs) | RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size + - arg->afm_win[i].v_offs), - RKISP1_CIF_ISP_AFM_RB_A + i * 8); + arg->afm_win[i].v_offs)); } - rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres); lum_var_shift = RKISP1_CIF_ISP_AFM_GET_LUM_SHIFT_a_V12(arg->var_shift); afm_var_shift = RKISP1_CIF_ISP_AFM_GET_AFM_SHIFT_a_V12(arg->var_shift); - rkisp1_write(params->rkisp1, + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT, RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(lum_var_shift, afm_var_shift) | RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(lum_var_shift, afm_var_shift) | - RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift), - RKISP1_CIF_ISP_AFM_VAR_SHIFT); + RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift)); /* restore afm status */ - rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, afm_ctrl); } static void rkisp1_ie_config(struct rkisp1_params *params, @@ -1011,8 +1005,8 @@ static void rkisp1_ie_config(struct rkisp1_params *params, eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; break; case V4L2_COLORFX_SET_CBCR: - rkisp1_write(params->rkisp1, arg->eff_tint, - RKISP1_CIF_IMG_EFF_TINT); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_TINT, + arg->eff_tint); eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA; break; /* @@ -1021,26 +1015,26 @@ static void rkisp1_ie_config(struct rkisp1_params *params, */ case V4L2_COLORFX_AQUA: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL; - rkisp1_write(params->rkisp1, arg->color_sel, - RKISP1_CIF_IMG_EFF_COLOR_SEL); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_COLOR_SEL, + arg->color_sel); break; case V4L2_COLORFX_EMBOSS: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS; - rkisp1_write(params->rkisp1, arg->eff_mat_1, - RKISP1_CIF_IMG_EFF_MAT_1); - rkisp1_write(params->rkisp1, arg->eff_mat_2, - RKISP1_CIF_IMG_EFF_MAT_2); - rkisp1_write(params->rkisp1, arg->eff_mat_3, - RKISP1_CIF_IMG_EFF_MAT_3); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_1, + arg->eff_mat_1); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_2, + arg->eff_mat_2); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3, + arg->eff_mat_3); break; case V4L2_COLORFX_SKETCH: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH; - rkisp1_write(params->rkisp1, arg->eff_mat_3, - RKISP1_CIF_IMG_EFF_MAT_3); - rkisp1_write(params->rkisp1, arg->eff_mat_4, - RKISP1_CIF_IMG_EFF_MAT_4); - rkisp1_write(params->rkisp1, arg->eff_mat_5, - RKISP1_CIF_IMG_EFF_MAT_5); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3, + arg->eff_mat_3); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_4, + arg->eff_mat_4); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_5, + arg->eff_mat_5); break; case V4L2_COLORFX_BW: eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE; @@ -1052,23 +1046,23 @@ static void rkisp1_ie_config(struct rkisp1_params *params, break; } - rkisp1_write(params->rkisp1, eff_ctrl, RKISP1_CIF_IMG_EFF_CTRL); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL, eff_ctrl); } static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) { if (en) { - rkisp1_param_set_bits(params, RKISP1_CIF_ICCL, - RKISP1_CIF_ICCL_IE_CLK); - rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL_ENABLE, - RKISP1_CIF_IMG_EFF_CTRL); + rkisp1_param_set_bits(params, RKISP1_CIF_VI_ICCL, + RKISP1_CIF_VI_ICCL_IE_CLK); + rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL, + RKISP1_CIF_IMG_EFF_CTRL_ENABLE); rkisp1_param_set_bits(params, RKISP1_CIF_IMG_EFF_CTRL, RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD); } else { rkisp1_param_clear_bits(params, RKISP1_CIF_IMG_EFF_CTRL, RKISP1_CIF_IMG_EFF_CTRL_ENABLE); - rkisp1_param_clear_bits(params, RKISP1_CIF_ICCL, - RKISP1_CIF_ICCL_IE_CLK); + rkisp1_param_clear_bits(params, RKISP1_CIF_VI_ICCL, + RKISP1_CIF_VI_ICCL_IE_CLK); } } @@ -1088,16 +1082,18 @@ static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) if (full_range) { for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) - rkisp1_write(params->rkisp1, full_range_coeff[i], - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, + full_range_coeff[i]); rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); } else { for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) - rkisp1_write(params->rkisp1, limited_range_coeff[i], - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, + limited_range_coeff[i]); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | @@ -1152,52 +1148,53 @@ static void rkisp1_dpf_config(struct rkisp1_params *params, rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE, isp_dpf_mode); - rkisp1_write(params->rkisp1, arg->gain.nf_b_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_B); - rkisp1_write(params->rkisp1, arg->gain.nf_r_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_R); - rkisp1_write(params->rkisp1, arg->gain.nf_gb_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_GB); - rkisp1_write(params->rkisp1, arg->gain.nf_gr_gain, - RKISP1_CIF_ISP_DPF_NF_GAIN_GR); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_B, + arg->gain.nf_b_gain); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_R, + arg->gain.nf_r_gain); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GB, + arg->gain.nf_gb_gain); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GR, + arg->gain.nf_gr_gain); for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) { - rkisp1_write(params->rkisp1, arg->nll.coeff[i], - RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4); + rkisp1_write(params->rkisp1, + RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4, + arg->nll.coeff[i]); } spatial_coeff = arg->g_flt.spatial_coeff[0] | (arg->g_flt.spatial_coeff[1] << 8) | (arg->g_flt.spatial_coeff[2] << 16) | (arg->g_flt.spatial_coeff[3] << 24); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4, + spatial_coeff); spatial_coeff = arg->g_flt.spatial_coeff[4] | (arg->g_flt.spatial_coeff[5] << 8); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6, + spatial_coeff); spatial_coeff = arg->rb_flt.spatial_coeff[0] | (arg->rb_flt.spatial_coeff[1] << 8) | (arg->rb_flt.spatial_coeff[2] << 16) | (arg->rb_flt.spatial_coeff[3] << 24); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4, + spatial_coeff); spatial_coeff = arg->rb_flt.spatial_coeff[4] | (arg->rb_flt.spatial_coeff[5] << 8); - rkisp1_write(params->rkisp1, spatial_coeff, - RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6, + spatial_coeff); } static void rkisp1_dpf_strength_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_dpf_strength_config *arg) { - rkisp1_write(params->rkisp1, arg->b, RKISP1_CIF_ISP_DPF_STRENGTH_B); - rkisp1_write(params->rkisp1, arg->g, RKISP1_CIF_ISP_DPF_STRENGTH_G); - rkisp1_write(params->rkisp1, arg->r, RKISP1_CIF_ISP_DPF_STRENGTH_R); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_B, arg->b); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_G, arg->g); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_R, arg->r); } static void @@ -1804,7 +1801,7 @@ static void rkisp1_init_params(struct rkisp1_params *params) params->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_params_cfg); - if (params->rkisp1->media_dev.hw_revision == RKISP1_V12) + if (params->rkisp1->info->isp_ver == RKISP1_V12) params->ops = &rkisp1_v12_params_ops; else params->ops = &rkisp1_v10_params_ops; @@ -1844,16 +1841,20 @@ int rkisp1_params_register(struct rkisp1_device *rkisp1) node->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); if (ret) - return ret; + goto error; + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(rkisp1->dev, "failed to register %s, ret=%d\n", vdev->name, ret); - goto err_cleanup_media_entity; + goto error; } + return 0; -err_cleanup_media_entity: + +error: media_entity_cleanup(&vdev->entity); + mutex_destroy(&node->vlock); return ret; } @@ -1863,6 +1864,10 @@ void rkisp1_params_unregister(struct rkisp1_device *rkisp1) struct rkisp1_vdev_node *node = ¶ms->vnode; struct video_device *vdev = &node->vdev; + if (!video_is_registered(vdev)) + return; + vb2_video_unregister_device(vdev); media_entity_cleanup(&vdev->entity); + mutex_destroy(&node->vlock); } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index 82f8d33d98b3..dd3e6c38be67 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -11,7 +11,7 @@ /* ISP_CTRL */ #define RKISP1_CIF_ISP_CTRL_ISP_ENABLE BIT(0) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT (0 << 1) -#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 BIT(1) +#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 (1 << 1) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601 (2 << 1) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601 (3 << 1) #define RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE (4 << 1) @@ -33,37 +33,37 @@ #define RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW BIT(1) #define RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW BIT(2) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB (0 << 3) -#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG BIT(3) +#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG (1 << 3) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG (2 << 3) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR (3 << 3) #define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(pat) ((pat) << 3) #define RKISP1_CIF_ISP_ACQ_PROP_YCBYCR (0 << 7) -#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB BIT(7) +#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB (1 << 7) #define RKISP1_CIF_ISP_ACQ_PROP_CBYCRY (2 << 7) #define RKISP1_CIF_ISP_ACQ_PROP_CRYCBY (3 << 7) #define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL (0 << 9) -#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN BIT(9) +#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN (1 << 9) #define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ODD (2 << 9) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B (0 << 12) -#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO BIT(12) +#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO (1 << 12) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12) #define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12) /* VI_DPCL */ #define RKISP1_CIF_VI_DPCL_DMA_JPEG (0 << 0) -#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI BIT(0) +#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI (1 << 0) #define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_JPEG (2 << 0) -#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP BIT(2) +#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP (1 << 2) #define RKISP1_CIF_VI_DPCL_CHAN_MODE_SP (2 << 2) #define RKISP1_CIF_VI_DPCL_CHAN_MODE_MPSP (3 << 2) #define RKISP1_CIF_VI_DPCL_DMA_SW_SPMUX (0 << 4) -#define RKISP1_CIF_VI_DPCL_DMA_SW_SI BIT(4) +#define RKISP1_CIF_VI_DPCL_DMA_SW_SI (1 << 4) #define RKISP1_CIF_VI_DPCL_DMA_SW_IE (2 << 4) #define RKISP1_CIF_VI_DPCL_DMA_SW_JPEG (3 << 4) #define RKISP1_CIF_VI_DPCL_DMA_SW_ISP (4 << 4) #define RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL (0 << 8) -#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA BIT(8) +#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA (1 << 8) #define RKISP1_CIF_VI_DPCL_IF_SEL_MIPI (2 << 8) #define RKISP1_CIF_VI_DPCL_DMA_IE_MUX_DMA BIT(10) #define RKISP1_CIF_VI_DPCL_DMA_SP_MUX_DMA BIT(11) @@ -112,26 +112,26 @@ #define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14) #define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15) #define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_16 (0 << 16) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 BIT(16) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 (1 << 16) #define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64 (2 << 16) #define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_16 (0 << 18) -#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 BIT(18) +#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 (1 << 18) #define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64 (2 << 18) #define RKISP1_CIF_MI_CTRL_INIT_BASE_EN BIT(20) #define RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN BIT(21) #define RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8 (0 << 22) -#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA BIT(22) +#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA (1 << 22) #define RKISP1_MI_CTRL_MP_WRITE_YUVINT (2 << 22) #define RKISP1_MI_CTRL_MP_WRITE_RAW12 (2 << 22) #define RKISP1_MI_CTRL_SP_WRITE_PLA (0 << 24) -#define RKISP1_MI_CTRL_SP_WRITE_SPLA BIT(24) +#define RKISP1_MI_CTRL_SP_WRITE_SPLA (1 << 24) #define RKISP1_MI_CTRL_SP_WRITE_INT (2 << 24) #define RKISP1_MI_CTRL_SP_INPUT_YUV400 (0 << 26) -#define RKISP1_MI_CTRL_SP_INPUT_YUV420 BIT(26) +#define RKISP1_MI_CTRL_SP_INPUT_YUV420 (1 << 26) #define RKISP1_MI_CTRL_SP_INPUT_YUV422 (2 << 26) #define RKISP1_MI_CTRL_SP_INPUT_YUV444 (3 << 26) #define RKISP1_MI_CTRL_SP_OUTPUT_YUV400 (0 << 28) -#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 BIT(28) +#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 (1 << 28) #define RKISP1_MI_CTRL_SP_OUTPUT_YUV422 (2 << 28) #define RKISP1_MI_CTRL_SP_OUTPUT_YUV444 (3 << 28) #define RKISP1_MI_CTRL_SP_OUTPUT_RGB565 (4 << 28) @@ -186,22 +186,22 @@ /* MI_DMA_CTRL */ #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 BIT(0) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 (1 << 0) #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0) #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2) -#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 BIT(2) +#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 (1 << 2) #define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2) #define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4) -#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR BIT(4) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) -#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 BIT(6) +#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR (1 << 4) #define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6) +#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 (1 << 6) #define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6) #define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6) #define RKISP1_CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8) #define RKISP1_CIF_MI_DMA_CTRL_CONTINUOUS_ENA BIT(9) #define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_NO (0 << 12) -#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT BIT(12) +#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT (1 << 12) #define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_16BIT (2 << 12) /* MI_DMA_START */ #define RKISP1_CIF_MI_DMA_START_ENABLE BIT(0) @@ -210,7 +210,7 @@ #define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1) #define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2) -/* CCL */ +/* VI_CCL */ #define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2) /* VI_ISP_CLK_CTRL */ #define RKISP1_CIF_CLK_CTRL_ISP_RAW BIT(0) @@ -241,32 +241,32 @@ #define RKISP1_CIF_CLK_CTRL_RSZS BIT(25) #define RKISP1_CIF_CLK_CTRL_MIPI BIT(26) #define RKISP1_CIF_CLK_CTRL_MARVINMI BIT(27) -/* ICCL */ -#define RKISP1_CIF_ICCL_ISP_CLK BIT(0) -#define RKISP1_CIF_ICCL_CP_CLK BIT(1) -#define RKISP1_CIF_ICCL_RES_2 BIT(2) -#define RKISP1_CIF_ICCL_MRSZ_CLK BIT(3) -#define RKISP1_CIF_ICCL_SRSZ_CLK BIT(4) -#define RKISP1_CIF_ICCL_JPEG_CLK BIT(5) -#define RKISP1_CIF_ICCL_MI_CLK BIT(6) -#define RKISP1_CIF_ICCL_RES_7 BIT(7) -#define RKISP1_CIF_ICCL_IE_CLK BIT(8) -#define RKISP1_CIF_ICCL_SIMP_CLK BIT(9) -#define RKISP1_CIF_ICCL_SMIA_CLK BIT(10) -#define RKISP1_CIF_ICCL_MIPI_CLK BIT(11) -#define RKISP1_CIF_ICCL_DCROP_CLK BIT(12) -/* IRCL */ -#define RKISP1_CIF_IRCL_ISP_SW_RST BIT(0) -#define RKISP1_CIF_IRCL_CP_SW_RST BIT(1) -#define RKISP1_CIF_IRCL_YCS_SW_RST BIT(2) -#define RKISP1_CIF_IRCL_MRSZ_SW_RST BIT(3) -#define RKISP1_CIF_IRCL_SRSZ_SW_RST BIT(4) -#define RKISP1_CIF_IRCL_JPEG_SW_RST BIT(5) -#define RKISP1_CIF_IRCL_MI_SW_RST BIT(6) -#define RKISP1_CIF_IRCL_CIF_SW_RST BIT(7) -#define RKISP1_CIF_IRCL_IE_SW_RST BIT(8) -#define RKISP1_CIF_IRCL_SI_SW_RST BIT(9) -#define RKISP1_CIF_IRCL_MIPI_SW_RST BIT(11) +/* VI_ICCL */ +#define RKISP1_CIF_VI_ICCL_ISP_CLK BIT(0) +#define RKISP1_CIF_VI_ICCL_CP_CLK BIT(1) +#define RKISP1_CIF_VI_ICCL_RES_2 BIT(2) +#define RKISP1_CIF_VI_ICCL_MRSZ_CLK BIT(3) +#define RKISP1_CIF_VI_ICCL_SRSZ_CLK BIT(4) +#define RKISP1_CIF_VI_ICCL_JPEG_CLK BIT(5) +#define RKISP1_CIF_VI_ICCL_MI_CLK BIT(6) +#define RKISP1_CIF_VI_ICCL_RES_7 BIT(7) +#define RKISP1_CIF_VI_ICCL_IE_CLK BIT(8) +#define RKISP1_CIF_VI_ICCL_SIMP_CLK BIT(9) +#define RKISP1_CIF_VI_ICCL_SMIA_CLK BIT(10) +#define RKISP1_CIF_VI_ICCL_MIPI_CLK BIT(11) +#define RKISP1_CIF_VI_ICCL_DCROP_CLK BIT(12) +/* VI_IRCL */ +#define RKISP1_CIF_VI_IRCL_ISP_SW_RST BIT(0) +#define RKISP1_CIF_VI_IRCL_CP_SW_RST BIT(1) +#define RKISP1_CIF_VI_IRCL_YCS_SW_RST BIT(2) +#define RKISP1_CIF_VI_IRCL_MRSZ_SW_RST BIT(3) +#define RKISP1_CIF_VI_IRCL_SRSZ_SW_RST BIT(4) +#define RKISP1_CIF_VI_IRCL_JPEG_SW_RST BIT(5) +#define RKISP1_CIF_VI_IRCL_MI_SW_RST BIT(6) +#define RKISP1_CIF_VI_IRCL_CIF_SW_RST BIT(7) +#define RKISP1_CIF_VI_IRCL_IE_SW_RST BIT(8) +#define RKISP1_CIF_VI_IRCL_SI_SW_RST BIT(9) +#define RKISP1_CIF_VI_IRCL_MIPI_SW_RST BIT(11) /* C_PROC_CTR */ #define RKISP1_CIF_C_PROC_CTR_ENABLE BIT(0) @@ -282,10 +282,10 @@ #define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000 /* DUAL_CROP_CTRL */ #define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0) -#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV BIT(0) +#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV (1 << 0) #define RKISP1_CIF_DUAL_CROP_MP_MODE_RAW (2 << 0) #define RKISP1_CIF_DUAL_CROP_SP_MODE_BYPASS (0 << 2) -#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV BIT(2) +#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV (1 << 2) #define RKISP1_CIF_DUAL_CROP_SP_MODE_RAW (2 << 2) #define RKISP1_CIF_DUAL_CROP_CFG_UPD_PERMANENT BIT(4) #define RKISP1_CIF_DUAL_CROP_CFG_UPD BIT(5) @@ -294,7 +294,7 @@ /* IMG_EFF_CTRL */ #define RKISP1_CIF_IMG_EFF_CTRL_ENABLE BIT(0) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE (0 << 1) -#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE BIT(1) +#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE (1 << 1) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA (2 << 1) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL (3 << 1) #define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS (4 << 1) @@ -314,7 +314,7 @@ /* IMG_EFF_COLOR_SEL */ #define RKISP1_CIF_IMG_EFF_COLOR_RGB 0 -#define RKISP1_CIF_IMG_EFF_COLOR_B BIT(0) +#define RKISP1_CIF_IMG_EFF_COLOR_B (1 << 0) #define RKISP1_CIF_IMG_EFF_COLOR_G (2 << 0) #define RKISP1_CIF_IMG_EFF_COLOR_GB (3 << 0) #define RKISP1_CIF_IMG_EFF_COLOR_R (4 << 0) @@ -365,7 +365,7 @@ /* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */ #define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS_V10 (0 << 0) -#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB_V10 BIT(0) +#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB_V10 (1 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_RED_V10 (2 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN_V10 (3 << 0) #define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE_V10 (4 << 0) @@ -443,6 +443,15 @@ #define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10) #define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF) +/* ISP_FLAGS_SHD */ +#define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_SHD BIT(0) +#define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_INFORM_SHD BIT(1) +#define RKISP1_CIF_ISP_FLAGS_SHD_INFORM_FIELD BIT(2) +#define RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK GENMASK(27, 16) +#define RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT 16 +#define RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC BIT(30) +#define RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC BIT(31) + /* AWB */ /* ISP_AWB_PROP */ #define RKISP1_CIF_ISP_AWB_YMAX_CMP_EN BIT(2) @@ -628,7 +637,7 @@ #define RKISP1_CIF_ISP_BLS_ENA BIT(0) #define RKISP1_CIF_ISP_BLS_MODE_MEASURED BIT(1) #define RKISP1_CIF_ISP_BLS_MODE_FIXED 0 -#define RKISP1_CIF_ISP_BLS_WINDOW_1 BIT(2) +#define RKISP1_CIF_ISP_BLS_WINDOW_1 (1 << 2) #define RKISP1_CIF_ISP_BLS_WINDOW_2 (2 << 2) /* GAMMA-IN */ @@ -676,11 +685,11 @@ /* CIF Registers */ /* =================================================================== */ #define RKISP1_CIF_CTRL_BASE 0x00000000 -#define RKISP1_CIF_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) +#define RKISP1_CIF_VI_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000) #define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008) #define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000C) -#define RKISP1_CIF_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) -#define RKISP1_CIF_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) +#define RKISP1_CIF_VI_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010) +#define RKISP1_CIF_VI_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014) #define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018) #define RKISP1_CIF_IMG_EFF_BASE 0x00000200 @@ -894,52 +903,29 @@ #define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040) #define RKISP1_CIF_MRSZ_BASE 0x00000C00 -#define RKISP1_CIF_MRSZ_CTRL (RKISP1_CIF_MRSZ_BASE + 0x00000000) -#define RKISP1_CIF_MRSZ_SCALE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000004) -#define RKISP1_CIF_MRSZ_SCALE_HCB (RKISP1_CIF_MRSZ_BASE + 0x00000008) -#define RKISP1_CIF_MRSZ_SCALE_HCR (RKISP1_CIF_MRSZ_BASE + 0x0000000C) -#define RKISP1_CIF_MRSZ_SCALE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000010) -#define RKISP1_CIF_MRSZ_SCALE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000014) -#define RKISP1_CIF_MRSZ_PHASE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000018) -#define RKISP1_CIF_MRSZ_PHASE_HC (RKISP1_CIF_MRSZ_BASE + 0x0000001C) -#define RKISP1_CIF_MRSZ_PHASE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000020) -#define RKISP1_CIF_MRSZ_PHASE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000024) -#define RKISP1_CIF_MRSZ_SCALE_LUT_ADDR (RKISP1_CIF_MRSZ_BASE + 0x00000028) -#define RKISP1_CIF_MRSZ_SCALE_LUT (RKISP1_CIF_MRSZ_BASE + 0x0000002C) -#define RKISP1_CIF_MRSZ_CTRL_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000030) -#define RKISP1_CIF_MRSZ_SCALE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000034) -#define RKISP1_CIF_MRSZ_SCALE_HCB_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000038) -#define RKISP1_CIF_MRSZ_SCALE_HCR_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000003C) -#define RKISP1_CIF_MRSZ_SCALE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000040) -#define RKISP1_CIF_MRSZ_SCALE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000044) -#define RKISP1_CIF_MRSZ_PHASE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000048) -#define RKISP1_CIF_MRSZ_PHASE_HC_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000004C) -#define RKISP1_CIF_MRSZ_PHASE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000050) -#define RKISP1_CIF_MRSZ_PHASE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000054) - #define RKISP1_CIF_SRSZ_BASE 0x00001000 -#define RKISP1_CIF_SRSZ_CTRL (RKISP1_CIF_SRSZ_BASE + 0x00000000) -#define RKISP1_CIF_SRSZ_SCALE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000004) -#define RKISP1_CIF_SRSZ_SCALE_HCB (RKISP1_CIF_SRSZ_BASE + 0x00000008) -#define RKISP1_CIF_SRSZ_SCALE_HCR (RKISP1_CIF_SRSZ_BASE + 0x0000000C) -#define RKISP1_CIF_SRSZ_SCALE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000010) -#define RKISP1_CIF_SRSZ_SCALE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000014) -#define RKISP1_CIF_SRSZ_PHASE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000018) -#define RKISP1_CIF_SRSZ_PHASE_HC (RKISP1_CIF_SRSZ_BASE + 0x0000001C) -#define RKISP1_CIF_SRSZ_PHASE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000020) -#define RKISP1_CIF_SRSZ_PHASE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000024) -#define RKISP1_CIF_SRSZ_SCALE_LUT_ADDR (RKISP1_CIF_SRSZ_BASE + 0x00000028) -#define RKISP1_CIF_SRSZ_SCALE_LUT (RKISP1_CIF_SRSZ_BASE + 0x0000002C) -#define RKISP1_CIF_SRSZ_CTRL_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000030) -#define RKISP1_CIF_SRSZ_SCALE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000034) -#define RKISP1_CIF_SRSZ_SCALE_HCB_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000038) -#define RKISP1_CIF_SRSZ_SCALE_HCR_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000003C) -#define RKISP1_CIF_SRSZ_SCALE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000040) -#define RKISP1_CIF_SRSZ_SCALE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000044) -#define RKISP1_CIF_SRSZ_PHASE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000048) -#define RKISP1_CIF_SRSZ_PHASE_HC_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000004C) -#define RKISP1_CIF_SRSZ_PHASE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000050) -#define RKISP1_CIF_SRSZ_PHASE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000054) +#define RKISP1_CIF_RSZ_CTRL 0x0000 +#define RKISP1_CIF_RSZ_SCALE_HY 0x0004 +#define RKISP1_CIF_RSZ_SCALE_HCB 0x0008 +#define RKISP1_CIF_RSZ_SCALE_HCR 0x000C +#define RKISP1_CIF_RSZ_SCALE_VY 0x0010 +#define RKISP1_CIF_RSZ_SCALE_VC 0x0014 +#define RKISP1_CIF_RSZ_PHASE_HY 0x0018 +#define RKISP1_CIF_RSZ_PHASE_HC 0x001C +#define RKISP1_CIF_RSZ_PHASE_VY 0x0020 +#define RKISP1_CIF_RSZ_PHASE_VC 0x0024 +#define RKISP1_CIF_RSZ_SCALE_LUT_ADDR 0x0028 +#define RKISP1_CIF_RSZ_SCALE_LUT 0x002C +#define RKISP1_CIF_RSZ_CTRL_SHD 0x0030 +#define RKISP1_CIF_RSZ_SCALE_HY_SHD 0x0034 +#define RKISP1_CIF_RSZ_SCALE_HCB_SHD 0x0038 +#define RKISP1_CIF_RSZ_SCALE_HCR_SHD 0x003C +#define RKISP1_CIF_RSZ_SCALE_VY_SHD 0x0040 +#define RKISP1_CIF_RSZ_SCALE_VC_SHD 0x0044 +#define RKISP1_CIF_RSZ_PHASE_HY_SHD 0x0048 +#define RKISP1_CIF_RSZ_PHASE_HC_SHD 0x004C +#define RKISP1_CIF_RSZ_PHASE_VY_SHD 0x0050 +#define RKISP1_CIF_RSZ_PHASE_VC_SHD 0x0054 #define RKISP1_CIF_MI_BASE 0x00001400 #define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 2070f4b06705..f4caa8f684aa 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -61,30 +61,6 @@ struct rkisp1_rsz_config { /* registers */ struct { u32 ctrl; - u32 ctrl_shd; - u32 scale_hy; - u32 scale_hcr; - u32 scale_hcb; - u32 scale_vy; - u32 scale_vc; - u32 scale_lut; - u32 scale_lut_addr; - u32 scale_hy_shd; - u32 scale_hcr_shd; - u32 scale_hcb_shd; - u32 scale_vy_shd; - u32 scale_vc_shd; - u32 phase_hy; - u32 phase_hc; - u32 phase_vy; - u32 phase_vc; - u32 phase_hy_shd; - u32 phase_hc_shd; - u32 phase_vy_shd; - u32 phase_vc_shd; - } rsz; - struct { - u32 ctrl; u32 yuvmode_mask; u32 rawmode_mask; u32 h_offset; @@ -101,30 +77,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = { .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ - .rsz = { - .ctrl = RKISP1_CIF_MRSZ_CTRL, - .scale_hy = RKISP1_CIF_MRSZ_SCALE_HY, - .scale_hcr = RKISP1_CIF_MRSZ_SCALE_HCR, - .scale_hcb = RKISP1_CIF_MRSZ_SCALE_HCB, - .scale_vy = RKISP1_CIF_MRSZ_SCALE_VY, - .scale_vc = RKISP1_CIF_MRSZ_SCALE_VC, - .scale_lut = RKISP1_CIF_MRSZ_SCALE_LUT, - .scale_lut_addr = RKISP1_CIF_MRSZ_SCALE_LUT_ADDR, - .scale_hy_shd = RKISP1_CIF_MRSZ_SCALE_HY_SHD, - .scale_hcr_shd = RKISP1_CIF_MRSZ_SCALE_HCR_SHD, - .scale_hcb_shd = RKISP1_CIF_MRSZ_SCALE_HCB_SHD, - .scale_vy_shd = RKISP1_CIF_MRSZ_SCALE_VY_SHD, - .scale_vc_shd = RKISP1_CIF_MRSZ_SCALE_VC_SHD, - .phase_hy = RKISP1_CIF_MRSZ_PHASE_HY, - .phase_hc = RKISP1_CIF_MRSZ_PHASE_HC, - .phase_vy = RKISP1_CIF_MRSZ_PHASE_VY, - .phase_vc = RKISP1_CIF_MRSZ_PHASE_VC, - .ctrl_shd = RKISP1_CIF_MRSZ_CTRL_SHD, - .phase_hy_shd = RKISP1_CIF_MRSZ_PHASE_HY_SHD, - .phase_hc_shd = RKISP1_CIF_MRSZ_PHASE_HC_SHD, - .phase_vy_shd = RKISP1_CIF_MRSZ_PHASE_VY_SHD, - .phase_vc_shd = RKISP1_CIF_MRSZ_PHASE_VC_SHD, - }, .dual_crop = { .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV, @@ -143,30 +95,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { .min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH, .min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT, /* registers */ - .rsz = { - .ctrl = RKISP1_CIF_SRSZ_CTRL, - .scale_hy = RKISP1_CIF_SRSZ_SCALE_HY, - .scale_hcr = RKISP1_CIF_SRSZ_SCALE_HCR, - .scale_hcb = RKISP1_CIF_SRSZ_SCALE_HCB, - .scale_vy = RKISP1_CIF_SRSZ_SCALE_VY, - .scale_vc = RKISP1_CIF_SRSZ_SCALE_VC, - .scale_lut = RKISP1_CIF_SRSZ_SCALE_LUT, - .scale_lut_addr = RKISP1_CIF_SRSZ_SCALE_LUT_ADDR, - .scale_hy_shd = RKISP1_CIF_SRSZ_SCALE_HY_SHD, - .scale_hcr_shd = RKISP1_CIF_SRSZ_SCALE_HCR_SHD, - .scale_hcb_shd = RKISP1_CIF_SRSZ_SCALE_HCB_SHD, - .scale_vy_shd = RKISP1_CIF_SRSZ_SCALE_VY_SHD, - .scale_vc_shd = RKISP1_CIF_SRSZ_SCALE_VC_SHD, - .phase_hy = RKISP1_CIF_SRSZ_PHASE_HY, - .phase_hc = RKISP1_CIF_SRSZ_PHASE_HC, - .phase_vy = RKISP1_CIF_SRSZ_PHASE_VY, - .phase_vc = RKISP1_CIF_SRSZ_PHASE_VC, - .ctrl_shd = RKISP1_CIF_SRSZ_CTRL_SHD, - .phase_hy_shd = RKISP1_CIF_SRSZ_PHASE_HY_SHD, - .phase_hc_shd = RKISP1_CIF_SRSZ_PHASE_HC_SHD, - .phase_vy_shd = RKISP1_CIF_SRSZ_PHASE_VY_SHD, - .phase_vc_shd = RKISP1_CIF_SRSZ_PHASE_VC_SHD, - }, .dual_crop = { .ctrl = RKISP1_CIF_DUAL_CROP_CTRL, .yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV, @@ -178,6 +106,17 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = { }, }; +static inline u32 rkisp1_rsz_read(struct rkisp1_resizer *rsz, u32 offset) +{ + return rkisp1_read(rsz->rkisp1, rsz->regs_base + offset); +} + +static inline void rkisp1_rsz_write(struct rkisp1_resizer *rsz, u32 offset, + u32 value) +{ + rkisp1_write(rsz->rkisp1, rsz->regs_base + offset, value); +} + static struct v4l2_mbus_framefmt * rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz, struct v4l2_subdev_state *sd_state, @@ -222,7 +161,7 @@ static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz, dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD; else dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rsz->rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); + rkisp1_write(rsz->rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); } /* configure dual-crop unit */ @@ -247,13 +186,13 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) } dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl); - rkisp1_write(rkisp1, sink_crop->left, rsz->config->dual_crop.h_offset); - rkisp1_write(rkisp1, sink_crop->top, rsz->config->dual_crop.v_offset); - rkisp1_write(rkisp1, sink_crop->width, rsz->config->dual_crop.h_size); - rkisp1_write(rkisp1, sink_crop->height, rsz->config->dual_crop.v_size); + rkisp1_write(rkisp1, rsz->config->dual_crop.h_offset, sink_crop->left); + rkisp1_write(rkisp1, rsz->config->dual_crop.v_offset, sink_crop->top); + rkisp1_write(rkisp1, rsz->config->dual_crop.h_size, sink_crop->width); + rkisp1_write(rkisp1, rsz->config->dual_crop.v_size, sink_crop->height); dc_ctrl |= rsz->config->dual_crop.yuvmode_mask; dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD; - rkisp1_write(rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl); + rkisp1_write(rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl); dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id, sink_fmt->width, sink_fmt->height, @@ -264,52 +203,17 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz) * Resizer hw configs */ -static void rkisp1_rsz_dump_regs(struct rkisp1_resizer *rsz) -{ - dev_dbg(rsz->rkisp1->dev, - "RSZ_CTRL 0x%08x/0x%08x\n" - "RSZ_SCALE_HY %d/%d\n" - "RSZ_SCALE_HCB %d/%d\n" - "RSZ_SCALE_HCR %d/%d\n" - "RSZ_SCALE_VY %d/%d\n" - "RSZ_SCALE_VC %d/%d\n" - "RSZ_PHASE_HY %d/%d\n" - "RSZ_PHASE_HC %d/%d\n" - "RSZ_PHASE_VY %d/%d\n" - "RSZ_PHASE_VC %d/%d\n", - rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy_shd), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc), - rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc_shd)); -} - static void rkisp1_rsz_update_shadow(struct rkisp1_resizer *rsz, enum rkisp1_shadow_regs_when when) { - u32 ctrl_cfg = rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl); + u32 ctrl_cfg = rkisp1_rsz_read(rsz, RKISP1_CIF_RSZ_CTRL); if (when == RKISP1_SHADOW_REGS_ASYNC) ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO; else ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD; - rkisp1_write(rsz->rkisp1, ctrl_cfg, rsz->config->rsz.ctrl); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, ctrl_cfg); } static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src) @@ -325,7 +229,7 @@ static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src) static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz, enum rkisp1_shadow_regs_when when) { - rkisp1_write(rsz->rkisp1, 0, rsz->config->rsz.ctrl); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, 0); if (when == RKISP1_SHADOW_REGS_SYNC) rkisp1_rsz_update_shadow(rsz, when); @@ -338,20 +242,19 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, struct v4l2_rect *src_c, enum rkisp1_shadow_regs_when when) { - struct rkisp1_device *rkisp1 = rsz->rkisp1; u32 ratio, rsz_ctrl = 0; unsigned int i; /* No phase offset */ - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hy); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hc); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vy); - rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vc); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HY, 0); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HC, 0); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VY, 0); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VC, 0); /* Linear interpolation */ for (i = 0; i < 64; i++) { - rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut_addr); - rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT_ADDR, i); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT, i); } if (sink_y->width != src_y->width) { @@ -359,7 +262,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_y->width < src_y->width) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP; ratio = rkisp1_rsz_calc_ratio(sink_y->width, src_y->width); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hy); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HY, ratio); } if (sink_c->width != src_c->width) { @@ -367,8 +270,8 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_c->width < src_c->width) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP; ratio = rkisp1_rsz_calc_ratio(sink_c->width, src_c->width); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcb); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcr); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCB, ratio); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCR, ratio); } if (sink_y->height != src_y->height) { @@ -376,7 +279,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_y->height < src_y->height) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP; ratio = rkisp1_rsz_calc_ratio(sink_y->height, src_y->height); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vy); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VY, ratio); } if (sink_c->height != src_c->height) { @@ -384,10 +287,10 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz, if (sink_c->height < src_c->height) rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP; ratio = rkisp1_rsz_calc_ratio(sink_c->height, src_c->height); - rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vc); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VC, ratio); } - rkisp1_write(rkisp1, rsz_ctrl, rsz->config->rsz.ctrl); + rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, rsz_ctrl); rkisp1_rsz_update_shadow(rsz, when); } @@ -448,8 +351,6 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz, /* set values in the hw */ rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when); - - rkisp1_rsz_dump_regs(rsz); } /* ---------------------------------------------------------------------------- @@ -532,14 +433,14 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *sink_mbus_info; + const struct rkisp1_mbus_info *sink_mbus_info; struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, which); src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC, which); - sink_mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */ if (sink_mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV && @@ -561,7 +462,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, struct v4l2_rect *r, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; @@ -572,7 +473,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, which); /* Not crop for MP bayer raw data */ - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (rsz->id == RKISP1_MAINPATH && mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { @@ -599,7 +500,7 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; + const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; @@ -615,10 +516,10 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, else sink_fmt->code = format->code; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { sink_fmt->code = RKISP1_DEF_FMT; - mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); + mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); } if (which == V4L2_SUBDEV_FORMAT_ACTIVE) rsz->pixel_enc = mbus_info->pixel_enc; @@ -782,8 +683,12 @@ static const struct v4l2_subdev_ops rkisp1_rsz_ops = { static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz) { + if (!rsz->rkisp1) + return; + v4l2_device_unregister_subdev(&rsz->sd); media_entity_cleanup(&rsz->sd.entity); + mutex_destroy(&rsz->ops_lock); } static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) @@ -799,10 +704,13 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) struct v4l2_subdev *sd = &rsz->sd; int ret; - if (rsz->id == RKISP1_SELFPATH) + if (rsz->id == RKISP1_SELFPATH) { + rsz->regs_base = RKISP1_CIF_SRSZ_BASE; rsz->config = &rkisp1_rsz_config_sp; - else + } else { + rsz->regs_base = RKISP1_CIF_MRSZ_BASE; rsz->config = &rkisp1_rsz_config_mp; + } v4l2_subdev_init(sd, &rkisp1_rsz_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -821,47 +729,43 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz) mutex_init(&rsz->ops_lock); ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads); if (ret) - return ret; + goto error; ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd); if (ret) { dev_err(sd->dev, "Failed to register resizer subdev\n"); - goto err_cleanup_media_entity; + goto error; } rkisp1_rsz_init_config(sd, &state); return 0; -err_cleanup_media_entity: +error: media_entity_cleanup(&sd->entity); - + mutex_destroy(&rsz->ops_lock); return ret; } int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1) { - struct rkisp1_resizer *rsz; - unsigned int i, j; + unsigned int i; int ret; for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) { - rsz = &rkisp1->resizer_devs[i]; + struct rkisp1_resizer *rsz = &rkisp1->resizer_devs[i]; + rsz->rkisp1 = rkisp1; rsz->id = i; + ret = rkisp1_rsz_register(rsz); - if (ret) - goto err_unreg_resizer_devs; + if (ret) { + rsz->rkisp1 = NULL; + rkisp1_resizer_devs_unregister(rkisp1); + return ret; + } } return 0; - -err_unreg_resizer_devs: - for (j = 0; j < i; j++) { - rsz = &rkisp1->resizer_devs[j]; - rkisp1_rsz_unregister(rsz); - } - - return ret; } void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index be5777c65bfb..2795eef91bdd 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -305,7 +305,7 @@ static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats, struct rkisp1_stat_buffer *pbuf) { struct rkisp1_device *rkisp1 = stats->rkisp1; - const struct rkisp1_isp_mbus_info *in_fmt = rkisp1->isp.sink_fmt; + const struct rkisp1_mbus_info *in_fmt = rkisp1->isp.sink_fmt; struct rkisp1_cif_isp_bls_meas_val *bls_val; bls_val = &pbuf->params.ae.bls_val; @@ -408,7 +408,7 @@ void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris) spin_lock(&stats->lock); - rkisp1_write(rkisp1, RKISP1_STATS_MEAS_MASK, RKISP1_CIF_ISP_ICR); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, RKISP1_STATS_MEAS_MASK); isp_mis_tmp = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS); if (isp_mis_tmp & RKISP1_STATS_MEAS_MASK) @@ -427,7 +427,7 @@ static void rkisp1_init_stats(struct rkisp1_stats *stats) stats->vdev_fmt.fmt.meta.buffersize = sizeof(struct rkisp1_stat_buffer); - if (stats->rkisp1->media_dev.hw_revision == RKISP1_V12) + if (stats->rkisp1->info->isp_ver == RKISP1_V12) stats->ops = &rkisp1_v12_stats_ops; else stats->ops = &rkisp1_v10_stats_ops; @@ -463,21 +463,21 @@ int rkisp1_stats_register(struct rkisp1_device *rkisp1) node->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); if (ret) - goto err_mutex_destroy; + goto error; ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(&vdev->dev, "failed to register %s, ret=%d\n", vdev->name, ret); - goto err_cleanup_media_entity; + goto error; } return 0; -err_cleanup_media_entity: +error: media_entity_cleanup(&vdev->entity); -err_mutex_destroy: mutex_destroy(&node->vlock); + stats->rkisp1 = NULL; return ret; } @@ -487,6 +487,9 @@ void rkisp1_stats_unregister(struct rkisp1_device *rkisp1) struct rkisp1_vdev_node *node = &stats->vnode; struct video_device *vdev = &node->vdev; + if (!stats->rkisp1) + return; + vb2_video_unregister_device(vdev); media_entity_cleanup(&vdev->entity); mutex_destroy(&node->vlock); diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c index e3559b047092..b147c645ae0b 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c @@ -339,8 +339,7 @@ static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_ void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm) { - u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len; - f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0; + u32 f_chk_addr, f_chk_len, s_chk_addr = 0, s_chk_len = 0; f_chk_addr = frm->addr.y; f_chk_len = frm->payload[0]; diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h index e894e85e84a4..1ea5fa1bf3c8 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h @@ -222,7 +222,7 @@ struct gsc_m2m_device { * @org_scaler_input_w: max pixel width when the scaler is enabled * @org_scaler_input_h: max pixel height when the scaler is enabled * @real_rot_dis_w: max pixel src cropped height with the rotator is off - * @real_rot_dis_h: max pixel src croppped width with the rotator is off + * @real_rot_dis_h: max pixel src cropped width with the rotator is off * @real_rot_en_w: max pixel src cropped width with the rotator is on * @real_rot_en_h: max pixel src cropped height with the rotator is on * @target_rot_dis_w: max pixel dst scaled width with the rotator is off diff --git a/drivers/media/platform/samsung/exynos4-is/common.c b/drivers/media/platform/samsung/exynos4-is/common.c index 26ee2388edfd..e41333535eac 100644 --- a/drivers/media/platform/samsung/exynos4-is/common.c +++ b/drivers/media/platform/samsung/exynos4-is/common.c @@ -21,7 +21,7 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity) while (pad->flags & MEDIA_PAD_FL_SINK) { /* source pad */ - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index 7ff4024003f4..03638c8f772d 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -737,7 +737,7 @@ static struct media_entity *fimc_pipeline_get_head(struct media_entity *me) struct media_pad *pad = &me->pads[0]; while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) { - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad) break; me = pad->entity; @@ -810,7 +810,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, return ret; } - pad = media_entity_remote_pad(&me->pads[sfmt.pad]); + pad = media_pad_remote_pad_first(&me->pads[sfmt.pad]); if (!pad) return -EINVAL; me = pad->entity; @@ -1115,7 +1115,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) if (p->flags & MEDIA_PAD_FL_SINK) { sink_pad = p; - src_pad = media_entity_remote_pad(sink_pad); + src_pad = media_pad_remote_pad_first(sink_pad); if (src_pad) break; } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h index da36b48b8f9f..9dcbb9853ac0 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h @@ -116,7 +116,7 @@ enum fimc_is_error { ERROR_COMMON_PARAMETER = 2, /* Invalid parameter */ /* setfile is not loaded before adjusting */ ERROR_COMMON_SETFILE_LOAD = 3, - /* setfile is not Adjusted before runnng. */ + /* setfile is not Adjusted before running. */ ERROR_COMMON_SETFILE_ADJUST = 4, /* Index of setfile is not valid (0~MAX_SETFILE_NUM-1) */ ERROR_COMMON_SETFILE_INDEX = 5, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c index 83688a7982f7..8f12240b0eb7 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c @@ -465,7 +465,7 @@ static int isp_video_pipeline_validate(struct fimc_isp *isp) return -EPIPE; /* Retrieve format at the source pad */ - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 1a396b7cd9a9..41b0a4a5929a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -789,7 +789,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc) return -EPIPE; } /* Retrieve format at the source pad */ - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c index 544b54e428c9..52b43ea04030 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.c +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c @@ -81,7 +81,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_pad *spad = &me->pads[i]; if (!(spad->flags & MEDIA_PAD_FL_SINK)) continue; - pad = media_entity_remote_pad(spad); + pad = media_pad_remote_pad_first(spad); if (pad) break; } diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c index 27a214936cb0..6a0d35f33e8c 100644 --- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c @@ -124,7 +124,7 @@ static char *csi_clock_name[] = { #define DEFAULT_SCLK_CSIS_FREQ 166000000UL static const char * const csis_supply_name[] = { - "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ + "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) supply */ "vddio", /* CSIS I/O and PLL (1.8V) supply */ }; #define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index 140854ab4dd8..c2d8f1e425d8 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -811,7 +811,7 @@ static int camif_pipeline_validate(struct camif_dev *camif) int ret; /* Retrieve format at the sensor subdev source pad */ - pad = media_entity_remote_pad(&camif->pads[0]); + pad = media_pad_remote_pad_first(&camif->pads[0]); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) return -EPIPE; diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index 456287186ad8..55814041b8d8 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -1709,7 +1709,7 @@ static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx, w_ratio = ctx->out_q.w / r->width; h_ratio = ctx->out_q.h / r->height; - scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio; + scale_factor = max(w_ratio, h_ratio); scale_factor = clamp_val(scale_factor, 1, 8); /* Align scale ratio to the nearest power of 2 */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c index 72a901e99450..187849841a28 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c @@ -88,7 +88,6 @@ int s5p_mfc_power_on(void) if (ret < 0) { mfc_err("clock prepare failed for clock: %s\n", pm->clk_names[i]); - i++; goto err; } } @@ -98,7 +97,7 @@ int s5p_mfc_power_on(void) return 0; err: - while (--i > 0) + while (--i >= 0) clk_disable_unprepare(pm->clocks[i]); pm_runtime_put(pm->device); return ret; diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index 7bb1384e4bad..cefe6b7bfdc4 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -107,7 +107,7 @@ static void channel_swdemux_tsklet(struct tasklet_struct *t) size, DMA_FROM_DEVICE); - buf = (u8 *) channel->back_buffer_aligned; + buf = channel->back_buffer_aligned; dev_dbg(fei->dev, "chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\trp=0x%lx, wp=0x%lx\n", @@ -176,7 +176,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) channel = fei->channel_data[stdemux->tsin_index]; - bitmap = (unsigned long *) channel->pid_buffer_aligned; + bitmap = channel->pid_buffer_aligned; /* 8192 is a special PID */ if (dvbdmxfeed->pid == 8192) { @@ -272,7 +272,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed) channel = fei->channel_data[stdemux->tsin_index]; - bitmap = (unsigned long *) channel->pid_buffer_aligned; + bitmap = channel->pid_buffer_aligned; if (dvbdmxfeed->pid == 8192) { tmp = readl(fei->io + C8SECTPFE_IB_PID_SET(channel->tsin_id)); @@ -333,8 +333,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed) __func__, __LINE__, stdemux, channel->tsin_id); /* turn off all PIDS in the bitmap */ - memset((void *)channel->pid_buffer_aligned - , 0x00, PID_TABLE_SIZE); + memset(channel->pid_buffer_aligned, 0, PID_TABLE_SIZE); /* manage cache so data is visible to HW */ dma_sync_single_for_device(fei->dev, @@ -458,23 +457,19 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, init_completion(&tsin->idle_completion); - tsin->back_buffer_start = kzalloc(FEI_BUFFER_SIZE + - FEI_ALIGNMENT, GFP_KERNEL); - + tsin->back_buffer_start = kzalloc(FEI_BUFFER_SIZE + FEI_ALIGNMENT, GFP_KERNEL); if (!tsin->back_buffer_start) { ret = -ENOMEM; goto err_unmap; } /* Ensure backbuffer is 32byte aligned */ - tsin->back_buffer_aligned = tsin->back_buffer_start - + FEI_ALIGNMENT; + tsin->back_buffer_aligned = tsin->back_buffer_start + FEI_ALIGNMENT; - tsin->back_buffer_aligned = (void *) - (((uintptr_t) tsin->back_buffer_aligned) & ~0x1F); + tsin->back_buffer_aligned = PTR_ALIGN(tsin->back_buffer_aligned, FEI_ALIGNMENT); tsin->back_buffer_busaddr = dma_map_single(fei->dev, - (void *)tsin->back_buffer_aligned, + tsin->back_buffer_aligned, FEI_BUFFER_SIZE, DMA_BIDIRECTIONAL); @@ -489,8 +484,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, * per pid. By powers of deduction we conclude stih407 family * is configured (at SoC design stage) for bit per pid. */ - tsin->pid_buffer_start = kzalloc(2048, GFP_KERNEL); - + tsin->pid_buffer_start = kzalloc(PID_TABLE_SIZE + PID_TABLE_SIZE, GFP_KERNEL); if (!tsin->pid_buffer_start) { ret = -ENOMEM; goto err_unmap; @@ -503,11 +497,9 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, * the register. */ - tsin->pid_buffer_aligned = tsin->pid_buffer_start + - PID_TABLE_SIZE; + tsin->pid_buffer_aligned = tsin->pid_buffer_start + PID_TABLE_SIZE; - tsin->pid_buffer_aligned = (void *) - (((uintptr_t) tsin->pid_buffer_aligned) & ~0x3ff); + tsin->pid_buffer_aligned = PTR_ALIGN(tsin->pid_buffer_aligned, PID_TABLE_SIZE); tsin->pid_buffer_busaddr = dma_map_single(fei->dev, tsin->pid_buffer_aligned, @@ -915,8 +907,7 @@ static int c8sectpfe_remove(struct platform_device *pdev) if (readl(fei->io + SYS_OTHER_CLKEN)) writel(0, fei->io + SYS_OTHER_CLKEN); - if (fei->c8sectpfeclk) - clk_disable_unprepare(fei->c8sectpfeclk); + clk_disable_unprepare(fei->c8sectpfeclk); return 0; } diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index 420ad4d8df5d..03eaee6d15da 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1669,14 +1669,12 @@ static int delta_open(struct file *file) set_default_params(ctx); /* enable ST231 clocks */ - if (delta->clk_st231) - if (clk_prepare_enable(delta->clk_st231)) - dev_warn(delta->dev, "failed to enable st231 clk\n"); + if (clk_prepare_enable(delta->clk_st231)) + dev_warn(delta->dev, "failed to enable st231 clk\n"); /* enable FLASH_PROMIP clock */ - if (delta->clk_flash_promip) - if (clk_prepare_enable(delta->clk_flash_promip)) - dev_warn(delta->dev, "failed to enable delta promip clk\n"); + if (clk_prepare_enable(delta->clk_flash_promip)) + dev_warn(delta->dev, "failed to enable delta promip clk\n"); mutex_unlock(&delta->lock); @@ -1717,12 +1715,10 @@ static int delta_release(struct file *file) v4l2_fh_exit(&ctx->fh); /* disable ST231 clocks */ - if (delta->clk_st231) - clk_disable_unprepare(delta->clk_st231); + clk_disable_unprepare(delta->clk_st231); /* disable FLASH_PROMIP clock */ - if (delta->clk_flash_promip) - clk_disable_unprepare(delta->clk_flash_promip); + clk_disable_unprepare(delta->clk_flash_promip); dev_dbg(delta->dev, "%s decoder instance released\n", ctx->name); @@ -1926,8 +1922,7 @@ static int delta_runtime_suspend(struct device *dev) { struct delta_dev *delta = dev_get_drvdata(dev); - if (delta->clk_delta) - clk_disable_unprepare(delta->clk_delta); + clk_disable_unprepare(delta->clk_delta); return 0; } @@ -1936,9 +1931,8 @@ static int delta_runtime_resume(struct device *dev) { struct delta_dev *delta = dev_get_drvdata(dev); - if (delta->clk_delta) - if (clk_prepare_enable(delta->clk_delta)) - dev_warn(dev, "failed to prepare/enable delta clk\n"); + if (clk_prepare_enable(delta->clk_delta)) + dev_warn(dev, "failed to prepare/enable delta clk\n"); return 0; } diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index 09a743cd7004..2ca95ab2b0fe 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -611,7 +611,7 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -622,7 +622,6 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) } static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, - struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct media_entity *entity = &dcmi->source->entity; @@ -664,7 +663,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, format->format.width, format->format.height); fmt.pad = pad->index; - ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt); + ret = v4l2_subdev_call(subdev, pad, set_fmt, NULL, &fmt); if (ret < 0) { dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n", __func__, format->format.code, @@ -682,7 +681,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, } /* Walk to next entity */ - sink_pad = media_entity_remote_pad(src_pad); + sink_pad = media_pad_remote_pad_first(src_pad); if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity)) break; @@ -706,7 +705,7 @@ static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -999,10 +998,6 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, const struct dcmi_format *sd_fmt; struct dcmi_framesize sd_fsize; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_state pad_state = { - .pads = &pad_cfg - }; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -1037,8 +1032,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, } v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); - ret = v4l2_subdev_call(dcmi->source, pad, set_fmt, - &pad_state, &format); + ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format); if (ret < 0) return ret; @@ -1115,7 +1109,7 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) mf->width = sd_framesize.width; mf->height = sd_framesize.height; - ret = dcmi_pipeline_s_fmt(dcmi, NULL, &format); + ret = dcmi_pipeline_s_fmt(dcmi, &format); if (ret < 0) return ret; @@ -1187,10 +1181,6 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_state pad_state = { - .pads = &pad_cfg - }; int ret; sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); @@ -1203,8 +1193,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, } v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); - ret = v4l2_subdev_call(dcmi->source, pad, set_fmt, - &pad_state, &format); + ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format); if (ret < 0) return ret; @@ -1592,26 +1581,32 @@ static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi) return 0; } -/* - * FIXME: For the time being we only support subdevices - * which expose RGB & YUV "parallel form" mbus code (_2X8). - * Nevertheless, this allows to support serial source subdevices - * and serial to parallel bridges which conform to this. - */ static const struct dcmi_format dcmi_formats[] = { { .fourcc = V4L2_PIX_FMT_RGB565, .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .bpp = 2, }, { + .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_1X16, + .bpp = 2, + }, { .fourcc = V4L2_PIX_FMT_YUYV, .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 2, }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .bpp = 2, + }, { .fourcc = V4L2_PIX_FMT_UYVY, .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 2, }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .bpp = 2, + }, { .fourcc = V4L2_PIX_FMT_JPEG, .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, .bpp = 1, @@ -1631,6 +1626,54 @@ static const struct dcmi_format dcmi_formats[] = { .fourcc = V4L2_PIX_FMT_SRGGB8, .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14, + .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14, + .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14, + .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14, + .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB14, + .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14, + .bpp = 2, }, }; diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig index 46b7b9bf989c..2dd15083a1d9 100644 --- a/drivers/media/platform/sunxi/Kconfig +++ b/drivers/media/platform/sunxi/Kconfig @@ -4,5 +4,7 @@ comment "Sunxi media platform drivers" source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" +source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig" +source "drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig" source "drivers/media/platform/sunxi/sun8i-di/Kconfig" source "drivers/media/platform/sunxi/sun8i-rotate/Kconfig" diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile index fc537c9f5ca9..9aa01cb01883 100644 --- a/drivers/media/platform/sunxi/Makefile +++ b/drivers/media/platform/sunxi/Makefile @@ -2,5 +2,7 @@ obj-y += sun4i-csi/ obj-y += sun6i-csi/ +obj-y += sun6i-mipi-csi2/ +obj-y += sun8i-a83t-mipi-csi2/ obj-y += sun8i-di/ obj-y += sun8i-rotate/ diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 682c26536034..1d46e113d01d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -77,7 +77,7 @@ sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_pad_remote_pad_first(&video->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -560,7 +560,7 @@ static int sun6i_video_link_validate(struct media_link *link) video->mbus_code = 0; - if (!media_entity_remote_pad(link->sink->entity->pads)) { + if (!media_pad_remote_pad_first(link->sink->entity->pads)) { dev_info(video->csi->dev, "video node %s pad not connected\n", vdev->name); return -ENOLINK; diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig new file mode 100644 index 000000000000..eb982466abd3 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_SUN6I_MIPI_CSI2 + tristate "Allwinner A31 MIPI CSI-2 Controller Driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV + depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + select PHY_SUN6I_MIPI_DPHY + select GENERIC_PHY_MIPI_DPHY + select REGMAP_MMIO + help + Support for the Allwinner A31 MIPI CSI-2 controller, also found on + other platforms such as the V3/V3s. diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile new file mode 100644 index 000000000000..14e4e03818b5 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +sun6i-mipi-csi2-y += sun6i_mipi_csi2.o + +obj-$(CONFIG_VIDEO_SUN6I_MIPI_CSI2) += sun6i-mipi-csi2.o diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c new file mode 100644 index 000000000000..a4e3f9a6b2ff --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -0,0 +1,750 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/mipi-csi2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#include "sun6i_mipi_csi2.h" +#include "sun6i_mipi_csi2_reg.h" + +/* Format */ + +static const struct sun6i_mipi_csi2_format sun6i_mipi_csi2_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, +}; + +static const struct sun6i_mipi_csi2_format * +sun6i_mipi_csi2_format_find(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sun6i_mipi_csi2_formats); i++) + if (sun6i_mipi_csi2_formats[i].mbus_code == mbus_code) + return &sun6i_mipi_csi2_formats[i]; + + return NULL; +} + +/* Controller */ + +static void sun6i_mipi_csi2_enable(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_EN, SUN6I_MIPI_CSI2_CTL_EN); +} + +static void sun6i_mipi_csi2_disable(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_EN, 0); +} + +static void sun6i_mipi_csi2_configure(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun6i_mipi_csi2_format *format; + struct device *dev = csi2_dev->dev; + u32 version = 0; + + format = sun6i_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) + return; + + /* + * The enable flow in the Allwinner BSP is a bit different: the enable + * and reset bits are set together before starting the CSI controller. + * + * In mainline we enable the CSI controller first (due to subdev logic). + * One reliable way to make this work is to deassert reset, configure + * registers and enable the controller when everything's ready. + * + * However, setting the version enable bit and removing it afterwards + * appears necessary for capture to work reliably, while replacing it + * with a delay doesn't do the trick. + */ + regmap_write(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_RESET_N | + SUN6I_MIPI_CSI2_CTL_VERSION_EN | + SUN6I_MIPI_CSI2_CTL_UNPK_EN); + + regmap_read(regmap, SUN6I_MIPI_CSI2_VERSION_REG, &version); + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_VERSION_EN, 0); + + dev_dbg(dev, "A31 MIPI CSI-2 version: %04x\n", version); + + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); + + /* + * Only a single virtual channel (index 0) is currently supported. + * While the registers do mention multiple physical channels being + * available (which can be configured to match a specific virtual + * channel or data type), it's unclear whether channels > 0 are actually + * connected and available and the reference source code only makes use + * of channel 0. + * + * Using extra channels would also require matching channels to be + * available on the CSI (and ISP) side, which is also unsure although + * some CSI implementations are said to support multiple channels for + * BT656 time-sharing. + * + * We still configure virtual channel numbers to ensure that virtual + * channel 0 only goes to channel 0. + */ + + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, format->data_type)); + + regmap_write(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, + SUN6I_MIPI_CSI2_CH_INT_PD_CLEAR); +} + +/* V4L2 Subdev */ + +static int sun6i_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + struct v4l2_subdev *source_subdev = csi2_dev->bridge.source_subdev; + union phy_configure_opts dphy_opts = { 0 }; + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun6i_mipi_csi2_format *format; + struct phy *dphy = csi2_dev->dphy; + struct device *dev = csi2_dev->dev; + struct v4l2_ctrl *ctrl; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + unsigned long pixel_rate; + int ret; + + if (!source_subdev) + return -ENODEV; + + if (!on) { + ret = v4l2_subdev_call(source_subdev, video, s_stream, 0); + goto disable; + } + + /* Runtime PM */ + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + /* Sensor Pixel Rate */ + + ctrl = v4l2_ctrl_find(source_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_err(dev, "missing sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); + if (!pixel_rate) { + dev_err(dev, "missing (zero) sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + /* D-PHY */ + + if (!lanes_count) { + dev_err(dev, "missing (zero) MIPI CSI-2 lanes count\n"); + ret = -ENODEV; + goto error_pm; + } + + format = sun6i_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) { + ret = -ENODEV; + goto error_pm; + } + + phy_mipi_dphy_get_default_config(pixel_rate, format->bpp, lanes_count, + dphy_cfg); + + /* + * Note that our hardware is using DDR, which is not taken in account by + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from + * the pixel rate, lanes count and bpp. + * + * The resulting clock rate is basically the symbol rate over the whole + * link. The actual clock rate is calculated with division by two since + * DDR samples both on rising and falling edges. + */ + + dev_dbg(dev, "A31 MIPI CSI-2 config:\n"); + dev_dbg(dev, "%ld pixels/s, %u bits/pixel, %u lanes, %lu Hz clock\n", + pixel_rate, format->bpp, lanes_count, + dphy_cfg->hs_clk_rate / 2); + + ret = phy_reset(dphy); + if (ret) { + dev_err(dev, "failed to reset MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_configure(dphy, &dphy_opts); + if (ret) { + dev_err(dev, "failed to configure MIPI D-PHY\n"); + goto error_pm; + } + + /* Controller */ + + sun6i_mipi_csi2_configure(csi2_dev); + sun6i_mipi_csi2_enable(csi2_dev); + + /* D-PHY */ + + ret = phy_power_on(dphy); + if (ret) { + dev_err(dev, "failed to power on MIPI D-PHY\n"); + goto error_pm; + } + + /* Source */ + + ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) + goto disable; + + return 0; + +disable: + if (!on) + ret = 0; + phy_power_off(dphy); + sun6i_mipi_csi2_disable(csi2_dev); + +error_pm: + pm_runtime_put(dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops sun6i_mipi_csi2_video_ops = { + .s_stream = sun6i_mipi_csi2_s_stream, +}; + +static void +sun6i_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) +{ + if (!sun6i_mipi_csi2_format_find(mbus_format->code)) + mbus_format->code = sun6i_mipi_csi2_formats[0].mbus_code; + + mbus_format->field = V4L2_FIELD_NONE; + mbus_format->colorspace = V4L2_COLORSPACE_RAW; + mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT; + mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int sun6i_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + unsigned int pad = SUN6I_MIPI_CSI2_PAD_SINK; + struct v4l2_mbus_framefmt *mbus_format = + v4l2_subdev_get_try_format(subdev, state, pad); + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + mbus_format->code = sun6i_mipi_csi2_formats[0].mbus_code; + mbus_format->width = 640; + mbus_format->height = 480; + + sun6i_mipi_csi2_mbus_format_prepare(mbus_format); + + mutex_unlock(lock); + + return 0; +} + +static int +sun6i_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(sun6i_mipi_csi2_formats)) + return -EINVAL; + + code_enum->code = sun6i_mipi_csi2_formats[code_enum->index].mbus_code; + + return 0; +} + +static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *mbus_format = *v4l2_subdev_get_try_format(subdev, state, + format->pad); + else + *mbus_format = csi2_dev->bridge.mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + sun6i_mipi_csi2_mbus_format_prepare(mbus_format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *mbus_format; + else + csi2_dev->bridge.mbus_format = *mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_pad_ops = { + .init_cfg = sun6i_mipi_csi2_init_cfg, + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, + .get_fmt = sun6i_mipi_csi2_get_fmt, + .set_fmt = sun6i_mipi_csi2_set_fmt, +}; + +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { + .video = &sun6i_mipi_csi2_video_ops, + .pad = &sun6i_mipi_csi2_pad_ops, +}; + +/* Media Entity */ + +static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* V4L2 Async */ + +static int +sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *remote_subdev, + struct v4l2_async_subdev *async_subdev) +{ + struct v4l2_subdev *subdev = notifier->sd; + struct sun6i_mipi_csi2_device *csi2_dev = + container_of(notifier, struct sun6i_mipi_csi2_device, + bridge.notifier); + struct media_entity *sink_entity = &subdev->entity; + struct media_entity *source_entity = &remote_subdev->entity; + struct device *dev = csi2_dev->dev; + int sink_pad_index = 0; + int source_pad_index; + int ret; + + ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (ret < 0) { + dev_err(dev, "missing source pad in external entity %s\n", + source_entity->name); + return -EINVAL; + } + + source_pad_index = ret; + + dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name, + source_pad_index, sink_entity->name, sink_pad_index); + + ret = media_create_pad_link(source_entity, source_pad_index, + sink_entity, sink_pad_index, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(dev, "failed to create %s:%u -> %s:%u link\n", + source_entity->name, source_pad_index, + sink_entity->name, sink_pad_index); + return ret; + } + + csi2_dev->bridge.source_subdev = remote_subdev; + + return 0; +} + +static const struct v4l2_async_notifier_operations +sun6i_mipi_csi2_notifier_ops = { + .bound = sun6i_mipi_csi2_notifier_bound, +}; + +/* Bridge */ + +static int +sun6i_mipi_csi2_bridge_source_setup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint; + struct v4l2_async_subdev *subdev_async; + struct fwnode_handle *handle; + struct device *dev = csi2_dev->dev; + int ret; + + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!handle) + return -ENODEV; + + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); + if (ret) + goto complete; + + subdev_async = + v4l2_async_nf_add_fwnode_remote(notifier, handle, + struct v4l2_async_subdev); + if (IS_ERR(subdev_async)) + ret = PTR_ERR(subdev_async); + +complete: + fwnode_handle_put(handle); + + return ret; +} + +static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct sun6i_mipi_csi2_bridge *bridge = &csi2_dev->bridge; + struct v4l2_subdev *subdev = &bridge->subdev; + struct v4l2_async_notifier *notifier = &bridge->notifier; + struct media_pad *pads = bridge->pads; + struct device *dev = csi2_dev->dev; + int ret; + + mutex_init(&bridge->lock); + + /* V4L2 Subdev */ + + v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops); + strscpy(subdev->name, SUN6I_MIPI_CSI2_NAME, sizeof(subdev->name)); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->owner = THIS_MODULE; + subdev->dev = dev; + + v4l2_set_subdevdata(subdev, csi2_dev); + + /* Media Entity */ + + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->entity.ops = &sun6i_mipi_csi2_entity_ops; + + /* Media Pads */ + + pads[SUN6I_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[SUN6I_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, SUN6I_MIPI_CSI2_PAD_COUNT, + pads); + if (ret) + return ret; + + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun6i_mipi_csi2_notifier_ops; + + ret = sun6i_mipi_csi2_bridge_source_setup(csi2_dev); + if (ret) + goto error_v4l2_notifier_cleanup; + + ret = v4l2_async_subdev_nf_register(subdev, notifier); + if (ret < 0) + goto error_v4l2_notifier_cleanup; + + /* V4L2 Subdev */ + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) + goto error_v4l2_notifier_unregister; + + return 0; + +error_v4l2_notifier_unregister: + v4l2_async_nf_unregister(notifier); + +error_v4l2_notifier_cleanup: + v4l2_async_nf_cleanup(notifier); + + media_entity_cleanup(&subdev->entity); + + return ret; +} + +static void +sun6i_mipi_csi2_bridge_cleanup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + struct v4l2_subdev *subdev = &csi2_dev->bridge.subdev; + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + + v4l2_async_unregister_subdev(subdev); + v4l2_async_nf_unregister(notifier); + v4l2_async_nf_cleanup(notifier); + media_entity_cleanup(&subdev->entity); +} + +/* Platform */ + +static int sun6i_mipi_csi2_suspend(struct device *dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + + clk_disable_unprepare(csi2_dev->clock_mod); + reset_control_assert(csi2_dev->reset); + + return 0; +} + +static int sun6i_mipi_csi2_resume(struct device *dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi2_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi2_dev->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + return 0; + +error_reset: + reset_control_assert(csi2_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun6i_mipi_csi2_pm_ops = { + .runtime_suspend = sun6i_mipi_csi2_suspend, + .runtime_resume = sun6i_mipi_csi2_resume, +}; + +static const struct regmap_config sun6i_mipi_csi2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x400, +}; + +static int +sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, + struct platform_device *platform_dev) +{ + struct device *dev = csi2_dev->dev; + void __iomem *io_base; + int ret; + + /* Registers */ + + io_base = devm_platform_ioremap_resource(platform_dev, 0); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + csi2_dev->regmap = + devm_regmap_init_mmio_clk(dev, "bus", io_base, + &sun6i_mipi_csi2_regmap_config); + if (IS_ERR(csi2_dev->regmap)) { + dev_err(dev, "failed to init register map\n"); + return PTR_ERR(csi2_dev->regmap); + } + + /* Clock */ + + csi2_dev->clock_mod = devm_clk_get(dev, "mod"); + if (IS_ERR(csi2_dev->clock_mod)) { + dev_err(dev, "failed to acquire mod clock\n"); + return PTR_ERR(csi2_dev->clock_mod); + } + + ret = clk_set_rate_exclusive(csi2_dev->clock_mod, 297000000); + if (ret) { + dev_err(dev, "failed to set mod clock rate\n"); + return ret; + } + + /* Reset */ + + csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(csi2_dev->reset)) { + dev_err(dev, "failed to get reset controller\n"); + return PTR_ERR(csi2_dev->reset); + } + + /* D-PHY */ + + csi2_dev->dphy = devm_phy_get(dev, "dphy"); + if (IS_ERR(csi2_dev->dphy)) { + dev_err(dev, "failed to get MIPI D-PHY\n"); + return PTR_ERR(csi2_dev->dphy); + } + + ret = phy_init(csi2_dev->dphy); + if (ret) { + dev_err(dev, "failed to initialize MIPI D-PHY\n"); + return ret; + } + + /* Runtime PM */ + + pm_runtime_enable(dev); + + return 0; +} + +static void +sun6i_mipi_csi2_resources_cleanup(struct sun6i_mipi_csi2_device *csi2_dev) +{ + pm_runtime_disable(csi2_dev->dev); + phy_exit(csi2_dev->dphy); + clk_rate_exclusive_put(csi2_dev->clock_mod); +} + +static int sun6i_mipi_csi2_probe(struct platform_device *platform_dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev; + struct device *dev = &platform_dev->dev; + int ret; + + csi2_dev = devm_kzalloc(dev, sizeof(*csi2_dev), GFP_KERNEL); + if (!csi2_dev) + return -ENOMEM; + + csi2_dev->dev = dev; + platform_set_drvdata(platform_dev, csi2_dev); + + ret = sun6i_mipi_csi2_resources_setup(csi2_dev, platform_dev); + if (ret) + return ret; + + ret = sun6i_mipi_csi2_bridge_setup(csi2_dev); + if (ret) + return ret; + + return 0; +} + +static int sun6i_mipi_csi2_remove(struct platform_device *platform_dev) +{ + struct sun6i_mipi_csi2_device *csi2_dev = + platform_get_drvdata(platform_dev); + + sun6i_mipi_csi2_bridge_cleanup(csi2_dev); + sun6i_mipi_csi2_resources_cleanup(csi2_dev); + + return 0; +} + +static const struct of_device_id sun6i_mipi_csi2_of_match[] = { + { .compatible = "allwinner,sun6i-a31-mipi-csi2" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); + +static struct platform_driver sun6i_mipi_csi2_platform_driver = { + .probe = sun6i_mipi_csi2_probe, + .remove = sun6i_mipi_csi2_remove, + .driver = { + .name = SUN6I_MIPI_CSI2_NAME, + .of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match), + .pm = &sun6i_mipi_csi2_pm_ops, + }, +}; +module_platform_driver(sun6i_mipi_csi2_platform_driver); + +MODULE_DESCRIPTION("Allwinner A31 MIPI CSI-2 Controller Driver"); +MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h new file mode 100644 index 000000000000..24b15e34b5e8 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN6I_MIPI_CSI2_H_ +#define _SUN6I_MIPI_CSI2_H_ + +#include <linux/phy/phy.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define SUN6I_MIPI_CSI2_NAME "sun6i-mipi-csi2" + +enum sun6i_mipi_csi2_pad { + SUN6I_MIPI_CSI2_PAD_SINK = 0, + SUN6I_MIPI_CSI2_PAD_SOURCE = 1, + SUN6I_MIPI_CSI2_PAD_COUNT = 2, +}; + +struct sun6i_mipi_csi2_format { + u32 mbus_code; + u8 data_type; + u32 bpp; +}; + +struct sun6i_mipi_csi2_bridge { + struct v4l2_subdev subdev; + struct media_pad pads[SUN6I_MIPI_CSI2_PAD_COUNT]; + struct v4l2_fwnode_endpoint endpoint; + struct v4l2_async_notifier notifier; + struct v4l2_mbus_framefmt mbus_format; + struct mutex lock; /* Mbus format lock. */ + + struct v4l2_subdev *source_subdev; +}; + +struct sun6i_mipi_csi2_device { + struct device *dev; + + struct regmap *regmap; + struct clk *clock_mod; + struct reset_control *reset; + struct phy *dphy; + + struct sun6i_mipi_csi2_bridge bridge; +}; + +#endif diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h new file mode 100644 index 000000000000..d9c92cf2b038 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN6I_MIPI_CSI2_REG_H_ +#define _SUN6I_MIPI_CSI2_REG_H_ + +#define SUN6I_MIPI_CSI2_CTL_REG 0x0 +#define SUN6I_MIPI_CSI2_CTL_RESET_N BIT(31) +#define SUN6I_MIPI_CSI2_CTL_VERSION_EN BIT(30) +#define SUN6I_MIPI_CSI2_CTL_UNPK_EN BIT(1) +#define SUN6I_MIPI_CSI2_CTL_EN BIT(0) + +#define SUN6I_MIPI_CSI2_CFG_REG 0x4 +#define SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(v) ((((v) - 1) << 8) & \ + GENMASK(9, 8)) +#define SUN6I_MIPI_CSI2_CFG_LANE_COUNT(v) (((v) - 1) & GENMASK(1, 0)) + +#define SUN6I_MIPI_CSI2_VCDT_RX_REG 0x8 +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + ((ch) * 8 + 6)) +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + ((ch) * 8)) +#define SUN6I_MIPI_CSI2_RX_PKT_NUM_REG 0xc + +#define SUN6I_MIPI_CSI2_VERSION_REG 0x3c + +#define SUN6I_MIPI_CSI2_CH_CFG_REG 0x40 +#define SUN6I_MIPI_CSI2_CH_INT_EN_REG 0x50 +#define SUN6I_MIPI_CSI2_CH_INT_EN_EOT_ERR BIT(29) +#define SUN6I_MIPI_CSI2_CH_INT_EN_CHKSUM_ERR BIT(28) +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_WRN BIT(27) +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_ERR BIT(26) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_SYNC_ERR BIT(25) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_SYNC_ERR BIT(24) +#define SUN6I_MIPI_CSI2_CH_INT_EN_EMB_DATA BIT(18) +#define SUN6I_MIPI_CSI2_CH_INT_EN_PF BIT(17) +#define SUN6I_MIPI_CSI2_CH_INT_EN_PH_UPDATE BIT(16) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_START_SYNC BIT(11) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_END_SYNC BIT(10) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_START_SYNC BIT(9) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_END_SYNC BIT(8) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FIFO_OVER BIT(0) + +#define SUN6I_MIPI_CSI2_CH_INT_PD_REG 0x58 +#define SUN6I_MIPI_CSI2_CH_INT_PD_CLEAR 0xff +#define SUN6I_MIPI_CSI2_CH_INT_PD_EOT_ERR BIT(29) +#define SUN6I_MIPI_CSI2_CH_INT_PD_CHKSUM_ERR BIT(28) +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_WRN BIT(27) +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_ERR BIT(26) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_SYNC_ERR BIT(25) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_SYNC_ERR BIT(24) +#define SUN6I_MIPI_CSI2_CH_INT_PD_EMB_DATA BIT(18) +#define SUN6I_MIPI_CSI2_CH_INT_PD_PF BIT(17) +#define SUN6I_MIPI_CSI2_CH_INT_PD_PH_UPDATE BIT(16) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_START_SYNC BIT(11) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_END_SYNC BIT(10) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_START_SYNC BIT(9) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_END_SYNC BIT(8) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FIFO_OVER BIT(0) + +#define SUN6I_MIPI_CSI2_CH_DT_TRIGGER_REG 0x60 +#define SUN6I_MIPI_CSI2_CH_CUR_PH_REG 0x70 +#define SUN6I_MIPI_CSI2_CH_ECC_REG 0x74 +#define SUN6I_MIPI_CSI2_CH_CKS_REG 0x78 +#define SUN6I_MIPI_CSI2_CH_FRAME_NUM_REG 0x7c +#define SUN6I_MIPI_CSI2_CH_LINE_NUM_REG 0x80 + +#define SUN6I_MIPI_CSI2_CH_OFFSET 0x100 + +#define SUN6I_MIPI_CSI2_CH_REG(reg, ch) \ + (SUN6I_MIPI_CSI2_CH_OFFSET * (ch) + (reg)) + +#endif diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig new file mode 100644 index 000000000000..789d58ee12ea --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_SUN8I_A83T_MIPI_CSI2 + tristate "Allwinner A83T MIPI CSI-2 Controller and D-PHY Driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV + depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + select REGMAP_MMIO + select GENERIC_PHY_MIPI_DPHY + help + Support for the Allwinner A83T MIPI CSI-2 controller and D-PHY. diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile new file mode 100644 index 000000000000..1427d15a879a --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +sun8i-a83t-mipi-csi2-y += sun8i_a83t_mipi_csi2.o sun8i_a83t_dphy.o + +obj-$(CONFIG_VIDEO_SUN8I_A83T_MIPI_CSI2) += sun8i-a83t-mipi-csi2.o diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c new file mode 100644 index 000000000000..24bbcc85013d --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#include <linux/phy/phy.h> +#include <linux/regmap.h> + +#include "sun8i_a83t_dphy.h" +#include "sun8i_a83t_mipi_csi2.h" + +static int sun8i_a83t_dphy_configure(struct phy *dphy, + union phy_configure_opts *opts) +{ + return phy_mipi_dphy_config_validate(&opts->mipi_dphy); +} + +static int sun8i_a83t_dphy_power_on(struct phy *dphy) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy); + struct regmap *regmap = csi2_dev->regmap; + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, + SUN8I_A83T_DPHY_CTRL_RESET_N | + SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N); + + regmap_write(regmap, SUN8I_A83T_DPHY_ANA0_REG, + SUN8I_A83T_DPHY_ANA0_REXT_EN | + SUN8I_A83T_DPHY_ANA0_RINT(2) | + SUN8I_A83T_DPHY_ANA0_SNK(2)); + + return 0; +}; + +static int sun8i_a83t_dphy_power_off(struct phy *dphy) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy); + struct regmap *regmap = csi2_dev->regmap; + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0); + + return 0; +}; + +static const struct phy_ops sun8i_a83t_dphy_ops = { + .configure = sun8i_a83t_dphy_configure, + .power_on = sun8i_a83t_dphy_power_on, + .power_off = sun8i_a83t_dphy_power_off, +}; + +int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct device *dev = csi2_dev->dev; + struct phy_provider *phy_provider; + + csi2_dev->dphy = devm_phy_create(dev, NULL, &sun8i_a83t_dphy_ops); + if (IS_ERR(csi2_dev->dphy)) { + dev_err(dev, "failed to create D-PHY\n"); + return PTR_ERR(csi2_dev->dphy); + } + + phy_set_drvdata(csi2_dev->dphy, csi2_dev); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + dev_err(dev, "failed to register D-PHY provider\n"); + return PTR_ERR(phy_provider); + } + + return 0; +} diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h new file mode 100644 index 000000000000..9ab709060770 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN8I_A83T_DPHY_H_ +#define _SUN8I_A83T_DPHY_H_ + +#include "sun8i_a83t_mipi_csi2.h" + +#define SUN8I_A83T_DPHY_CTRL_REG 0x10 +#define SUN8I_A83T_DPHY_CTRL_INIT_VALUE 0xb8df698e +#define SUN8I_A83T_DPHY_CTRL_RESET_N BIT(31) +#define SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N BIT(15) +#define SUN8I_A83T_DPHY_CTRL_DEBUG BIT(8) +#define SUN8I_A83T_DPHY_STATUS_REG 0x14 +#define SUN8I_A83T_DPHY_STATUS_CLK_STOP BIT(10) +#define SUN8I_A83T_DPHY_STATUS_CLK_ULPS BIT(9) +#define SUN8I_A83T_DPHY_STATUS_HSCLK BIT(8) +#define SUN8I_A83T_DPHY_STATUS_D3_STOP BIT(7) +#define SUN8I_A83T_DPHY_STATUS_D2_STOP BIT(6) +#define SUN8I_A83T_DPHY_STATUS_D1_STOP BIT(5) +#define SUN8I_A83T_DPHY_STATUS_D0_STOP BIT(4) +#define SUN8I_A83T_DPHY_STATUS_D3_ULPS BIT(3) +#define SUN8I_A83T_DPHY_STATUS_D2_ULPS BIT(2) +#define SUN8I_A83T_DPHY_STATUS_D1_ULPS BIT(1) +#define SUN8I_A83T_DPHY_STATUS_D0_ULPS BIT(0) + +#define SUN8I_A83T_DPHY_ANA0_REG 0x30 +#define SUN8I_A83T_DPHY_ANA0_REXT_EN BIT(31) +#define SUN8I_A83T_DPHY_ANA0_REXT BIT(30) +#define SUN8I_A83T_DPHY_ANA0_RINT(v) (((v) << 28) & GENMASK(29, 28)) +#define SUN8I_A83T_DPHY_ANA0_SNK(v) (((v) << 20) & GENMASK(22, 20)) + +int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device *csi2_dev); + +#endif diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c new file mode 100644 index 000000000000..d052ee77ef0a --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -0,0 +1,816 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/mipi-csi2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#include "sun8i_a83t_dphy.h" +#include "sun8i_a83t_mipi_csi2.h" +#include "sun8i_a83t_mipi_csi2_reg.h" + +/* Format */ + +static const struct sun8i_a83t_mipi_csi2_format +sun8i_a83t_mipi_csi2_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .data_type = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .data_type = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, +}; + +static const struct sun8i_a83t_mipi_csi2_format * +sun8i_a83t_mipi_csi2_format_find(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sun8i_a83t_mipi_csi2_formats); i++) + if (sun8i_a83t_mipi_csi2_formats[i].mbus_code == mbus_code) + return &sun8i_a83t_mipi_csi2_formats[i]; + + return NULL; +} + +/* Controller */ + +static void +sun8i_a83t_mipi_csi2_init(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + /* + * The Allwinner BSP sets various magic values on a bunch of registers. + * This is apparently a necessary initialization process that will cause + * the capture to fail with unsolicited interrupts hitting if skipped. + * + * Most of the registers are set to proper values later, except for the + * two reserved registers. They are said to hold a "hardware lock" + * value, without more information available. + */ + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, + SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG, + SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0); + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, + SUN8I_A83T_DPHY_CTRL_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG, + SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG, + SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE); +} + +static void +sun8i_a83t_mipi_csi2_enable(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN); +} + +static void +sun8i_a83t_mipi_csi2_disable(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + + regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN, 0); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0); +} + +static void +sun8i_a83t_mipi_csi2_configure(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct regmap *regmap = csi2_dev->regmap; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun8i_a83t_mipi_csi2_format *format; + struct device *dev = csi2_dev->dev; + u32 version = 0; + + format = sun8i_a83t_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) + return; + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, + SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N); + + regmap_read(regmap, SUN8I_A83T_MIPI_CSI2_VERSION_REG, &version); + + dev_dbg(dev, "A83T MIPI CSI-2 version: %04x\n", version); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN | + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(8) | + SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(1) | + SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(lanes_count)); + + /* + * Only a single virtual channel (index 0) is currently supported. + * While the registers do mention multiple physical channels being + * available (which can be configured to match a specific virtual + * channel or data type), it's unclear whether channels > 0 are actually + * connected and available and the reference source code only makes use + * of channel 0. + * + * Using extra channels would also require matching channels to be + * available on the CSI (and ISP) side, which is also unsure although + * some CSI implementations are said to support multiple channels for + * BT656 time-sharing. + * + * We still configure virtual channel numbers to ensure that virtual + * channel 0 only goes to channel 0. + */ + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_VCDT0_REG, + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(3, 3) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(2, 2) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(1, 1) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(0, 0) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(0, format->data_type)); +} + +/* V4L2 Subdev */ + +static int sun8i_a83t_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + struct v4l2_subdev *source_subdev = csi2_dev->bridge.source_subdev; + union phy_configure_opts dphy_opts = { 0 }; + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; + struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format; + const struct sun8i_a83t_mipi_csi2_format *format; + struct phy *dphy = csi2_dev->dphy; + struct device *dev = csi2_dev->dev; + struct v4l2_ctrl *ctrl; + unsigned int lanes_count = + csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes; + unsigned long pixel_rate; + int ret; + + if (!source_subdev) + return -ENODEV; + + if (!on) { + ret = v4l2_subdev_call(source_subdev, video, s_stream, 0); + goto disable; + } + + /* Runtime PM */ + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + /* Sensor pixel rate */ + + ctrl = v4l2_ctrl_find(source_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_err(dev, "missing sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); + if (!pixel_rate) { + dev_err(dev, "missing (zero) sensor pixel rate\n"); + ret = -ENODEV; + goto error_pm; + } + + /* D-PHY */ + + if (!lanes_count) { + dev_err(dev, "missing (zero) MIPI CSI-2 lanes count\n"); + ret = -ENODEV; + goto error_pm; + } + + format = sun8i_a83t_mipi_csi2_format_find(mbus_format->code); + if (WARN_ON(!format)) { + ret = -ENODEV; + goto error_pm; + } + + phy_mipi_dphy_get_default_config(pixel_rate, format->bpp, lanes_count, + dphy_cfg); + + /* + * Note that our hardware is using DDR, which is not taken in account by + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from + * the pixel rate, lanes count and bpp. + * + * The resulting clock rate is basically the symbol rate over the whole + * link. The actual clock rate is calculated with division by two since + * DDR samples both on rising and falling edges. + */ + + dev_dbg(dev, "A83T MIPI CSI-2 config:\n"); + dev_dbg(dev, "%ld pixels/s, %u bits/pixel, %u lanes, %lu Hz clock\n", + pixel_rate, format->bpp, lanes_count, + dphy_cfg->hs_clk_rate / 2); + + ret = phy_reset(dphy); + if (ret) { + dev_err(dev, "failed to reset MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_configure(dphy, &dphy_opts); + if (ret) { + dev_err(dev, "failed to configure MIPI D-PHY\n"); + goto error_pm; + } + + /* Controller */ + + sun8i_a83t_mipi_csi2_configure(csi2_dev); + sun8i_a83t_mipi_csi2_enable(csi2_dev); + + /* D-PHY */ + + ret = phy_power_on(dphy); + if (ret) { + dev_err(dev, "failed to power on MIPI D-PHY\n"); + goto error_pm; + } + + /* Source */ + + ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) + goto disable; + + return 0; + +disable: + if (!on) + ret = 0; + phy_power_off(dphy); + sun8i_a83t_mipi_csi2_disable(csi2_dev); + +error_pm: + pm_runtime_put(dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops +sun8i_a83t_mipi_csi2_video_ops = { + .s_stream = sun8i_a83t_mipi_csi2_s_stream, +}; + +static void +sun8i_a83t_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) +{ + if (!sun8i_a83t_mipi_csi2_format_find(mbus_format->code)) + mbus_format->code = sun8i_a83t_mipi_csi2_formats[0].mbus_code; + + mbus_format->field = V4L2_FIELD_NONE; + mbus_format->colorspace = V4L2_COLORSPACE_RAW; + mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT; + mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int sun8i_a83t_mipi_csi2_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + unsigned int pad = SUN8I_A83T_MIPI_CSI2_PAD_SINK; + struct v4l2_mbus_framefmt *mbus_format = + v4l2_subdev_get_try_format(subdev, state, pad); + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + mbus_format->code = sun8i_a83t_mipi_csi2_formats[0].mbus_code; + mbus_format->width = 640; + mbus_format->height = 480; + + sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format); + + mutex_unlock(lock); + + return 0; +} + +static int +sun8i_a83t_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(sun8i_a83t_mipi_csi2_formats)) + return -EINVAL; + + code_enum->code = + sun8i_a83t_mipi_csi2_formats[code_enum->index].mbus_code; + + return 0; +} + +static int sun8i_a83t_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *mbus_format = *v4l2_subdev_get_try_format(subdev, state, + format->pad); + else + *mbus_format = csi2_dev->bridge.mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi2_dev->bridge.lock; + + mutex_lock(lock); + + sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *mbus_format; + else + csi2_dev->bridge.mbus_format = *mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun8i_a83t_mipi_csi2_pad_ops = { + .init_cfg = sun8i_a83t_mipi_csi2_init_cfg, + .enum_mbus_code = sun8i_a83t_mipi_csi2_enum_mbus_code, + .get_fmt = sun8i_a83t_mipi_csi2_get_fmt, + .set_fmt = sun8i_a83t_mipi_csi2_set_fmt, +}; + +static const struct v4l2_subdev_ops sun8i_a83t_mipi_csi2_subdev_ops = { + .video = &sun8i_a83t_mipi_csi2_video_ops, + .pad = &sun8i_a83t_mipi_csi2_pad_ops, +}; + +/* Media Entity */ + +static const struct media_entity_operations sun8i_a83t_mipi_csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* V4L2 Async */ + +static int +sun8i_a83t_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *remote_subdev, + struct v4l2_async_subdev *async_subdev) +{ + struct v4l2_subdev *subdev = notifier->sd; + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + container_of(notifier, struct sun8i_a83t_mipi_csi2_device, + bridge.notifier); + struct media_entity *sink_entity = &subdev->entity; + struct media_entity *source_entity = &remote_subdev->entity; + struct device *dev = csi2_dev->dev; + int sink_pad_index = 0; + int source_pad_index; + int ret; + + ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (ret < 0) { + dev_err(dev, "missing source pad in external entity %s\n", + source_entity->name); + return -EINVAL; + } + + source_pad_index = ret; + + dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name, + source_pad_index, sink_entity->name, sink_pad_index); + + ret = media_create_pad_link(source_entity, source_pad_index, + sink_entity, sink_pad_index, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(dev, "failed to create %s:%u -> %s:%u link\n", + source_entity->name, source_pad_index, + sink_entity->name, sink_pad_index); + return ret; + } + + csi2_dev->bridge.source_subdev = remote_subdev; + + return 0; +} + +static const struct v4l2_async_notifier_operations +sun8i_a83t_mipi_csi2_notifier_ops = { + .bound = sun8i_a83t_mipi_csi2_notifier_bound, +}; + +/* Bridge */ + +static int +sun8i_a83t_mipi_csi2_bridge_source_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint; + struct v4l2_async_subdev *subdev_async; + struct fwnode_handle *handle; + struct device *dev = csi2_dev->dev; + int ret; + + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!handle) + return -ENODEV; + + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); + if (ret) + goto complete; + + subdev_async = + v4l2_async_nf_add_fwnode_remote(notifier, handle, + struct v4l2_async_subdev); + if (IS_ERR(subdev_async)) + ret = PTR_ERR(subdev_async); + +complete: + fwnode_handle_put(handle); + + return ret; +} + +static int +sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct sun8i_a83t_mipi_csi2_bridge *bridge = &csi2_dev->bridge; + struct v4l2_subdev *subdev = &bridge->subdev; + struct v4l2_async_notifier *notifier = &bridge->notifier; + struct media_pad *pads = bridge->pads; + struct device *dev = csi2_dev->dev; + int ret; + + mutex_init(&bridge->lock); + + /* V4L2 Subdev */ + + v4l2_subdev_init(subdev, &sun8i_a83t_mipi_csi2_subdev_ops); + strscpy(subdev->name, SUN8I_A83T_MIPI_CSI2_NAME, sizeof(subdev->name)); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->owner = THIS_MODULE; + subdev->dev = dev; + + v4l2_set_subdevdata(subdev, csi2_dev); + + /* Media Entity */ + + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->entity.ops = &sun8i_a83t_mipi_csi2_entity_ops; + + /* Media Pads */ + + pads[SUN8I_A83T_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[SUN8I_A83T_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, + SUN8I_A83T_MIPI_CSI2_PAD_COUNT, pads); + if (ret) + return ret; + + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun8i_a83t_mipi_csi2_notifier_ops; + + ret = sun8i_a83t_mipi_csi2_bridge_source_setup(csi2_dev); + if (ret) + goto error_v4l2_notifier_cleanup; + + ret = v4l2_async_subdev_nf_register(subdev, notifier); + if (ret < 0) + goto error_v4l2_notifier_cleanup; + + /* V4L2 Subdev */ + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) + goto error_v4l2_notifier_unregister; + + return 0; + +error_v4l2_notifier_unregister: + v4l2_async_nf_unregister(notifier); + +error_v4l2_notifier_cleanup: + v4l2_async_nf_cleanup(notifier); + + media_entity_cleanup(&subdev->entity); + + return ret; +} + +static void +sun8i_a83t_mipi_csi2_bridge_cleanup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + struct v4l2_subdev *subdev = &csi2_dev->bridge.subdev; + struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier; + + v4l2_async_unregister_subdev(subdev); + v4l2_async_nf_unregister(notifier); + v4l2_async_nf_cleanup(notifier); + media_entity_cleanup(&subdev->entity); +} + +/* Platform */ + +static int sun8i_a83t_mipi_csi2_suspend(struct device *dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + + clk_disable_unprepare(csi2_dev->clock_misc); + clk_disable_unprepare(csi2_dev->clock_mipi); + clk_disable_unprepare(csi2_dev->clock_mod); + reset_control_assert(csi2_dev->reset); + + return 0; +} + +static int sun8i_a83t_mipi_csi2_resume(struct device *dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi2_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi2_dev->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(csi2_dev->clock_mipi); + if (ret) { + dev_err(dev, "failed to enable MIPI clock\n"); + goto error_clock_mod; + } + + ret = clk_prepare_enable(csi2_dev->clock_misc); + if (ret) { + dev_err(dev, "failed to enable CSI misc clock\n"); + goto error_clock_mipi; + } + + sun8i_a83t_mipi_csi2_init(csi2_dev); + + return 0; + +error_clock_mipi: + clk_disable_unprepare(csi2_dev->clock_mipi); + +error_clock_mod: + clk_disable_unprepare(csi2_dev->clock_mod); + +error_reset: + reset_control_assert(csi2_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun8i_a83t_mipi_csi2_pm_ops = { + .runtime_suspend = sun8i_a83t_mipi_csi2_suspend, + .runtime_resume = sun8i_a83t_mipi_csi2_resume, +}; + +static const struct regmap_config sun8i_a83t_mipi_csi2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x120, +}; + +static int +sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev, + struct platform_device *platform_dev) +{ + struct device *dev = csi2_dev->dev; + void __iomem *io_base; + int ret; + + /* Registers */ + + io_base = devm_platform_ioremap_resource(platform_dev, 0); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + csi2_dev->regmap = + devm_regmap_init_mmio_clk(dev, "bus", io_base, + &sun8i_a83t_mipi_csi2_regmap_config); + if (IS_ERR(csi2_dev->regmap)) { + dev_err(dev, "failed to init register map\n"); + return PTR_ERR(csi2_dev->regmap); + } + + /* Clocks */ + + csi2_dev->clock_mod = devm_clk_get(dev, "mod"); + if (IS_ERR(csi2_dev->clock_mod)) { + dev_err(dev, "failed to acquire mod clock\n"); + return PTR_ERR(csi2_dev->clock_mod); + } + + ret = clk_set_rate_exclusive(csi2_dev->clock_mod, 297000000); + if (ret) { + dev_err(dev, "failed to set mod clock rate\n"); + return ret; + } + + csi2_dev->clock_mipi = devm_clk_get(dev, "mipi"); + if (IS_ERR(csi2_dev->clock_mipi)) { + dev_err(dev, "failed to acquire mipi clock\n"); + return PTR_ERR(csi2_dev->clock_mipi); + } + + csi2_dev->clock_misc = devm_clk_get(dev, "misc"); + if (IS_ERR(csi2_dev->clock_misc)) { + dev_err(dev, "failed to acquire misc clock\n"); + return PTR_ERR(csi2_dev->clock_misc); + } + + /* Reset */ + + csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(csi2_dev->reset)) { + dev_err(dev, "failed to get reset controller\n"); + return PTR_ERR(csi2_dev->reset); + } + + /* D-PHY */ + + ret = sun8i_a83t_dphy_register(csi2_dev); + if (ret) { + dev_err(dev, "failed to initialize MIPI D-PHY\n"); + return ret; + } + + /* Runtime PM */ + + pm_runtime_enable(dev); + + return 0; +} + +static void +sun8i_a83t_mipi_csi2_resources_cleanup(struct sun8i_a83t_mipi_csi2_device *csi2_dev) +{ + pm_runtime_disable(csi2_dev->dev); + phy_exit(csi2_dev->dphy); + clk_rate_exclusive_put(csi2_dev->clock_mod); +} + +static int sun8i_a83t_mipi_csi2_probe(struct platform_device *platform_dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev; + struct device *dev = &platform_dev->dev; + int ret; + + csi2_dev = devm_kzalloc(dev, sizeof(*csi2_dev), GFP_KERNEL); + if (!csi2_dev) + return -ENOMEM; + + csi2_dev->dev = dev; + platform_set_drvdata(platform_dev, csi2_dev); + + ret = sun8i_a83t_mipi_csi2_resources_setup(csi2_dev, platform_dev); + if (ret) + return ret; + + ret = sun8i_a83t_mipi_csi2_bridge_setup(csi2_dev); + if (ret) + return ret; + + return 0; +} + +static int sun8i_a83t_mipi_csi2_remove(struct platform_device *platform_dev) +{ + struct sun8i_a83t_mipi_csi2_device *csi2_dev = + platform_get_drvdata(platform_dev); + + sun8i_a83t_mipi_csi2_bridge_cleanup(csi2_dev); + sun8i_a83t_mipi_csi2_resources_cleanup(csi2_dev); + + return 0; +} + +static const struct of_device_id sun8i_a83t_mipi_csi2_of_match[] = { + { .compatible = "allwinner,sun8i-a83t-mipi-csi2" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match); + +static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = { + .probe = sun8i_a83t_mipi_csi2_probe, + .remove = sun8i_a83t_mipi_csi2_remove, + .driver = { + .name = SUN8I_A83T_MIPI_CSI2_NAME, + .of_match_table = of_match_ptr(sun8i_a83t_mipi_csi2_of_match), + .pm = &sun8i_a83t_mipi_csi2_pm_ops, + }, +}; +module_platform_driver(sun8i_a83t_mipi_csi2_platform_driver); + +MODULE_DESCRIPTION("Allwinner A83T MIPI CSI-2 and D-PHY Controller Driver"); +MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h new file mode 100644 index 000000000000..f1e64c53434c --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN8I_A83T_MIPI_CSI2_H_ +#define _SUN8I_A83T_MIPI_CSI2_H_ + +#include <linux/phy/phy.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define SUN8I_A83T_MIPI_CSI2_NAME "sun8i-a83t-mipi-csi2" + +enum sun8i_a83t_mipi_csi2_pad { + SUN8I_A83T_MIPI_CSI2_PAD_SINK = 0, + SUN8I_A83T_MIPI_CSI2_PAD_SOURCE = 1, + SUN8I_A83T_MIPI_CSI2_PAD_COUNT = 2, +}; + +struct sun8i_a83t_mipi_csi2_format { + u32 mbus_code; + u8 data_type; + u32 bpp; +}; + +struct sun8i_a83t_mipi_csi2_bridge { + struct v4l2_subdev subdev; + struct media_pad pads[SUN8I_A83T_MIPI_CSI2_PAD_COUNT]; + struct v4l2_fwnode_endpoint endpoint; + struct v4l2_async_notifier notifier; + struct v4l2_mbus_framefmt mbus_format; + struct mutex lock; /* Mbus format lock. */ + + struct v4l2_subdev *source_subdev; +}; + +struct sun8i_a83t_mipi_csi2_device { + struct device *dev; + + struct regmap *regmap; + struct clk *clock_mod; + struct clk *clock_mipi; + struct clk *clock_misc; + struct reset_control *reset; + struct phy *dphy; + + struct sun8i_a83t_mipi_csi2_bridge bridge; +}; + +#endif diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h new file mode 100644 index 000000000000..2cfc9eb490e6 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com> + * Copyright 2020-2022 Bootlin + * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> + */ + +#ifndef _SUN8I_A83T_MIPI_CSI2_REG_H_ +#define _SUN8I_A83T_MIPI_CSI2_REG_H_ + +#define SUN8I_A83T_MIPI_CSI2_VERSION_REG 0x0 +#define SUN8I_A83T_MIPI_CSI2_CTRL_REG 0x4 +#define SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE 0xb8c39bec +#define SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N BIT(31) +#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG 0x8 +#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE 0xb8d257f8 +#define SUN8I_A83T_MIPI_CSI2_RSVD0_REG 0xc + +#define SUN8I_A83T_MIPI_CSI2_RSVD1_REG 0x18 +#define SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE 0xb8c8a30c +#define SUN8I_A83T_MIPI_CSI2_RSVD2_REG 0x1c +#define SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE 0xb8df8ad7 +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_REG 0x20 +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_ECC_ERR_DBL BIT(28) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC3 BIT(27) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC2 BIT(26) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC1 BIT(25) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC0 BIT(24) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT3 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT2 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT1 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT0 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT3 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT2 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT1 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT0 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_REG 0x24 +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT7 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT6 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT5 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT4 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT7 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT6 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT5 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT4 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_REG 0x28 +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_ECC_ERR_DBL BIT(28) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC3 BIT(27) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC2 BIT(26) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC1 BIT(25) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC0 BIT(24) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT3 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT2 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT1 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT0 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT3 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT2 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT1 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT0 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_REG 0x2c +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_0 BIT(0) + +#define SUN8I_A83T_MIPI_CSI2_CFG_REG 0x100 +#define SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE 0xb8c64f24 +#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN BIT(31) +#define SUN8I_A83T_MIPI_CSI2_CFG_BYPASS_ECC_EN BIT(29) +#define SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN BIT(28) +#define SUN8I_A83T_MIPI_CSI2_CFG_NONE_UNPKT_RX_MODE BIT(27) +#define SUN8I_A83T_MIPI_CSI2_CFG_YC_SWAB BIT(26) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_BYTE BIT(24) +#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(v) (((v) << 18) & \ + GENMASK(22, 18)) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(v) ((((v) - 1) << 16) & \ + GENMASK(17, 16)) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(v) ((((v) - 1) << 4) & \ + GENMASK(5, 4)) +#define SUN8I_A83T_MIPI_CSI2_VCDT0_REG 0x104 +#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + ((ch) * 8 + 6)) +#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + ((ch) * 8)) +#define SUN8I_A83T_MIPI_CSI2_VCDT1_REG 0x108 +#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + (((ch) - 4) * 8 + 6)) +#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + (((ch) - 4) * 8)) + +#endif diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c index e69fed117fea..e136d70b4048 100644 --- a/drivers/media/platform/ti/cal/cal-camerarx.c +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -305,7 +305,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy) /* * CSI-2 PHY Link Initialization Sequence, according to the DRA74xP / * DRA75xP / DRA76xP / DRA77xP TRM. The DRA71x / DRA72x and the AM65x / - * DRA80xM TRMs have a a slightly simplified sequence. + * DRA80xM TRMs have a slightly simplified sequence. */ /* @@ -592,7 +592,7 @@ int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy, if (!phy->source) return -EPIPE; - pad = media_entity_remote_pad(&phy->pads[CAL_CAMERARX_PAD_SINK]); + pad = media_pad_remote_pad_first(&phy->pads[CAL_CAMERARX_PAD_SINK]); if (!pad) return -EPIPE; diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 07ae1a34e6b0..776da0cfcdbe 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -685,7 +685,7 @@ static int cal_video_check_format(struct cal_ctx *ctx) const struct v4l2_mbus_framefmt *format; struct media_pad *remote_pad; - remote_pad = media_entity_remote_pad(&ctx->pad); + remote_pad = media_pad_remote_pad_first(&ctx->pad); if (!remote_pad) return -ENODEV; diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c index 97ef770266af..da27da4c165a 100644 --- a/drivers/media/platform/ti/davinci/vpif.c +++ b/drivers/media/platform/ti/davinci/vpif.c @@ -469,6 +469,7 @@ static int vpif_probe(struct platform_device *pdev) endpoint); if (!endpoint) return 0; + of_node_put(endpoint); /* * For DT platforms, manually create platform_devices for diff --git a/drivers/media/platform/ti/omap/omap_voutlib.c b/drivers/media/platform/ti/omap/omap_voutlib.c index 480a7e95533d..fdea2309ee37 100644 --- a/drivers/media/platform/ti/omap/omap_voutlib.c +++ b/drivers/media/platform/ti/omap/omap_voutlib.c @@ -314,7 +314,7 @@ unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr) if (virt_addr) { while (size > 0) { - SetPageReserved(virt_to_page(addr)); + SetPageReserved(virt_to_page((void *)addr)); addr += PAGE_SIZE; size -= PAGE_SIZE; } @@ -335,7 +335,7 @@ void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size) order = get_order(size); while (size > 0) { - ClearPageReserved(virt_to_page(addr)); + ClearPageReserved(virt_to_page((void *)addr)); addr += PAGE_SIZE; size -= PAGE_SIZE; } diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index 4c937f3f323e..d251736eb420 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -700,7 +700,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -797,7 +797,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -942,7 +942,7 @@ static int isp_pipeline_is_last(struct media_entity *me) pipe = to_isp_pipeline(me); if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) return 0; - pad = media_entity_remote_pad(&pipe->output->pad); + pad = media_pad_remote_pad_first(&pipe->output->pad); return pad->entity == me; } diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c index 108b5e9f82cb..11afb8aec292 100644 --- a/drivers/media/platform/ti/omap3isp/ispccdc.c +++ b/drivers/media/platform/ti/omap3isp/ispccdc.c @@ -1133,7 +1133,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) ccdc->bt656 = false; ccdc->fields = 0; - pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]); + pad = media_pad_remote_pad_first(&ccdc->pads[CCDC_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); if (ccdc->input == CCDC_INPUT_PARALLEL) { struct v4l2_subdev *sd = diff --git a/drivers/media/platform/ti/omap3isp/ispccp2.c b/drivers/media/platform/ti/omap3isp/ispccp2.c index acb58b6ddba1..fc90ff88464f 100644 --- a/drivers/media/platform/ti/omap3isp/ispccp2.c +++ b/drivers/media/platform/ti/omap3isp/ispccp2.c @@ -357,7 +357,7 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) ccp2_pwr_cfg(ccp2); - pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); + pad = media_pad_remote_pad_first(&ccp2->pads[CCP2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); buscfg = v4l2_subdev_to_bus_cfg(pipe->external); diff --git a/drivers/media/platform/ti/omap3isp/ispcsi2.c b/drivers/media/platform/ti/omap3isp/ispcsi2.c index 6302e0c94034..6870980a2fa9 100644 --- a/drivers/media/platform/ti/omap3isp/ispcsi2.c +++ b/drivers/media/platform/ti/omap3isp/ispcsi2.c @@ -561,7 +561,7 @@ static int csi2_configure(struct isp_csi2_device *csi2) if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) return -EBUSY; - pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); + pad = media_pad_remote_pad_first(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); buscfg = v4l2_subdev_to_bus_cfg(pipe->external); diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 8811d6dd4ee7..d7059180e80e 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -206,7 +206,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_pad_remote_pad_first(&video->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -981,7 +981,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video, continue; /* ISP entities have always sink pad == 0. Find source. */ - source_pad = media_entity_remote_pad(&ents[i]->pads[0]); + source_pad = media_pad_remote_pad_first(&ents[i]->pads[0]); if (source_pad == NULL) continue; diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index b31e5913a4cd..71d97042a470 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -118,7 +118,7 @@ static int video_mux_s_stream(struct v4l2_subdev *sd, int enable) return -EINVAL; } - pad = media_entity_remote_pad(&sd->entity.pads[vmux->active]); + pad = media_pad_remote_pad_first(&sd->entity.pads[vmux->active]); if (!pad) { dev_err(sd->dev, "Failed to find remote source pad\n"); return -ENOLINK; diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index 051c60cba1e0..cf8e892c47f0 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -474,7 +474,7 @@ static struct v4l2_subdev *xcsi2rxss_get_remote_subdev(struct media_pad *local) { struct media_pad *remote; - remote = media_entity_remote_pad(local); + remote = media_pad_remote_pad_first(local); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 338c3661d809..2d1ef7a25c33 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -44,7 +44,7 @@ xvip_dma_remote_subdev(struct media_pad *local, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(local); + remote = media_pad_remote_pad_first(local); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -107,7 +107,7 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start) if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h index d0b0e0600952..48fe229c5b33 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.h +++ b/drivers/media/platform/xilinx/xilinx-vip.h @@ -28,8 +28,8 @@ struct clk; #define XVIP_MAX_HEIGHT 7680 /* - * Pad IDs. IP cores with with multiple inputs or outputs should define - * their own values. + * Pad IDs. IP cores with multiple inputs or outputs should define their own + * values. */ #define XVIP_PAD_SINK 0 #define XVIP_PAD_SOURCE 1 diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 3155e876616d..fff4dd48eaca 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -135,8 +135,6 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes"); #define dbginfo(dev, format, arg...) \ do { if (debug) dev_info(dev , format , ## arg); } while (0) -#undef err -#define err(format, arg...) printk(KERN_ERR format , ## arg) struct ati_receiver_type { /* either default_keymap or get_default_keymap should be set */ @@ -816,11 +814,12 @@ static int ati_remote_probe(struct usb_interface *interface, struct ati_receiver_type *type = (struct ati_receiver_type *)id->driver_info; struct ati_remote *ati_remote; struct input_dev *input_dev; + struct device *device = &interface->dev; struct rc_dev *rc_dev; int err = -ENOMEM; if (iface_host->desc.bNumEndpoints != 2) { - err("%s: Unexpected desc.bNumEndpoints\n", __func__); + dev_err(device, "%s: Unexpected desc.bNumEndpoints\n", __func__); return -ENODEV; } @@ -828,15 +827,15 @@ static int ati_remote_probe(struct usb_interface *interface, endpoint_out = &iface_host->endpoint[1].desc; if (!usb_endpoint_is_int_in(endpoint_in)) { - err("%s: Unexpected endpoint_in\n", __func__); + dev_err(device, "%s: Unexpected endpoint_in\n", __func__); return -ENODEV; } if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) { - err("%s: endpoint_in message size==0? \n", __func__); + dev_err(device, "%s: endpoint_in message size==0?\n", __func__); return -ENODEV; } if (!usb_endpoint_is_int_out(endpoint_out)) { - err("%s: Unexpected endpoint_out\n", __func__); + dev_err(device, "%s: Unexpected endpoint_out\n", __func__); return -ENODEV; } diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index b40dbf500186..1464ef9c55bc 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -38,7 +38,7 @@ struct igorplugusb { struct timer_list timer; - uint8_t buf_in[MAX_PACKET]; + u8 *buf_in; char phys[64]; }; @@ -110,7 +110,6 @@ static void igorplugusb_callback(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - usb_unlink_urb(urb); return; default: dev_warn(ir->dev, "Error: urb status = %d\n", urb->status); @@ -126,7 +125,7 @@ static void igorplugusb_cmd(struct igorplugusb *ir, int cmd) ir->request.bRequest = cmd; ir->urb->transfer_flags = 0; ret = usb_submit_urb(ir->urb, GFP_ATOMIC); - if (ret) + if (ret && ret != -EPERM) dev_err(ir->dev, "submit urb failed: %d", ret); } @@ -171,15 +170,18 @@ static int igorplugusb_probe(struct usb_interface *intf, ir->request.bRequest = GET_INFRACODE; ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN; - ir->request.wLength = cpu_to_le16(sizeof(ir->buf_in)); + ir->request.wLength = cpu_to_le16(MAX_PACKET); ir->urb = usb_alloc_urb(0, GFP_KERNEL); if (!ir->urb) goto fail; + ir->buf_in = kmalloc(MAX_PACKET, GFP_KERNEL); + if (!ir->buf_in) + goto fail; usb_fill_control_urb(ir->urb, udev, usb_rcvctrlpipe(udev, 0), (uint8_t *)&ir->request, - ir->buf_in, sizeof(ir->buf_in), igorplugusb_callback, ir); + ir->buf_in, MAX_PACKET, igorplugusb_callback, ir); usb_make_path(udev, ir->phys, sizeof(ir->phys)); @@ -220,9 +222,12 @@ static int igorplugusb_probe(struct usb_interface *intf, return 0; fail: - rc_free_device(ir->rc); - usb_free_urb(ir->urb); + usb_poison_urb(ir->urb); del_timer(&ir->timer); + usb_unpoison_urb(ir->urb); + usb_free_urb(ir->urb); + rc_free_device(ir->rc); + kfree(ir->buf_in); return ret; } @@ -232,10 +237,12 @@ static void igorplugusb_disconnect(struct usb_interface *intf) struct igorplugusb *ir = usb_get_intfdata(intf); rc_unregister_device(ir->rc); + usb_poison_urb(ir->urb); del_timer_sync(&ir->timer); usb_set_intfdata(intf, NULL); - usb_kill_urb(ir->urb); + usb_unpoison_urb(ir->urb); usb_free_urb(ir->urb); + kfree(ir->buf_in); } static const struct usb_device_id igorplugusb_table[] = { diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index c9cb8277723f..276bf3c8a8cb 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -149,10 +149,8 @@ static void iguanair_rx(struct urb *urb) return; ir = urb->context; - if (!ir) { - usb_unlink_urb(urb); + if (!ir) return; - } switch (urb->status) { case 0: @@ -161,7 +159,6 @@ static void iguanair_rx(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - usb_unlink_urb(urb); return; case -EPIPE: default: diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c index d41580f6e4c7..b02ded52f19e 100644 --- a/drivers/media/rc/imon_raw.c +++ b/drivers/media/rc/imon_raw.c @@ -14,7 +14,7 @@ struct imon { struct device *dev; struct urb *ir_urb; struct rc_dev *rcdev; - __be64 ir_buf; + __be64 *ir_buf; char phys[64]; }; @@ -29,7 +29,7 @@ struct imon { static void imon_ir_data(struct imon *imon) { struct ir_raw_event rawir = {}; - u64 data = be64_to_cpu(imon->ir_buf); + u64 data = be64_to_cpup(imon->ir_buf); u8 packet_no = data & 0xff; int offset = 40; int bit; @@ -37,7 +37,7 @@ static void imon_ir_data(struct imon *imon) if (packet_no == 0xff) return; - dev_dbg(imon->dev, "data: %*ph", 8, &imon->ir_buf); + dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf); /* * Only the first 5 bytes contain IR data. Right shift so we move @@ -137,10 +137,16 @@ static int imon_probe(struct usb_interface *intf, if (!imon->ir_urb) return -ENOMEM; + imon->ir_buf = kmalloc(sizeof(__be64), GFP_KERNEL); + if (!imon->ir_buf) { + ret = -ENOMEM; + goto free_urb; + } + imon->dev = &intf->dev; usb_fill_int_urb(imon->ir_urb, udev, usb_rcvintpipe(udev, ir_ep->bEndpointAddress), - &imon->ir_buf, sizeof(imon->ir_buf), + imon->ir_buf, sizeof(__be64), imon_ir_rx, imon, ir_ep->bInterval); rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW); @@ -177,6 +183,7 @@ static int imon_probe(struct usb_interface *intf, free_urb: usb_free_urb(imon->ir_urb); + kfree(imon->ir_buf); return ret; } @@ -186,6 +193,7 @@ static void imon_disconnect(struct usb_interface *intf) usb_kill_urb(imon->ir_urb); usb_free_urb(imon->ir_urb); + kfree(imon->ir_buf); } static const struct usb_device_id imon_table[] = { diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 765375bda0c6..25ab61dae126 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -715,7 +715,7 @@ int lirc_register(struct rc_dev *dev) const char *rx_type, *tx_type; int err, minor; - minor = ida_simple_get(&lirc_ida, 0, RC_DEV_MAX, GFP_KERNEL); + minor = ida_alloc_max(&lirc_ida, RC_DEV_MAX - 1, GFP_KERNEL); if (minor < 0) return minor; @@ -760,7 +760,7 @@ int lirc_register(struct rc_dev *dev) return 0; out_ida: - ida_simple_remove(&lirc_ida, minor); + ida_free(&lirc_ida, minor); return err; } @@ -778,7 +778,7 @@ void lirc_unregister(struct rc_dev *dev) spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); cdev_device_del(&dev->lirc_cdev, &dev->lirc_dev); - ida_simple_remove(&lirc_ida, MINOR(dev->lirc_dev.devt)); + ida_free(&lirc_ida, MINOR(dev->lirc_dev.devt)); } int __init lirc_dev_init(void) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b90438a71c80..eba0cd30e314 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -786,7 +786,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, dev->last_toggle != toggle); struct lirc_scancode sc = { .scancode = scancode, .rc_proto = protocol, - .flags = toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0, + .flags = (toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0) | + (!new_event ? LIRC_SCANCODE_FLAG_REPEAT : 0), .keycode = keycode }; @@ -1897,7 +1898,7 @@ int rc_register_device(struct rc_dev *dev) if (!dev) return -EINVAL; - minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL); + minor = ida_alloc_max(&rc_ida, RC_DEV_MAX - 1, GFP_KERNEL); if (minor < 0) return minor; @@ -1980,7 +1981,7 @@ out_rx_free: out_raw: ir_raw_event_free(dev); out_minor: - ida_simple_remove(&rc_ida, minor); + ida_free(&rc_ida, minor); return rc; } EXPORT_SYMBOL_GPL(rc_register_device); @@ -2040,7 +2041,7 @@ void rc_unregister_device(struct rc_dev *dev) device_del(&dev->dev); - ida_simple_remove(&rc_ida, dev->minor); + ida_free(&rc_ida, dev->minor); if (!dev->managed_alloc) rc_free_device(dev); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index cb22316b3f00..9f2947af33aa 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -1155,9 +1155,9 @@ static int redrat3_dev_resume(struct usb_interface *intf) { struct redrat3_dev *rr3 = usb_get_intfdata(intf); - if (usb_submit_urb(rr3->narrow_urb, GFP_ATOMIC)) + if (usb_submit_urb(rr3->narrow_urb, GFP_NOIO)) return -EIO; - if (usb_submit_urb(rr3->wide_urb, GFP_ATOMIC)) + if (usb_submit_urb(rr3->wide_urb, GFP_NOIO)) return -EIO; led_classdev_resume(&rr3->led); return 0; diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index deb85330c940..9b209e687f25 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -406,7 +406,7 @@ static int streamzap_resume(struct usb_interface *intf) { struct streamzap_ir *sz = usb_get_intfdata(intf); - if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { + if (usb_submit_urb(sz->urb_in, GFP_NOIO)) { dev_err(sz->dev, "Error submitting urb\n"); return -EIO; } diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index 629787d53ee1..560a26f3965c 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -90,7 +90,6 @@ static void ttusbir_bulk_complete(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - usb_unlink_urb(urb); return; case -EPIPE: default: @@ -166,7 +165,6 @@ static void ttusbir_urb_complete(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - usb_unlink_urb(urb); return; case -EPIPE: default: @@ -402,7 +400,7 @@ static int ttusbir_resume(struct usb_interface *intf) led_classdev_resume(&tt->led); for (i = 0; i < NUM_URBS; i++) { - rc = usb_submit_urb(tt->urb[i], GFP_KERNEL); + rc = usb_submit_urb(tt->urb[i], GFP_NOIO); if (rc) { dev_warn(tt->dev, "failed to submit urb: %d\n", rc); break; diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c index 7424b2031152..a1572381d097 100644 --- a/drivers/media/rc/xbox_remote.c +++ b/drivers/media/rc/xbox_remote.c @@ -163,8 +163,8 @@ static void xbox_remote_rc_init(struct xbox_remote *xbox_remote) rdev->dev.parent = &xbox_remote->interface->dev; } -static int xbox_remote_initialize(struct xbox_remote *xbox_remote, - struct usb_endpoint_descriptor *endpoint_in) +static void xbox_remote_initialize(struct xbox_remote *xbox_remote, + struct usb_endpoint_descriptor *endpoint_in) { struct usb_device *udev = xbox_remote->udev; int pipe, maxp; @@ -177,8 +177,6 @@ static int xbox_remote_initialize(struct xbox_remote *xbox_remote, usb_fill_int_urb(xbox_remote->irq_urb, udev, pipe, xbox_remote->inbuf, maxp, xbox_remote_irq_in, xbox_remote, endpoint_in->bInterval); - - return 0; } /* @@ -249,9 +247,7 @@ static int xbox_remote_probe(struct usb_interface *interface, xbox_remote_rc_init(xbox_remote); /* Device Hardware Initialization */ - err = xbox_remote_initialize(xbox_remote, endpoint_in); - if (err) - goto exit_kill_urbs; + xbox_remote_initialize(xbox_remote, endpoint_in); /* Set up and register rc device */ err = rc_register_device(xbox_remote->rdev); diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index be43f7d32df9..1d1bee111732 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -280,17 +280,13 @@ static int device_process(struct vicodec_ctx *ctx, */ if (!(ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)) { struct vb2_buffer *ref_vb2_buf; - int ref_buf_idx; struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - ref_buf_idx = vb2_find_timestamp(vq_cap, - ctx->state.ref_frame_ts, 0); - if (ref_buf_idx < 0) + ref_vb2_buf = vb2_find_buffer(vq_cap, ctx->state.ref_frame_ts); + if (!ref_vb2_buf) return -EINVAL; - - ref_vb2_buf = vq_cap->bufs[ref_buf_idx]; if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR) ret = -EINVAL; ctx->state.ref_frame.buf = diff --git a/drivers/media/test-drivers/vimc/Makefile b/drivers/media/test-drivers/vimc/Makefile index a53b2b532e9f..9b9631562473 100644 --- a/drivers/media/test-drivers/vimc/Makefile +++ b/drivers/media/test-drivers/vimc/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \ - vimc-debayer.o vimc-scaler.o vimc-sensor.o + vimc-debayer.o vimc-scaler.o vimc-sensor.o vimc-lens.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index d1e2d0739c00..6c437802f91f 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -13,7 +13,7 @@ #include "vimc-common.h" #include "vimc-streamer.h" -struct vimc_cap_device { +struct vimc_capture_device { struct vimc_ent_device ved; struct video_device vdev; struct v4l2_pix_format format; @@ -41,7 +41,7 @@ static const struct v4l2_pix_format fmt_default = { .colorspace = V4L2_COLORSPACE_SRGB, }; -struct vimc_cap_buffer { +struct vimc_capture_buffer { /* * struct vb2_v4l2_buffer must be the first element * the videobuf2 framework will allocate this struct based on @@ -52,7 +52,7 @@ struct vimc_cap_buffer { struct list_head list; }; -static int vimc_cap_querycap(struct file *file, void *priv, +static int vimc_capture_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { strscpy(cap->driver, VIMC_PDEV_NAME, sizeof(cap->driver)); @@ -63,26 +63,26 @@ static int vimc_cap_querycap(struct file *file, void *priv, return 0; } -static void vimc_cap_get_format(struct vimc_ent_device *ved, +static void vimc_capture_get_format(struct vimc_ent_device *ved, struct v4l2_pix_format *fmt) { - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + struct vimc_capture_device *vcapture = container_of(ved, struct vimc_capture_device, ved); - *fmt = vcap->format; + *fmt = vcapture->format; } -static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vimc_cap_device *vcap = video_drvdata(file); + struct vimc_capture_device *vcapture = video_drvdata(file); - f->fmt.pix = vcap->format; + f->fmt.pix = vcapture->format; return 0; } -static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *format = &f->fmt.pix; @@ -114,40 +114,40 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vimc_cap_device *vcap = video_drvdata(file); + struct vimc_capture_device *vcapture = video_drvdata(file); int ret; /* Do not change the format while stream is on */ - if (vb2_is_busy(&vcap->queue)) + if (vb2_is_busy(&vcapture->queue)) return -EBUSY; - ret = vimc_cap_try_fmt_vid_cap(file, priv, f); + ret = vimc_capture_try_fmt_vid_cap(file, priv, f); if (ret) return ret; - dev_dbg(vcap->ved.dev, "%s: format update: " + dev_dbg(vcapture->ved.dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcapture->vdev.name, /* old */ - vcap->format.width, vcap->format.height, - vcap->format.pixelformat, vcap->format.colorspace, - vcap->format.quantization, vcap->format.xfer_func, - vcap->format.ycbcr_enc, + vcapture->format.width, vcapture->format.height, + vcapture->format.pixelformat, vcapture->format.colorspace, + vcapture->format.quantization, vcapture->format.xfer_func, + vcapture->format.ycbcr_enc, /* new */ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat, f->fmt.pix.colorspace, f->fmt.pix.quantization, f->fmt.pix.xfer_func, f->fmt.pix.ycbcr_enc); - vcap->format = f->fmt.pix; + vcapture->format = f->fmt.pix; return 0; } -static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, +static int vimc_capture_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { const struct vimc_pix_map *vpix; @@ -169,7 +169,7 @@ static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vimc_cap_enum_framesizes(struct file *file, void *fh, +static int vimc_capture_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { const struct vimc_pix_map *vpix; @@ -193,7 +193,7 @@ static int vimc_cap_enum_framesizes(struct file *file, void *fh, return 0; } -static const struct v4l2_file_operations vimc_cap_fops = { +static const struct v4l2_file_operations vimc_capture_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -203,14 +203,14 @@ static const struct v4l2_file_operations vimc_cap_fops = { .mmap = vb2_fop_mmap, }; -static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { - .vidioc_querycap = vimc_cap_querycap, +static const struct v4l2_ioctl_ops vimc_capture_ioctl_ops = { + .vidioc_querycap = vimc_capture_querycap, - .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, - .vidioc_enum_framesizes = vimc_cap_enum_framesizes, + .vidioc_g_fmt_vid_cap = vimc_capture_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_capture_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_capture_try_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = vimc_capture_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_capture_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, @@ -223,40 +223,40 @@ static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { .vidioc_streamoff = vb2_ioctl_streamoff, }; -static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap, +static void vimc_capture_return_all_buffers(struct vimc_capture_device *vcapture, enum vb2_buffer_state state) { - struct vimc_cap_buffer *vbuf, *node; + struct vimc_capture_buffer *vbuf, *node; - spin_lock(&vcap->qlock); + spin_lock(&vcapture->qlock); - list_for_each_entry_safe(vbuf, node, &vcap->buf_list, list) { + list_for_each_entry_safe(vbuf, node, &vcapture->buf_list, list) { list_del(&vbuf->list); vb2_buffer_done(&vbuf->vb2.vb2_buf, state); } - spin_unlock(&vcap->qlock); + spin_unlock(&vcapture->qlock); } -static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) +static int vimc_capture_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); - struct media_entity *entity = &vcap->vdev.entity; + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq); + struct media_entity *entity = &vcapture->vdev.entity; int ret; - vcap->sequence = 0; + vcapture->sequence = 0; /* Start the media pipeline */ - ret = media_pipeline_start(entity, &vcap->stream.pipe); + ret = media_pipeline_start(entity, &vcapture->stream.pipe); if (ret) { - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); + vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED); return ret; } - ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); + ret = vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 1); if (ret) { media_pipeline_stop(entity); - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); + vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED); return ret; } @@ -267,65 +267,65 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) * Stop the stream engine. Any remaining buffers in the stream queue are * dequeued and passed on to the vb2 framework marked as STATE_ERROR. */ -static void vimc_cap_stop_streaming(struct vb2_queue *vq) +static void vimc_capture_stop_streaming(struct vb2_queue *vq) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq); - vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0); + vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 0); /* Stop the media pipeline */ - media_pipeline_stop(&vcap->vdev.entity); + media_pipeline_stop(&vcapture->vdev.entity); /* Release all active buffers */ - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR); + vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_ERROR); } -static void vimc_cap_buf_queue(struct vb2_buffer *vb2_buf) +static void vimc_capture_buf_queue(struct vb2_buffer *vb2_buf) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vb2_buf->vb2_queue); - struct vimc_cap_buffer *buf = container_of(vb2_buf, - struct vimc_cap_buffer, + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vb2_buf->vb2_queue); + struct vimc_capture_buffer *buf = container_of(vb2_buf, + struct vimc_capture_buffer, vb2.vb2_buf); - spin_lock(&vcap->qlock); - list_add_tail(&buf->list, &vcap->buf_list); - spin_unlock(&vcap->qlock); + spin_lock(&vcapture->qlock); + list_add_tail(&buf->list, &vcapture->buf_list); + spin_unlock(&vcapture->qlock); } -static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, +static int vimc_capture_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq); if (*nplanes) - return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0; + return sizes[0] < vcapture->format.sizeimage ? -EINVAL : 0; /* We don't support multiplanes for now */ *nplanes = 1; - sizes[0] = vcap->format.sizeimage; + sizes[0] = vcapture->format.sizeimage; return 0; } -static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) +static int vimc_capture_buffer_prepare(struct vb2_buffer *vb) { - struct vimc_cap_device *vcap = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = vcap->format.sizeimage; + struct vimc_capture_device *vcapture = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = vcapture->format.sizeimage; if (vb2_plane_size(vb, 0) < size) { - dev_err(vcap->ved.dev, "%s: buffer too small (%lu < %lu)\n", - vcap->vdev.name, vb2_plane_size(vb, 0), size); + dev_err(vcapture->ved.dev, "%s: buffer too small (%lu < %lu)\n", + vcapture->vdev.name, vb2_plane_size(vb, 0), size); return -EINVAL; } return 0; } -static const struct vb2_ops vimc_cap_qops = { - .start_streaming = vimc_cap_start_streaming, - .stop_streaming = vimc_cap_stop_streaming, - .buf_queue = vimc_cap_buf_queue, - .queue_setup = vimc_cap_queue_setup, - .buf_prepare = vimc_cap_buffer_prepare, +static const struct vb2_ops vimc_capture_qops = { + .start_streaming = vimc_capture_start_streaming, + .stop_streaming = vimc_capture_stop_streaming, + .buf_queue = vimc_capture_buf_queue, + .queue_setup = vimc_capture_queue_setup, + .buf_prepare = vimc_capture_buffer_prepare, /* * Since q->lock is set we can use the standard * vb2_ops_wait_prepare/finish helper functions. @@ -334,107 +334,107 @@ static const struct vb2_ops vimc_cap_qops = { .wait_finish = vb2_ops_wait_finish, }; -static const struct media_entity_operations vimc_cap_mops = { +static const struct media_entity_operations vimc_capture_mops = { .link_validate = vimc_vdev_link_validate, }; -static void vimc_cap_release(struct vimc_ent_device *ved) +static void vimc_capture_release(struct vimc_ent_device *ved) { - struct vimc_cap_device *vcap = - container_of(ved, struct vimc_cap_device, ved); + struct vimc_capture_device *vcapture = + container_of(ved, struct vimc_capture_device, ved); - media_entity_cleanup(vcap->ved.ent); - kfree(vcap); + media_entity_cleanup(vcapture->ved.ent); + kfree(vcapture); } -static void vimc_cap_unregister(struct vimc_ent_device *ved) +static void vimc_capture_unregister(struct vimc_ent_device *ved) { - struct vimc_cap_device *vcap = - container_of(ved, struct vimc_cap_device, ved); + struct vimc_capture_device *vcapture = + container_of(ved, struct vimc_capture_device, ved); - vb2_video_unregister_device(&vcap->vdev); + vb2_video_unregister_device(&vcapture->vdev); } -static void *vimc_cap_process_frame(struct vimc_ent_device *ved, +static void *vimc_capture_process_frame(struct vimc_ent_device *ved, const void *frame) { - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + struct vimc_capture_device *vcapture = container_of(ved, struct vimc_capture_device, ved); - struct vimc_cap_buffer *vimc_buf; + struct vimc_capture_buffer *vimc_buf; void *vbuf; - spin_lock(&vcap->qlock); + spin_lock(&vcapture->qlock); /* Get the first entry of the list */ - vimc_buf = list_first_entry_or_null(&vcap->buf_list, + vimc_buf = list_first_entry_or_null(&vcapture->buf_list, typeof(*vimc_buf), list); if (!vimc_buf) { - spin_unlock(&vcap->qlock); + spin_unlock(&vcapture->qlock); return ERR_PTR(-EAGAIN); } /* Remove this entry from the list */ list_del(&vimc_buf->list); - spin_unlock(&vcap->qlock); + spin_unlock(&vcapture->qlock); /* Fill the buffer */ vimc_buf->vb2.vb2_buf.timestamp = ktime_get_ns(); - vimc_buf->vb2.sequence = vcap->sequence++; - vimc_buf->vb2.field = vcap->format.field; + vimc_buf->vb2.sequence = vcapture->sequence++; + vimc_buf->vb2.field = vcapture->format.field; vbuf = vb2_plane_vaddr(&vimc_buf->vb2.vb2_buf, 0); - memcpy(vbuf, frame, vcap->format.sizeimage); + memcpy(vbuf, frame, vcapture->format.sizeimage); /* Set it as ready */ vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, - vcap->format.sizeimage); + vcapture->format.sizeimage); vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); return NULL; } -static struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, +static struct vimc_ent_device *vimc_capture_add(struct vimc_device *vimc, const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; const struct vimc_pix_map *vpix; - struct vimc_cap_device *vcap; + struct vimc_capture_device *vcapture; struct video_device *vdev; struct vb2_queue *q; int ret; - /* Allocate the vimc_cap_device struct */ - vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); - if (!vcap) + /* Allocate the vimc_capture_device struct */ + vcapture = kzalloc(sizeof(*vcapture), GFP_KERNEL); + if (!vcapture) return ERR_PTR(-ENOMEM); /* Initialize the media entity */ - vcap->vdev.entity.name = vcfg_name; - vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; - vcap->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vcap->vdev.entity, - 1, &vcap->pad); + vcapture->vdev.entity.name = vcfg_name; + vcapture->vdev.entity.function = MEDIA_ENT_F_IO_V4L; + vcapture->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vcapture->vdev.entity, + 1, &vcapture->pad); if (ret) - goto err_free_vcap; + goto err_free_vcapture; /* Initialize the lock */ - mutex_init(&vcap->lock); + mutex_init(&vcapture->lock); /* Initialize the vb2 queue */ - q = &vcap->queue; + q = &vcapture->queue; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_DMABUF; if (vimc_allocator == VIMC_ALLOCATOR_VMALLOC) q->io_modes |= VB2_USERPTR; - q->drv_priv = vcap; - q->buf_struct_size = sizeof(struct vimc_cap_buffer); - q->ops = &vimc_cap_qops; + q->drv_priv = vcapture; + q->buf_struct_size = sizeof(struct vimc_capture_buffer); + q->ops = &vimc_capture_qops; q->mem_ops = vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG ? &vb2_dma_contig_memops : &vb2_vmalloc_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->min_buffers_needed = 2; - q->lock = &vcap->lock; + q->lock = &vcapture->lock; q->dev = v4l2_dev->dev; ret = vb2_queue_init(q); @@ -445,57 +445,57 @@ static struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, } /* Initialize buffer list and its lock */ - INIT_LIST_HEAD(&vcap->buf_list); - spin_lock_init(&vcap->qlock); + INIT_LIST_HEAD(&vcapture->buf_list); + spin_lock_init(&vcapture->qlock); /* Set default frame format */ - vcap->format = fmt_default; - vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; - vcap->format.sizeimage = vcap->format.bytesperline * - vcap->format.height; + vcapture->format = fmt_default; + vpix = vimc_pix_map_by_pixelformat(vcapture->format.pixelformat); + vcapture->format.bytesperline = vcapture->format.width * vpix->bpp; + vcapture->format.sizeimage = vcapture->format.bytesperline * + vcapture->format.height; /* Fill the vimc_ent_device struct */ - vcap->ved.ent = &vcap->vdev.entity; - vcap->ved.process_frame = vimc_cap_process_frame; - vcap->ved.vdev_get_format = vimc_cap_get_format; - vcap->ved.dev = vimc->mdev.dev; + vcapture->ved.ent = &vcapture->vdev.entity; + vcapture->ved.process_frame = vimc_capture_process_frame; + vcapture->ved.vdev_get_format = vimc_capture_get_format; + vcapture->ved.dev = vimc->mdev.dev; /* Initialize the video_device struct */ - vdev = &vcap->vdev; + vdev = &vcapture->vdev; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; - vdev->entity.ops = &vimc_cap_mops; + vdev->entity.ops = &vimc_capture_mops; vdev->release = video_device_release_empty; - vdev->fops = &vimc_cap_fops; - vdev->ioctl_ops = &vimc_cap_ioctl_ops; - vdev->lock = &vcap->lock; + vdev->fops = &vimc_capture_fops; + vdev->ioctl_ops = &vimc_capture_ioctl_ops; + vdev->lock = &vcapture->lock; vdev->queue = q; vdev->v4l2_dev = v4l2_dev; vdev->vfl_dir = VFL_DIR_RX; strscpy(vdev->name, vcfg_name, sizeof(vdev->name)); - video_set_drvdata(vdev, &vcap->ved); + video_set_drvdata(vdev, &vcapture->ved); /* Register the video_device with the v4l2 and the media framework */ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) { dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n", - vcap->vdev.name, ret); + vcapture->vdev.name, ret); goto err_clean_m_ent; } - return &vcap->ved; + return &vcapture->ved; err_clean_m_ent: - media_entity_cleanup(&vcap->vdev.entity); -err_free_vcap: - kfree(vcap); + media_entity_cleanup(&vcapture->vdev.entity); +err_free_vcapture: + kfree(vcapture); return ERR_PTR(ret); } -struct vimc_ent_type vimc_cap_type = { - .add = vimc_cap_add, - .unregister = vimc_cap_unregister, - .release = vimc_cap_release +struct vimc_ent_type vimc_capture_type = { + .add = vimc_capture_add, + .unregister = vimc_capture_unregister, + .release = vimc_capture_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-common.h b/drivers/media/test-drivers/vimc/vimc-common.h index ba1930772589..7641a101a728 100644 --- a/drivers/media/test-drivers/vimc/vimc-common.h +++ b/drivers/media/test-drivers/vimc/vimc-common.h @@ -167,10 +167,11 @@ struct vimc_ent_config { */ bool vimc_is_source(struct media_entity *ent); -extern struct vimc_ent_type vimc_sen_type; -extern struct vimc_ent_type vimc_deb_type; -extern struct vimc_ent_type vimc_sca_type; -extern struct vimc_ent_type vimc_cap_type; +extern struct vimc_ent_type vimc_sensor_type; +extern struct vimc_ent_type vimc_debayer_type; +extern struct vimc_ent_type vimc_scaler_type; +extern struct vimc_ent_type vimc_capture_type; +extern struct vimc_ent_type vimc_lens_type; /** * vimc_pix_map_by_index - get vimc_pix_map struct by its index diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c index 06edf9d4d92c..2ae7a0f11ebf 100644 --- a/drivers/media/test-drivers/vimc/vimc-core.c +++ b/drivers/media/test-drivers/vimc/vimc-core.c @@ -24,7 +24,7 @@ MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n" #define VIMC_MDEV_MODEL_NAME "VIMC MDEV" -#define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ +#define VIMC_DATA_LINK(src, srcpad, sink, sinkpad, link_flags) { \ .src_ent = src, \ .src_pad = srcpad, \ .sink_ent = sink, \ @@ -32,8 +32,13 @@ MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n" .flags = link_flags, \ } -/* Structure which describes links between entities */ -struct vimc_ent_link { +#define VIMC_ANCILLARY_LINK(primary, ancillary) { \ + .primary_ent = primary, \ + .ancillary_ent = ancillary \ +} + +/* Structure which describes data links between entities */ +struct vimc_data_link { unsigned int src_ent; u16 src_pad; unsigned int sink_ent; @@ -41,12 +46,35 @@ struct vimc_ent_link { u32 flags; }; +/* Enum to improve clarity when defining vimc_data_links */ +enum vimc_data_link_ents { + SENSOR_A, + SENSOR_B, + DEBAYER_A, + DEBAYER_B, + RAW_CAPTURE_0, + RAW_CAPTURE_1, + RGB_YUV_INPUT, + SCALER, + RGB_YUV_CAPTURE, + LENS_A, + LENS_B, +}; + +/* Structure which describes ancillary links between entities */ +struct vimc_ancillary_link { + unsigned int primary_ent; + unsigned int ancillary_ent; +}; + /* Structure which describes the whole topology */ struct vimc_pipeline_config { const struct vimc_ent_config *ents; size_t num_ents; - const struct vimc_ent_link *links; - size_t num_links; + const struct vimc_data_link *data_links; + size_t num_data_links; + const struct vimc_ancillary_link *ancillary_links; + size_t num_ancillary_links; }; /* -------------------------------------------------------------------------- @@ -54,69 +82,91 @@ struct vimc_pipeline_config { */ static struct vimc_ent_config ent_config[] = { - { + [SENSOR_A] = { .name = "Sensor A", - .type = &vimc_sen_type + .type = &vimc_sensor_type }, - { + [SENSOR_B] = { .name = "Sensor B", - .type = &vimc_sen_type + .type = &vimc_sensor_type }, - { + [DEBAYER_A] = { .name = "Debayer A", - .type = &vimc_deb_type + .type = &vimc_debayer_type }, - { + [DEBAYER_B] = { .name = "Debayer B", - .type = &vimc_deb_type + .type = &vimc_debayer_type }, - { + [RAW_CAPTURE_0] = { .name = "Raw Capture 0", - .type = &vimc_cap_type + .type = &vimc_capture_type }, - { + [RAW_CAPTURE_1] = { .name = "Raw Capture 1", - .type = &vimc_cap_type + .type = &vimc_capture_type }, - { + [RGB_YUV_INPUT] = { /* TODO: change this to vimc-input when it is implemented */ .name = "RGB/YUV Input", - .type = &vimc_sen_type + .type = &vimc_sensor_type }, - { + [SCALER] = { .name = "Scaler", - .type = &vimc_sca_type + .type = &vimc_scaler_type }, - { + [RGB_YUV_CAPTURE] = { .name = "RGB/YUV Capture", - .type = &vimc_cap_type + .type = &vimc_capture_type + }, + [LENS_A] = { + .name = "Lens A", + .type = &vimc_lens_type + }, + [LENS_B] = { + .name = "Lens B", + .type = &vimc_lens_type }, }; -static const struct vimc_ent_link ent_links[] = { +static const struct vimc_data_link data_links[] = { /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */ - VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_A, 0, DEBAYER_A, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */ - VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_A, 0, RAW_CAPTURE_0, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */ - VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_B, 0, DEBAYER_B, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */ - VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SENSOR_B, 0, RAW_CAPTURE_1, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */ - VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED), + VIMC_DATA_LINK(DEBAYER_A, 1, SCALER, 0, MEDIA_LNK_FL_ENABLED), /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */ - VIMC_ENT_LINK(3, 1, 7, 0, 0), + VIMC_DATA_LINK(DEBAYER_B, 1, SCALER, 0, 0), /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */ - VIMC_ENT_LINK(6, 0, 7, 0, 0), + VIMC_DATA_LINK(RGB_YUV_INPUT, 0, SCALER, 0, 0), /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */ - VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + VIMC_DATA_LINK(SCALER, 1, RGB_YUV_CAPTURE, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), +}; + +static const struct vimc_ancillary_link ancillary_links[] = { + /* Link: Sensor A -> Lens A */ + VIMC_ANCILLARY_LINK(0, 9), + /* Link: Sensor B -> Lens B */ + VIMC_ANCILLARY_LINK(1, 10), }; static struct vimc_pipeline_config pipe_cfg = { - .ents = ent_config, - .num_ents = ARRAY_SIZE(ent_config), - .links = ent_links, - .num_links = ARRAY_SIZE(ent_links) + .ents = ent_config, + .num_ents = ARRAY_SIZE(ent_config), + .data_links = data_links, + .num_data_links = ARRAY_SIZE(data_links), + .ancillary_links = ancillary_links, + .num_ancillary_links = ARRAY_SIZE(ancillary_links), }; /* -------------------------------------------------------------------------- */ @@ -135,8 +185,8 @@ static int vimc_create_links(struct vimc_device *vimc) int ret; /* Initialize the links between entities */ - for (i = 0; i < vimc->pipe_cfg->num_links; i++) { - const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; + for (i = 0; i < vimc->pipe_cfg->num_data_links; i++) { + const struct vimc_data_link *link = &vimc->pipe_cfg->data_links[i]; struct vimc_ent_device *ved_src = vimc->ent_devs[link->src_ent]; @@ -150,6 +200,22 @@ static int vimc_create_links(struct vimc_device *vimc) goto err_rm_links; } + for (i = 0; i < vimc->pipe_cfg->num_ancillary_links; i++) { + const struct vimc_ancillary_link *link = &vimc->pipe_cfg->ancillary_links[i]; + + struct vimc_ent_device *ved_primary = + vimc->ent_devs[link->primary_ent]; + struct vimc_ent_device *ved_ancillary = + vimc->ent_devs[link->ancillary_ent]; + struct media_link *ret_link = + media_create_ancillary_link(ved_primary->ent, ved_ancillary->ent); + + if (IS_ERR(ret_link)) { + ret = PTR_ERR(ret_link); + goto err_rm_links; + } + } + return 0; err_rm_links: diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c index 2d06cdbacc76..f671251fdf0e 100644 --- a/drivers/media/test-drivers/vimc/vimc-debayer.c +++ b/drivers/media/test-drivers/vimc/vimc-debayer.c @@ -15,28 +15,29 @@ #include "vimc-common.h" -enum vimc_deb_rgb_colors { - VIMC_DEB_RED = 0, - VIMC_DEB_GREEN = 1, - VIMC_DEB_BLUE = 2, +enum vimc_debayer_rgb_colors { + VIMC_DEBAYER_RED = 0, + VIMC_DEBAYER_GREEN = 1, + VIMC_DEBAYER_BLUE = 2, }; -struct vimc_deb_pix_map { +struct vimc_debayer_pix_map { u32 code; - enum vimc_deb_rgb_colors order[2][2]; + enum vimc_debayer_rgb_colors order[2][2]; }; -struct vimc_deb_device { +struct vimc_debayer_device { struct vimc_ent_device ved; struct v4l2_subdev sd; /* The active format */ struct v4l2_mbus_framefmt sink_fmt; u32 src_code; - void (*set_rgb_src)(struct vimc_deb_device *vdeb, unsigned int lin, - unsigned int col, unsigned int rgb[3]); + void (*set_rgb_src)(struct vimc_debayer_device *vdebayer, + unsigned int lin, unsigned int col, + unsigned int rgb[3]); /* Values calculated when the stream starts */ u8 *src_frame; - const struct vimc_deb_pix_map *sink_pix_map; + const struct vimc_debayer_pix_map *sink_pix_map; unsigned int sink_bpp; unsigned int mean_win_size; struct v4l2_ctrl_handler hdl; @@ -51,7 +52,7 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = { .colorspace = V4L2_COLORSPACE_SRGB, }; -static const u32 vimc_deb_src_mbus_codes[] = { +static const u32 vimc_debayer_src_mbus_codes[] = { MEDIA_BUS_FMT_GBR888_1X24, MEDIA_BUS_FMT_BGR888_1X24, MEDIA_BUS_FMT_BGR888_3X8, @@ -64,95 +65,95 @@ static const u32 vimc_deb_src_mbus_codes[] = { MEDIA_BUS_FMT_RGB888_1X32_PADHI, }; -static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { +static const struct vimc_debayer_pix_map vimc_debayer_pix_map_list[] = { { .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } + .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } } }, { .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE }, + { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED }, + { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } } }, { .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } + .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } } }, { .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE }, + { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED }, + { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } } }, { .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } + .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } } }, { .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE }, + { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED }, + { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } } }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN }, + { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } } }, }; -static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code(u32 code) +static const struct vimc_debayer_pix_map *vimc_debayer_pix_map_by_code(u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(vimc_deb_pix_map_list); i++) - if (vimc_deb_pix_map_list[i].code == code) - return &vimc_deb_pix_map_list[i]; + for (i = 0; i < ARRAY_SIZE(vimc_debayer_pix_map_list); i++) + if (vimc_debayer_pix_map_list[i].code == code) + return &vimc_debayer_pix_map_list[i]; return NULL; } -static bool vimc_deb_src_code_is_valid(u32 code) +static bool vimc_debayer_src_code_is_valid(u32 code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(vimc_deb_src_mbus_codes); i++) - if (vimc_deb_src_mbus_codes[i] == code) + for (i = 0; i < ARRAY_SIZE(vimc_debayer_src_mbus_codes); i++) + if (vimc_debayer_src_mbus_codes[i] == code) return true; return false; } -static int vimc_deb_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_debayer_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; unsigned int i; @@ -162,45 +163,45 @@ static int vimc_deb_init_cfg(struct v4l2_subdev *sd, for (i = 1; i < sd->entity.num_pads; i++) { mf = v4l2_subdev_get_try_format(sd, sd_state, i); *mf = sink_fmt_default; - mf->code = vdeb->src_code; + mf->code = vdebayer->src_code; } return 0; } -static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) +static int vimc_debayer_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) { if (VIMC_IS_SRC(code->pad)) { - if (code->index >= ARRAY_SIZE(vimc_deb_src_mbus_codes)) + if (code->index >= ARRAY_SIZE(vimc_debayer_src_mbus_codes)) return -EINVAL; - code->code = vimc_deb_src_mbus_codes[code->index]; + code->code = vimc_debayer_src_mbus_codes[code->index]; } else { - if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list)) + if (code->index >= ARRAY_SIZE(vimc_debayer_pix_map_list)) return -EINVAL; - code->code = vimc_deb_pix_map_list[code->index].code; + code->code = vimc_debayer_pix_map_list[code->index].code; } return 0; } -static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) +static int vimc_debayer_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) { if (fse->index) return -EINVAL; if (VIMC_IS_SINK(fse->pad)) { - const struct vimc_deb_pix_map *vpix = - vimc_deb_pix_map_by_code(fse->code); + const struct vimc_debayer_pix_map *vpix = + vimc_debayer_pix_map_by_code(fse->code); if (!vpix) return -EINVAL; - } else if (!vimc_deb_src_code_is_valid(fse->code)) { + } else if (!vimc_debayer_src_code_is_valid(fse->code)) { return -EINVAL; } @@ -212,30 +213,30 @@ static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int vimc_deb_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) +static int vimc_debayer_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); /* Get the current sink format */ fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? *v4l2_subdev_get_try_format(sd, sd_state, 0) : - vdeb->sink_fmt; + vdebayer->sink_fmt; /* Set the right code for the source pad */ if (VIMC_IS_SRC(fmt->pad)) - fmt->format.code = vdeb->src_code; + fmt->format.code = vdebayer->src_code; return 0; } -static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) +static void vimc_debayer_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) { - const struct vimc_deb_pix_map *vpix; + const struct vimc_debayer_pix_map *vpix; /* Don't accept a code that is not on the debayer table */ - vpix = vimc_deb_pix_map_by_code(fmt->code); + vpix = vimc_debayer_pix_map_by_code(fmt->code); if (!vpix) fmt->code = sink_fmt_default.code; @@ -250,21 +251,21 @@ static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) vimc_colorimetry_clamp(fmt); } -static int vimc_deb_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) +static int vimc_debayer_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; u32 *src_code; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vdeb->src_frame) + if (vdebayer->src_frame) return -EBUSY; - sink_fmt = &vdeb->sink_fmt; - src_code = &vdeb->src_code; + sink_fmt = &vdebayer->sink_fmt; + src_code = &vdebayer->src_code; } else { sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0); src_code = &v4l2_subdev_get_try_format(sd, sd_state, 1)->code; @@ -279,17 +280,17 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, fmt->format = *sink_fmt; - if (vimc_deb_src_code_is_valid(code)) + if (vimc_debayer_src_code_is_valid(code)) *src_code = code; fmt->format.code = *src_code; } else { /* Set the new format in the sink pad */ - vimc_deb_adjust_sink_fmt(&fmt->format); + vimc_debayer_adjust_sink_fmt(&fmt->format); - dev_dbg(vdeb->ved.dev, "%s: sink format update: " + dev_dbg(vdebayer->ved.dev, "%s: sink format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb->sd.name, + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdebayer->sd.name, /* old */ sink_fmt->width, sink_fmt->height, sink_fmt->code, sink_fmt->colorspace, sink_fmt->quantization, @@ -305,97 +306,97 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { - .init_cfg = vimc_deb_init_cfg, - .enum_mbus_code = vimc_deb_enum_mbus_code, - .enum_frame_size = vimc_deb_enum_frame_size, - .get_fmt = vimc_deb_get_fmt, - .set_fmt = vimc_deb_set_fmt, +static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = { + .init_cfg = vimc_debayer_init_cfg, + .enum_mbus_code = vimc_debayer_enum_mbus_code, + .enum_frame_size = vimc_debayer_enum_frame_size, + .get_fmt = vimc_debayer_get_fmt, + .set_fmt = vimc_debayer_set_fmt, }; -static void vimc_deb_process_rgb_frame(struct vimc_deb_device *vdeb, - unsigned int lin, - unsigned int col, - unsigned int rgb[3]) +static void vimc_debayer_process_rgb_frame(struct vimc_debayer_device *vdebayer, + unsigned int lin, + unsigned int col, + unsigned int rgb[3]) { const struct vimc_pix_map *vpix; unsigned int i, index; - vpix = vimc_pix_map_by_code(vdeb->src_code); - index = VIMC_FRAME_INDEX(lin, col, vdeb->sink_fmt.width, 3); + vpix = vimc_pix_map_by_code(vdebayer->src_code); + index = VIMC_FRAME_INDEX(lin, col, vdebayer->sink_fmt.width, 3); for (i = 0; i < 3; i++) { switch (vpix->pixelformat) { case V4L2_PIX_FMT_RGB24: - vdeb->src_frame[index + i] = rgb[i]; + vdebayer->src_frame[index + i] = rgb[i]; break; case V4L2_PIX_FMT_BGR24: - vdeb->src_frame[index + i] = rgb[2 - i]; + vdebayer->src_frame[index + i] = rgb[2 - i]; break; } } } -static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) +static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd); if (enable) { const struct vimc_pix_map *vpix; unsigned int frame_size; - if (vdeb->src_frame) + if (vdebayer->src_frame) return 0; /* Calculate the frame size of the source pad */ - vpix = vimc_pix_map_by_code(vdeb->src_code); - frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * + vpix = vimc_pix_map_by_code(vdebayer->src_code); + frame_size = vdebayer->sink_fmt.width * vdebayer->sink_fmt.height * vpix->bpp; /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code); - vdeb->sink_bpp = vpix->bpp; + vpix = vimc_pix_map_by_code(vdebayer->sink_fmt.code); + vdebayer->sink_bpp = vpix->bpp; /* Get the corresponding pixel map from the table */ - vdeb->sink_pix_map = - vimc_deb_pix_map_by_code(vdeb->sink_fmt.code); + vdebayer->sink_pix_map = + vimc_debayer_pix_map_by_code(vdebayer->sink_fmt.code); /* * Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory */ - vdeb->src_frame = vmalloc(frame_size); - if (!vdeb->src_frame) + vdebayer->src_frame = vmalloc(frame_size); + if (!vdebayer->src_frame) return -ENOMEM; } else { - if (!vdeb->src_frame) + if (!vdebayer->src_frame) return 0; - vfree(vdeb->src_frame); - vdeb->src_frame = NULL; + vfree(vdebayer->src_frame); + vdebayer->src_frame = NULL; } return 0; } -static const struct v4l2_subdev_core_ops vimc_deb_core_ops = { +static const struct v4l2_subdev_core_ops vimc_debayer_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; -static const struct v4l2_subdev_video_ops vimc_deb_video_ops = { - .s_stream = vimc_deb_s_stream, +static const struct v4l2_subdev_video_ops vimc_debayer_video_ops = { + .s_stream = vimc_debayer_s_stream, }; -static const struct v4l2_subdev_ops vimc_deb_ops = { - .core = &vimc_deb_core_ops, - .pad = &vimc_deb_pad_ops, - .video = &vimc_deb_video_ops, +static const struct v4l2_subdev_ops vimc_debayer_ops = { + .core = &vimc_debayer_core_ops, + .pad = &vimc_debayer_pad_ops, + .video = &vimc_debayer_video_ops, }; -static unsigned int vimc_deb_get_val(const u8 *bytes, - const unsigned int n_bytes) +static unsigned int vimc_debayer_get_val(const u8 *bytes, + const unsigned int n_bytes) { unsigned int i; unsigned int acc = 0; @@ -406,11 +407,11 @@ static unsigned int vimc_deb_get_val(const u8 *bytes, return acc; } -static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, - const u8 *frame, - const unsigned int lin, - const unsigned int col, - unsigned int rgb[3]) +static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer, + const u8 *frame, + const unsigned int lin, + const unsigned int col, + unsigned int rgb[3]) { unsigned int i, seek, wlin, wcol; unsigned int n_rgb[3] = {0, 0, 0}; @@ -423,13 +424,13 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, * the top left corner of the mean window (considering the current * pixel as the center) */ - seek = vdeb->mean_win_size / 2; + seek = vdebayer->mean_win_size / 2; /* Sum the values of the colors in the mean window */ - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n", - vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek); + vdebayer->sd.name, lin, col, vdebayer->sink_fmt.height, seek); /* * Iterate through all the lines in the mean window, start @@ -438,7 +439,7 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, * frame */ for (wlin = seek > lin ? 0 : lin - seek; - wlin < lin + seek + 1 && wlin < vdeb->sink_fmt.height; + wlin < lin + seek + 1 && wlin < vdebayer->sink_fmt.height; wlin++) { /* @@ -448,78 +449,80 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, * frame */ for (wcol = seek > col ? 0 : col - seek; - wcol < col + seek + 1 && wcol < vdeb->sink_fmt.width; + wcol < col + seek + 1 && wcol < vdebayer->sink_fmt.width; wcol++) { - enum vimc_deb_rgb_colors color; + enum vimc_debayer_rgb_colors color; unsigned int index; /* Check which color this pixel is */ - color = vdeb->sink_pix_map->order[wlin % 2][wcol % 2]; + color = vdebayer->sink_pix_map->order[wlin % 2][wcol % 2]; index = VIMC_FRAME_INDEX(wlin, wcol, - vdeb->sink_fmt.width, - vdeb->sink_bpp); + vdebayer->sink_fmt.width, + vdebayer->sink_bpp); - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n", - vdeb->sd.name, index, wlin, wcol, color); + vdebayer->sd.name, index, wlin, wcol, color); /* Get its value */ rgb[color] = rgb[color] + - vimc_deb_get_val(&frame[index], vdeb->sink_bpp); + vimc_debayer_get_val(&frame[index], + vdebayer->sink_bpp); /* Save how many values we already added */ n_rgb[color]++; - dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n", - vdeb->sd.name, rgb[color], n_rgb[color]); + dev_dbg(vdebayer->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n", + vdebayer->sd.name, rgb[color], n_rgb[color]); } } /* Calculate the mean */ for (i = 0; i < 3; i++) { - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n", - vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]); + vdebayer->sd.name, lin, col, i, rgb[i], n_rgb[i]); if (n_rgb[i]) rgb[i] = rgb[i] / n_rgb[i]; - dev_dbg(vdeb->ved.dev, + dev_dbg(vdebayer->ved.dev, "deb: %s: FINAL CALC: %dx%d Color %d, val %d\n", - vdeb->sd.name, lin, col, i, rgb[i]); + vdebayer->sd.name, lin, col, i, rgb[i]); } } -static void *vimc_deb_process_frame(struct vimc_ent_device *ved, - const void *sink_frame) +static void *vimc_debayer_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) { - struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, - ved); + struct vimc_debayer_device *vdebayer = + container_of(ved, struct vimc_debayer_device, ved); + unsigned int rgb[3]; unsigned int i, j; /* If the stream in this node is not active, just return */ - if (!vdeb->src_frame) + if (!vdebayer->src_frame) return ERR_PTR(-EINVAL); - for (i = 0; i < vdeb->sink_fmt.height; i++) - for (j = 0; j < vdeb->sink_fmt.width; j++) { - vimc_deb_calc_rgb_sink(vdeb, sink_frame, i, j, rgb); - vdeb->set_rgb_src(vdeb, i, j, rgb); + for (i = 0; i < vdebayer->sink_fmt.height; i++) + for (j = 0; j < vdebayer->sink_fmt.width; j++) { + vimc_debayer_calc_rgb_sink(vdebayer, sink_frame, i, j, rgb); + vdebayer->set_rgb_src(vdebayer, i, j, rgb); } - return vdeb->src_frame; + return vdebayer->src_frame; } -static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl) +static int vimc_debayer_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vimc_deb_device *vdeb = - container_of(ctrl->handler, struct vimc_deb_device, hdl); + struct vimc_debayer_device *vdebayer = + container_of(ctrl->handler, struct vimc_debayer_device, hdl); switch (ctrl->id) { case VIMC_CID_MEAN_WIN_SIZE: - vdeb->mean_win_size = ctrl->val; + vdebayer->mean_win_size = ctrl->val; break; default: return -EINVAL; @@ -527,29 +530,29 @@ static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = { - .s_ctrl = vimc_deb_s_ctrl, +static const struct v4l2_ctrl_ops vimc_debayer_ctrl_ops = { + .s_ctrl = vimc_debayer_s_ctrl, }; -static void vimc_deb_release(struct vimc_ent_device *ved) +static void vimc_debayer_release(struct vimc_ent_device *ved) { - struct vimc_deb_device *vdeb = - container_of(ved, struct vimc_deb_device, ved); + struct vimc_debayer_device *vdebayer = + container_of(ved, struct vimc_debayer_device, ved); - v4l2_ctrl_handler_free(&vdeb->hdl); - media_entity_cleanup(vdeb->ved.ent); - kfree(vdeb); + v4l2_ctrl_handler_free(&vdebayer->hdl); + media_entity_cleanup(vdebayer->ved.ent); + kfree(vdebayer); } -static const struct v4l2_ctrl_config vimc_deb_ctrl_class = { +static const struct v4l2_ctrl_config vimc_debayer_ctrl_class = { .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, .id = VIMC_CID_VIMC_CLASS, .name = "VIMC Controls", .type = V4L2_CTRL_TYPE_CTRL_CLASS, }; -static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = { - .ops = &vimc_deb_ctrl_ops, +static const struct v4l2_ctrl_config vimc_debayer_ctrl_mean_win_size = { + .ops = &vimc_debayer_ctrl_ops, .id = VIMC_CID_MEAN_WIN_SIZE, .name = "Debayer Mean Window Size", .type = V4L2_CTRL_TYPE_INTEGER, @@ -559,65 +562,65 @@ static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = { .def = 3, }; -static struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, - const char *vcfg_name) +static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc, + const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_deb_device *vdeb; + struct vimc_debayer_device *vdebayer; int ret; - /* Allocate the vdeb struct */ - vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL); - if (!vdeb) + /* Allocate the vdebayer struct */ + vdebayer = kzalloc(sizeof(*vdebayer), GFP_KERNEL); + if (!vdebayer) return ERR_PTR(-ENOMEM); /* Create controls: */ - v4l2_ctrl_handler_init(&vdeb->hdl, 2); - v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_class, NULL); - v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_mean_win_size, NULL); - vdeb->sd.ctrl_handler = &vdeb->hdl; - if (vdeb->hdl.error) { - ret = vdeb->hdl.error; - goto err_free_vdeb; + v4l2_ctrl_handler_init(&vdebayer->hdl, 2); + v4l2_ctrl_new_custom(&vdebayer->hdl, &vimc_debayer_ctrl_class, NULL); + v4l2_ctrl_new_custom(&vdebayer->hdl, &vimc_debayer_ctrl_mean_win_size, NULL); + vdebayer->sd.ctrl_handler = &vdebayer->hdl; + if (vdebayer->hdl.error) { + ret = vdebayer->hdl.error; + goto err_free_vdebayer; } /* Initialize ved and sd */ - vdeb->pads[0].flags = MEDIA_PAD_FL_SINK; - vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE; + vdebayer->pads[0].flags = MEDIA_PAD_FL_SINK; + vdebayer->pads[1].flags = MEDIA_PAD_FL_SOURCE; - ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, + ret = vimc_ent_sd_register(&vdebayer->ved, &vdebayer->sd, v4l2_dev, vcfg_name, MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, - vdeb->pads, &vimc_deb_ops); + vdebayer->pads, &vimc_debayer_ops); if (ret) goto err_free_hdl; - vdeb->ved.process_frame = vimc_deb_process_frame; - vdeb->ved.dev = vimc->mdev.dev; - vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def; + vdebayer->ved.process_frame = vimc_debayer_process_frame; + vdebayer->ved.dev = vimc->mdev.dev; + vdebayer->mean_win_size = vimc_debayer_ctrl_mean_win_size.def; /* Initialize the frame format */ - vdeb->sink_fmt = sink_fmt_default; + vdebayer->sink_fmt = sink_fmt_default; /* * TODO: Add support for more output formats, we only support * RGB888 for now * NOTE: the src format is always the same as the sink, except * for the code */ - vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24; - vdeb->set_rgb_src = vimc_deb_process_rgb_frame; + vdebayer->src_code = MEDIA_BUS_FMT_RGB888_1X24; + vdebayer->set_rgb_src = vimc_debayer_process_rgb_frame; - return &vdeb->ved; + return &vdebayer->ved; err_free_hdl: - v4l2_ctrl_handler_free(&vdeb->hdl); -err_free_vdeb: - kfree(vdeb); + v4l2_ctrl_handler_free(&vdebayer->hdl); +err_free_vdebayer: + kfree(vdebayer); return ERR_PTR(ret); } -struct vimc_ent_type vimc_deb_type = { - .add = vimc_deb_add, - .release = vimc_deb_release +struct vimc_ent_type vimc_debayer_type = { + .add = vimc_debayer_add, + .release = vimc_debayer_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-lens.c b/drivers/media/test-drivers/vimc/vimc-lens.c new file mode 100644 index 000000000000..3ce7f4b4d2cc --- /dev/null +++ b/drivers/media/test-drivers/vimc/vimc-lens.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-lens.c Virtual Media Controller Driver + * Copyright (C) 2022 Google, Inc + * Author: yunkec@google.com (Yunke Cao) + */ + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-subdev.h> + +#include "vimc-common.h" + +#define VIMC_LENS_MAX_FOCUS_POS 1023 +#define VIMC_LENS_MAX_FOCUS_STEP 1 + +struct vimc_lens_device { + struct vimc_ent_device ved; + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + u32 focus_absolute; +}; + +static const struct v4l2_subdev_core_ops vimc_lens_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops vimc_lens_ops = { + .core = &vimc_lens_core_ops +}; + +static int vimc_lens_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vimc_lens_device *vlens = + container_of(ctrl->handler, struct vimc_lens_device, hdl); + if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { + vlens->focus_absolute = ctrl->val; + return 0; + } + return -EINVAL; +} + +static const struct v4l2_ctrl_ops vimc_lens_ctrl_ops = { + .s_ctrl = vimc_lens_s_ctrl, +}; + +static struct vimc_ent_device *vimc_lens_add(struct vimc_device *vimc, + const char *vcfg_name) +{ + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; + struct vimc_lens_device *vlens; + int ret; + + /* Allocate the vlens struct */ + vlens = kzalloc(sizeof(*vlens), GFP_KERNEL); + if (!vlens) + return ERR_PTR(-ENOMEM); + + v4l2_ctrl_handler_init(&vlens->hdl, 1); + + v4l2_ctrl_new_std(&vlens->hdl, &vimc_lens_ctrl_ops, + V4L2_CID_FOCUS_ABSOLUTE, 0, + VIMC_LENS_MAX_FOCUS_POS, VIMC_LENS_MAX_FOCUS_STEP, 0); + vlens->sd.ctrl_handler = &vlens->hdl; + if (vlens->hdl.error) { + ret = vlens->hdl.error; + goto err_free_vlens; + } + vlens->ved.dev = vimc->mdev.dev; + + ret = vimc_ent_sd_register(&vlens->ved, &vlens->sd, v4l2_dev, + vcfg_name, MEDIA_ENT_F_LENS, 0, + NULL, &vimc_lens_ops); + if (ret) + goto err_free_hdl; + + return &vlens->ved; + +err_free_hdl: + v4l2_ctrl_handler_free(&vlens->hdl); +err_free_vlens: + kfree(vlens); + + return ERR_PTR(ret); +} + +static void vimc_lens_release(struct vimc_ent_device *ved) +{ + struct vimc_lens_device *vlens = + container_of(ved, struct vimc_lens_device, ved); + + v4l2_ctrl_handler_free(&vlens->hdl); + media_entity_cleanup(vlens->ved.ent); + kfree(vlens); +} + +struct vimc_ent_type vimc_lens_type = { + .add = vimc_lens_add, + .release = vimc_lens_release +}; diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c index 820b8f5b502f..b671774e2784 100644 --- a/drivers/media/test-drivers/vimc/vimc-scaler.c +++ b/drivers/media/test-drivers/vimc/vimc-scaler.c @@ -16,14 +16,14 @@ /* Pad identifier */ enum vic_sca_pad { - VIMC_SCA_SINK = 0, - VIMC_SCA_SRC = 1, + VIMC_SCALER_SINK = 0, + VIMC_SCALER_SRC = 1, }; -#define VIMC_SCA_FMT_WIDTH_DEFAULT 640 -#define VIMC_SCA_FMT_HEIGHT_DEFAULT 480 +#define VIMC_SCALER_FMT_WIDTH_DEFAULT 640 +#define VIMC_SCALER_FMT_HEIGHT_DEFAULT 480 -struct vimc_sca_device { +struct vimc_scaler_device { struct vimc_ent_device ved; struct v4l2_subdev sd; struct v4l2_rect crop_rect; @@ -36,16 +36,16 @@ struct vimc_sca_device { }; static const struct v4l2_mbus_framefmt fmt_default = { - .width = VIMC_SCA_FMT_WIDTH_DEFAULT, - .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, + .width = VIMC_SCALER_FMT_WIDTH_DEFAULT, + .height = VIMC_SCALER_FMT_HEIGHT_DEFAULT, .code = MEDIA_BUS_FMT_RGB888_1X24, .field = V4L2_FIELD_NONE, .colorspace = V4L2_COLORSPACE_SRGB, }; static const struct v4l2_rect crop_rect_default = { - .width = VIMC_SCA_FMT_WIDTH_DEFAULT, - .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, + .width = VIMC_SCALER_FMT_WIDTH_DEFAULT, + .height = VIMC_SCALER_FMT_HEIGHT_DEFAULT, .top = 0, .left = 0, }; @@ -58,7 +58,7 @@ static const struct v4l2_rect crop_rect_min = { }; static struct v4l2_rect -vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) +vimc_scaler_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) { /* Get the crop bounds to clamp the crop rectangle correctly */ struct v4l2_rect r = { @@ -70,7 +70,7 @@ vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) return r; } -static int vimc_sca_init_cfg(struct v4l2_subdev *sd, +static int vimc_scaler_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *mf; @@ -82,13 +82,13 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd, *mf = fmt_default; } - r = v4l2_subdev_get_try_crop(sd, sd_state, VIMC_SCA_SINK); + r = v4l2_subdev_get_try_crop(sd, sd_state, VIMC_SCALER_SINK); *r = crop_rect_default; return 0; } -static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, +static int vimc_scaler_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { @@ -109,7 +109,7 @@ static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, +static int vimc_scaler_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { @@ -133,57 +133,57 @@ static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, } static struct v4l2_mbus_framefmt * -vimc_sca_pad_format(struct vimc_sca_device *vsca, +vimc_scaler_pad_format(struct vimc_scaler_device *vscaler, struct v4l2_subdev_state *sd_state, u32 pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&vsca->sd, sd_state, pad); + return v4l2_subdev_get_try_format(&vscaler->sd, sd_state, pad); else - return &vsca->fmt[pad]; + return &vscaler->fmt[pad]; } static struct v4l2_rect * -vimc_sca_pad_crop(struct vimc_sca_device *vsca, +vimc_scaler_pad_crop(struct vimc_scaler_device *vscaler, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&vsca->sd, sd_state, - VIMC_SCA_SINK); + return v4l2_subdev_get_try_crop(&vscaler->sd, sd_state, + VIMC_SCALER_SINK); else - return &vsca->crop_rect; + return &vscaler->crop_rect; } -static int vimc_sca_get_fmt(struct v4l2_subdev *sd, +static int vimc_scaler_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); - format->format = *vimc_sca_pad_format(vsca, sd_state, format->pad, + format->format = *vimc_scaler_pad_format(vscaler, sd_state, format->pad, format->which); return 0; } -static int vimc_sca_set_fmt(struct v4l2_subdev *sd, +static int vimc_scaler_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *fmt; /* Do not change the active format while stream is on */ - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsca->src_frame) + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame) return -EBUSY; - fmt = vimc_sca_pad_format(vsca, sd_state, format->pad, format->which); + fmt = vimc_scaler_pad_format(vscaler, sd_state, format->pad, format->which); /* * The media bus code and colorspace can only be changed on the sink * pad, the source pad only follows. */ - if (format->pad == VIMC_SCA_SINK) { + if (format->pad == VIMC_SCALER_SINK) { const struct vimc_pix_map *vpix; /* Only accept code in the pix map table in non bayer format. */ @@ -211,17 +211,17 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, * Propagate the sink pad format to the crop rectangle and the source * pad. */ - if (format->pad == VIMC_SCA_SINK) { + if (format->pad == VIMC_SCALER_SINK) { struct v4l2_mbus_framefmt *src_fmt; struct v4l2_rect *crop; - crop = vimc_sca_pad_crop(vsca, sd_state, format->which); + crop = vimc_scaler_pad_crop(vscaler, sd_state, format->which); crop->width = fmt->width; crop->height = fmt->height; crop->top = 0; crop->left = 0; - src_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SRC, + src_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SRC, format->which); *src_fmt = *fmt; } @@ -231,11 +231,11 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, return 0; } -static int vimc_sca_get_selection(struct v4l2_subdev *sd, +static int vimc_scaler_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; if (VIMC_IS_SRC(sel->pad)) @@ -243,12 +243,12 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *vimc_sca_pad_crop(vsca, sd_state, sel->which); + sel->r = *vimc_scaler_pad_crop(vscaler, sd_state, sel->which); break; case V4L2_SEL_TGT_CROP_BOUNDS: - sink_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SINK, + sink_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SINK, sel->which); - sel->r = vimc_sca_get_crop_bound_sink(sink_fmt); + sel->r = vimc_scaler_get_crop_bound_sink(sink_fmt); break; default: return -EINVAL; @@ -257,22 +257,22 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd, return 0; } -static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r, +static void vimc_scaler_adjust_sink_crop(struct v4l2_rect *r, const struct v4l2_mbus_framefmt *sink_fmt) { const struct v4l2_rect sink_rect = - vimc_sca_get_crop_bound_sink(sink_fmt); + vimc_scaler_get_crop_bound_sink(sink_fmt); /* Disallow rectangles smaller than the minimal one. */ v4l2_rect_set_min_size(r, &crop_rect_min); v4l2_rect_map_inside(r, &sink_rect); } -static int vimc_sca_set_selection(struct v4l2_subdev *sd, +static int vimc_scaler_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *crop_rect; @@ -280,165 +280,165 @@ static int vimc_sca_set_selection(struct v4l2_subdev *sd, if (VIMC_IS_SRC(sel->pad) || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsca->src_frame) + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame) return -EBUSY; - crop_rect = vimc_sca_pad_crop(vsca, sd_state, sel->which); - sink_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SINK, + crop_rect = vimc_scaler_pad_crop(vscaler, sd_state, sel->which); + sink_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SINK, sel->which); - vimc_sca_adjust_sink_crop(&sel->r, sink_fmt); + vimc_scaler_adjust_sink_crop(&sel->r, sink_fmt); *crop_rect = sel->r; return 0; } -static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { - .init_cfg = vimc_sca_init_cfg, - .enum_mbus_code = vimc_sca_enum_mbus_code, - .enum_frame_size = vimc_sca_enum_frame_size, - .get_fmt = vimc_sca_get_fmt, - .set_fmt = vimc_sca_set_fmt, - .get_selection = vimc_sca_get_selection, - .set_selection = vimc_sca_set_selection, +static const struct v4l2_subdev_pad_ops vimc_scaler_pad_ops = { + .init_cfg = vimc_scaler_init_cfg, + .enum_mbus_code = vimc_scaler_enum_mbus_code, + .enum_frame_size = vimc_scaler_enum_frame_size, + .get_fmt = vimc_scaler_get_fmt, + .set_fmt = vimc_scaler_set_fmt, + .get_selection = vimc_scaler_get_selection, + .set_selection = vimc_scaler_set_selection, }; -static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) +static int vimc_scaler_s_stream(struct v4l2_subdev *sd, int enable) { - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd); if (enable) { const struct vimc_pix_map *vpix; unsigned int frame_size; - if (vsca->src_frame) + if (vscaler->src_frame) return 0; /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vsca->fmt[VIMC_SCA_SINK].code); - vsca->bpp = vpix->bpp; + vpix = vimc_pix_map_by_code(vscaler->fmt[VIMC_SCALER_SINK].code); + vscaler->bpp = vpix->bpp; /* Calculate the frame size of the source pad */ - frame_size = vsca->fmt[VIMC_SCA_SRC].width - * vsca->fmt[VIMC_SCA_SRC].height * vsca->bpp; + frame_size = vscaler->fmt[VIMC_SCALER_SRC].width + * vscaler->fmt[VIMC_SCALER_SRC].height * vscaler->bpp; /* Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory */ - vsca->src_frame = vmalloc(frame_size); - if (!vsca->src_frame) + vscaler->src_frame = vmalloc(frame_size); + if (!vscaler->src_frame) return -ENOMEM; } else { - if (!vsca->src_frame) + if (!vscaler->src_frame) return 0; - vfree(vsca->src_frame); - vsca->src_frame = NULL; + vfree(vscaler->src_frame); + vscaler->src_frame = NULL; } return 0; } -static const struct v4l2_subdev_video_ops vimc_sca_video_ops = { - .s_stream = vimc_sca_s_stream, +static const struct v4l2_subdev_video_ops vimc_scaler_video_ops = { + .s_stream = vimc_scaler_s_stream, }; -static const struct v4l2_subdev_ops vimc_sca_ops = { - .pad = &vimc_sca_pad_ops, - .video = &vimc_sca_video_ops, +static const struct v4l2_subdev_ops vimc_scaler_ops = { + .pad = &vimc_scaler_pad_ops, + .video = &vimc_scaler_video_ops, }; -static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca, +static void vimc_scaler_fill_src_frame(const struct vimc_scaler_device *const vscaler, const u8 *const sink_frame) { - const struct v4l2_mbus_framefmt *src_fmt = &vsca->fmt[VIMC_SCA_SRC]; - const struct v4l2_rect *r = &vsca->crop_rect; - unsigned int snk_width = vsca->fmt[VIMC_SCA_SINK].width; + const struct v4l2_mbus_framefmt *src_fmt = &vscaler->fmt[VIMC_SCALER_SRC]; + const struct v4l2_rect *r = &vscaler->crop_rect; + unsigned int snk_width = vscaler->fmt[VIMC_SCALER_SINK].width; unsigned int src_x, src_y; - u8 *walker = vsca->src_frame; + u8 *walker = vscaler->src_frame; /* Set each pixel at the src_frame to its sink_frame equivalent */ for (src_y = 0; src_y < src_fmt->height; src_y++) { unsigned int snk_y, y_offset; snk_y = (src_y * r->height) / src_fmt->height + r->top; - y_offset = snk_y * snk_width * vsca->bpp; + y_offset = snk_y * snk_width * vscaler->bpp; for (src_x = 0; src_x < src_fmt->width; src_x++) { unsigned int snk_x, x_offset, index; snk_x = (src_x * r->width) / src_fmt->width + r->left; - x_offset = snk_x * vsca->bpp; + x_offset = snk_x * vscaler->bpp; index = y_offset + x_offset; - memcpy(walker, &sink_frame[index], vsca->bpp); - walker += vsca->bpp; + memcpy(walker, &sink_frame[index], vscaler->bpp); + walker += vscaler->bpp; } } } -static void *vimc_sca_process_frame(struct vimc_ent_device *ved, +static void *vimc_scaler_process_frame(struct vimc_ent_device *ved, const void *sink_frame) { - struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + struct vimc_scaler_device *vscaler = container_of(ved, struct vimc_scaler_device, ved); /* If the stream in this node is not active, just return */ - if (!vsca->src_frame) + if (!vscaler->src_frame) return ERR_PTR(-EINVAL); - vimc_sca_fill_src_frame(vsca, sink_frame); + vimc_scaler_fill_src_frame(vscaler, sink_frame); - return vsca->src_frame; + return vscaler->src_frame; }; -static void vimc_sca_release(struct vimc_ent_device *ved) +static void vimc_scaler_release(struct vimc_ent_device *ved) { - struct vimc_sca_device *vsca = - container_of(ved, struct vimc_sca_device, ved); + struct vimc_scaler_device *vscaler = + container_of(ved, struct vimc_scaler_device, ved); - media_entity_cleanup(vsca->ved.ent); - kfree(vsca); + media_entity_cleanup(vscaler->ved.ent); + kfree(vscaler); } -static struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, +static struct vimc_ent_device *vimc_scaler_add(struct vimc_device *vimc, const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_sca_device *vsca; + struct vimc_scaler_device *vscaler; int ret; - /* Allocate the vsca struct */ - vsca = kzalloc(sizeof(*vsca), GFP_KERNEL); - if (!vsca) + /* Allocate the vscaler struct */ + vscaler = kzalloc(sizeof(*vscaler), GFP_KERNEL); + if (!vscaler) return ERR_PTR(-ENOMEM); /* Initialize ved and sd */ - vsca->pads[VIMC_SCA_SINK].flags = MEDIA_PAD_FL_SINK; - vsca->pads[VIMC_SCA_SRC].flags = MEDIA_PAD_FL_SOURCE; + vscaler->pads[VIMC_SCALER_SINK].flags = MEDIA_PAD_FL_SINK; + vscaler->pads[VIMC_SCALER_SRC].flags = MEDIA_PAD_FL_SOURCE; - ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, + ret = vimc_ent_sd_register(&vscaler->ved, &vscaler->sd, v4l2_dev, vcfg_name, MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, - vsca->pads, &vimc_sca_ops); + vscaler->pads, &vimc_scaler_ops); if (ret) { - kfree(vsca); + kfree(vscaler); return ERR_PTR(ret); } - vsca->ved.process_frame = vimc_sca_process_frame; - vsca->ved.dev = vimc->mdev.dev; + vscaler->ved.process_frame = vimc_scaler_process_frame; + vscaler->ved.dev = vimc->mdev.dev; /* Initialize the frame format */ - vsca->fmt[VIMC_SCA_SINK] = fmt_default; - vsca->fmt[VIMC_SCA_SRC] = fmt_default; + vscaler->fmt[VIMC_SCALER_SINK] = fmt_default; + vscaler->fmt[VIMC_SCALER_SRC] = fmt_default; /* Initialize the crop selection */ - vsca->crop_rect = crop_rect_default; + vscaler->crop_rect = crop_rect_default; - return &vsca->ved; + return &vscaler->ved; } -struct vimc_ent_type vimc_sca_type = { - .add = vimc_sca_add, - .release = vimc_sca_release +struct vimc_ent_type vimc_scaler_type = { + .add = vimc_scaler_add, + .release = vimc_scaler_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c index 74ab79cadb5d..41a3dce2d714 100644 --- a/drivers/media/test-drivers/vimc/vimc-sensor.c +++ b/drivers/media/test-drivers/vimc/vimc-sensor.c @@ -14,18 +14,18 @@ #include "vimc-common.h" -enum vimc_sen_osd_mode { - VIMC_SEN_OSD_SHOW_ALL = 0, - VIMC_SEN_OSD_SHOW_COUNTERS = 1, - VIMC_SEN_OSD_SHOW_NONE = 2 +enum vimc_sensor_osd_mode { + VIMC_SENSOR_OSD_SHOW_ALL = 0, + VIMC_SENSOR_OSD_SHOW_COUNTERS = 1, + VIMC_SENSOR_OSD_SHOW_NONE = 2 }; -struct vimc_sen_device { +struct vimc_sensor_device { struct vimc_ent_device ved; struct v4l2_subdev sd; struct tpg_data tpg; u8 *frame; - enum vimc_sen_osd_mode osd_value; + enum vimc_sensor_osd_mode osd_value; u64 start_stream_ts; /* The active format */ struct v4l2_mbus_framefmt mbus_format; @@ -41,8 +41,8 @@ static const struct v4l2_mbus_framefmt fmt_default = { .colorspace = V4L2_COLORSPACE_SRGB, }; -static int vimc_sen_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) +static int vimc_sensor_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { unsigned int i; @@ -56,9 +56,9 @@ static int vimc_sen_init_cfg(struct v4l2_subdev *sd, return 0; } -static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) +static int vimc_sensor_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) { u32 mbus_code = vimc_mbus_code_by_index(code->index); @@ -70,9 +70,9 @@ static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) +static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) { const struct vimc_pix_map *vpix; @@ -92,39 +92,39 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, return 0; } -static int vimc_sen_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) +static int vimc_sensor_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) { - struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); + struct vimc_sensor_device *vsensor = + container_of(sd, struct vimc_sensor_device, sd); fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) : - vsen->mbus_format; + vsensor->mbus_format; return 0; } -static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) +static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor) { const struct vimc_pix_map *vpix = - vimc_pix_map_by_code(vsen->mbus_format.code); + vimc_pix_map_by_code(vsensor->mbus_format.code); - tpg_reset_source(&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height, vsen->mbus_format.field); - tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp); - tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); - tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); + tpg_reset_source(&vsensor->tpg, vsensor->mbus_format.width, + vsensor->mbus_format.height, vsensor->mbus_format.field); + tpg_s_bytesperline(&vsensor->tpg, 0, vsensor->mbus_format.width * vpix->bpp); + tpg_s_buf_height(&vsensor->tpg, vsensor->mbus_format.height); + tpg_s_fourcc(&vsensor->tpg, vpix->pixelformat); /* TODO: add support for V4L2_FIELD_ALTERNATE */ - tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false); - tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace); - tpg_s_ycbcr_enc(&vsen->tpg, vsen->mbus_format.ycbcr_enc); - tpg_s_quantization(&vsen->tpg, vsen->mbus_format.quantization); - tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); + tpg_s_field(&vsensor->tpg, vsensor->mbus_format.field, false); + tpg_s_colorspace(&vsensor->tpg, vsensor->mbus_format.colorspace); + tpg_s_ycbcr_enc(&vsensor->tpg, vsensor->mbus_format.ycbcr_enc); + tpg_s_quantization(&vsensor->tpg, vsensor->mbus_format.quantization); + tpg_s_xfer_func(&vsensor->tpg, vsensor->mbus_format.xfer_func); } -static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) +static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt) { const struct vimc_pix_map *vpix; @@ -145,29 +145,29 @@ static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) vimc_colorimetry_clamp(fmt); } -static int vimc_sen_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) +static int vimc_sensor_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) { - struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd); + struct vimc_sensor_device *vsensor = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vsen->frame) + if (vsensor->frame) return -EBUSY; - mf = &vsen->mbus_format; + mf = &vsensor->mbus_format; } else { mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); } /* Set the new format */ - vimc_sen_adjust_fmt(&fmt->format); + vimc_sensor_adjust_fmt(&fmt->format); - dev_dbg(vsen->ved.dev, "%s: format update: " + dev_dbg(vsensor->ved.dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name, + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsensor->sd.name, /* old */ mf->width, mf->height, mf->code, mf->colorspace, mf->quantization, @@ -182,146 +182,147 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { - .init_cfg = vimc_sen_init_cfg, - .enum_mbus_code = vimc_sen_enum_mbus_code, - .enum_frame_size = vimc_sen_enum_frame_size, - .get_fmt = vimc_sen_get_fmt, - .set_fmt = vimc_sen_set_fmt, +static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = { + .init_cfg = vimc_sensor_init_cfg, + .enum_mbus_code = vimc_sensor_enum_mbus_code, + .enum_frame_size = vimc_sensor_enum_frame_size, + .get_fmt = vimc_sensor_get_fmt, + .set_fmt = vimc_sensor_set_fmt, }; -static void *vimc_sen_process_frame(struct vimc_ent_device *ved, - const void *sink_frame) +static void *vimc_sensor_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) { - struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, - ved); + struct vimc_sensor_device *vsensor = + container_of(ved, struct vimc_sensor_device, ved); + const unsigned int line_height = 16; u8 *basep[TPG_MAX_PLANES][2]; unsigned int line = 1; char str[100]; - tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); - tpg_calc_text_basep(&vsen->tpg, basep, 0, vsen->frame); - switch (vsen->osd_value) { - case VIMC_SEN_OSD_SHOW_ALL: { - const char *order = tpg_g_color_order(&vsen->tpg); + tpg_fill_plane_buffer(&vsensor->tpg, 0, 0, vsensor->frame); + tpg_calc_text_basep(&vsensor->tpg, basep, 0, vsensor->frame); + switch (vsensor->osd_value) { + case VIMC_SENSOR_OSD_SHOW_ALL: { + const char *order = tpg_g_color_order(&vsensor->tpg); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, order); snprintf(str, sizeof(str), "brightness %3d, contrast %3d, saturation %3d, hue %d ", - vsen->tpg.brightness, - vsen->tpg.contrast, - vsen->tpg.saturation, - vsen->tpg.hue); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); + vsensor->tpg.brightness, + vsensor->tpg.contrast, + vsensor->tpg.saturation, + vsensor->tpg.hue); + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), "sensor size: %dx%d", - vsen->mbus_format.width, - vsen->mbus_format.height); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); + vsensor->mbus_format.width, + vsensor->mbus_format.height); + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); fallthrough; } - case VIMC_SEN_OSD_SHOW_COUNTERS: { + case VIMC_SENSOR_OSD_SHOW_COUNTERS: { unsigned int ms; - ms = div_u64(ktime_get_ns() - vsen->start_stream_ts, 1000000); + ms = div_u64(ktime_get_ns() - vsensor->start_stream_ts, 1000000); snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d", (ms / (60 * 60 * 1000)) % 24, (ms / (60 * 1000)) % 60, (ms / 1000) % 60, ms % 1000); - tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str); break; } - case VIMC_SEN_OSD_SHOW_NONE: + case VIMC_SENSOR_OSD_SHOW_NONE: default: break; } - return vsen->frame; + return vsensor->frame; } -static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) +static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable) { - struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); + struct vimc_sensor_device *vsensor = + container_of(sd, struct vimc_sensor_device, sd); if (enable) { const struct vimc_pix_map *vpix; unsigned int frame_size; - vsen->start_stream_ts = ktime_get_ns(); + vsensor->start_stream_ts = ktime_get_ns(); /* Calculate the frame size */ - vpix = vimc_pix_map_by_code(vsen->mbus_format.code); - frame_size = vsen->mbus_format.width * vpix->bpp * - vsen->mbus_format.height; + vpix = vimc_pix_map_by_code(vsensor->mbus_format.code); + frame_size = vsensor->mbus_format.width * vpix->bpp * + vsensor->mbus_format.height; /* * Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory */ - vsen->frame = vmalloc(frame_size); - if (!vsen->frame) + vsensor->frame = vmalloc(frame_size); + if (!vsensor->frame) return -ENOMEM; /* configure the test pattern generator */ - vimc_sen_tpg_s_format(vsen); + vimc_sensor_tpg_s_format(vsensor); } else { - vfree(vsen->frame); - vsen->frame = NULL; + vfree(vsensor->frame); + vsensor->frame = NULL; } return 0; } -static const struct v4l2_subdev_core_ops vimc_sen_core_ops = { +static const struct v4l2_subdev_core_ops vimc_sensor_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; -static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { - .s_stream = vimc_sen_s_stream, +static const struct v4l2_subdev_video_ops vimc_sensor_video_ops = { + .s_stream = vimc_sensor_s_stream, }; -static const struct v4l2_subdev_ops vimc_sen_ops = { - .core = &vimc_sen_core_ops, - .pad = &vimc_sen_pad_ops, - .video = &vimc_sen_video_ops, +static const struct v4l2_subdev_ops vimc_sensor_ops = { + .core = &vimc_sensor_core_ops, + .pad = &vimc_sensor_pad_ops, + .video = &vimc_sensor_video_ops, }; -static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl) +static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vimc_sen_device *vsen = - container_of(ctrl->handler, struct vimc_sen_device, hdl); + struct vimc_sensor_device *vsensor = + container_of(ctrl->handler, struct vimc_sensor_device, hdl); switch (ctrl->id) { case VIMC_CID_TEST_PATTERN: - tpg_s_pattern(&vsen->tpg, ctrl->val); + tpg_s_pattern(&vsensor->tpg, ctrl->val); break; case V4L2_CID_HFLIP: - tpg_s_hflip(&vsen->tpg, ctrl->val); + tpg_s_hflip(&vsensor->tpg, ctrl->val); break; case V4L2_CID_VFLIP: - tpg_s_vflip(&vsen->tpg, ctrl->val); + tpg_s_vflip(&vsensor->tpg, ctrl->val); break; case V4L2_CID_BRIGHTNESS: - tpg_s_brightness(&vsen->tpg, ctrl->val); + tpg_s_brightness(&vsensor->tpg, ctrl->val); break; case V4L2_CID_CONTRAST: - tpg_s_contrast(&vsen->tpg, ctrl->val); + tpg_s_contrast(&vsensor->tpg, ctrl->val); break; case V4L2_CID_HUE: - tpg_s_hue(&vsen->tpg, ctrl->val); + tpg_s_hue(&vsensor->tpg, ctrl->val); break; case V4L2_CID_SATURATION: - tpg_s_saturation(&vsen->tpg, ctrl->val); + tpg_s_saturation(&vsensor->tpg, ctrl->val); break; case VIMC_CID_OSD_TEXT_MODE: - vsen->osd_value = ctrl->val; + vsensor->osd_value = ctrl->val; break; default: return -EINVAL; @@ -329,31 +330,31 @@ static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = { - .s_ctrl = vimc_sen_s_ctrl, +static const struct v4l2_ctrl_ops vimc_sensor_ctrl_ops = { + .s_ctrl = vimc_sensor_s_ctrl, }; -static void vimc_sen_release(struct vimc_ent_device *ved) +static void vimc_sensor_release(struct vimc_ent_device *ved) { - struct vimc_sen_device *vsen = - container_of(ved, struct vimc_sen_device, ved); + struct vimc_sensor_device *vsensor = + container_of(ved, struct vimc_sensor_device, ved); - v4l2_ctrl_handler_free(&vsen->hdl); - tpg_free(&vsen->tpg); - media_entity_cleanup(vsen->ved.ent); - kfree(vsen); + v4l2_ctrl_handler_free(&vsensor->hdl); + tpg_free(&vsensor->tpg); + media_entity_cleanup(vsensor->ved.ent); + kfree(vsensor); } /* Image Processing Controls */ -static const struct v4l2_ctrl_config vimc_sen_ctrl_class = { +static const struct v4l2_ctrl_config vimc_sensor_ctrl_class = { .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, .id = VIMC_CID_VIMC_CLASS, .name = "VIMC Controls", .type = V4L2_CTRL_TYPE_CTRL_CLASS, }; -static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = { - .ops = &vimc_sen_ctrl_ops, +static const struct v4l2_ctrl_config vimc_sensor_ctrl_test_pattern = { + .ops = &vimc_sensor_ctrl_ops, .id = VIMC_CID_TEST_PATTERN, .name = "Test Pattern", .type = V4L2_CTRL_TYPE_MENU, @@ -368,8 +369,8 @@ static const char * const vimc_ctrl_osd_mode_strings[] = { NULL, }; -static const struct v4l2_ctrl_config vimc_sen_ctrl_osd_mode = { - .ops = &vimc_sen_ctrl_ops, +static const struct v4l2_ctrl_config vimc_sensor_ctrl_osd_mode = { + .ops = &vimc_sensor_ctrl_ops, .id = VIMC_CID_OSD_TEXT_MODE, .name = "Show Information", .type = V4L2_CTRL_TYPE_MENU, @@ -377,76 +378,76 @@ static const struct v4l2_ctrl_config vimc_sen_ctrl_osd_mode = { .qmenu = vimc_ctrl_osd_mode_strings, }; -static struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, - const char *vcfg_name) +static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc, + const char *vcfg_name) { struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_sen_device *vsen; + struct vimc_sensor_device *vsensor; int ret; - /* Allocate the vsen struct */ - vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); - if (!vsen) + /* Allocate the vsensor struct */ + vsensor = kzalloc(sizeof(*vsensor), GFP_KERNEL); + if (!vsensor) return ERR_PTR(-ENOMEM); - v4l2_ctrl_handler_init(&vsen->hdl, 4); + v4l2_ctrl_handler_init(&vsensor->hdl, 4); - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL); - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL); - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_osd_mode, NULL); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_class, NULL); + v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_test_pattern, NULL); + v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_osd_mode, NULL); + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_HUE, -128, 127, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops, V4L2_CID_SATURATION, 0, 255, 1, 128); - vsen->sd.ctrl_handler = &vsen->hdl; - if (vsen->hdl.error) { - ret = vsen->hdl.error; - goto err_free_vsen; + vsensor->sd.ctrl_handler = &vsensor->hdl; + if (vsensor->hdl.error) { + ret = vsensor->hdl.error; + goto err_free_vsensor; } /* Initialize the test pattern generator */ - tpg_init(&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH); + tpg_init(&vsensor->tpg, vsensor->mbus_format.width, + vsensor->mbus_format.height); + ret = tpg_alloc(&vsensor->tpg, VIMC_FRAME_MAX_WIDTH); if (ret) goto err_free_hdl; /* Initialize ved and sd */ - vsen->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, + vsensor->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = vimc_ent_sd_register(&vsensor->ved, &vsensor->sd, v4l2_dev, vcfg_name, - MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad, - &vimc_sen_ops); + MEDIA_ENT_F_CAM_SENSOR, 1, &vsensor->pad, + &vimc_sensor_ops); if (ret) goto err_free_tpg; - vsen->ved.process_frame = vimc_sen_process_frame; - vsen->ved.dev = vimc->mdev.dev; + vsensor->ved.process_frame = vimc_sensor_process_frame; + vsensor->ved.dev = vimc->mdev.dev; /* Initialize the frame format */ - vsen->mbus_format = fmt_default; + vsensor->mbus_format = fmt_default; - return &vsen->ved; + return &vsensor->ved; err_free_tpg: - tpg_free(&vsen->tpg); + tpg_free(&vsensor->tpg); err_free_hdl: - v4l2_ctrl_handler_free(&vsen->hdl); -err_free_vsen: - kfree(vsen); + v4l2_ctrl_handler_free(&vsensor->hdl); +err_free_vsensor: + kfree(vsensor); return ERR_PTR(ret); } -struct vimc_ent_type vimc_sen_type = { - .add = vimc_sen_add, - .release = vimc_sen_release +struct vimc_ent_type vimc_sensor_type = { + .add = vimc_sensor_add, + .release = vimc_sensor_release }; diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c index 65feb3c596db..807551a5143b 100644 --- a/drivers/media/test-drivers/vimc/vimc-streamer.c +++ b/drivers/media/test-drivers/vimc/vimc-streamer.c @@ -30,7 +30,7 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent) for (i = 0; i < ent->num_pads; i++) { if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE) continue; - pad = media_entity_remote_pad(&ent->pads[i]); + pad = media_pad_remote_pad_first(&ent->pads[i]); return pad ? pad->entity : NULL; } return NULL; diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c index e7516dc1227b..a78d676575bc 100644 --- a/drivers/media/test-drivers/vivid/vivid-ctrls.c +++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c @@ -34,6 +34,7 @@ #define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10) #define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11) #define VIVID_CID_RO_INTEGER (VIVID_CID_CUSTOM_BASE + 12) +#define VIVID_CID_U32_DYN_ARRAY (VIVID_CID_CUSTOM_BASE + 13) #define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) #define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) @@ -46,6 +47,7 @@ #define VIVID_CID_INSERT_SAV (VIVID_CID_VIVID_BASE + 6) #define VIVID_CID_INSERT_EAV (VIVID_CID_VIVID_BASE + 7) #define VIVID_CID_VBI_CAP_INTERLACED (VIVID_CID_VIVID_BASE + 8) +#define VIVID_CID_INSERT_HDMI_VIDEO_GUARD_BAND (VIVID_CID_VIVID_BASE + 9) #define VIVID_CID_HFLIP (VIVID_CID_VIVID_BASE + 20) #define VIVID_CID_VFLIP (VIVID_CID_VIVID_BASE + 21) @@ -189,6 +191,19 @@ static const struct v4l2_ctrl_config vivid_ctrl_u32_array = { .dims = { 1 }, }; +static const struct v4l2_ctrl_config vivid_ctrl_u32_dyn_array = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_U32_DYN_ARRAY, + .name = "U32 Dynamic Array", + .type = V4L2_CTRL_TYPE_U32, + .flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, + .def = 50, + .min = 10, + .max = 90, + .step = 1, + .dims = { 100 }, +}; + static const struct v4l2_ctrl_config vivid_ctrl_u16_matrix = { .ops = &vivid_user_gen_ctrl_ops, .id = VIVID_CID_U16_MATRIX, @@ -474,6 +489,9 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) case VIVID_CID_INSERT_EAV: tpg_s_insert_eav(&dev->tpg, ctrl->val); break; + case VIVID_CID_INSERT_HDMI_VIDEO_GUARD_BAND: + tpg_s_insert_hdmi_video_guard_band(&dev->tpg, ctrl->val); + break; case VIVID_CID_HFLIP: dev->sensor_hflip = ctrl->val; tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip); @@ -660,6 +678,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = { .step = 1, }; +static const struct v4l2_ctrl_config vivid_ctrl_insert_hdmi_video_guard_band = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_INSERT_HDMI_VIDEO_GUARD_BAND, + .name = "Insert Video Guard Band", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + static const struct v4l2_ctrl_config vivid_ctrl_hflip = { .ops = &vivid_vid_cap_ctrl_ops, .id = VIVID_CID_HFLIP, @@ -1612,6 +1639,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, dev->ro_int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_ro_int32, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_dyn_array, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL); @@ -1638,6 +1666,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_hdmi_video_guard_band, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL); if (show_ccs_cap) { dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap, diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.c b/drivers/media/test-drivers/vivid/vivid-vid-common.c index 19701fe72030..38d788b5cf19 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-common.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-common.c @@ -199,6 +199,21 @@ struct vivid_fmt vivid_formats[] = { .buffers = 1, }, { + .fourcc = V4L2_PIX_FMT_YUVA32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xff000000, + }, + { + .fourcc = V4L2_PIX_FMT_YUVX32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { .fourcc = V4L2_PIX_FMT_GREY, .vdownsampling = { 1 }, .bit_depth = { 8 }, diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index 8de08704f8e4..af88e0766388 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -17,7 +17,6 @@ source "drivers/media/usb/cpia2/Kconfig" source "drivers/media/usb/gspca/Kconfig" source "drivers/media/usb/pwc/Kconfig" source "drivers/media/usb/s2255/Kconfig" -source "drivers/media/usb/stkwebcam/Kconfig" source "drivers/media/usb/usbtv/Kconfig" source "drivers/media/usb/uvc/Kconfig" source "drivers/media/usb/zr364xx/Kconfig" diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index 044bd46c799c..25fa2015b179 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -10,7 +10,6 @@ obj-y += dvb-usb/ obj-y += dvb-usb-v2/ obj-y += s2255/ obj-y += siano/ -obj-y += stkwebcam/ obj-y += ttusb-budget/ obj-y += ttusb-dec/ obj-y += zr364xx/ diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index d568452618d1..240a7cc56777 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -123,7 +123,7 @@ struct airspy { /* USB control message buffer */ #define BUF_SIZE 128 - u8 buf[BUF_SIZE]; + u8 *buf; /* Current configuration */ unsigned int f_adc; @@ -856,6 +856,7 @@ static void airspy_video_release(struct v4l2_device *v) v4l2_ctrl_handler_free(&s->hdl); v4l2_device_unregister(&s->v4l2_dev); + kfree(s->buf); kfree(s); } @@ -963,7 +964,10 @@ static int airspy_probe(struct usb_interface *intf, { struct airspy *s; int ret; - u8 u8tmp, buf[BUF_SIZE]; + u8 u8tmp, *buf; + + buf = NULL; + ret = -ENOMEM; s = kzalloc(sizeof(struct airspy), GFP_KERNEL); if (s == NULL) { @@ -971,6 +975,13 @@ static int airspy_probe(struct usb_interface *intf, return -ENOMEM; } + s->buf = kzalloc(BUF_SIZE, GFP_KERNEL); + if (!s->buf) + goto err_free_mem; + buf = kzalloc(BUF_SIZE, GFP_KERNEL); + if (!buf) + goto err_free_mem; + mutex_init(&s->v4l2_lock); mutex_init(&s->vb_queue_lock); spin_lock_init(&s->queued_bufs_lock); @@ -1068,6 +1079,8 @@ err_free_controls: v4l2_ctrl_handler_free(&s->hdl); v4l2_device_unregister(&s->v4l2_dev); err_free_mem: + kfree(buf); + kfree(s->buf); kfree(s); return ret; } diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 4d5ab1433b44..ce1b0d9e0741 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -10,16 +10,6 @@ // // This driver is based on my previous au600 usb pstn audio driver // and inherits all the copyrights -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index d1e66b503f4d..b5f58dc6dd0f 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -4,16 +4,6 @@ // // Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org> // Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index ae25d2cbfdfe..4d037c92af7c 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -8,16 +8,6 @@ // Mauro Carvalho Chehab <mchehab@kernel.org> // Sascha Sommer <saschasommer@freenet.de> // Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index c837cc528a33..61d7bf701d57 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -7,16 +7,6 @@ // Mauro Carvalho Chehab <mchehab@kernel.org> // Sascha Sommer <saschasommer@freenet.de> // Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 471bd74667e3..185e89c18d68 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -16,10 +16,6 @@ // Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: // (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au> // (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation version 2 of the License. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index b9a8d3fbad1a..a7eb11f7fb34 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -7,16 +7,6 @@ // Mauro Carvalho Chehab <mchehab@kernel.org> // Sascha Sommer <saschasommer@freenet.de> // Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com> -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 0b6d77c3bec8..5f3b00869bdb 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -6,16 +6,6 @@ // Markus Rechberger <mrechberger@gmail.com> // Mauro Carvalho Chehab <mchehab@kernel.org> // Sascha Sommer <saschasommer@freenet.de> -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h index 6216cdd182f3..8455dcfdaf81 100644 --- a/drivers/media/usb/em28xx/em28xx-v4l.h +++ b/drivers/media/usb/em28xx/em28xx-v4l.h @@ -4,15 +4,6 @@ * video capture devices * * Copyright (C) 2013-2014 Mauro Carvalho Chehab <mchehab+samsung@kernel.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 63c48361d3f2..b253c44c9724 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -5,16 +5,6 @@ // Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> // // This work was sponsored by EyeMagnet Limited. -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 6b84c3413e83..8181c0e6a25b 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -11,16 +11,6 @@ // // Some parts based on SN9C10x PC Camera Controllers GPL driver made // by Luca Risolia <luca.risolia@studio.unibo.it> -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. #include "em28xx.h" diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 7fc0b68a4a22..db18dd814a67 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -8,16 +8,6 @@ * Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com> * * Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _EM28XX_H diff --git a/drivers/media/usb/gspca/spca501.c b/drivers/media/usb/gspca/spca501.c index ecc97f807cfa..f7c75d7535c4 100644 --- a/drivers/media/usb/gspca/spca501.c +++ b/drivers/media/usb/gspca/spca501.c @@ -488,7 +488,7 @@ static const __u16 spca501_init_data[][3] = { /* Data for video camera init before capture. * Capture and decoding by Colin Peart. - * This is is for the 3com HomeConnect Lite which is spca501a based. + * This is for the 3com HomeConnect Lite which is spca501a based. */ static const __u16 spca501_3com_open_data[][3] = { /* bmRequest,value,index */ diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c index cc87c24dd24c..acfb9a195106 100644 --- a/drivers/media/usb/gspca/xirlink_cit.c +++ b/drivers/media/usb/gspca/xirlink_cit.c @@ -817,7 +817,7 @@ static void cit_model2_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) * 00_d141_0124 * 00_0096_0127 * 00_fea8_0124 -*/ + */ static void cit_model3_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2) { cit_write_reg(gspca_dev, 0x0078, 0x012d); diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 60e57e0f1927..fd7d2a9d0449 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -409,7 +409,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, struct hdpvr_device *dev = video_drvdata(file); struct hdpvr_buffer *buf = NULL; struct urb *urb; - unsigned int ret = 0; + int ret = 0; int rem, cnt; if (*pos) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index a9666373af6b..62ff1fa1c753 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -2610,6 +2610,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, del_timer_sync(&hdw->encoder_run_timer); del_timer_sync(&hdw->encoder_wait_timer); flush_work(&hdw->workpoll); + v4l2_device_unregister(&hdw->v4l2_dev); usb_free_urb(hdw->ctl_read_urb); usb_free_urb(hdw->ctl_write_urb); kfree(hdw->ctl_read_buffer); @@ -5040,7 +5041,7 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw) /* Note: There apparently is no replacement for VIDIOC_CROPCAP using v4l2-subdev - therefore we can't support that AT ALL right now. (Of course, no sub-drivers seem to implement it either. - But now it's a a chicken and egg problem...) */ + But now it's a chicken and egg problem...) */ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp); pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll type=%u strength=%u audio=0x%x cap=0x%x low=%u hi=%u", vtp->type, diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index a714ad77ca8e..1e30e05953dc 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -136,6 +136,8 @@ static uint16_t usbtv_norm_to_16f_reg(v4l2_std_id norm) return 0x00a8; if (norm & (V4L2_STD_PAL_M | V4L2_STD_PAL_60)) return 0x00bc; + if (norm & V4L2_STD_PAL_Nc) + return 0x00fe; /* Fallback to automatic detection for other standards */ return 0x0000; } @@ -241,7 +243,8 @@ static int usbtv_select_norm(struct usbtv *usbtv, v4l2_std_id norm) static const v4l2_std_id ntsc_mask = V4L2_STD_NTSC | V4L2_STD_NTSC_443; static const v4l2_std_id pal_mask = - V4L2_STD_PAL | V4L2_STD_PAL_60 | V4L2_STD_PAL_M; + V4L2_STD_PAL | V4L2_STD_PAL_60 | V4L2_STD_PAL_M | + V4L2_STD_PAL_Nc; if (norm & ntsc_mask) ret = usbtv_set_regs(usbtv, ntsc, ARRAY_SIZE(ntsc)); diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h index 77a368e90fd0..b9fa7c0088c9 100644 --- a/drivers/media/usb/usbtv/usbtv.h +++ b/drivers/media/usb/usbtv/usbtv.h @@ -68,7 +68,8 @@ #define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15) #define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff) -#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL | V4L2_STD_SECAM) +#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM) /* parameters for supported TV norms */ struct usbtv_norm_params { diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 0e78233fc8a0..8c208db9600b 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -366,6 +366,7 @@ static const struct uvc_menu_info power_line_frequency_controls[] = { { 0, "Disabled" }, { 1, "50 Hz" }, { 2, "60 Hz" }, + { 3, "Auto" }, }; static const struct uvc_menu_info exposure_auto_controls[] = { @@ -505,17 +506,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, }, { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .entity = UVC_GUID_UVC_PROCESSING, - .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, - .size = 2, - .offset = 0, - .v4l2_type = V4L2_CTRL_TYPE_MENU, - .data_type = UVC_CTRL_DATA_TYPE_ENUM, - .menu_info = power_line_frequency_controls, - .menu_count = ARRAY_SIZE(power_line_frequency_controls), - }, - { .id = V4L2_CID_HUE_AUTO, .entity = UVC_GUID_UVC_PROCESSING, .selector = UVC_PU_HUE_AUTO_CONTROL, @@ -730,6 +720,34 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { }, }; +static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_info = power_line_frequency_controls, + .menu_count = ARRAY_SIZE(power_line_frequency_controls) - 1, + }, +}; + +static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = { + { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_info = power_line_frequency_controls, + .menu_count = ARRAY_SIZE(power_line_frequency_controls), + }, +}; + /* ------------------------------------------------------------------------ * Utility functions */ @@ -749,7 +767,8 @@ static inline void uvc_clear_bit(u8 *data, int bit) data[bit >> 3] &= ~(1 << (bit & 7)); } -/* Extract the bit string specified by mapping->offset and mapping->size +/* + * Extract the bit string specified by mapping->offset and mapping->size * from the little-endian data stored at 'data' and return the result as * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. @@ -785,7 +804,8 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping, return value; } -/* Set the bit string specified by mapping->offset and mapping->size +/* + * Set the bit string specified by mapping->offset and mapping->size * in the little-endian data stored at 'data' to the value 'value'. */ static void uvc_set_le_value(struct uvc_control_mapping *mapping, @@ -795,7 +815,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, int offset = mapping->offset; u8 mask; - /* According to the v4l2 spec, writing any value to a button control + /* + * According to the v4l2 spec, writing any value to a button control * should result in the action belonging to the button control being * triggered. UVC devices however want to see a 1 written -> override * value. @@ -927,7 +948,8 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, UVC_VC_EXTENSION_UNIT) return ret; - /* GET_RES is mandatory for XU controls, but some + /* + * GET_RES is mandatory for XU controls, but some * cameras still choke on it. Ignore errors and set the * resolution value to zero. */ @@ -1522,8 +1544,10 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, changes); - /* Mark the queue as active, allowing this initial - event to be accepted. */ + /* + * Mark the queue as active, allowing this initial event to be + * accepted. + */ sev->elems = elems; v4l2_event_queue_fh(sev->fh, &ev); } @@ -1596,7 +1620,8 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, if (!ctrl->initialized) continue; - /* Reset the loaded flag for auto-update controls that were + /* + * Reset the loaded flag for auto-update controls that were * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent * uvc_ctrl_get from using the cached value, and for write-only * controls to prevent uvc_ctrl_set from setting bits not @@ -1755,7 +1780,8 @@ int uvc_ctrl_set(struct uvc_fh *handle, return -ERANGE; value = mapping->menu_info[xctrl->value].value; - /* Valid menu indices are reported by the GET_RES request for + /* + * Valid menu indices are reported by the GET_RES request for * UVC controls that support it. */ if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && @@ -1779,7 +1805,8 @@ int uvc_ctrl_set(struct uvc_fh *handle, break; } - /* If the mapping doesn't span the whole UVC control, the current value + /* + * If the mapping doesn't span the whole UVC control, the current value * needs to be loaded from the device to perform the read-modify-write * operation. */ @@ -2180,7 +2207,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, unsigned int size; unsigned int i; - /* Most mappings come from static kernel data and need to be duplicated. + /* + * Most mappings come from static kernel data and need to be duplicated. * Mappings that come from userspace will be unnecessarily duplicated, * this could be optimized. */ @@ -2385,11 +2413,11 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, { const struct uvc_control_info *info = uvc_ctrls; const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls); - const struct uvc_control_mapping *mapping = uvc_ctrl_mappings; - const struct uvc_control_mapping *mend = - mapping + ARRAY_SIZE(uvc_ctrl_mappings); + const struct uvc_control_mapping *mapping; + const struct uvc_control_mapping *mend; - /* XU controls initialization requires querying the device for control + /* + * XU controls initialization requires querying the device for control * information. As some buggy UVC devices will crash when queried * repeatedly in a tight loop, delay XU controls initialization until * first use. @@ -2415,6 +2443,48 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, if (!ctrl->initialized) return; + /* + * First check if the device provides a custom mapping for this control, + * used to override standard mappings for non-conformant devices. Don't + * process standard mappings if a custom mapping is found. This + * mechanism doesn't support combining standard and custom mappings for + * a single control. + */ + if (chain->dev->info->mappings) { + bool custom = false; + unsigned int i; + + for (i = 0; (mapping = chain->dev->info->mappings[i]); ++i) { + if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && + ctrl->info.selector == mapping->selector) { + __uvc_ctrl_add_mapping(chain, ctrl, mapping); + custom = true; + } + } + + if (custom) + return; + } + + /* Process common mappings next. */ + mapping = uvc_ctrl_mappings; + mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings); + + for (; mapping < mend; ++mapping) { + if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && + ctrl->info.selector == mapping->selector) + __uvc_ctrl_add_mapping(chain, ctrl, mapping); + } + + /* Finally process version-specific mappings. */ + if (chain->dev->uvc_version < 0x0150) { + mapping = uvc_ctrl_mappings_uvc11; + mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc11); + } else { + mapping = uvc_ctrl_mappings_uvc15; + mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc15); + } + for (; mapping < mend; ++mapping) { if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && ctrl->info.selector == mapping->selector) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 6c86faecbea2..9c05776f11d1 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -329,7 +329,8 @@ static enum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients) return V4L2_YCBCR_ENC_DEFAULT; /* Reserved */ } -/* Simplify a fraction using a simple continued fraction decomposition. The +/* + * Simplify a fraction using a simple continued fraction decomposition. The * idea here is to convert fractions such as 333333/10000000 to 1/30 using * 32 bit arithmetic only. The algorithm is not perfect and relies upon two * arbitrary parameters to remove non-significative terms from the simple @@ -347,8 +348,9 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator, if (an == NULL) return; - /* Convert the fraction to a simple continued fraction. See - * https://mathforum.org/dr.math/faq/faq.fractions.html + /* + * Convert the fraction to a simple continued fraction. See + * https://en.wikipedia.org/wiki/Continued_fraction * Stop if the current term is bigger than or equal to the given * threshold. */ @@ -383,7 +385,8 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator, kfree(an); } -/* Convert a fraction to a frame interval in 100ns multiples. The idea here is +/* + * Convert a fraction to a frame interval in 100ns multiples. The idea here is * to compute numerator / denominator * 10000000 using 32 bit fixed point * arithmetic only. */ @@ -396,7 +399,8 @@ u32 uvc_fraction_to_interval(u32 numerator, u32 denominator) numerator/denominator >= ((u32)-1)/10000000) return (u32)-1; - /* Divide both the denominator and the multiplier by two until + /* + * Divide both the denominator and the multiplier by two until * numerator * multiplier doesn't overflow. If anyone knows a better * algorithm please let me know. */ @@ -548,7 +552,8 @@ static int uvc_parse_format(struct uvc_device *dev, format->bpp = buffer[21]; - /* Some devices report a format that doesn't match what they + /* + * Some devices report a format that doesn't match what they * really send. */ if (dev->quirks & UVC_QUIRK_FORCE_Y8) { @@ -663,7 +668,8 @@ static int uvc_parse_format(struct uvc_device *dev, buflen -= buffer[0]; buffer += buffer[0]; - /* Parse the frame descriptors. Only uncompressed, MJPEG and frame + /* + * Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && @@ -705,7 +711,8 @@ static int uvc_parse_format(struct uvc_device *dev, } frame->dwFrameInterval = *intervals; - /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize + /* + * Several UVC chipsets screw up dwMaxVideoFrameBufferSize * completely. Observed behaviours range from setting the * value to 1.1x the actual frame size to hardwiring the * 16 low bits to 0. This results in a higher than necessary @@ -717,7 +724,8 @@ static int uvc_parse_format(struct uvc_device *dev, frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth * frame->wHeight / 8; - /* Some bogus devices report dwMinFrameInterval equal to + /* + * Some bogus devices report dwMinFrameInterval equal to * dwMaxFrameInterval and have dwFrameIntervalStep set to * zero. Setting all null intervals to 1 fixes the problem and * some other divisions by zero that could happen. @@ -727,7 +735,8 @@ static int uvc_parse_format(struct uvc_device *dev, *(*intervals)++ = interval ? interval : 1; } - /* Make sure that the default frame interval stays between + /* + * Make sure that the default frame interval stays between * the boundaries. */ n -= frame->bFrameIntervalType ? 1 : 2; @@ -819,7 +828,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, return -ENOMEM; } - /* The Pico iMage webcam has its class-specific interface descriptors + /* + * The Pico iMage webcam has its class-specific interface descriptors * after the endpoint descriptors. */ if (buflen == 0) { @@ -918,7 +928,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, break; case UVC_VS_FORMAT_DV: - /* DV format has no frame descriptor. We will create a + /* + * DV format has no frame descriptor. We will create a * dummy frame descriptor with a dummy frame interval. */ nformats++; @@ -1105,7 +1116,8 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, if (buffer[1] != 0x41 || buffer[2] != 0x01) break; - /* Logitech implements several vendor specific functions + /* + * Logitech implements several vendor specific functions * through vendor specific extension units (LXU). * * The LXU descriptors are similar to XU descriptors @@ -1303,7 +1315,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - /* Make sure the terminal type MSB is not null, otherwise it + /* + * Make sure the terminal type MSB is not null, otherwise it * could be confused with a unit. */ type = get_unaligned_le16(&buffer[4]); @@ -1437,7 +1450,8 @@ static int uvc_parse_control(struct uvc_device *dev) int buflen = alts->extralen; int ret; - /* Parse the default alternate setting only, as the UVC specification + /* + * Parse the default alternate setting only, as the UVC specification * defines a single alternate setting, the default alternate setting * zero. */ @@ -1455,7 +1469,8 @@ next_descriptor: buffer += buffer[0]; } - /* Check if the optional status endpoint is present. Built-in iSight + /* + * Check if the optional status endpoint is present. Built-in iSight * webcams have an interrupt endpoint but spit proprietary data that * don't conform to the UVC status endpoint messages. Don't try to * handle the interrupt endpoint for those cameras. @@ -2057,7 +2072,8 @@ static int uvc_scan_device(struct uvc_device *dev) if (!UVC_ENTITY_IS_OTERM(term)) continue; - /* If the terminal is already included in a chain, skip it. + /* + * If the terminal is already included in a chain, skip it. * This can happen for chains that have multiple output * terminals, where all output terminals beside the first one * will be inserted in the chain in forward scans. @@ -2309,7 +2325,8 @@ static int uvc_register_terms(struct uvc_device *dev, if (ret < 0) return ret; - /* Register a metadata node, but ignore a possible failure, + /* + * Register a metadata node, but ignore a possible failure, * complete registration of video nodes anyway. */ uvc_meta_register(stream); @@ -2507,7 +2524,8 @@ static void uvc_disconnect(struct usb_interface *intf) { struct uvc_device *dev = usb_get_intfdata(intf); - /* Set the USB interface data to NULL. This can be done outside the + /* + * Set the USB interface data to NULL. This can be done outside the * lock, as there's no other reader. */ usb_set_intfdata(intf, NULL); @@ -2643,6 +2661,30 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); * Driver initialization and cleanup */ +static const struct uvc_menu_info power_line_frequency_controls_limited[] = { + { 1, "50 Hz" }, + { 2, "60 Hz" }, +}; + +static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = { + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .entity = UVC_GUID_UVC_PROCESSING, + .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, + .size = 2, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_info = power_line_frequency_controls_limited, + .menu_count = ARRAY_SIZE(power_line_frequency_controls_limited), +}; + +static const struct uvc_device_info uvc_ctrl_power_line_limited = { + .mappings = (const struct uvc_control_mapping *[]) { + &uvc_ctrl_power_line_mapping_limited, + NULL, /* Sentinel */ + }, +}; + static const struct uvc_device_info uvc_quirk_probe_minmax = { .quirks = UVC_QUIRK_PROBE_MINMAX, }; @@ -2673,6 +2715,33 @@ static const struct uvc_device_info uvc_quirk_force_y8 = { * though they are compliant. */ static const struct usb_device_id uvc_ids[] = { + /* Quanta USB2.0 HD UVC Webcam */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0408, + .idProduct = 0x3090, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + /* Quanta USB2.0 HD UVC Webcam */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0408, + .idProduct = 0x4030, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + /* Quanta USB2.0 HD UVC Webcam */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0408, + .idProduct = 0x4034, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, /* LogiLink Wireless Webcam */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -2784,6 +2853,33 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) }, + /* Chicony EasyCamera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x04f2, + .idProduct = 0xb5eb, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + /* Chicony EasyCamera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x04f2, + .idProduct = 0xb6ba, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, + /* Chicony EasyCamera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x04f2, + .idProduct = 0xb746, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -3168,6 +3264,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) }, + /* Acer EasyCamera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x1172, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, /* Intel RealSense D4M */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_isight.c b/drivers/media/usb/uvc/uvc_isight.c index 2578d6ee4829..43cda5e760a3 100644 --- a/drivers/media/usb/uvc/uvc_isight.c +++ b/drivers/media/usb/uvc/uvc_isight.c @@ -14,7 +14,8 @@ #include "uvcvideo.h" -/* Built-in iSight webcams implements most of UVC 1.0 except a +/* + * Built-in iSight webcams implements most of UVC 1.0 except a * different packet format. Instead of sending a header at the * beginning of each isochronous transfer payload, the webcam sends a * single header per image (on its own in a packet), followed by @@ -65,7 +66,8 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, buf->state = UVC_BUF_STATE_ACTIVE; } - /* Mark the buffer as done if we're at the beginning of a new frame. + /* + * Mark the buffer as done if we're at the beginning of a new frame. * * Empty buffers (bytesused == 0) don't trigger end of frame detection * as it doesn't make sense to return an empty buffer. @@ -75,7 +77,8 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, return -EAGAIN; } - /* Copy the video data to the buffer. Skip header packets, as they + /* + * Copy the video data to the buffer. Skip header packets, as they * contain no data. */ if (!is_header) { @@ -109,7 +112,9 @@ void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, urb->iso_frame_desc[i].status); } - /* Decode the payload packet. + /* + * Decode the payload packet. + * * uvc_video_decode is entered twice when a frame transition * has been detected because the end of frame can only be * reliably detected when the first packet of the new frame diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 21a907d32bb7..16fa17bbd15e 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -135,7 +135,8 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) kref_init(&buf->ref); list_add_tail(&buf->queue, &queue->irqqueue); } else { - /* If the device is disconnected return the buffer to userspace + /* + * If the device is disconnected return the buffer to userspace * directly. The next QBUF call will fail with -ENODEV. */ buf->state = UVC_BUF_STATE_ERROR; @@ -412,7 +413,8 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) spin_lock_irqsave(&queue->irqlock, flags); uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); - /* This must be protected by the irqlock spinlock to avoid race + /* + * This must be protected by the irqlock spinlock to avoid race * conditions between uvc_buffer_queue and the disconnection event that * could result in an interruptible wait in uvc_dequeue_buffer. Do not * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index 753c8226db70..7518ffce22ed 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -202,8 +202,7 @@ static void uvc_status_complete(struct urb *urb) case -ENOENT: /* usb_kill_urb() called. */ case -ECONNRESET: /* usb_unlink_urb() called. */ case -ESHUTDOWN: /* The endpoint is being disabled. */ - case -EPROTO: /* Device is disconnected (reported by some - * host controller). */ + case -EPROTO: /* Device is disconnected (reported by some host controllers). */ return; default: @@ -272,7 +271,8 @@ int uvc_status_init(struct uvc_device *dev) pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); - /* For high-speed interrupt endpoints, the bInterval value is used as + /* + * For high-speed interrupt endpoints, the bInterval value is used as * an exponent of two. Some developers forgot about it. */ interval = ep->desc.bInterval; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 648dcd579e81..4cc3fa6b8c98 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -63,7 +63,8 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, break; case V4L2_CTRL_TYPE_MENU: - /* Prevent excessive memory consumption, as well as integer + /* + * Prevent excessive memory consumption, as well as integer * overflows. */ if (xmap->menu_count == 0 || @@ -177,7 +178,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, fcc[0], fcc[1], fcc[2], fcc[3], fmt->fmt.pix.width, fmt->fmt.pix.height); - /* Check if the hardware supports the requested format, use the default + /* + * Check if the hardware supports the requested format, use the default * format otherwise. */ for (i = 0; i < stream->nformats; ++i) { @@ -191,7 +193,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, fmt->fmt.pix.pixelformat = format->fcc; } - /* Find the closest image size. The distance between image sizes is + /* + * Find the closest image size. The distance between image sizes is * the size in pixels of the non-overlapping regions between the * requested size and the frame-specified size. */ @@ -233,7 +236,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; probe->dwFrameInterval = uvc_try_frame_interval(frame, interval); - /* Some webcams stall the probe control set request when the + /* + * Some webcams stall the probe control set request when the * dwMaxVideoFrameSize field is set to zero. The UVC specification * clearly states that the field is read-only from the host, so this * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by @@ -254,9 +258,10 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, ret = uvc_probe_video(stream, probe); mutex_unlock(&stream->mutex); if (ret < 0) - goto done; + return ret; - /* After the probe, update fmt with the values returned from + /* + * After the probe, update fmt with the values returned from * negotiation with the device. Some devices return invalid bFormatIndex * and bFrameIndex values, in which case we can only assume they have * accepted the requested format as-is. @@ -300,7 +305,6 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, if (uvc_frame != NULL) *uvc_frame = frame; -done: return ret; } diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 6d3dfa4e0bb2..170a008f4006 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -189,7 +189,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, ctrl->dwMaxVideoFrameSize = frame->dwMaxVideoFrameBufferSize; - /* The "TOSHIBA Web Camera - 5M" Chicony device (04f2:b50b) seems to + /* + * The "TOSHIBA Web Camera - 5M" Chicony device (04f2:b50b) seems to * compute the bandwidth on 16 bits and erroneously sign-extend it to * 32 bits, resulting in a huge bandwidth value. Detect and fix that * condition by setting the 16 MSBs to 0 when they're all equal to 1. @@ -207,7 +208,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, ? ctrl->dwFrameInterval : frame->dwFrameInterval[0]; - /* Compute a bandwidth estimation by multiplying the frame + /* + * Compute a bandwidth estimation by multiplying the frame * size by the number of video frames per second, divide the * result by the number of USB frames (or micro-frames for * high-speed devices) per second and add the UVC header size @@ -220,7 +222,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, bandwidth /= 8; bandwidth += 12; - /* The bandwidth estimate is too low for many cameras. Don't use + /* + * The bandwidth estimate is too low for many cameras. Don't use * maximum packet sizes lower than 1024 bytes to try and work * around the problem. According to measurements done on two * different camera models, the value is high enough to get most @@ -267,7 +270,8 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, size, uvc_timeout_param); if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) { - /* Some cameras, mostly based on Bison Electronics chipsets, + /* + * Some cameras, mostly based on Bison Electronics chipsets, * answer a GET_MIN or GET_MAX request with the wCompQuality * field only. */ @@ -279,7 +283,8 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, ret = 0; goto out; } else if (query == UVC_GET_DEF && probe == 1 && ret != size) { - /* Many cameras don't support the GET_DEF request on their + /* + * Many cameras don't support the GET_DEF request on their * video probe control. Warn once and return, the caller will * fall back to GET_CUR. */ @@ -322,7 +327,8 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, ctrl->bMaxVersion = 0; } - /* Some broken devices return null or wrong dwMaxVideoFrameSize and + /* + * Some broken devices return null or wrong dwMaxVideoFrameSize and * dwMaxPayloadTransferSize fields. Try to get the value from the * format and frame descriptors. */ @@ -386,7 +392,8 @@ int uvc_probe_video(struct uvc_streaming *stream, unsigned int i; int ret; - /* Perform probing. The device should adjust the requested values + /* + * Perform probing. The device should adjust the requested values * according to its capabilities. However, some devices, namely the * first generation UVC Logitech webcams, don't implement the Video * Probe control properly, and just return the needed bandwidth. For @@ -493,7 +500,8 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, if (len < header_size) return; - /* Extract the timestamps: + /* + * Extract the timestamps: * * - store the frame PTS in the buffer structure * - if the SCR field is present, retrieve the host SOF counter and @@ -506,7 +514,8 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, if (!has_scr) return; - /* To limit the amount of data, drop SCRs with an SOF identical to the + /* + * To limit the amount of data, drop SCRs with an SOF identical to the * previous one. */ dev_sof = get_unaligned_le16(&data[header_size - 2]); @@ -518,7 +527,8 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, host_sof = usb_get_current_frame_number(stream->dev->udev); time = uvc_video_get_time(); - /* The UVC specification allows device implementations that can't obtain + /* + * The UVC specification allows device implementations that can't obtain * the USB frame number to keep their own frame counters as long as they * match the size and frequency of the frame number associated with USB * SOF tokens. The SOF values sent by such devices differ from the USB @@ -756,7 +766,8 @@ void uvc_video_clock_update(struct uvc_streaming *stream, y1 = NSEC_PER_SEC; y2 = (u32)ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1; - /* Interpolated and host SOF timestamps can wrap around at slightly + /* + * Interpolated and host SOF timestamps can wrap around at slightly * different times. Handle this by adding or removing 2048 to or from * the computed SOF value to keep it close to the SOF samples mean * value. @@ -854,7 +865,8 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream, stream->stats.frame.pts = pts; } - /* Do all frames have a PTS in their first non-empty packet, or before + /* + * Do all frames have a PTS in their first non-empty packet, or before * their first empty packet ? */ if (stream->stats.frame.size == 0) { @@ -945,7 +957,8 @@ size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, unsigned int duration; size_t count = 0; - /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF + /* + * Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF * frequency this will not overflow before more than 1h. */ duration = ktime_ms_delta(stream->stats.stream.stop_ts, @@ -997,7 +1010,8 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream) * Video codecs */ -/* Video payload decoding is handled by uvc_video_decode_start(), +/* + * Video payload decoding is handled by uvc_video_decode_start(), * uvc_video_decode_data() and uvc_video_decode_end(). * * uvc_video_decode_start is called with URB data at the start of a bulk or @@ -1037,7 +1051,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, { u8 fid; - /* Sanity checks: + /* + * Sanity checks: * - packet must be at least 2 bytes long * - bHeaderLength value must be at least 2 bytes (see above) * - bHeaderLength value can't be larger than the packet size. @@ -1049,7 +1064,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, fid = data[1] & UVC_STREAM_FID; - /* Increase the sequence number regardless of any buffer states, so + /* + * Increase the sequence number regardless of any buffer states, so * that discontinuous sequence numbers always indicate lost frames. */ if (stream->last_fid != fid) { @@ -1061,7 +1077,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, uvc_video_clock_decode(stream, buf, data, len); uvc_video_stats_decode(stream, data, len); - /* Store the payload FID bit and return immediately when the buffer is + /* + * Store the payload FID bit and return immediately when the buffer is * NULL. */ if (buf == NULL) { @@ -1076,7 +1093,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, buf->error = 1; } - /* Synchronize to the input stream by waiting for the FID bit to be + /* + * Synchronize to the input stream by waiting for the FID bit to be * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. * stream->last_fid is initialized to -1, so the first isochronous * frame will always be in sync. @@ -1102,7 +1120,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, buf->state = UVC_BUF_STATE_ACTIVE; } - /* Mark the buffer as done if we're at the beginning of a new frame. + /* + * Mark the buffer as done if we're at the beginning of a new frame. * End of frame detection is better implemented by checking the EOF * bit (FID bit toggling is delayed by one frame compared to the EOF * bit), but some devices don't set the bit at end of frame (and the @@ -1226,7 +1245,8 @@ static void uvc_video_decode_end(struct uvc_streaming *stream, } } -/* Video payload encoding is handled by uvc_video_encode_header() and +/* + * Video payload encoding is handled by uvc_video_encode_header() and * uvc_video_encode_data(). Only bulk transfers are currently supported. * * uvc_video_encode_header is called at the start of a payload. It adds header @@ -1450,7 +1470,8 @@ static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb, len = urb->actual_length; stream->bulk.payload_size += len; - /* If the URB is the first of its payload, decode and save the + /* + * If the URB is the first of its payload, decode and save the * header. */ if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) { @@ -1474,7 +1495,8 @@ static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb, } } - /* The buffer queue might have been cancelled while a bulk transfer + /* + * The buffer queue might have been cancelled while a bulk transfer * was in progress, so we can reach here with buf equal to NULL. Make * sure buf is never dereferenced if NULL. */ @@ -1483,7 +1505,8 @@ static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb, if (!stream->bulk.skip_payload && buf != NULL) uvc_video_decode_data(uvc_urb, buf, mem, len); - /* Detect the payload end by a URB smaller than the maximum size (or + /* + * Detect the payload end by a URB smaller than the maximum size (or * a payload size equal to the maximum) and process the header again. */ if (urb->actual_length < urb->transfer_buffer_length || @@ -1686,7 +1709,8 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, if (stream->urb_size) return stream->urb_size / psize; - /* Compute the number of packets. Bulk endpoints might transfer UVC + /* + * Compute the number of packets. Bulk endpoints might transfer UVC * payloads across multiple URBs. */ npackets = DIV_ROUND_UP(size, psize); @@ -1975,7 +1999,8 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, } } - /* The Logitech C920 temporarily forgets that it should not be adjusting + /* + * The Logitech C920 temporarily forgets that it should not be adjusting * Exposure Absolute during init so restore controls to stored values. */ if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT) @@ -2018,7 +2043,8 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset) { int ret; - /* If the bus has been reset on resume, set the alternate setting to 0. + /* + * If the bus has been reset on resume, set the alternate setting to 0. * This should be the default value, but some devices crash or otherwise * misbehave if they don't receive a SET_INTERFACE request before any * other video control request. @@ -2071,14 +2097,16 @@ int uvc_video_init(struct uvc_streaming *stream) atomic_set(&stream->active, 0); - /* Alternate setting 0 should be the default, yet the XBox Live Vision + /* + * Alternate setting 0 should be the default, yet the XBox Live Vision * Cam (and possibly other devices) crash or otherwise misbehave if * they don't receive a SET_INTERFACE request before any other video * control request. */ usb_set_interface(stream->dev->udev, stream->intfnum, 0); - /* Set the streaming probe control with default streaming parameters + /* + * Set the streaming probe control with default streaming parameters * retrieved from the device. Webcams that don't support GET_DEF * requests on the probe control will just keep their current streaming * parameters. @@ -2086,7 +2114,8 @@ int uvc_video_init(struct uvc_streaming *stream) if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0) uvc_set_video_ctrl(stream, probe, 1); - /* Initialize the streaming parameters with the probe control current + /* + * Initialize the streaming parameters with the probe control current * value. This makes sure SET_CUR requests on the streaming commit * control will always use values retrieved from a successful GET_CUR * request on the probe control, as required by the UVC specification. @@ -2095,7 +2124,8 @@ int uvc_video_init(struct uvc_streaming *stream) if (ret < 0) return ret; - /* Check if the default format descriptor exists. Use the first + /* + * Check if the default format descriptor exists. Use the first * available format otherwise. */ for (i = stream->nformats; i > 0; --i) { @@ -2110,7 +2140,8 @@ int uvc_video_init(struct uvc_streaming *stream) return -EINVAL; } - /* Zero bFrameIndex might be correct. Stream-based formats (including + /* + * Zero bFrameIndex might be correct. Stream-based formats (including * MPEG-2 TS and DV) do not support frames but have a dummy frame * descriptor with bFrameIndex set to zero. If the default frame * descriptor is not found, use the first available frame. @@ -2187,7 +2218,8 @@ void uvc_video_stop_streaming(struct uvc_streaming *stream) if (stream->intf->num_altsetting > 1) { usb_set_interface(stream->dev->udev, stream->intfnum, 0); } else { - /* UVC doesn't specify how to inform a bulk-based device + /* + * UVC doesn't specify how to inform a bulk-based device * when the video stream is stopped. Windows sends a * CLEAR_FEATURE(HALT) request to the video streaming * bulk endpoint, mimic the same behaviour. diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index c5b4febd2d94..24c911aeebce 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -225,7 +225,8 @@ struct gpio_desc; struct sg_table; struct uvc_device; -/* TODO: Put the most frequently accessed fields at the beginning of +/* + * TODO: Put the most frequently accessed fields at the beginning of * structures to maximize cache efficiency. */ struct uvc_control_info { @@ -270,8 +271,7 @@ struct uvc_control { struct uvc_entity *entity; struct uvc_control_info info; - u8 index; /* Used to match the uvc_control entry with a - uvc_control_info. */ + u8 index; /* Used to match the uvc_control entry with a uvc_control_info. */ u8 dirty:1, loaded:1, modified:1, @@ -289,7 +289,8 @@ struct uvc_format_desc { u32 fcc; }; -/* The term 'entity' refers to both UVC units and UVC terminals. +/* + * The term 'entity' refers to both UVC units and UVC terminals. * * The type field is either the terminal type (wTerminalType in the terminal * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor). @@ -308,8 +309,7 @@ struct uvc_format_desc { struct uvc_entity { struct list_head list; /* Entity as part of a UVC device. */ - struct list_head chain; /* Entity as part of a video device - * chain. */ + struct list_head chain; /* Entity as part of a video device chain. */ unsigned int flags; /* @@ -591,7 +591,8 @@ struct uvc_streaming { struct uvc_format *cur_format; struct uvc_frame *cur_frame; - /* Protect access to ctrl, cur_format, cur_frame and hardware video + /* + * Protect access to ctrl, cur_format, cur_frame and hardware video * probe control. */ struct mutex mutex; @@ -667,6 +668,7 @@ struct uvc_device_info { u32 quirks; u32 meta_format; u16 uvc_version; + const struct uvc_control_mapping **mappings; }; struct uvc_device { diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 1be9a2cc947a..348559bc2468 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -9,7 +9,7 @@ config VIDEO_V4L2_I2C default y config VIDEO_V4L2_SUBDEV_API - bool "V4L2 sub-device userspace API" + bool depends on VIDEO_DEV && MEDIA_CONTROLLER help Enables the V4L2 sub-device pad-level userspace API used to configure @@ -56,9 +56,11 @@ config V4L2_MEM2MEM_DEV # Used by LED subsystem flash drivers config V4L2_FLASH_LED_CLASS tristate "V4L2 flash API for LED flash class devices" - depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_DEV depends on LEDS_CLASS_FLASH + select MEDIA_CONTROLLER select V4L2_ASYNC + select VIDEO_V4L2_SUBDEV_API help Say Y here to enable V4L2 flash API support for LED flash class drivers. diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index c6995718237a..2f1b718a9189 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -52,6 +52,15 @@ static int v4l2_async_nf_call_complete(struct v4l2_async_notifier *n) return n->ops->complete(n); } +static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n, + struct v4l2_async_subdev *asd) +{ + if (!n->ops || !n->ops->destroy) + return; + + n->ops->destroy(asd); +} + static bool match_i2c(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { @@ -66,8 +75,10 @@ static bool match_i2c(struct v4l2_async_notifier *notifier, #endif } -static bool match_fwnode(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) +static bool +match_fwnode_one(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode, + struct v4l2_async_subdev *asd) { struct fwnode_handle *other_fwnode; struct fwnode_handle *dev_fwnode; @@ -80,15 +91,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier, * fwnode or a device fwnode. Start with the simple case of direct * fwnode matching. */ - if (sd->fwnode == asd->match.fwnode) - return true; - - /* - * Check the same situation for any possible secondary assigned to the - * subdev's fwnode - */ - if (!IS_ERR_OR_NULL(sd->fwnode->secondary) && - sd->fwnode->secondary == asd->match.fwnode) + if (sd_fwnode == asd->match.fwnode) return true; /* @@ -99,7 +102,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier, * ACPI. This won't make a difference, as drivers should not try to * match unconnected endpoints. */ - sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd->fwnode); + sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode); asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode); if (sd_fwnode_is_ep == asd_fwnode_is_ep) @@ -110,11 +113,11 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier, * parent of the endpoint fwnode, and compare it with the other fwnode. */ if (sd_fwnode_is_ep) { - dev_fwnode = fwnode_graph_get_port_parent(sd->fwnode); + dev_fwnode = fwnode_graph_get_port_parent(sd_fwnode); other_fwnode = asd->match.fwnode; } else { dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode); - other_fwnode = sd->fwnode; + other_fwnode = sd_fwnode; } fwnode_handle_put(dev_fwnode); @@ -143,6 +146,19 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier, return true; } +static bool match_fwnode(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) +{ + if (match_fwnode_one(notifier, sd, sd->fwnode, asd)) + return true; + + /* Also check the secondary fwnode. */ + if (IS_ERR_OR_NULL(sd->fwnode->secondary)) + return false; + + return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd); +} + static LIST_HEAD(subdev_list); static LIST_HEAD(notifier_list); static DEFINE_MUTEX(list_lock); @@ -626,6 +642,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier) } list_del(&asd->asd_list); + v4l2_async_nf_call_destroy(notifier, asd); kfree(asd); } } diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index df34b2a283bc..e0fbe6ba4b6c 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -266,6 +266,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, @@ -277,6 +278,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) /* Tiled YUV formats */ { .format = V4L2_PIX_FMT_NV12_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_P010_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .hdiv = 2, .vdiv = 2 }, /* YUV planar formats, non contiguous variant */ { .format = V4L2_PIX_FMT_YUV420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index db9baa0bd05f..50d012ba3c02 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -97,29 +97,47 @@ static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) return ptr_to_user(c, ctrl, ctrl->p_new); } -/* Helper function: copy the caller-provider value to the given control value */ -static int user_to_ptr(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl, - union v4l2_ctrl_ptr ptr) +/* Helper function: copy the caller-provider value as the new control value */ +static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) { int ret; u32 size; - ctrl->is_new = 1; + ctrl->is_new = 0; + if (ctrl->is_dyn_array && + c->size > ctrl->p_dyn_alloc_elems * ctrl->elem_size) { + void *old = ctrl->p_dyn; + void *tmp = kvzalloc(2 * c->size, GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size); + memcpy(tmp + c->size, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size); + ctrl->p_new.p = tmp; + ctrl->p_cur.p = tmp + c->size; + ctrl->p_dyn = tmp; + ctrl->p_dyn_alloc_elems = c->size / ctrl->elem_size; + kvfree(old); + } + if (ctrl->is_ptr && !ctrl->is_string) { + unsigned int elems = c->size / ctrl->elem_size; unsigned int idx; - ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0; - if (ret || !ctrl->is_array) - return ret; - for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++) - ctrl->type_ops->init(ctrl, idx, ptr); + if (copy_from_user(ctrl->p_new.p, c->ptr, c->size)) + return -EFAULT; + ctrl->is_new = 1; + if (ctrl->is_dyn_array) + ctrl->new_elems = elems; + else if (ctrl->is_array) + for (idx = elems; idx < ctrl->elems; idx++) + ctrl->type_ops->init(ctrl, idx, ctrl->p_new); return 0; } switch (ctrl->type) { case V4L2_CTRL_TYPE_INTEGER64: - *ptr.p_s64 = c->value64; + *ctrl->p_new.p_s64 = c->value64; break; case V4L2_CTRL_TYPE_STRING: size = c->size; @@ -127,32 +145,27 @@ static int user_to_ptr(struct v4l2_ext_control *c, return -ERANGE; if (size > ctrl->maximum + 1) size = ctrl->maximum + 1; - ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0; + ret = copy_from_user(ctrl->p_new.p_char, c->string, size) ? -EFAULT : 0; if (!ret) { - char last = ptr.p_char[size - 1]; + char last = ctrl->p_new.p_char[size - 1]; - ptr.p_char[size - 1] = 0; + ctrl->p_new.p_char[size - 1] = 0; /* * If the string was longer than ctrl->maximum, * then return an error. */ - if (strlen(ptr.p_char) == ctrl->maximum && last) + if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last) return -ERANGE; } return ret; default: - *ptr.p_s32 = c->value; + *ctrl->p_new.p_s32 = c->value; break; } + ctrl->is_new = 1; return 0; } -/* Helper function: copy the caller-provider value as the new control value */ -static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) -{ - return user_to_ptr(c, ctrl, ctrl->p_new); -} - /* * VIDIOC_G/TRY/S_EXT_CTRLS implementation */ @@ -254,7 +267,31 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, have_clusters = true; if (ctrl->cluster[0] != ctrl) ref = find_ref_lock(hdl, ctrl->cluster[0]->id); - if (ctrl->is_ptr && !ctrl->is_string) { + if (ctrl->is_dyn_array) { + unsigned int max_size = ctrl->dims[0] * ctrl->elem_size; + unsigned int tot_size = ctrl->elem_size; + + if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) + tot_size *= ref->p_req_elems; + else + tot_size *= ctrl->elems; + + c->size = ctrl->elem_size * (c->size / ctrl->elem_size); + if (get) { + if (c->size < tot_size) { + c->size = tot_size; + return -ENOSPC; + } + c->size = tot_size; + } else { + if (c->size > max_size) { + c->size = max_size; + return -ENOSPC; + } + if (!c->size) + return -EFAULT; + } + } else if (ctrl->is_ptr && !ctrl->is_string) { unsigned int tot_size = ctrl->elems * ctrl->elem_size; if (c->size < tot_size) { @@ -346,7 +383,7 @@ static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) * * Note that v4l2_g_ext_ctrls_common() with 'which' set to * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was - * completed, and in that case valid_p_req is true for all controls. + * completed, and in that case p_req_valid is true for all controls. */ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs, @@ -430,7 +467,9 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, if (is_default) ret = def_to_user(cs->controls + idx, ref->ctrl); - else if (is_request && ref->valid_p_req) + else if (is_request && ref->p_req_dyn_enomem) + ret = -ENOMEM; + else if (is_request && ref->p_req_valid) ret = req_to_user(cs->controls + idx, ref); else if (is_volatile) ret = new_to_user(cs->controls + idx, ref->ctrl); @@ -457,6 +496,17 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev, } EXPORT_SYMBOL(v4l2_g_ext_ctrls); +/* Validate a new control */ +static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) +{ + unsigned int idx; + int err = 0; + + for (idx = 0; !err && idx < ctrl->new_elems; idx++) + err = ctrl->type_ops->validate(ctrl, idx, p_new); + return err; +} + /* Validate controls. */ static int validate_ctrls(struct v4l2_ext_controls *cs, struct v4l2_ctrl_helper *helpers, @@ -872,6 +922,9 @@ int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, /* It's a driver bug if this happens. */ if (WARN_ON(ctrl->type != type)) return -EINVAL; + /* Setting dynamic arrays is not (yet?) supported. */ + if (WARN_ON(ctrl->is_dyn_array)) + return -EINVAL; memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size); return set_ctrl(NULL, ctrl, 0); } diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 949c1884d9c1..1f85828d6694 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -307,6 +307,21 @@ static void std_log(const struct v4l2_ctrl *ctrl) case V4L2_CTRL_TYPE_VP9_FRAME: pr_cont("VP9_FRAME"); break; + case V4L2_CTRL_TYPE_HEVC_SPS: + pr_cont("HEVC_SPS"); + break; + case V4L2_CTRL_TYPE_HEVC_PPS: + pr_cont("HEVC_PPS"); + break; + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + pr_cont("HEVC_SLICE_PARAMS"); + break; + case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: + pr_cont("HEVC_SCALING_MATRIX"); + break; + case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS: + pr_cont("HEVC_DECODE_PARAMS"); + break; default: pr_cont("unknown type %d", ctrl->type); break; @@ -521,7 +536,6 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, struct v4l2_ctrl_h264_decode_params *p_h264_dec_params; struct v4l2_ctrl_hevc_sps *p_hevc_sps; struct v4l2_ctrl_hevc_pps *p_hevc_pps; - struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params; struct v4l2_area *area; @@ -799,8 +813,6 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, p_hevc_pps->pps_beta_offset_div2 = 0; p_hevc_pps->pps_tc_offset_div2 = 0; } - - zero_padding(*p_hevc_pps); break; case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS: @@ -809,21 +821,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, if (p_hevc_decode_params->num_active_dpb_entries > V4L2_HEVC_DPB_ENTRIES_NUM_MAX) return -EINVAL; - - for (i = 0; i < p_hevc_decode_params->num_active_dpb_entries; - i++) { - struct v4l2_hevc_dpb_entry *dpb_entry = - &p_hevc_decode_params->dpb[i]; - - zero_padding(*dpb_entry); - } break; case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: - p_hevc_slice_params = p; - - zero_padding(p_hevc_slice_params->pred_weight_table); - zero_padding(*p_hevc_slice_params); break; case V4L2_CTRL_TYPE_HDR10_CLL_INFO: @@ -991,11 +991,12 @@ EXPORT_SYMBOL(v4l2_ctrl_notify); /* Copy the one value to another. */ static void ptr_to_ptr(struct v4l2_ctrl *ctrl, - union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to) + union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to, + unsigned int elems) { if (ctrl == NULL) return; - memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size); + memcpy(to.p, from.p_const, elems * ctrl->elem_size); } /* Copy the new value to the current value. */ @@ -1008,8 +1009,11 @@ void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) /* has_changed is set by cluster_changed */ changed = ctrl->has_changed; - if (changed) - ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur); + if (changed) { + if (ctrl->is_dyn_array) + ctrl->elems = ctrl->new_elems; + ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur, ctrl->elems); + } if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) { /* Note: CH_FLAGS is only set for auto clusters. */ @@ -1039,36 +1043,122 @@ void cur_to_new(struct v4l2_ctrl *ctrl) { if (ctrl == NULL) return; - ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new); + if (ctrl->is_dyn_array) + ctrl->new_elems = ctrl->elems; + ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems); +} + +static bool req_alloc_dyn_array(struct v4l2_ctrl_ref *ref, u32 elems) +{ + void *tmp; + + if (elems < ref->p_req_dyn_alloc_elems) + return true; + + tmp = kvmalloc(elems * ref->ctrl->elem_size, GFP_KERNEL); + + if (!tmp) { + ref->p_req_dyn_enomem = true; + return false; + } + ref->p_req_dyn_enomem = false; + kvfree(ref->p_req.p); + ref->p_req.p = tmp; + ref->p_req_dyn_alloc_elems = elems; + return true; } /* Copy the new value to the request value */ void new_to_req(struct v4l2_ctrl_ref *ref) { + struct v4l2_ctrl *ctrl; + if (!ref) return; - ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req); - ref->valid_p_req = true; + + ctrl = ref->ctrl; + if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->new_elems)) + return; + + ref->p_req_elems = ctrl->new_elems; + ptr_to_ptr(ctrl, ctrl->p_new, ref->p_req, ref->p_req_elems); + ref->p_req_valid = true; } /* Copy the current value to the request value */ void cur_to_req(struct v4l2_ctrl_ref *ref) { + struct v4l2_ctrl *ctrl; + if (!ref) return; - ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req); - ref->valid_p_req = true; + + ctrl = ref->ctrl; + if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->elems)) + return; + + ref->p_req_elems = ctrl->elems; + ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req, ctrl->elems); + ref->p_req_valid = true; } /* Copy the request value to the new value */ -void req_to_new(struct v4l2_ctrl_ref *ref) +int req_to_new(struct v4l2_ctrl_ref *ref) { + struct v4l2_ctrl *ctrl; + if (!ref) - return; - if (ref->valid_p_req) - ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new); - else - ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new); + return 0; + + ctrl = ref->ctrl; + + /* + * This control was never set in the request, so just use the current + * value. + */ + if (!ref->p_req_valid) { + if (ctrl->is_dyn_array) + ctrl->new_elems = ctrl->elems; + ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems); + return 0; + } + + /* Not a dynamic array, so just copy the request value */ + if (!ctrl->is_dyn_array) { + ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems); + return 0; + } + + /* Sanity check, should never happen */ + if (WARN_ON(!ref->p_req_dyn_alloc_elems)) + return -ENOMEM; + + /* + * Check if the number of elements in the request is more than the + * elements in ctrl->p_dyn. If so, attempt to realloc ctrl->p_dyn. + * Note that p_dyn is allocated with twice the number of elements + * in the dynamic array since it has to store both the current and + * new value of such a control. + */ + if (ref->p_req_elems > ctrl->p_dyn_alloc_elems) { + unsigned int sz = ref->p_req_elems * ctrl->elem_size; + void *old = ctrl->p_dyn; + void *tmp = kvzalloc(2 * sz, GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size); + memcpy(tmp + sz, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size); + ctrl->p_new.p = tmp; + ctrl->p_cur.p = tmp + sz; + ctrl->p_dyn = tmp; + ctrl->p_dyn_alloc_elems = ref->p_req_elems; + kvfree(old); + } + + ctrl->new_elems = ref->p_req_elems; + ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems); + return 0; } /* Control range checking */ @@ -1110,17 +1200,6 @@ int check_range(enum v4l2_ctrl_type type, } } -/* Validate a new control */ -int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) -{ - unsigned idx; - int err = 0; - - for (idx = 0; !err && idx < ctrl->elems; idx++) - err = ctrl->type_ops->validate(ctrl, idx, p_new); - return err; -} - /* Set the handler's error code if it wasn't set earlier already */ static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err) { @@ -1164,6 +1243,8 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) /* Free all nodes */ list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) { list_del(&ref->node); + if (ref->p_req_dyn_alloc_elems) + kvfree(ref->p_req.p); kfree(ref); } /* Free all controls owned by the handler */ @@ -1171,6 +1252,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) list_del(&ctrl->node); list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node) list_del(&sev->node); + kvfree(ctrl->p_dyn); kvfree(ctrl); } kvfree(hdl->buckets); @@ -1286,7 +1368,7 @@ int handler_new_ref(struct v4l2_ctrl_handler *hdl, if (hdl->error) return hdl->error; - if (allocate_req) + if (allocate_req && !ctrl->is_dyn_array) size_extra_req = ctrl->elems * ctrl->elem_size; new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL); if (!new_ref) @@ -1460,7 +1542,6 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, elem_size = sizeof(s32); break; } - tot_ctrl_size = elem_size * elems; /* Sanity checks */ if (id == 0 || name == NULL || !elem_size || @@ -1481,17 +1562,33 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, handler_set_err(hdl, -EINVAL); return NULL; } + if (flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) { + /* + * For now only support this for one-dimensional arrays only. + * + * This can be relaxed in the future, but this will + * require more effort. + */ + if (nr_of_dims != 1) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + /* Start with just 1 element */ + elems = 1; + } + tot_ctrl_size = elem_size * elems; sz_extra = 0; if (type == V4L2_CTRL_TYPE_BUTTON) flags |= V4L2_CTRL_FLAG_WRITE_ONLY | V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; else if (type == V4L2_CTRL_TYPE_CTRL_CLASS) flags |= V4L2_CTRL_FLAG_READ_ONLY; - else if (type == V4L2_CTRL_TYPE_INTEGER64 || - type == V4L2_CTRL_TYPE_STRING || - type >= V4L2_CTRL_COMPOUND_TYPES || - is_array) + else if (!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) && + (type == V4L2_CTRL_TYPE_INTEGER64 || + type == V4L2_CTRL_TYPE_STRING || + type >= V4L2_CTRL_COMPOUND_TYPES || + is_array)) sz_extra += 2 * tot_ctrl_size; if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) @@ -1520,7 +1617,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string; ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64; ctrl->is_array = is_array; + ctrl->is_dyn_array = !!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY); ctrl->elems = elems; + ctrl->new_elems = elems; ctrl->nr_of_dims = nr_of_dims; if (nr_of_dims) memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0])); @@ -1533,6 +1632,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ctrl->cur.val = ctrl->val = def; data = &ctrl[1]; + if (ctrl->is_dyn_array) { + ctrl->p_dyn_alloc_elems = elems; + ctrl->p_dyn = kvzalloc(2 * elems * elem_size, GFP_KERNEL); + if (!ctrl->p_dyn) { + kvfree(ctrl); + return NULL; + } + data = ctrl->p_dyn; + } + if (!ctrl->is_int) { ctrl->p_new.p = data; ctrl->p_cur.p = data + tot_ctrl_size; @@ -1542,7 +1651,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, } if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) { - ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size; + if (ctrl->is_dyn_array) + ctrl->p_def.p = &ctrl[1]; + else + ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size; memcpy(ctrl->p_def.p, p_def.p_const, elem_size); } @@ -1552,6 +1664,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, } if (handler_new_ref(hdl, ctrl, NULL, false, false)) { + kvfree(ctrl->p_dyn); kvfree(ctrl); return NULL; } @@ -1889,6 +2002,9 @@ static int cluster_changed(struct v4l2_ctrl *master) continue; } + if (ctrl->elems != ctrl->new_elems) + ctrl_changed = true; + for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, ctrl->p_cur, ctrl->p_new); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index 16f42d2fd359..e22921e7ea61 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -704,9 +704,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return hevc_tier; case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return hevc_loop_filter_mode; - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: + case V4L2_CID_STATELESS_HEVC_DECODE_MODE: return hevc_decode_mode; - case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: + case V4L2_CID_STATELESS_HEVC_START_CODE: return hevc_start_code; case V4L2_CID_CAMERA_ORIENTATION: return camera_orientation; @@ -1003,13 +1003,6 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field"; case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame"; case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR"; - case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; - case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; - case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; - case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix"; - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: return "HEVC Decode Parameters"; - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; - case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; /* CAMERA controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1188,6 +1181,14 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_STATELESS_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR: return "VP9 Probabilities Updates"; case V4L2_CID_STATELESS_VP9_FRAME: return "VP9 Frame Decode Parameters"; + case V4L2_CID_STATELESS_HEVC_SPS: return "HEVC Sequence Parameter Set"; + case V4L2_CID_STATELESS_HEVC_PPS: return "HEVC Picture Parameter Set"; + case V4L2_CID_STATELESS_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; + case V4L2_CID_STATELESS_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix"; + case V4L2_CID_STATELESS_HEVC_DECODE_PARAMS: return "HEVC Decode Parameters"; + case V4L2_CID_STATELESS_HEVC_DECODE_MODE: return "HEVC Decode Mode"; + case V4L2_CID_STATELESS_HEVC_START_CODE: return "HEVC Start Code"; + case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS: return "HEVC Entry Point Offsets"; /* Colorimetry controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1363,8 +1364,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: case V4L2_CID_MPEG_VIDEO_HEVC_TIER: case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: - case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: + case V4L2_CID_STATELESS_HEVC_DECODE_MODE: + case V4L2_CID_STATELESS_HEVC_START_CODE: case V4L2_CID_STATELESS_H264_DECODE_MODE: case V4L2_CID_STATELESS_H264_START_CODE: case V4L2_CID_CAMERA_ORIENTATION: @@ -1502,21 +1503,26 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_STATELESS_VP8_FRAME: *type = V4L2_CTRL_TYPE_VP8_FRAME; break; - case V4L2_CID_MPEG_VIDEO_HEVC_SPS: + case V4L2_CID_STATELESS_HEVC_SPS: *type = V4L2_CTRL_TYPE_HEVC_SPS; break; - case V4L2_CID_MPEG_VIDEO_HEVC_PPS: + case V4L2_CID_STATELESS_HEVC_PPS: *type = V4L2_CTRL_TYPE_HEVC_PPS; break; - case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: + case V4L2_CID_STATELESS_HEVC_SLICE_PARAMS: *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; + *flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY; break; - case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: + case V4L2_CID_STATELESS_HEVC_SCALING_MATRIX: *type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX; break; - case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: + case V4L2_CID_STATELESS_HEVC_DECODE_PARAMS: *type = V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS; break; + case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS: + *type = V4L2_CTRL_TYPE_U32; + *flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY; + break; case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR: *type = V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR; break; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-priv.h b/drivers/media/v4l2-core/v4l2-ctrls-priv.h index d4bf2c716f97..aba6176fab6c 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-priv.h +++ b/drivers/media/v4l2-core/v4l2-ctrls-priv.h @@ -57,10 +57,9 @@ void cur_to_new(struct v4l2_ctrl *ctrl); void cur_to_req(struct v4l2_ctrl_ref *ref); void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags); void new_to_req(struct v4l2_ctrl_ref *ref); -void req_to_new(struct v4l2_ctrl_ref *ref); +int req_to_new(struct v4l2_ctrl_ref *ref); void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl); void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes); -int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new); int handler_new_ref(struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl *ctrl, struct v4l2_ctrl_ref **ctrl_ref, diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c index 7d098f287fd9..c637049d7a2b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-request.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c @@ -143,7 +143,7 @@ v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id) { struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id); - return (ref && ref->valid_p_req) ? ref->ctrl : NULL; + return (ref && ref->p_req_valid) ? ref->ctrl : NULL; } EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find); @@ -373,7 +373,7 @@ void v4l2_ctrl_request_complete(struct media_request *req, v4l2_ctrl_unlock(master); continue; } - if (ref->valid_p_req) + if (ref->p_req_valid) continue; /* Copy the current control value into the request */ @@ -442,7 +442,7 @@ int v4l2_ctrl_request_setup(struct media_request *req, struct v4l2_ctrl_ref *r = find_ref(hdl, master->cluster[i]->id); - if (r->valid_p_req) { + if (r->p_req_valid) { have_new_data = true; break; } @@ -458,7 +458,11 @@ int v4l2_ctrl_request_setup(struct media_request *req, struct v4l2_ctrl_ref *r = find_ref(hdl, master->cluster[i]->id); - req_to_new(r); + ret = req_to_new(r); + if (ret) { + v4l2_ctrl_unlock(master); + goto error; + } master->cluster[i]->is_new = 1; r->req_done = true; } @@ -490,6 +494,7 @@ int v4l2_ctrl_request_setup(struct media_request *req, break; } +error: media_request_object_put(obj); return ret; } diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 21470de62d72..c314025d977e 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1007,6 +1007,31 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) return -EINVAL; } +static void v4l_sanitize_colorspace(u32 pixelformat, u32 *colorspace, + u32 *encoding, u32 *quantization, + u32 *xfer_func) +{ + bool is_hsv = pixelformat == V4L2_PIX_FMT_HSV24 || + pixelformat == V4L2_PIX_FMT_HSV32; + + if (!v4l2_is_colorspace_valid(*colorspace)) { + *colorspace = V4L2_COLORSPACE_DEFAULT; + *encoding = V4L2_YCBCR_ENC_DEFAULT; + *quantization = V4L2_QUANTIZATION_DEFAULT; + *xfer_func = V4L2_XFER_FUNC_DEFAULT; + } + + if ((!is_hsv && !v4l2_is_ycbcr_enc_valid(*encoding)) || + (is_hsv && !v4l2_is_hsv_enc_valid(*encoding))) + *encoding = V4L2_YCBCR_ENC_DEFAULT; + + if (!v4l2_is_quant_valid(*quantization)) + *quantization = V4L2_QUANTIZATION_DEFAULT; + + if (!v4l2_is_xfer_func_valid(*xfer_func)) + *xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + static void v4l_sanitize_format(struct v4l2_format *fmt) { unsigned int offset; @@ -1026,20 +1051,40 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) * field to the magic value when the extended pixel format structure * isn't used by applications. */ + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || + fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (fmt->fmt.pix.priv != V4L2_PIX_FMT_PRIV_MAGIC) { + fmt->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + + offset = offsetof(struct v4l2_pix_format, priv) + + sizeof(fmt->fmt.pix.priv); + memset(((void *)&fmt->fmt.pix) + offset, 0, + sizeof(fmt->fmt.pix) - offset); + } + } - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return; - - if (fmt->fmt.pix.priv == V4L2_PIX_FMT_PRIV_MAGIC) - return; + /* Replace invalid colorspace values with defaults. */ + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE || + fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + v4l_sanitize_colorspace(fmt->fmt.pix.pixelformat, + &fmt->fmt.pix.colorspace, + &fmt->fmt.pix.ycbcr_enc, + &fmt->fmt.pix.quantization, + &fmt->fmt.pix.xfer_func); + } else if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || + fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + u32 ycbcr_enc = fmt->fmt.pix_mp.ycbcr_enc; + u32 quantization = fmt->fmt.pix_mp.quantization; + u32 xfer_func = fmt->fmt.pix_mp.xfer_func; - fmt->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + v4l_sanitize_colorspace(fmt->fmt.pix_mp.pixelformat, + &fmt->fmt.pix_mp.colorspace, &ycbcr_enc, + &quantization, &xfer_func); - offset = offsetof(struct v4l2_pix_format, priv) - + sizeof(fmt->fmt.pix.priv); - memset(((void *)&fmt->fmt.pix) + offset, 0, - sizeof(fmt->fmt.pix) - offset); + fmt->fmt.pix_mp.ycbcr_enc = ycbcr_enc; + fmt->fmt.pix_mp.quantization = quantization; + fmt->fmt.pix_mp.xfer_func = xfer_func; + } } static int v4l_querycap(const struct v4l2_ioctl_ops *ops, @@ -1296,6 +1341,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_XYUV32: descr = "32-bit XYUV 8-8-8-8"; break; case V4L2_PIX_FMT_VUYA32: descr = "32-bit VUYA 8-8-8-8"; break; case V4L2_PIX_FMT_VUYX32: descr = "32-bit VUYX 8-8-8-8"; break; + case V4L2_PIX_FMT_YUVA32: descr = "32-bit YUVA 8-8-8-8"; break; + case V4L2_PIX_FMT_YUVX32: descr = "32-bit YUVX 8-8-8-8"; break; case V4L2_PIX_FMT_YUV410: descr = "Planar YUV 4:1:0"; break; case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break; case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break; @@ -1306,9 +1353,11 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break; case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break; case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break; + case V4L2_PIX_FMT_P010: descr = "10-bit Y/CbCr 4:2:0"; break; case V4L2_PIX_FMT_NV12_4L4: descr = "Y/CbCr 4:2:0 (4x4 Linear)"; break; case V4L2_PIX_FMT_NV12_16L16: descr = "Y/CbCr 4:2:0 (16x16 Linear)"; break; case V4L2_PIX_FMT_NV12_32L32: descr = "Y/CbCr 4:2:0 (32x32 Linear)"; break; + case V4L2_PIX_FMT_P010_4L4: descr = "10-bit Y/CbCr 4:2:0 (4x4 Linear)"; break; case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break; case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break; case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break; diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 6469f9a25a4e..837e1855f94b 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -925,7 +925,7 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file, if ((!src_q->streaming || src_q->error || list_empty(&src_q->queued_list)) && (!dst_q->streaming || dst_q->error || - list_empty(&dst_q->queued_list))) + (list_empty(&dst_q->queued_list) && !dst_q->last_buffer_dequeued))) return EPOLLERR; spin_lock_irqsave(&src_q->done_lock, flags); diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 1fd6a0c6e1d8..421ce9dbf44c 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -22,10 +22,14 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/atomisp/Kconfig" +source "drivers/staging/media/av7110/Kconfig" + source "drivers/staging/media/hantro/Kconfig" source "drivers/staging/media/imx/Kconfig" +source "drivers/staging/media/ipu3/Kconfig" + source "drivers/staging/media/max96712/Kconfig" source "drivers/staging/media/meson/vdec/Kconfig" @@ -34,14 +38,12 @@ source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/rkvdec/Kconfig" -source "drivers/staging/media/sunxi/Kconfig" +source "drivers/staging/media/stkwebcam/Kconfig" -source "drivers/staging/media/zoran/Kconfig" +source "drivers/staging/media/sunxi/Kconfig" source "drivers/staging/media/tegra-video/Kconfig" -source "drivers/staging/media/ipu3/Kconfig" - -source "drivers/staging/media/av7110/Kconfig" +source "drivers/staging/media/zoran/Kconfig" endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 66d6f6d51c86..950e96f10aad 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ +obj-$(CONFIG_VIDEO_STKWEBCAM) += stkwebcam/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ obj-$(CONFIG_VIDEO_HANTRO) += hantro/ diff --git a/drivers/staging/media/atomisp/Makefile b/drivers/staging/media/atomisp/Makefile index 2485d7b3fee2..fb7b406f50bf 100644 --- a/drivers/staging/media/atomisp/Makefile +++ b/drivers/staging/media/atomisp/Makefile @@ -13,7 +13,6 @@ atomisp = $(srctree)/drivers/staging/media/atomisp/ # SPDX-License-Identifier: GPL-2.0 atomisp-objs += \ - pci/atomisp_acc.o \ pci/atomisp_cmd.o \ pci/atomisp_compat_css20.o \ pci/atomisp_csi2.o \ @@ -45,9 +44,7 @@ atomisp-objs += \ pci/camera/pipe/src/pipe_util.o \ pci/camera/util/src/util.o \ pci/hmm/hmm_bo.o \ - pci/hmm/hmm_dynamic_pool.o \ pci/hmm/hmm.o \ - pci/hmm/hmm_reserved_pool.o \ pci/ia_css_device_access.o \ pci/ia_css_isp_configs.o \ pci/ia_css_isp_states.o \ diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 00d6842c07d6..3c81ab73cdae 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -616,13 +616,15 @@ static int mt9m114_get_intg_factor(struct i2c_client *client, struct camera_mipi_info *info, const struct mt9m114_res_struct *res) { - struct atomisp_sensor_mode_data *buf = &info->data; + struct atomisp_sensor_mode_data *buf; u32 reg_val; int ret; if (!info) return -EINVAL; + buf = &info->data; + ret = mt9m114_read_reg(client, MISENSOR_32BIT, REG_PIXEL_CLK, ®_val); if (ret) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index da98094d7094..d5d099ac1b70 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -906,22 +906,17 @@ static int ov2722_get_fmt(struct v4l2_subdev *sd, static int ov2722_detect(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; + u16 high = 0, low = 0; u16 id; u8 revision; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_CHIP_ID_L, &low); + ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_CHIP_ID_H, &high); + ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_CHIP_ID_L, &low); id = (high << 8) | low; if ((id != OV2722_ID) && (id != OV2720_ID)) { @@ -929,8 +924,9 @@ static int ov2722_detect(struct i2c_client *client) return -ENODEV; } - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_SUB_ID, &high); + high = 0; + ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_SUB_ID, &high); revision = (u8)high & 0x0f; dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h index 79df07bd69b6..a1366666f49c 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h @@ -855,7 +855,7 @@ static struct ov5693_reg const ov5693_1616x1216_30fps[] = { {OV5693_8BIT, 0x3813, 0x06}, /*{3812,3813} windowing Y offset*/ {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/ {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/ - {OV5693_8BIT, 0x3820, 0x00}, /*FLIP/Binnning control*/ + {OV5693_8BIT, 0x3820, 0x00}, /*FLIP/Binning control*/ {OV5693_8BIT, 0x3821, 0x1e}, /*MIRROR control*/ {OV5693_8BIT, 0x5002, 0x00}, {OV5693_8BIT, 0x5041, 0x84}, diff --git a/drivers/staging/media/atomisp/include/hmm/hmm.h b/drivers/staging/media/atomisp/include/hmm/hmm.h index b48bdf5c274c..c0384bb0a762 100644 --- a/drivers/staging/media/atomisp/include/hmm/hmm.h +++ b/drivers/staging/media/atomisp/include/hmm/hmm.h @@ -26,21 +26,18 @@ #include <linux/slab.h> #include <linux/mm.h> -#include "hmm/hmm_pool.h" +#include "hmm_common.h" +#include "hmm/hmm_bo.h" #include "ia_css_types.h" #define mmgr_NULL ((ia_css_ptr)0) #define mmgr_EXCEPTION ((ia_css_ptr) - 1) -int hmm_pool_register(unsigned int pool_size, enum hmm_pool_type pool_type); -void hmm_pool_unregister(enum hmm_pool_type pool_type); - int hmm_init(void); void hmm_cleanup(void); -ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type, - int from_highmem, const void __user *userptr, - const uint16_t attrs); +ia_css_ptr hmm_alloc(size_t bytes); +ia_css_ptr hmm_create_from_userdata(size_t bytes, const void __user *userptr); void hmm_free(ia_css_ptr ptr); int hmm_load(ia_css_ptr virt, void *data, unsigned int bytes); int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes); @@ -69,17 +66,6 @@ void hmm_vunmap(ia_css_ptr virt); void hmm_flush_vmap(ia_css_ptr virt); /* - * Address translation from ISP shared memory address to kernel virtual address - * if the memory is not vmmaped, then do it. - */ -void *hmm_isp_vaddr_to_host_vaddr(ia_css_ptr ptr, bool cached); - -/* - * Address translation from kernel virtual address to ISP shared memory address - */ -ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr); - -/* * map ISP memory starts with virt to specific vma. * * used for mmap operation. @@ -89,16 +75,6 @@ ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr); */ int hmm_mmap(struct vm_area_struct *vma, ia_css_ptr virt); -/* show memory statistic - */ -void hmm_show_mem_stat(const char *func, const int line); - -/* init memory statistic - */ -void hmm_init_mem_stat(int res_pgnr, int dyc_en, int dyc_pgnr); - -extern bool dypool_enable; -extern unsigned int dypool_pgnr; extern struct hmm_bo_device bo_device; #endif diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h index 8c78a5d87b65..385e22fc4a46 100644 --- a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h +++ b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h @@ -76,17 +76,10 @@ enum hmm_bo_type { HMM_BO_PRIVATE, - HMM_BO_SHARE, HMM_BO_USER, HMM_BO_LAST, }; -enum hmm_page_type { - HMM_PAGE_TYPE_RESERVED, - HMM_PAGE_TYPE_DYNAMIC, - HMM_PAGE_TYPE_GENERAL, -}; - #define HMM_BO_MASK 0x1 #define HMM_BO_FREE 0x0 #define HMM_BO_ALLOCED 0x1 @@ -121,11 +114,6 @@ struct hmm_bo_device { struct kmem_cache *bo_cache; }; -struct hmm_page_object { - struct page *page; - enum hmm_page_type type; -}; - struct hmm_buffer_object { struct hmm_bo_device *bdev; struct list_head list; @@ -136,8 +124,6 @@ struct hmm_buffer_object { /* mutex protecting this BO */ struct mutex mutex; enum hmm_bo_type type; - struct hmm_page_object *page_obj; /* physical pages */ - int from_highmem; int mmap_count; int status; int mem_type; @@ -218,34 +204,20 @@ void hmm_bo_ref(struct hmm_buffer_object *bo); */ void hmm_bo_unref(struct hmm_buffer_object *bo); -/* - * allocate/free physical pages for the bo. will try to alloc mem - * from highmem if from_highmem is set, and type indicate that the - * pages will be allocated by using video driver (for share buffer) - * or by ISP driver itself. - */ - int hmm_bo_allocated(struct hmm_buffer_object *bo); /* - * allocate/free physical pages for the bo. will try to alloc mem - * from highmem if from_highmem is set, and type indicate that the + * Allocate/Free physical pages for the bo. Type indicates if the * pages will be allocated by using video driver (for share buffer) * or by ISP driver itself. */ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo, - enum hmm_bo_type type, int from_highmem, - const void __user *userptr, bool cached); + enum hmm_bo_type type, + const void __user *userptr); void hmm_bo_free_pages(struct hmm_buffer_object *bo); int hmm_bo_page_allocated(struct hmm_buffer_object *bo); /* - * get physical page info of the bo. - */ -int hmm_bo_get_page_info(struct hmm_buffer_object *bo, - struct hmm_page_object **page_obj, int *pgnr); - -/* * bind/unbind the physical pages to a virtual address space. */ int hmm_bo_bind(struct hmm_buffer_object *bo); @@ -280,9 +252,6 @@ void hmm_bo_vunmap(struct hmm_buffer_object *bo); int hmm_bo_mmap(struct vm_area_struct *vma, struct hmm_buffer_object *bo); -extern struct hmm_pool dynamic_pool; -extern struct hmm_pool reserved_pool; - /* * find the buffer object by its virtual address vaddr. * return NULL if no such buffer object found. diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_common.h b/drivers/staging/media/atomisp/include/hmm/hmm_common.h index 7152e9b52ba4..d8610b135de0 100644 --- a/drivers/staging/media/atomisp/include/hmm/hmm_common.h +++ b/drivers/staging/media/atomisp/include/hmm/hmm_common.h @@ -68,30 +68,4 @@ #define check_null_return_void(ptr, fmt, arg ...) \ var_equal_return_void(ptr, NULL, fmt, ## arg) -/* hmm_mem_stat is used to trace the hmm mem used by ISP pipe. The unit is page - * number. - * - * res_size: reserved mem pool size, being allocated from system at system boot time. - * res_size >= res_cnt. - * sys_size: system mem pool size, being allocated from system at camera running time. - * dyc_size: dynamic mem pool size. - * dyc_thr: dynamic mem pool high watermark. - * dyc_size <= dyc_thr. - * usr_size: user ptr mem size. - * - * res_cnt: track the mem allocated from reserved pool at camera running time. - * tol_cnt: track the total mem used by ISP pipe at camera running time. - */ -struct _hmm_mem_stat { - int res_size; - int sys_size; - int dyc_size; - int dyc_thr; - int usr_size; - int res_cnt; - int tol_cnt; -}; - -extern struct _hmm_mem_stat hmm_mem_stat; - #endif diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_pool.h b/drivers/staging/media/atomisp/include/hmm/hmm_pool.h deleted file mode 100644 index 3fef57de973c..000000000000 --- a/drivers/staging/media/atomisp/include/hmm/hmm_pool.h +++ /dev/null @@ -1,116 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ -#ifndef __HMM_POOL_H__ -#define __HMM_POOL_H__ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/kref.h> -#include "hmm_common.h" -#include "hmm/hmm_bo.h" - -#define ALLOC_PAGE_FAIL_NUM 5 - -enum hmm_pool_type { - HMM_POOL_TYPE_RESERVED, - HMM_POOL_TYPE_DYNAMIC, -}; - -/** - * struct hmm_pool_ops - memory pool callbacks. - * - * @pool_init: initialize the memory pool. - * @pool_exit: uninitialize the memory pool. - * @pool_alloc_pages: allocate pages from memory pool. - * @pool_free_pages: free pages to memory pool. - * @pool_inited: check whether memory pool is initialized. - */ -struct hmm_pool_ops { - int (*pool_init)(void **pool, unsigned int pool_size); - void (*pool_exit)(void **pool); - unsigned int (*pool_alloc_pages)(void *pool, - struct hmm_page_object *page_obj, - unsigned int size, bool cached); - void (*pool_free_pages)(void *pool, - struct hmm_page_object *page_obj); - int (*pool_inited)(void *pool); -}; - -struct hmm_pool { - struct hmm_pool_ops *pops; - - void *pool_info; -}; - -/** - * struct hmm_reserved_pool_info - represents reserved pool private data. - * @pages: a array that store physical pages. - * The array is as reserved memory pool. - * @index: to indicate the first blank page number - * in reserved memory pool(pages array). - * @pgnr: the valid page amount in reserved memory - * pool. - * @list_lock: list lock is used to protect the operation - * to reserved memory pool. - * @flag: reserved memory pool state flag. - */ -struct hmm_reserved_pool_info { - struct page **pages; - - unsigned int index; - unsigned int pgnr; - spinlock_t list_lock; - bool initialized; -}; - -/** - * struct hmm_dynamic_pool_info - represents dynamic pool private data. - * @pages_list: a list that store physical pages. - * The pages list is as dynamic memory pool. - * @list_lock: list lock is used to protect the operation - * to dynamic memory pool. - * @flag: dynamic memory pool state flag. - * @pgptr_cache: struct kmem_cache, manages a cache. - */ -struct hmm_dynamic_pool_info { - struct list_head pages_list; - - /* list lock is used to protect the free pages block lists */ - spinlock_t list_lock; - - struct kmem_cache *pgptr_cache; - bool initialized; - - unsigned int pool_size; - unsigned int pgnr; -}; - -struct hmm_page { - struct page *page; - struct list_head list; -}; - -extern struct hmm_pool_ops reserved_pops; -extern struct hmm_pool_ops dynamic_pops; - -#endif diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index 22c4103b0385..f96f5adbd9de 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -740,24 +740,6 @@ enum atomisp_frame_status { ATOMISP_FRAME_STATUS_FLASH_FAILED, }; -enum atomisp_acc_type { - ATOMISP_ACC_STANDALONE, /* Stand-alone acceleration */ - ATOMISP_ACC_OUTPUT, /* Accelerator stage on output frame */ - ATOMISP_ACC_VIEWFINDER /* Accelerator stage on viewfinder frame */ -}; - -enum atomisp_acc_arg_type { - ATOMISP_ACC_ARG_SCALAR_IN, /* Scalar input argument */ - ATOMISP_ACC_ARG_SCALAR_OUT, /* Scalar output argument */ - ATOMISP_ACC_ARG_SCALAR_IO, /* Scalar in/output argument */ - ATOMISP_ACC_ARG_PTR_IN, /* Pointer input argument */ - ATOMISP_ACC_ARG_PTR_OUT, /* Pointer output argument */ - ATOMISP_ACC_ARG_PTR_IO, /* Pointer in/output argument */ - ATOMISP_ARG_PTR_NOFLUSH, /* Pointer argument will not be flushed */ - ATOMISP_ARG_PTR_STABLE, /* Pointer input argument that is stable */ - ATOMISP_ACC_ARG_FRAME /* Frame argument */ -}; - /* ISP memories, isp2400 */ enum atomisp_acc_memory { ATOMISP_ACC_MEMORY_PMEM0 = 0, @@ -836,56 +818,6 @@ enum atomisp_burst_capture_options { #define EXT_ISP_SHOT_MODE_ANIMATED_PHOTO 10 #define EXT_ISP_SHOT_MODE_SPORTS 11 -struct atomisp_sp_arg { - enum atomisp_acc_arg_type type; /* Type of SP argument */ - void *value; /* Value of SP argument */ - unsigned int size; /* Size of SP argument */ -}; - -/* Acceleration API */ - -/* For CSS 1.0 only */ -struct atomisp_acc_fw_arg { - unsigned int fw_handle; - unsigned int index; - void __user *value; - size_t size; -}; - -/* - * Set arguments after first mapping with ATOMISP_IOC_ACC_S_MAPPED_ARG. - */ -struct atomisp_acc_s_mapped_arg { - unsigned int fw_handle; - __u32 memory; /* one of enum atomisp_acc_memory */ - size_t length; - unsigned long css_ptr; -}; - -struct atomisp_acc_fw_abort { - unsigned int fw_handle; - /* Timeout in us */ - unsigned int timeout; -}; - -struct atomisp_acc_fw_load { - unsigned int size; - unsigned int fw_handle; - void __user *data; -}; - -/* - * Load firmware to specified pipeline. - */ -struct atomisp_acc_fw_load_to_pipe { - __u32 flags; /* Flags, see below for valid values */ - unsigned int fw_handle; /* Handle, filled by kernel. */ - __u32 size; /* Firmware binary size */ - void __user *data; /* Pointer to firmware */ - __u32 type; /* Binary type */ - __u32 reserved[3]; /* Set to zero */ -}; - /* * Set Senor run mode */ @@ -893,37 +825,6 @@ struct atomisp_s_runmode { __u32 mode; }; -#define ATOMISP_ACC_FW_LOAD_FL_PREVIEW BIT(0) -#define ATOMISP_ACC_FW_LOAD_FL_COPY BIT(1) -#define ATOMISP_ACC_FW_LOAD_FL_VIDEO BIT(2) -#define ATOMISP_ACC_FW_LOAD_FL_CAPTURE BIT(3) -#define ATOMISP_ACC_FW_LOAD_FL_ACC BIT(4) -#define ATOMISP_ACC_FW_LOAD_FL_ENABLE BIT(16) - -#define ATOMISP_ACC_FW_LOAD_TYPE_NONE 0 /* Normal binary: don't use */ -#define ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT 1 /* Stage on output */ -#define ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER 2 /* Stage on viewfinder */ -#define ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE 3 /* Stand-alone acceleration */ - -struct atomisp_acc_map { - __u32 flags; /* Flags, see list below */ - __u32 length; /* Length of data in bytes */ - void __user *user_ptr; /* Pointer into user space */ - unsigned long css_ptr; /* Pointer into CSS address space */ - __u32 reserved[4]; /* Set to zero */ -}; - -#define ATOMISP_MAP_FLAG_NOFLUSH 0x0001 /* Do not flush cache */ -#define ATOMISP_MAP_FLAG_CACHED 0x0002 /* Enable cache */ -#define ATOMISP_MAP_FLAG_CONTIGUOUS 0x0004 -#define ATOMISP_MAP_FLAG_CLEARED 0x0008 - -struct atomisp_acc_state { - __u32 flags; /* Flags, see list below */ -#define ATOMISP_STATE_FLAG_ENABLE ATOMISP_ACC_FW_LOAD_FL_ENABLE - unsigned int fw_handle; -}; - struct atomisp_update_exposure { unsigned int gain; unsigned int digi_gain; @@ -1091,29 +992,6 @@ struct atomisp_sensor_ae_bracketing_lut { #define ATOMISP_IOC_S_3A_CONFIG \ _IOW('v', BASE_VIDIOC_PRIVATE + 23, struct atomisp_3a_config) -/* Accelerate ioctls */ -#define ATOMISP_IOC_ACC_LOAD \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_load) - -#define ATOMISP_IOC_ACC_UNLOAD \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 24, unsigned int) - -/* For CSS 1.0 only */ -#define ATOMISP_IOC_ACC_S_ARG \ - _IOW('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_arg) - -#define ATOMISP_IOC_ACC_START \ - _IOW('v', BASE_VIDIOC_PRIVATE + 24, unsigned int) - -#define ATOMISP_IOC_ACC_WAIT \ - _IOW('v', BASE_VIDIOC_PRIVATE + 25, unsigned int) - -#define ATOMISP_IOC_ACC_ABORT \ - _IOW('v', BASE_VIDIOC_PRIVATE + 25, struct atomisp_acc_fw_abort) - -#define ATOMISP_IOC_ACC_DESTAB \ - _IOW('v', BASE_VIDIOC_PRIVATE + 25, struct atomisp_acc_fw_arg) - /* sensor OTP memory read */ #define ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA \ _IOWR('v', BASE_VIDIOC_PRIVATE + 26, struct v4l2_private_int_data) @@ -1133,24 +1011,6 @@ struct atomisp_sensor_ae_bracketing_lut { #define ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA \ _IOWR('v', BASE_VIDIOC_PRIVATE + 29, struct v4l2_private_int_data) -/* - * Ioctls to map and unmap user buffers to CSS address space for acceleration. - * User fills fields length and user_ptr and sets other fields to zero, - * kernel may modify the flags and sets css_ptr. - */ -#define ATOMISP_IOC_ACC_MAP \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map) - -/* User fills fields length, user_ptr, and css_ptr and zeroes other fields. */ -#define ATOMISP_IOC_ACC_UNMAP \ - _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map) - -#define ATOMISP_IOC_ACC_S_MAPPED_ARG \ - _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_s_mapped_arg) - -#define ATOMISP_IOC_ACC_LOAD_TO_PIPE \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 31, struct atomisp_acc_fw_load_to_pipe) - #define ATOMISP_IOC_S_PARAMETERS \ _IOW('v', BASE_VIDIOC_PRIVATE + 32, struct atomisp_parameters) @@ -1184,12 +1044,6 @@ struct atomisp_sensor_ae_bracketing_lut { #define ATOMISP_IOC_S_EXPOSURE_WINDOW \ _IOW('v', BASE_VIDIOC_PRIVATE + 40, struct atomisp_ae_window) -#define ATOMISP_IOC_S_ACC_STATE \ - _IOW('v', BASE_VIDIOC_PRIVATE + 41, struct atomisp_acc_state) - -#define ATOMISP_IOC_G_ACC_STATE \ - _IOR('v', BASE_VIDIOC_PRIVATE + 41, struct atomisp_acc_state) - #define ATOMISP_IOC_INJECT_A_FAKE_EVENT \ _IOW('v', BASE_VIDIOC_PRIVATE + 42, int) diff --git a/drivers/staging/media/atomisp/notes.txt b/drivers/staging/media/atomisp/notes.txt new file mode 100644 index 000000000000..d128b792e05f --- /dev/null +++ b/drivers/staging/media/atomisp/notes.txt @@ -0,0 +1,30 @@ +Some notes about the working of the atomisp drivers (learned while working +on cleaning it up). + +The atomisp seems to be a generic DSP(ISP) like processor without a fixed +pipeline. It does not have its own memory, but instead uses main memory. +The ISP has its own address-space and main memory needs to be mapped into +its address space through the ISP's MMU. + +Memory is allocated by the hmm code. hmm_alloc() returns an ISP virtual +address. The hmm code keeps a list of all allocations and when necessary +the hmm code finds the backing hmm-buffer-object (hmm_bo) by looking +up the hmm_bo based on the ISP virtual address. + +The actual processing pipeline is made by loading one or more programs, +called binaries. The shisp_240??0_v21.bin firmware file contains many +different binaries. Binaries are picked by filling a ia_css_binary_descr +struct with various input and output parameters and then calling +ia_css_binary_find(). Some binaries support creating multiple outputs +(preview + video frame?) at the same time. + +For example for the /dev/video0 preview node load_preview_binaries() +from atomisp/pci/sh_css.c is called and then loads a preview and +optionally a scalar binary. Note when digital zoom is disabled +(it is enabled by default) only the preview binary is loaded. +So in this case a single binary handles the entire pipeline. + +Since getting a picture requires multiple processing steps, +this means that unlike in fixed pipelines the soft pipelines +on the ISP can do multiple processing steps in a single pipeline +element (in a single binary). diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp_acc.c deleted file mode 100644 index 28cb271663c4..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp_acc.c +++ /dev/null @@ -1,625 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Support for Clovertrail PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -/* - * This file implements loadable acceleration firmware API, - * including ioctls to map and unmap acceleration parameters and buffers. - */ - -#include <linux/init.h> -#include <media/v4l2-event.h> - -#include "hmm.h" - -#include "atomisp_acc.h" -#include "atomisp_internal.h" -#include "atomisp_compat.h" -#include "atomisp_cmd.h" - -#include "ia_css.h" - -static const struct { - unsigned int flag; - enum ia_css_pipe_id pipe_id; -} acc_flag_to_pipe[] = { - { ATOMISP_ACC_FW_LOAD_FL_PREVIEW, IA_CSS_PIPE_ID_PREVIEW }, - { ATOMISP_ACC_FW_LOAD_FL_COPY, IA_CSS_PIPE_ID_COPY }, - { ATOMISP_ACC_FW_LOAD_FL_VIDEO, IA_CSS_PIPE_ID_VIDEO }, - { ATOMISP_ACC_FW_LOAD_FL_CAPTURE, IA_CSS_PIPE_ID_CAPTURE }, - { ATOMISP_ACC_FW_LOAD_FL_ACC, IA_CSS_PIPE_ID_ACC } -}; - -/* - * Allocate struct atomisp_acc_fw along with space for firmware. - * The returned struct atomisp_acc_fw is cleared (firmware region is not). - */ -static struct atomisp_acc_fw *acc_alloc_fw(unsigned int fw_size) -{ - struct atomisp_acc_fw *acc_fw; - - acc_fw = kzalloc(sizeof(*acc_fw), GFP_KERNEL); - if (!acc_fw) - return NULL; - - acc_fw->fw = vmalloc(fw_size); - if (!acc_fw->fw) { - kfree(acc_fw); - return NULL; - } - - return acc_fw; -} - -static void acc_free_fw(struct atomisp_acc_fw *acc_fw) -{ - vfree(acc_fw->fw); - kfree(acc_fw); -} - -static struct atomisp_acc_fw * -acc_get_fw(struct atomisp_sub_device *asd, unsigned int handle) -{ - struct atomisp_acc_fw *acc_fw; - - list_for_each_entry(acc_fw, &asd->acc.fw, list) - if (acc_fw->handle == handle) - return acc_fw; - - return NULL; -} - -static struct atomisp_map *acc_get_map(struct atomisp_sub_device *asd, - unsigned long css_ptr, size_t length) -{ - struct atomisp_map *atomisp_map; - - list_for_each_entry(atomisp_map, &asd->acc.memory_maps, list) { - if (atomisp_map->ptr == css_ptr && - atomisp_map->length == length) - return atomisp_map; - } - return NULL; -} - -static int acc_stop_acceleration(struct atomisp_sub_device *asd) -{ - int ret; - - ret = atomisp_css_stop_acc_pipe(asd); - atomisp_css_destroy_acc_pipe(asd); - - return ret; -} - -void atomisp_acc_cleanup(struct atomisp_device *isp) -{ - int i; - - for (i = 0; i < isp->num_of_streams; i++) - ida_destroy(&isp->asd[i].acc.ida); -} - -void atomisp_acc_release(struct atomisp_sub_device *asd) -{ - struct atomisp_acc_fw *acc_fw, *ta; - struct atomisp_map *atomisp_map, *tm; - - /* Stop acceleration if already running */ - if (asd->acc.pipeline) - acc_stop_acceleration(asd); - - /* Unload all loaded acceleration binaries */ - list_for_each_entry_safe(acc_fw, ta, &asd->acc.fw, list) { - list_del(&acc_fw->list); - ida_free(&asd->acc.ida, acc_fw->handle); - acc_free_fw(acc_fw); - } - - /* Free all mapped memory blocks */ - list_for_each_entry_safe(atomisp_map, tm, &asd->acc.memory_maps, list) { - list_del(&atomisp_map->list); - hmm_free(atomisp_map->ptr); - kfree(atomisp_map); - } -} - -int atomisp_acc_load_to_pipe(struct atomisp_sub_device *asd, - struct atomisp_acc_fw_load_to_pipe *user_fw) -{ - static const unsigned int pipeline_flags = - ATOMISP_ACC_FW_LOAD_FL_PREVIEW | ATOMISP_ACC_FW_LOAD_FL_COPY | - ATOMISP_ACC_FW_LOAD_FL_VIDEO | - ATOMISP_ACC_FW_LOAD_FL_CAPTURE | ATOMISP_ACC_FW_LOAD_FL_ACC; - - struct atomisp_acc_fw *acc_fw; - int handle; - - if (!user_fw->data || user_fw->size < sizeof(*acc_fw->fw)) - return -EINVAL; - - /* Binary has to be enabled at least for one pipeline */ - if (!(user_fw->flags & pipeline_flags)) - return -EINVAL; - - /* We do not support other flags yet */ - if (user_fw->flags & ~pipeline_flags) - return -EINVAL; - - if (user_fw->type < ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT || - user_fw->type > ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE) - return -EINVAL; - - if (asd->acc.pipeline || asd->acc.extension_mode) - return -EBUSY; - - acc_fw = acc_alloc_fw(user_fw->size); - if (!acc_fw) - return -ENOMEM; - - if (copy_from_user(acc_fw->fw, user_fw->data, user_fw->size)) { - acc_free_fw(acc_fw); - return -EFAULT; - } - - handle = ida_alloc(&asd->acc.ida, GFP_KERNEL); - if (handle < 0) { - acc_free_fw(acc_fw); - return -ENOSPC; - } - - user_fw->fw_handle = handle; - acc_fw->handle = handle; - acc_fw->flags = user_fw->flags; - acc_fw->type = user_fw->type; - acc_fw->fw->handle = handle; - - /* - * correct isp firmware type in order ISP firmware can be appended - * to correct pipe properly - */ - if (acc_fw->fw->type == ia_css_isp_firmware) { - static const int type_to_css[] = { - [ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT] = - IA_CSS_ACC_OUTPUT, - [ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER] = - IA_CSS_ACC_VIEWFINDER, - [ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE] = - IA_CSS_ACC_STANDALONE, - }; - acc_fw->fw->info.isp.type = type_to_css[acc_fw->type]; - } - - list_add_tail(&acc_fw->list, &asd->acc.fw); - return 0; -} - -int atomisp_acc_load(struct atomisp_sub_device *asd, - struct atomisp_acc_fw_load *user_fw) -{ - struct atomisp_acc_fw_load_to_pipe ltp = {0}; - int r; - - ltp.flags = ATOMISP_ACC_FW_LOAD_FL_ACC; - ltp.type = ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE; - ltp.size = user_fw->size; - ltp.data = user_fw->data; - r = atomisp_acc_load_to_pipe(asd, <p); - user_fw->fw_handle = ltp.fw_handle; - return r; -} - -int atomisp_acc_unload(struct atomisp_sub_device *asd, unsigned int *handle) -{ - struct atomisp_acc_fw *acc_fw; - - if (asd->acc.pipeline || asd->acc.extension_mode) - return -EBUSY; - - acc_fw = acc_get_fw(asd, *handle); - if (!acc_fw) - return -EINVAL; - - list_del(&acc_fw->list); - ida_free(&asd->acc.ida, acc_fw->handle); - acc_free_fw(acc_fw); - - return 0; -} - -int atomisp_acc_start(struct atomisp_sub_device *asd, unsigned int *handle) -{ - struct atomisp_device *isp = asd->isp; - struct atomisp_acc_fw *acc_fw; - int ret; - unsigned int nbin; - - if (asd->acc.pipeline || asd->acc.extension_mode) - return -EBUSY; - - /* Invalidate caches. FIXME: should flush only necessary buffers */ - wbinvd(); - - ret = atomisp_css_create_acc_pipe(asd); - if (ret) - return ret; - - nbin = 0; - list_for_each_entry(acc_fw, &asd->acc.fw, list) { - if (*handle != 0 && *handle != acc_fw->handle) - continue; - - if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE) - continue; - - /* Add the binary into the pipeline */ - ret = atomisp_css_load_acc_binary(asd, acc_fw->fw, nbin); - if (ret < 0) { - dev_err(isp->dev, "acc_load_binary failed\n"); - goto err_stage; - } - - ret = atomisp_css_set_acc_parameters(acc_fw); - if (ret < 0) { - dev_err(isp->dev, "acc_set_parameters failed\n"); - goto err_stage; - } - nbin++; - } - if (nbin < 1) { - /* Refuse creating pipelines with no binaries */ - dev_err(isp->dev, "%s: no acc binary available\n", __func__); - ret = -EINVAL; - goto err_stage; - } - - ret = atomisp_css_start_acc_pipe(asd); - if (ret) { - dev_err(isp->dev, "%s: atomisp_acc_start_acc_pipe failed\n", - __func__); - goto err_stage; - } - - return 0; - -err_stage: - atomisp_css_destroy_acc_pipe(asd); - return ret; -} - -int atomisp_acc_wait(struct atomisp_sub_device *asd, unsigned int *handle) -{ - struct atomisp_device *isp = asd->isp; - int ret; - - if (!asd->acc.pipeline) - return -ENOENT; - - if (*handle && !acc_get_fw(asd, *handle)) - return -EINVAL; - - ret = atomisp_css_wait_acc_finish(asd); - if (acc_stop_acceleration(asd) == -EIO) { - atomisp_reset(isp); - return -EINVAL; - } - - return ret; -} - -void atomisp_acc_done(struct atomisp_sub_device *asd, unsigned int handle) -{ - struct v4l2_event event = { 0 }; - - event.type = V4L2_EVENT_ATOMISP_ACC_COMPLETE; - event.u.frame_sync.frame_sequence = atomic_read(&asd->sequence); - event.id = handle; - - v4l2_event_queue(asd->subdev.devnode, &event); -} - -int atomisp_acc_map(struct atomisp_sub_device *asd, struct atomisp_acc_map *map) -{ - struct atomisp_map *atomisp_map; - ia_css_ptr cssptr; - int pgnr; - - if (map->css_ptr) - return -EINVAL; - - if (asd->acc.pipeline) - return -EBUSY; - - if (map->user_ptr) { - /* Buffer to map must be page-aligned */ - if ((unsigned long)map->user_ptr & ~PAGE_MASK) { - dev_err(asd->isp->dev, - "%s: mapped buffer address %p is not page aligned\n", - __func__, map->user_ptr); - return -EINVAL; - } - - pgnr = DIV_ROUND_UP(map->length, PAGE_SIZE); - if (pgnr < ((PAGE_ALIGN(map->length)) >> PAGE_SHIFT)) { - dev_err(asd->isp->dev, - "user space memory size is less than the expected size..\n"); - return -ENOMEM; - } else if (pgnr > ((PAGE_ALIGN(map->length)) >> PAGE_SHIFT)) { - dev_err(asd->isp->dev, - "user space memory size is large than the expected size..\n"); - return -ENOMEM; - } - - cssptr = hmm_alloc(map->length, HMM_BO_USER, 0, map->user_ptr, - map->flags & ATOMISP_MAP_FLAG_CACHED); - - } else { - /* Allocate private buffer. */ - cssptr = hmm_alloc(map->length, HMM_BO_PRIVATE, 0, NULL, - map->flags & ATOMISP_MAP_FLAG_CACHED); - } - - if (!cssptr) - return -ENOMEM; - - atomisp_map = kmalloc(sizeof(*atomisp_map), GFP_KERNEL); - if (!atomisp_map) { - hmm_free(cssptr); - return -ENOMEM; - } - atomisp_map->ptr = cssptr; - atomisp_map->length = map->length; - list_add(&atomisp_map->list, &asd->acc.memory_maps); - - dev_dbg(asd->isp->dev, "%s: userptr %p, css_address 0x%x, size %d\n", - __func__, map->user_ptr, cssptr, map->length); - map->css_ptr = cssptr; - return 0; -} - -int atomisp_acc_unmap(struct atomisp_sub_device *asd, - struct atomisp_acc_map *map) -{ - struct atomisp_map *atomisp_map; - - if (asd->acc.pipeline) - return -EBUSY; - - atomisp_map = acc_get_map(asd, map->css_ptr, map->length); - if (!atomisp_map) - return -EINVAL; - - list_del(&atomisp_map->list); - hmm_free(atomisp_map->ptr); - kfree(atomisp_map); - return 0; -} - -int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd, - struct atomisp_acc_s_mapped_arg *arg) -{ - struct atomisp_acc_fw *acc_fw; - - if (arg->memory >= ATOMISP_ACC_NR_MEMORY) - return -EINVAL; - - if (asd->acc.pipeline) - return -EBUSY; - - acc_fw = acc_get_fw(asd, arg->fw_handle); - if (!acc_fw) - return -EINVAL; - - if (arg->css_ptr != 0 || arg->length != 0) { - /* Unless the parameter is cleared, check that it exists */ - if (!acc_get_map(asd, arg->css_ptr, arg->length)) - return -EINVAL; - } - - acc_fw->args[arg->memory].length = arg->length; - acc_fw->args[arg->memory].css_ptr = arg->css_ptr; - - dev_dbg(asd->isp->dev, "%s: mem %d, address %p, size %ld\n", - __func__, arg->memory, (void *)arg->css_ptr, - (unsigned long)arg->length); - return 0; -} - -static void atomisp_acc_unload_some_extensions(struct atomisp_sub_device *asd, - int i, - struct atomisp_acc_fw *acc_fw) -{ - while (--i >= 0) { - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - atomisp_css_unload_acc_extension(asd, acc_fw->fw, - acc_flag_to_pipe[i].pipe_id); - } - } -} - -/* - * Appends the loaded acceleration binary extensions to the - * current ISP mode. Must be called just before sh_css_start(). - */ -int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) -{ - struct atomisp_acc_fw *acc_fw; - bool ext_loaded = false; - bool continuous = asd->continuous_mode->val && - asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW; - int ret = 0, i = -1; - struct atomisp_device *isp = asd->isp; - - if (asd->acc.pipeline || asd->acc.extension_mode) - return -EBUSY; - - /* Invalidate caches. FIXME: should flush only necessary buffers */ - wbinvd(); - - list_for_each_entry(acc_fw, &asd->acc.fw, list) { - if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT && - acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER) - continue; - - for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) { - /* - * QoS (ACC pipe) acceleration stages are - * currently allowed only in continuous mode. - * Skip them for all other modes. - */ - if (!continuous && - acc_flag_to_pipe[i].flag == - ATOMISP_ACC_FW_LOAD_FL_ACC) - continue; - - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - ret = atomisp_css_load_acc_extension(asd, - acc_fw->fw, - acc_flag_to_pipe[i].pipe_id, - acc_fw->type); - if (ret) { - atomisp_acc_unload_some_extensions(asd, i, acc_fw); - goto error; - } - - ext_loaded = true; - } - } - - ret = atomisp_css_set_acc_parameters(acc_fw); - if (ret < 0) { - atomisp_acc_unload_some_extensions(asd, i, acc_fw); - goto error; - } - } - - if (!ext_loaded) - return ret; - - ret = atomisp_css_update_stream(asd); - if (ret) { - dev_err(isp->dev, "%s: update stream failed.\n", __func__); - atomisp_acc_unload_extensions(asd); - goto error; - } - - asd->acc.extension_mode = true; - return 0; - -error: - list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) { - if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT && - acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER) - continue; - - for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) { - if (!continuous && - acc_flag_to_pipe[i].flag == - ATOMISP_ACC_FW_LOAD_FL_ACC) - continue; - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - atomisp_css_unload_acc_extension(asd, - acc_fw->fw, - acc_flag_to_pipe[i].pipe_id); - } - } - } - return ret; -} - -void atomisp_acc_unload_extensions(struct atomisp_sub_device *asd) -{ - struct atomisp_acc_fw *acc_fw; - int i; - - if (!asd->acc.extension_mode) - return; - - list_for_each_entry_reverse(acc_fw, &asd->acc.fw, list) { - if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT && - acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER) - continue; - - for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) { - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - atomisp_css_unload_acc_extension(asd, - acc_fw->fw, - acc_flag_to_pipe[i].pipe_id); - } - } - } - - asd->acc.extension_mode = false; -} - -int atomisp_acc_set_state(struct atomisp_sub_device *asd, - struct atomisp_acc_state *arg) -{ - struct atomisp_acc_fw *acc_fw; - bool enable = (arg->flags & ATOMISP_STATE_FLAG_ENABLE) != 0; - struct ia_css_pipe *pipe; - int r; - int i; - - if (!asd->acc.extension_mode) - return -EBUSY; - - if (arg->flags & ~ATOMISP_STATE_FLAG_ENABLE) - return -EINVAL; - - acc_fw = acc_get_fw(asd, arg->fw_handle); - if (!acc_fw) - return -EINVAL; - - if (enable) - wbinvd(); - - for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) { - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - pipe = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. - pipes[acc_flag_to_pipe[i].pipe_id]; - r = ia_css_pipe_set_qos_ext_state(pipe, acc_fw->handle, - enable); - if (r) - return -EBADRQC; - } - } - - if (enable) - acc_fw->flags |= ATOMISP_ACC_FW_LOAD_FL_ENABLE; - else - acc_fw->flags &= ~ATOMISP_ACC_FW_LOAD_FL_ENABLE; - - return 0; -} - -int atomisp_acc_get_state(struct atomisp_sub_device *asd, - struct atomisp_acc_state *arg) -{ - struct atomisp_acc_fw *acc_fw; - - if (!asd->acc.extension_mode) - return -EBUSY; - - acc_fw = acc_get_fw(asd, arg->fw_handle); - if (!acc_fw) - return -EINVAL; - - arg->flags = acc_fw->flags; - - return 0; -} diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.h b/drivers/staging/media/atomisp/pci/atomisp_acc.h deleted file mode 100644 index 48d94232229b..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp_acc.h +++ /dev/null @@ -1,120 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for Clovertrail PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#ifndef __ATOMISP_ACC_H__ -#define __ATOMISP_ACC_H__ - -#include "../../include/linux/atomisp.h" -#include "atomisp_internal.h" - -#include "ia_css_types.h" - -/* - * Interface functions for AtomISP driver acceleration API implementation. - */ - -struct atomisp_sub_device; - -void atomisp_acc_cleanup(struct atomisp_device *isp); - -/* - * Free up any allocated resources. - * Must be called each time when the device is closed. - * Note that there isn't corresponding open() call; - * this function may be called sequentially multiple times. - * Must be called to free up resources before driver is unloaded. - */ -void atomisp_acc_release(struct atomisp_sub_device *asd); - -/* Load acceleration binary. DEPRECATED. */ -int atomisp_acc_load(struct atomisp_sub_device *asd, - struct atomisp_acc_fw_load *fw); - -/* Load acceleration binary with specified properties */ -int atomisp_acc_load_to_pipe(struct atomisp_sub_device *asd, - struct atomisp_acc_fw_load_to_pipe *fw); - -/* Unload specified acceleration binary */ -int atomisp_acc_unload(struct atomisp_sub_device *asd, - unsigned int *handle); - -/* - * Map a memory region into ISP memory space. - */ -int atomisp_acc_map(struct atomisp_sub_device *asd, - struct atomisp_acc_map *map); - -/* - * Unmap a mapped memory region. - */ -int atomisp_acc_unmap(struct atomisp_sub_device *asd, - struct atomisp_acc_map *map); - -/* - * Set acceleration binary argument to a previously mapped memory region. - */ -int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd, - struct atomisp_acc_s_mapped_arg *arg); - -/* - * Start acceleration. - * Return immediately, acceleration is left running in background. - * Specify either acceleration binary or pipeline which to start. - */ -int atomisp_acc_start(struct atomisp_sub_device *asd, - unsigned int *handle); - -/* - * Wait until acceleration finishes. - * This MUST be called after each acceleration has been started. - * Specify either acceleration binary or pipeline handle. - */ -int atomisp_acc_wait(struct atomisp_sub_device *asd, - unsigned int *handle); - -/* - * Used by ISR to notify ACC stage finished. - * This is internally used and does not export as IOCTL. - */ -void atomisp_acc_done(struct atomisp_sub_device *asd, unsigned int handle); - -/* - * Appends the loaded acceleration binary extensions to the - * current ISP mode. Must be called just before atomisp_css_start(). - */ -int atomisp_acc_load_extensions(struct atomisp_sub_device *asd); - -/* - * Must be called after streaming is stopped: - * unloads any loaded acceleration extensions. - */ -void atomisp_acc_unload_extensions(struct atomisp_sub_device *asd); - -/* - * Set acceleration firmware flags. - */ -int atomisp_acc_set_state(struct atomisp_sub_device *asd, - struct atomisp_acc_state *arg); - -/* - * Get acceleration firmware flags. - */ -int atomisp_acc_get_state(struct atomisp_sub_device *asd, - struct atomisp_acc_state *arg); - -#endif /* __ATOMISP_ACC_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index 97d5a528969b..c932f340068f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -42,7 +42,6 @@ #include "atomisp_ioctl.h" #include "atomisp-regs.h" #include "atomisp_tables.h" -#include "atomisp_acc.h" #include "atomisp_compat.h" #include "atomisp_subdev.h" #include "atomisp_dfs_tables.h" @@ -539,7 +538,7 @@ irqreturn_t atomisp_isr(int irq, void *dev) clear_irq_reg(isp); - if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp)) + if (!atomisp_streaming_count(isp)) goto out_nowake; for (i = 0; i < isp->num_of_streams; i++) { @@ -901,9 +900,9 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, int err; unsigned long irqflags; struct ia_css_frame *frame = NULL; - struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp; - struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp; - struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp; + struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp, *s3a_iter; + struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp, *dis_iter; + struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp, *md_iter; enum atomisp_metadata_type md_type; struct atomisp_device *isp = asd->isp; struct v4l2_control ctrl; @@ -942,60 +941,75 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, switch (buf_type) { case IA_CSS_BUFFER_TYPE_3A_STATISTICS: - list_for_each_entry_safe(s3a_buf, _s3a_buf_tmp, + list_for_each_entry_safe(s3a_iter, _s3a_buf_tmp, &asd->s3a_stats_in_css, list) { - if (s3a_buf->s3a_data == + if (s3a_iter->s3a_data == buffer.css_buffer.data.stats_3a) { - list_del_init(&s3a_buf->list); - list_add_tail(&s3a_buf->list, + list_del_init(&s3a_iter->list); + list_add_tail(&s3a_iter->list, &asd->s3a_stats_ready); + s3a_buf = s3a_iter; break; } } asd->s3a_bufs_in_css[css_pipe_id]--; atomisp_3a_stats_ready_event(asd, buffer.css_buffer.exp_id); - dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n", - __func__, s3a_buf->s3a_data->exp_id); + if (s3a_buf) + dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n", + __func__, s3a_buf->s3a_data->exp_id); + else + dev_dbg(isp->dev, "%s: s3a stat is ready with no exp_id found\n", + __func__); break; case IA_CSS_BUFFER_TYPE_METADATA: if (error) break; md_type = atomisp_get_metadata_type(asd, css_pipe_id); - list_for_each_entry_safe(md_buf, _md_buf_tmp, + list_for_each_entry_safe(md_iter, _md_buf_tmp, &asd->metadata_in_css[md_type], list) { - if (md_buf->metadata == + if (md_iter->metadata == buffer.css_buffer.data.metadata) { - list_del_init(&md_buf->list); - list_add_tail(&md_buf->list, + list_del_init(&md_iter->list); + list_add_tail(&md_iter->list, &asd->metadata_ready[md_type]); + md_buf = md_iter; break; } } asd->metadata_bufs_in_css[stream_id][css_pipe_id]--; atomisp_metadata_ready_event(asd, md_type); - dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n", - __func__, md_buf->metadata->exp_id); + if (md_buf) + dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n", + __func__, md_buf->metadata->exp_id); + else + dev_dbg(isp->dev, "%s: metadata is ready with no exp_id found\n", + __func__); break; case IA_CSS_BUFFER_TYPE_DIS_STATISTICS: - list_for_each_entry_safe(dis_buf, _dis_buf_tmp, + list_for_each_entry_safe(dis_iter, _dis_buf_tmp, &asd->dis_stats_in_css, list) { - if (dis_buf->dis_data == + if (dis_iter->dis_data == buffer.css_buffer.data.stats_dvs) { spin_lock_irqsave(&asd->dis_stats_lock, irqflags); - list_del_init(&dis_buf->list); - list_add(&dis_buf->list, &asd->dis_stats); + list_del_init(&dis_iter->list); + list_add(&dis_iter->list, &asd->dis_stats); asd->params.dis_proj_data_valid = true; spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); + dis_buf = dis_iter; break; } } asd->dis_bufs_in_css--; - dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n", - __func__, dis_buf->dis_data->exp_id); + if (dis_buf) + dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n", + __func__, dis_buf->dis_data->exp_id); + else + dev_dbg(isp->dev, "%s: dis stat is ready with no exp_id found\n", + __func__); break; case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: @@ -1302,34 +1316,11 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) for (i = 0; i < isp->num_of_streams; i++) { struct atomisp_sub_device *asd = &isp->asd[i]; - struct ia_css_pipeline *acc_pipeline; - struct ia_css_pipe *acc_pipe = NULL; if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED && !asd->stream_prepared) continue; - /* - * AtomISP::waitStageUpdate is blocked when WDT happens. - * By calling acc_done() for all loaded fw_handles, - * HAL will be unblocked. - */ - acc_pipe = asd->stream_env[i].pipes[IA_CSS_PIPE_ID_ACC]; - if (acc_pipe) { - acc_pipeline = ia_css_pipe_get_pipeline(acc_pipe); - if (acc_pipeline) { - struct ia_css_pipeline_stage *stage; - - for (stage = acc_pipeline->stages; stage; - stage = stage->next) { - const struct ia_css_fw_info *fw; - - fw = stage->firmware; - atomisp_acc_done(asd, fw->handle); - } - } - } - depth_cnt++; if (asd->delayed_init == ATOMISP_DELAYED_INIT_QUEUED) @@ -1350,8 +1341,6 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) dev_warn(isp->dev, "can't stop streaming on sensor!\n"); - atomisp_acc_unload_extensions(asd); - atomisp_clear_css_buffer_counters(asd); css_pipe_id = atomisp_get_css_pipe_id(asd); @@ -1863,7 +1852,7 @@ irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr) spin_lock_irqsave(&isp->lock, flags); - if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp)) { + if (!atomisp_streaming_count(isp)) { spin_unlock_irqrestore(&isp->lock, flags); return IRQ_HANDLED; } @@ -1914,9 +1903,6 @@ out: && isp->sw_contex.file_input) v4l2_subdev_call(isp->inputs[asd->input_curr].camera, video, s_stream, 1); - /* FIXME! FIX ACC implementation */ - if (asd->acc.pipeline && css_pipe_done[asd->index]) - atomisp_css_acc_done(asd); } dev_dbg(isp->dev, "<%s\n", __func__); @@ -6504,7 +6490,7 @@ int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id) ret = atomisp_css_exp_id_unlock(asd, exp_id); if (ret) { dev_err(asd->isp->dev, - "%s exp_id is wrapping back to %d but force unlock failed,, err %d.\n", + "%s exp_id is wrapping back to %d but force unlock failed, err %d.\n", __func__, exp_id, ret); return ret; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp_compat.h index 64c1bf0943e6..3393ae6824f0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat.h @@ -240,7 +240,7 @@ int atomisp_css_input_configure_port(struct atomisp_sub_device *asd, unsigned int metadata_width, unsigned int metadata_height); -void atomisp_create_pipes_stream(struct atomisp_sub_device *asd); +int atomisp_create_pipes_stream(struct atomisp_sub_device *asd); void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd); void atomisp_css_stop(struct atomisp_sub_device *asd, @@ -442,33 +442,6 @@ int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd, int atomisp_css_update_stream(struct atomisp_sub_device *asd); -int atomisp_css_create_acc_pipe(struct atomisp_sub_device *asd); - -int atomisp_css_start_acc_pipe(struct atomisp_sub_device *asd); - -int atomisp_css_stop_acc_pipe(struct atomisp_sub_device *asd); - -void atomisp_css_destroy_acc_pipe(struct atomisp_sub_device *asd); - -int atomisp_css_load_acc_extension(struct atomisp_sub_device *asd, - struct ia_css_fw_info *fw, - enum ia_css_pipe_id pipe_id, - unsigned int type); - -void atomisp_css_unload_acc_extension(struct atomisp_sub_device *asd, - struct ia_css_fw_info *fw, - enum ia_css_pipe_id pipe_id); - -int atomisp_css_wait_acc_finish(struct atomisp_sub_device *asd); - -void atomisp_css_acc_done(struct atomisp_sub_device *asd); - -int atomisp_css_load_acc_binary(struct atomisp_sub_device *asd, - struct ia_css_fw_info *fw, - unsigned int index); - -void atomisp_css_unload_acc_binary(struct atomisp_sub_device *asd); - struct atomisp_acc_fw; int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw); diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index 781a11cca599..5aa108a1724c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -31,7 +31,6 @@ #include "atomisp-regs.h" #include "atomisp_fops.h" #include "atomisp_ioctl.h" -#include "atomisp_acc.h" #include "ia_css_debug.h" #include "ia_css_isp_param.h" @@ -419,24 +418,14 @@ static void __dump_stream_config(struct atomisp_sub_device *asd, } static int __destroy_stream(struct atomisp_sub_device *asd, - struct atomisp_stream_env *stream_env, bool force) + struct atomisp_stream_env *stream_env) { struct atomisp_device *isp = asd->isp; - int i; unsigned long timeout; if (!stream_env->stream) return 0; - if (!force) { - for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) - if (stream_env->update_pipe[i]) - break; - - if (i == IA_CSS_PIPE_ID_NUM) - return 0; - } - if (stream_env->stream_state == CSS_STREAM_STARTED && ia_css_stream_stop(stream_env->stream) != 0) { dev_err(isp->dev, "stop stream failed.\n"); @@ -470,12 +459,12 @@ static int __destroy_stream(struct atomisp_sub_device *asd, return 0; } -static int __destroy_streams(struct atomisp_sub_device *asd, bool force) +static int __destroy_streams(struct atomisp_sub_device *asd) { int ret, i; for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) { - ret = __destroy_stream(asd, &asd->stream_env[i], force); + ret = __destroy_stream(asd, &asd->stream_env[i]); if (ret) return ret; } @@ -530,21 +519,19 @@ static int __create_streams(struct atomisp_sub_device *asd) return 0; rollback: for (i--; i >= 0; i--) - __destroy_stream(asd, &asd->stream_env[i], true); + __destroy_stream(asd, &asd->stream_env[i]); return ret; } static int __destroy_stream_pipes(struct atomisp_sub_device *asd, - struct atomisp_stream_env *stream_env, - bool force) + struct atomisp_stream_env *stream_env) { struct atomisp_device *isp = asd->isp; int ret = 0; int i; for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { - if (!stream_env->pipes[i] || - !(force || stream_env->update_pipe[i])) + if (!stream_env->pipes[i]) continue; if (ia_css_pipe_destroy(stream_env->pipes[i]) != 0) { @@ -558,7 +545,7 @@ static int __destroy_stream_pipes(struct atomisp_sub_device *asd, return ret; } -static int __destroy_pipes(struct atomisp_sub_device *asd, bool force) +static int __destroy_pipes(struct atomisp_sub_device *asd) { struct atomisp_device *isp = asd->isp; int i; @@ -572,7 +559,7 @@ static int __destroy_pipes(struct atomisp_sub_device *asd, bool force) continue; } - ret = __destroy_stream_pipes(asd, &asd->stream_env[i], force); + ret = __destroy_stream_pipes(asd, &asd->stream_env[i]); if (ret) return ret; } @@ -582,8 +569,11 @@ static int __destroy_pipes(struct atomisp_sub_device *asd, bool force) void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd) { - __destroy_streams(asd, true); - __destroy_pipes(asd, true); + if (__destroy_streams(asd)) + dev_warn(asd->isp->dev, "destroy stream failed.\n"); + + if (__destroy_pipes(asd)) + dev_warn(asd->isp->dev, "destroy pipe failed.\n"); } static void __apply_additional_pipe_config( @@ -786,39 +776,32 @@ pipe_err: return -EINVAL; } -void atomisp_create_pipes_stream(struct atomisp_sub_device *asd) -{ - __create_pipes(asd); - __create_streams(asd); -} - -int atomisp_css_update_stream(struct atomisp_sub_device *asd) +int atomisp_create_pipes_stream(struct atomisp_sub_device *asd) { int ret; - struct atomisp_device *isp = asd->isp; - - if (__destroy_streams(asd, true)) - dev_warn(isp->dev, "destroy stream failed.\n"); - - if (__destroy_pipes(asd, true)) - dev_warn(isp->dev, "destroy pipe failed.\n"); ret = __create_pipes(asd); if (ret) { - dev_err(isp->dev, "create pipe failed %d.\n", ret); - return -EIO; + dev_err(asd->isp->dev, "create pipe failed %d.\n", ret); + return ret; } ret = __create_streams(asd); if (ret) { - dev_warn(isp->dev, "create stream failed %d.\n", ret); - __destroy_pipes(asd, true); - return -EIO; + dev_warn(asd->isp->dev, "create stream failed %d.\n", ret); + __destroy_pipes(asd); + return ret; } return 0; } +int atomisp_css_update_stream(struct atomisp_sub_device *asd) +{ + atomisp_destroy_pipes_stream_force(asd); + return atomisp_create_pipes_stream(asd); +} + int atomisp_css_init(struct atomisp_device *isp) { unsigned int mmu_base_addr; @@ -1103,23 +1086,12 @@ int atomisp_css_start(struct atomisp_sub_device *asd, int ret = 0, i = 0; if (in_reset) { - if (__destroy_streams(asd, true)) - dev_warn(isp->dev, "destroy stream failed.\n"); - - if (__destroy_pipes(asd, true)) - dev_warn(isp->dev, "destroy pipe failed.\n"); + ret = atomisp_css_update_stream(asd); + if (ret) + return ret; - if (__create_pipes(asd)) { - dev_err(isp->dev, "create pipe error.\n"); - return -EINVAL; - } - if (__create_streams(asd)) { - dev_err(isp->dev, "create stream error.\n"); - ret = -EINVAL; - goto stream_err; - } - /* in_reset == true, extension firmwares are reloaded after the recovery */ - atomisp_acc_load_extensions(asd); + /* Invalidate caches. FIXME: should flush only necessary buffers */ + wbinvd(); } /* @@ -1134,15 +1106,9 @@ int atomisp_css_start(struct atomisp_sub_device *asd, * recreated in the next stream on. */ if (!asd->stream_prepared) { - if (__create_pipes(asd)) { - dev_err(isp->dev, "create pipe error.\n"); - return -EINVAL; - } - if (__create_streams(asd)) { - dev_err(isp->dev, "create stream error.\n"); - ret = -EINVAL; - goto stream_err; - } + ret = atomisp_create_pipes_stream(asd); + if (ret) + return ret; } /* * SP can only be started one time @@ -1181,9 +1147,7 @@ int atomisp_css_start(struct atomisp_sub_device *asd, return 0; start_err: - __destroy_streams(asd, true); -stream_err: - __destroy_pipes(asd, true); + atomisp_destroy_pipes_stream_force(asd); /* css 2.0 API limitation: ia_css_stop_sp() could be only called after * destroy all pipes @@ -2088,13 +2052,8 @@ void atomisp_css_stop(struct atomisp_sub_device *asd, unsigned long irqflags; unsigned int i; - /* if is called in atomisp_reset(), force destroy stream */ - if (__destroy_streams(asd, true)) - dev_err(isp->dev, "destroy stream failed.\n"); - - /* if is called in atomisp_reset(), force destroy all pipes */ - if (__destroy_pipes(asd, true)) - dev_err(isp->dev, "destroy pipes failed.\n"); + /* if is called in atomisp_reset(), force destroy streams and pipes */ + atomisp_destroy_pipes_stream_force(asd); atomisp_init_raw_buffer_bitmap(asd); @@ -2634,27 +2593,15 @@ static int __get_frame_info(struct atomisp_sub_device *asd, struct ia_css_pipe_info p_info; /* FIXME! No need to destroy/recreate all streams */ - if (__destroy_streams(asd, true)) - dev_warn(isp->dev, "destroy stream failed.\n"); - - if (__destroy_pipes(asd, true)) - dev_warn(isp->dev, "destroy pipe failed.\n"); - - if (__create_pipes(asd)) { - dev_err(isp->dev, "can't create pipes\n"); - return -EINVAL; - } - - if (__create_streams(asd)) { - dev_err(isp->dev, "can't create streams\n"); - goto stream_err; - } + ret = atomisp_css_update_stream(asd); + if (ret) + return ret; ret = ia_css_pipe_get_info(asd->stream_env[stream_index].pipes[pipe_id], &p_info); if (ret) { dev_err(isp->dev, "can't get info from pipe\n"); - goto stream_err; + goto get_info_err; } switch (type) { @@ -2685,8 +2632,8 @@ static int __get_frame_info(struct atomisp_sub_device *asd, return 0; -stream_err: - __destroy_pipes(asd, true); +get_info_err: + atomisp_destroy_pipes_stream_force(asd); return -EINVAL; } @@ -3824,30 +3771,6 @@ void atomisp_css_set_cont_prev_start_time(struct atomisp_device *isp, return; } -void atomisp_css_acc_done(struct atomisp_sub_device *asd) -{ - complete(&asd->acc.acc_done); -} - -int atomisp_css_wait_acc_finish(struct atomisp_sub_device *asd) -{ - int ret = 0; - struct atomisp_device *isp = asd->isp; - - /* Unlock the isp mutex taken in IOCTL handler before sleeping! */ - rt_mutex_unlock(&isp->mutex); - if (wait_for_completion_interruptible_timeout(&asd->acc.acc_done, - ATOMISP_ISP_TIMEOUT_DURATION) == 0) { - dev_err(isp->dev, "<%s: completion timeout\n", __func__); - ia_css_debug_dump_sp_sw_debug_info(); - ia_css_debug_dump_debug_info(__func__); - ret = -EIO; - } - rt_mutex_lock(&isp->mutex); - - return ret; -} - /* Set the ACC binary arguments */ int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw) { @@ -3866,204 +3789,6 @@ int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw) return 0; } -/* Load acc binary extension */ -int atomisp_css_load_acc_extension(struct atomisp_sub_device *asd, - struct ia_css_fw_info *fw, - enum ia_css_pipe_id pipe_id, - unsigned int type) -{ - struct ia_css_fw_info **hd; - - fw->next = NULL; - hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] - .pipe_configs[pipe_id].acc_extension); - while (*hd) - hd = &(*hd)->next; - *hd = fw; - - asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] - .update_pipe[pipe_id] = true; - return 0; -} - -/* Unload acc binary extension */ -void atomisp_css_unload_acc_extension(struct atomisp_sub_device *asd, - struct ia_css_fw_info *fw, - enum ia_css_pipe_id pipe_id) -{ - struct ia_css_fw_info **hd; - - hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] - .pipe_configs[pipe_id].acc_extension); - while (*hd && *hd != fw) - hd = &(*hd)->next; - if (!*hd) { - dev_err(asd->isp->dev, "did not find acc fw for removal\n"); - return; - } - *hd = fw->next; - fw->next = NULL; - - asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] - .update_pipe[pipe_id] = true; -} - -int atomisp_css_create_acc_pipe(struct atomisp_sub_device *asd) -{ - struct atomisp_device *isp = asd->isp; - struct ia_css_pipe_config *pipe_config; - struct atomisp_stream_env *stream_env = - &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; - - if (stream_env->acc_stream) { - if (stream_env->acc_stream_state == CSS_STREAM_STARTED) { - if (ia_css_stream_stop(stream_env->acc_stream) - != 0) { - dev_err(isp->dev, "stop acc_stream failed.\n"); - return -EBUSY; - } - } - - if (ia_css_stream_destroy(stream_env->acc_stream) - != 0) { - dev_err(isp->dev, "destroy acc_stream failed.\n"); - return -EBUSY; - } - stream_env->acc_stream = NULL; - } - - pipe_config = &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]; - ia_css_pipe_config_defaults(pipe_config); - asd->acc.acc_stages = kzalloc(MAX_ACC_STAGES * - sizeof(void *), GFP_KERNEL); - if (!asd->acc.acc_stages) - return -ENOMEM; - pipe_config->acc_stages = asd->acc.acc_stages; - pipe_config->mode = IA_CSS_PIPE_MODE_ACC; - pipe_config->num_acc_stages = 0; - - /* - * We delay the ACC pipeline creation to atomisp_css_start_acc_pipe, - * because pipe configuration will soon be changed by - * atomisp_css_load_acc_binary() - */ - return 0; -} - -int atomisp_css_start_acc_pipe(struct atomisp_sub_device *asd) -{ - struct atomisp_device *isp = asd->isp; - struct atomisp_stream_env *stream_env = - &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; - struct ia_css_pipe_config *pipe_config = - &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]; - - if (ia_css_pipe_create(pipe_config, - &stream_env->pipes[IA_CSS_PIPE_ID_ACC]) != 0) { - dev_err(isp->dev, "%s: ia_css_pipe_create failed\n", - __func__); - return -EBADE; - } - - memset(&stream_env->acc_stream_config, 0, - sizeof(struct ia_css_stream_config)); - if (ia_css_stream_create(&stream_env->acc_stream_config, 1, - &stream_env->pipes[IA_CSS_PIPE_ID_ACC], - &stream_env->acc_stream) != 0) { - dev_err(isp->dev, "%s: create acc_stream error.\n", __func__); - return -EINVAL; - } - stream_env->acc_stream_state = CSS_STREAM_CREATED; - - init_completion(&asd->acc.acc_done); - asd->acc.pipeline = stream_env->pipes[IA_CSS_PIPE_ID_ACC]; - - atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, false); - - if (ia_css_start_sp()) { - dev_err(isp->dev, "start sp error.\n"); - return -EIO; - } - - if (ia_css_stream_start(stream_env->acc_stream) - != 0) { - dev_err(isp->dev, "acc_stream start error.\n"); - return -EIO; - } - - stream_env->acc_stream_state = CSS_STREAM_STARTED; - return 0; -} - -int atomisp_css_stop_acc_pipe(struct atomisp_sub_device *asd) -{ - struct atomisp_stream_env *stream_env = - &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; - if (stream_env->acc_stream_state == CSS_STREAM_STARTED) { - ia_css_stream_stop(stream_env->acc_stream); - stream_env->acc_stream_state = CSS_STREAM_STOPPED; - } - return 0; -} - -void atomisp_css_destroy_acc_pipe(struct atomisp_sub_device *asd) -{ - struct atomisp_stream_env *stream_env = - &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]; - if (stream_env->acc_stream) { - if (ia_css_stream_destroy(stream_env->acc_stream) - != 0) - dev_warn(asd->isp->dev, - "destroy acc_stream failed.\n"); - stream_env->acc_stream = NULL; - } - - if (stream_env->pipes[IA_CSS_PIPE_ID_ACC]) { - if (ia_css_pipe_destroy(stream_env->pipes[IA_CSS_PIPE_ID_ACC]) - != 0) - dev_warn(asd->isp->dev, - "destroy ACC pipe failed.\n"); - stream_env->pipes[IA_CSS_PIPE_ID_ACC] = NULL; - stream_env->update_pipe[IA_CSS_PIPE_ID_ACC] = false; - ia_css_pipe_config_defaults( - &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]); - ia_css_pipe_extra_config_defaults( - &stream_env->pipe_extra_configs[IA_CSS_PIPE_ID_ACC]); - } - asd->acc.pipeline = NULL; - - /* css 2.0 API limitation: ia_css_stop_sp() could be only called after - * destroy all pipes - */ - ia_css_stop_sp(); - - kfree(asd->acc.acc_stages); - asd->acc.acc_stages = NULL; - - atomisp_freq_scaling(asd->isp, ATOMISP_DFS_MODE_LOW, false); -} - -int atomisp_css_load_acc_binary(struct atomisp_sub_device *asd, - struct ia_css_fw_info *fw, - unsigned int index) -{ - struct ia_css_pipe_config *pipe_config = - &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL] - .pipe_configs[IA_CSS_PIPE_ID_ACC]; - - if (index >= MAX_ACC_STAGES) { - dev_dbg(asd->isp->dev, "%s: index(%d) out of range\n", - __func__, index); - return -ENOMEM; - } - - pipe_config->acc_stages[index] = fw; - pipe_config->num_acc_stages = index + 1; - pipe_config->acc_num_execs = 1; - - return 0; -} - static struct atomisp_sub_device *__get_atomisp_subdev( struct ia_css_pipe *css_pipe, struct atomisp_device *isp, @@ -4075,8 +3800,7 @@ static struct atomisp_sub_device *__get_atomisp_subdev( for (i = 0; i < isp->num_of_streams; i++) { asd = &isp->asd[i]; - if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED && - !asd->acc.pipeline) + if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED) continue; for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) { stream_env = &asd->stream_env[j]; @@ -4211,8 +3935,7 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, css_pipe_done[asd->index] = true; break; case IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE: - dev_dbg(isp->dev, "event: acc stage done"); - atomisp_acc_done(asd, current_event.event.fw_handle); + dev_warn(isp->dev, "unexpected event: acc stage done"); break; default: dev_dbg(isp->dev, "unhandled css stored event: 0x%x\n", diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h b/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h index 86d3fbe01378..33821b51d90e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h @@ -140,19 +140,6 @@ struct atomisp_calibration_group32 { compat_uptr_t calb_grp_values; }; -struct atomisp_acc_fw_load32 { - unsigned int size; - unsigned int fw_handle; - compat_uptr_t data; -}; - -struct atomisp_acc_fw_arg32 { - unsigned int fw_handle; - unsigned int index; - compat_uptr_t value; - compat_size_t size; -}; - struct v4l2_private_int_data32 { __u32 size; compat_uptr_t data; @@ -170,21 +157,6 @@ struct atomisp_shading_table32 { compat_uptr_t data[ATOMISP_NUM_SC_COLORS]; }; -struct atomisp_acc_map32 { - __u32 flags; /* Flags, see list below */ - __u32 length; /* Length of data in bytes */ - compat_uptr_t user_ptr; /* Pointer into user space */ - compat_ulong_t css_ptr; /* Pointer into CSS address space */ - __u32 reserved[4]; /* Set to zero */ -}; - -struct atomisp_acc_s_mapped_arg32 { - unsigned int fw_handle; - __u32 memory; /* one of enum atomisp_acc_memory */ - compat_size_t length; - compat_ulong_t css_ptr; -}; - struct atomisp_parameters32 { compat_uptr_t wb_config; /* White Balance config */ compat_uptr_t cc_config; /* Color Correction config */ @@ -265,15 +237,6 @@ struct atomisp_parameters32 { u32 per_frame_setting; }; -struct atomisp_acc_fw_load_to_pipe32 { - __u32 flags; /* Flags, see below for valid values */ - unsigned int fw_handle; /* Handle, filled by kernel. */ - __u32 size; /* Firmware binary size */ - compat_uptr_t data; /* Pointer to firmware */ - __u32 type; /* Binary type */ - __u32 reserved[3]; /* Set to zero */ -}; - struct atomisp_dvs_6axis_config32 { u32 exp_id; u32 width_y; @@ -323,15 +286,6 @@ struct atomisp_sensor_ae_bracketing_lut32 { #define ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32 \ _IOWR('v', BASE_VIDIOC_PRIVATE + 22, struct atomisp_calibration_group32) -#define ATOMISP_IOC_ACC_LOAD32 \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_load32) - -#define ATOMISP_IOC_ACC_S_ARG32 \ - _IOW('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_arg32) - -#define ATOMISP_IOC_ACC_DESTAB32 \ - _IOW('v', BASE_VIDIOC_PRIVATE + 25, struct atomisp_acc_fw_arg32) - #define ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32 \ _IOWR('v', BASE_VIDIOC_PRIVATE + 26, struct v4l2_private_int_data32) @@ -341,18 +295,6 @@ struct atomisp_sensor_ae_bracketing_lut32 { #define ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32 \ _IOWR('v', BASE_VIDIOC_PRIVATE + 29, struct v4l2_private_int_data32) -#define ATOMISP_IOC_ACC_MAP32 \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map32) - -#define ATOMISP_IOC_ACC_UNMAP32 \ - _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map32) - -#define ATOMISP_IOC_ACC_S_MAPPED_ARG32 \ - _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_s_mapped_arg32) - -#define ATOMISP_IOC_ACC_LOAD_TO_PIPE32 \ - _IOWR('v', BASE_VIDIOC_PRIVATE + 31, struct atomisp_acc_fw_load_to_pipe32) - #define ATOMISP_IOC_S_PARAMETERS32 \ _IOW('v', BASE_VIDIOC_PRIVATE + 32, struct atomisp_parameters32) diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c index dcb571f515a7..3ddc935ec01d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c +++ b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c @@ -45,10 +45,8 @@ struct _iunit_debug { #define OPTION_BIN_LIST BIT(0) #define OPTION_BIN_RUN BIT(1) -#define OPTION_MEM_STAT BIT(2) #define OPTION_VALID (OPTION_BIN_LIST \ - | OPTION_BIN_RUN \ - | OPTION_MEM_STAT) + | OPTION_BIN_RUN) static struct _iunit_debug iunit_debug = { .dbglvl = 0, @@ -81,9 +79,6 @@ static inline int iunit_dump_dbgopt(struct atomisp_device *isp, goto opt_err; } } - - if (opt & OPTION_MEM_STAT) - hmm_show_mem_stat(__func__, __LINE__); } else { ret = -EINVAL; dev_err(isp->dev, "%s dump nothing[ret=%d]\n", __func__, ret); diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index be6a74d5ac19..77150e4ae144 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -38,8 +38,6 @@ #include "type_support.h" #include "device_access/device_access.h" -#include "atomisp_acc.h" - #define ISP_LEFT_PAD 128 /* equal to 2*NWAY */ /* @@ -865,12 +863,6 @@ dev_init: goto error; } - if (dypool_enable) { - ret = hmm_pool_register(dypool_pgnr, HMM_POOL_TYPE_DYNAMIC); - if (ret) - dev_err(isp->dev, "Failed to register dynamic memory pool.\n"); - } - /* Init ISP */ if (atomisp_css_init(isp)) { ret = -EINVAL; @@ -910,7 +902,6 @@ css_error: atomisp_css_uninit(isp); pm_runtime_put(vdev->v4l2_dev->dev); error: - hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC); rt_mutex_unlock(&isp->mutex); return ret; } @@ -1021,8 +1012,6 @@ subdev_uninit: if (atomisp_dev_users(isp)) goto done; - atomisp_acc_release(asd); - atomisp_destroy_pipes_stream_force(asd); atomisp_css_uninit(isp); @@ -1032,8 +1021,6 @@ subdev_uninit: isp->css_env.isp_css_fw.bytes = 0; } - hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC); - ret = v4l2_subdev_call(isp->flash, core, s_power, 0); if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off flash\n"); diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 8fd470efd658..459645c2e2a7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -25,7 +25,6 @@ #include <media/v4l2-event.h> #include <media/videobuf-vmalloc.h> -#include "atomisp_acc.h" #include "atomisp_cmd.h" #include "atomisp_common.h" #include "atomisp_fops.h" @@ -625,17 +624,6 @@ unsigned int atomisp_streaming_count(struct atomisp_device *isp) return sum; } -unsigned int atomisp_is_acc_enabled(struct atomisp_device *isp) -{ - unsigned int i; - - for (i = 0; i < isp->num_of_streams; i++) - if (isp->asd[i].acc.pipeline) - return 1; - - return 0; -} - /* * get input are used to get current primary/secondary camera */ @@ -1371,7 +1359,7 @@ static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) ret = ia_css_frame_map(&handle, &frame_info, (void __user *)buf->m.userptr, - 0, pgnr); + pgnr); if (ret) { dev_err(isp->dev, "Failed to map user buffer\n"); goto error; @@ -1913,11 +1901,8 @@ static int atomisp_streamon(struct file *file, void *fh, css_pipe_id = atomisp_get_css_pipe_id(asd); - ret = atomisp_acc_load_extensions(asd); - if (ret < 0) { - dev_err(isp->dev, "acc extension failed to load\n"); - goto out; - } + /* Invalidate caches. FIXME: should flush only necessary buffers */ + wbinvd(); if (asd->params.css_update_params_needed) { atomisp_apply_css_parameters(asd, &asd->params.css_param); @@ -2154,7 +2139,6 @@ int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) video, s_stream, 0); rt_mutex_lock(&isp->mutex); - atomisp_acc_unload_extensions(asd); } spin_lock_irqsave(&isp->lock, flags); @@ -2283,8 +2267,17 @@ stopsensor: dev_err(isp->dev, "atomisp_reset"); atomisp_reset(isp); for (i = 0; i < isp->num_of_streams; i++) { - if (recreate_streams[i]) - atomisp_create_pipes_stream(&isp->asd[i]); + if (recreate_streams[i]) { + int ret2; + + ret2 = atomisp_create_pipes_stream(&isp->asd[i]); + if (ret2) { + dev_err(isp->dev, "%s error re-creating streams: %d\n", + __func__, ret2); + if (!ret) + ret = ret2; + } + } } isp->isp_timeout = false; } @@ -3118,38 +3111,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, err = -EINVAL; break; - case ATOMISP_IOC_ACC_LOAD: - err = atomisp_acc_load(asd, arg); - break; - - case ATOMISP_IOC_ACC_LOAD_TO_PIPE: - err = atomisp_acc_load_to_pipe(asd, arg); - break; - - case ATOMISP_IOC_ACC_UNLOAD: - err = atomisp_acc_unload(asd, arg); - break; - - case ATOMISP_IOC_ACC_START: - err = atomisp_acc_start(asd, arg); - break; - - case ATOMISP_IOC_ACC_WAIT: - err = atomisp_acc_wait(asd, arg); - break; - - case ATOMISP_IOC_ACC_MAP: - err = atomisp_acc_map(asd, arg); - break; - - case ATOMISP_IOC_ACC_UNMAP: - err = atomisp_acc_unmap(asd, arg); - break; - - case ATOMISP_IOC_ACC_S_MAPPED_ARG: - err = atomisp_acc_s_mapped_arg(asd, arg); - break; - case ATOMISP_IOC_S_ISP_SHD_TAB: err = atomisp_set_shading_table(asd, arg); break; @@ -3198,12 +3159,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, case ATOMISP_IOC_S_EXPOSURE_WINDOW: err = atomisp_s_ae_window(asd, arg); break; - case ATOMISP_IOC_S_ACC_STATE: - err = atomisp_acc_set_state(asd, arg); - break; - case ATOMISP_IOC_G_ACC_STATE: - err = atomisp_acc_get_state(asd, arg); - break; case ATOMISP_IOC_INJECT_A_FAKE_EVENT: err = atomisp_inject_a_fake_event(asd, arg); break; diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h index 412bfcf33c0f..d85e0d697a4e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h @@ -57,7 +57,6 @@ extern const struct v4l2_ioctl_ops atomisp_file_ioctl_ops; unsigned int atomisp_streaming_count(struct atomisp_device *isp); -unsigned int atomisp_is_acc_enabled(struct atomisp_device *isp); /* compat_ioctl for 32bit userland app and 64bit kernel */ long atomisp_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg); diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 1807cfa786a7..394fe6959033 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -1081,9 +1081,6 @@ static void atomisp_init_acc_pipe(struct atomisp_sub_device *asd, { pipe->asd = asd; pipe->isp = asd->isp; - INIT_LIST_HEAD(&asd->acc.fw); - INIT_LIST_HEAD(&asd->acc.memory_maps); - ida_init(&asd->acc.ida); } /* diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index 7d731f1fee72..798a93793a9a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -322,16 +322,6 @@ struct atomisp_sub_device { struct v4l2_ctrl *disable_dz; - struct { - struct list_head fw; - struct list_head memory_maps; - struct ia_css_pipe *pipeline; - bool extension_mode; - struct ida ida; - struct completion acc_done; - void *acc_stages; - } acc; - struct atomisp_subdev_params params; struct atomisp_stream_env stream_env[ATOMISP_INPUT_STREAM_NUM]; diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 49ccfb1646da..643ba981601b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -37,7 +37,6 @@ #include "atomisp_file.h" #include "atomisp_ioctl.h" #include "atomisp_internal.h" -#include "atomisp_acc.h" #include "atomisp-regs.h" #include "atomisp_dfs_tables.h" #include "atomisp_drvfs.h" @@ -59,23 +58,6 @@ static uint skip_fwload; module_param(skip_fwload, uint, 0644); MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load"); -/* set reserved memory pool size in page */ -static unsigned int repool_pgnr = 32768; -module_param(repool_pgnr, uint, 0644); -MODULE_PARM_DESC(repool_pgnr, - "Set the reserved memory pool size in page (default:32768)"); - -/* set dynamic memory pool size in page */ -unsigned int dypool_pgnr = UINT_MAX; -module_param(dypool_pgnr, uint, 0644); -MODULE_PARM_DESC(dypool_pgnr, - "Set the dynamic memory pool size in page (default: unlimited)"); - -bool dypool_enable = true; -module_param(dypool_enable, bool, 0644); -MODULE_PARM_DESC(dypool_enable, - "dynamic memory pool enable/disable (default:enabled)"); - /* memory optimization: deferred firmware loading */ bool defer_fw_load; module_param(defer_fw_load, bool, 0644); @@ -1770,13 +1752,6 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); - hmm_init_mem_stat(repool_pgnr, dypool_enable, dypool_pgnr); - err = hmm_pool_register(repool_pgnr, HMM_POOL_TYPE_RESERVED); - if (err) { - dev_err(&pdev->dev, "Failed to register reserved memory pool.\n"); - goto hmm_pool_fail; - } - /* Init ISP memory management */ hmm_init(); @@ -1813,12 +1788,9 @@ css_init_fail: devm_free_irq(&pdev->dev, pdev->irq, isp); request_irq_fail: hmm_cleanup(); - hmm_pool_unregister(HMM_POOL_TYPE_RESERVED); -hmm_pool_fail: pm_runtime_get_noresume(&pdev->dev); destroy_workqueue(isp->wdt_work_queue); wdt_work_queue_fail: - atomisp_acc_cleanup(isp); atomisp_unregister_entities(isp); register_entities_fail: atomisp_uninitialize_modules(isp); @@ -1869,8 +1841,6 @@ static void atomisp_pci_remove(struct pci_dev *pdev) atomisp_drvfs_exit(); - atomisp_acc_cleanup(isp); - ia_css_unload_firmware(); hmm_cleanup(); @@ -1885,8 +1855,6 @@ static void atomisp_pci_remove(struct pci_dev *pdev) atomisp_file_input_cleanup(isp); release_firmware(isp->firmware); - - hmm_pool_unregister(HMM_POOL_TYPE_RESERVED); } static const struct pci_device_id atomisp_pci_tbl[] = { diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h index ee861ddb8e92..5660bd4221be 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h @@ -25,7 +25,7 @@ * Simple queuing trace buffer for debug data * instantiatable in SP DMEM * - * The buffer has a remote and and a local store + * The buffer has a remote and a local store * which contain duplicate data (when in sync). * The buffers are automatically synched when the * user dequeues, or manualy using the synch function diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/media/atomisp/pci/hmm/hmm.c index c1cda16f2dc0..fc6cfe9f7744 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c @@ -28,7 +28,6 @@ #include <linux/sysfs.h> #include "hmm/hmm.h" -#include "hmm/hmm_pool.h" #include "hmm/hmm_bo.h" #include "atomisp_internal.h" @@ -37,11 +36,8 @@ #include "mmu/sh_mmu_mrfld.h" struct hmm_bo_device bo_device; -struct hmm_pool dynamic_pool; -struct hmm_pool reserved_pool; static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; static bool hmm_initialized; -struct _hmm_mem_stat hmm_mem_stat; /* * p: private @@ -113,62 +109,13 @@ static ssize_t free_bo_show(struct device *dev, struct device_attribute *attr, return bo_show(dev, attr, buf, &bo_device.entire_bo_list, false); } -static ssize_t reserved_pool_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - ssize_t ret = 0; - - struct hmm_reserved_pool_info *pinfo = reserved_pool.pool_info; - unsigned long flags; - - if (!pinfo || !pinfo->initialized) - return 0; - - spin_lock_irqsave(&pinfo->list_lock, flags); - ret = scnprintf(buf, PAGE_SIZE, "%d out of %d pages available\n", - pinfo->index, pinfo->pgnr); - spin_unlock_irqrestore(&pinfo->list_lock, flags); - - if (ret > 0) - ret++; /* Add trailing zero, not included by scnprintf */ - - return ret; -}; - -static ssize_t dynamic_pool_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - ssize_t ret = 0; - - struct hmm_dynamic_pool_info *pinfo = dynamic_pool.pool_info; - unsigned long flags; - - if (!pinfo || !pinfo->initialized) - return 0; - - spin_lock_irqsave(&pinfo->list_lock, flags); - ret = scnprintf(buf, PAGE_SIZE, "%d (max %d) pages available\n", - pinfo->pgnr, pinfo->pool_size); - spin_unlock_irqrestore(&pinfo->list_lock, flags); - - if (ret > 0) - ret++; /* Add trailing zero, not included by scnprintf */ - - return ret; -}; static DEVICE_ATTR_RO(active_bo); static DEVICE_ATTR_RO(free_bo); -static DEVICE_ATTR_RO(reserved_pool); -static DEVICE_ATTR_RO(dynamic_pool); static struct attribute *sysfs_attrs_ctrl[] = { &dev_attr_active_bo.attr, &dev_attr_free_bo.attr, - &dev_attr_reserved_pool.attr, - &dev_attr_dynamic_pool.attr, NULL }; @@ -194,7 +141,7 @@ int hmm_init(void) * at the beginning, to avoid hmm_alloc return 0 in the * further allocation. */ - dummy_ptr = hmm_alloc(1, HMM_BO_PRIVATE, 0, NULL, 0); + dummy_ptr = hmm_alloc(1); if (!ret) { ret = sysfs_create_group(&atomisp_dev->kobj, @@ -221,17 +168,12 @@ void hmm_cleanup(void) hmm_initialized = false; } -ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type, - int from_highmem, const void __user *userptr, - const uint16_t attrs) +static ia_css_ptr __hmm_alloc(size_t bytes, enum hmm_bo_type type, const void __user *userptr) { unsigned int pgnr; struct hmm_buffer_object *bo; - bool cached = attrs & ATOMISP_MAP_FLAG_CACHED; int ret; - WARN_ON(attrs & ATOMISP_MAP_FLAG_CONTIGUOUS); - /* * Check if we are initialized. In the ideal world we wouldn't need * this but we can tackle it once the driver is a lot cleaner @@ -250,7 +192,7 @@ ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type, } /* Allocate pages for memory */ - ret = hmm_bo_alloc_pages(bo, type, from_highmem, userptr, cached); + ret = hmm_bo_alloc_pages(bo, type, userptr); if (ret) { dev_err(atomisp_dev, "hmm_bo_alloc_pages failed.\n"); goto alloc_page_err; @@ -263,14 +205,9 @@ ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type, goto bind_err; } - hmm_mem_stat.tol_cnt += pgnr; - - if (attrs & ATOMISP_MAP_FLAG_CLEARED) - hmm_set(bo->start, 0, bytes); - dev_dbg(atomisp_dev, - "%s: pages: 0x%08x (%zu bytes), type: %d from highmem %d, user ptr %p, cached %d\n", - __func__, bo->start, bytes, type, from_highmem, userptr, cached); + "%s: pages: 0x%08x (%zu bytes), type: %d, user ptr %p\n", + __func__, bo->start, bytes, type, userptr); return bo->start; @@ -282,6 +219,16 @@ create_bo_err: return 0; } +ia_css_ptr hmm_alloc(size_t bytes) +{ + return __hmm_alloc(bytes, HMM_BO_PRIVATE, NULL); +} + +ia_css_ptr hmm_create_from_userdata(size_t bytes, const void __user *userptr) +{ + return __hmm_alloc(bytes, HMM_BO_USER, userptr); +} + void hmm_free(ia_css_ptr virt) { struct hmm_buffer_object *bo; @@ -300,8 +247,6 @@ void hmm_free(ia_css_ptr virt) return; } - hmm_mem_stat.tol_cnt -= bo->pgnr; - hmm_bo_unbind(bo); hmm_bo_free_pages(bo); hmm_bo_unref(bo); @@ -350,7 +295,7 @@ static int load_and_flush_by_kmap(ia_css_ptr virt, void *data, idx = (virt - bo->start) >> PAGE_SHIFT; offset = (virt - bo->start) - (idx << PAGE_SHIFT); - src = (char *)kmap(bo->page_obj[idx].page) + offset; + src = (char *)kmap_local_page(bo->pages[idx]) + offset; if ((bytes + offset) >= PAGE_SIZE) { len = PAGE_SIZE - offset; @@ -369,7 +314,7 @@ static int load_and_flush_by_kmap(ia_css_ptr virt, void *data, clflush_cache_range(src, len); - kunmap(bo->page_obj[idx].page); + kunmap_local(src); } return 0; @@ -482,10 +427,7 @@ int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes) idx = (virt - bo->start) >> PAGE_SHIFT; offset = (virt - bo->start) - (idx << PAGE_SHIFT); - if (in_atomic()) - des = (char *)kmap_atomic(bo->page_obj[idx].page); - else - des = (char *)kmap(bo->page_obj[idx].page); + des = (char *)kmap_local_page(bo->pages[idx]); if (!des) { dev_err(atomisp_dev, @@ -512,14 +454,7 @@ int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes) clflush_cache_range(des, len); - if (in_atomic()) - /* - * Note: kunmap_atomic requires return addr from - * kmap_atomic, not the page. See linux/highmem.h - */ - kunmap_atomic(des - offset); - else - kunmap(bo->page_obj[idx].page); + kunmap_local(des); } return 0; @@ -563,7 +498,7 @@ int hmm_set(ia_css_ptr virt, int c, unsigned int bytes) idx = (virt - bo->start) >> PAGE_SHIFT; offset = (virt - bo->start) - (idx << PAGE_SHIFT); - des = (char *)kmap(bo->page_obj[idx].page) + offset; + des = (char *)kmap_local_page(bo->pages[idx]) + offset; if ((bytes + offset) >= PAGE_SIZE) { len = PAGE_SIZE - offset; @@ -579,7 +514,7 @@ int hmm_set(ia_css_ptr virt, int c, unsigned int bytes) clflush_cache_range(des, len); - kunmap(bo->page_obj[idx].page); + kunmap_local(des); } return 0; @@ -602,7 +537,7 @@ phys_addr_t hmm_virt_to_phys(ia_css_ptr virt) idx = (virt - bo->start) >> PAGE_SHIFT; offset = (virt - bo->start) - (idx << PAGE_SHIFT); - return page_to_phys(bo->page_obj[idx].page) + offset; + return page_to_phys(bo->pages[idx]) + offset; } int hmm_mmap(struct vm_area_struct *vma, ia_css_ptr virt) @@ -671,96 +606,3 @@ void hmm_vunmap(ia_css_ptr virt) hmm_bo_vunmap(bo); } - -int hmm_pool_register(unsigned int pool_size, enum hmm_pool_type pool_type) -{ -#if 0 // Just use the "normal" pool - switch (pool_type) { - case HMM_POOL_TYPE_RESERVED: - reserved_pool.pops = &reserved_pops; - return reserved_pool.pops->pool_init(&reserved_pool.pool_info, - pool_size); - case HMM_POOL_TYPE_DYNAMIC: - dynamic_pool.pops = &dynamic_pops; - return dynamic_pool.pops->pool_init(&dynamic_pool.pool_info, - pool_size); - default: - dev_err(atomisp_dev, "invalid pool type.\n"); - return -EINVAL; - } -#else - return 0; -#endif -} - -void hmm_pool_unregister(enum hmm_pool_type pool_type) -{ -#if 0 // Just use the "normal" pool - switch (pool_type) { - case HMM_POOL_TYPE_RESERVED: - if (reserved_pool.pops && reserved_pool.pops->pool_exit) - reserved_pool.pops->pool_exit(&reserved_pool.pool_info); - break; - case HMM_POOL_TYPE_DYNAMIC: - if (dynamic_pool.pops && dynamic_pool.pops->pool_exit) - dynamic_pool.pops->pool_exit(&dynamic_pool.pool_info); - break; - default: - dev_err(atomisp_dev, "invalid pool type.\n"); - break; - } -#endif - - return; -} - -void *hmm_isp_vaddr_to_host_vaddr(ia_css_ptr ptr, bool cached) -{ - return hmm_vmap(ptr, cached); - /* vmunmap will be done in hmm_bo_release() */ -} - -ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr) -{ - struct hmm_buffer_object *bo; - - bo = hmm_bo_device_search_vmap_start(&bo_device, ptr); - if (bo) - return bo->start; - - dev_err(atomisp_dev, - "can not find buffer object whose kernel virtual address is %p\n", - ptr); - return 0; -} - -void hmm_show_mem_stat(const char *func, const int line) -{ - pr_info("tol_cnt=%d usr_size=%d res_size=%d res_cnt=%d sys_size=%d dyc_thr=%d dyc_size=%d.\n", - hmm_mem_stat.tol_cnt, - hmm_mem_stat.usr_size, hmm_mem_stat.res_size, - hmm_mem_stat.res_cnt, hmm_mem_stat.sys_size, - hmm_mem_stat.dyc_thr, hmm_mem_stat.dyc_size); -} - -void hmm_init_mem_stat(int res_pgnr, int dyc_en, int dyc_pgnr) -{ - hmm_mem_stat.res_size = res_pgnr; - /* If reserved mem pool is not enabled, set its "mem stat" values as -1. */ - if (hmm_mem_stat.res_size == 0) { - hmm_mem_stat.res_size = -1; - hmm_mem_stat.res_cnt = -1; - } - - /* If dynamic memory pool is not enabled, set its "mem stat" values as -1. */ - if (!dyc_en) { - hmm_mem_stat.dyc_size = -1; - hmm_mem_stat.dyc_thr = -1; - } else { - hmm_mem_stat.dyc_size = 0; - hmm_mem_stat.dyc_thr = dyc_pgnr; - } - hmm_mem_stat.usr_size = 0; - hmm_mem_stat.sys_size = 0; - hmm_mem_stat.tol_cnt = 0; -} diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c index 0168f9839c90..f50494123f03 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c @@ -42,7 +42,6 @@ #include "atomisp_internal.h" #include "hmm/hmm_common.h" -#include "hmm/hmm_pool.h" #include "hmm/hmm_bo.h" static unsigned int order_to_nr(unsigned int order) @@ -627,75 +626,31 @@ found: } static void free_private_bo_pages(struct hmm_buffer_object *bo, - struct hmm_pool *dypool, - struct hmm_pool *repool, int free_pgnr) { int i, ret; for (i = 0; i < free_pgnr; i++) { - switch (bo->page_obj[i].type) { - case HMM_PAGE_TYPE_RESERVED: - if (repool->pops - && repool->pops->pool_free_pages) { - repool->pops->pool_free_pages(repool->pool_info, - &bo->page_obj[i]); - hmm_mem_stat.res_cnt--; - } - break; - /* - * HMM_PAGE_TYPE_GENERAL indicates that pages are from system - * memory, so when free them, they should be put into dynamic - * pool. - */ - case HMM_PAGE_TYPE_DYNAMIC: - case HMM_PAGE_TYPE_GENERAL: - if (dypool->pops - && dypool->pops->pool_inited - && dypool->pops->pool_inited(dypool->pool_info)) { - if (dypool->pops->pool_free_pages) - dypool->pops->pool_free_pages( - dypool->pool_info, - &bo->page_obj[i]); - break; - } - - fallthrough; - + ret = set_pages_wb(bo->pages[i], 1); + if (ret) + dev_err(atomisp_dev, + "set page to WB err ...ret = %d\n", + ret); /* - * if dynamic memory pool doesn't exist, need to free - * pages to system directly. - */ - default: - ret = set_pages_wb(bo->page_obj[i].page, 1); - if (ret) - dev_err(atomisp_dev, - "set page to WB err ...ret = %d\n", - ret); - /* - W/A: set_pages_wb seldom return value = -EFAULT - indicate that address of page is not in valid - range(0xffff880000000000~0xffffc7ffffffffff) - then, _free_pages would panic; Do not know why page - address be valid,it maybe memory corruption by lowmemory - */ - if (!ret) { - __free_pages(bo->page_obj[i].page, 0); - hmm_mem_stat.sys_size--; - } - break; + W/A: set_pages_wb seldom return value = -EFAULT + indicate that address of page is not in valid + range(0xffff880000000000~0xffffc7ffffffffff) + then, _free_pages would panic; Do not know why page + address be valid,it maybe memory corruption by lowmemory + */ + if (!ret) { + __free_pages(bo->pages[i], 0); } } - - return; } /*Allocate pages which will be used only by ISP*/ -static int alloc_private_pages(struct hmm_buffer_object *bo, - int from_highmem, - bool cached, - struct hmm_pool *dypool, - struct hmm_pool *repool) +static int alloc_private_pages(struct hmm_buffer_object *bo) { int ret; unsigned int pgnr, order, blk_pgnr, alloc_pgnr; @@ -706,50 +661,11 @@ static int alloc_private_pages(struct hmm_buffer_object *bo, bool reduce_order = false; bool lack_mem = true; - if (from_highmem) - gfp |= __GFP_HIGHMEM; - pgnr = bo->pgnr; - bo->page_obj = kmalloc_array(pgnr, sizeof(struct hmm_page_object), - GFP_KERNEL); - if (unlikely(!bo->page_obj)) - return -ENOMEM; - i = 0; alloc_pgnr = 0; - /* - * get physical pages from dynamic pages pool. - */ - if (dypool->pops && dypool->pops->pool_alloc_pages) { - alloc_pgnr = dypool->pops->pool_alloc_pages(dypool->pool_info, - bo->page_obj, pgnr, - cached); - hmm_mem_stat.dyc_size -= alloc_pgnr; - - if (alloc_pgnr == pgnr) - return 0; - } - - pgnr -= alloc_pgnr; - i += alloc_pgnr; - - /* - * get physical pages from reserved pages pool for atomisp. - */ - if (repool->pops && repool->pops->pool_alloc_pages) { - alloc_pgnr = repool->pops->pool_alloc_pages(repool->pool_info, - &bo->page_obj[i], pgnr, - cached); - hmm_mem_stat.res_cnt += alloc_pgnr; - if (alloc_pgnr == pgnr) - return 0; - } - - pgnr -= alloc_pgnr; - i += alloc_pgnr; - while (pgnr) { order = nr_to_order_bottom(pgnr); /* @@ -804,28 +720,24 @@ retry: } else { blk_pgnr = order_to_nr(order); - if (!cached) { - /* - * set memory to uncacheable -- UC_MINUS - */ - ret = set_pages_uc(pages, blk_pgnr); - if (ret) { - dev_err(atomisp_dev, - "set page uncacheablefailed.\n"); + /* + * set memory to uncacheable -- UC_MINUS + */ + ret = set_pages_uc(pages, blk_pgnr); + if (ret) { + dev_err(atomisp_dev, + "set page uncacheablefailed.\n"); - __free_pages(pages, order); + __free_pages(pages, order); - goto cleanup; - } + goto cleanup; } - for (j = 0; j < blk_pgnr; j++) { - bo->page_obj[i].page = pages + j; - bo->page_obj[i++].type = HMM_PAGE_TYPE_GENERAL; + for (j = 0; j < blk_pgnr; j++, i++) { + bo->pages[i] = pages + j; } pgnr -= blk_pgnr; - hmm_mem_stat.sys_size += blk_pgnr; /* * if order is not reduced this time, clear @@ -841,60 +753,31 @@ retry: return 0; cleanup: alloc_pgnr = i; - free_private_bo_pages(bo, dypool, repool, alloc_pgnr); - - kfree(bo->page_obj); - + free_private_bo_pages(bo, alloc_pgnr); return -ENOMEM; } -static void free_private_pages(struct hmm_buffer_object *bo, - struct hmm_pool *dypool, - struct hmm_pool *repool) -{ - free_private_bo_pages(bo, dypool, repool, bo->pgnr); - - kfree(bo->page_obj); -} - static void free_user_pages(struct hmm_buffer_object *bo, unsigned int page_nr) { int i; - hmm_mem_stat.usr_size -= bo->pgnr; - if (bo->mem_type == HMM_BO_MEM_TYPE_PFN) { unpin_user_pages(bo->pages, page_nr); } else { for (i = 0; i < page_nr; i++) put_page(bo->pages[i]); } - kfree(bo->pages); - kfree(bo->page_obj); } /* * Convert user space virtual address into pages list */ static int alloc_user_pages(struct hmm_buffer_object *bo, - const void __user *userptr, bool cached) + const void __user *userptr) { int page_nr; - int i; struct vm_area_struct *vma; - struct page **pages; - - pages = kmalloc_array(bo->pgnr, sizeof(struct page *), GFP_KERNEL); - if (unlikely(!pages)) - return -ENOMEM; - - bo->page_obj = kmalloc_array(bo->pgnr, sizeof(struct hmm_page_object), - GFP_KERNEL); - if (unlikely(!bo->page_obj)) { - kfree(pages); - return -ENOMEM; - } mutex_unlock(&bo->mutex); mmap_read_lock(current->mm); @@ -902,8 +785,6 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, mmap_read_unlock(current->mm); if (!vma) { dev_err(atomisp_dev, "find_vma failed\n"); - kfree(bo->page_obj); - kfree(pages); mutex_lock(&bo->mutex); return -EFAULT; } @@ -915,18 +796,16 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, userptr = untagged_addr(userptr); - bo->pages = pages; - if (vma->vm_flags & (VM_IO | VM_PFNMAP)) { page_nr = pin_user_pages((unsigned long)userptr, bo->pgnr, FOLL_LONGTERM | FOLL_WRITE, - pages, NULL); + bo->pages, NULL); bo->mem_type = HMM_BO_MEM_TYPE_PFN; } else { /*Handle frame buffer allocated in user space*/ mutex_unlock(&bo->mutex); page_nr = get_user_pages_fast((unsigned long)userptr, - (int)(bo->pgnr), 1, pages); + (int)(bo->pgnr), 1, bo->pages); mutex_lock(&bo->mutex); bo->mem_type = HMM_BO_MEM_TYPE_USER; } @@ -936,8 +815,6 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, bo->pgnr, bo->mem_type == HMM_BO_MEM_TYPE_USER ? "user" : "pfn", page_nr); - hmm_mem_stat.usr_size += bo->pgnr; - /* can be written by caller, not forced */ if (page_nr != bo->pgnr) { dev_err(atomisp_dev, @@ -948,11 +825,6 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, goto out_of_mem; } - for (i = 0; i < bo->pgnr; i++) { - bo->page_obj[i].page = pages[i]; - bo->page_obj[i].type = HMM_PAGE_TYPE_GENERAL; - } - return 0; out_of_mem: @@ -966,20 +838,14 @@ out_of_mem: * allocate/free physical pages for the bo. * * type indicate where are the pages from. currently we have 3 types - * of memory: HMM_BO_PRIVATE, HMM_BO_USER, HMM_BO_SHARE. - * - * from_highmem is only valid when type is HMM_BO_PRIVATE, it will - * try to alloc memory from highmem if from_highmem is set. + * of memory: HMM_BO_PRIVATE, HMM_BO_USER. * * userptr is only valid when type is HMM_BO_USER, it indicates * the start address from user space task. - * - * from_highmem and userptr will both be ignored when type is - * HMM_BO_SHARE. */ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo, - enum hmm_bo_type type, int from_highmem, - const void __user *userptr, bool cached) + enum hmm_bo_type type, + const void __user *userptr) { int ret = -EINVAL; @@ -988,15 +854,20 @@ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo, mutex_lock(&bo->mutex); check_bo_status_no_goto(bo, HMM_BO_PAGE_ALLOCED, status_err); + bo->pages = kmalloc_array(bo->pgnr, sizeof(struct page *), GFP_KERNEL); + if (unlikely(!bo->pages)) { + ret = -ENOMEM; + goto alloc_err; + } + /* * TO DO: * add HMM_BO_USER type */ if (type == HMM_BO_PRIVATE) { - ret = alloc_private_pages(bo, from_highmem, - cached, &dynamic_pool, &reserved_pool); + ret = alloc_private_pages(bo); } else if (type == HMM_BO_USER) { - ret = alloc_user_pages(bo, userptr, cached); + ret = alloc_user_pages(bo, userptr); } else { dev_err(atomisp_dev, "invalid buffer type.\n"); ret = -EINVAL; @@ -1013,6 +884,7 @@ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo, return 0; alloc_err: + kfree(bo->pages); mutex_unlock(&bo->mutex); dev_err(atomisp_dev, "alloc pages err...\n"); return ret; @@ -1038,11 +910,13 @@ void hmm_bo_free_pages(struct hmm_buffer_object *bo) bo->status &= (~HMM_BO_PAGE_ALLOCED); if (bo->type == HMM_BO_PRIVATE) - free_private_pages(bo, &dynamic_pool, &reserved_pool); + free_private_bo_pages(bo, bo->pgnr); else if (bo->type == HMM_BO_USER) free_user_pages(bo, bo->pgnr); else dev_err(atomisp_dev, "invalid buffer type.\n"); + + kfree(bo->pages); mutex_unlock(&bo->mutex); return; @@ -1061,32 +935,6 @@ int hmm_bo_page_allocated(struct hmm_buffer_object *bo) } /* - * get physical page info of the bo. - */ -int hmm_bo_get_page_info(struct hmm_buffer_object *bo, - struct hmm_page_object **page_obj, int *pgnr) -{ - check_bo_null_return(bo, -EINVAL); - - mutex_lock(&bo->mutex); - - check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err); - - *page_obj = bo->page_obj; - *pgnr = bo->pgnr; - - mutex_unlock(&bo->mutex); - - return 0; - -status_err: - dev_err(atomisp_dev, - "buffer object not page allocated yet.\n"); - mutex_unlock(&bo->mutex); - return -EINVAL; -} - -/* * bind the physical pages to a virtual address space. */ int hmm_bo_bind(struct hmm_buffer_object *bo) @@ -1113,7 +961,7 @@ int hmm_bo_bind(struct hmm_buffer_object *bo) for (i = 0; i < bo->pgnr; i++) { ret = isp_mmu_map(&bdev->mmu, virt, - page_to_phys(bo->page_obj[i].page), 1); + page_to_phys(bo->pages[i]), 1); if (ret) goto map_err; virt += (1 << PAGE_SHIFT); @@ -1227,9 +1075,6 @@ int hmm_bo_binded(struct hmm_buffer_object *bo) void *hmm_bo_vmap(struct hmm_buffer_object *bo, bool cached) { - struct page **pages; - int i; - check_bo_null_return(bo, NULL); mutex_lock(&bo->mutex); @@ -1246,27 +1091,15 @@ void *hmm_bo_vmap(struct hmm_buffer_object *bo, bool cached) bo->status &= ~(HMM_BO_VMAPED | HMM_BO_VMAPED_CACHED); } - pages = kmalloc_array(bo->pgnr, sizeof(*pages), GFP_KERNEL); - if (unlikely(!pages)) { - mutex_unlock(&bo->mutex); - return NULL; - } - - for (i = 0; i < bo->pgnr; i++) - pages[i] = bo->page_obj[i].page; - - bo->vmap_addr = vmap(pages, bo->pgnr, VM_MAP, + bo->vmap_addr = vmap(bo->pages, bo->pgnr, VM_MAP, cached ? PAGE_KERNEL : PAGE_KERNEL_NOCACHE); if (unlikely(!bo->vmap_addr)) { - kfree(pages); mutex_unlock(&bo->mutex); dev_err(atomisp_dev, "vmap failed...\n"); return NULL; } bo->status |= (cached ? HMM_BO_VMAPED_CACHED : HMM_BO_VMAPED); - kfree(pages); - mutex_unlock(&bo->mutex); return bo->vmap_addr; } @@ -1396,7 +1229,7 @@ int hmm_bo_mmap(struct vm_area_struct *vma, struct hmm_buffer_object *bo) virt = vma->vm_start; for (i = 0; i < pgnr; i++) { - pfn = page_to_pfn(bo->page_obj[i].page); + pfn = page_to_pfn(bo->pages[i]); if (remap_pfn_range(vma, virt, pfn, PAGE_SIZE, PAGE_SHARED)) { dev_warn(atomisp_dev, "remap_pfn_range failed: virt = 0x%x, pfn = 0x%x, mapped_pgnr = %d\n", diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_dynamic_pool.c b/drivers/staging/media/atomisp/pci/hmm/hmm_dynamic_pool.c deleted file mode 100644 index eaf97e5f3b68..000000000000 --- a/drivers/staging/media/atomisp/pci/hmm/hmm_dynamic_pool.c +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ -/* - * This file contains functions for dynamic memory pool management - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/mm.h> - -#include <asm/set_memory.h> - -#include "atomisp_internal.h" - -#include "hmm/hmm_pool.h" - -/* - * dynamic memory pool ops. - */ -static unsigned int get_pages_from_dynamic_pool(void *pool, - struct hmm_page_object *page_obj, - unsigned int size, bool cached) -{ - struct hmm_page *hmm_page; - unsigned long flags; - unsigned int i = 0; - struct hmm_dynamic_pool_info *dypool_info = pool; - - if (!dypool_info) - return 0; - - spin_lock_irqsave(&dypool_info->list_lock, flags); - if (dypool_info->initialized) { - while (!list_empty(&dypool_info->pages_list)) { - hmm_page = list_entry(dypool_info->pages_list.next, - struct hmm_page, list); - - list_del(&hmm_page->list); - dypool_info->pgnr--; - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - - page_obj[i].page = hmm_page->page; - page_obj[i++].type = HMM_PAGE_TYPE_DYNAMIC; - kmem_cache_free(dypool_info->pgptr_cache, hmm_page); - - if (i == size) - return i; - - spin_lock_irqsave(&dypool_info->list_lock, flags); - } - } - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - - return i; -} - -static void free_pages_to_dynamic_pool(void *pool, - struct hmm_page_object *page_obj) -{ - struct hmm_page *hmm_page; - unsigned long flags; - int ret; - struct hmm_dynamic_pool_info *dypool_info = pool; - - if (!dypool_info) - return; - - spin_lock_irqsave(&dypool_info->list_lock, flags); - if (!dypool_info->initialized) { - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - return; - } - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - - if (page_obj->type == HMM_PAGE_TYPE_RESERVED) - return; - - if (dypool_info->pgnr >= dypool_info->pool_size) { - /* free page directly back to system */ - ret = set_pages_wb(page_obj->page, 1); - if (ret) - dev_err(atomisp_dev, - "set page to WB err ...ret=%d\n", ret); - /* - W/A: set_pages_wb seldom return value = -EFAULT - indicate that address of page is not in valid - range(0xffff880000000000~0xffffc7ffffffffff) - then, _free_pages would panic; Do not know why page - address be valid, it maybe memory corruption by lowmemory - */ - if (!ret) { - __free_pages(page_obj->page, 0); - hmm_mem_stat.sys_size--; - } - return; - } - hmm_page = kmem_cache_zalloc(dypool_info->pgptr_cache, - GFP_KERNEL); - if (!hmm_page) { - /* free page directly */ - ret = set_pages_wb(page_obj->page, 1); - if (ret) - dev_err(atomisp_dev, - "set page to WB err ...ret=%d\n", ret); - if (!ret) { - __free_pages(page_obj->page, 0); - hmm_mem_stat.sys_size--; - } - return; - } - - hmm_page->page = page_obj->page; - - /* - * add to pages_list of pages_pool - */ - spin_lock_irqsave(&dypool_info->list_lock, flags); - list_add_tail(&hmm_page->list, &dypool_info->pages_list); - dypool_info->pgnr++; - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - hmm_mem_stat.dyc_size++; -} - -static int hmm_dynamic_pool_init(void **pool, unsigned int pool_size) -{ - struct hmm_dynamic_pool_info *dypool_info; - - if (pool_size == 0) - return 0; - - dypool_info = kmalloc(sizeof(struct hmm_dynamic_pool_info), - GFP_KERNEL); - if (unlikely(!dypool_info)) - return -ENOMEM; - - dypool_info->pgptr_cache = kmem_cache_create("pgptr_cache", - sizeof(struct hmm_page), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!dypool_info->pgptr_cache) { - kfree(dypool_info); - return -ENOMEM; - } - - INIT_LIST_HEAD(&dypool_info->pages_list); - spin_lock_init(&dypool_info->list_lock); - dypool_info->initialized = true; - dypool_info->pool_size = pool_size; - dypool_info->pgnr = 0; - - *pool = dypool_info; - - return 0; -} - -static void hmm_dynamic_pool_exit(void **pool) -{ - struct hmm_dynamic_pool_info *dypool_info = *pool; - struct hmm_page *hmm_page; - unsigned long flags; - int ret; - - if (!dypool_info) - return; - - spin_lock_irqsave(&dypool_info->list_lock, flags); - if (!dypool_info->initialized) { - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - return; - } - dypool_info->initialized = false; - - while (!list_empty(&dypool_info->pages_list)) { - hmm_page = list_entry(dypool_info->pages_list.next, - struct hmm_page, list); - - list_del(&hmm_page->list); - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - - /* can cause thread sleep, so cannot be put into spin_lock */ - ret = set_pages_wb(hmm_page->page, 1); - if (ret) - dev_err(atomisp_dev, - "set page to WB err...ret=%d\n", ret); - if (!ret) { - __free_pages(hmm_page->page, 0); - hmm_mem_stat.dyc_size--; - hmm_mem_stat.sys_size--; - } - kmem_cache_free(dypool_info->pgptr_cache, hmm_page); - spin_lock_irqsave(&dypool_info->list_lock, flags); - } - - spin_unlock_irqrestore(&dypool_info->list_lock, flags); - - kmem_cache_destroy(dypool_info->pgptr_cache); - - kfree(dypool_info); - - *pool = NULL; -} - -static int hmm_dynamic_pool_inited(void *pool) -{ - struct hmm_dynamic_pool_info *dypool_info = pool; - - if (!dypool_info) - return 0; - - return dypool_info->initialized; -} - -struct hmm_pool_ops dynamic_pops = { - .pool_init = hmm_dynamic_pool_init, - .pool_exit = hmm_dynamic_pool_exit, - .pool_alloc_pages = get_pages_from_dynamic_pool, - .pool_free_pages = free_pages_to_dynamic_pool, - .pool_inited = hmm_dynamic_pool_inited, -}; diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_reserved_pool.c b/drivers/staging/media/atomisp/pci/hmm/hmm_reserved_pool.c deleted file mode 100644 index 57525fece921..000000000000 --- a/drivers/staging/media/atomisp/pci/hmm/hmm_reserved_pool.c +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ -/* - * This file contains functions for reserved memory pool management - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/mm.h> - -#include <asm/set_memory.h> - -#include "atomisp_internal.h" -#include "hmm/hmm_pool.h" - -/* - * reserved memory pool ops. - */ -static unsigned int get_pages_from_reserved_pool(void *pool, - struct hmm_page_object *page_obj, - unsigned int size, bool cached) -{ - unsigned long flags; - unsigned int i = 0; - unsigned int repool_pgnr; - int j; - struct hmm_reserved_pool_info *repool_info = pool; - - if (!repool_info) - return 0; - - spin_lock_irqsave(&repool_info->list_lock, flags); - if (repool_info->initialized) { - repool_pgnr = repool_info->index; - - for (j = repool_pgnr - 1; j >= 0; j--) { - page_obj[i].page = repool_info->pages[j]; - page_obj[i].type = HMM_PAGE_TYPE_RESERVED; - i++; - repool_info->index--; - if (i == size) - break; - } - } - spin_unlock_irqrestore(&repool_info->list_lock, flags); - return i; -} - -static void free_pages_to_reserved_pool(void *pool, - struct hmm_page_object *page_obj) -{ - unsigned long flags; - struct hmm_reserved_pool_info *repool_info = pool; - - if (!repool_info) - return; - - spin_lock_irqsave(&repool_info->list_lock, flags); - - if (repool_info->initialized && - repool_info->index < repool_info->pgnr && - page_obj->type == HMM_PAGE_TYPE_RESERVED) { - repool_info->pages[repool_info->index++] = page_obj->page; - } - - spin_unlock_irqrestore(&repool_info->list_lock, flags); -} - -static int hmm_reserved_pool_setup(struct hmm_reserved_pool_info **repool_info, - unsigned int pool_size) -{ - struct hmm_reserved_pool_info *pool_info; - - pool_info = kmalloc(sizeof(struct hmm_reserved_pool_info), - GFP_KERNEL); - if (unlikely(!pool_info)) - return -ENOMEM; - - pool_info->pages = kmalloc(sizeof(struct page *) * pool_size, - GFP_KERNEL); - if (unlikely(!pool_info->pages)) { - kfree(pool_info); - return -ENOMEM; - } - - pool_info->index = 0; - pool_info->pgnr = 0; - spin_lock_init(&pool_info->list_lock); - pool_info->initialized = true; - - *repool_info = pool_info; - - return 0; -} - -static int hmm_reserved_pool_init(void **pool, unsigned int pool_size) -{ - int ret; - unsigned int blk_pgnr; - unsigned int pgnr = pool_size; - unsigned int order = 0; - unsigned int i = 0; - int fail_number = 0; - struct page *pages; - int j; - struct hmm_reserved_pool_info *repool_info; - - if (pool_size == 0) - return 0; - - ret = hmm_reserved_pool_setup(&repool_info, pool_size); - if (ret) { - dev_err(atomisp_dev, "hmm_reserved_pool_setup failed.\n"); - return ret; - } - - pgnr = pool_size; - - i = 0; - order = MAX_ORDER; - - while (pgnr) { - blk_pgnr = 1U << order; - while (blk_pgnr > pgnr) { - order--; - blk_pgnr >>= 1U; - } - BUG_ON(order > MAX_ORDER); - - pages = alloc_pages(GFP_KERNEL | __GFP_NOWARN, order); - if (unlikely(!pages)) { - if (order == 0) { - fail_number++; - dev_err(atomisp_dev, "%s: alloc_pages failed: %d\n", - __func__, fail_number); - /* if fail five times, will goto end */ - - /* FIXME: whether is the mechanism is ok? */ - if (fail_number == ALLOC_PAGE_FAIL_NUM) - goto end; - } else { - order--; - } - } else { - blk_pgnr = 1U << order; - - ret = set_pages_uc(pages, blk_pgnr); - if (ret) { - dev_err(atomisp_dev, - "set pages uncached failed\n"); - __free_pages(pages, order); - goto end; - } - - for (j = 0; j < blk_pgnr; j++) - repool_info->pages[i++] = pages + j; - - repool_info->index += blk_pgnr; - repool_info->pgnr += blk_pgnr; - - pgnr -= blk_pgnr; - - fail_number = 0; - } - } - -end: - repool_info->initialized = true; - - *pool = repool_info; - - dev_info(atomisp_dev, - "hmm_reserved_pool init successfully,hmm_reserved_pool is with %d pages.\n", - repool_info->pgnr); - return 0; -} - -static void hmm_reserved_pool_exit(void **pool) -{ - unsigned long flags; - int i, ret; - unsigned int pgnr; - struct hmm_reserved_pool_info *repool_info = *pool; - - if (!repool_info) - return; - - spin_lock_irqsave(&repool_info->list_lock, flags); - if (!repool_info->initialized) { - spin_unlock_irqrestore(&repool_info->list_lock, flags); - return; - } - pgnr = repool_info->pgnr; - repool_info->index = 0; - repool_info->pgnr = 0; - repool_info->initialized = false; - spin_unlock_irqrestore(&repool_info->list_lock, flags); - - for (i = 0; i < pgnr; i++) { - ret = set_pages_wb(repool_info->pages[i], 1); - if (ret) - dev_err(atomisp_dev, - "set page to WB err...ret=%d\n", ret); - /* - W/A: set_pages_wb seldom return value = -EFAULT - indicate that address of page is not in valid - range(0xffff880000000000~0xffffc7ffffffffff) - then, _free_pages would panic; Do not know why - page address be valid, it maybe memory corruption by lowmemory - */ - if (!ret) - __free_pages(repool_info->pages[i], 0); - } - - kfree(repool_info->pages); - kfree(repool_info); - - *pool = NULL; -} - -static int hmm_reserved_pool_inited(void *pool) -{ - struct hmm_reserved_pool_info *repool_info = pool; - - if (!repool_info) - return 0; - - return repool_info->initialized; -} - -struct hmm_pool_ops reserved_pops = { - .pool_init = hmm_reserved_pool_init, - .pool_exit = hmm_reserved_pool_exit, - .pool_alloc_pages = get_pages_from_reserved_pool, - .pool_free_pages = free_pages_to_reserved_pool, - .pool_inited = hmm_reserved_pool_inited, -}; diff --git a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h index 96c86f0dc81c..514d933f934d 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h @@ -169,7 +169,6 @@ struct ia_css_frame { /** exposure id, see ia_css_event_public.h for more detail */ u32 isp_config_id; /** Unique ID to track which config was actually applied to a particular frame */ bool valid; /** First video output frame is not valid */ - bool contiguous; /** memory is allocated physically contiguously */ union { unsigned int _initialisation_dummy; struct ia_css_frame_plane raw; @@ -245,44 +244,6 @@ ia_css_frame_allocate_from_info(struct ia_css_frame **frame, void ia_css_frame_free(struct ia_css_frame *frame); -/* @brief Allocate a contiguous CSS frame structure - * - * @param frame The allocated frame. - * @param width The width (in pixels) of the frame. - * @param height The height (in lines) of the frame. - * @param format The frame format. - * @param stride The padded stride, in pixels. - * @param raw_bit_depth The raw bit depth, in bits. - * @return The error code. - * - * Contiguous frame allocation, only for FPGA display driver which needs - * physically contiguous memory. - * Deprecated. - */ -int -ia_css_frame_allocate_contiguous(struct ia_css_frame **frame, - unsigned int width, - unsigned int height, - enum ia_css_frame_format format, - unsigned int stride, - unsigned int raw_bit_depth); - -/* @brief Allocate a contiguous CSS frame from a frame info structure. - * - * @param frame The allocated frame. - * @param[in] info The frame info structure. - * @return The error code. - * - * Allocate a frame using the resolution and format from a frame info struct. - * This is a convenience function, implemented on top of - * ia_css_frame_allocate_contiguous(). - * Only for FPGA display driver which needs physically contiguous memory. - * Deprecated. - */ -int -ia_css_frame_allocate_contiguous_from_info(struct ia_css_frame **frame, - const struct ia_css_frame_info *info); - /* @brief Allocate a CSS frame structure using a frame info structure. * * @param frame The allocated frame. @@ -334,7 +295,6 @@ int ia_css_frame_map(struct ia_css_frame **frame, const struct ia_css_frame_info *info, const void __user *data, - u16 attribute, unsigned int pgnr); /* @brief Unmap a CSS frame structure. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c index 13caa55fd51a..bf0a768f8fe1 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c @@ -331,7 +331,7 @@ ia_css_isp_dvs_statistics_allocate( HIVE_ISP_DDR_WORD_BYTES); me->size = hor_size + ver_size; - me->data_ptr = hmm_alloc(me->size, HMM_BO_PRIVATE, 0, NULL, 0); + me->data_ptr = hmm_alloc(me->size); if (me->data_ptr == mmgr_NULL) goto err; me->hor_size = hor_size; diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c index f608740e8340..c13de289a3db 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c @@ -294,7 +294,7 @@ ia_css_isp_dvs2_statistics_allocate( * grid->aligned_height * IA_CSS_DVS2_NUM_COEF_TYPES; me->size = 2 * size; - me->data_ptr = hmm_alloc(me->size, HMM_BO_PRIVATE, 0, NULL, 0); + me->data_ptr = hmm_alloc(me->size); if (me->data_ptr == mmgr_NULL) goto err; me->hor_proj = me->data_ptr; diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h index bfe4f5976771..73432dc35ae3 100644 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h +++ b/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h @@ -145,12 +145,6 @@ more details. #define RAW_BUF_LINES ((ENABLE_RAW_BINNING || ENABLE_FIXED_BAYER_DS) ? 4 : 2) -#define RAW_BUF_STRIDE \ - (BINARY_ID == SH_CSS_BINARY_ID_POST_ISP ? MAX_VECTORS_PER_INPUT_CHUNK : \ - ISP_NUM_STRIPES > 1 ? MAX_VECTORS_PER_INPUT_STRIPE + _ISP_EXTRA_PADDING_VECS : \ - !ENABLE_CONTINUOUS ? MAX_VECTORS_PER_INPUT_LINE : \ - MAX_VECTORS_PER_INPUT_CHUNK) - /* [isp vmem] table size[vectors] per line per color (GR,R,B,GB), multiples of NWAY */ #define ISP2400_SCTBL_VECTORS_PER_LINE_PER_COLOR \ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index f46238725eea..3d269bd23207 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -1305,8 +1305,6 @@ void ia_css_debug_frame_print(const struct ia_css_frame *frame, ia_css_debug_dtrace(2, " padded width = %d\n", frame->info.padded_width); ia_css_debug_dtrace(2, " format = %d\n", frame->info.format); - ia_css_debug_dtrace(2, " is contiguous = %s\n", - frame->contiguous ? "yes" : "no"); switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_NV12: case IA_CSS_FRAME_FORMAT_NV16: diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h index c756a134efc3..700070c58eda 100644 --- a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h +++ b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h @@ -109,16 +109,13 @@ void ia_css_frame_free_multiple(unsigned int num_frames, * * @param frame The allocated frame. * @param[in] size_bytes The frame size in bytes. - * @param[in] contiguous Allocate memory physically contiguously or not. * @return The error code. * * Allocate a frame using the given size in bytes. * The frame structure is partially null initialized. */ -int ia_css_frame_allocate_with_buffer_size( - struct ia_css_frame **frame, - const unsigned int size_bytes, - const bool contiguous); +int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame, + const unsigned int size_bytes); /* @brief Check whether 2 frames are same type * diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c index a3aae638b0bf..5a7058320ee6 100644 --- a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c +++ b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c @@ -48,12 +48,6 @@ static void frame_init_raw_single_plane( unsigned int subpixels_per_line, unsigned int bits_per_pixel); -static void frame_init_mipi_plane(struct ia_css_frame *frame, - struct ia_css_frame_plane *plane, - unsigned int height, - unsigned int subpixels_per_line, - unsigned int bytes_per_pixel); - static void frame_init_nv_planes(struct ia_css_frame *frame, unsigned int horizontal_decimation, unsigned int vertical_decimation, @@ -77,15 +71,13 @@ static int frame_allocate_with_data(struct ia_css_frame **frame, unsigned int height, enum ia_css_frame_format format, unsigned int padded_width, - unsigned int raw_bit_depth, - bool contiguous); + unsigned int raw_bit_depth); static struct ia_css_frame *frame_create(unsigned int width, unsigned int height, enum ia_css_frame_format format, unsigned int padded_width, unsigned int raw_bit_depth, - bool contiguous, bool valid); static unsigned @@ -137,7 +129,7 @@ int ia_css_frame_allocate(struct ia_css_frame **frame, width, height, format, padded_width, raw_bit_depth); err = frame_allocate_with_data(frame, width, height, format, - padded_width, raw_bit_depth, false); + padded_width, raw_bit_depth); if ((*frame) && err == 0) ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, @@ -154,7 +146,6 @@ int ia_css_frame_allocate(struct ia_css_frame **frame, int ia_css_frame_map(struct ia_css_frame **frame, const struct ia_css_frame_info *info, const void __user *data, - u16 attribute, unsigned int pgnr) { int err = 0; @@ -180,9 +171,7 @@ int ia_css_frame_map(struct ia_css_frame **frame, goto error; } - me->data = hmm_alloc(me->data_bytes, HMM_BO_USER, 0, data, - attribute & ATOMISP_MAP_FLAG_CACHED); - + me->data = hmm_create_from_userdata(me->data_bytes, data); if (me->data == mmgr_NULL) err = -EINVAL; @@ -216,7 +205,6 @@ int ia_css_frame_create_from_info(struct ia_css_frame **frame, info->format, info->padded_width, info->raw_bit_depth, - false, false); if (!me) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, @@ -270,49 +258,6 @@ int ia_css_frame_set_data(struct ia_css_frame *frame, return err; } -int ia_css_frame_allocate_contiguous(struct ia_css_frame **frame, - unsigned int width, - unsigned int height, - enum ia_css_frame_format format, - unsigned int padded_width, - unsigned int raw_bit_depth) -{ - int err = 0; - - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, - "ia_css_frame_allocate_contiguous() enter: width=%d, height=%d, format=%d, padded_width=%d, raw_bit_depth=%d\n", - width, height, format, padded_width, raw_bit_depth); - - err = frame_allocate_with_data(frame, width, height, format, - padded_width, raw_bit_depth, true); - - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, - "ia_css_frame_allocate_contiguous() leave: frame=%p\n", - frame ? *frame : (void *)-1); - - return err; -} - -int ia_css_frame_allocate_contiguous_from_info( - struct ia_css_frame **frame, - const struct ia_css_frame_info *info) -{ - int err = 0; - - assert(frame); - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, - "ia_css_frame_allocate_contiguous_from_info() enter:\n"); - err = ia_css_frame_allocate_contiguous(frame, - info->res.width, - info->res.height, - info->format, - info->padded_width, - info->raw_bit_depth); - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, - "ia_css_frame_allocate_contiguous_from_info() leave:\n"); - return err; -} - void ia_css_frame_free(struct ia_css_frame *frame) { IA_CSS_ENTER_PRIVATE("frame = %p", frame); @@ -343,11 +288,9 @@ int ia_css_frame_init_planes(struct ia_css_frame *frame) switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_MIPI: - frame_init_mipi_plane(frame, &frame->planes.raw, - frame->info.res.height, - frame->info.padded_width, - frame->info.raw_bit_depth <= 8 ? 1 : 2); - break; + dev_err(atomisp_dev, + "%s: unexpected use of IA_CSS_FRAME_FORMAT_MIPI\n", __func__); + return -EINVAL; case IA_CSS_FRAME_FORMAT_RAW_PACKED: frame_init_raw_single_plane(frame, &frame->planes.raw, frame->info.res.height, @@ -460,10 +403,7 @@ void ia_css_frame_info_set_width(struct ia_css_frame_info *info, IA_CSS_LEAVE_PRIVATE(""); return; } - if (min_padded_width > width) - align = min_padded_width; - else - align = width; + align = max(min_padded_width, width); info->res.width = width; /* frames with a U and V plane of 8 bits per pixel need to have @@ -529,16 +469,14 @@ void ia_css_frame_free_multiple(unsigned int num_frames, } } -int ia_css_frame_allocate_with_buffer_size( - struct ia_css_frame **frame, - const unsigned int buffer_size_bytes, - const bool contiguous) +int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame, + const unsigned int buffer_size_bytes) { /* AM: Body coppied from frame_allocate_with_data(). */ int err; struct ia_css_frame *me = frame_create(0, 0, IA_CSS_FRAME_FORMAT_NUM,/* Not valid format yet */ - 0, 0, contiguous, false); + 0, 0, false); if (!me) return -ENOMEM; @@ -670,22 +608,6 @@ static void frame_init_raw_single_plane( return; } -static void frame_init_mipi_plane(struct ia_css_frame *frame, - struct ia_css_frame_plane *plane, - unsigned int height, - unsigned int subpixels_per_line, - unsigned int bytes_per_pixel) -{ - unsigned int stride; - - stride = subpixels_per_line * bytes_per_pixel; - frame->data_bytes = 8388608; /* 8*1024*1024 */ - frame->valid = false; - frame->contiguous = true; - frame_init_plane(plane, subpixels_per_line, stride, height, 0); - return; -} - static void frame_init_nv_planes(struct ia_css_frame *frame, unsigned int horizontal_decimation, unsigned int vertical_decimation, @@ -803,11 +725,7 @@ static int frame_allocate_buffer_data(struct ia_css_frame *frame) #ifdef ISP2401 IA_CSS_ENTER_LEAVE_PRIVATE("frame->data_bytes=%d\n", frame->data_bytes); #endif - frame->data = hmm_alloc(frame->data_bytes, - HMM_BO_PRIVATE, 0, NULL, - frame->contiguous ? - ATOMISP_MAP_FLAG_CONTIGUOUS : 0); - + frame->data = hmm_alloc(frame->data_bytes); if (frame->data == mmgr_NULL) return -ENOMEM; return 0; @@ -818,8 +736,7 @@ static int frame_allocate_with_data(struct ia_css_frame **frame, unsigned int height, enum ia_css_frame_format format, unsigned int padded_width, - unsigned int raw_bit_depth, - bool contiguous) + unsigned int raw_bit_depth) { int err; struct ia_css_frame *me = frame_create(width, @@ -827,7 +744,6 @@ static int frame_allocate_with_data(struct ia_css_frame **frame, format, padded_width, raw_bit_depth, - contiguous, true); if (!me) @@ -857,7 +773,6 @@ static struct ia_css_frame *frame_create(unsigned int width, enum ia_css_frame_format format, unsigned int padded_width, unsigned int raw_bit_depth, - bool contiguous, bool valid) { struct ia_css_frame *me = kvmalloc(sizeof(*me), GFP_KERNEL); @@ -871,7 +786,6 @@ static struct ia_css_frame *frame_create(unsigned int width, me->info.format = format; me->info.padded_width = padded_width; me->info.raw_bit_depth = raw_bit_depth; - me->contiguous = contiguous; me->valid = valid; me->data_bytes = 0; me->data = mmgr_NULL; diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c b/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c index 823ec54b6281..99c2f3a533ab 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c @@ -131,7 +131,7 @@ ia_css_isp_param_allocate_isp_parameters( goto cleanup; } if (pclass != IA_CSS_PARAM_CLASS_PARAM) { - css_params->params[pclass][mem].address = hmm_alloc(size, HMM_BO_PRIVATE, 0, NULL, 0); + css_params->params[pclass][mem].address = hmm_alloc(size); if (!css_params->params[pclass][mem].address) { err = -ENOMEM; goto cleanup; diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c index 39604752785b..2e07dab8bf51 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c @@ -254,14 +254,15 @@ void rmgr_pop_handle(struct ia_css_rmgr_vbuf_pool *pool, void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool, struct ia_css_rmgr_vbuf_handle **handle) { - struct ia_css_rmgr_vbuf_handle h = { 0 }; - if ((!pool) || (!handle) || (!*handle)) { IA_CSS_LOG("Invalid inputs"); return; } if (pool->copy_on_write) { + struct ia_css_rmgr_vbuf_handle *new_handle; + struct ia_css_rmgr_vbuf_handle h = { 0 }; + /* only one reference, reuse (no new retain) */ if ((*handle)->count == 1) return; @@ -272,23 +273,29 @@ void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool, h.size = (*handle)->size; /* release ref to current buffer */ ia_css_rmgr_refcount_release_vbuf(handle); - **handle = h; + new_handle = &h; + } else { + new_handle = *handle; } /* get new buffer for needed size */ - if ((*handle)->vptr == 0x0) { + if (new_handle->vptr == 0x0) { if (pool->recycle) { /* try and pop from pool */ - rmgr_pop_handle(pool, handle); + rmgr_pop_handle(pool, &new_handle); } - if ((*handle)->vptr == 0x0) { + if (new_handle->vptr == 0x0) { /* we need to allocate */ - (*handle)->vptr = hmm_alloc((*handle)->size, - HMM_BO_PRIVATE, 0, NULL, 0); + new_handle->vptr = hmm_alloc(new_handle->size); } else { /* we popped a buffer */ + *handle = new_handle; return; } } + /* Note that new_handle will change to an internally maintained one */ + ia_css_rmgr_refcount_retain_vbuf(&new_handle); + *handle = new_handle; + return; } /* Note that handle will change to an internally maintained one */ ia_css_rmgr_refcount_retain_vbuf(handle); diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c b/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c index 7f4592565af6..c34bfc5f970d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c +++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c @@ -64,7 +64,7 @@ int ia_css_spctrl_load_fw(sp_ID_t sp_id, ia_css_spctrl_cfg *spctrl_cfg) * Data used to be stored separately, because of access alignment constraints, * fix the FW generation instead */ - code_addr = hmm_alloc(spctrl_cfg->code_size, HMM_BO_PRIVATE, 0, NULL, 0); + code_addr = hmm_alloc(spctrl_cfg->code_size); if (code_addr == mmgr_NULL) return -ENOMEM; hmm_store(code_addr, spctrl_cfg->code, spctrl_cfg->code_size); diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 1d605e533e29..da96aaffebc1 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -3061,7 +3061,6 @@ init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, assert(vf_frame); sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->info, idx); - vf_frame->contiguous = false; vf_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, thread_id, &queue_id); @@ -3243,7 +3242,6 @@ init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, in_frame->info.raw_bit_depth = ia_css_pipe_util_pipe_input_format_bpp(pipe); ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0); - in_frame->contiguous = false; in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id); @@ -3271,7 +3269,6 @@ init_out_frameinfo_defaults(struct ia_css_pipe *pipe, assert(out_frame); sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx); - out_frame->contiguous = false; out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id); @@ -3510,8 +3507,7 @@ create_host_acc_pipeline(struct ia_css_pipe *pipe) if (pipe->config.acc_extension) pipe->pipeline.pipe_qos_config = 0; - fw = pipe->vf_stage; - for (i = 0; fw; fw = fw->next) { + for (fw = pipe->vf_stage; fw; fw = fw->next) { err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw); if (err) goto ERR; @@ -7158,7 +7154,6 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe, ia_css_pipeline_clean(me); /* Construct out_frame info */ - out_frame->contiguous = false; out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; if (copy_on_sp(pipe) && @@ -7208,7 +7203,6 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0); if (err) return err; - out_frame->contiguous = false; out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id); diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index dd688f8ab649..e7ef578db8ab 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -369,7 +369,7 @@ void sh_css_unload_firmware(void) ia_css_ptr sh_css_load_blob(const unsigned char *blob, unsigned int size) { - ia_css_ptr target_addr = hmm_alloc(size, HMM_BO_PRIVATE, 0, NULL, 0); + ia_css_ptr target_addr = hmm_alloc(size); /* * this will allocate memory aligned to a DDR word boundary which * is required for the CSS DMA to read the instructions. diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.c b/drivers/staging/media/atomisp/pci/sh_css_mipi.c index 0acf75497ae7..bc6e8598a776 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.c @@ -431,8 +431,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, /* allocate new frame */ err = ia_css_frame_allocate_with_buffer_size( &my_css.mipi_frames[port][i], - my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES, - false); + my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES); if (err) { for (j = 0; j < i; j++) { if (my_css.mipi_frames[port][j]) { diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 09f87c285b8d..0e7c38b2bfe3 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -2072,8 +2072,7 @@ static bool realloc_isp_css_mm_buf( size_t *curr_size, size_t needed_size, bool force, - int *err, - uint16_t mmgr_attribute) + int *err) { s32 id; @@ -2095,11 +2094,7 @@ static bool realloc_isp_css_mm_buf( id = IA_CSS_REFCOUNT_PARAM_BUFFER; ia_css_refcount_decrement(id, *curr_buf); - *curr_buf = ia_css_refcount_increment(id, hmm_alloc(needed_size, - HMM_BO_PRIVATE, 0, - NULL, - mmgr_attribute)); - + *curr_buf = ia_css_refcount_increment(id, hmm_alloc(needed_size)); if (!*curr_buf) { *err = -ENOMEM; *curr_size = 0; @@ -2122,7 +2117,7 @@ static bool reallocate_buffer( IA_CSS_ENTER_PRIVATE("void"); ret = realloc_isp_css_mm_buf(curr_buf, - curr_size, needed_size, force, err, 0); + curr_size, needed_size, force, err); IA_CSS_LEAVE_PRIVATE("ret=%d", ret); return ret; @@ -2161,7 +2156,7 @@ ia_css_isp_3a_statistics_allocate(const struct ia_css_3a_grid_info *grid) me->hmem_size = CEIL_MUL(me->hmem_size, HIVE_ISP_DDR_WORD_BYTES); me->size = me->dmem_size + me->vmem_size * 2 + me->hmem_size; - me->data_ptr = hmm_alloc(me->size, HMM_BO_PRIVATE, 0, NULL, 0); + me->data_ptr = hmm_alloc(me->size); if (me->data_ptr == mmgr_NULL) { kvfree(me); me = NULL; @@ -2211,7 +2206,7 @@ ia_css_metadata_allocate(const struct ia_css_metadata_info *metadata_info) md->info = *metadata_info; md->exp_id = 0; - md->address = hmm_alloc(metadata_info->size, HMM_BO_PRIVATE, 0, NULL, 0); + md->address = hmm_alloc(metadata_info->size); if (md->address == mmgr_NULL) goto error; @@ -2364,13 +2359,13 @@ sh_css_create_isp_params(struct ia_css_stream *stream, ddr_ptrs_size->isp_param = params_size; ddr_ptrs->isp_param = ia_css_refcount_increment(IA_CSS_REFCOUNT_PARAM_BUFFER, - hmm_alloc(params_size, HMM_BO_PRIVATE, 0, NULL, 0)); + hmm_alloc(params_size)); succ &= (ddr_ptrs->isp_param != mmgr_NULL); ddr_ptrs_size->macc_tbl = sizeof(struct ia_css_macc_table); ddr_ptrs->macc_tbl = ia_css_refcount_increment(IA_CSS_REFCOUNT_PARAM_BUFFER, - hmm_alloc(sizeof(struct ia_css_macc_table), HMM_BO_PRIVATE, 0, NULL, 0)); + hmm_alloc(sizeof(struct ia_css_macc_table))); succ &= (ddr_ptrs->macc_tbl != mmgr_NULL); *isp_params_out = params; @@ -2584,14 +2579,10 @@ sh_css_params_init(void) for (i = 0; i < SH_CSS_MAX_STAGES; i++) { xmem_sp_stage_ptrs[p][i] = ia_css_refcount_increment(-1, - hmm_alloc(sizeof(struct sh_css_sp_stage), - HMM_BO_PRIVATE, 0, NULL, - ATOMISP_MAP_FLAG_CLEARED)); + hmm_alloc(sizeof(struct sh_css_sp_stage))); xmem_isp_stage_ptrs[p][i] = ia_css_refcount_increment(-1, - hmm_alloc(sizeof(struct sh_css_sp_stage), - HMM_BO_PRIVATE, 0, NULL, - ATOMISP_MAP_FLAG_CLEARED)); + hmm_alloc(sizeof(struct sh_css_sp_stage))); if ((xmem_sp_stage_ptrs[p][i] == mmgr_NULL) || (xmem_isp_stage_ptrs[p][i] == mmgr_NULL)) { @@ -2599,6 +2590,9 @@ sh_css_params_init(void) IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } + + hmm_set(xmem_sp_stage_ptrs[p][i], 0, sizeof(struct sh_css_sp_stage)); + hmm_set(xmem_isp_stage_ptrs[p][i], 0, sizeof(struct sh_css_sp_stage)); } } @@ -2609,13 +2603,9 @@ sh_css_params_init(void) sp_ddr_ptrs = ia_css_refcount_increment(-1, hmm_alloc(CEIL_MUL(sizeof(struct sh_css_ddr_address_map), - HIVE_ISP_DDR_WORD_BYTES), - HMM_BO_PRIVATE, 0, NULL, - ATOMISP_MAP_FLAG_CLEARED)); + HIVE_ISP_DDR_WORD_BYTES))); xmem_sp_group_ptrs = ia_css_refcount_increment(-1, - hmm_alloc(sizeof(struct sh_css_sp_group), - HMM_BO_PRIVATE, 0, NULL, - ATOMISP_MAP_FLAG_CLEARED)); + hmm_alloc(sizeof(struct sh_css_sp_group))); if ((sp_ddr_ptrs == mmgr_NULL) || (xmem_sp_group_ptrs == mmgr_NULL)) { @@ -2623,6 +2613,9 @@ sh_css_params_init(void) IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } + hmm_set(sp_ddr_ptrs, 0, CEIL_MUL(sizeof(struct sh_css_ddr_address_map), + HIVE_ISP_DDR_WORD_BYTES)); + hmm_set(xmem_sp_group_ptrs, 0, sizeof(struct sh_css_sp_group)); IA_CSS_LEAVE_ERR_PRIVATE(0); return 0; } @@ -2667,7 +2660,7 @@ int ia_css_pipe_set_bci_scaler_lut(struct ia_css_pipe *pipe, } if (!stream_started) { - pipe->scaler_pp_lut = hmm_alloc(sizeof(zoom_table), HMM_BO_PRIVATE, 0, NULL, 0); + pipe->scaler_pp_lut = hmm_alloc(sizeof(zoom_table)); if (pipe->scaler_pp_lut == mmgr_NULL) { ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, @@ -2709,7 +2702,7 @@ int sh_css_params_map_and_store_default_gdc_lut(void) host_lut_store((void *)zoom_table); - default_gdc_lut = hmm_alloc(sizeof(zoom_table), HMM_BO_PRIVATE, 0, NULL, 0); + default_gdc_lut = hmm_alloc(sizeof(zoom_table)); if (default_gdc_lut == mmgr_NULL) return -ENOMEM; @@ -3802,7 +3795,7 @@ static int write_ia_css_isp_parameter_set_info_to_ddr( assert(out); *out = ia_css_refcount_increment(IA_CSS_REFCOUNT_PARAM_SET_POOL, - hmm_alloc(sizeof(struct ia_css_isp_parameter_set_info), HMM_BO_PRIVATE, 0, NULL, 0)); + hmm_alloc(sizeof(struct ia_css_isp_parameter_set_info))); succ = (*out != mmgr_NULL); if (succ) hmm_store(*out, diff --git a/drivers/staging/media/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c index d74ee0ecfb36..df81a9b744c2 100644 --- a/drivers/staging/media/av7110/av7110.c +++ b/drivers/staging/media/av7110/av7110.c @@ -2364,7 +2364,7 @@ static int av7110_attach(struct saa7146_dev* dev, budgetpatch = 0; /* autodetect the presence of budget patch * this only works if saa7146 has been recently - * reset with with MASK_31 to MC1 + * reset with MASK_31 to MC1 * * will wait for VBI_B event (vertical blank at port B) * and will reset GPIO3 after VBI_B is detected. diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 26308bb29adc..2989ebc631cc 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -227,6 +227,7 @@ struct hantro_dev { * * @ctrl_handler: Control handler used to register controls. * @jpeg_quality: User-specified JPEG compression quality. + * @bit_depth: Bit depth of current frame * * @codec_ops: Set of operations related to codec mode. * @postproc: Post-processing context. @@ -252,6 +253,7 @@ struct hantro_ctx { struct v4l2_ctrl_handler ctrl_handler; int jpeg_quality; + int bit_depth; const struct hantro_codec_ops *codec_ops; struct hantro_postproc_ctx postproc; @@ -277,6 +279,7 @@ struct hantro_ctx { * @enc_fmt: Format identifier for encoder registers. * @frmsize: Supported range of frame sizes (only for bitstream formats). * @postprocessed: Indicates if this format needs the post-processor. + * @match_depth: Indicates if format bit depth must match video bit depth */ struct hantro_fmt { char *name; @@ -287,6 +290,7 @@ struct hantro_fmt { enum hantro_enc_fmt enc_fmt; struct v4l2_frmsize_stepwise frmsize; bool postprocessed; + bool match_depth; }; struct hantro_reg { diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index ac232b5f7825..2036f72eeb4a 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -47,12 +47,10 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) { struct vb2_queue *q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); struct vb2_buffer *buf; - int index; - index = vb2_find_timestamp(q, ts, 0); - if (index < 0) + buf = vb2_find_buffer(q, ts); + if (!buf) return 0; - buf = vb2_get_buffer(q, index); return hantro_get_dec_buf_addr(ctx, buf); } @@ -265,7 +263,7 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) if (sps->bit_depth_luma_minus8 != 0) /* Only 8-bit is supported */ return -EINVAL; - } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) { + } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) { const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) @@ -304,18 +302,16 @@ static int hantro_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int hantro_hevc_s_ctrl(struct v4l2_ctrl *ctrl) +static int hantro_vp9_s_ctrl(struct v4l2_ctrl *ctrl) { struct hantro_ctx *ctx; ctx = container_of(ctrl->handler, struct hantro_ctx, ctrl_handler); - vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); - switch (ctrl->id) { - case V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP: - ctx->hevc_dec.ctrls.hevc_hdr_skip_length = ctrl->val; + case V4L2_CID_STATELESS_VP9_FRAME: + ctx->bit_depth = ctrl->p_new.p_vp9_frame->bit_depth; break; default: return -EINVAL; @@ -332,8 +328,8 @@ static const struct v4l2_ctrl_ops hantro_jpeg_ctrl_ops = { .s_ctrl = hantro_jpeg_s_ctrl, }; -static const struct v4l2_ctrl_ops hantro_hevc_ctrl_ops = { - .s_ctrl = hantro_hevc_s_ctrl, +static const struct v4l2_ctrl_ops hantro_vp9_ctrl_ops = { + .s_ctrl = hantro_vp9_s_ctrl, }; #define HANTRO_JPEG_ACTIVE_MARKERS (V4L2_JPEG_ACTIVE_MARKER_APP0 | \ @@ -438,18 +434,18 @@ static const struct hantro_ctrl controls[] = { }, { .codec = HANTRO_HEVC_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, - .min = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, - .max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, - .def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, + .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, + .min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, }, }, { .codec = HANTRO_HEVC_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, - .min = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, - .max = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, - .def = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, + .id = V4L2_CID_STATELESS_HEVC_START_CODE, + .min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, + .max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, + .def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, }, }, { .codec = HANTRO_HEVC_DECODER, @@ -469,40 +465,29 @@ static const struct hantro_ctrl controls[] = { }, { .codec = HANTRO_HEVC_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, + .id = V4L2_CID_STATELESS_HEVC_SPS, .ops = &hantro_ctrl_ops, }, }, { .codec = HANTRO_HEVC_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, + .id = V4L2_CID_STATELESS_HEVC_PPS, }, }, { .codec = HANTRO_HEVC_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS, + .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, }, }, { .codec = HANTRO_HEVC_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, - }, - }, { - .codec = HANTRO_HEVC_DECODER, - .cfg = { - .id = V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP, - .name = "Hantro HEVC slice header skip bytes", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 0x100, - .step = 1, - .ops = &hantro_hevc_ctrl_ops, + .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, }, }, { .codec = HANTRO_VP9_DECODER, .cfg = { .id = V4L2_CID_STATELESS_VP9_FRAME, + .ops = &hantro_vp9_ctrl_ops, }, }, { .codec = HANTRO_VP9_DECODER, @@ -638,6 +623,7 @@ static const struct of_device_id of_hantro_match[] = { { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3568-vepu", .data = &rk3568_vepu_variant, }, { .compatible = "rockchip,rk3568-vpu", .data = &rk3568_vpu_variant, }, #endif #ifdef CONFIG_VIDEO_HANTRO_IMX8M diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c index 5df6f08e26f5..233ecd863d5f 100644 --- a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c +++ b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c @@ -117,6 +117,41 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx) vpu_debug(1, "%s: no chroma!\n", __func__); } +static int compute_header_skip_length(struct hantro_ctx *ctx) +{ + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps; + int skip = 0; + + if (pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT) + /* size of pic_output_flag */ + skip++; + + if (sps->flags & V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE) + /* size of pic_order_cnt_lsb */ + skip += 2; + + if (!(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC)) { + /* size of pic_order_cnt_lsb */ + skip += sps->log2_max_pic_order_cnt_lsb_minus4 + 4; + + /* size of short_term_ref_pic_set_sps_flag */ + skip++; + + if (decode_params->short_term_ref_pic_set_size) + /* size of st_ref_pic_set( num_short_term_ref_pic_sets ) */ + skip += decode_params->short_term_ref_pic_set_size; + else if (sps->num_short_term_ref_pic_sets > 1) + skip += fls(sps->num_short_term_ref_pic_sets - 1); + + skip += decode_params->long_term_ref_pic_set_size; + } + + return skip; +} + static void set_params(struct hantro_ctx *ctx) { const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; @@ -134,7 +169,7 @@ static void set_params(struct hantro_ctx *ctx) hantro_reg_write(vpu, &g2_output_8_bits, 0); - hantro_reg_write(vpu, &g2_hdr_skip_length, ctrls->hevc_hdr_skip_length); + hantro_reg_write(vpu, &g2_hdr_skip_length, compute_header_skip_length(ctx)); min_log2_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3; max_log2_ctb_size = min_log2_cb_size + sps->log2_diff_max_min_luma_coding_block_size; @@ -390,11 +425,10 @@ static int set_ref(struct hantro_ctx *ctx) !!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED)); /* - * Write POC count diff from current pic. For frame decoding only compute - * pic_order_cnt[0] and ignore pic_order_cnt[1] used in field-coding. + * Write POC count diff from current pic. */ for (i = 0; i < decode_params->num_active_dpb_entries && i < ARRAY_SIZE(cur_poc); i++) { - char poc_diff = decode_params->pic_order_cnt_val - dpb[i].pic_order_cnt[0]; + char poc_diff = decode_params->pic_order_cnt_val - dpb[i].pic_order_cnt_val; hantro_reg_write(vpu, &cur_poc[i], poc_diff); } @@ -421,7 +455,7 @@ static int set_ref(struct hantro_ctx *ctx) dpb_longterm_e = 0; for (i = 0; i < decode_params->num_active_dpb_entries && i < (V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1); i++) { - luma_addr = hantro_hevc_get_ref_buf(ctx, dpb[i].pic_order_cnt[0]); + luma_addr = hantro_hevc_get_ref_buf(ctx, dpb[i].pic_order_cnt_val); if (!luma_addr) return -ENOMEM; diff --git a/drivers/staging/media/hantro/hantro_g2_regs.h b/drivers/staging/media/hantro/hantro_g2_regs.h index 877d663a8181..82606783591a 100644 --- a/drivers/staging/media/hantro/hantro_g2_regs.h +++ b/drivers/staging/media/hantro/hantro_g2_regs.h @@ -107,7 +107,7 @@ #define g2_start_code_e G2_DEC_REG(10, 31, 0x1) #define g2_init_qp_old G2_DEC_REG(10, 25, 0x3f) -#define g2_init_qp G2_DEC_REG(10, 24, 0x3f) +#define g2_init_qp G2_DEC_REG(10, 24, 0x7f) #define g2_num_tile_cols_old G2_DEC_REG(10, 20, 0x1f) #define g2_num_tile_cols G2_DEC_REG(10, 19, 0x1f) #define g2_num_tile_rows_old G2_DEC_REG(10, 15, 0x1f) diff --git a/drivers/staging/media/hantro/hantro_g2_vp9_dec.c b/drivers/staging/media/hantro/hantro_g2_vp9_dec.c index 91c21b634fab..6fc4b555517f 100644 --- a/drivers/staging/media/hantro/hantro_g2_vp9_dec.c +++ b/drivers/staging/media/hantro/hantro_g2_vp9_dec.c @@ -111,17 +111,17 @@ get_ref_buf(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) { struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; - int buf_idx; + struct vb2_buffer *buf; /* * If a ref is unused or invalid, address of current destination * buffer is returned. */ - buf_idx = vb2_find_timestamp(cap_q, timestamp, 0); - if (buf_idx < 0) - return vb2_to_hantro_decoded_buf(&dst->vb2_buf); + buf = vb2_find_buffer(cap_q, timestamp); + if (!buf) + buf = &dst->vb2_buf; - return vb2_to_hantro_decoded_buf(vb2_get_buffer(cap_q, buf_idx)); + return vb2_to_hantro_decoded_buf(buf); } static void update_dec_buf_info(struct hantro_decoded_buffer *buf, @@ -515,16 +515,8 @@ static void config_bit_depth(struct hantro_ctx *ctx, const struct v4l2_ctrl_vp9_frame *dec_params) { if (ctx->dev->variant->legacy_regs) { - u8 pp_shift = 0; - hantro_reg_write(ctx->dev, &g2_bit_depth_y, dec_params->bit_depth); hantro_reg_write(ctx->dev, &g2_bit_depth_c, dec_params->bit_depth); - hantro_reg_write(ctx->dev, &g2_rs_out_bit_depth, dec_params->bit_depth); - - if (dec_params->bit_depth > 8) - pp_shift = 16 - dec_params->bit_depth; - - hantro_reg_write(ctx->dev, &g2_pp_pix_shift, pp_shift); hantro_reg_write(ctx->dev, &g2_pix_shift, 0); } else { hantro_reg_write(ctx->dev, &g2_bit_depth_y_minus8, dec_params->bit_depth - 8); diff --git a/drivers/staging/media/hantro/hantro_hevc.c b/drivers/staging/media/hantro/hantro_hevc.c index f86c98e19177..b990bc98164c 100644 --- a/drivers/staging/media/hantro/hantro_hevc.c +++ b/drivers/staging/media/hantro/hantro_hevc.c @@ -33,7 +33,7 @@ void hantro_hevc_ref_init(struct hantro_ctx *ctx) } dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, - int poc) + s32 poc) { struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; int i; @@ -154,6 +154,25 @@ err_free_tile_buffers: return -ENOMEM; } +static int hantro_hevc_validate_sps(struct hantro_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps) +{ + /* + * for tile pixel format check if the width and height match + * hardware constraints + */ + if (ctx->vpu_dst_fmt->fourcc == V4L2_PIX_FMT_NV12_4L4) { + if (ctx->dst_fmt.width != + ALIGN(sps->pic_width_in_luma_samples, ctx->vpu_dst_fmt->frmsize.step_width)) + return -EINVAL; + + if (ctx->dst_fmt.height != + ALIGN(sps->pic_height_in_luma_samples, ctx->vpu_dst_fmt->frmsize.step_height)) + return -EINVAL; + } + + return 0; +} + int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx) { struct hantro_hevc_dec_hw_ctx *hevc_ctx = &ctx->hevc_dec; @@ -163,22 +182,26 @@ int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx) hantro_start_prepare_run(ctx); ctrls->decode_params = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS); if (WARN_ON(!ctrls->decode_params)) return -EINVAL; ctrls->scaling = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX); if (WARN_ON(!ctrls->scaling)) return -EINVAL; ctrls->sps = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SPS); if (WARN_ON(!ctrls->sps)) return -EINVAL; + ret = hantro_hevc_validate_sps(ctx, ctrls->sps); + if (ret) + return ret; + ctrls->pps = - hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_PPS); + hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_PPS); if (WARN_ON(!ctrls->pps)) return -EINVAL; diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 52a960f6fa4a..e83f0c523a30 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -18,9 +18,21 @@ #define DEC_8190_ALIGN_MASK 0x07U #define MB_DIM 16 +#define TILE_MB_DIM 4 #define MB_WIDTH(w) DIV_ROUND_UP(w, MB_DIM) #define MB_HEIGHT(h) DIV_ROUND_UP(h, MB_DIM) +#define FMT_MIN_WIDTH 48 +#define FMT_MIN_HEIGHT 48 +#define FMT_HD_WIDTH 1280 +#define FMT_HD_HEIGHT 720 +#define FMT_FHD_WIDTH 1920 +#define FMT_FHD_HEIGHT 1088 +#define FMT_UHD_WIDTH 3840 +#define FMT_UHD_HEIGHT 2160 +#define FMT_4K_WIDTH 4096 +#define FMT_4K_HEIGHT 2304 + #define NUM_REF_PICTURES (V4L2_HEVC_DPB_ENTRIES_NUM_MAX + 1) struct hantro_dev; @@ -133,7 +145,7 @@ struct hantro_hevc_dec_hw_ctx { struct hantro_aux_buf tile_bsd; struct hantro_aux_buf ref_bufs[NUM_REF_PICTURES]; struct hantro_aux_buf scaling_lists; - int ref_bufs_poc[NUM_REF_PICTURES]; + s32 ref_bufs_poc[NUM_REF_PICTURES]; u32 ref_bufs_used; struct hantro_hevc_dec_ctrls ctrls; unsigned int num_tile_cols_allocated; @@ -306,6 +318,7 @@ extern const struct hantro_variant rk3066_vpu_variant; extern const struct hantro_variant rk3288_vpu_variant; extern const struct hantro_variant rk3328_vpu_variant; extern const struct hantro_variant rk3399_vpu_variant; +extern const struct hantro_variant rk3568_vepu_variant; extern const struct hantro_variant rk3568_vpu_variant; extern const struct hantro_variant sama5d4_vdec_variant; extern const struct hantro_variant sunxi_vpu_variant; @@ -345,9 +358,10 @@ void hantro_hevc_dec_exit(struct hantro_ctx *ctx); int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx); int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx); void hantro_hevc_ref_init(struct hantro_ctx *ctx); -dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, int poc); +dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, s32 poc); int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr); + static inline unsigned short hantro_vp9_num_sbs(unsigned short dimension) { return (dimension + 63) / 64; diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/staging/media/hantro/hantro_postproc.c index ab168c1c0d28..a0928c508434 100644 --- a/drivers/staging/media/hantro/hantro_postproc.c +++ b/drivers/staging/media/hantro/hantro_postproc.c @@ -12,6 +12,7 @@ #include "hantro_hw.h" #include "hantro_g1_regs.h" #include "hantro_g2_regs.h" +#include "hantro_v4l2.h" #define HANTRO_PP_REG_WRITE(vpu, reg_name, val) \ { \ @@ -112,12 +113,14 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *dst_buf; - size_t chroma_offset = ctx->dst_fmt.width * ctx->dst_fmt.height; int down_scale = down_scale_factor(ctx); + size_t chroma_offset; dma_addr_t dst_dma; dst_buf = hantro_get_dst_buf(ctx); dst_dma = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + chroma_offset = ctx->dst_fmt.plane_fmt[0].bytesperline * + ctx->dst_fmt.height; if (down_scale) { hantro_reg_write(vpu, &g2_down_scale_e, 1); @@ -129,6 +132,16 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) hantro_write_addr(vpu, G2_RS_OUT_LUMA_ADDR, dst_dma); hantro_write_addr(vpu, G2_RS_OUT_CHROMA_ADDR, dst_dma + chroma_offset); } + if (ctx->dev->variant->legacy_regs) { + int out_depth = hantro_get_format_depth(ctx->dst_fmt.pixelformat); + u8 pp_shift = 0; + + if (out_depth > 8) + pp_shift = 16 - out_depth; + + hantro_reg_write(ctx->dev, &g2_rs_out_bit_depth, out_depth); + hantro_reg_write(ctx->dev, &g2_pp_pix_shift, pp_shift); + } hantro_reg_write(vpu, &g2_out_rs_e, 1); } @@ -174,18 +187,27 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx) struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q; unsigned int num_buffers = cap_queue->num_buffers; + struct v4l2_pix_format_mplane pix_mp; + const struct hantro_fmt *fmt; unsigned int i, buf_size; - buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage; + /* this should always pick native format */ + fmt = hantro_get_default_fmt(ctx, false); + if (!fmt) + return -EINVAL; + v4l2_fill_pixfmt_mp(&pix_mp, fmt->fourcc, ctx->src_fmt.width, + ctx->src_fmt.height); + + buf_size = pix_mp.plane_fmt[0].sizeimage; if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) - buf_size += hantro_h264_mv_size(ctx->dst_fmt.width, - ctx->dst_fmt.height); + buf_size += hantro_h264_mv_size(pix_mp.width, + pix_mp.height); else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_VP9_FRAME) - buf_size += hantro_vp9_mv_size(ctx->dst_fmt.width, - ctx->dst_fmt.height); + buf_size += hantro_vp9_mv_size(pix_mp.width, + pix_mp.height); else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_HEVC_SLICE) - buf_size += hantro_hevc_mv_size(ctx->dst_fmt.width, - ctx->dst_fmt.height); + buf_size += hantro_hevc_mv_size(pix_mp.width, + pix_mp.height); for (i = 0; i < num_buffers; ++i) { struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i]; diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index 22ad182ee972..2c7a805289e7 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -64,6 +64,42 @@ hantro_get_postproc_formats(const struct hantro_ctx *ctx, return ctx->dev->variant->postproc_fmts; } +int hantro_get_format_depth(u32 fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_P010: + case V4L2_PIX_FMT_P010_4L4: + return 10; + default: + return 8; + } +} + +static bool +hantro_check_depth_match(const struct hantro_ctx *ctx, + const struct hantro_fmt *fmt) +{ + int fmt_depth, ctx_depth = 8; + + if (!fmt->match_depth && !fmt->postprocessed) + return true; + + /* 0 means default depth, which is 8 */ + if (ctx->bit_depth) + ctx_depth = ctx->bit_depth; + + fmt_depth = hantro_get_format_depth(fmt->fourcc); + + /* + * Allow only downconversion for postproc formats for now. + * It may be possible to relax that on some HW. + */ + if (!fmt->match_depth) + return fmt_depth <= ctx_depth; + + return fmt_depth == ctx_depth; +} + static const struct hantro_fmt * hantro_find_format(const struct hantro_ctx *ctx, u32 fourcc) { @@ -82,7 +118,7 @@ hantro_find_format(const struct hantro_ctx *ctx, u32 fourcc) return NULL; } -static const struct hantro_fmt * +const struct hantro_fmt * hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream) { const struct hantro_fmt *formats; @@ -91,7 +127,8 @@ hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream) formats = hantro_get_formats(ctx, &num_fmts); for (i = 0; i < num_fmts; i++) { if (bitstream == (formats[i].codec_mode != - HANTRO_MODE_NONE)) + HANTRO_MODE_NONE) && + hantro_check_depth_match(ctx, &formats[i])) return &formats[i]; } return NULL; @@ -162,11 +199,13 @@ static int vidioc_enum_fmt(struct file *file, void *priv, formats = hantro_get_formats(ctx, &num_fmts); for (i = 0; i < num_fmts; i++) { bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE; + fmt = &formats[i]; if (skip_mode_none == mode_none) continue; + if (!hantro_check_depth_match(ctx, fmt)) + continue; if (j == f->index) { - fmt = &formats[i]; f->pixelformat = fmt->fourcc; return 0; } @@ -182,8 +221,11 @@ static int vidioc_enum_fmt(struct file *file, void *priv, return -EINVAL; formats = hantro_get_postproc_formats(ctx, &num_fmts); for (i = 0; i < num_fmts; i++) { + fmt = &formats[i]; + + if (!hantro_check_depth_match(ctx, fmt)) + continue; if (j == f->index) { - fmt = &formats[i]; f->pixelformat = fmt->fourcc; return 0; } @@ -259,7 +301,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, } else if (ctx->is_encoder) { vpu_fmt = ctx->vpu_dst_fmt; } else { - vpu_fmt = ctx->vpu_src_fmt; + vpu_fmt = fmt; /* * Width/height on the CAPTURE end of a decoder are ignored and * replaced by the OUTPUT ones. diff --git a/drivers/staging/media/hantro/hantro_v4l2.h b/drivers/staging/media/hantro/hantro_v4l2.h index 18bc682c8556..64f6f57e9d7a 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.h +++ b/drivers/staging/media/hantro/hantro_v4l2.h @@ -22,5 +22,8 @@ extern const struct v4l2_ioctl_ops hantro_ioctl_ops; extern const struct vb2_ops hantro_queue_ops; void hantro_reset_fmts(struct hantro_ctx *ctx); +int hantro_get_format_depth(u32 fourcc); +const struct hantro_fmt * +hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream); #endif /* HANTRO_V4L2_H_ */ diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c index 9802508bade2..77f574fdfa77 100644 --- a/drivers/staging/media/hantro/imx8m_vpu_hw.c +++ b/drivers/staging/media/hantro/imx8m_vpu_hw.c @@ -83,6 +83,14 @@ static const struct hantro_fmt imx8m_vpu_postproc_fmts[] = { .fourcc = V4L2_PIX_FMT_YUYV, .codec_mode = HANTRO_MODE_NONE, .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = MB_DIM, + }, }, }; @@ -90,17 +98,25 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = MB_DIM, + }, }, { .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, .codec_mode = HANTRO_MODE_MPEG2_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1920, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -109,11 +125,11 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_VP8_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 3840, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 2160, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -122,11 +138,11 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_H264_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 3840, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 2160, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -137,6 +153,14 @@ static const struct hantro_fmt imx8m_vpu_g2_postproc_fmts[] = { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = MB_DIM, + }, }, }; @@ -144,18 +168,26 @@ static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12_4L4, .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = TILE_MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = TILE_MB_DIM, + }, }, { .fourcc = V4L2_PIX_FMT_HEVC_SLICE, .codec_mode = HANTRO_MODE_HEVC_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 3840, - .step_width = MB_DIM, - .min_height = 48, - .max_height = 2160, - .step_height = MB_DIM, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = TILE_MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = TILE_MB_DIM, }, }, { @@ -163,12 +195,12 @@ static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { .codec_mode = HANTRO_MODE_VP9_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 3840, - .step_width = MB_DIM, - .min_height = 48, - .max_height = 2160, - .step_height = MB_DIM, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = TILE_MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = TILE_MB_DIM, }, }, }; diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c index fc96501f3bc8..8de6fd2e8eef 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -63,6 +63,14 @@ static const struct hantro_fmt rockchip_vpu1_postproc_fmts[] = { .fourcc = V4L2_PIX_FMT_YUYV, .codec_mode = HANTRO_MODE_NONE, .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, }, }; @@ -70,17 +78,25 @@ static const struct hantro_fmt rk3066_vpu_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, }, { .fourcc = V4L2_PIX_FMT_H264_SLICE, .codec_mode = HANTRO_MODE_H264_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1920, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -89,11 +105,11 @@ static const struct hantro_fmt rk3066_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_MPEG2_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1920, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -102,11 +118,11 @@ static const struct hantro_fmt rk3066_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_VP8_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1920, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -116,17 +132,25 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_4K_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_4K_HEIGHT, + .step_height = MB_DIM, + }, }, { .fourcc = V4L2_PIX_FMT_H264_SLICE, .codec_mode = HANTRO_MODE_H264_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 4096, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_4K_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 2304, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_4K_HEIGHT, .step_height = MB_DIM, }, }, @@ -135,11 +159,11 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_MPEG2_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1920, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -148,31 +172,80 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_VP8_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 3840, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 2160, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, .step_height = MB_DIM, }, }, }; -static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { +static const struct hantro_fmt rockchip_vdpu2_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, }, { .fourcc = V4L2_PIX_FMT_H264_SLICE, .codec_mode = HANTRO_MODE_H264_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1920, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, + .codec_mode = HANTRO_MODE_MPEG2_DEC, + .max_depth = 2, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = MB_DIM, + }, + }, +}; + +static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -181,11 +254,11 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_MPEG2_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1920, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -194,11 +267,11 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_VP8_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 3840, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 2160, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, .step_height = MB_DIM, }, }, @@ -417,6 +490,14 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { }, }; +static const struct hantro_codec_ops rk3568_vepu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = rockchip_vpu2_jpeg_enc_run, + .reset = rockchip_vpu2_enc_reset, + .done = rockchip_vpu2_jpeg_enc_done, + }, +}; + /* * VPU variant. */ @@ -439,6 +520,10 @@ static const struct hantro_irq rockchip_vpu2_irqs[] = { { "vdpu", rockchip_vpu2_vdpu_irq }, }; +static const struct hantro_irq rk3568_vepu_irqs[] = { + { "vepu", rockchip_vpu2_vepu_irq }, +}; + static const char * const rk3066_vpu_clk_names[] = { "aclk_vdpu", "hclk_vdpu", "aclk_vepu", "hclk_vepu" @@ -516,8 +601,8 @@ const struct hantro_variant rk3288_vpu_variant = { const struct hantro_variant rk3328_vpu_variant = { .dec_offset = 0x400, - .dec_fmts = rk3399_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .dec_fmts = rockchip_vdpu2_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rockchip_vdpu2_dec_fmts), .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | HANTRO_H264_DECODER, .codec_ops = rk3399_vpu_codec_ops, @@ -528,6 +613,11 @@ const struct hantro_variant rk3328_vpu_variant = { .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names), }; +/* + * H.264 decoding explicitly disabled in RK3399. + * This ensures userspace applications use the Rockchip VDEC core, + * which has better performance. + */ const struct hantro_variant rk3399_vpu_variant = { .enc_offset = 0x0, .enc_fmts = rockchip_vpu_enc_fmts, @@ -545,10 +635,23 @@ const struct hantro_variant rk3399_vpu_variant = { .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) }; +const struct hantro_variant rk3568_vepu_variant = { + .enc_offset = 0x0, + .enc_fmts = rockchip_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts), + .codec = HANTRO_JPEG_ENCODER, + .codec_ops = rk3568_vepu_codec_ops, + .irqs = rk3568_vepu_irqs, + .num_irqs = ARRAY_SIZE(rk3568_vepu_irqs), + .init = rockchip_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) +}; + const struct hantro_variant rk3568_vpu_variant = { .dec_offset = 0x400, - .dec_fmts = rk3399_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .dec_fmts = rockchip_vdpu2_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rockchip_vdpu2_dec_fmts), .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | HANTRO_H264_DECODER, .codec_ops = rk3399_vpu_codec_ops, @@ -564,8 +667,8 @@ const struct hantro_variant px30_vpu_variant = { .enc_fmts = rockchip_vpu_enc_fmts, .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts), .dec_offset = 0x400, - .dec_fmts = rk3399_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .dec_fmts = rockchip_vdpu2_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rockchip_vdpu2_dec_fmts), .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | HANTRO_H264_DECODER, .codec_ops = rk3399_vpu_codec_ops, diff --git a/drivers/staging/media/hantro/sama5d4_vdec_hw.c b/drivers/staging/media/hantro/sama5d4_vdec_hw.c index b2fc1c5613e1..b205e2db5b04 100644 --- a/drivers/staging/media/hantro/sama5d4_vdec_hw.c +++ b/drivers/staging/media/hantro/sama5d4_vdec_hw.c @@ -16,6 +16,14 @@ static const struct hantro_fmt sama5d4_vdec_postproc_fmts[] = { .fourcc = V4L2_PIX_FMT_YUYV, .codec_mode = HANTRO_MODE_NONE, .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_HD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_HD_HEIGHT, + .step_height = MB_DIM, + }, }, }; @@ -23,17 +31,25 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_HD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_HD_HEIGHT, + .step_height = MB_DIM, + }, }, { .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, .codec_mode = HANTRO_MODE_MPEG2_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1280, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_HD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 720, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_HD_HEIGHT, .step_height = MB_DIM, }, }, @@ -42,11 +58,11 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = { .codec_mode = HANTRO_MODE_VP8_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1280, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_HD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 720, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_HD_HEIGHT, .step_height = MB_DIM, }, }, @@ -55,11 +71,11 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = { .codec_mode = HANTRO_MODE_H264_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 1280, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_HD_WIDTH, .step_width = MB_DIM, - .min_height = 48, - .max_height = 720, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_HD_HEIGHT, .step_height = MB_DIM, }, }, diff --git a/drivers/staging/media/hantro/sunxi_vpu_hw.c b/drivers/staging/media/hantro/sunxi_vpu_hw.c index c0edd5856a0c..02ce8b064a8f 100644 --- a/drivers/staging/media/hantro/sunxi_vpu_hw.c +++ b/drivers/staging/media/hantro/sunxi_vpu_hw.c @@ -14,6 +14,27 @@ static const struct hantro_fmt sunxi_vpu_postproc_fmts[] = { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = 32, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = 32, + }, + }, + { + .fourcc = V4L2_PIX_FMT_P010, + .codec_mode = HANTRO_MODE_NONE, + .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = 32, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = 32, + }, }, }; @@ -21,17 +42,39 @@ static const struct hantro_fmt sunxi_vpu_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12_4L4, .codec_mode = HANTRO_MODE_NONE, + .match_depth = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = 32, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = 32, + }, + }, + { + .fourcc = V4L2_PIX_FMT_P010_4L4, + .codec_mode = HANTRO_MODE_NONE, + .match_depth = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = 32, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = 32, + }, }, { .fourcc = V4L2_PIX_FMT_VP9_FRAME, .codec_mode = HANTRO_MODE_VP9_DEC, .max_depth = 2, .frmsize = { - .min_width = 48, - .max_width = 3840, + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, .step_width = 32, - .min_height = 48, - .max_height = 2160, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, .step_height = 32, }, }, diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c index 80b69a9a752c..e6d6ed3b1161 100644 --- a/drivers/staging/media/imx/imx-media-dev-common.c +++ b/drivers/staging/media/imx/imx-media-dev-common.c @@ -235,7 +235,7 @@ static int imx_media_inherit_controls(struct imx_media_dev *imxmd, if (!(spad->flags & MEDIA_PAD_FL_SINK)) continue; - pad = media_entity_remote_pad(spad); + pad = media_pad_remote_pad_first(spad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) continue; diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 94bc866ca28c..294c808b2ebe 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -698,7 +698,7 @@ imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id, (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE))) continue; - pad = media_entity_remote_pad(spad); + pad = media_pad_remote_pad_first(spad); if (!pad) continue; diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 8467a1491048..a0553c24cce4 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -17,18 +17,17 @@ #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/spinlock.h> #include <linux/types.h> #include <media/v4l2-device.h> -#include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> +#include <media/v4l2-ioctl.h> #include <media/v4l2-mc.h> #include <media/v4l2-subdev.h> #include <media/videobuf2-dma-contig.h> -#include <media/imx.h> -#include "imx-media.h" - #define IMX7_CSI_PAD_SINK 0 #define IMX7_CSI_PAD_SRC 1 #define IMX7_CSI_PADS_NUM 2 @@ -159,45 +158,102 @@ #define CSI_CSICR18 0x48 #define CSI_CSICR19 0x4c +#define IMX7_CSI_VIDEO_NAME "imx-capture" +/* In bytes, per queue */ +#define IMX7_CSI_VIDEO_MEM_LIMIT SZ_64M +#define IMX7_CSI_VIDEO_EOF_TIMEOUT 2000 + +#define IMX7_CSI_DEF_MBUS_CODE MEDIA_BUS_FMT_UYVY8_2X8 +#define IMX7_CSI_DEF_PIX_FORMAT V4L2_PIX_FMT_UYVY +#define IMX7_CSI_DEF_PIX_WIDTH 640 +#define IMX7_CSI_DEF_PIX_HEIGHT 480 + enum imx_csi_model { IMX7_CSI_IMX7 = 0, IMX7_CSI_IMX8MQ, }; +struct imx7_csi_pixfmt { + /* the in-memory FourCC pixel format */ + u32 fourcc; + /* + * the set of equivalent media bus codes for the fourcc. + * NOTE! codes pointer is NULL for in-memory-only formats. + */ + const u32 *codes; + int bpp; /* total bpp */ + bool yuv; +}; + +struct imx7_csi_vb2_buffer { + struct vb2_v4l2_buffer vbuf; + struct list_head list; +}; + +static inline struct imx7_csi_vb2_buffer * +to_imx7_csi_vb2_buffer(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + return container_of(vbuf, struct imx7_csi_vb2_buffer, vbuf); +} + +struct imx7_csi_dma_buf { + void *virt; + dma_addr_t phys; + unsigned long len; +}; + struct imx7_csi { struct device *dev; - struct v4l2_subdev sd; - struct v4l2_async_notifier notifier; - struct imx_media_video_dev *vdev; - struct imx_media_dev *imxmd; - struct media_pad pad[IMX7_CSI_PADS_NUM]; - /* lock to protect members below */ - struct mutex lock; - /* lock to protect irq handler when stop streaming */ - spinlock_t irqlock; + /* Resources and locks */ + void __iomem *regbase; + int irq; + struct clk *mclk; + + struct mutex lock; /* Protects is_streaming, format_mbus, cc */ + spinlock_t irqlock; /* Protects last_eof */ + + /* Media and V4L2 device */ + struct media_device mdev; + struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; + struct media_pipeline pipe; struct v4l2_subdev *src_sd; + bool is_csi2; + + /* V4L2 subdev */ + struct v4l2_subdev sd; + struct media_pad pad[IMX7_CSI_PADS_NUM]; struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM]; - const struct imx_media_pixfmt *cc[IMX7_CSI_PADS_NUM]; - struct v4l2_fract frame_interval[IMX7_CSI_PADS_NUM]; + const struct imx7_csi_pixfmt *cc[IMX7_CSI_PADS_NUM]; - void __iomem *regbase; - int irq; - struct clk *mclk; + /* Video device */ + struct video_device *vdev; /* Video device */ + struct media_pad vdev_pad; /* Video device pad */ + + struct v4l2_pix_format vdev_fmt; /* The user format */ + const struct imx7_csi_pixfmt *vdev_cc; + struct v4l2_rect vdev_compose; /* The compose rectangle */ - /* active vb2 buffers to send to video dev sink */ - struct imx_media_buffer *active_vb2_buf[2]; - struct imx_media_dma_buf underrun_buf; + struct mutex vdev_mutex; /* Protect vdev operations */ + struct vb2_queue q; /* The videobuf2 queue */ + struct list_head ready_q; /* List of queued buffers */ + spinlock_t q_lock; /* Protect ready_q */ + + /* Buffers and streaming state */ + struct imx7_csi_vb2_buffer *active_vb2_buf[2]; + struct imx7_csi_dma_buf underrun_buf; + + bool is_streaming; int buf_num; u32 frame_sequence; bool last_eof; - bool is_streaming; - bool is_csi2; - struct completion last_eof_completion; enum imx_csi_model model; @@ -242,7 +298,8 @@ static void imx7_csi_init_default(struct imx7_csi *csi) imx7_csi_reg_write(csi, 0, CSI_CSICR2); imx7_csi_reg_write(csi, BIT_FRMCNT_RST, CSI_CSICR3); - imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(800) | BIT_IMAGE_HEIGHT(600), + imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(IMX7_CSI_DEF_PIX_WIDTH) | + BIT_IMAGE_HEIGHT(IMX7_CSI_DEF_PIX_HEIGHT), CSI_CSIIMAG_PARA); imx7_csi_reg_write(csi, BIT_DMA_REFLASH_RFF, CSI_CSICR3); @@ -336,16 +393,17 @@ static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t phys, imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB1); } +static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi); + static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi) { - struct imx_media_video_dev *vdev = csi->vdev; - struct imx_media_buffer *buf; + struct imx7_csi_vb2_buffer *buf; struct vb2_buffer *vb2_buf; dma_addr_t phys[2]; int i; for (i = 0; i < 2; i++) { - buf = imx_media_capture_device_next_buf(vdev); + buf = imx7_csi_video_next_buf(csi); if (buf) { csi->active_vb2_buf[i] = buf; vb2_buf = &buf->vbuf.vb2_buf; @@ -362,7 +420,7 @@ static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi) static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi, enum vb2_buffer_state return_status) { - struct imx_media_buffer *buf; + struct imx7_csi_vb2_buffer *buf; int i; /* return any remaining active frames with return_status */ @@ -378,13 +436,36 @@ static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi, } } +static void imx7_csi_free_dma_buf(struct imx7_csi *csi, + struct imx7_csi_dma_buf *buf) +{ + if (buf->virt) + dma_free_coherent(csi->dev, buf->len, buf->virt, buf->phys); + + buf->virt = NULL; + buf->phys = 0; +} + +static int imx7_csi_alloc_dma_buf(struct imx7_csi *csi, + struct imx7_csi_dma_buf *buf, int size) +{ + imx7_csi_free_dma_buf(csi, buf); + + buf->len = PAGE_ALIGN(size); + buf->virt = dma_alloc_coherent(csi->dev, buf->len, &buf->phys, + GFP_DMA | GFP_KERNEL); + if (!buf->virt) + return -ENOMEM; + + return 0; +} + static int imx7_csi_dma_setup(struct imx7_csi *csi) { - struct imx_media_video_dev *vdev = csi->vdev; int ret; - ret = imx_media_alloc_dma_buf(csi->dev, &csi->underrun_buf, - vdev->fmt.sizeimage); + ret = imx7_csi_alloc_dma_buf(csi, &csi->underrun_buf, + csi->vdev_fmt.sizeimage); if (ret < 0) { v4l2_warn(&csi->sd, "consider increasing the CMA area\n"); return ret; @@ -403,7 +484,7 @@ static void imx7_csi_dma_cleanup(struct imx7_csi *csi, enum vb2_buffer_state return_status) { imx7_csi_dma_unsetup_vb2_buf(csi, return_status); - imx_media_free_dma_buf(csi->dev, &csi->underrun_buf); + imx7_csi_free_dma_buf(csi, &csi->underrun_buf); } static void imx7_csi_dma_stop(struct imx7_csi *csi) @@ -420,7 +501,7 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi) /* * and then wait for interrupt handler to mark completion. */ - timeout_jiffies = msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT); + timeout_jiffies = msecs_to_jiffies(IMX7_CSI_VIDEO_EOF_TIMEOUT); ret = wait_for_completion_timeout(&csi->last_eof_completion, timeout_jiffies); if (ret == 0) @@ -431,8 +512,7 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi) static void imx7_csi_configure(struct imx7_csi *csi) { - struct imx_media_video_dev *vdev = csi->vdev; - struct v4l2_pix_format *out_pix = &vdev->fmt; + struct v4l2_pix_format *out_pix = &csi->vdev_fmt; int width = out_pix->width; u32 stride = 0; u32 cr3 = BIT_FRMCNT_RST; @@ -631,14 +711,13 @@ static void imx7_csi_error_recovery(struct imx7_csi *csi) static void imx7_csi_vb2_buf_done(struct imx7_csi *csi) { - struct imx_media_video_dev *vdev = csi->vdev; - struct imx_media_buffer *done, *next; + struct imx7_csi_vb2_buffer *done, *next; struct vb2_buffer *vb; dma_addr_t phys; done = csi->active_vb2_buf[csi->buf_num]; if (done) { - done->vbuf.field = vdev->fmt.field; + done->vbuf.field = csi->vdev_fmt.field; done->vbuf.sequence = csi->frame_sequence; vb = &done->vbuf.vb2_buf; vb->timestamp = ktime_get_ns(); @@ -647,7 +726,7 @@ static void imx7_csi_vb2_buf_done(struct imx7_csi *csi) csi->frame_sequence++; /* get next queued buffer */ - next = imx_media_capture_device_next_buf(vdev); + next = imx7_csi_video_next_buf(csi); if (next) { phys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0); csi->active_vb2_buf[csi->buf_num] = next; @@ -718,6 +797,831 @@ static irqreturn_t imx7_csi_irq_handler(int irq, void *data) } /* ----------------------------------------------------------------------------- + * Format Helpers + */ + +#define IMX_BUS_FMTS(fmt...) (const u32[]) {fmt, 0} + +/* + * List of supported pixel formats for the subdevs. Keep V4L2_PIX_FMT_UYVY and + * MEDIA_BUS_FMT_UYVY8_2X8 first to match IMX7_CSI_DEF_PIX_FORMAT and + * IMX7_CSI_DEF_MBUS_CODE. + */ +static const struct imx7_csi_pixfmt pixel_formats[] = { + /*** YUV formats start here ***/ + { + .fourcc = V4L2_PIX_FMT_UYVY, + .codes = IMX_BUS_FMTS( + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16 + ), + .yuv = true, + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .codes = IMX_BUS_FMTS( + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16 + ), + .yuv = true, + .bpp = 16, + }, + /*** raw bayer and grayscale formats start here ***/ + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR8_1X8), + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG8_1X8), + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG8_1X8), + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB8_1X8), + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR10_1X10), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG10_1X10), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG10_1X10), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB10_1X10), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR12_1X12), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG12_1X12), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG12_1X12), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB12_1X12), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR14, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR14_1X14), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG14, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG14_1X14), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG14, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG14_1X14), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB14, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB14_1X14), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_GREY, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y8_1X8), + .bpp = 8, + }, { + .fourcc = V4L2_PIX_FMT_Y10, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y10_1X10), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_Y12, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y12_1X12), + .bpp = 16, + }, { + .fourcc = V4L2_PIX_FMT_Y14, + .codes = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y14_1X14), + .bpp = 16, + }, +}; + +/* + * Search in the pixel_formats[] array for an entry with the given fourcc + * return it. + */ +static const struct imx7_csi_pixfmt *imx7_csi_find_pixel_format(u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) { + const struct imx7_csi_pixfmt *fmt = &pixel_formats[i]; + + if (fmt->fourcc == fourcc) + return fmt; + } + + return NULL; +} + +/* + * Search in the pixel_formats[] array for an entry with the given media + * bus code and return it. + */ +static const struct imx7_csi_pixfmt *imx7_csi_find_mbus_format(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) { + const struct imx7_csi_pixfmt *fmt = &pixel_formats[i]; + unsigned int j; + + if (!fmt->codes) + continue; + + for (j = 0; fmt->codes[j]; j++) { + if (code == fmt->codes[j]) + return fmt; + } + } + + return NULL; +} + +/* + * Enumerate entries in the pixel_formats[] array that match the + * requested search criteria. Return the media-bus code that matches + * the search criteria at the requested match index. + * + * @code: The returned media-bus code that matches the search criteria at + * the requested match index. + * @index: The requested match index. + */ +static int imx7_csi_enum_mbus_formats(u32 *code, u32 index) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) { + const struct imx7_csi_pixfmt *fmt = &pixel_formats[i]; + unsigned int j; + + if (!fmt->codes) + continue; + + for (j = 0; fmt->codes[j]; j++) { + if (index == 0) { + *code = fmt->codes[j]; + return 0; + } + + index--; + } + } + + return -EINVAL; +} + +static int imx7_csi_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, + const struct v4l2_mbus_framefmt *mbus, + const struct imx7_csi_pixfmt *cc) +{ + u32 width; + u32 stride; + + if (!cc) { + cc = imx7_csi_find_mbus_format(mbus->code); + if (!cc) + return -EINVAL; + } + + /* Round up width for minimum burst size */ + width = round_up(mbus->width, 8); + + /* Round up stride for IDMAC line start address alignment */ + stride = round_up((width * cc->bpp) >> 3, 8); + + pix->width = width; + pix->height = mbus->height; + pix->pixelformat = cc->fourcc; + pix->colorspace = mbus->colorspace; + pix->xfer_func = mbus->xfer_func; + pix->ycbcr_enc = mbus->ycbcr_enc; + pix->quantization = mbus->quantization; + pix->field = mbus->field; + pix->bytesperline = stride; + pix->sizeimage = stride * pix->height; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Video Capture Device - IOCTLs + */ + +static int imx7_csi_video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct imx7_csi *csi = video_drvdata(file); + + strscpy(cap->driver, IMX7_CSI_VIDEO_NAME, sizeof(cap->driver)); + strscpy(cap->card, IMX7_CSI_VIDEO_NAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev_name(csi->dev)); + + return 0; +} + +static int imx7_csi_video_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + unsigned int index = f->index; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) { + const struct imx7_csi_pixfmt *fmt = &pixel_formats[i]; + + /* + * If a media bus code is specified, only consider formats that + * match it. + */ + if (f->mbus_code) { + unsigned int j; + + if (!fmt->codes) + continue; + + for (j = 0; fmt->codes[j]; j++) { + if (f->mbus_code == fmt->codes[j]) + break; + } + + if (!fmt->codes[j]) + continue; + } + + if (index == 0) { + f->pixelformat = fmt->fourcc; + return 0; + } + + index--; + } + + return -EINVAL; +} + +static int imx7_csi_video_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + const struct imx7_csi_pixfmt *cc; + + if (fsize->index > 0) + return -EINVAL; + + cc = imx7_csi_find_pixel_format(fsize->pixel_format); + if (!cc) + return -EINVAL; + + /* + * TODO: The constraints are hardware-specific and may depend on the + * pixel format. This should come from the driver using + * imx_media_capture. + */ + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = 1; + fsize->stepwise.max_width = 65535; + fsize->stepwise.min_height = 1; + fsize->stepwise.max_height = 65535; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int imx7_csi_video_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct imx7_csi *csi = video_drvdata(file); + + f->fmt.pix = csi->vdev_fmt; + + return 0; +} + +static const struct imx7_csi_pixfmt * +__imx7_csi_video_try_fmt(struct v4l2_pix_format *pixfmt, + struct v4l2_rect *compose) +{ + struct v4l2_mbus_framefmt fmt_src; + const struct imx7_csi_pixfmt *cc; + + /* + * Find the pixel format, default to the first supported format if not + * found. + */ + cc = imx7_csi_find_pixel_format(pixfmt->pixelformat); + if (!cc) { + pixfmt->pixelformat = IMX7_CSI_DEF_PIX_FORMAT; + cc = imx7_csi_find_pixel_format(pixfmt->pixelformat); + } + + /* Allow IDMAC interweave but enforce field order from source. */ + if (V4L2_FIELD_IS_INTERLACED(pixfmt->field)) { + switch (pixfmt->field) { + case V4L2_FIELD_SEQ_TB: + pixfmt->field = V4L2_FIELD_INTERLACED_TB; + break; + case V4L2_FIELD_SEQ_BT: + pixfmt->field = V4L2_FIELD_INTERLACED_BT; + break; + default: + break; + } + } + + v4l2_fill_mbus_format(&fmt_src, pixfmt, 0); + imx7_csi_mbus_fmt_to_pix_fmt(pixfmt, &fmt_src, cc); + + if (compose) { + compose->width = fmt_src.width; + compose->height = fmt_src.height; + } + + return cc; +} + +static int imx7_csi_video_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + __imx7_csi_video_try_fmt(&f->fmt.pix, NULL); + return 0; +} + +static int imx7_csi_video_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct imx7_csi *csi = video_drvdata(file); + const struct imx7_csi_pixfmt *cc; + + if (vb2_is_busy(&csi->q)) { + dev_err(csi->dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + cc = __imx7_csi_video_try_fmt(&f->fmt.pix, &csi->vdev_compose); + + csi->vdev_cc = cc; + csi->vdev_fmt = f->fmt.pix; + + return 0; +} + +static int imx7_csi_video_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct imx7_csi *csi = video_drvdata(file); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + /* The compose rectangle is fixed to the source format. */ + s->r = csi->vdev_compose; + break; + case V4L2_SEL_TGT_COMPOSE_PADDED: + /* + * The hardware writes with a configurable but fixed DMA burst + * size. If the source format width is not burst size aligned, + * the written frame contains padding to the right. + */ + s->r.left = 0; + s->r.top = 0; + s->r.width = csi->vdev_fmt.width; + s->r.height = csi->vdev_fmt.height; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ioctl_ops imx7_csi_video_ioctl_ops = { + .vidioc_querycap = imx7_csi_video_querycap, + + .vidioc_enum_fmt_vid_cap = imx7_csi_video_enum_fmt_vid_cap, + .vidioc_enum_framesizes = imx7_csi_video_enum_framesizes, + + .vidioc_g_fmt_vid_cap = imx7_csi_video_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = imx7_csi_video_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = imx7_csi_video_s_fmt_vid_cap, + + .vidioc_g_selection = imx7_csi_video_g_selection, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Video Capture Device - Queue Operations + */ + +static int imx7_csi_video_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct imx7_csi *csi = vb2_get_drv_priv(vq); + struct v4l2_pix_format *pix = &csi->vdev_fmt; + unsigned int count = *nbuffers; + + if (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (*nplanes) { + if (*nplanes != 1 || sizes[0] < pix->sizeimage) + return -EINVAL; + count += vq->num_buffers; + } + + count = min_t(__u32, IMX7_CSI_VIDEO_MEM_LIMIT / pix->sizeimage, count); + + if (*nplanes) + *nbuffers = (count < vq->num_buffers) ? 0 : + count - vq->num_buffers; + else + *nbuffers = count; + + *nplanes = 1; + sizes[0] = pix->sizeimage; + + return 0; +} + +static int imx7_csi_video_buf_init(struct vb2_buffer *vb) +{ + struct imx7_csi_vb2_buffer *buf = to_imx7_csi_vb2_buffer(vb); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} + +static int imx7_csi_video_buf_prepare(struct vb2_buffer *vb) +{ + struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_pix_format *pix = &csi->vdev_fmt; + + if (vb2_plane_size(vb, 0) < pix->sizeimage) { + dev_err(csi->dev, + "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), (long)pix->sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, pix->sizeimage); + + return 0; +} + +static void imx7_csi_video_buf_queue(struct vb2_buffer *vb) +{ + struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue); + struct imx7_csi_vb2_buffer *buf = to_imx7_csi_vb2_buffer(vb); + unsigned long flags; + + spin_lock_irqsave(&csi->q_lock, flags); + + list_add_tail(&buf->list, &csi->ready_q); + + spin_unlock_irqrestore(&csi->q_lock, flags); +} + +static int imx7_csi_video_validate_fmt(struct imx7_csi *csi) +{ + struct v4l2_subdev_format fmt_src; + const struct imx7_csi_pixfmt *cc; + int ret; + + /* Retrieve the media bus format on the source subdev. */ + fmt_src.pad = IMX7_CSI_PAD_SRC; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(&csi->sd, pad, get_fmt, NULL, &fmt_src); + if (ret) + return ret; + + /* + * Verify that the media bus size matches the size set on the video + * node. It is sufficient to check the compose rectangle size without + * checking the rounded size from pix_fmt, as the rounded size is + * derived directly from the compose rectangle size, and will thus + * always match if the compose rectangle matches. + */ + if (csi->vdev_compose.width != fmt_src.format.width || + csi->vdev_compose.height != fmt_src.format.height) + return -EPIPE; + + /* + * Verify that the media bus code is compatible with the pixel format + * set on the video node. + */ + cc = imx7_csi_find_mbus_format(fmt_src.format.code); + if (!cc || csi->vdev_cc->yuv != cc->yuv) + return -EPIPE; + + return 0; +} + +static int imx7_csi_video_start_streaming(struct vb2_queue *vq, + unsigned int count) +{ + struct imx7_csi *csi = vb2_get_drv_priv(vq); + struct imx7_csi_vb2_buffer *buf, *tmp; + unsigned long flags; + int ret; + + ret = imx7_csi_video_validate_fmt(csi); + if (ret) { + dev_err(csi->dev, "capture format not valid\n"); + goto err_buffers; + } + + mutex_lock(&csi->mdev.graph_mutex); + + ret = __media_pipeline_start(&csi->sd.entity, &csi->pipe); + if (ret) + goto err_unlock; + + ret = v4l2_subdev_call(&csi->sd, video, s_stream, 1); + if (ret) + goto err_stop; + + mutex_unlock(&csi->mdev.graph_mutex); + + return 0; + +err_stop: + __media_pipeline_stop(&csi->sd.entity); +err_unlock: + mutex_unlock(&csi->mdev.graph_mutex); + dev_err(csi->dev, "pipeline start failed with %d\n", ret); +err_buffers: + spin_lock_irqsave(&csi->q_lock, flags); + list_for_each_entry_safe(buf, tmp, &csi->ready_q, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&csi->q_lock, flags); + return ret; +} + +static void imx7_csi_video_stop_streaming(struct vb2_queue *vq) +{ + struct imx7_csi *csi = vb2_get_drv_priv(vq); + struct imx7_csi_vb2_buffer *frame; + struct imx7_csi_vb2_buffer *tmp; + unsigned long flags; + + mutex_lock(&csi->mdev.graph_mutex); + v4l2_subdev_call(&csi->sd, video, s_stream, 0); + __media_pipeline_stop(&csi->sd.entity); + mutex_unlock(&csi->mdev.graph_mutex); + + /* release all active buffers */ + spin_lock_irqsave(&csi->q_lock, flags); + list_for_each_entry_safe(frame, tmp, &csi->ready_q, list) { + list_del(&frame->list); + vb2_buffer_done(&frame->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&csi->q_lock, flags); +} + +static const struct vb2_ops imx7_csi_video_qops = { + .queue_setup = imx7_csi_video_queue_setup, + .buf_init = imx7_csi_video_buf_init, + .buf_prepare = imx7_csi_video_buf_prepare, + .buf_queue = imx7_csi_video_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = imx7_csi_video_start_streaming, + .stop_streaming = imx7_csi_video_stop_streaming, +}; + +/* ----------------------------------------------------------------------------- + * Video Capture Device - File Operations + */ + +static int imx7_csi_video_open(struct file *file) +{ + struct imx7_csi *csi = video_drvdata(file); + int ret; + + if (mutex_lock_interruptible(&csi->vdev_mutex)) + return -ERESTARTSYS; + + ret = v4l2_fh_open(file); + if (ret) { + dev_err(csi->dev, "v4l2_fh_open failed\n"); + goto out; + } + + ret = v4l2_pipeline_pm_get(&csi->vdev->entity); + if (ret) + v4l2_fh_release(file); + +out: + mutex_unlock(&csi->vdev_mutex); + return ret; +} + +static int imx7_csi_video_release(struct file *file) +{ + struct imx7_csi *csi = video_drvdata(file); + struct vb2_queue *vq = &csi->q; + + mutex_lock(&csi->vdev_mutex); + + if (file->private_data == vq->owner) { + vb2_queue_release(vq); + vq->owner = NULL; + } + + v4l2_pipeline_pm_put(&csi->vdev->entity); + + v4l2_fh_release(file); + mutex_unlock(&csi->vdev_mutex); + return 0; +} + +static const struct v4l2_file_operations imx7_csi_video_fops = { + .owner = THIS_MODULE, + .open = imx7_csi_video_open, + .release = imx7_csi_video_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +/* ----------------------------------------------------------------------------- + * Video Capture Device - Init & Cleanup + */ + +static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi) +{ + struct imx7_csi_vb2_buffer *buf = NULL; + unsigned long flags; + + spin_lock_irqsave(&csi->q_lock, flags); + + /* get next queued buffer */ + if (!list_empty(&csi->ready_q)) { + buf = list_entry(csi->ready_q.next, struct imx7_csi_vb2_buffer, + list); + list_del(&buf->list); + } + + spin_unlock_irqrestore(&csi->q_lock, flags); + + return buf; +} + +static int imx7_csi_video_init_format(struct imx7_csi *csi) +{ + struct v4l2_subdev_format fmt_src = { + .pad = IMX7_CSI_PAD_SRC, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + fmt_src.format.code = IMX7_CSI_DEF_MBUS_CODE; + fmt_src.format.width = IMX7_CSI_DEF_PIX_WIDTH; + fmt_src.format.height = IMX7_CSI_DEF_PIX_HEIGHT; + + imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &fmt_src.format, NULL); + csi->vdev_compose.width = fmt_src.format.width; + csi->vdev_compose.height = fmt_src.format.height; + + csi->vdev_cc = imx7_csi_find_pixel_format(csi->vdev_fmt.pixelformat); + + return 0; +} + +static int imx7_csi_video_register(struct imx7_csi *csi) +{ + struct v4l2_subdev *sd = &csi->sd; + struct v4l2_device *v4l2_dev = sd->v4l2_dev; + struct video_device *vdev = csi->vdev; + int ret; + + vdev->v4l2_dev = v4l2_dev; + + /* Initialize the default format and compose rectangle. */ + ret = imx7_csi_video_init_format(csi); + if (ret < 0) + return ret; + + /* Register the video device. */ + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(csi->dev, "Failed to register video device\n"); + return ret; + } + + dev_info(csi->dev, "Registered %s as /dev/%s\n", vdev->name, + video_device_node_name(vdev)); + + /* Create the link from the CSI subdev to the video device. */ + ret = media_create_pad_link(&sd->entity, IMX7_CSI_PAD_SRC, + &vdev->entity, 0, MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(csi->dev, "failed to create link to device node\n"); + video_unregister_device(vdev); + return ret; + } + + return 0; +} + +static void imx7_csi_video_unregister(struct imx7_csi *csi) +{ + media_entity_cleanup(&csi->vdev->entity); + video_unregister_device(csi->vdev); +} + +static int imx7_csi_video_init(struct imx7_csi *csi) +{ + struct video_device *vdev; + struct vb2_queue *vq; + int ret; + + mutex_init(&csi->vdev_mutex); + INIT_LIST_HEAD(&csi->ready_q); + spin_lock_init(&csi->q_lock); + + /* Allocate and initialize the video device. */ + vdev = video_device_alloc(); + if (!vdev) + return -ENOMEM; + + vdev->fops = &imx7_csi_video_fops; + vdev->ioctl_ops = &imx7_csi_video_ioctl_ops; + vdev->minor = -1; + vdev->release = video_device_release; + vdev->vfl_dir = VFL_DIR_RX; + vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING + | V4L2_CAP_IO_MC; + vdev->lock = &csi->vdev_mutex; + vdev->queue = &csi->q; + + snprintf(vdev->name, sizeof(vdev->name), "%s capture", csi->sd.name); + + video_set_drvdata(vdev, csi); + csi->vdev = vdev; + + /* Initialize the video device pad. */ + csi->vdev_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vdev->entity, 1, &csi->vdev_pad); + if (ret) { + video_device_release(vdev); + return ret; + } + + /* Initialize the vb2 queue. */ + vq = &csi->q; + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->io_modes = VB2_MMAP | VB2_DMABUF; + vq->drv_priv = csi; + vq->buf_struct_size = sizeof(struct imx7_csi_vb2_buffer); + vq->ops = &imx7_csi_video_qops; + vq->mem_ops = &vb2_dma_contig_memops; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->lock = &csi->vdev_mutex; + vq->min_buffers_needed = 2; + vq->dev = csi->dev; + + ret = vb2_queue_init(vq); + if (ret) { + dev_err(csi->dev, "vb2_queue_init failed\n"); + video_device_release(vdev); + return ret; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- * V4L2 Subdev Operations */ @@ -764,36 +1668,48 @@ out_unlock: return ret; } +static struct v4l2_mbus_framefmt * +imx7_csi_get_format(struct imx7_csi *csi, + struct v4l2_subdev_state *sd_state, + unsigned int pad, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); + + return &csi->format_mbus[pad]; +} + static int imx7_csi_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { + const enum v4l2_subdev_format_whence which = + sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; struct imx7_csi *csi = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *mf; - int ret; + const struct imx7_csi_pixfmt *cc; int i; + cc = imx7_csi_find_mbus_format(IMX7_CSI_DEF_MBUS_CODE); + for (i = 0; i < IMX7_CSI_PADS_NUM; i++) { - mf = v4l2_subdev_get_try_format(sd, sd_state, i); + struct v4l2_mbus_framefmt *mf = + imx7_csi_get_format(csi, sd_state, i, which); - ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE, - &csi->cc[i]); - if (ret < 0) - return ret; - } + mf->code = IMX7_CSI_DEF_MBUS_CODE; + mf->width = IMX7_CSI_DEF_PIX_WIDTH; + mf->height = IMX7_CSI_DEF_PIX_HEIGHT; + mf->field = V4L2_FIELD_NONE; - return 0; -} + mf->colorspace = V4L2_COLORSPACE_SRGB; + mf->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mf->colorspace); + mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace); + mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv, + mf->colorspace, mf->ycbcr_enc); -static struct v4l2_mbus_framefmt * -imx7_csi_get_format(struct imx7_csi *csi, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); + csi->cc[i] = cc; + } - return &csi->format_mbus[pad]; + return 0; } static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd, @@ -811,8 +1727,7 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd, switch (code->pad) { case IMX7_CSI_PAD_SINK: - ret = imx_media_enum_mbus_formats(&code->code, code->index, - PIXFMT_SEL_ANY); + ret = imx7_csi_enum_mbus_formats(&code->code, code->index); break; case IMX7_CSI_PAD_SRC: if (code->index != 0) { @@ -857,12 +1772,58 @@ out_unlock: return ret; } +/* + * Default the colorspace in tryfmt to SRGB if set to an unsupported + * colorspace or not initialized. Then set the remaining colorimetry + * parameters based on the colorspace if they are uninitialized. + * + * tryfmt->code must be set on entry. + */ +static void imx7_csi_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt) +{ + const struct imx7_csi_pixfmt *cc; + bool is_rgb = false; + + cc = imx7_csi_find_mbus_format(tryfmt->code); + if (cc && !cc->yuv) + is_rgb = true; + + switch (tryfmt->colorspace) { + case V4L2_COLORSPACE_SMPTE170M: + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_JPEG: + case V4L2_COLORSPACE_SRGB: + case V4L2_COLORSPACE_BT2020: + case V4L2_COLORSPACE_OPRGB: + case V4L2_COLORSPACE_DCI_P3: + case V4L2_COLORSPACE_RAW: + break; + default: + tryfmt->colorspace = V4L2_COLORSPACE_SRGB; + break; + } + + if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT) + tryfmt->xfer_func = + V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace); + + if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + tryfmt->ycbcr_enc = + V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace); + + if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT) + tryfmt->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, + tryfmt->colorspace, + tryfmt->ycbcr_enc); +} + static int imx7_csi_try_fmt(struct imx7_csi *csi, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat, - const struct imx_media_pixfmt **cc) + const struct imx7_csi_pixfmt **cc) { - const struct imx_media_pixfmt *in_cc; + const struct imx7_csi_pixfmt *in_cc; struct v4l2_mbus_framefmt *in_fmt; u32 code; @@ -873,8 +1834,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, switch (sdformat->pad) { case IMX7_CSI_PAD_SRC: - in_cc = imx_media_find_mbus_format(in_fmt->code, - PIXFMT_SEL_ANY); + in_cc = imx7_csi_find_mbus_format(in_fmt->code); sdformat->format.width = in_fmt->width; sdformat->format.height = in_fmt->height; @@ -888,14 +1848,11 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc; break; case IMX7_CSI_PAD_SINK: - *cc = imx_media_find_mbus_format(sdformat->format.code, - PIXFMT_SEL_ANY); + *cc = imx7_csi_find_mbus_format(sdformat->format.code); if (!*cc) { - imx_media_enum_mbus_formats(&code, 0, - PIXFMT_SEL_YUV_RGB); - *cc = imx_media_find_mbus_format(code, - PIXFMT_SEL_YUV_RGB); - sdformat->format.code = (*cc)->codes[0]; + code = IMX7_CSI_DEF_MBUS_CODE; + *cc = imx7_csi_find_mbus_format(code); + sdformat->format.code = code; } if (sdformat->format.field != V4L2_FIELD_INTERLACED) @@ -905,7 +1862,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, return -EINVAL; } - imx_media_try_colorimetry(&sdformat->format, false); + imx7_csi_try_colorimetry(&sdformat->format); return 0; } @@ -915,9 +1872,9 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *sdformat) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); - const struct imx_media_pixfmt *outcc; + const struct imx7_csi_pixfmt *outcc; struct v4l2_mbus_framefmt *outfmt; - const struct imx_media_pixfmt *cc; + const struct imx7_csi_pixfmt *cc; struct v4l2_mbus_framefmt *fmt; struct v4l2_subdev_format format; int ret = 0; @@ -977,9 +1934,8 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd, struct v4l2_subdev_format *sink_fmt) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); - struct imx_media_video_dev *vdev = csi->vdev; - const struct v4l2_pix_format *out_pix = &vdev->fmt; - struct media_pad *pad; + struct media_pad *pad = NULL; + unsigned int i; int ret; if (!csi->src_sd) @@ -1001,7 +1957,17 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd, case MEDIA_ENT_F_VID_MUX: /* The input is the mux, check its input. */ - pad = imx_media_pipeline_pad(&csi->src_sd->entity, 0, 0, true); + for (i = 0; i < csi->src_sd->entity.num_pads; i++) { + struct media_pad *spad = &csi->src_sd->entity.pads[i]; + + if (!(spad->flags & MEDIA_PAD_FL_SINK)) + continue; + + pad = media_pad_remote_pad_first(spad); + if (pad) + break; + } + if (!pad) return -ENODEV; @@ -1017,29 +1983,6 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd, break; } - /* Validate the sink link, ensure the pixel format is supported. */ - switch (out_pix->pixelformat) { - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_GREY: - case V4L2_PIX_FMT_Y10: - case V4L2_PIX_FMT_Y12: - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_SBGGR16: - case V4L2_PIX_FMT_SGBRG16: - case V4L2_PIX_FMT_SGRBG16: - case V4L2_PIX_FMT_SRGGB16: - break; - - default: - dev_dbg(csi->dev, "Invalid capture pixel format 0x%08x\n", - out_pix->pixelformat); - return -EINVAL; - } - return 0; } @@ -1047,31 +1990,27 @@ static int imx7_csi_registered(struct v4l2_subdev *sd) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); int ret; - int i; - for (i = 0; i < IMX7_CSI_PADS_NUM; i++) { - /* set a default mbus format */ - ret = imx_media_init_mbus_fmt(&csi->format_mbus[i], - 800, 600, 0, V4L2_FIELD_NONE, - &csi->cc[i]); - if (ret < 0) - return ret; + ret = imx7_csi_video_init(csi); + if (ret) + return ret; - /* init default frame interval */ - csi->frame_interval[i].numerator = 1; - csi->frame_interval[i].denominator = 30; - } + ret = imx7_csi_video_register(csi); + if (ret) + return ret; - csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd, - IMX7_CSI_PAD_SRC, false); - if (IS_ERR(csi->vdev)) - return PTR_ERR(csi->vdev); + ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); + if (ret) + goto err_unreg; - ret = imx_media_capture_device_register(csi->vdev, - MEDIA_LNK_FL_IMMUTABLE); + ret = media_device_register(&csi->mdev); if (ret) - imx_media_capture_device_remove(csi->vdev); + goto err_unreg; + + return 0; +err_unreg: + imx7_csi_video_unregister(csi); return ret; } @@ -1079,8 +2018,7 @@ static void imx7_csi_unregistered(struct v4l2_subdev *sd) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); - imx_media_capture_device_unregister(csi->vdev); - imx_media_capture_device_remove(csi->vdev); + imx7_csi_video_unregister(csi); } static const struct v4l2_subdev_video_ops imx7_csi_video_ops = { @@ -1125,21 +2063,22 @@ static int imx7_csi_notify_bound(struct v4l2_async_notifier *notifier, struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier); struct media_pad *sink = &csi->sd.entity.pads[IMX7_CSI_PAD_SINK]; - /* - * If the subdev is a video mux, it must be one of the CSI - * muxes. Mark it as such via its group id. - */ - if (sd->entity.function == MEDIA_ENT_F_VID_MUX) - sd->grp_id = IMX_MEDIA_GRP_ID_CSI_MUX; - csi->src_sd = sd; return v4l2_create_fwnode_links_to_pad(sd, sink, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); } +static int imx7_csi_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier); + + return v4l2_device_register_subdev_nodes(&csi->v4l2_dev); +} + static const struct v4l2_async_notifier_operations imx7_csi_notify_ops = { .bound = imx7_csi_notify_bound, + .complete = imx7_csi_notify_complete, }; static int imx7_csi_async_register(struct imx7_csi *csi) @@ -1168,48 +2107,133 @@ static int imx7_csi_async_register(struct imx7_csi *csi) csi->notifier.ops = &imx7_csi_notify_ops; - ret = v4l2_async_subdev_nf_register(&csi->sd, &csi->notifier); + ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); if (ret) return ret; - return v4l2_async_register_subdev(&csi->sd); + return 0; +} + +static void imx7_csi_media_cleanup(struct imx7_csi *csi) +{ + v4l2_device_unregister(&csi->v4l2_dev); + media_device_unregister(&csi->mdev); + media_device_cleanup(&csi->mdev); +} + +static const struct media_device_ops imx7_csi_media_ops = { + .link_notify = v4l2_pipeline_link_notify, +}; + +static int imx7_csi_media_dev_init(struct imx7_csi *csi) +{ + int ret; + + strscpy(csi->mdev.model, "imx-media", sizeof(csi->mdev.model)); + csi->mdev.ops = &imx7_csi_media_ops; + csi->mdev.dev = csi->dev; + + csi->v4l2_dev.mdev = &csi->mdev; + strscpy(csi->v4l2_dev.name, "imx-media", + sizeof(csi->v4l2_dev.name)); + snprintf(csi->mdev.bus_info, sizeof(csi->mdev.bus_info), + "platform:%s", dev_name(csi->mdev.dev)); + + media_device_init(&csi->mdev); + + ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + if (ret < 0) { + v4l2_err(&csi->v4l2_dev, + "Failed to register v4l2_device: %d\n", ret); + goto cleanup; + } + + return 0; + +cleanup: + media_device_cleanup(&csi->mdev); + + return ret; +} + +static int imx7_csi_media_init(struct imx7_csi *csi) +{ + unsigned int i; + int ret; + + /* add media device */ + ret = imx7_csi_media_dev_init(csi); + if (ret) + return ret; + + v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops); + v4l2_set_subdevdata(&csi->sd, csi); + csi->sd.internal_ops = &imx7_csi_internal_ops; + csi->sd.entity.ops = &imx7_csi_entity_ops; + csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + csi->sd.dev = csi->dev; + csi->sd.owner = THIS_MODULE; + csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(csi->sd.name, sizeof(csi->sd.name), "csi"); + + for (i = 0; i < IMX7_CSI_PADS_NUM; i++) + csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM, + csi->pad); + if (ret) + goto error; + + ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd); + if (ret) + goto error; + + return 0; + +error: + imx7_csi_media_cleanup(csi); + return ret; } static int imx7_csi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - struct imx_media_dev *imxmd; struct imx7_csi *csi; - int i, ret; + int ret; csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); if (!csi) return -ENOMEM; csi->dev = dev; + platform_set_drvdata(pdev, csi); + + spin_lock_init(&csi->irqlock); + mutex_init(&csi->lock); + /* Acquire resources and install interrupt handler. */ csi->mclk = devm_clk_get(&pdev->dev, "mclk"); if (IS_ERR(csi->mclk)) { ret = PTR_ERR(csi->mclk); dev_err(dev, "Failed to get mclk: %d", ret); - return ret; + goto destroy_mutex; } csi->irq = platform_get_irq(pdev, 0); - if (csi->irq < 0) - return csi->irq; + if (csi->irq < 0) { + ret = csi->irq; + goto destroy_mutex; + } csi->regbase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(csi->regbase)) - return PTR_ERR(csi->regbase); + if (IS_ERR(csi->regbase)) { + ret = PTR_ERR(csi->regbase); + goto destroy_mutex; + } csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev); - spin_lock_init(&csi->irqlock); - mutex_init(&csi->lock); - - /* install interrupt handler */ ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi", (void *)csi); if (ret < 0) { @@ -1217,42 +2241,15 @@ static int imx7_csi_probe(struct platform_device *pdev) goto destroy_mutex; } - /* add media device */ - imxmd = imx_media_dev_init(dev, NULL); - if (IS_ERR(imxmd)) { - ret = PTR_ERR(imxmd); + /* Initialize all the media device infrastructure. */ + ret = imx7_csi_media_init(csi); + if (ret) goto destroy_mutex; - } - platform_set_drvdata(pdev, &csi->sd); - - ret = imx_media_of_add_csi(imxmd, node); - if (ret < 0 && ret != -ENODEV && ret != -EEXIST) - goto cleanup; - - ret = imx_media_dev_notifier_register(imxmd, NULL); - if (ret < 0) - goto cleanup; - - csi->imxmd = imxmd; - v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops); - v4l2_set_subdevdata(&csi->sd, csi); - csi->sd.internal_ops = &imx7_csi_internal_ops; - csi->sd.entity.ops = &imx7_csi_entity_ops; - csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; - csi->sd.dev = &pdev->dev; - csi->sd.owner = THIS_MODULE; - csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI; - snprintf(csi->sd.name, sizeof(csi->sd.name), "csi"); - - for (i = 0; i < IMX7_CSI_PADS_NUM; i++) - csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ? - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM, - csi->pad); - if (ret < 0) - goto cleanup; + /* Set the default mbus formats. */ + ret = imx7_csi_init_cfg(&csi->sd, NULL); + if (ret) + goto media_cleanup; ret = imx7_csi_async_register(csi); if (ret) @@ -1263,13 +2260,8 @@ static int imx7_csi_probe(struct platform_device *pdev) subdev_notifier_cleanup: v4l2_async_nf_unregister(&csi->notifier); v4l2_async_nf_cleanup(&csi->notifier); - -cleanup: - v4l2_async_nf_unregister(&imxmd->notifier); - v4l2_async_nf_cleanup(&imxmd->notifier); - v4l2_device_unregister(&imxmd->v4l2_dev); - media_device_unregister(&imxmd->md); - media_device_cleanup(&imxmd->md); +media_cleanup: + imx7_csi_media_cleanup(csi); destroy_mutex: mutex_destroy(&csi->lock); @@ -1279,20 +2271,13 @@ destroy_mutex: static int imx7_csi_remove(struct platform_device *pdev) { - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct imx7_csi *csi = v4l2_get_subdevdata(sd); - struct imx_media_dev *imxmd = csi->imxmd; - - v4l2_async_nf_unregister(&imxmd->notifier); - v4l2_async_nf_cleanup(&imxmd->notifier); + struct imx7_csi *csi = platform_get_drvdata(pdev); - media_device_unregister(&imxmd->md); - v4l2_device_unregister(&imxmd->v4l2_dev); - media_device_cleanup(&imxmd->md); + imx7_csi_media_cleanup(csi); v4l2_async_nf_unregister(&csi->notifier); v4l2_async_nf_cleanup(&csi->notifier); - v4l2_async_unregister_subdev(sd); + v4l2_async_unregister_subdev(&csi->sd); mutex_destroy(&csi->lock); diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index 68588e9dab0b..28aacda0f5a7 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -395,7 +395,7 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe, if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -464,7 +464,7 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe, if (!(pad->flags & MEDIA_PAD_FL_SINK)) break; - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; @@ -553,7 +553,7 @@ static int iss_pipeline_is_last(struct media_entity *me) pipe = to_iss_pipeline(me); if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED) return 0; - pad = media_entity_remote_pad(&pipe->output->pad); + pad = media_pad_remote_pad_first(&pipe->output->pad); return pad->entity == me; } diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index 124ab2f44fbf..04ce0e7eb557 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -538,7 +538,7 @@ static int csi2_configure(struct iss_csi2_device *csi2) if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) return -EBUSY; - pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); + pad = media_pad_remote_pad_first(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); pdata = sensor->host_priv; diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index d0da083deed5..9512cd3314f2 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -190,7 +190,7 @@ iss_video_remote_subdev(struct iss_video *video, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_pad_remote_pad_first(&video->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 2992fb87cf72..4af5a831bde0 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -109,7 +109,7 @@ struct rkvdec_h264_run { const struct v4l2_ctrl_h264_sps *sps; const struct v4l2_ctrl_h264_pps *pps; const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; - int ref_buf_idx[V4L2_H264_NUM_DPB_ENTRIES]; + struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES]; }; struct rkvdec_h264_ctx { @@ -742,17 +742,16 @@ static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb; struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; - int buf_idx = -1; + struct vb2_buffer *buf = NULL; if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { - buf_idx = vb2_find_timestamp(cap_q, - dpb[i].reference_ts, 0); - if (buf_idx < 0) + buf = vb2_find_buffer(cap_q, dpb[i].reference_ts); + if (!buf) pr_debug("No buffer for reference_ts %llu", dpb[i].reference_ts); } - run->ref_buf_idx[i] = buf_idx; + run->ref_buf[i] = buf; } } @@ -805,7 +804,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb))) continue; - dpb_valid = run->ref_buf_idx[ref->index] >= 0; + dpb_valid = run->ref_buf[ref->index] != NULL; bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF; set_ps_field(hw_rps, DPB_INFO(i, j), @@ -881,24 +880,6 @@ static const u32 poc_reg_tbl_bottom_field[16] = { RKVDEC_REG_H264_POC_REFER2(1) }; -static struct vb2_buffer * -get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run, - unsigned int dpb_idx) -{ - struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; - struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; - int buf_idx = run->ref_buf_idx[dpb_idx]; - - /* - * If a DPB entry is unused or invalid, address of current destination - * buffer is returned. - */ - if (buf_idx < 0) - return &run->base.bufs.dst->vb2_buf; - - return vb2_get_buffer(cap_q, buf_idx); -} - static void config_registers(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run) { @@ -971,8 +952,14 @@ static void config_registers(struct rkvdec_ctx *ctx, /* config ref pic address & poc */ for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { - struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i); - + struct vb2_buffer *vb_buf = run->ref_buf[i]; + + /* + * If a DPB entry is unused or invalid, address of current destination + * buffer is returned. + */ + if (!vb_buf) + vb_buf = &dst_buf->vb2_buf; refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0); if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) diff --git a/drivers/staging/media/rkvdec/rkvdec-vp9.c b/drivers/staging/media/rkvdec/rkvdec-vp9.c index 311a12656072..d8c1c0db15c7 100644 --- a/drivers/staging/media/rkvdec/rkvdec-vp9.c +++ b/drivers/staging/media/rkvdec/rkvdec-vp9.c @@ -383,17 +383,17 @@ get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp) { struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; - int buf_idx; + struct vb2_buffer *buf; /* * If a ref is unused or invalid, address of current destination * buffer is returned. */ - buf_idx = vb2_find_timestamp(cap_q, timestamp, 0); - if (buf_idx < 0) - return vb2_to_rkvdec_decoded_buf(&dst->vb2_buf); + buf = vb2_find_buffer(cap_q, timestamp); + if (!buf) + buf = &dst->vb2_buf; - return vb2_to_rkvdec_decoded_buf(vb2_get_buffer(cap_q, buf_idx)); + return vb2_to_rkvdec_decoded_buf(buf); } static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf) @@ -1015,7 +1015,6 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) vp9_ctx->priv_tbl.size = sizeof(*priv_tbl); vp9_ctx->priv_tbl.cpu = priv_tbl; - memset(priv_tbl, 0, sizeof(*priv_tbl)); count_tbl = dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE, &vp9_ctx->count_tbl.dma, GFP_KERNEL); @@ -1026,7 +1025,6 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) vp9_ctx->count_tbl.size = RKVDEC_VP9_COUNT_SIZE; vp9_ctx->count_tbl.cpu = count_tbl; - memset(count_tbl, 0, sizeof(*count_tbl)); rkvdec_init_v4l2_vp9_count_tbl(ctx); return 0; diff --git a/drivers/media/usb/stkwebcam/Kconfig b/drivers/staging/media/stkwebcam/Kconfig index d94d023f1aa0..4450403dff41 100644 --- a/drivers/media/usb/stkwebcam/Kconfig +++ b/drivers/staging/media/stkwebcam/Kconfig @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only -config USB_STKWEBCAM - tristate "USB Syntek DC1125 Camera support" +config VIDEO_STKWEBCAM + tristate "USB Syntek DC1125 Camera support (DEPRECATED)" depends on VIDEO_DEV + depends on USB help Say Y here if you want to use this type of camera. Supported devices are typically found in some Asus laptops, @@ -9,6 +10,9 @@ config USB_STKWEBCAM may be supported by the stk11xx driver, from which this is derived, see <http://sourceforge.net/projects/syntekdriver/> + This driver is deprecated and is scheduled for removal by + the end of 2022. See the TODO file for more information. + To compile this driver as a module, choose M here: the module will be called stkwebcam. diff --git a/drivers/media/usb/stkwebcam/Makefile b/drivers/staging/media/stkwebcam/Makefile index daa9ae6d48c2..17ad7b6f43d0 100644 --- a/drivers/media/usb/stkwebcam/Makefile +++ b/drivers/staging/media/stkwebcam/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only stkwebcam-objs := stk-webcam.o stk-sensor.o -obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o +obj-$(CONFIG_VIDEO_STKWEBCAM) += stkwebcam.o diff --git a/drivers/staging/media/stkwebcam/TODO b/drivers/staging/media/stkwebcam/TODO new file mode 100644 index 000000000000..735304a72729 --- /dev/null +++ b/drivers/staging/media/stkwebcam/TODO @@ -0,0 +1,12 @@ +This is a very old driver for very old hardware (specifically +laptops that use this sensor). In addition according to reports +the picture quality is quite bad. + +This is also one of the few drivers still not using the vb2 +framework (or even the old videobuf framework!), so this driver +is now deprecated with the intent of removing it altogether by +the end of 2022. + +In order to keep this driver it has to be converted to vb2. +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/media/usb/stkwebcam/stk-sensor.c b/drivers/staging/media/stkwebcam/stk-sensor.c index 94aa6a27f934..94aa6a27f934 100644 --- a/drivers/media/usb/stkwebcam/stk-sensor.c +++ b/drivers/staging/media/stkwebcam/stk-sensor.c diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/staging/media/stkwebcam/stk-webcam.c index 787edb3d47c2..787edb3d47c2 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/staging/media/stkwebcam/stk-webcam.c diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/staging/media/stkwebcam/stk-webcam.h index 136decffe9ce..136decffe9ce 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/staging/media/stkwebcam/stk-webcam.h diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 68b3dcdb5df3..960a0130cd62 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -42,7 +42,7 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl) if (sps->bit_depth_luma_minus8 != 0) /* Only 8-bit is supported */ return -EINVAL; - } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) { + } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) { const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl); @@ -164,42 +164,54 @@ static const struct cedrus_control cedrus_controls[] = { }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, + .id = V4L2_CID_STATELESS_HEVC_SPS, .ops = &cedrus_ctrl_ops, }, .codec = CEDRUS_CODEC_H265, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, + .id = V4L2_CID_STATELESS_HEVC_PPS, }, .codec = CEDRUS_CODEC_H265, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, + .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, + /* The driver can only handle 1 entry per slice for now */ + .dims = { 1 }, }, .codec = CEDRUS_CODEC_H265, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX, + .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, }, .codec = CEDRUS_CODEC_H265, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, - .max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, - .def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, + .id = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS, + /* maximum 256 entry point offsets per slice */ + .dims = { 256 }, + .max = 0xffffffff, + .step = 1, }, .codec = CEDRUS_CODEC_H265, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, - .max = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, - .def = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, + .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, + .max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, + .def = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, + }, + .codec = CEDRUS_CODEC_H265, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_HEVC_START_CODE, + .max = V4L2_STATELESS_HEVC_START_CODE_NONE, + .def = V4L2_STATELESS_HEVC_START_CODE_NONE, }, .codec = CEDRUS_CODEC_H265, }, @@ -211,7 +223,7 @@ static const struct cedrus_control cedrus_controls[] = { }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS, + .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, }, .codec = CEDRUS_CODEC_H265, }, @@ -230,6 +242,17 @@ void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id) return NULL; } +u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id) +{ + unsigned int i; + + for (i = 0; ctx->ctrls[i]; i++) + if (ctx->ctrls[i]->id == id) + return ctx->ctrls[i]->elems; + + return 0; +} + static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) { struct v4l2_ctrl_handler *hdl = &ctx->hdl; @@ -240,7 +263,8 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT); if (hdl->error) { v4l2_err(&dev->v4l2_dev, - "Failed to initialize control handler\n"); + "Failed to initialize control handler: %d\n", + hdl->error); return hdl->error; } @@ -255,7 +279,9 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) NULL); if (hdl->error) { v4l2_err(&dev->v4l2_dev, - "Failed to create new custom control\n"); + "Failed to create %s control: %d\n", + v4l2_ctrl_get_name(cedrus_controls[i].cfg.id), + hdl->error); v4l2_ctrl_handler_free(hdl); kfree(ctx->ctrls); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 3bc094eb497f..084193019350 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -81,6 +81,8 @@ struct cedrus_h265_run { const struct v4l2_ctrl_hevc_slice_params *slice_params; const struct v4l2_ctrl_hevc_decode_params *decode_params; const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; + const u32 *entry_points; + u32 entry_points_count; }; struct cedrus_vp8_run { @@ -146,6 +148,8 @@ struct cedrus_ctx { ssize_t mv_col_buf_unit_size; void *neighbor_info_buf; dma_addr_t neighbor_info_buf_addr; + void *entry_points_buf; + dma_addr_t entry_points_buf_addr; } h265; struct { unsigned int last_frame_p_type; @@ -162,7 +166,7 @@ struct cedrus_dec_ops { void (*irq_clear)(struct cedrus_ctx *ctx); void (*irq_disable)(struct cedrus_ctx *ctx); enum cedrus_irq_status (*irq_status)(struct cedrus_ctx *ctx); - void (*setup)(struct cedrus_ctx *ctx, struct cedrus_run *run); + int (*setup)(struct cedrus_ctx *ctx, struct cedrus_run *run); int (*start)(struct cedrus_ctx *ctx); void (*stop)(struct cedrus_ctx *ctx); void (*trigger)(struct cedrus_ctx *ctx); @@ -261,5 +265,6 @@ vb2_to_cedrus_buffer(const struct vb2_buffer *p) } void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id); +u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id); #endif diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 9c7200299465..3b6aa78a2985 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -28,6 +28,7 @@ void cedrus_device_run(void *priv) struct cedrus_dev *dev = ctx->dev; struct cedrus_run run = {}; struct media_request *src_req; + int error; run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -65,15 +66,19 @@ void cedrus_device_run(void *priv) case V4L2_PIX_FMT_HEVC_SLICE: run.h265.sps = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_HEVC_SPS); + V4L2_CID_STATELESS_HEVC_SPS); run.h265.pps = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_HEVC_PPS); + V4L2_CID_STATELESS_HEVC_PPS); run.h265.slice_params = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); + V4L2_CID_STATELESS_HEVC_SLICE_PARAMS); run.h265.decode_params = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS); + V4L2_CID_STATELESS_HEVC_DECODE_PARAMS); run.h265.scaling_matrix = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX); + V4L2_CID_STATELESS_HEVC_SCALING_MATRIX); + run.h265.entry_points = cedrus_find_control_data(ctx, + V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS); + run.h265.entry_points_count = cedrus_get_num_of_controls(ctx, + V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS); break; case V4L2_PIX_FMT_VP8_FRAME: @@ -89,16 +94,26 @@ void cedrus_device_run(void *priv) cedrus_dst_format_set(dev, &ctx->dst_fmt); - dev->dec_ops[ctx->current_codec]->setup(ctx, &run); + error = dev->dec_ops[ctx->current_codec]->setup(ctx, &run); + if (error) + v4l2_err(&ctx->dev->v4l2_dev, + "Failed to setup decoding job: %d\n", error); /* Complete request(s) controls if needed. */ if (src_req) v4l2_ctrl_request_complete(src_req, &ctx->hdl); - dev->dec_ops[ctx->current_codec]->trigger(ctx); - - /* Start the watchdog timer. */ - schedule_delayed_work(&dev->watchdog_work, - msecs_to_jiffies(2000)); + /* Trigger decoding if setup went well, bail out otherwise. */ + if (!error) { + dev->dec_ops[ctx->current_codec]->trigger(ctx); + + /* Start the watchdog timer. */ + schedule_delayed_work(&dev->watchdog_work, + msecs_to_jiffies(2000)); + } else { + v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, + ctx->fh.m2m_ctx, + VB2_BUF_STATE_ERROR); + } } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index d8fb93035470..c345e67ba9bc 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -493,8 +493,7 @@ static void cedrus_h264_irq_disable(struct cedrus_ctx *ctx) reg & ~VE_H264_CTRL_INT_MASK); } -static void cedrus_h264_setup(struct cedrus_ctx *ctx, - struct cedrus_run *run) +static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { struct cedrus_dev *dev = ctx->dev; @@ -510,6 +509,8 @@ static void cedrus_h264_setup(struct cedrus_ctx *ctx, cedrus_write_frame_list(ctx, run); cedrus_set_params(ctx, run); + + return 0; } static int cedrus_h264_start(struct cedrus_ctx *ctx) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 44f385be9f6c..687f87598f78 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -143,10 +143,13 @@ static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx, for (i = 0; i < num_active_dpb_entries; i++) { int buffer_index = vb2_find_timestamp(vq, dpb[i].timestamp, 0); u32 pic_order_cnt[2] = { - dpb[i].pic_order_cnt[0], - dpb[i].pic_order_cnt[1] + dpb[i].pic_order_cnt_val, + dpb[i].pic_order_cnt_val }; + if (buffer_index < 0) + continue; + cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic, pic_order_cnt, buffer_index); @@ -301,8 +304,91 @@ static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx, } } -static void cedrus_h265_setup(struct cedrus_ctx *ctx, - struct cedrus_run *run) +static int cedrus_h265_is_low_delay(struct cedrus_run *run) +{ + const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_hevc_dpb_entry *dpb; + s32 poc; + int i; + + slice_params = run->h265.slice_params; + poc = run->h265.decode_params->pic_order_cnt_val; + dpb = run->h265.decode_params->dpb; + + for (i = 0; i < slice_params->num_ref_idx_l0_active_minus1 + 1; i++) + if (dpb[slice_params->ref_idx_l0[i]].pic_order_cnt_val > poc) + return 1; + + if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_B) + return 0; + + for (i = 0; i < slice_params->num_ref_idx_l1_active_minus1 + 1; i++) + if (dpb[slice_params->ref_idx_l1[i]].pic_order_cnt_val > poc) + return 1; + + return 0; +} + +static void cedrus_h265_write_tiles(struct cedrus_ctx *ctx, + struct cedrus_run *run, + unsigned int ctb_addr_x, + unsigned int ctb_addr_y) +{ + const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_ctrl_hevc_pps *pps; + struct cedrus_dev *dev = ctx->dev; + const u32 *entry_points; + u32 *entry_points_buf; + int i, x, tx, y, ty; + + pps = run->h265.pps; + slice_params = run->h265.slice_params; + entry_points = run->h265.entry_points; + entry_points_buf = ctx->codec.h265.entry_points_buf; + + for (x = 0, tx = 0; tx < pps->num_tile_columns_minus1 + 1; tx++) { + if (x + pps->column_width_minus1[tx] + 1 > ctb_addr_x) + break; + + x += pps->column_width_minus1[tx] + 1; + } + + for (y = 0, ty = 0; ty < pps->num_tile_rows_minus1 + 1; ty++) { + if (y + pps->row_height_minus1[ty] + 1 > ctb_addr_y) + break; + + y += pps->row_height_minus1[ty] + 1; + } + + cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, (y << 16) | (x << 0)); + cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, + ((y + pps->row_height_minus1[ty]) << 16) | + ((x + pps->column_width_minus1[tx]) << 0)); + + if (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) { + for (i = 0; i < slice_params->num_entry_point_offsets; i++) + entry_points_buf[i] = entry_points[i]; + } else { + for (i = 0; i < slice_params->num_entry_point_offsets; i++) { + if (tx + 1 >= pps->num_tile_columns_minus1 + 1) { + x = 0; + tx = 0; + y += pps->row_height_minus1[ty++] + 1; + } else { + x += pps->column_width_minus1[tx++] + 1; + } + + entry_points_buf[i * 4 + 0] = entry_points[i]; + entry_points_buf[i * 4 + 1] = 0x0; + entry_points_buf[i * 4 + 2] = (y << 16) | (x << 0); + entry_points_buf[i * 4 + 3] = + ((y + pps->row_height_minus1[ty]) << 16) | + ((x + pps->column_width_minus1[tx]) << 0); + } + } +} + +static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { struct cedrus_dev *dev = ctx->dev; const struct v4l2_ctrl_hevc_sps *sps; @@ -312,11 +398,15 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, const struct v4l2_hevc_pred_weight_table *pred_weight_table; unsigned int width_in_ctb_luma, ctb_size_luma; unsigned int log2_max_luma_coding_block_size; + unsigned int ctb_addr_x, ctb_addr_y; dma_addr_t src_buf_addr; dma_addr_t src_buf_end_addr; u32 chroma_log2_weight_denom; + u32 num_entry_point_offsets; u32 output_pic_list_index; u32 pic_order_cnt[2]; + u8 *padding; + int count; u32 reg; sps = run->h265.sps; @@ -324,6 +414,15 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, slice_params = run->h265.slice_params; decode_params = run->h265.decode_params; pred_weight_table = &slice_params->pred_weight_table; + num_entry_point_offsets = slice_params->num_entry_point_offsets; + + /* + * If entry points offsets are present, we should get them + * exactly the right amount. + */ + if (num_entry_point_offsets && + num_entry_point_offsets != run->h265.entry_points_count) + return -ERANGE; log2_max_luma_coding_block_size = sps->log2_min_luma_coding_block_size_minus3 + 3 + @@ -358,8 +457,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING); if (!ctx->codec.h265.mv_col_buf) { ctx->codec.h265.mv_col_buf_size = 0; - // TODO: Abort the process here. - return; + return -ENOMEM; } } @@ -391,12 +489,19 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg); /* Coding tree block address */ - reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma); - reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma); + ctb_addr_x = slice_params->slice_segment_addr % width_in_ctb_luma; + ctb_addr_y = slice_params->slice_segment_addr / width_in_ctb_luma; + reg = VE_DEC_H265_DEC_CTB_ADDR_X(ctb_addr_x); + reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(ctb_addr_y); cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg); - cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0); - cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0); + if ((pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) || + (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED)) { + cedrus_h265_write_tiles(ctx, run, ctb_addr_x, ctb_addr_y); + } else { + cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0); + cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0); + } /* Clear the number of correctly-decoded coding tree blocks. */ if (ctx->fh.m2m_ctx->new_frame) @@ -405,7 +510,30 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Initialize bitstream access. */ cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC); - cedrus_h265_skip_bits(dev, slice_params->data_bit_offset); + /* + * Cedrus expects that bitstream pointer is actually at the end of the slice header + * instead of start of slice data. Padding is 8 bits at most (one bit set to 1 and + * at most seven bits set to 0), so we have to inspect only one byte before slice data. + */ + + if (slice_params->data_byte_offset == 0) + return -EOPNOTSUPP; + + padding = (u8 *)vb2_plane_vaddr(&run->src->vb2_buf, 0) + + slice_params->data_byte_offset - 1; + + /* at least one bit must be set in that byte */ + if (*padding == 0) + return -EINVAL; + + for (count = 0; count < 8; count++) + if (*padding & (1 << count)) + break; + + /* Include the one bit. */ + count++; + + cedrus_h265_skip_bits(dev, slice_params->data_byte_offset * 8 - count); /* Bitstream parameters. */ @@ -500,7 +628,9 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED, pps->flags); - /* TODO: VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED */ + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED, + V4L2_HEVC_PPS_FLAG_TILES_ENABLED, + pps->flags); reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TRANSQUANT_BYPASS_ENABLED, V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED, @@ -559,7 +689,6 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, reg = VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(slice_params->slice_tc_offset_div2) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(slice_params->slice_beta_offset_div2) | - VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(decode_params->num_poc_st_curr_after == 0) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(slice_params->slice_cr_qp_offset) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(slice_params->slice_cb_qp_offset) | VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_QP_DELTA(slice_params->slice_qp_delta); @@ -572,16 +701,22 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED, slice_params->flags); + if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_I && !cedrus_h265_is_low_delay(run)) + reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_NOT_LOW_DELAY; + cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO1, reg); chroma_log2_weight_denom = pred_weight_table->luma_log2_weight_denom + pred_weight_table->delta_chroma_log2_weight_denom; - reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(0) | + reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(num_entry_point_offsets) | VE_DEC_H265_DEC_SLICE_HDR_INFO2_CHROMA_LOG2_WEIGHT_DENOM(chroma_log2_weight_denom) | VE_DEC_H265_DEC_SLICE_HDR_INFO2_LUMA_LOG2_WEIGHT_DENOM(pred_weight_table->luma_log2_weight_denom); cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO2, reg); + cedrus_write(dev, VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR, + ctx->codec.h265.entry_points_buf_addr >> 8); + /* Decoded picture size. */ reg = VE_DEC_H265_DEC_PIC_SIZE_WIDTH(ctx->src_fmt.width) | @@ -659,6 +794,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Enable appropriate interruptions. */ cedrus_write(dev, VE_DEC_H265_CTRL, VE_DEC_H265_CTRL_IRQ_MASK); + + return 0; } static int cedrus_h265_start(struct cedrus_ctx *ctx) @@ -676,6 +813,18 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx) if (!ctx->codec.h265.neighbor_info_buf) return -ENOMEM; + ctx->codec.h265.entry_points_buf = + dma_alloc_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE, + &ctx->codec.h265.entry_points_buf_addr, + GFP_KERNEL); + if (!ctx->codec.h265.entry_points_buf) { + dma_free_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, + ctx->codec.h265.neighbor_info_buf, + ctx->codec.h265.neighbor_info_buf_addr, + DMA_ATTR_NO_KERNEL_MAPPING); + return -ENOMEM; + } + return 0; } @@ -696,6 +845,9 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx) ctx->codec.h265.neighbor_info_buf, ctx->codec.h265.neighbor_info_buf_addr, DMA_ATTR_NO_KERNEL_MAPPING); + dma_free_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE, + ctx->codec.h265.entry_points_buf, + ctx->codec.h265.entry_points_buf_addr); } static void cedrus_h265_trigger(struct cedrus_ctx *ctx) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 5dad2f296c6d..4cfc4a3c8a7f 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -48,7 +48,7 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx) cedrus_write(dev, VE_DEC_MPEG_CTRL, reg); } -static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) +static int cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { const struct v4l2_ctrl_mpeg2_sequence *seq; const struct v4l2_ctrl_mpeg2_picture *pic; @@ -185,6 +185,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) VE_DEC_MPEG_CTRL_MC_CACHE_EN; cedrus_write(dev, VE_DEC_MPEG_CTRL, reg); + + return 0; } static void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index bdb062ad8682..d81f7513ade0 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -377,13 +377,12 @@ #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED BIT(23) #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED BIT(22) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_NOT_LOW_DELAY BIT(21) #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(v) \ SHIFT_AND_MASK_BITS(v, 31, 28) #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(v) \ SHIFT_AND_MASK_BITS(v, 27, 24) -#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(v) \ - ((v) ? BIT(21) : 0) #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(v) \ SHIFT_AND_MASK_BITS(v, 20, 16) #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(v) \ diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 33726175d980..66714609b577 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -568,7 +568,6 @@ int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; src_vq->io_modes = VB2_MMAP | VB2_DMABUF; - src_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct cedrus_buffer); src_vq->ops = &cedrus_qops; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c index f4016684b32d..3f750d1795b6 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c @@ -651,8 +651,7 @@ static void cedrus_vp8_irq_disable(struct cedrus_ctx *ctx) reg & ~VE_H264_CTRL_INT_MASK); } -static void cedrus_vp8_setup(struct cedrus_ctx *ctx, - struct cedrus_run *run) +static int cedrus_vp8_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { const struct v4l2_ctrl_vp8_frame *slice = run->vp8.frame_params; struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; @@ -855,6 +854,8 @@ static void cedrus_vp8_setup(struct cedrus_ctx *ctx, ctx->codec.vp8.last_sharpness_level = slice->lf.sharpness_level; } + + return 0; } static int cedrus_vp8_start(struct cedrus_ctx *ctx) diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 8e184aa4c252..9d46a36cc014 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -157,7 +157,7 @@ tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan) { struct media_pad *pad; - pad = media_entity_remote_pad(&chan->pad); + pad = media_pad_remote_pad_first(&chan->pad); if (!pad) return NULL; @@ -177,7 +177,7 @@ tegra_channel_get_remote_source_subdev(struct tegra_vi_channel *chan) pad = &subdev->entity.pads[0]; while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) { - pad = media_entity_remote_pad(pad); + pad = media_pad_remote_pad_first(pad); if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; entity = pad->entity; diff --git a/drivers/staging/media/zoran/videocodec.c b/drivers/staging/media/zoran/videocodec.c index 3af7d02bd910..a0c8bde5ec11 100644 --- a/drivers/staging/media/zoran/videocodec.c +++ b/drivers/staging/media/zoran/videocodec.c @@ -16,16 +16,6 @@ #include "videocodec.h" -static int videocodec_debug; -module_param(videocodec_debug, int, 0); -MODULE_PARM_DESC(videocodec_debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (videocodec_debug >= num) \ - printk(format, ##args); \ - } while (0) - struct attached_list { struct videocodec *codec; struct attached_list *next; @@ -47,6 +37,7 @@ static struct codec_list *codeclist_top; struct videocodec *videocodec_attach(struct videocodec_master *master) { struct codec_list *h = codeclist_top; + struct zoran *zr; struct attached_list *a, *ptr; struct videocodec *codec; int res; @@ -56,11 +47,13 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) return NULL; } - dprintk(2, "%s: '%s', flags %lx, magic %lx\n", __func__, - master->name, master->flags, master->magic); + zr = videocodec_master_to_zoran(master); + + zrdev_dbg(zr, "%s: '%s', flags %lx, magic %lx\n", __func__, + master->name, master->flags, master->magic); if (!h) { - pr_err("%s: no device available\n", __func__); + zrdev_err(zr, "%s: no device available\n", __func__); return NULL; } @@ -68,7 +61,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) // attach only if the slave has at least the flags // expected by the master if ((master->flags & h->codec->flags) == master->flags) { - dprintk(4, "%s: try '%s'\n", __func__, h->codec->name); + zrdev_dbg(zr, "%s: try '%s'\n", __func__, h->codec->name); codec = kmemdup(h->codec, sizeof(struct videocodec), GFP_KERNEL); if (!codec) @@ -79,7 +72,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) codec->master_data = master; res = codec->setup(codec); if (res == 0) { - dprintk(3, "%s: '%s'\n", __func__, codec->name); + zrdev_dbg(zr, "%s: '%s'\n", __func__, codec->name); ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); if (!ptr) goto out_kfree; @@ -88,12 +81,13 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) a = h->list; if (!a) { h->list = ptr; - dprintk(4, "videocodec: first element\n"); + zrdev_dbg(zr, "videocodec: first element\n"); } else { while (a->next) a = a->next; // find end a->next = ptr; - dprintk(4, "videocodec: in after '%s'\n", h->codec->name); + zrdev_dbg(zr, "videocodec: in after '%s'\n", + h->codec->name); } h->attached += 1; @@ -105,7 +99,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) h = h->next; } - pr_err("%s: no codec found!\n", __func__); + zrdev_err(zr, "%s: no codec found!\n", __func__); return NULL; out_kfree: @@ -116,6 +110,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) int videocodec_detach(struct videocodec *codec) { struct codec_list *h = codeclist_top; + struct zoran *zr; struct attached_list *a, *prev; int res; @@ -124,11 +119,13 @@ int videocodec_detach(struct videocodec *codec) return -EINVAL; } - dprintk(2, "%s: '%s', type: %x, flags %lx, magic %lx\n", __func__, - codec->name, codec->type, codec->flags, codec->magic); + zr = videocodec_to_zoran(codec); + + zrdev_dbg(zr, "%s: '%s', type: %x, flags %lx, magic %lx\n", __func__, + codec->name, codec->type, codec->flags, codec->magic); if (!h) { - pr_err("%s: no device left...\n", __func__); + zrdev_err(zr, "%s: no device left...\n", __func__); return -ENXIO; } @@ -139,18 +136,19 @@ int videocodec_detach(struct videocodec *codec) if (codec == a->codec) { res = a->codec->unset(a->codec); if (res >= 0) { - dprintk(3, "%s: '%s'\n", __func__, a->codec->name); + zrdev_dbg(zr, "%s: '%s'\n", __func__, + a->codec->name); a->codec->master_data = NULL; } else { - pr_err("%s: '%s'\n", __func__, a->codec->name); + zrdev_err(zr, "%s: '%s'\n", __func__, a->codec->name); a->codec->master_data = NULL; } if (!prev) { h->list = a->next; - dprintk(4, "videocodec: delete first\n"); + zrdev_dbg(zr, "videocodec: delete first\n"); } else { prev->next = a->next; - dprintk(4, "videocodec: delete middle\n"); + zrdev_dbg(zr, "videocodec: delete middle\n"); } kfree(a->codec); kfree(a); @@ -163,22 +161,25 @@ int videocodec_detach(struct videocodec *codec) h = h->next; } - pr_err("%s: given codec not found!\n", __func__); + zrdev_err(zr, "%s: given codec not found!\n", __func__); return -EINVAL; } int videocodec_register(const struct videocodec *codec) { struct codec_list *ptr, *h = codeclist_top; + struct zoran *zr; if (!codec) { pr_err("%s: no data!\n", __func__); return -EINVAL; } - dprintk(2, - "videocodec: register '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); + zr = videocodec_to_zoran((struct videocodec *)codec); + + zrdev_dbg(zr, + "videocodec: register '%s', type: %x, flags %lx, magic %lx\n", + codec->name, codec->type, codec->flags, codec->magic); ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); if (!ptr) @@ -187,13 +188,13 @@ int videocodec_register(const struct videocodec *codec) if (!h) { codeclist_top = ptr; - dprintk(4, "videocodec: hooked in as first element\n"); + zrdev_dbg(zr, "videocodec: hooked in as first element\n"); } else { while (h->next) h = h->next; // find the end h->next = ptr; - dprintk(4, "videocodec: hooked in after '%s'\n", - h->codec->name); + zrdev_dbg(zr, "videocodec: hooked in after '%s'\n", + h->codec->name); } return 0; @@ -202,37 +203,41 @@ int videocodec_register(const struct videocodec *codec) int videocodec_unregister(const struct videocodec *codec) { struct codec_list *prev = NULL, *h = codeclist_top; + struct zoran *zr; if (!codec) { pr_err("%s: no data!\n", __func__); return -EINVAL; } - dprintk(2, - "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); + zr = videocodec_to_zoran((struct videocodec *)codec); + + zrdev_dbg(zr, + "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n", + codec->name, codec->type, codec->flags, codec->magic); if (!h) { - pr_err("%s: no device left...\n", __func__); + zrdev_err(zr, "%s: no device left...\n", __func__); return -ENXIO; } while (h) { if (codec == h->codec) { if (h->attached) { - pr_err("videocodec: '%s' is used\n", h->codec->name); + zrdev_err(zr, "videocodec: '%s' is used\n", + h->codec->name); return -EBUSY; } - dprintk(3, "videocodec: unregister '%s' is ok.\n", - h->codec->name); + zrdev_dbg(zr, "videocodec: unregister '%s' is ok.\n", + h->codec->name); if (!prev) { codeclist_top = h->next; - dprintk(4, - "videocodec: delete first element\n"); + zrdev_dbg(zr, + "videocodec: delete first element\n"); } else { prev->next = h->next; - dprintk(4, - "videocodec: delete middle element\n"); + zrdev_dbg(zr, + "videocodec: delete middle element\n"); } kfree(h); return 0; @@ -241,7 +246,7 @@ int videocodec_unregister(const struct videocodec *codec) h = h->next; } - pr_err("%s: given codec not found!\n", __func__); + zrdev_err(zr, "%s: given codec not found!\n", __func__); return -EINVAL; } diff --git a/drivers/staging/media/zoran/videocodec.h b/drivers/staging/media/zoran/videocodec.h index 9dea348fee40..5e6057edd339 100644 --- a/drivers/staging/media/zoran/videocodec.h +++ b/drivers/staging/media/zoran/videocodec.h @@ -307,4 +307,19 @@ extern int videocodec_unregister(const struct videocodec *); int videocodec_debugfs_show(struct seq_file *m); +#include "zoran.h" +static inline struct zoran *videocodec_master_to_zoran(struct videocodec_master *master) +{ + struct zoran *zr = master->data; + + return zr; +} + +static inline struct zoran *videocodec_to_zoran(struct videocodec *codec) +{ + struct videocodec_master *master = codec->master_data; + + return videocodec_master_to_zoran(master); +} + #endif /*ifndef __LINUX_VIDEOCODEC_H */ diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h index 654c95fa5aba..05227e5298f6 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -19,6 +19,8 @@ #define _BUZ_H_ #include <linux/debugfs.h> +#include <linux/pci.h> +#include <linux/i2c-algo-bit.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> #include <media/videobuf2-core.h> @@ -301,6 +303,18 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) #endif +/* + * Debugging macros + */ +#define zrdev_dbg(zr, format, args...) \ + pci_dbg((zr)->pci_dev, format, ##args) \ + +#define zrdev_err(zr, format, args...) \ + pci_err((zr)->pci_dev, format, ##args) \ + +#define zrdev_info(zr, format, args...) \ + pci_info((zr)->pci_dev, format, ##args) \ + int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir); void zoran_queue_exit(struct zoran *zr); int zr_set_buf(struct zoran *zr); diff --git a/drivers/staging/media/zoran/zr36016.c b/drivers/staging/media/zoran/zr36016.c index 26c7c32b6bc0..0e0532537a3e 100644 --- a/drivers/staging/media/zoran/zr36016.c +++ b/drivers/staging/media/zoran/zr36016.c @@ -22,17 +22,6 @@ /* amount of chips attached via this driver */ static int zr36016_codecs; -static int zr36016_debug; -module_param(zr36016_debug, int, 0); -MODULE_PARM_DESC(zr36016_debug, "Debug level (0-4)"); - - -#define dprintk(num, format, args...) \ - do { \ - if (zr36016_debug >= num) \ - printk(format, ##args); \ - } while (0) - /* ========================================================================= Local hardware I/O functions: @@ -43,27 +32,30 @@ MODULE_PARM_DESC(zr36016_debug, "Debug level (0-4)"); static u8 zr36016_read(struct zr36016 *ptr, u16 reg) { u8 value = 0; + struct zoran *zr = videocodec_to_zoran(ptr->codec); /* just in case something is wrong... */ if (ptr->codec->master_data->readreg) value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF; else - pr_err("%s: invalid I/O setup, nothing read!\n", ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name); - dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value); + zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value); return value; } static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value) { - dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg); + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg); // just in case something is wrong... if (ptr->codec->master_data->writereg) ptr->codec->master_data->writereg(ptr->codec, reg, value); else - pr_err("%s: invalid I/O setup, nothing written!\n", ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name); } /* indirect read and write functions */ @@ -72,30 +64,34 @@ static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value) static u8 zr36016_readi(struct zr36016 *ptr, u16 reg) { u8 value = 0; + struct zoran *zr = videocodec_to_zoran(ptr->codec); /* just in case something is wrong... */ if ((ptr->codec->master_data->writereg) && (ptr->codec->master_data->readreg)) { ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; // DATA } else { - pr_err("%s: invalid I/O setup, nothing read (i)!\n", ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing read (i)!\n", ptr->name); } - dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name, reg, value); + zrdev_dbg(zr, "%s: reading indirect from 0x%04x: %02x\n", + ptr->name, reg, value); return value; } static void zr36016_writei(struct zr36016 *ptr, u16 reg, u8 value) { - dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, - value, reg); + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, + value, reg); /* just in case something is wrong... */ if (ptr->codec->master_data->writereg) { ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); // DATA } else { - pr_err("%s: invalid I/O setup, nothing written (i)!\n", ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing written (i)!\n", ptr->name); } } @@ -120,32 +116,34 @@ static u8 zr36016_read_version(struct zr36016 *ptr) static int zr36016_basic_test(struct zr36016 *ptr) { - if (zr36016_debug) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + if (*KERN_INFO <= CONSOLE_LOGLEVEL_DEFAULT) { int i; zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); - dprintk(1, KERN_INFO "%s: registers: ", ptr->name); + zrdev_dbg(zr, "%s: registers: ", ptr->name); for (i = 0; i <= 0x0b; i++) - dprintk(1, "%02x ", zr36016_readi(ptr, i)); - dprintk(1, "\n"); + zrdev_dbg(zr, "%02x ", zr36016_readi(ptr, i)); + zrdev_dbg(zr, "\n"); } // for testing just write 0, then the default value to a register and read // it back in both cases zr36016_writei(ptr, ZR016I_PAX_LO, 0x00); if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) { - pr_err("%s: attach failed, can't connect to vfe processor!\n", ptr->name); + zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name); return -ENXIO; } zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0); if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) { - pr_err("%s: attach failed, can't connect to vfe processor!\n", ptr->name); + zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name); return -ENXIO; } // we allow version numbers from 0-3, should be enough, though zr36016_read_version(ptr); if (ptr->version & 0x0c) { - pr_err("%s: attach failed, suspicious version %d found...\n", ptr->name, - ptr->version); + zrdev_err(zr, "%s: attach failed, suspicious version %d found...\n", ptr->name, + ptr->version); return -ENXIO; } @@ -164,10 +162,11 @@ static int zr36016_pushit(struct zr36016 *ptr, u16 len, const char *data) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); int i = 0; - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", - ptr->name, startreg, len); + zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", + ptr->name, startreg, len); while (i < len) { zr36016_writei(ptr, startreg++, data[i++]); } @@ -225,8 +224,9 @@ static void zr36016_init(struct zr36016 *ptr) static int zr36016_set_mode(struct videocodec *codec, int mode) { struct zr36016 *ptr = (struct zr36016 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); + zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode); if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) return -EINVAL; @@ -242,11 +242,12 @@ static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm struct vfe_settings *cap, struct vfe_polarity *pol) { struct zr36016 *ptr = (struct zr36016 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); - dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", - ptr->name, norm->h_start, norm->v_start, - cap->x, cap->y, cap->width, cap->height, - cap->decimation); + zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", + ptr->name, norm->h_start, norm->v_start, + cap->x, cap->y, cap->width, cap->height, + cap->decimation); /* if () return -EINVAL; * trust the master driver that it knows what it does - so @@ -276,9 +277,11 @@ static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm static int zr36016_control(struct videocodec *codec, int type, int size, void *data) { struct zr36016 *ptr = (struct zr36016 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); int *ival = (int *)data; - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, size); + zrdev_dbg(zr, "%s: control %d call with %d byte\n", + ptr->name, type, size); switch (type) { case CODEC_G_STATUS: /* get last status - we don't know it ... */ @@ -325,11 +328,12 @@ static int zr36016_control(struct videocodec *codec, int type, int size, void *d static int zr36016_unset(struct videocodec *codec) { struct zr36016 *ptr = codec->data; + struct zoran *zr = videocodec_to_zoran(codec); if (ptr) { /* do wee need some codec deinit here, too ???? */ - dprintk(1, "%s: finished codec #%d\n", ptr->name, ptr->num); + zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num); kfree(ptr); codec->data = NULL; @@ -352,12 +356,13 @@ static int zr36016_unset(struct videocodec *codec) static int zr36016_setup(struct videocodec *codec) { struct zr36016 *ptr; + struct zoran *zr = videocodec_to_zoran(codec); int res; - dprintk(2, "zr36016: initializing VFE subsystem #%d.\n", zr36016_codecs); + zrdev_dbg(zr, "zr36016: initializing VFE subsystem #%d.\n", zr36016_codecs); if (zr36016_codecs == MAX_CODECS) { - pr_err("zr36016: Can't attach more codecs!\n"); + zrdev_err(zr, "zr36016: Can't attach more codecs!\n"); return -ENOSPC; } //mem structure init @@ -384,7 +389,8 @@ static int zr36016_setup(struct videocodec *codec) ptr->ydec = 0; zr36016_init(ptr); - dprintk(1, KERN_INFO "%s: codec v%d attached and running\n", ptr->name, ptr->version); + zrdev_dbg(zr, "%s: codec v%d attached and running\n", + ptr->name, ptr->version); return 0; } @@ -417,9 +423,8 @@ int zr36016_init_module(void) void zr36016_cleanup_module(void) { if (zr36016_codecs) { - dprintk(1, - "zr36016: something's wrong - %d codecs left somehow.\n", - zr36016_codecs); + pr_debug("zr36016: something's wrong - %d codecs left somehow.\n", + zr36016_codecs); } videocodec_unregister(&zr36016_codec); } diff --git a/drivers/staging/media/zoran/zr36050.c b/drivers/staging/media/zoran/zr36050.c index 38f7021e7b06..6a7ef28d996c 100644 --- a/drivers/staging/media/zoran/zr36050.c +++ b/drivers/staging/media/zoran/zr36050.c @@ -29,17 +29,6 @@ /* amount of chips attached via this driver */ static int zr36050_codecs; -/* debugging is available via module parameter */ -static int zr36050_debug; -module_param(zr36050_debug, int, 0); -MODULE_PARM_DESC(zr36050_debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (zr36050_debug >= num) \ - printk(format, ##args); \ - } while (0) - /* ========================================================================= Local hardware I/O functions: @@ -49,32 +38,32 @@ MODULE_PARM_DESC(zr36050_debug, "Debug level (0-4)"); /* read and write functions */ static u8 zr36050_read(struct zr36050 *ptr, u16 reg) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); u8 value = 0; /* just in case something is wrong... */ if (ptr->codec->master_data->readreg) value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF; else - dprintk(1, - KERN_ERR "%s: invalid I/O setup, nothing read!\n", ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name); - dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value); + zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value); return value; } static void zr36050_write(struct zr36050 *ptr, u16 reg, u8 value) { - dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg); + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg); /* just in case something is wrong... */ if (ptr->codec->master_data->writereg) ptr->codec->master_data->writereg(ptr->codec, reg, value); else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written!\n", - ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", + ptr->name); } /* ========================================================================= @@ -117,14 +106,15 @@ static u16 zr36050_read_scalefactor(struct zr36050 *ptr) static void zr36050_wait_end(struct zr36050 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); int i = 0; while (!(zr36050_read_status1(ptr) & 0x4)) { udelay(1); if (i++ > 200000) { // 200ms, there is for sure something wrong!!! - dprintk(1, - "%s: timeout at wait_end (last status: 0x%02x)\n", - ptr->name, ptr->status1); + zrdev_err(zr, + "%s: timeout at wait_end (last status: 0x%02x)\n", + ptr->name, ptr->status1); break; } } @@ -138,33 +128,32 @@ static void zr36050_wait_end(struct zr36050 *ptr) static int zr36050_basic_test(struct zr36050 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); + zr36050_write(ptr, ZR050_SOF_IDX, 0x00); zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00); if ((zr36050_read(ptr, ZR050_SOF_IDX) | zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); + zrdev_err(zr, + "%s: attach failed, can't connect to jpeg processor!\n", + ptr->name); return -ENXIO; } zr36050_write(ptr, ZR050_SOF_IDX, 0xff); zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0); if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) | zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); + zrdev_err(zr, + "%s: attach failed, can't connect to jpeg processor!\n", + ptr->name); return -ENXIO; } zr36050_wait_end(ptr); if ((ptr->status1 & 0x4) == 0) { - dprintk(1, - KERN_ERR - "%s: attach failed, jpeg processor failed (end flag)!\n", - ptr->name); + zrdev_err(zr, + "%s: attach failed, jpeg processor failed (end flag)!\n", + ptr->name); return -EBUSY; } @@ -179,10 +168,11 @@ static int zr36050_basic_test(struct zr36050 *ptr) static int zr36050_pushit(struct zr36050 *ptr, u16 startreg, u16 len, const char *data) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); int i = 0; - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, - startreg, len); + zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, + startreg, len); while (i < len) zr36050_write(ptr, startreg++, data[i++]); @@ -305,11 +295,12 @@ static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; static int zr36050_set_sof(struct zr36050 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); char sof_data[34]; // max. size of register set int i; - dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name, - ptr->width, ptr->height, NO_OF_COMPONENTS); + zrdev_dbg(zr, "%s: write SOF (%dx%d, %d components)\n", ptr->name, + ptr->width, ptr->height, NO_OF_COMPONENTS); sof_data[0] = 0xff; sof_data[1] = 0xc0; sof_data[2] = 0x00; @@ -336,10 +327,11 @@ static int zr36050_set_sof(struct zr36050 *ptr) static int zr36050_set_sos(struct zr36050 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); char sos_data[16]; // max. size of register set int i; - dprintk(3, "%s: write SOS\n", ptr->name); + zrdev_dbg(zr, "%s: write SOS\n", ptr->name); sos_data[0] = 0xff; sos_data[1] = 0xda; sos_data[2] = 0x00; @@ -363,9 +355,10 @@ static int zr36050_set_sos(struct zr36050 *ptr) static int zr36050_set_dri(struct zr36050 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); char dri_data[6]; // max. size of register set - dprintk(3, "%s: write DRI\n", ptr->name); + zrdev_dbg(zr, "%s: write DRI\n", ptr->name); dri_data[0] = 0xff; dri_data[1] = 0xdd; dri_data[2] = 0x00; @@ -387,9 +380,10 @@ static void zr36050_init(struct zr36050 *ptr) { int sum = 0; long bitcnt, tmp; + struct zoran *zr = videocodec_to_zoran(ptr->codec); if (ptr->mode == CODEC_DO_COMPRESSION) { - dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name); + zrdev_dbg(zr, "%s: COMPRESSION SETUP\n", ptr->name); /* 050 communicates with 057 in master mode */ zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR); @@ -419,7 +413,7 @@ static void zr36050_init(struct zr36050 *ptr) /* setup the fixed jpeg tables - maybe variable, though - * (see table init section above) */ - dprintk(3, "%s: write DQT, DHT, APP\n", ptr->name); + zrdev_dbg(zr, "%s: write DQT, DHT, APP\n", ptr->name); sum += zr36050_pushit(ptr, ZR050_DQT_IDX, sizeof(zr36050_dqt), zr36050_dqt); sum += zr36050_pushit(ptr, ZR050_DHT_IDX, @@ -442,11 +436,11 @@ static void zr36050_init(struct zr36050 *ptr) zr36050_write(ptr, ZR050_GO, 1); // launch codec zr36050_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", - ptr->name, ptr->status1); + zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n", + ptr->name, ptr->status1); if ((ptr->status1 & 0x4) == 0) { - pr_err("%s: init aborted!\n", ptr->name); + zrdev_err(zr, "%s: init aborted!\n", ptr->name); return; // something is wrong, its timed out!!!! } @@ -457,9 +451,9 @@ static void zr36050_init(struct zr36050 *ptr) bitcnt = sum << 3; /* need the size in bits */ tmp = bitcnt >> 16; - dprintk(3, - "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", - ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); + zrdev_dbg(zr, + "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", + ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8); zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff); tmp = bitcnt & 0xffff; @@ -470,8 +464,8 @@ static void zr36050_init(struct zr36050 *ptr) bitcnt -= ((bitcnt * 5) >> 6); // bits without eob tmp = bitcnt >> 16; - dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n", - ptr->name, bitcnt, tmp); + zrdev_dbg(zr, "%s: code: nettobit=%ld, highnettobits=%ld\n", + ptr->name, bitcnt, tmp); zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8); zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff); tmp = bitcnt & 0xffff; @@ -489,7 +483,7 @@ static void zr36050_init(struct zr36050 *ptr) ((ptr->app.len > 0) ? ZR050_ME_APP : 0) | ((ptr->com.len > 0) ? ZR050_ME_COM : 0)); } else { - dprintk(2, "%s: EXPANSION SETUP\n", ptr->name); + zrdev_dbg(zr, "%s: EXPANSION SETUP\n", ptr->name); /* 050 communicates with 055 in master mode */ zr36050_write(ptr, ZR050_HARDWARE, @@ -502,7 +496,7 @@ static void zr36050_init(struct zr36050 *ptr) zr36050_write(ptr, ZR050_INT_REQ_0, 0); zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 - dprintk(3, "%s: write DHT\n", ptr->name); + zrdev_dbg(zr, "%s: write DHT\n", ptr->name); zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht), zr36050_dht); @@ -511,11 +505,11 @@ static void zr36050_init(struct zr36050 *ptr) zr36050_write(ptr, ZR050_GO, 1); // launch codec zr36050_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", - ptr->name, ptr->status1); + zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n", + ptr->name, ptr->status1); if ((ptr->status1 & 0x4) == 0) { - pr_err("%s: init aborted!\n", ptr->name); + zrdev_err(zr, "%s: init aborted!\n", ptr->name); return; // something is wrong, its timed out!!!! } @@ -539,8 +533,9 @@ static void zr36050_init(struct zr36050 *ptr) static int zr36050_set_mode(struct videocodec *codec, int mode) { struct zr36050 *ptr = (struct zr36050 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); + zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode); if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) return -EINVAL; @@ -556,12 +551,13 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm struct vfe_settings *cap, struct vfe_polarity *pol) { struct zr36050 *ptr = (struct zr36050 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); int size; - dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n", - ptr->name, norm->h_start, norm->v_start, - cap->x, cap->y, cap->width, cap->height, - cap->decimation, cap->quality); + zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n", + ptr->name, norm->h_start, norm->v_start, + cap->x, cap->y, cap->width, cap->height, + cap->decimation, cap->quality); /* if () return -EINVAL; * trust the master driver that it knows what it does - so * we allow invalid startx/y and norm for now ... */ @@ -594,10 +590,11 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm static int zr36050_control(struct videocodec *codec, int type, int size, void *data) { struct zr36050 *ptr = (struct zr36050 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); int *ival = (int *)data; - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); + zrdev_dbg(zr, "%s: control %d call with %d byte\n", ptr->name, type, + size); switch (type) { case CODEC_G_STATUS: /* get last status */ @@ -713,12 +710,13 @@ static int zr36050_control(struct videocodec *codec, int type, int size, void *d static int zr36050_unset(struct videocodec *codec) { struct zr36050 *ptr = codec->data; + struct zoran *zr = videocodec_to_zoran(codec); if (ptr) { /* do wee need some codec deinit here, too ???? */ - dprintk(1, "%s: finished codec #%d\n", ptr->name, - ptr->num); + zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, + ptr->num); kfree(ptr); codec->data = NULL; @@ -741,14 +739,15 @@ static int zr36050_unset(struct videocodec *codec) static int zr36050_setup(struct videocodec *codec) { struct zr36050 *ptr; + struct zoran *zr = videocodec_to_zoran(codec); int res; - dprintk(2, "zr36050: initializing MJPEG subsystem #%d.\n", - zr36050_codecs); + zrdev_dbg(zr, "zr36050: initializing MJPEG subsystem #%d.\n", + zr36050_codecs); if (zr36050_codecs == MAX_CODECS) { - dprintk(1, - KERN_ERR "zr36050: Can't attach more codecs!\n"); + zrdev_err(zr, + "zr36050: Can't attach more codecs!\n"); return -ENOSPC; } //mem structure init @@ -789,8 +788,8 @@ static int zr36050_setup(struct videocodec *codec) zr36050_init(ptr); - dprintk(1, KERN_INFO "%s: codec attached and running\n", - ptr->name); + zrdev_info(zr, "%s: codec attached and running\n", + ptr->name); return 0; } @@ -823,9 +822,8 @@ int zr36050_init_module(void) void zr36050_cleanup_module(void) { if (zr36050_codecs) { - dprintk(1, - "zr36050: something's wrong - %d codecs left somehow.\n", - zr36050_codecs); + pr_debug("zr36050: something's wrong - %d codecs left somehow.\n", + zr36050_codecs); } videocodec_unregister(&zr36050_codec); } diff --git a/drivers/staging/media/zoran/zr36060.c b/drivers/staging/media/zoran/zr36060.c index d0c369e31c81..7798016f1f96 100644 --- a/drivers/staging/media/zoran/zr36060.c +++ b/drivers/staging/media/zoran/zr36060.c @@ -32,16 +32,6 @@ static bool low_bitrate; module_param(low_bitrate, bool, 0); MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate"); -static int zr36060_debug; -module_param(zr36060_debug, int, 0); -MODULE_PARM_DESC(zr36060_debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (zr36060_debug >= num) \ - printk(format, ##args); \ - } while (0) - /* ========================================================================= * Local hardware I/O functions: * read/write via codec layer (registers are located in the master device) @@ -51,25 +41,28 @@ MODULE_PARM_DESC(zr36060_debug, "Debug level (0-4)"); static u8 zr36060_read(struct zr36060 *ptr, u16 reg) { u8 value = 0; + struct zoran *zr = videocodec_to_zoran(ptr->codec); // just in case something is wrong... if (ptr->codec->master_data->readreg) value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xff; else - pr_err("%s: invalid I/O setup, nothing read!\n", ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name); return value; } static void zr36060_write(struct zr36060 *ptr, u16 reg, u8 value) { - dprintk(4, "0x%02x @0x%04x\n", value, reg); + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "0x%02x @0x%04x\n", value, reg); // just in case something is wrong... if (ptr->codec->master_data->writereg) ptr->codec->master_data->writereg(ptr->codec, reg, value); else - pr_err("%s: invalid I/O setup, nothing written!\n", ptr->name); + zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name); } /* ========================================================================= @@ -101,14 +94,15 @@ static u16 zr36060_read_scalefactor(struct zr36060 *ptr) /* wait if codec is ready to proceed (end of processing) or time is over */ static void zr36060_wait_end(struct zr36060 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); int i = 0; while (zr36060_read_status(ptr) & ZR060_CFSR_BUSY) { udelay(1); if (i++ > 200000) { // 200ms, there is for sure something wrong!!! - dprintk(1, - "%s: timeout at wait_end (last status: 0x%02x)\n", - ptr->name, ptr->status); + zrdev_dbg(zr, + "%s: timeout at wait_end (last status: 0x%02x)\n", + ptr->name, ptr->status); break; } } @@ -117,15 +111,17 @@ static void zr36060_wait_end(struct zr36060 *ptr) /* Basic test of "connectivity", writes/reads to/from memory the SOF marker */ static int zr36060_basic_test(struct zr36060 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); + if ((zr36060_read(ptr, ZR060_IDR_DEV) != 0x33) && (zr36060_read(ptr, ZR060_IDR_REV) != 0x01)) { - pr_err("%s: attach failed, can't connect to jpeg processor!\n", ptr->name); + zrdev_err(zr, "%s: attach failed, can't connect to jpeg processor!\n", ptr->name); return -ENXIO; } zr36060_wait_end(ptr); if (ptr->status & ZR060_CFSR_BUSY) { - pr_err("%s: attach failed, jpeg processor failed (end flag)!\n", ptr->name); + zrdev_err(zr, "%s: attach failed, jpeg processor failed (end flag)!\n", ptr->name); return -EBUSY; } @@ -135,10 +131,11 @@ static int zr36060_basic_test(struct zr36060 *ptr) /* simple loop for pushing the init datasets */ static int zr36060_pushit(struct zr36060 *ptr, u16 startreg, u16 len, const char *data) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); int i = 0; - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, - startreg, len); + zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, + startreg, len); while (i < len) zr36060_write(ptr, startreg++, data[i++]); @@ -249,11 +246,12 @@ static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; /* SOF (start of frame) segment depends on width, height and sampling ratio of each color component */ static int zr36060_set_sof(struct zr36060 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); char sof_data[34]; // max. size of register set int i; - dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name, - ptr->width, ptr->height, NO_OF_COMPONENTS); + zrdev_dbg(zr, "%s: write SOF (%dx%d, %d components)\n", ptr->name, + ptr->width, ptr->height, NO_OF_COMPONENTS); sof_data[0] = 0xff; sof_data[1] = 0xc0; sof_data[2] = 0x00; @@ -277,10 +275,11 @@ static int zr36060_set_sof(struct zr36060 *ptr) /* SOS (start of scan) segment depends on the used scan components of each color component */ static int zr36060_set_sos(struct zr36060 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); char sos_data[16]; // max. size of register set int i; - dprintk(3, "%s: write SOS\n", ptr->name); + zrdev_dbg(zr, "%s: write SOS\n", ptr->name); sos_data[0] = 0xff; sos_data[1] = 0xda; sos_data[2] = 0x00; @@ -302,9 +301,10 @@ static int zr36060_set_sos(struct zr36060 *ptr) /* DRI (define restart interval) */ static int zr36060_set_dri(struct zr36060 *ptr) { + struct zoran *zr = videocodec_to_zoran(ptr->codec); char dri_data[6]; // max. size of register set - dprintk(3, "%s: write DRI\n", ptr->name); + zrdev_dbg(zr, "%s: write DRI\n", ptr->name); dri_data[0] = 0xff; dri_data[1] = 0xdd; dri_data[2] = 0x00; @@ -321,9 +321,10 @@ static void zr36060_init(struct zr36060 *ptr) { int sum = 0; long bitcnt, tmp; + struct zoran *zr = videocodec_to_zoran(ptr->codec); if (ptr->mode == CODEC_DO_COMPRESSION) { - dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name); + zrdev_dbg(zr, "%s: COMPRESSION SETUP\n", ptr->name); zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST); @@ -376,9 +377,9 @@ static void zr36060_init(struct zr36060 *ptr) bitcnt = sum << 3; /* need the size in bits */ tmp = bitcnt >> 16; - dprintk(3, - "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", - ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); + zrdev_dbg(zr, + "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", + ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); zr36060_write(ptr, ZR060_TCV_NET_HI, tmp >> 8); zr36060_write(ptr, ZR060_TCV_NET_MH, tmp & 0xff); tmp = bitcnt & 0xffff; @@ -389,8 +390,8 @@ static void zr36060_init(struct zr36060 *ptr) bitcnt -= ((bitcnt * 5) >> 6); // bits without eob tmp = bitcnt >> 16; - dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n", - ptr->name, bitcnt, tmp); + zrdev_dbg(zr, "%s: code: nettobit=%ld, highnettobits=%ld\n", + ptr->name, bitcnt, tmp); zr36060_write(ptr, ZR060_TCV_DATA_HI, tmp >> 8); zr36060_write(ptr, ZR060_TCV_DATA_MH, tmp & 0xff); tmp = bitcnt & 0xffff; @@ -408,7 +409,7 @@ static void zr36060_init(struct zr36060 *ptr) zr36060_write(ptr, ZR060_VCR, ZR060_VCR_RANGE); } else { - dprintk(2, "%s: EXPANSION SETUP\n", ptr->name); + zrdev_dbg(zr, "%s: EXPANSION SETUP\n", ptr->name); zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST); @@ -441,10 +442,11 @@ static void zr36060_init(struct zr36060 *ptr) /* Load the tables */ zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST | ZR060_LOAD_LOAD); zr36060_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", ptr->name, ptr->status); + zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n", + ptr->name, ptr->status); if (ptr->status & ZR060_CFSR_BUSY) { - pr_err("%s: init aborted!\n", ptr->name); + zrdev_err(zr, "%s: init aborted!\n", ptr->name); return; // something is wrong, its timed out!!!! } } @@ -461,8 +463,9 @@ static void zr36060_init(struct zr36060 *ptr) static int zr36060_set_mode(struct videocodec *codec, int mode) { struct zr36060 *ptr = (struct zr36060 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); + zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode); if (mode != CODEC_DO_EXPANSION && mode != CODEC_DO_COMPRESSION) return -EINVAL; @@ -478,11 +481,12 @@ static int zr36060_set_video(struct videocodec *codec, const struct tvnorm *norm struct vfe_settings *cap, struct vfe_polarity *pol) { struct zr36060 *ptr = (struct zr36060 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); u32 reg; int size; - dprintk(2, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name, - cap->x, cap->y, cap->width, cap->height, cap->decimation); + zrdev_dbg(zr, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name, + cap->x, cap->y, cap->width, cap->height, cap->decimation); /* if () return -EINVAL; * trust the master driver that it knows what it does - so @@ -637,10 +641,11 @@ static int zr36060_set_video(struct videocodec *codec, const struct tvnorm *norm static int zr36060_control(struct videocodec *codec, int type, int size, void *data) { struct zr36060 *ptr = (struct zr36060 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); int *ival = (int *)data; - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); + zrdev_dbg(zr, "%s: control %d call with %d byte\n", ptr->name, type, + size); switch (type) { case CODEC_G_STATUS: /* get last status */ @@ -753,11 +758,12 @@ static int zr36060_control(struct videocodec *codec, int type, int size, void *d static int zr36060_unset(struct videocodec *codec) { struct zr36060 *ptr = codec->data; + struct zoran *zr = videocodec_to_zoran(codec); if (ptr) { /* do wee need some codec deinit here, too ???? */ - dprintk(1, "%s: finished codec #%d\n", ptr->name, ptr->num); + zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num); kfree(ptr); codec->data = NULL; @@ -778,12 +784,14 @@ static int zr36060_unset(struct videocodec *codec) static int zr36060_setup(struct videocodec *codec) { struct zr36060 *ptr; + struct zoran *zr = videocodec_to_zoran(codec); int res; - dprintk(2, "zr36060: initializing MJPEG subsystem #%d.\n", zr36060_codecs); + zrdev_dbg(zr, "zr36060: initializing MJPEG subsystem #%d.\n", + zr36060_codecs); if (zr36060_codecs == MAX_CODECS) { - pr_err("zr36060: Can't attach more codecs!\n"); + zrdev_err(zr, "zr36060: Can't attach more codecs!\n"); return -ENOSPC; } //mem structure init @@ -823,7 +831,7 @@ static int zr36060_setup(struct videocodec *codec) zr36060_init(ptr); - dprintk(1, KERN_INFO "%s: codec attached and running\n", ptr->name); + zrdev_info(zr, "%s: codec attached and running\n", ptr->name); return 0; } @@ -852,9 +860,8 @@ int zr36060_init_module(void) void zr36060_cleanup_module(void) { if (zr36060_codecs) { - dprintk(1, - "zr36060: something's wrong - %d codecs left somehow.\n", - zr36060_codecs); + pr_debug("zr36060: something's wrong - %d codecs left somehow.\n", + zr36060_codecs); } /* however, we can't just stay alive */ |