diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-28 15:49:58 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-06-28 15:49:58 -0700 |
commit | 31e798fd6f0ff0acdc49c1a358b581730936a09a (patch) | |
tree | 5c1c271ad457a8328aea35539e69c6ad9d1474b7 /drivers/staging | |
parent | 36824f198c621cebeb22966b5e244378fa341295 (diff) | |
parent | 61c6f04a988e420a1fc5e8e81cf9aebf142a7bd6 (diff) |
Merge tag 'media/v5.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- V4L2 core control API was split into separate files
- New RC maps: tango and tc-90405
- Hantro driver got support for G2/HEVC decoder
- av7710 is moving to staging, together with some legacy APIs
- several cleanups related to compat_ioctl32 code
- Move the MPEG-2 stateless control type out of staging
- Address several issues with RPM get logic on media drivers
- Lots of cleanups, bug fixes and improvements.
* tag 'media/v5.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (394 commits)
media: s5p-mfc: Fix display delay control creation
media: mtk-vpu: on suspend, read/write regs only if vpu is running
media: video-mux: Skip dangling endpoints
media: Fix Media Controller API config checks
media: i2c: rdacm20: Re-work ov10635 reset
media: i2c: rdacm20: Check return values
media: i2c: rdacm20: Report camera module name
media: i2c: rdacm20: Enable noise immunity
media: i2c: rdacm20: Embed 'serializer' field
media: i2c: rdacm21: Power up OV10640 before OV490
media: i2c: rdacm21: Fix OV10640 powerup
media: i2c: rdacm21: Add delay after OV490 reset
media: i2c: max9271: Introduce wake_up() function
media: i2c: max9271: Check max9271_write() return
media: i2c: max9286: Rework comments in .bound()
media: i2c: max9286: Define high channel amplitude
media: i2c: max9286: Cache channel amplitude
media: i2c: max9286: Rename reverse_channel_mv
media: i2c: max9286: Adjust parameters indent
media: hantro: add support for Rockchip RK3036
...
Diffstat (limited to 'drivers/staging')
164 files changed, 18727 insertions, 4224 deletions
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index ca59986b20f8..e3aaae920847 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -42,4 +42,6 @@ source "drivers/staging/media/tegra-video/Kconfig" source "drivers/staging/media/ipu3/Kconfig" +source "drivers/staging/media/av7110/Kconfig" + endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 716929a1a313..5b5afc5b03a0 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_VIDEO_ZORAN) += zoran/ +obj-$(CONFIG_DVB_AV7110) += av7110/ diff --git a/drivers/staging/media/atomisp/Makefile b/drivers/staging/media/atomisp/Makefile index 51498b2e85b8..606b7754fdfd 100644 --- a/drivers/staging/media/atomisp/Makefile +++ b/drivers/staging/media/atomisp/Makefile @@ -16,7 +16,6 @@ atomisp-objs += \ pci/atomisp_acc.o \ pci/atomisp_cmd.o \ pci/atomisp_compat_css20.o \ - pci/atomisp_compat_ioctl32.o \ pci/atomisp_csi2.o \ pci/atomisp_drvfs.o \ pci/atomisp_file.o \ diff --git a/drivers/staging/media/atomisp/TODO b/drivers/staging/media/atomisp/TODO index 6987bb2d32cf..2d1ef9eb262a 100644 --- a/drivers/staging/media/atomisp/TODO +++ b/drivers/staging/media/atomisp/TODO @@ -120,6 +120,11 @@ TODO for this driver until the other work is done, as there will be a lot of code churn until this driver becomes functional again. +16. Fix private ioctls to not need a compat_ioctl handler for running + 32-bit tasks. The compat code has been removed because of bugs, + and should not be needed for modern drivers. Fixing this properly + unfortunately means an incompatible ABI change. + Limitations =========== diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index d170d0adfea4..687888d643df 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -300,7 +300,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client, /* pixel clock calculattion */ dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz; - pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); + dev_dbg(&client->dev, "vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); /* get integration time */ buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN; @@ -326,7 +326,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client, if (ret) return ret; buf->crop_horizontal_start = val | (reg_val & 0xFF); - pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start); + dev_dbg(&client->dev, "crop_horizontal_start=%d\n", buf->crop_horizontal_start); /* Getting crop_vertical_start */ ret = gc0310_read_reg(client, GC0310_8BIT, @@ -339,7 +339,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client, if (ret) return ret; buf->crop_vertical_start = val | (reg_val & 0xFF); - pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start); + dev_dbg(&client->dev, "crop_vertical_start=%d\n", buf->crop_vertical_start); /* Getting output_width */ ret = gc0310_read_reg(client, GC0310_8BIT, @@ -352,7 +352,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client, if (ret) return ret; buf->output_width = val | (reg_val & 0xFF); - pr_info("output_width=%d\n", buf->output_width); + dev_dbg(&client->dev, "output_width=%d\n", buf->output_width); /* Getting output_height */ ret = gc0310_read_reg(client, GC0310_8BIT, @@ -365,12 +365,12 @@ static int gc0310_get_intg_factor(struct i2c_client *client, if (ret) return ret; buf->output_height = val | (reg_val & 0xFF); - pr_info("output_height=%d\n", buf->output_height); + dev_dbg(&client->dev, "output_height=%d\n", buf->output_height); buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1; buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1; - pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end); - pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end); + dev_dbg(&client->dev, "crop_horizontal_end=%d\n", buf->crop_horizontal_end); + dev_dbg(&client->dev, "crop_vertical_end=%d\n", buf->crop_vertical_end); /* Getting line_length_pck */ ret = gc0310_read_reg(client, GC0310_8BIT, @@ -389,7 +389,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client, return ret; sh_delay = reg_val; buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4; - pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, + dev_dbg(&client->dev, "hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, sh_delay, buf->line_length_pck); /* Getting frame_length_lines */ @@ -404,7 +404,7 @@ static int gc0310_get_intg_factor(struct i2c_client *client, return ret; vert_blanking = val | (reg_val & 0xFF); buf->frame_length_lines = buf->output_height + vert_blanking; - pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking, + dev_dbg(&client->dev, "vert_blanking=%d frame_length_lines=%d\n", vert_blanking, buf->frame_length_lines); buf->binning_factor_x = res->bin_factor_x ? @@ -434,7 +434,7 @@ static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) dgain = gain / 2; } - pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain); + dev_dbg(&client->dev, "gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain); /* set analog gain */ ret = gc0310_write_reg(client, GC0310_8BIT, @@ -458,7 +458,7 @@ static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg, struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain); + dev_dbg(&client->dev, "coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain); /* set exposure */ ret = gc0310_write_reg(client, GC0310_8BIT, @@ -718,7 +718,6 @@ static int gc0310_init(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); struct gc0310_device *dev = to_gc0310_sensor(sd); - pr_info("%s S\n", __func__); mutex_lock(&dev->input_lock); /* set initial registers */ @@ -730,7 +729,6 @@ static int gc0310_init(struct v4l2_subdev *sd) mutex_unlock(&dev->input_lock); - pr_info("%s E\n", __func__); return ret; } @@ -796,7 +794,6 @@ static int power_up(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - pr_info("%s S\n", __func__); if (!dev->platform_data) { dev_err(&client->dev, "no camera_sensor_platform_data"); @@ -823,7 +820,6 @@ static int power_up(struct v4l2_subdev *sd) msleep(100); - pr_info("%s E\n", __func__); return 0; fail_gpio: @@ -959,20 +955,17 @@ static int startup(struct v4l2_subdev *sd) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - pr_info("%s S\n", __func__); - ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs); if (ret) { dev_err(&client->dev, "gc0310 write register err.\n"); return ret; } - pr_info("%s E\n", __func__); return ret; } static int gc0310_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -982,8 +975,6 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd, int ret = 0; int idx = 0; - pr_info("%s S\n", __func__); - if (format->pad) return -EINVAL; @@ -1008,7 +999,7 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; mutex_unlock(&dev->input_lock); return 0; } @@ -1020,8 +1011,8 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd, return -EINVAL; } - printk("%s: before gc0310_write_reg_array %s\n", __func__, - gc0310_res[dev->fmt_idx].desc); + dev_dbg(&client->dev, "%s: before gc0310_write_reg_array %s\n", + __func__, gc0310_res[dev->fmt_idx].desc); ret = startup(sd); if (ret) { dev_err(&client->dev, "gc0310 startup err\n"); @@ -1035,14 +1026,13 @@ static int gc0310_set_fmt(struct v4l2_subdev *sd, goto err; } - pr_info("%s E\n", __func__); err: mutex_unlock(&dev->input_lock); return ret; } static int gc0310_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -1068,7 +1058,6 @@ static int gc0310_detect(struct i2c_client *client) int ret; u16 id; - pr_info("%s S\n", __func__); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -1085,7 +1074,7 @@ static int gc0310_detect(struct i2c_client *client) return -ENODEV; } id = ((((u16)high) << 8) | (u16)low); - pr_info("sensor ID = 0x%x\n", id); + dev_dbg(&client->dev, "sensor ID = 0x%x\n", id); if (id != GC0310_ID) { dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id, @@ -1095,8 +1084,6 @@ static int gc0310_detect(struct i2c_client *client) dev_dbg(&client->dev, "detect gc0310 success\n"); - pr_info("%s E\n", __func__); - return 0; } @@ -1106,7 +1093,7 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; - pr_info("%s S enable=%d\n", __func__, enable); + dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable); mutex_lock(&dev->input_lock); if (enable) { @@ -1142,7 +1129,6 @@ static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) } mutex_unlock(&dev->input_lock); - pr_info("%s E\n", __func__); return ret; } @@ -1153,7 +1139,6 @@ static int gc0310_s_config(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; - pr_info("%s S\n", __func__); if (!platform_data) return -ENODEV; @@ -1196,7 +1181,6 @@ static int gc0310_s_config(struct v4l2_subdev *sd, } mutex_unlock(&dev->input_lock); - pr_info("%s E\n", __func__); return 0; fail_csi_cfg: @@ -1221,7 +1205,7 @@ static int gc0310_g_frame_interval(struct v4l2_subdev *sd, } static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= MAX_FMTS) @@ -1232,7 +1216,7 @@ static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, } static int gc0310_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { int index = fse->index; @@ -1365,7 +1349,6 @@ static int gc0310_probe(struct i2c_client *client) if (ret) gc0310_remove(client); - pr_info("%s E\n", __func__); return ret; out_free: v4l2_device_unregister_subdev(&dev->sd); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 78147ffb6099..9363c1a52ae9 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -171,8 +171,8 @@ static int __gc2235_buf_reg_array(struct i2c_client *client, } static int __gc2235_write_reg_is_consecutive(struct i2c_client *client, - struct gc2235_write_ctrl *ctrl, - const struct gc2235_reg *next) + struct gc2235_write_ctrl *ctrl, + const struct gc2235_reg *next) { if (ctrl->index == 0) return 1; @@ -228,7 +228,7 @@ static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val) static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val) { - /*const f number for imx*/ + /* const f number for imx */ *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM; return 0; } @@ -427,7 +427,8 @@ static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return 0; } -/* This returns the exposure time being used. This should only be used +/* + * This returns the exposure time being used. This should only be used * for filling in EXIF data, not for actual image processing. */ static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value) @@ -658,9 +659,9 @@ static int gc2235_s_power(struct v4l2_subdev *sd, int on) { int ret; - if (on == 0) + if (on == 0) { ret = power_down(sd); - else { + } else { ret = power_up(sd); if (!ret) ret = __gc2235_init(sd); @@ -746,11 +747,12 @@ static int startup(struct v4l2_subdev *sd) int ret = 0; if (is_init == 0) { - /* force gc2235 to do a reset in res change, otherwise it - * can not output normal after switching res. and it is not - * necessary for first time run up after power on, for the sack - * of performance - */ + /* + * force gc2235 to do a reset in res change, otherwise it + * can not output normal after switching res. and it is not + * necessary for first time run up after power on, for the sack + * of performance + */ power_down(sd); power_up(sd); gc2235_write_reg_array(client, gc2235_init_settings); @@ -767,7 +769,7 @@ static int startup(struct v4l2_subdev *sd) } static int gc2235_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -796,7 +798,7 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd, } fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; mutex_unlock(&dev->input_lock); return 0; } @@ -825,7 +827,7 @@ err: } static int gc2235_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -904,7 +906,8 @@ static int gc2235_s_config(struct v4l2_subdev *sd, (struct camera_sensor_platform_data *)platform_data; mutex_lock(&dev->input_lock); - /* power off the module, then power on it in future + /* + * power off the module, then power on it in future * as first power on by board may not fulfill the * power on sequqence needed by the module */ @@ -963,7 +966,7 @@ static int gc2235_g_frame_interval(struct v4l2_subdev *sd, } static int gc2235_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= MAX_FMTS) @@ -974,7 +977,7 @@ static int gc2235_enum_mbus_code(struct v4l2_subdev *sd, } static int gc2235_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { int index = fse->index; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c index b93c80471f22..7a20d918a9d5 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c @@ -50,14 +50,16 @@ struct tbd_data_record_header { static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr, unsigned int size) { - /* The configuration data contains any number of sequences where + /* + * The configuration data contains any number of sequences where * the first byte (that is, uint8_t) that marks the number of bytes * in the sequence to follow, is indeed followed by the indicated * number of bytes of actual data to be written to sensor. * By convention, the first two bytes of actual data should be * understood as an address in the sensor address space (hibyte * followed by lobyte) where the remaining data in the sequence - * will be written. */ + * will be written. + */ u8 *ptr = bufptr; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index f5de81132177..11196180a206 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -475,10 +475,12 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Note: current modules wire only one GPIO signal (RESET#), + /* + * Note: current modules wire only one GPIO signal (RESET#), * but the schematic wires up two to the connector. BIOS * versions have been unfortunately inconsistent with which - * ACPI index RESET# is on, so hit both */ + * ACPI index RESET# is on, so hit both + */ if (flag) { ret = dev->platform_data->gpio0_ctrl(sd, 0); @@ -560,7 +562,7 @@ static int power_down(struct v4l2_subdev *sd) if (ret) dev_err(&client->dev, "vprog failed.\n"); - /*according to DS, 20ms is needed after power down*/ + /* according to DS, 20ms is needed after power down */ msleep(20); return ret; @@ -568,9 +570,9 @@ static int power_down(struct v4l2_subdev *sd) static int mt9m114_s_power(struct v4l2_subdev *sd, int power) { - if (power == 0) + if (power == 0) { return power_down(sd); - else { + } else { if (power_up(sd)) return -EINVAL; @@ -801,7 +803,7 @@ static int mt9m114_get_intg_factor(struct i2c_client *client, } static int mt9m114_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -822,7 +824,7 @@ static int mt9m114_get_fmt(struct v4l2_subdev *sd, } static int mt9m114_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -846,7 +848,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, mt9m114_try_res(&width, &height); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; return 0; } res_index = mt9m114_to_res(width, height); @@ -947,7 +949,7 @@ static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val) static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val) { - /*const f number for mt9m114*/ + /* const f number for mt9m114 */ *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM; return 0; } @@ -998,44 +1000,48 @@ static long mt9m114_s_exposure(struct v4l2_subdev *sd, struct mt9m114_device *dev = to_mt9m114_sensor(sd); int ret = 0; unsigned int coarse_integration = 0; - unsigned int FLines = 0; - unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */ - unsigned int AnalogGain, DigitalGain; - u32 AnalogGainToWrite = 0; + unsigned int f_lines = 0; + unsigned int frame_len_lines = 0; /* ExposureTime.FrameLengthLines; */ + unsigned int analog_gain, digital_gain; + u32 analog_gain_to_write = 0; dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__, exposure->integration_time[0], exposure->gain[0], exposure->gain[1]); coarse_integration = exposure->integration_time[0]; - /* fine_integration = ExposureTime.FineIntegrationTime; */ - /* FrameLengthLines = ExposureTime.FrameLengthLines; */ - FLines = mt9m114_res[dev->res].lines_per_frame; - AnalogGain = exposure->gain[0]; - DigitalGain = exposure->gain[1]; + /* + * fine_integration = ExposureTime.FineIntegrationTime; + * frame_len_lines = ExposureTime.FrameLengthLines; + */ + f_lines = mt9m114_res[dev->res].lines_per_frame; + analog_gain = exposure->gain[0]; + digital_gain = exposure->gain[1]; if (!dev->streamon) { /*Save the first exposure values while stream is off*/ dev->first_exp = coarse_integration; - dev->first_gain = AnalogGain; - dev->first_diggain = DigitalGain; + dev->first_gain = analog_gain; + dev->first_diggain = digital_gain; } - /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) + - ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */ + /* digital_gain = 0x400 * (((u16) digital_gain) >> 8) + */ + /* ((unsigned int)(0x400 * (((u16) digital_gain) & 0xFF)) >>8); */ /* set frame length */ - if (FLines < coarse_integration + 6) - FLines = coarse_integration + 6; - if (FLines < FrameLengthLines) - FLines = FrameLengthLines; - ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines); + if (f_lines < coarse_integration + 6) + f_lines = coarse_integration + 6; + if (f_lines < frame_len_lines) + f_lines = frame_len_lines; + ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, f_lines); if (ret) { - v4l2_err(client, "%s: fail to set FLines\n", __func__); + v4l2_err(client, "%s: fail to set f_lines\n", __func__); return -EINVAL; } /* set coarse integration */ - /* 3A provide real exposure time. - should not translate to any value here. */ + /* + * 3A provide real exposure time. + * should not translate to any value here. + */ ret = mt9m114_write_reg(client, MISENSOR_16BIT, REG_EXPO_COARSE, (u16)(coarse_integration)); if (ret) { @@ -1044,38 +1050,40 @@ static long mt9m114_s_exposure(struct v4l2_subdev *sd, } /* - // set analog/digital gain - switch(AnalogGain) + * set analog/digital gain + switch(analog_gain) { case 0: - AnalogGainToWrite = 0x0; + analog_gain_to_write = 0x0; break; case 1: - AnalogGainToWrite = 0x20; + analog_gain_to_write = 0x20; break; case 2: - AnalogGainToWrite = 0x60; + analog_gain_to_write = 0x60; break; case 4: - AnalogGainToWrite = 0xA0; + analog_gain_to_write = 0xA0; break; case 8: - AnalogGainToWrite = 0xE0; + analog_gain_to_write = 0xE0; break; default: - AnalogGainToWrite = 0x20; + analog_gain_to_write = 0x20; break; } */ - if (DigitalGain >= 16 || DigitalGain <= 1) - DigitalGain = 1; - /* AnalogGainToWrite = - (u16)((DigitalGain << 12) | AnalogGainToWrite); */ - AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain); + if (digital_gain >= 16 || digital_gain <= 1) + digital_gain = 1; + /* + * analog_gain_to_write = (u16)((digital_gain << 12) + * | analog_gain_to_write); + */ + analog_gain_to_write = (u16)((digital_gain << 12) | (u16)analog_gain); ret = mt9m114_write_reg(client, MISENSOR_16BIT, - REG_GAIN, AnalogGainToWrite); + REG_GAIN, analog_gain_to_write); if (ret) { - v4l2_err(client, "%s: fail to set AnalogGainToWrite\n", + v4l2_err(client, "%s: fail to set analog_gain_to_write\n", __func__); return -EINVAL; } @@ -1095,8 +1103,10 @@ static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return 0; } -/* This returns the exposure time being used. This should only be used - for filling in EXIF data, not for actual image processing. */ +/* + * This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1158,7 +1168,7 @@ static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val) * This function is for touch exposure feature. */ static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1247,7 +1257,8 @@ static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val) s32 luma = 0x37; int err; - /* EV value only support -2 to 2 + /* + * EV value only support -2 to 2 * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17 */ if (val < -2 || val > 2) @@ -1295,9 +1306,10 @@ static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val) return 0; } -/* Fake interface +/* + * Fake interface * mt9m114 now can not support 3a_lock -*/ + */ static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val) { aaalock = val; @@ -1719,7 +1731,7 @@ static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable) } static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index) @@ -1730,7 +1742,7 @@ static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd, } static int mt9m114_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { unsigned int index = fse->index; @@ -1843,7 +1855,7 @@ static int mt9m114_probe(struct i2c_client *client) return ret; } - /*TODO add format code here*/ + /* TODO add format code here */ dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; dev->pad.flags = MEDIA_PAD_FL_SOURCE; dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index c90730513438..2111e4a478c1 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -127,7 +127,7 @@ static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val) static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) { - /*const f number for ov2680*/ + /* const f number for ov2680 */ *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; return 0; @@ -399,7 +399,8 @@ static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return 0; } -/* This returns the exposure time being used. This should only be used +/* + * This returns the exposure time being used. This should only be used * for filling in EXIF data, not for actual image processing. */ static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) @@ -461,11 +462,11 @@ static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) ret = ov2680_read_reg(client, 1, OV2680_FLIP_REG, &val); if (ret) return ret; - if (value) { + if (value) val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - } else { + else val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - } + ret = ov2680_write_reg(client, 1, OV2680_FLIP_REG, val); if (ret) @@ -727,11 +728,13 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* The OV2680 documents only one GPIO input (#XSHUTDN), but + /* + * The OV2680 documents only one GPIO input (#XSHUTDN), but * existing integrations often wire two (reset/power_down) * because that is the way other sensors work. There is no * way to tell how it is wired internally, so existing - * firmwares expose both and we drive them symmetrically. */ + * firmwares expose both and we drive them symmetrically. + */ if (flag) { ret = dev->platform_data->gpio0_ctrl(sd, 1); usleep_range(10000, 15000); @@ -911,7 +914,7 @@ static int get_resolution_index(int w, int h) } static int ov2680_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -948,7 +951,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, } fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; mutex_unlock(&dev->input_lock); return 0; } @@ -977,7 +980,8 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, goto err; } - /*recall flip functions to avoid flip registers + /* + * recall flip functions to avoid flip registers * were overridden by default setting */ if (h_flag) @@ -987,7 +991,8 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, v4l2_info(client, "\n%s idx %d\n", __func__, dev->fmt_idx); - /*ret = startup(sd); + /* + * ret = startup(sd); * if (ret) * dev_err(&client->dev, "ov2680 startup err\n"); */ @@ -997,7 +1002,7 @@ err: } static int ov2680_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -1096,7 +1101,8 @@ static int ov2680_s_config(struct v4l2_subdev *sd, (struct camera_sensor_platform_data *)platform_data; mutex_lock(&dev->input_lock); - /* power off the module, then power on it in future + /* + * power off the module, then power on it in future * as first power on by board may not fulfill the * power on sequqence needed by the module */ @@ -1155,7 +1161,7 @@ static int ov2680_g_frame_interval(struct v4l2_subdev *sd, } static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= MAX_FMTS) @@ -1166,7 +1172,7 @@ static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, } static int ov2680_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { int index = fse->index; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 1209492c1826..90d0871a78a3 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -49,8 +49,8 @@ static int ov2722_read_reg(struct i2c_client *client, return -ENODEV; } - if (data_length != OV2722_8BIT && data_length != OV2722_16BIT - && data_length != OV2722_32BIT) { + if (data_length != OV2722_8BIT && data_length != OV2722_16BIT && + data_length != OV2722_32BIT) { dev_err(&client->dev, "%s error, invalid data length\n", __func__); return -EINVAL; @@ -212,8 +212,8 @@ static int __ov2722_buf_reg_array(struct i2c_client *client, } static int __ov2722_write_reg_is_consecutive(struct i2c_client *client, - struct ov2722_write_ctrl *ctrl, - const struct ov2722_reg *next) + struct ov2722_write_ctrl *ctrl, + const struct ov2722_reg *next) { if (ctrl->index == 0) return 1; @@ -774,11 +774,11 @@ static int ov2722_s_power(struct v4l2_subdev *sd, int on) if (on == 0) return power_down(sd); - else { - ret = power_up(sd); - if (!ret) - return ov2722_init(sd); - } + + ret = power_up(sd); + if (!ret) + return ov2722_init(sd); + return ret; } @@ -876,7 +876,7 @@ static int startup(struct v4l2_subdev *sd) } static int ov2722_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -906,7 +906,7 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd, } fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; mutex_unlock(&dev->input_lock); return 0; } @@ -961,7 +961,7 @@ err: } static int ov2722_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -1104,7 +1104,7 @@ static int ov2722_g_frame_interval(struct v4l2_subdev *sd, } static int ov2722_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= MAX_FMTS) @@ -1115,7 +1115,7 @@ static int ov2722_enum_mbus_code(struct v4l2_subdev *sd, } static int ov2722_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { int index = fse->index; diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h index 787bbf59e895..bcce18b65fa6 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.h +++ b/drivers/staging/media/atomisp/i2c/mt9m114.h @@ -764,8 +764,10 @@ static struct misensor_reg const mt9m114_common[] = { {MISENSOR_8BIT, 0xC85C, 0x03}, /* cam_crop_cropmode = 3 */ {MISENSOR_16BIT, 0xC868, 0x0280}, /* cam_output_width = 952 */ {MISENSOR_16BIT, 0xC86A, 0x01E0}, /* cam_output_height = 538 */ - /* LOAD = Step3-Recommended - * Patch,Errata and Sensor optimization Setting */ + /* + * LOAD = Step3-Recommended + * Patch, Errata and Sensor optimization Setting + */ {MISENSOR_16BIT, 0x316A, 0x8270}, /* DAC_TXLO_ROW */ {MISENSOR_16BIT, 0x316C, 0x8270}, /* DAC_TXLO */ {MISENSOR_16BIT, 0x3ED0, 0x2305}, /* DAC_LD_4_5 */ diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 49920245e064..4d43b45915e5 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -459,8 +459,8 @@ static struct ov2680_reg const ov2680_656x496_30fps[] = { }; /* -* 800x600 30fps VBlanking 1lane 10Bit (binning) -*/ + * 800x600 30fps VBlanking 1lane 10Bit (binning) + */ static struct ov2680_reg const ov2680_720x592_30fps[] = { {0x3086, 0x01}, {0x3501, 0x26}, @@ -504,8 +504,8 @@ static struct ov2680_reg const ov2680_720x592_30fps[] = { }; /* -* 800x600 30fps VBlanking 1lane 10Bit (binning) -*/ + * 800x600 30fps VBlanking 1lane 10Bit (binning) + */ static struct ov2680_reg const ov2680_800x600_30fps[] = { {0x3086, 0x01}, {0x3501, 0x26}, @@ -634,7 +634,7 @@ static struct ov2680_reg const ov2680_1296x976_30fps[] = { /* * 1456*1096 30fps VBlanking 1lane 10bit(no-scaling) -*/ + */ static struct ov2680_reg const ov2680_1456x1096_30fps[] = { {0x3086, 0x00}, {0x3501, 0x48}, diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index e698b63d6cb7..0828ca9ab6f2 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -1577,7 +1577,7 @@ static int startup(struct v4l2_subdev *sd) } static int ov5693_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -1608,7 +1608,7 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; mutex_unlock(&dev->input_lock); return 0; } @@ -1676,7 +1676,7 @@ err: } static int ov5693_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -1825,7 +1825,7 @@ static int ov5693_g_frame_interval(struct v4l2_subdev *sd, } static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= MAX_FMTS) @@ -1836,7 +1836,7 @@ static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, } static int ov5693_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { int index = fse->index; diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp_acc.c index f638d0bd09fe..9a1751895ab0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_acc.c +++ b/drivers/staging/media/atomisp/pci/atomisp_acc.c @@ -77,8 +77,8 @@ 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; + if (acc_fw->handle == handle) + return acc_fw; return NULL; } @@ -464,9 +464,11 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) 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. */ + /* + * 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) diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index 14abc1ca00e8..366161cff560 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -1138,9 +1138,10 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK; } - } else + } else { asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK; + } } else { asd->frame_status[vb->i] = ATOMISP_FRAME_STATUS_OK; } @@ -4841,6 +4842,9 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; 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, }; @@ -4876,7 +4880,7 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, snr_mbus_fmt->width, snr_mbus_fmt->height); ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - pad, set_fmt, &pad_cfg, &format); + pad, set_fmt, &pad_state, &format); if (ret) return ret; @@ -4941,9 +4945,9 @@ atomisp_try_fmt_file(struct atomisp_device *isp, struct v4l2_format *f) depth = get_pixel_depth(pixelformat); - if (field == V4L2_FIELD_ANY) + if (field == V4L2_FIELD_ANY) { field = V4L2_FIELD_NONE; - else if (field != V4L2_FIELD_NONE) { + } else if (field != V4L2_FIELD_NONE) { dev_err(isp->dev, "Wrong output field\n"); return -EINVAL; } @@ -5251,11 +5255,11 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, atomisp_output_fmts[] in atomisp_v4l2.c */ vf_ffmt.code = V4L2_MBUS_FMT_CUSTOM_YUV420; - atomisp_subdev_set_selection(&asd->subdev, fh.pad, + atomisp_subdev_set_selection(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SOURCE_VF, V4L2_SEL_TGT_COMPOSE, 0, &vf_size); - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, + atomisp_subdev_set_ffmt(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SOURCE_VF, &vf_ffmt); asd->video_out_vf.sh_fmt = IA_CSS_FRAME_FORMAT_NV12; @@ -5492,6 +5496,9 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; const struct atomisp_format_bridge *format; struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_state pad_state = { + .pads = &pad_cfg + }; struct v4l2_subdev_format vformat = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -5530,7 +5537,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) { vformat.which = V4L2_SUBDEV_FORMAT_TRY; ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - pad, set_fmt, &pad_cfg, &vformat); + pad, set_fmt, &pad_state, &vformat); if (ret) return ret; if (ffmt->width < req_ffmt->width || @@ -5568,7 +5575,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, asd->params.video_dis_en = false; } - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, + atomisp_subdev_set_ffmt(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK, ffmt); @@ -5647,7 +5654,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) } atomisp_subdev_set_selection( - &asd->subdev, fh.pad, + &asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, source_pad, V4L2_SEL_TGT_COMPOSE, 0, &r); @@ -5777,7 +5784,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) ATOMISP_SUBDEV_PAD_SINK); isp_source_fmt.code = format_bridge->mbus_code; - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, + atomisp_subdev_set_ffmt(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, source_pad, &isp_source_fmt); @@ -5896,13 +5903,13 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) isp_sink_crop.height = f->fmt.pix.height; } - atomisp_subdev_set_selection(&asd->subdev, fh.pad, + atomisp_subdev_set_selection(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK, V4L2_SEL_TGT_CROP, V4L2_SEL_FLAG_KEEP_CONFIG, &isp_sink_crop); - atomisp_subdev_set_selection(&asd->subdev, fh.pad, + atomisp_subdev_set_selection(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, source_pad, V4L2_SEL_TGT_COMPOSE, 0, &isp_sink_crop); @@ -5921,7 +5928,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) f->fmt.pix.height); } - atomisp_subdev_set_selection(&asd->subdev, fh.pad, + atomisp_subdev_set_selection(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, source_pad, V4L2_SEL_TGT_COMPOSE, 0, @@ -5955,14 +5962,14 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) f->fmt.pix.width, ATOM_ISP_STEP_HEIGHT); } - atomisp_subdev_set_selection(&asd->subdev, fh.pad, + atomisp_subdev_set_selection(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK, V4L2_SEL_TGT_CROP, V4L2_SEL_FLAG_KEEP_CONFIG, &sink_crop); } - atomisp_subdev_set_selection(&asd->subdev, fh.pad, + atomisp_subdev_set_selection(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, source_pad, V4L2_SEL_TGT_COMPOSE, 0, @@ -6053,7 +6060,8 @@ int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f) ffmt.height = f->fmt.pix.height; ffmt.code = format_bridge->mbus_code; - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, V4L2_SUBDEV_FORMAT_ACTIVE, + atomisp_subdev_set_ffmt(&asd->subdev, fh.state, + V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK, &ffmt); return 0; @@ -6564,17 +6572,17 @@ static int atomisp_get_pipe_id(struct atomisp_video_pipe *pipe) { struct atomisp_sub_device *asd = pipe->asd; - if (ATOMISP_USE_YUVPP(asd)) + if (ATOMISP_USE_YUVPP(asd)) { return IA_CSS_PIPE_ID_YUVPP; - else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) + } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { return IA_CSS_PIPE_ID_VIDEO; - else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) + } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { return IA_CSS_PIPE_ID_CAPTURE; - else if (pipe == &asd->video_out_video_capture) + } else if (pipe == &asd->video_out_video_capture) { return IA_CSS_PIPE_ID_VIDEO; - else if (pipe == &asd->video_out_vf) + } else if (pipe == &asd->video_out_vf) { return IA_CSS_PIPE_ID_CAPTURE; - else if (pipe == &asd->video_out_preview) { + } else if (pipe == &asd->video_out_preview) { if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) return IA_CSS_PIPE_ID_VIDEO; else diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index 412baeb91944..e8bdd264d31b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -49,9 +49,7 @@ struct ia_css_frame; /* FIXME: check if can go */ extern int atomisp_punit_hpll_freq; -/* - * Helper function - */ +/* Helper function */ void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr, unsigned int size); struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd); @@ -65,9 +63,7 @@ bool atomisp_buffers_queued(struct atomisp_sub_device *asd); /* ISP2401 */ bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe); -/* - * Interrupt functions - */ +/* Interrupt functions */ void atomisp_msi_irq_init(struct atomisp_device *isp); void atomisp_msi_irq_uninit(struct atomisp_device *isp); void atomisp_wdt_work(struct work_struct *work); @@ -82,15 +78,10 @@ int atomisp_get_frame_pgnr(struct atomisp_device *isp, const struct ia_css_frame *frame, u32 *p_pgnr); void atomisp_delayed_init_work(struct work_struct *work); -/* - * Get internal fmt according to V4L2 fmt - */ - +/* Get internal fmt according to V4L2 fmt */ bool atomisp_is_viewfinder_support(struct atomisp_device *isp); -/* - * ISP features control function - */ +/* ISP features control function */ /* * Function to set sensor runmode by user when @@ -105,9 +96,7 @@ int atomisp_set_sensor_runmode(struct atomisp_sub_device *asd, int atomisp_gdc_cac(struct atomisp_sub_device *asd, int flag, __s32 *value); -/* - * Function to enable/disable low light mode (including ANR) - */ +/* Function to enable/disable low light mode (including ANR) */ int atomisp_low_light(struct atomisp_sub_device *asd, int flag, __s32 *value); @@ -120,91 +109,63 @@ int atomisp_xnr(struct atomisp_sub_device *asd, int flag, int *arg); int atomisp_formats(struct atomisp_sub_device *asd, int flag, struct atomisp_formats_config *config); -/* - * Function to configure noise reduction - */ +/* Function to configure noise reduction */ int atomisp_nr(struct atomisp_sub_device *asd, int flag, struct atomisp_nr_config *config); -/* - * Function to configure temporal noise reduction (TNR) - */ +/* Function to configure temporal noise reduction (TNR) */ int atomisp_tnr(struct atomisp_sub_device *asd, int flag, struct atomisp_tnr_config *config); -/* - * Function to configure black level compensation - */ +/* Function to configure black level compensation */ int atomisp_black_level(struct atomisp_sub_device *asd, int flag, struct atomisp_ob_config *config); -/* - * Function to configure edge enhancement - */ +/* Function to configure edge enhancement */ int atomisp_ee(struct atomisp_sub_device *asd, int flag, struct atomisp_ee_config *config); -/* - * Function to update Gamma table for gamma, brightness and contrast config - */ +/* Function to update Gamma table for gamma, brightness and contrast config */ int atomisp_gamma(struct atomisp_sub_device *asd, int flag, struct atomisp_gamma_table *config); -/* - * Function to update Ctc table for Chroma Enhancement - */ + +/* Function to update Ctc table for Chroma Enhancement */ int atomisp_ctc(struct atomisp_sub_device *asd, int flag, struct atomisp_ctc_table *config); -/* - * Function to update gamma correction parameters - */ +/* Function to update gamma correction parameters */ int atomisp_gamma_correction(struct atomisp_sub_device *asd, int flag, struct atomisp_gc_config *config); -/* - * Function to update Gdc table for gdc - */ +/* Function to update Gdc table for gdc */ int atomisp_gdc_cac_table(struct atomisp_sub_device *asd, int flag, struct atomisp_morph_table *config); -/* - * Function to update table for macc - */ +/* Function to update table for macc */ int atomisp_macc_table(struct atomisp_sub_device *asd, int flag, struct atomisp_macc_config *config); -/* - * Function to get DIS statistics. - */ + +/* Function to get DIS statistics. */ int atomisp_get_dis_stat(struct atomisp_sub_device *asd, struct atomisp_dis_statistics *stats); -/* - * Function to get DVS2 BQ resolution settings - */ +/* Function to get DVS2 BQ resolution settings */ int atomisp_get_dvs2_bq_resolutions(struct atomisp_sub_device *asd, struct atomisp_dvs2_bq_resolutions *bq_res); -/* - * Function to set the DIS coefficients. - */ +/* Function to set the DIS coefficients. */ int atomisp_set_dis_coefs(struct atomisp_sub_device *asd, struct atomisp_dis_coefficients *coefs); -/* - * Function to set the DIS motion vector. - */ +/* Function to set the DIS motion vector. */ int atomisp_set_dis_vector(struct atomisp_sub_device *asd, struct atomisp_dis_vector *vector); -/* - * Function to set/get 3A stat from isp - */ +/* Function to set/get 3A stat from isp */ int atomisp_3a_stat(struct atomisp_sub_device *asd, int flag, struct atomisp_3a_statistics *config); -/* - * Function to get metadata from isp - */ +/* Function to get metadata from isp */ int atomisp_get_metadata(struct atomisp_sub_device *asd, int flag, struct atomisp_metadata *config); @@ -213,84 +174,59 @@ int atomisp_get_metadata_by_type(struct atomisp_sub_device *asd, int flag, int atomisp_set_parameters(struct video_device *vdev, struct atomisp_parameters *arg); -/* - * Function to set/get isp parameters to isp - */ + +/* Function to set/get isp parameters to isp */ int atomisp_param(struct atomisp_sub_device *asd, int flag, struct atomisp_parm *config); -/* - * Function to configure color effect of the image - */ +/* Function to configure color effect of the image */ int atomisp_color_effect(struct atomisp_sub_device *asd, int flag, __s32 *effect); -/* - * Function to configure bad pixel correction - */ +/* Function to configure bad pixel correction */ int atomisp_bad_pixel(struct atomisp_sub_device *asd, int flag, __s32 *value); -/* - * Function to configure bad pixel correction params - */ +/* Function to configure bad pixel correction params */ int atomisp_bad_pixel_param(struct atomisp_sub_device *asd, int flag, struct atomisp_dp_config *config); -/* - * Function to enable/disable video image stablization - */ +/* Function to enable/disable video image stablization */ int atomisp_video_stable(struct atomisp_sub_device *asd, int flag, __s32 *value); -/* - * Function to configure fixed pattern noise - */ +/* Function to configure fixed pattern noise */ int atomisp_fixed_pattern(struct atomisp_sub_device *asd, int flag, __s32 *value); -/* - * Function to configure fixed pattern noise table - */ +/* Function to configure fixed pattern noise table */ int atomisp_fixed_pattern_table(struct atomisp_sub_device *asd, struct v4l2_framebuffer *config); -/* - * Function to configure false color correction - */ +/* Function to configure false color correction */ int atomisp_false_color(struct atomisp_sub_device *asd, int flag, __s32 *value); -/* - * Function to configure false color correction params - */ +/* Function to configure false color correction params */ int atomisp_false_color_param(struct atomisp_sub_device *asd, int flag, struct atomisp_de_config *config); -/* - * Function to configure white balance params - */ +/* Function to configure white balance params */ int atomisp_white_balance_param(struct atomisp_sub_device *asd, int flag, struct atomisp_wb_config *config); int atomisp_3a_config_param(struct atomisp_sub_device *asd, int flag, struct atomisp_3a_config *config); -/* - * Function to setup digital zoom - */ +/* Function to setup digital zoom */ int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag, __s32 *value); -/* - * Function set camera_prefiles.xml current sensor pixel array size - */ +/* Function set camera_prefiles.xml current sensor pixel array size */ int atomisp_set_array_res(struct atomisp_sub_device *asd, struct atomisp_resolution *config); -/* - * Function to calculate real zoom region for every pipe - */ +/* Function to calculate real zoom region for every pipe */ int atomisp_calculate_real_zoom_region(struct atomisp_sub_device *asd, struct ia_css_dz_config *dz_config, enum ia_css_pipe_id css_pipe_id); @@ -371,9 +307,7 @@ void atomisp_css_flush(struct atomisp_device *isp); int atomisp_source_pad_to_stream_id(struct atomisp_sub_device *asd, uint16_t source_pad); -/* - * Events. Only one event has to be exported for now. - */ +/* Events. Only one event has to be exported for now. */ void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id); enum mipi_port_id __get_mipi_port(struct atomisp_device *isp, @@ -389,34 +323,25 @@ void atomisp_free_css_parameters(struct atomisp_css_params *css_param); void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe); void atomisp_flush_params_queue(struct atomisp_video_pipe *asd); -/* - * Function to do Raw Buffer related operation, after enable Lock Unlock Raw Buffer - */ + +/* Function to do Raw Buffer related operation, after enable Lock Unlock Raw Buffer */ int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id); int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id); -/* - * Function to update Raw Buffer bitmap - */ +/* Function to update Raw Buffer bitmap */ int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id); void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd); -/* - * Function to enable/disable zoom for capture pipe - */ +/* Function to enable/disable zoom for capture pipe */ int atomisp_enable_dz_capt_pipe(struct atomisp_sub_device *asd, unsigned int *enable); -/* - * Function to get metadata type bu pipe id - */ +/* Function to get metadata type bu pipe id */ enum atomisp_metadata_type atomisp_get_metadata_type(struct atomisp_sub_device *asd, enum ia_css_pipe_id pipe_id); -/* - * Function for HAL to inject a fake event to wake up poll thread - */ +/* Function for HAL to inject a fake event to wake up poll thread */ int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event); /* diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index ce3165291eec..f60198bb8a1a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -2782,9 +2782,9 @@ int atomisp_get_css_frame_info(struct atomisp_sub_device *asd, int stream_index; struct atomisp_device *isp = asd->isp; - if (ATOMISP_SOC_CAMERA(asd)) + if (ATOMISP_SOC_CAMERA(asd)) { stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); - else { + } else { stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ? ATOMISP_INPUT_STREAM_VIDEO : atomisp_source_pad_to_stream_id(asd, source_pad); diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c b/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c deleted file mode 100644 index e5553df5bad4..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.c +++ /dev/null @@ -1,1202 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Support for Intel Camera Imaging ISP subsystem. - * - * Copyright (c) 2013 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. - * - * - */ -#ifdef CONFIG_COMPAT -#include <linux/compat.h> - -#include <linux/videodev2.h> - -#include "atomisp_internal.h" -#include "atomisp_compat.h" -#include "atomisp_ioctl.h" -#include "atomisp_compat_ioctl32.h" - -/* Macros borrowed from v4l2-compat-ioctl32.c */ - -#define get_user_cast(__x, __ptr) \ -({ \ - get_user(__x, (typeof(*__ptr) __user *)(__ptr)); \ -}) - -#define put_user_force(__x, __ptr) \ -({ \ - put_user((typeof(*__x) __force *)(__x), __ptr); \ -}) - -/* Use the same argument order as copy_in_user */ -#define assign_in_user(to, from) \ -({ \ - typeof(*from) __assign_tmp; \ - \ - get_user_cast(__assign_tmp, from) || put_user(__assign_tmp, to);\ -}) - -static int get_atomisp_histogram32(struct atomisp_histogram __user *kp, - struct atomisp_histogram32 __user *up) -{ - compat_uptr_t tmp; - - if (!access_ok(up, sizeof(struct atomisp_histogram32)) || - assign_in_user(&kp->num_elements, &up->num_elements) || - get_user(tmp, &up->data) || - put_user(compat_ptr(tmp), &kp->data)) - return -EFAULT; - - return 0; -} - -static int put_atomisp_histogram32(struct atomisp_histogram __user *kp, - struct atomisp_histogram32 __user *up) -{ - void __user *tmp; - - if (!access_ok(up, sizeof(struct atomisp_histogram32)) || - assign_in_user(&up->num_elements, &kp->num_elements) || - get_user(tmp, &kp->data) || - put_user(ptr_to_compat(tmp), &up->data)) - return -EFAULT; - - return 0; -} - -static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp, - struct v4l2_framebuffer32 __user *up) -{ - compat_uptr_t tmp; - - if (!access_ok(up, sizeof(struct v4l2_framebuffer32)) || - get_user(tmp, &up->base) || - put_user_force(compat_ptr(tmp), &kp->base) || - assign_in_user(&kp->capability, &up->capability) || - assign_in_user(&kp->flags, &up->flags) || - copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt))) - return -EFAULT; - - return 0; -} - -static int get_atomisp_dis_statistics32(struct atomisp_dis_statistics __user *kp, - struct atomisp_dis_statistics32 __user *up) -{ - compat_uptr_t hor_prod_odd_real; - compat_uptr_t hor_prod_odd_imag; - compat_uptr_t hor_prod_even_real; - compat_uptr_t hor_prod_even_imag; - compat_uptr_t ver_prod_odd_real; - compat_uptr_t ver_prod_odd_imag; - compat_uptr_t ver_prod_even_real; - compat_uptr_t ver_prod_even_imag; - - if (!access_ok(up, sizeof(struct atomisp_dis_statistics32)) || - copy_in_user(kp, up, sizeof(struct atomisp_dvs_grid_info)) || - get_user(hor_prod_odd_real, - &up->dvs2_stat.hor_prod.odd_real) || - get_user(hor_prod_odd_imag, - &up->dvs2_stat.hor_prod.odd_imag) || - get_user(hor_prod_even_real, - &up->dvs2_stat.hor_prod.even_real) || - get_user(hor_prod_even_imag, - &up->dvs2_stat.hor_prod.even_imag) || - get_user(ver_prod_odd_real, - &up->dvs2_stat.ver_prod.odd_real) || - get_user(ver_prod_odd_imag, - &up->dvs2_stat.ver_prod.odd_imag) || - get_user(ver_prod_even_real, - &up->dvs2_stat.ver_prod.even_real) || - get_user(ver_prod_even_imag, - &up->dvs2_stat.ver_prod.even_imag) || - assign_in_user(&kp->exp_id, &up->exp_id) || - put_user(compat_ptr(hor_prod_odd_real), - &kp->dvs2_stat.hor_prod.odd_real) || - put_user(compat_ptr(hor_prod_odd_imag), - &kp->dvs2_stat.hor_prod.odd_imag) || - put_user(compat_ptr(hor_prod_even_real), - &kp->dvs2_stat.hor_prod.even_real) || - put_user(compat_ptr(hor_prod_even_imag), - &kp->dvs2_stat.hor_prod.even_imag) || - put_user(compat_ptr(ver_prod_odd_real), - &kp->dvs2_stat.ver_prod.odd_real) || - put_user(compat_ptr(ver_prod_odd_imag), - &kp->dvs2_stat.ver_prod.odd_imag) || - put_user(compat_ptr(ver_prod_even_real), - &kp->dvs2_stat.ver_prod.even_real) || - put_user(compat_ptr(ver_prod_even_imag), - &kp->dvs2_stat.ver_prod.even_imag)) - return -EFAULT; - - return 0; -} - -static int put_atomisp_dis_statistics32(struct atomisp_dis_statistics __user *kp, - struct atomisp_dis_statistics32 __user *up) -{ - void __user *hor_prod_odd_real; - void __user *hor_prod_odd_imag; - void __user *hor_prod_even_real; - void __user *hor_prod_even_imag; - void __user *ver_prod_odd_real; - void __user *ver_prod_odd_imag; - void __user *ver_prod_even_real; - void __user *ver_prod_even_imag; - - if (!!access_ok(up, sizeof(struct atomisp_dis_statistics32)) || - copy_in_user(up, kp, sizeof(struct atomisp_dvs_grid_info)) || - get_user(hor_prod_odd_real, - &kp->dvs2_stat.hor_prod.odd_real) || - get_user(hor_prod_odd_imag, - &kp->dvs2_stat.hor_prod.odd_imag) || - get_user(hor_prod_even_real, - &kp->dvs2_stat.hor_prod.even_real) || - get_user(hor_prod_even_imag, - &kp->dvs2_stat.hor_prod.even_imag) || - get_user(ver_prod_odd_real, - &kp->dvs2_stat.ver_prod.odd_real) || - get_user(ver_prod_odd_imag, - &kp->dvs2_stat.ver_prod.odd_imag) || - get_user(ver_prod_even_real, - &kp->dvs2_stat.ver_prod.even_real) || - get_user(ver_prod_even_imag, - &kp->dvs2_stat.ver_prod.even_imag) || - put_user(ptr_to_compat(hor_prod_odd_real), - &up->dvs2_stat.hor_prod.odd_real) || - put_user(ptr_to_compat(hor_prod_odd_imag), - &up->dvs2_stat.hor_prod.odd_imag) || - put_user(ptr_to_compat(hor_prod_even_real), - &up->dvs2_stat.hor_prod.even_real) || - put_user(ptr_to_compat(hor_prod_even_imag), - &up->dvs2_stat.hor_prod.even_imag) || - put_user(ptr_to_compat(ver_prod_odd_real), - &up->dvs2_stat.ver_prod.odd_real) || - put_user(ptr_to_compat(ver_prod_odd_imag), - &up->dvs2_stat.ver_prod.odd_imag) || - put_user(ptr_to_compat(ver_prod_even_real), - &up->dvs2_stat.ver_prod.even_real) || - put_user(ptr_to_compat(ver_prod_even_imag), - &up->dvs2_stat.ver_prod.even_imag) || - assign_in_user(&up->exp_id, &kp->exp_id)) - return -EFAULT; - - return 0; -} - -static int get_atomisp_dis_coefficients32(struct atomisp_dis_coefficients __user *kp, - struct atomisp_dis_coefficients32 __user *up) -{ - compat_uptr_t hor_coefs_odd_real; - compat_uptr_t hor_coefs_odd_imag; - compat_uptr_t hor_coefs_even_real; - compat_uptr_t hor_coefs_even_imag; - compat_uptr_t ver_coefs_odd_real; - compat_uptr_t ver_coefs_odd_imag; - compat_uptr_t ver_coefs_even_real; - compat_uptr_t ver_coefs_even_imag; - - if (!access_ok(up, sizeof(struct atomisp_dis_coefficients32)) || - copy_in_user(kp, up, sizeof(struct atomisp_dvs_grid_info)) || - get_user(hor_coefs_odd_real, &up->hor_coefs.odd_real) || - get_user(hor_coefs_odd_imag, &up->hor_coefs.odd_imag) || - get_user(hor_coefs_even_real, &up->hor_coefs.even_real) || - get_user(hor_coefs_even_imag, &up->hor_coefs.even_imag) || - get_user(ver_coefs_odd_real, &up->ver_coefs.odd_real) || - get_user(ver_coefs_odd_imag, &up->ver_coefs.odd_imag) || - get_user(ver_coefs_even_real, &up->ver_coefs.even_real) || - get_user(ver_coefs_even_imag, &up->ver_coefs.even_imag) || - put_user(compat_ptr(hor_coefs_odd_real), - &kp->hor_coefs.odd_real) || - put_user(compat_ptr(hor_coefs_odd_imag), - &kp->hor_coefs.odd_imag) || - put_user(compat_ptr(hor_coefs_even_real), - &kp->hor_coefs.even_real) || - put_user(compat_ptr(hor_coefs_even_imag), - &kp->hor_coefs.even_imag) || - put_user(compat_ptr(ver_coefs_odd_real), - &kp->ver_coefs.odd_real) || - put_user(compat_ptr(ver_coefs_odd_imag), - &kp->ver_coefs.odd_imag) || - put_user(compat_ptr(ver_coefs_even_real), - &kp->ver_coefs.even_real) || - put_user(compat_ptr(ver_coefs_even_imag), - &kp->ver_coefs.even_imag)) - return -EFAULT; - - return 0; -} - -static int get_atomisp_dvs_6axis_config32(struct atomisp_dvs_6axis_config __user *kp, - struct atomisp_dvs_6axis_config32 __user *up) -{ - compat_uptr_t xcoords_y; - compat_uptr_t ycoords_y; - compat_uptr_t xcoords_uv; - compat_uptr_t ycoords_uv; - - if (!access_ok(up, sizeof(struct atomisp_dvs_6axis_config32)) || - assign_in_user(&kp->exp_id, &up->exp_id) || - assign_in_user(&kp->width_y, &up->width_y) || - assign_in_user(&kp->height_y, &up->height_y) || - assign_in_user(&kp->width_uv, &up->width_uv) || - assign_in_user(&kp->height_uv, &up->height_uv) || - get_user(xcoords_y, &up->xcoords_y) || - get_user(ycoords_y, &up->ycoords_y) || - get_user(xcoords_uv, &up->xcoords_uv) || - get_user(ycoords_uv, &up->ycoords_uv) || - put_user_force(compat_ptr(xcoords_y), &kp->xcoords_y) || - put_user_force(compat_ptr(ycoords_y), &kp->ycoords_y) || - put_user_force(compat_ptr(xcoords_uv), &kp->xcoords_uv) || - put_user_force(compat_ptr(ycoords_uv), &kp->ycoords_uv)) - return -EFAULT; - - return 0; -} - -static int get_atomisp_3a_statistics32(struct atomisp_3a_statistics __user *kp, - struct atomisp_3a_statistics32 __user *up) -{ - compat_uptr_t data; - compat_uptr_t rgby_data; - - if (!access_ok(up, sizeof(struct atomisp_3a_statistics32)) || - copy_in_user(kp, up, sizeof(struct atomisp_grid_info)) || - get_user(rgby_data, &up->rgby_data) || - put_user(compat_ptr(rgby_data), &kp->rgby_data) || - get_user(data, &up->data) || - put_user(compat_ptr(data), &kp->data) || - assign_in_user(&kp->exp_id, &up->exp_id) || - assign_in_user(&kp->isp_config_id, &up->isp_config_id)) - return -EFAULT; - - return 0; -} - -static int put_atomisp_3a_statistics32(struct atomisp_3a_statistics __user *kp, - struct atomisp_3a_statistics32 __user *up) -{ - void __user *data; - void __user *rgby_data; - - if (!access_ok(up, sizeof(struct atomisp_3a_statistics32)) || - copy_in_user(up, kp, sizeof(struct atomisp_grid_info)) || - get_user(rgby_data, &kp->rgby_data) || - put_user(ptr_to_compat(rgby_data), &up->rgby_data) || - get_user(data, &kp->data) || - put_user(ptr_to_compat(data), &up->data) || - assign_in_user(&up->exp_id, &kp->exp_id) || - assign_in_user(&up->isp_config_id, &kp->isp_config_id)) - return -EFAULT; - - return 0; -} - -static int get_atomisp_metadata_stat32(struct atomisp_metadata __user *kp, - struct atomisp_metadata32 __user *up) -{ - compat_uptr_t data; - compat_uptr_t effective_width; - - if (!access_ok(up, sizeof(struct atomisp_metadata32)) || - get_user(data, &up->data) || - put_user(compat_ptr(data), &kp->data) || - assign_in_user(&kp->width, &up->width) || - assign_in_user(&kp->height, &up->height) || - assign_in_user(&kp->stride, &up->stride) || - assign_in_user(&kp->exp_id, &up->exp_id) || - get_user(effective_width, &up->effective_width) || - put_user_force(compat_ptr(effective_width), &kp->effective_width)) - return -EFAULT; - - return 0; -} - -static int put_atomisp_metadata_stat32(struct atomisp_metadata __user *kp, - struct atomisp_metadata32 __user *up) -{ - void __user *data; - void *effective_width; - - if (!access_ok(up, sizeof(struct atomisp_metadata32)) || - get_user(data, &kp->data) || - put_user(ptr_to_compat(data), &up->data) || - assign_in_user(&up->width, &kp->width) || - assign_in_user(&up->height, &kp->height) || - assign_in_user(&up->stride, &kp->stride) || - assign_in_user(&up->exp_id, &kp->exp_id) || - get_user(effective_width, &kp->effective_width) || - put_user(ptr_to_compat((void __user *)effective_width), - &up->effective_width)) - return -EFAULT; - - return 0; -} - -static int -put_atomisp_metadata_by_type_stat32(struct atomisp_metadata_with_type __user *kp, - struct atomisp_metadata_with_type32 __user *up) -{ - void __user *data; - u32 *effective_width; - - if (!access_ok(up, sizeof(struct atomisp_metadata_with_type32)) || - get_user(data, &kp->data) || - put_user(ptr_to_compat(data), &up->data) || - assign_in_user(&up->width, &kp->width) || - assign_in_user(&up->height, &kp->height) || - assign_in_user(&up->stride, &kp->stride) || - assign_in_user(&up->exp_id, &kp->exp_id) || - get_user(effective_width, &kp->effective_width) || - put_user(ptr_to_compat((void __user *)effective_width), - &up->effective_width) || - assign_in_user(&up->type, &kp->type)) - return -EFAULT; - - return 0; -} - -static int -get_atomisp_metadata_by_type_stat32(struct atomisp_metadata_with_type __user *kp, - struct atomisp_metadata_with_type32 __user *up) -{ - compat_uptr_t data; - compat_uptr_t effective_width; - - if (!access_ok(up, sizeof(struct atomisp_metadata_with_type32)) || - get_user(data, &up->data) || - put_user(compat_ptr(data), &kp->data) || - assign_in_user(&kp->width, &up->width) || - assign_in_user(&kp->height, &up->height) || - assign_in_user(&kp->stride, &up->stride) || - assign_in_user(&kp->exp_id, &up->exp_id) || - get_user(effective_width, &up->effective_width) || - put_user_force(compat_ptr(effective_width), &kp->effective_width) || - assign_in_user(&kp->type, &up->type)) - return -EFAULT; - - return 0; -} - -static int -get_atomisp_morph_table32(struct atomisp_morph_table __user *kp, - struct atomisp_morph_table32 __user *up) -{ - unsigned int n = ATOMISP_MORPH_TABLE_NUM_PLANES; - - if (!access_ok(up, sizeof(struct atomisp_morph_table32)) || - assign_in_user(&kp->enabled, &up->enabled) || - assign_in_user(&kp->width, &up->width) || - assign_in_user(&kp->height, &up->height)) - return -EFAULT; - - while (n-- > 0) { - compat_uptr_t coord_kp; - - if (get_user(coord_kp, &up->coordinates_x[n]) || - put_user(compat_ptr(coord_kp), &kp->coordinates_x[n]) || - get_user(coord_kp, &up->coordinates_y[n]) || - put_user(compat_ptr(coord_kp), &kp->coordinates_y[n])) - return -EFAULT; - } - return 0; -} - -static int put_atomisp_morph_table32(struct atomisp_morph_table __user *kp, - struct atomisp_morph_table32 __user *up) -{ - unsigned int n = ATOMISP_MORPH_TABLE_NUM_PLANES; - - if (!access_ok(up, sizeof(struct atomisp_morph_table32)) || - assign_in_user(&up->enabled, &kp->enabled) || - assign_in_user(&up->width, &kp->width) || - assign_in_user(&up->height, &kp->height)) - return -EFAULT; - - while (n-- > 0) { - void __user *coord_kp; - - if (get_user(coord_kp, &kp->coordinates_x[n]) || - put_user(ptr_to_compat(coord_kp), &up->coordinates_x[n]) || - get_user(coord_kp, &kp->coordinates_y[n]) || - put_user(ptr_to_compat(coord_kp), &up->coordinates_y[n])) - return -EFAULT; - } - return 0; -} - -static int get_atomisp_overlay32(struct atomisp_overlay __user *kp, - struct atomisp_overlay32 __user *up) -{ - compat_uptr_t frame; - - if (!access_ok(up, sizeof(struct atomisp_overlay32)) || - get_user(frame, &up->frame) || - put_user_force(compat_ptr(frame), &kp->frame) || - assign_in_user(&kp->bg_y, &up->bg_y) || - assign_in_user(&kp->bg_u, &up->bg_u) || - assign_in_user(&kp->bg_v, &up->bg_v) || - assign_in_user(&kp->blend_input_perc_y, - &up->blend_input_perc_y) || - assign_in_user(&kp->blend_input_perc_u, - &up->blend_input_perc_u) || - assign_in_user(&kp->blend_input_perc_v, - &up->blend_input_perc_v) || - assign_in_user(&kp->blend_overlay_perc_y, - &up->blend_overlay_perc_y) || - assign_in_user(&kp->blend_overlay_perc_u, - &up->blend_overlay_perc_u) || - assign_in_user(&kp->blend_overlay_perc_v, - &up->blend_overlay_perc_v) || - assign_in_user(&kp->overlay_start_x, &up->overlay_start_x) || - assign_in_user(&kp->overlay_start_y, &up->overlay_start_y)) - return -EFAULT; - - return 0; -} - -static int put_atomisp_overlay32(struct atomisp_overlay __user *kp, - struct atomisp_overlay32 __user *up) -{ - void *frame; - - if (!access_ok(up, sizeof(struct atomisp_overlay32)) || - get_user(frame, &kp->frame) || - put_user(ptr_to_compat((void __user *)frame), &up->frame) || - assign_in_user(&up->bg_y, &kp->bg_y) || - assign_in_user(&up->bg_u, &kp->bg_u) || - assign_in_user(&up->bg_v, &kp->bg_v) || - assign_in_user(&up->blend_input_perc_y, - &kp->blend_input_perc_y) || - assign_in_user(&up->blend_input_perc_u, - &kp->blend_input_perc_u) || - assign_in_user(&up->blend_input_perc_v, - &kp->blend_input_perc_v) || - assign_in_user(&up->blend_overlay_perc_y, - &kp->blend_overlay_perc_y) || - assign_in_user(&up->blend_overlay_perc_u, - &kp->blend_overlay_perc_u) || - assign_in_user(&up->blend_overlay_perc_v, - &kp->blend_overlay_perc_v) || - assign_in_user(&up->overlay_start_x, &kp->overlay_start_x) || - assign_in_user(&up->overlay_start_y, &kp->overlay_start_y)) - return -EFAULT; - - return 0; -} - -static int -get_atomisp_calibration_group32(struct atomisp_calibration_group __user *kp, - struct atomisp_calibration_group32 __user *up) -{ - compat_uptr_t calb_grp_values; - - if (!access_ok(up, sizeof(struct atomisp_calibration_group32)) || - assign_in_user(&kp->size, &up->size) || - assign_in_user(&kp->type, &up->type) || - get_user(calb_grp_values, &up->calb_grp_values) || - put_user_force(compat_ptr(calb_grp_values), &kp->calb_grp_values)) - return -EFAULT; - - return 0; -} - -static int -put_atomisp_calibration_group32(struct atomisp_calibration_group __user *kp, - struct atomisp_calibration_group32 __user *up) -{ - void *calb_grp_values; - - if (!access_ok(up, sizeof(struct atomisp_calibration_group32)) || - assign_in_user(&up->size, &kp->size) || - assign_in_user(&up->type, &kp->type) || - get_user(calb_grp_values, &kp->calb_grp_values) || - put_user(ptr_to_compat((void __user *)calb_grp_values), - &up->calb_grp_values)) - return -EFAULT; - - return 0; -} - -static int get_atomisp_acc_fw_load32(struct atomisp_acc_fw_load __user *kp, - struct atomisp_acc_fw_load32 __user *up) -{ - compat_uptr_t data; - - if (!access_ok(up, sizeof(struct atomisp_acc_fw_load32)) || - assign_in_user(&kp->size, &up->size) || - assign_in_user(&kp->fw_handle, &up->fw_handle) || - get_user_cast(data, &up->data) || - put_user(compat_ptr(data), &kp->data)) - return -EFAULT; - - return 0; -} - -static int put_atomisp_acc_fw_load32(struct atomisp_acc_fw_load __user *kp, - struct atomisp_acc_fw_load32 __user *up) -{ - void __user *data; - - if (!access_ok(up, sizeof(struct atomisp_acc_fw_load32)) || - assign_in_user(&up->size, &kp->size) || - assign_in_user(&up->fw_handle, &kp->fw_handle) || - get_user(data, &kp->data) || - put_user(ptr_to_compat(data), &up->data)) - return -EFAULT; - - return 0; -} - -static int get_atomisp_acc_fw_arg32(struct atomisp_acc_fw_arg __user *kp, - struct atomisp_acc_fw_arg32 __user *up) -{ - compat_uptr_t value; - - if (!access_ok(up, sizeof(struct atomisp_acc_fw_arg32)) || - assign_in_user(&kp->fw_handle, &up->fw_handle) || - assign_in_user(&kp->index, &up->index) || - get_user(value, &up->value) || - put_user(compat_ptr(value), &kp->value) || - assign_in_user(&kp->size, &up->size)) - return -EFAULT; - - return 0; -} - -static int put_atomisp_acc_fw_arg32(struct atomisp_acc_fw_arg __user *kp, - struct atomisp_acc_fw_arg32 __user *up) -{ - void __user *value; - - if (!access_ok(up, sizeof(struct atomisp_acc_fw_arg32)) || - assign_in_user(&up->fw_handle, &kp->fw_handle) || - assign_in_user(&up->index, &kp->index) || - get_user(value, &kp->value) || - put_user(ptr_to_compat(value), &up->value) || - assign_in_user(&up->size, &kp->size)) - return -EFAULT; - - return 0; -} - -static int get_v4l2_private_int_data32(struct v4l2_private_int_data __user *kp, - struct v4l2_private_int_data32 __user *up) -{ - compat_uptr_t data; - - if (!access_ok(up, sizeof(struct v4l2_private_int_data32)) || - assign_in_user(&kp->size, &up->size) || - get_user(data, &up->data) || - put_user(compat_ptr(data), &kp->data) || - assign_in_user(&kp->reserved[0], &up->reserved[0]) || - assign_in_user(&kp->reserved[1], &up->reserved[1])) - return -EFAULT; - - return 0; -} - -static int put_v4l2_private_int_data32(struct v4l2_private_int_data __user *kp, - struct v4l2_private_int_data32 __user *up) -{ - void __user *data; - - if (!access_ok(up, sizeof(struct v4l2_private_int_data32)) || - assign_in_user(&up->size, &kp->size) || - get_user(data, &kp->data) || - put_user(ptr_to_compat(data), &up->data) || - assign_in_user(&up->reserved[0], &kp->reserved[0]) || - assign_in_user(&up->reserved[1], &kp->reserved[1])) - return -EFAULT; - - return 0; -} - -static int get_atomisp_shading_table32(struct atomisp_shading_table __user *kp, - struct atomisp_shading_table32 __user *up) -{ - unsigned int n = ATOMISP_NUM_SC_COLORS; - - if (!access_ok(up, sizeof(struct atomisp_shading_table32)) || - assign_in_user(&kp->enable, &up->enable) || - assign_in_user(&kp->sensor_width, &up->sensor_width) || - assign_in_user(&kp->sensor_height, &up->sensor_height) || - assign_in_user(&kp->width, &up->width) || - assign_in_user(&kp->height, &up->height) || - assign_in_user(&kp->fraction_bits, &up->fraction_bits)) - return -EFAULT; - - while (n-- > 0) { - compat_uptr_t tmp; - - if (get_user(tmp, &up->data[n]) || - put_user_force(compat_ptr(tmp), &kp->data[n])) - return -EFAULT; - } - return 0; -} - -static int get_atomisp_acc_map32(struct atomisp_acc_map __user *kp, - struct atomisp_acc_map32 __user *up) -{ - compat_uptr_t user_ptr; - - if (!access_ok(up, sizeof(struct atomisp_acc_map32)) || - assign_in_user(&kp->flags, &up->flags) || - assign_in_user(&kp->length, &up->length) || - get_user(user_ptr, &up->user_ptr) || - put_user(compat_ptr(user_ptr), &kp->user_ptr) || - assign_in_user(&kp->css_ptr, &up->css_ptr) || - assign_in_user(&kp->reserved[0], &up->reserved[0]) || - assign_in_user(&kp->reserved[1], &up->reserved[1]) || - assign_in_user(&kp->reserved[2], &up->reserved[2]) || - assign_in_user(&kp->reserved[3], &up->reserved[3])) - return -EFAULT; - - return 0; -} - -static int put_atomisp_acc_map32(struct atomisp_acc_map __user *kp, - struct atomisp_acc_map32 __user *up) -{ - void __user *user_ptr; - - if (!access_ok(up, sizeof(struct atomisp_acc_map32)) || - assign_in_user(&up->flags, &kp->flags) || - assign_in_user(&up->length, &kp->length) || - get_user(user_ptr, &kp->user_ptr) || - put_user(ptr_to_compat(user_ptr), &up->user_ptr) || - assign_in_user(&up->css_ptr, &kp->css_ptr) || - assign_in_user(&up->reserved[0], &kp->reserved[0]) || - assign_in_user(&up->reserved[1], &kp->reserved[1]) || - assign_in_user(&up->reserved[2], &kp->reserved[2]) || - assign_in_user(&up->reserved[3], &kp->reserved[3])) - return -EFAULT; - - return 0; -} - -static int -get_atomisp_acc_s_mapped_arg32(struct atomisp_acc_s_mapped_arg __user *kp, - struct atomisp_acc_s_mapped_arg32 __user *up) -{ - if (!access_ok(up, sizeof(struct atomisp_acc_s_mapped_arg32)) || - assign_in_user(&kp->fw_handle, &up->fw_handle) || - assign_in_user(&kp->memory, &up->memory) || - assign_in_user(&kp->length, &up->length) || - assign_in_user(&kp->css_ptr, &up->css_ptr)) - return -EFAULT; - - return 0; -} - -static int -put_atomisp_acc_s_mapped_arg32(struct atomisp_acc_s_mapped_arg __user *kp, - struct atomisp_acc_s_mapped_arg32 __user *up) -{ - if (!access_ok(up, sizeof(struct atomisp_acc_s_mapped_arg32)) || - assign_in_user(&up->fw_handle, &kp->fw_handle) || - assign_in_user(&up->memory, &kp->memory) || - assign_in_user(&up->length, &kp->length) || - assign_in_user(&up->css_ptr, &kp->css_ptr)) - return -EFAULT; - - return 0; -} - -static int get_atomisp_parameters32(struct atomisp_parameters __user *kp, - struct atomisp_parameters32 __user *up) -{ - int n = offsetof(struct atomisp_parameters32, output_frame) / - sizeof(compat_uptr_t); - compat_uptr_t stp, mtp, dcp, dscp; - struct { - struct atomisp_shading_table shading_table; - struct atomisp_morph_table morph_table; - struct atomisp_dis_coefficients dvs2_coefs; - struct atomisp_dvs_6axis_config dvs_6axis_config; - } __user *karg = (void __user *)(kp + 1); - - if (!access_ok(up, sizeof(struct atomisp_parameters32))) - return -EFAULT; - - while (n >= 0) { - compat_uptr_t __user *src = (compat_uptr_t __user *)up + n; - void * __user *dst = (void * __user *)kp + n; - compat_uptr_t tmp; - - if (get_user_cast(tmp, src) || put_user_force(compat_ptr(tmp), dst)) - return -EFAULT; - n--; - } - - if (assign_in_user(&kp->isp_config_id, &up->isp_config_id) || - assign_in_user(&kp->per_frame_setting, &up->per_frame_setting) || - get_user(stp, &up->shading_table) || - get_user(mtp, &up->morph_table) || - get_user(dcp, &up->dvs2_coefs) || - get_user(dscp, &up->dvs_6axis_config)) - return -EFAULT; - - /* handle shading table */ - if (stp && (get_atomisp_shading_table32(&karg->shading_table, - compat_ptr(stp)) || - put_user_force(&karg->shading_table, &kp->shading_table))) - return -EFAULT; - - /* handle morph table */ - if (mtp && (get_atomisp_morph_table32(&karg->morph_table, - compat_ptr(mtp)) || - put_user_force(&karg->morph_table, &kp->morph_table))) - return -EFAULT; - - /* handle dvs2 coefficients */ - if (dcp && (get_atomisp_dis_coefficients32(&karg->dvs2_coefs, - compat_ptr(dcp)) || - put_user_force(&karg->dvs2_coefs, &kp->dvs2_coefs))) - return -EFAULT; - - /* handle dvs 6axis configuration */ - if (dscp && - (get_atomisp_dvs_6axis_config32(&karg->dvs_6axis_config, - compat_ptr(dscp)) || - put_user_force(&karg->dvs_6axis_config, &kp->dvs_6axis_config))) - return -EFAULT; - - return 0; -} - -static int -get_atomisp_acc_fw_load_to_pipe32(struct atomisp_acc_fw_load_to_pipe __user *kp, - struct atomisp_acc_fw_load_to_pipe32 __user *up) -{ - compat_uptr_t data; - - if (!access_ok(up, sizeof(struct atomisp_acc_fw_load_to_pipe32)) || - assign_in_user(&kp->flags, &up->flags) || - assign_in_user(&kp->fw_handle, &up->fw_handle) || - assign_in_user(&kp->size, &up->size) || - assign_in_user(&kp->type, &up->type) || - assign_in_user(&kp->reserved[0], &up->reserved[0]) || - assign_in_user(&kp->reserved[1], &up->reserved[1]) || - assign_in_user(&kp->reserved[2], &up->reserved[2]) || - get_user(data, &up->data) || - put_user(compat_ptr(data), &kp->data)) - return -EFAULT; - - return 0; -} - -static int -put_atomisp_acc_fw_load_to_pipe32(struct atomisp_acc_fw_load_to_pipe __user *kp, - struct atomisp_acc_fw_load_to_pipe32 __user *up) -{ - void __user *data; - - if (!access_ok(up, sizeof(struct atomisp_acc_fw_load_to_pipe32)) || - assign_in_user(&up->flags, &kp->flags) || - assign_in_user(&up->fw_handle, &kp->fw_handle) || - assign_in_user(&up->size, &kp->size) || - assign_in_user(&up->type, &kp->type) || - assign_in_user(&up->reserved[0], &kp->reserved[0]) || - assign_in_user(&up->reserved[1], &kp->reserved[1]) || - assign_in_user(&up->reserved[2], &kp->reserved[2]) || - get_user(data, &kp->data) || - put_user(ptr_to_compat(data), &up->data)) - return -EFAULT; - - return 0; -} - -static int -get_atomisp_sensor_ae_bracketing_lut(struct atomisp_sensor_ae_bracketing_lut __user *kp, - struct atomisp_sensor_ae_bracketing_lut32 __user *up) -{ - compat_uptr_t lut; - - if (!access_ok(up, sizeof(struct atomisp_sensor_ae_bracketing_lut32)) || - assign_in_user(&kp->lut_size, &up->lut_size) || - get_user(lut, &up->lut) || - put_user_force(compat_ptr(lut), &kp->lut)) - return -EFAULT; - - return 0; -} - -static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret = -ENOIOCTLCMD; - - if (file->f_op->unlocked_ioctl) - ret = file->f_op->unlocked_ioctl(file, cmd, arg); - - return ret; -} - -static long atomisp_do_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - union { - struct atomisp_histogram his; - struct atomisp_dis_statistics dis_s; - struct atomisp_dis_coefficients dis_c; - struct atomisp_dvs_6axis_config dvs_c; - struct atomisp_3a_statistics s3a_s; - struct atomisp_morph_table mor_t; - struct v4l2_framebuffer v4l2_buf; - struct atomisp_overlay overlay; - struct atomisp_calibration_group cal_grp; - struct atomisp_acc_fw_load acc_fw_load; - struct atomisp_acc_fw_arg acc_fw_arg; - struct v4l2_private_int_data v4l2_pri_data; - struct atomisp_shading_table shd_tbl; - struct atomisp_acc_map acc_map; - struct atomisp_acc_s_mapped_arg acc_map_arg; - struct atomisp_parameters param; - struct atomisp_acc_fw_load_to_pipe acc_fw_to_pipe; - struct atomisp_metadata md; - struct atomisp_metadata_with_type md_with_type; - struct atomisp_sensor_ae_bracketing_lut lut; - } __user *karg; - void __user *up = compat_ptr(arg); - long err = -ENOIOCTLCMD; - - karg = compat_alloc_user_space( - sizeof(*karg) + (cmd == ATOMISP_IOC_S_PARAMETERS32 ? - sizeof(struct atomisp_shading_table) + - sizeof(struct atomisp_morph_table) + - sizeof(struct atomisp_dis_coefficients) + - sizeof(struct atomisp_dvs_6axis_config) : 0)); - if (!karg) - return -ENOMEM; - - /* First, convert the command. */ - switch (cmd) { - case ATOMISP_IOC_G_HISTOGRAM32: - cmd = ATOMISP_IOC_G_HISTOGRAM; - break; - case ATOMISP_IOC_S_HISTOGRAM32: - cmd = ATOMISP_IOC_S_HISTOGRAM; - break; - case ATOMISP_IOC_G_DIS_STAT32: - cmd = ATOMISP_IOC_G_DIS_STAT; - break; - case ATOMISP_IOC_S_DIS_COEFS32: - cmd = ATOMISP_IOC_S_DIS_COEFS; - break; - case ATOMISP_IOC_S_DIS_VECTOR32: - cmd = ATOMISP_IOC_S_DIS_VECTOR; - break; - case ATOMISP_IOC_G_3A_STAT32: - cmd = ATOMISP_IOC_G_3A_STAT; - break; - case ATOMISP_IOC_G_ISP_GDC_TAB32: - cmd = ATOMISP_IOC_G_ISP_GDC_TAB; - break; - case ATOMISP_IOC_S_ISP_GDC_TAB32: - cmd = ATOMISP_IOC_S_ISP_GDC_TAB; - break; - case ATOMISP_IOC_S_ISP_FPN_TABLE32: - cmd = ATOMISP_IOC_S_ISP_FPN_TABLE; - break; - case ATOMISP_IOC_G_ISP_OVERLAY32: - cmd = ATOMISP_IOC_G_ISP_OVERLAY; - break; - case ATOMISP_IOC_S_ISP_OVERLAY32: - cmd = ATOMISP_IOC_S_ISP_OVERLAY; - break; - case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32: - cmd = ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP; - break; - case ATOMISP_IOC_ACC_LOAD32: - cmd = ATOMISP_IOC_ACC_LOAD; - break; - case ATOMISP_IOC_ACC_S_ARG32: - cmd = ATOMISP_IOC_ACC_S_ARG; - break; - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32: - cmd = ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA; - break; - case ATOMISP_IOC_S_ISP_SHD_TAB32: - cmd = ATOMISP_IOC_S_ISP_SHD_TAB; - break; - case ATOMISP_IOC_ACC_DESTAB32: - cmd = ATOMISP_IOC_ACC_DESTAB; - break; - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32: - cmd = ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA; - break; - case ATOMISP_IOC_ACC_MAP32: - cmd = ATOMISP_IOC_ACC_MAP; - break; - case ATOMISP_IOC_ACC_UNMAP32: - cmd = ATOMISP_IOC_ACC_UNMAP; - break; - case ATOMISP_IOC_ACC_S_MAPPED_ARG32: - cmd = ATOMISP_IOC_ACC_S_MAPPED_ARG; - break; - case ATOMISP_IOC_S_PARAMETERS32: - cmd = ATOMISP_IOC_S_PARAMETERS; - break; - case ATOMISP_IOC_ACC_LOAD_TO_PIPE32: - cmd = ATOMISP_IOC_ACC_LOAD_TO_PIPE; - break; - case ATOMISP_IOC_G_METADATA32: - cmd = ATOMISP_IOC_G_METADATA; - break; - case ATOMISP_IOC_G_METADATA_BY_TYPE32: - cmd = ATOMISP_IOC_G_METADATA_BY_TYPE; - break; - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT32: - cmd = ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT; - break; - } - - switch (cmd) { - case ATOMISP_IOC_G_HISTOGRAM: - case ATOMISP_IOC_S_HISTOGRAM: - err = get_atomisp_histogram32(&karg->his, up); - break; - case ATOMISP_IOC_G_DIS_STAT: - err = get_atomisp_dis_statistics32(&karg->dis_s, up); - break; - case ATOMISP_IOC_S_DIS_COEFS: - err = get_atomisp_dis_coefficients32(&karg->dis_c, up); - break; - case ATOMISP_IOC_S_DIS_VECTOR: - err = get_atomisp_dvs_6axis_config32(&karg->dvs_c, up); - break; - case ATOMISP_IOC_G_3A_STAT: - err = get_atomisp_3a_statistics32(&karg->s3a_s, up); - break; - case ATOMISP_IOC_G_ISP_GDC_TAB: - case ATOMISP_IOC_S_ISP_GDC_TAB: - err = get_atomisp_morph_table32(&karg->mor_t, up); - break; - case ATOMISP_IOC_S_ISP_FPN_TABLE: - err = get_v4l2_framebuffer32(&karg->v4l2_buf, up); - break; - case ATOMISP_IOC_G_ISP_OVERLAY: - case ATOMISP_IOC_S_ISP_OVERLAY: - err = get_atomisp_overlay32(&karg->overlay, up); - break; - case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP: - err = get_atomisp_calibration_group32(&karg->cal_grp, up); - break; - case ATOMISP_IOC_ACC_LOAD: - err = get_atomisp_acc_fw_load32(&karg->acc_fw_load, up); - break; - case ATOMISP_IOC_ACC_S_ARG: - case ATOMISP_IOC_ACC_DESTAB: - err = get_atomisp_acc_fw_arg32(&karg->acc_fw_arg, up); - break; - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA: - err = get_v4l2_private_int_data32(&karg->v4l2_pri_data, up); - break; - case ATOMISP_IOC_S_ISP_SHD_TAB: - err = get_atomisp_shading_table32(&karg->shd_tbl, up); - break; - case ATOMISP_IOC_ACC_MAP: - case ATOMISP_IOC_ACC_UNMAP: - err = get_atomisp_acc_map32(&karg->acc_map, up); - break; - case ATOMISP_IOC_ACC_S_MAPPED_ARG: - err = get_atomisp_acc_s_mapped_arg32(&karg->acc_map_arg, up); - break; - case ATOMISP_IOC_S_PARAMETERS: - err = get_atomisp_parameters32(&karg->param, up); - break; - case ATOMISP_IOC_ACC_LOAD_TO_PIPE: - err = get_atomisp_acc_fw_load_to_pipe32(&karg->acc_fw_to_pipe, - up); - break; - case ATOMISP_IOC_G_METADATA: - err = get_atomisp_metadata_stat32(&karg->md, up); - break; - case ATOMISP_IOC_G_METADATA_BY_TYPE: - err = get_atomisp_metadata_by_type_stat32(&karg->md_with_type, - up); - break; - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT: - err = get_atomisp_sensor_ae_bracketing_lut(&karg->lut, up); - break; - } - if (err) - return err; - - err = native_ioctl(file, cmd, (unsigned long)karg); - if (err) - return err; - - switch (cmd) { - case ATOMISP_IOC_G_HISTOGRAM: - err = put_atomisp_histogram32(&karg->his, up); - break; - case ATOMISP_IOC_G_DIS_STAT: - err = put_atomisp_dis_statistics32(&karg->dis_s, up); - break; - case ATOMISP_IOC_G_3A_STAT: - err = put_atomisp_3a_statistics32(&karg->s3a_s, up); - break; - case ATOMISP_IOC_G_ISP_GDC_TAB: - err = put_atomisp_morph_table32(&karg->mor_t, up); - break; - case ATOMISP_IOC_G_ISP_OVERLAY: - err = put_atomisp_overlay32(&karg->overlay, up); - break; - case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP: - err = put_atomisp_calibration_group32(&karg->cal_grp, up); - break; - case ATOMISP_IOC_ACC_LOAD: - err = put_atomisp_acc_fw_load32(&karg->acc_fw_load, up); - break; - case ATOMISP_IOC_ACC_S_ARG: - case ATOMISP_IOC_ACC_DESTAB: - err = put_atomisp_acc_fw_arg32(&karg->acc_fw_arg, up); - break; - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA: - err = put_v4l2_private_int_data32(&karg->v4l2_pri_data, up); - break; - case ATOMISP_IOC_ACC_MAP: - case ATOMISP_IOC_ACC_UNMAP: - err = put_atomisp_acc_map32(&karg->acc_map, up); - break; - case ATOMISP_IOC_ACC_S_MAPPED_ARG: - err = put_atomisp_acc_s_mapped_arg32(&karg->acc_map_arg, up); - break; - case ATOMISP_IOC_ACC_LOAD_TO_PIPE: - err = put_atomisp_acc_fw_load_to_pipe32(&karg->acc_fw_to_pipe, - up); - break; - case ATOMISP_IOC_G_METADATA: - err = put_atomisp_metadata_stat32(&karg->md, up); - break; - case ATOMISP_IOC_G_METADATA_BY_TYPE: - err = put_atomisp_metadata_by_type_stat32(&karg->md_with_type, - up); - break; - } - - return err; -} - -long atomisp_compat_ioctl32(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - long ret = -ENOIOCTLCMD; - - if (!file->f_op->unlocked_ioctl) - return ret; - - switch (cmd) { - case ATOMISP_IOC_G_XNR: - case ATOMISP_IOC_S_XNR: - case ATOMISP_IOC_G_NR: - case ATOMISP_IOC_S_NR: - case ATOMISP_IOC_G_TNR: - case ATOMISP_IOC_S_TNR: - case ATOMISP_IOC_G_BLACK_LEVEL_COMP: - case ATOMISP_IOC_S_BLACK_LEVEL_COMP: - case ATOMISP_IOC_G_EE: - case ATOMISP_IOC_S_EE: - case ATOMISP_IOC_S_DIS_VECTOR: - case ATOMISP_IOC_G_ISP_PARM: - case ATOMISP_IOC_S_ISP_PARM: - case ATOMISP_IOC_G_ISP_GAMMA: - case ATOMISP_IOC_S_ISP_GAMMA: - case ATOMISP_IOC_ISP_MAKERNOTE: - case ATOMISP_IOC_G_ISP_MACC: - case ATOMISP_IOC_S_ISP_MACC: - case ATOMISP_IOC_G_ISP_BAD_PIXEL_DETECTION: - case ATOMISP_IOC_S_ISP_BAD_PIXEL_DETECTION: - case ATOMISP_IOC_G_ISP_FALSE_COLOR_CORRECTION: - case ATOMISP_IOC_S_ISP_FALSE_COLOR_CORRECTION: - case ATOMISP_IOC_G_ISP_CTC: - case ATOMISP_IOC_S_ISP_CTC: - case ATOMISP_IOC_G_ISP_WHITE_BALANCE: - case ATOMISP_IOC_S_ISP_WHITE_BALANCE: - case ATOMISP_IOC_CAMERA_BRIDGE: - case ATOMISP_IOC_G_SENSOR_MODE_DATA: - case ATOMISP_IOC_S_EXPOSURE: - case ATOMISP_IOC_G_3A_CONFIG: - case ATOMISP_IOC_S_3A_CONFIG: - case ATOMISP_IOC_ACC_UNLOAD: - case ATOMISP_IOC_ACC_START: - case ATOMISP_IOC_ACC_WAIT: - case ATOMISP_IOC_ACC_ABORT: - case ATOMISP_IOC_G_ISP_GAMMA_CORRECTION: - case ATOMISP_IOC_S_ISP_GAMMA_CORRECTION: - case ATOMISP_IOC_S_CONT_CAPTURE_CONFIG: - case ATOMISP_IOC_G_DVS2_BQ_RESOLUTIONS: - case ATOMISP_IOC_EXT_ISP_CTRL: - case ATOMISP_IOC_EXP_ID_UNLOCK: - case ATOMISP_IOC_EXP_ID_CAPTURE: - case ATOMISP_IOC_S_ENABLE_DZ_CAPT_PIPE: - case ATOMISP_IOC_G_FORMATS_CONFIG: - case ATOMISP_IOC_S_FORMATS_CONFIG: - case ATOMISP_IOC_S_EXPOSURE_WINDOW: - case ATOMISP_IOC_S_ACC_STATE: - case ATOMISP_IOC_G_ACC_STATE: - case ATOMISP_IOC_INJECT_A_FAKE_EVENT: - case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_INFO: - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_MODE: - case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_MODE: - case ATOMISP_IOC_G_INVALID_FRAME_NUM: - case ATOMISP_IOC_S_ARRAY_RESOLUTION: - case ATOMISP_IOC_S_SENSOR_RUNMODE: - case ATOMISP_IOC_G_UPDATE_EXPOSURE: - ret = native_ioctl(file, cmd, arg); - break; - - case ATOMISP_IOC_G_HISTOGRAM32: - case ATOMISP_IOC_S_HISTOGRAM32: - case ATOMISP_IOC_G_DIS_STAT32: - case ATOMISP_IOC_S_DIS_COEFS32: - case ATOMISP_IOC_S_DIS_VECTOR32: - case ATOMISP_IOC_G_3A_STAT32: - case ATOMISP_IOC_G_ISP_GDC_TAB32: - case ATOMISP_IOC_S_ISP_GDC_TAB32: - case ATOMISP_IOC_S_ISP_FPN_TABLE32: - case ATOMISP_IOC_G_ISP_OVERLAY32: - case ATOMISP_IOC_S_ISP_OVERLAY32: - case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32: - case ATOMISP_IOC_ACC_LOAD32: - case ATOMISP_IOC_ACC_S_ARG32: - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32: - case ATOMISP_IOC_S_ISP_SHD_TAB32: - case ATOMISP_IOC_ACC_DESTAB32: - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32: - case ATOMISP_IOC_ACC_MAP32: - case ATOMISP_IOC_ACC_UNMAP32: - case ATOMISP_IOC_ACC_S_MAPPED_ARG32: - case ATOMISP_IOC_S_PARAMETERS32: - case ATOMISP_IOC_ACC_LOAD_TO_PIPE32: - case ATOMISP_IOC_G_METADATA32: - case ATOMISP_IOC_G_METADATA_BY_TYPE32: - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT32: - ret = atomisp_do_compat_ioctl(file, cmd, arg); - break; - - default: - dev_warn(isp->dev, - "%s: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n", - __func__, _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), - cmd); - break; - } - return ret; -} -#endif /* CONFIG_COMPAT */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 060b8765ae96..56456e59bf89 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -25,13 +25,13 @@ static struct v4l2_mbus_framefmt *__csi2_get_format(struct atomisp_mipi_csi2_device * csi2, - struct - v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which, unsigned int pad) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad); + return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, + pad); else return &csi2->formats[pad]; } @@ -44,7 +44,7 @@ static struct v4l2_mbus_framefmt *__csi2_get_format(struct * return -EINVAL or zero on success */ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { const struct atomisp_in_fmt_conv *ic = atomisp_in_fmt_conv; @@ -70,13 +70,13 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, * return -EINVAL or zero on success */ static int csi2_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, cfg, fmt->which, fmt->pad); + format = __csi2_get_format(csi2, sd_state, fmt->which, fmt->pad); fmt->format = *format; @@ -84,12 +84,14 @@ static int csi2_get_format(struct v4l2_subdev *sd, } int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, unsigned int which, uint16_t pad, struct v4l2_mbus_framefmt *ffmt) { struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2, cfg, which, pad); + struct v4l2_mbus_framefmt *actual_ffmt = __csi2_get_format(csi2, + sd_state, + which, pad); if (pad == CSI2_PAD_SINK) { const struct atomisp_in_fmt_conv *ic; @@ -110,12 +112,14 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, tmp_ffmt = *ffmt = *actual_ffmt; - return atomisp_csi2_set_ffmt(sd, cfg, which, CSI2_PAD_SOURCE, + return atomisp_csi2_set_ffmt(sd, sd_state, which, + CSI2_PAD_SOURCE, &tmp_ffmt); } /* FIXME: DPCM decompression */ - *actual_ffmt = *ffmt = *__csi2_get_format(csi2, cfg, which, CSI2_PAD_SINK); + *actual_ffmt = *ffmt = *__csi2_get_format(csi2, sd_state, which, + CSI2_PAD_SINK); return 0; } @@ -129,10 +133,10 @@ int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, * return -EINVAL or zero on success */ static int csi2_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - return atomisp_csi2_set_ffmt(sd, cfg, fmt->which, fmt->pad, + return atomisp_csi2_set_ffmt(sd, sd_state, fmt->which, fmt->pad, &fmt->format); } diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h index 59261e8f1a1a..e35711be8a37 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h @@ -44,7 +44,7 @@ struct atomisp_mipi_csi2_device { }; int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, unsigned int which, uint16_t pad, struct v4l2_mbus_framefmt *ffmt); int atomisp_mipi_csi2_init(struct atomisp_device *isp); diff --git a/drivers/staging/media/atomisp/pci/atomisp_file.c b/drivers/staging/media/atomisp/pci/atomisp_file.c index e568ca99c45a..4570a9ab100b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_file.c +++ b/drivers/staging/media/atomisp/pci/atomisp_file.c @@ -80,7 +80,7 @@ static int file_input_s_stream(struct v4l2_subdev *sd, int enable) } static int file_input_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -104,16 +104,16 @@ static int file_input_get_fmt(struct v4l2_subdev *sd, } static int file_input_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; if (format->pad) return -EINVAL; - file_input_get_fmt(sd, cfg, format); + file_input_get_fmt(sd, sd_state, format); if (format->which == V4L2_SUBDEV_FORMAT_TRY) - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; return 0; } @@ -130,7 +130,7 @@ static int file_input_s_power(struct v4l2_subdev *sd, int on) } static int file_input_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { /*to fake*/ @@ -138,7 +138,7 @@ static int file_input_enum_mbus_code(struct v4l2_subdev *sd, } static int file_input_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { /*to fake*/ @@ -146,7 +146,7 @@ static int file_input_enum_frame_size(struct v4l2_subdev *sd, } static int file_input_enum_frame_ival(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index f1e6b2597853..f82bf082aa79 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -837,7 +837,7 @@ dev_init: } /* runtime power management, turn on ISP */ - ret = pm_runtime_get_sync(vdev->v4l2_dev->dev); + ret = pm_runtime_resume_and_get(vdev->v4l2_dev->dev); if (ret < 0) { dev_err(isp->dev, "Failed to power on device\n"); goto error; @@ -881,9 +881,9 @@ done: css_error: atomisp_css_uninit(isp); + pm_runtime_put(vdev->v4l2_dev->dev); error: hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC); - pm_runtime_put(vdev->v4l2_dev->dev); rt_mutex_unlock(&isp->mutex); return ret; } @@ -963,7 +963,7 @@ static int atomisp_release(struct file *file) if (!isp->sw_contex.file_input && asd->fmt_auto->val) { struct v4l2_mbus_framefmt isp_sink_fmt = { 0 }; - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, + atomisp_subdev_set_ffmt(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt); } @@ -975,7 +975,7 @@ subdev_uninit: if (isp->sw_contex.file_input && asd->fmt_auto->val) { struct v4l2_mbus_framefmt isp_sink_fmt = { 0 }; - atomisp_subdev_set_ffmt(&asd->subdev, fh.pad, + atomisp_subdev_set_ffmt(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt); } @@ -1016,7 +1016,7 @@ subdev_uninit: done: if (!acc_node) { - atomisp_subdev_set_selection(&asd->subdev, fh.pad, + atomisp_subdev_set_selection(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, atomisp_subdev_source_pad(vdev), V4L2_SEL_TGT_COMPOSE, 0, @@ -1283,7 +1283,8 @@ const struct v4l2_file_operations atomisp_fops = { .unlocked_ioctl = video_ioctl2, #ifdef CONFIG_COMPAT /* - * There are problems with this code. Disable this for now. + * this was removed because of bugs, the interface + * needs to be made safe for compat tasks instead. .compat_ioctl32 = atomisp_compat_ioctl32, */ #endif @@ -1297,10 +1298,7 @@ const struct v4l2_file_operations atomisp_file_fops = { .mmap = atomisp_file_mmap, .unlocked_ioctl = video_ioctl2, #ifdef CONFIG_COMPAT - /* - * There are problems with this code. Disable this for now. - .compat_ioctl32 = atomisp_compat_ioctl32, - */ + /* .compat_ioctl32 = atomisp_compat_ioctl32, */ #endif .poll = atomisp_poll, }; diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 2ef5f44e4b6b..12f22ad007c7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -213,7 +213,7 @@ static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd, * return -EINVAL or zero on success */ static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1) @@ -246,7 +246,7 @@ static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad, } struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, u32 which, uint32_t pad, uint32_t target) { @@ -255,9 +255,9 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd, if (which == V4L2_SUBDEV_FORMAT_TRY) { switch (target) { case V4L2_SEL_TGT_CROP: - return v4l2_subdev_get_try_crop(sd, cfg, pad); + return v4l2_subdev_get_try_crop(sd, sd_state, pad); case V4L2_SEL_TGT_COMPOSE: - return v4l2_subdev_get_try_compose(sd, cfg, pad); + return v4l2_subdev_get_try_compose(sd, sd_state, pad); } } @@ -273,19 +273,20 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, uint32_t which, + struct v4l2_subdev_state *sd_state, uint32_t which, uint32_t pad) { struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(sd, cfg, pad); + return v4l2_subdev_get_try_format(sd, sd_state, pad); return &isp_sd->fmt[pad].fmt; } static void isp_get_fmt_rect(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, uint32_t which, + struct v4l2_subdev_state *sd_state, + uint32_t which, struct v4l2_mbus_framefmt **ffmt, struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM]) @@ -293,16 +294,16 @@ static void isp_get_fmt_rect(struct v4l2_subdev *sd, unsigned int i; for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) { - ffmt[i] = atomisp_subdev_get_ffmt(sd, cfg, which, i); - crop[i] = atomisp_subdev_get_rect(sd, cfg, which, i, + ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i); + crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i, V4L2_SEL_TGT_CROP); - comp[i] = atomisp_subdev_get_rect(sd, cfg, which, i, + comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i, V4L2_SEL_TGT_COMPOSE); } } static void isp_subdev_propagate(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, u32 which, uint32_t pad, uint32_t target, uint32_t flags) { @@ -313,7 +314,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd, if (flags & V4L2_SEL_FLAG_KEEP_CONFIG) return; - isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp); + isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp); switch (pad) { case ATOMISP_SUBDEV_PAD_SINK: { @@ -323,7 +324,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd, r.width = ffmt[pad]->width; r.height = ffmt[pad]->height; - atomisp_subdev_set_selection(sd, cfg, which, pad, + atomisp_subdev_set_selection(sd, sd_state, which, pad, target, flags, &r); break; } @@ -331,7 +332,7 @@ static void isp_subdev_propagate(struct v4l2_subdev *sd, } static int isp_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { struct v4l2_rect *rec; @@ -340,7 +341,7 @@ static int isp_subdev_get_selection(struct v4l2_subdev *sd, if (rval) return rval; - rec = atomisp_subdev_get_rect(sd, cfg, sel->which, sel->pad, + rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad, sel->target); if (!rec) return -EINVAL; @@ -365,7 +366,7 @@ static const char *atomisp_pad_str(unsigned int pad) } int atomisp_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, u32 which, uint32_t pad, uint32_t target, u32 flags, struct v4l2_rect *r) { @@ -382,7 +383,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad); - isp_get_fmt_rect(sd, cfg, which, ffmt, crop, comp); + isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp); dev_dbg(isp->dev, "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n", @@ -450,7 +451,8 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, struct v4l2_rect tmp = *crop[pad]; atomisp_subdev_set_selection( - sd, cfg, which, i, V4L2_SEL_TGT_COMPOSE, + sd, sd_state, which, i, + V4L2_SEL_TGT_COMPOSE, flags, &tmp); } } @@ -472,9 +474,9 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, * when dvs is disabled. */ dvs_w = dvs_h = 12; - } else + } else { dvs_w = dvs_h = 0; - + } atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h); atomisp_css_input_set_effective_resolution(isp_sd, stream_id, crop[pad]->width, crop[pad]->height); @@ -551,9 +553,9 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, ffmt[pad]->height = comp[pad]->height; } - if (!atomisp_subdev_get_rect(sd, cfg, which, pad, target)) + if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target)) return -EINVAL; - *r = *atomisp_subdev_get_rect(sd, cfg, which, pad, target); + *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target); dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n", r->left, r->top, r->width, r->height); @@ -562,7 +564,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, } static int isp_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target); @@ -570,7 +572,8 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd, if (rval) return rval; - return atomisp_subdev_set_selection(sd, cfg, sel->which, sel->pad, + return atomisp_subdev_set_selection(sd, sd_state, sel->which, + sel->pad, sel->target, sel->flags, &sel->r); } @@ -609,13 +612,14 @@ static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd) } void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, uint32_t which, + struct v4l2_subdev_state *sd_state, + uint32_t which, u32 pad, struct v4l2_mbus_framefmt *ffmt) { struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); struct atomisp_device *isp = isp_sd->isp; struct v4l2_mbus_framefmt *__ffmt = - atomisp_subdev_get_ffmt(sd, cfg, which, pad); + atomisp_subdev_get_ffmt(sd, sd_state, which, pad); u16 vdev_pad = atomisp_subdev_source_pad(sd->devnode); enum atomisp_input_stream_id stream_id; @@ -640,7 +644,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, *__ffmt = *ffmt; - isp_subdev_propagate(sd, cfg, which, pad, + isp_subdev_propagate(sd, sd_state, which, pad, V4L2_SEL_TGT_CROP, 0); if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { @@ -679,10 +683,11 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, * to the format type. */ static int isp_subdev_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - fmt->format = *atomisp_subdev_get_ffmt(sd, cfg, fmt->which, fmt->pad); + fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which, + fmt->pad); return 0; } @@ -698,10 +703,11 @@ static int isp_subdev_get_format(struct v4l2_subdev *sd, * to the format type. */ static int isp_subdev_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { - atomisp_subdev_set_ffmt(sd, cfg, fmt->which, fmt->pad, &fmt->format); + atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad, + &fmt->format); return 0; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index 330a77eed8aa..d6fcfab6352d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -437,19 +437,20 @@ uint16_t atomisp_subdev_source_pad(struct video_device *vdev); /* Get pointer to appropriate format */ struct v4l2_mbus_framefmt *atomisp_subdev_get_ffmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, uint32_t which, + struct v4l2_subdev_state *sd_state, uint32_t which, uint32_t pad); struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, u32 which, uint32_t pad, uint32_t target); int atomisp_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, u32 which, uint32_t pad, uint32_t target, u32 flags, struct v4l2_rect *r); /* Actually set the format */ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, uint32_t which, + struct v4l2_subdev_state *sd_state, + uint32_t which, u32 pad, struct v4l2_mbus_framefmt *ffmt); int atomisp_update_run_mode(struct atomisp_sub_device *asd); diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c index 1def80bab180..e29a96da5f98 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c @@ -29,7 +29,7 @@ static int tpg_s_stream(struct v4l2_subdev *sd, int enable) } static int tpg_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { /*to fake*/ @@ -37,7 +37,7 @@ static int tpg_get_fmt(struct v4l2_subdev *sd, } static int tpg_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; @@ -47,7 +47,7 @@ static int tpg_set_fmt(struct v4l2_subdev *sd, /* only raw8 grbg is supported by TPG */ fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; + sd_state->pads->try_fmt = *fmt; return 0; } return 0; @@ -65,7 +65,7 @@ static int tpg_s_power(struct v4l2_subdev *sd, int on) } static int tpg_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { /*to fake*/ @@ -73,7 +73,7 @@ static int tpg_enum_mbus_code(struct v4l2_subdev *sd, } static int tpg_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { /*to fake*/ @@ -81,7 +81,7 @@ static int tpg_enum_frame_size(struct v4l2_subdev *sd, } static int tpg_enum_frame_ival(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { /*to fake*/ diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 0295e2e32d79..948769ca6539 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -1178,7 +1178,7 @@ static void atomisp_unregister_entities(struct atomisp_device *isp) atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]); list_for_each_entry_safe(sd, next, &isp->v4l2_dev.subdevs, list) - v4l2_device_unregister_subdev(sd); + v4l2_device_unregister_subdev(sd); v4l2_device_unregister(&isp->v4l2_dev); media_device_unregister(&isp->media_dev); @@ -1500,9 +1500,9 @@ static int init_atomisp_wdts(struct atomisp_device *isp) for (i = 0; i < isp->num_of_streams; i++) { struct atomisp_sub_device *asd = &isp->asd[i]; - if (!IS_ISP2401) + if (!IS_ISP2401) { timer_setup(&asd->wdt, atomisp_wdt, 0); - else { + } else { timer_setup(&asd->video_out_capture.wdt, atomisp_wdt, 0); timer_setup(&asd->video_out_preview.wdt, diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 27dd8ce8ba0a..d26b1301eeb7 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -239,8 +239,8 @@ ia_css_reset_defaults(struct sh_css *css); static void sh_css_init_host_sp_control_vars(void); -static int set_num_primary_stages(unsigned int *num, - enum ia_css_pipe_version version); +static int +set_num_primary_stages(unsigned int *num, enum ia_css_pipe_version version); static bool need_capture_pp(const struct ia_css_pipe *pipe); @@ -308,8 +308,7 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline, const void *acc_fw); static int -alloc_continuous_frames( - struct ia_css_pipe *pipe, bool init_time); +alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time); static void pipe_global_init(void); @@ -413,7 +412,6 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe, static void sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe) { - assert(pipe); if (!pipe) { IA_CSS_ERROR("NULL input parameter"); return; @@ -453,15 +451,15 @@ static enum ia_css_frame_format yuv422_copy_formats[] = { * by the copy binary given the stream format. * */ static int -verify_copy_out_frame_format(struct ia_css_pipe *pipe) { +verify_copy_out_frame_format(struct ia_css_pipe *pipe) +{ enum ia_css_frame_format out_fmt = pipe->output_info[0].format; unsigned int i, found = 0; assert(pipe); assert(pipe->stream); - switch (pipe->stream->config.input_config.format) - { + switch (pipe->stream->config.input_config.format) { case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: case ATOMISP_INPUT_FORMAT_YUV420_8: for (i = 0; i < ARRAY_SIZE(yuv420_copy_formats) && !found; i++) @@ -528,7 +526,8 @@ ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream) #if !defined(ISP2401) static int -sh_css_config_input_network(struct ia_css_stream *stream) { +sh_css_config_input_network(struct ia_css_stream *stream) +{ unsigned int fmt_type; struct ia_css_pipe *pipe = stream->last_pipe; struct ia_css_binary *binary = NULL; @@ -554,8 +553,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) { stream->config.mode); if ((binary && (binary->online || stream->config.continuous)) || - pipe->config.mode == IA_CSS_PIPE_MODE_COPY) - { + pipe->config.mode == IA_CSS_PIPE_MODE_COPY) { err = ia_css_ifmtr_configure(&stream->config, binary); if (err) @@ -563,8 +561,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) { } if (stream->config.mode == IA_CSS_INPUT_MODE_TPG || - stream->config.mode == IA_CSS_INPUT_MODE_PRBS) - { + stream->config.mode == IA_CSS_INPUT_MODE_PRBS) { unsigned int hblank_cycles = 100, vblank_lines = 6, width, @@ -723,35 +720,32 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_id( switch (stream_cfg->mode) { case IA_CSS_INPUT_MODE_TPG: - if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0) { + if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0) isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID; - } else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1) { + else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1) isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID; - } else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2) { + else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2) isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID; - } break; case IA_CSS_INPUT_MODE_PRBS: - if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0) { + if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0) isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID; - } else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1) { + else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1) isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID; - } else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2) { + else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2) isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID; - } break; case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: - if (stream_cfg->source.port.port == MIPI_PORT0_ID) { + if (stream_cfg->source.port.port == MIPI_PORT0_ID) isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT0_ID; - } else if (stream_cfg->source.port.port == MIPI_PORT1_ID) { + else if (stream_cfg->source.port.port == MIPI_PORT1_ID) isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT1_ID; - } else if (stream_cfg->source.port.port == MIPI_PORT2_ID) { + else if (stream_cfg->source.port.port == MIPI_PORT2_ID) isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT2_ID; - } break; default: @@ -804,15 +798,14 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr( rc = true; switch (stream_cfg->mode) { case IA_CSS_INPUT_MODE_TPG: - if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP) { + if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP) isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_RAMP; - } else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD) { + else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD) isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_CHBO; - } else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO) { + else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO) isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_MONO; - } else { + else rc = false; - } /* * TODO @@ -951,12 +944,12 @@ static bool sh_css_translate_stream_cfg_to_input_system_input_port_resolution( stream_cfg->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) && stream_cfg->source.port.compression.type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) { if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel == - UNCOMPRESSED_BITS_PER_PIXEL_10) { + UNCOMPRESSED_BITS_PER_PIXEL_10) fmt_type = ATOMISP_INPUT_FORMAT_RAW_10; - } else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel == - UNCOMPRESSED_BITS_PER_PIXEL_12) { + else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel == + UNCOMPRESSED_BITS_PER_PIXEL_12) fmt_type = ATOMISP_INPUT_FORMAT_RAW_12; - } else + else return false; } @@ -1045,7 +1038,8 @@ static bool sh_css_translate_binary_info_to_input_system_output_port_attr( } static int -sh_css_config_input_network(struct ia_css_stream *stream) { +sh_css_config_input_network(struct ia_css_stream *stream) +{ bool rc; ia_css_isys_descr_t isys_stream_descr; unsigned int sp_thread_id; @@ -1060,19 +1054,16 @@ sh_css_config_input_network(struct ia_css_stream *stream) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "sh_css_config_input_network() enter 0x%p:\n", stream); - if (stream->config.continuous) - { - if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) { + if (stream->config.continuous) { + if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) pipe = stream->last_pipe; - } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP) { + else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP) pipe = stream->last_pipe; - } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) { + else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) pipe = stream->last_pipe->pipe_settings.preview.copy_pipe; - } else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) { + else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) pipe = stream->last_pipe->pipe_settings.video.copy_pipe; - } - } else - { + } else { pipe = stream->last_pipe; if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE) { /* @@ -1087,7 +1078,6 @@ sh_css_config_input_network(struct ia_css_stream *stream) { } } - assert(pipe); if (!pipe) return -EINVAL; @@ -1095,8 +1085,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) { if (pipe->pipeline.stages->binary) binary = pipe->pipeline.stages->binary; - if (binary) - { + if (binary) { /* this was being done in ifmtr in 2400. * online and cont bypass the init_in_frameinfo_memory_defaults * so need to do it here @@ -1111,8 +1100,7 @@ sh_css_config_input_network(struct ia_css_stream *stream) { /* get the target input terminal */ sp_pipeline_input_terminal = &sh_css_sp_group.pipe_io[sp_thread_id].input; - for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) - { + for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) { /* initialization */ memset((void *)(&isys_stream_descr), 0, sizeof(ia_css_isys_descr_t)); sp_pipeline_input_terminal->context.virtual_input_system_stream[i].valid = 0; @@ -1210,11 +1198,10 @@ static inline struct ia_css_pipe *stream_get_target_pipe( struct ia_css_pipe *target_pipe; /* get the pipe that consumes the stream */ - if (stream->config.continuous) { + if (stream->config.continuous) target_pipe = stream_get_copy_pipe(stream); - } else { + else target_pipe = stream_get_last_pipe(stream); - } return target_pipe; } @@ -1388,10 +1375,9 @@ start_binary(struct ia_css_pipe *pipe, /* start the copy function on the SP */ static int start_copy_on_sp(struct ia_css_pipe *pipe, - struct ia_css_frame *out_frame) { + struct ia_css_frame *out_frame) +{ (void)out_frame; - assert(pipe); - assert(pipe->stream); if ((!pipe) || (!pipe->stream)) return -EINVAL; @@ -1406,8 +1392,7 @@ start_copy_on_sp(struct ia_css_pipe *pipe, sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2); #if !defined(ISP2401) - if (pipe->stream->reconfigure_css_rx) - { + if (pipe->stream->reconfigure_css_rx) { ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, pipe->stream->config.mode); pipe->stream->reconfigure_css_rx = false; @@ -1596,7 +1581,8 @@ ia_css_reset_defaults(struct sh_css *css) int ia_css_load_firmware(struct device *dev, const struct ia_css_env *env, - const struct ia_css_fw *fw) { + const struct ia_css_fw *fw) +{ int err; if (!env) @@ -1607,16 +1593,14 @@ ia_css_load_firmware(struct device *dev, const struct ia_css_env *env, ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() enter\n"); /* make sure we initialize my_css */ - if (my_css.flush != env->cpu_mem_env.flush) - { + if (my_css.flush != env->cpu_mem_env.flush) { ia_css_reset_defaults(&my_css); my_css.flush = env->cpu_mem_env.flush; } ia_css_unload_firmware(); /* in case we are called twice */ err = sh_css_load_firmware(dev, fw->data, fw->bytes); - if (!err) - { + if (!err) { err = ia_css_binary_init_infos(); if (!err) fw_explicitly_loaded = true; @@ -1630,7 +1614,8 @@ int ia_css_init(struct device *dev, const struct ia_css_env *env, const struct ia_css_fw *fw, u32 mmu_l1_base, - enum ia_css_irq_type irq_type) { + enum ia_css_irq_type irq_type) +{ int err; ia_css_spctrl_cfg spctrl_cfg; @@ -1704,16 +1689,14 @@ ia_css_init(struct device *dev, const struct ia_css_env *env, my_css.flush = flush_func; err = ia_css_rmgr_init(); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR(err); return err; } IA_CSS_LOG("init: %d", my_css_save_initialized); - if (!my_css_save_initialized) - { + if (!my_css_save_initialized) { my_css_save_initialized = true; my_css_save.mode = sh_css_mode_working; memset(my_css_save.stream_seeds, 0, @@ -1741,19 +1724,16 @@ ia_css_init(struct device *dev, const struct ia_css_env *env, gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_0, 0); err = ia_css_refcount_init(REFCOUNT_SIZE); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR(err); return err; } err = sh_css_params_init(); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR(err); return err; } - if (fw) - { + if (fw) { ia_css_unload_firmware(); /* in case we already had firmware loaded */ err = sh_css_load_firmware(dev, fw->data, fw->bytes); if (err) { @@ -1774,23 +1754,20 @@ ia_css_init(struct device *dev, const struct ia_css_env *env, return -EINVAL; err = ia_css_spctrl_load_fw(SP0_ID, &spctrl_cfg); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR(err); return err; } #if WITH_PC_MONITORING - if (!thread_alive) - { + if (!thread_alive) { thread_alive++; sh_css_print("PC_MONITORING: %s() -- create thread DISABLED\n", __func__); spying_thread_create(); } #endif - if (!sh_css_hrt_system_is_idle()) - { + if (!sh_css_hrt_system_is_idle()) { IA_CSS_LEAVE_ERR(-EBUSY); return -EBUSY; } @@ -1823,7 +1800,8 @@ ia_css_init(struct device *dev, const struct ia_css_env *env, } int -ia_css_enable_isys_event_queue(bool enable) { +ia_css_enable_isys_event_queue(bool enable) +{ if (sh_css_sp_is_running()) return -EBUSY; sh_css_sp_enable_isys_event_queue(enable); @@ -1844,7 +1822,8 @@ sh_css_flush(struct ia_css_acc_fw *fw) * doing it from stream_create since we could run out of sp threads due to * allocation on inactive pipelines. */ static int -map_sp_threads(struct ia_css_stream *stream, bool map) { +map_sp_threads(struct ia_css_stream *stream, bool map) +{ struct ia_css_pipe *main_pipe = NULL; struct ia_css_pipe *copy_pipe = NULL; struct ia_css_pipe *capture_pipe = NULL; @@ -1852,12 +1831,10 @@ map_sp_threads(struct ia_css_stream *stream, bool map) { int err = 0; enum ia_css_pipe_id pipe_id; - assert(stream); IA_CSS_ENTER_PRIVATE("stream = %p, map = %s", stream, map ? "true" : "false"); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -1867,8 +1844,7 @@ map_sp_threads(struct ia_css_stream *stream, bool map) { ia_css_pipeline_map(main_pipe->pipe_num, map); - switch (pipe_id) - { + switch (pipe_id) { case IA_CSS_PIPE_ID_PREVIEW: copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; capture_pipe = main_pipe->pipe_settings.preview.capture_pipe; @@ -1887,23 +1863,17 @@ map_sp_threads(struct ia_css_stream *stream, bool map) { } if (acc_pipe) - { ia_css_pipeline_map(acc_pipe->pipe_num, map); - } if (capture_pipe) - { ia_css_pipeline_map(capture_pipe->pipe_num, map); - } /* Firmware expects copy pipe to be the last pipe mapped. (if needed) */ if (copy_pipe) - { ia_css_pipeline_map(copy_pipe->pipe_num, map); - } + /* DH regular multi pipe - not continuous mode: map the next pipes too */ - if (!stream->config.continuous) - { + if (!stream->config.continuous) { int i; for (i = 1; i < stream->num_pipes; i++) @@ -1917,7 +1887,8 @@ map_sp_threads(struct ia_css_stream *stream, bool map) { /* creates a host pipeline skeleton for all pipes in a stream. Called during * stream_create. */ static int -create_host_pipeline_structure(struct ia_css_stream *stream) { +create_host_pipeline_structure(struct ia_css_stream *stream) +{ struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL; struct ia_css_pipe *acc_pipe = NULL; enum ia_css_pipe_id pipe_id; @@ -1926,27 +1897,22 @@ create_host_pipeline_structure(struct ia_css_stream *stream) { unsigned int copy_pipe_delay = 0, capture_pipe_delay = 0; - assert(stream); IA_CSS_ENTER_PRIVATE("stream = %p", stream); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } main_pipe = stream->last_pipe; - assert(main_pipe); - if (!main_pipe) - { + if (!main_pipe) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } pipe_id = main_pipe->mode; - switch (pipe_id) - { + switch (pipe_id) { case IA_CSS_PIPE_ID_PREVIEW: copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; copy_pipe_delay = main_pipe->dvs_frame_delay; @@ -1986,30 +1952,23 @@ create_host_pipeline_structure(struct ia_css_stream *stream) { } if (!(err) && copy_pipe) - { err = ia_css_pipeline_create(©_pipe->pipeline, copy_pipe->mode, copy_pipe->pipe_num, copy_pipe_delay); - } if (!(err) && capture_pipe) - { err = ia_css_pipeline_create(&capture_pipe->pipeline, capture_pipe->mode, capture_pipe->pipe_num, capture_pipe_delay); - } if (!(err) && acc_pipe) - { err = ia_css_pipeline_create(&acc_pipe->pipeline, acc_pipe->mode, acc_pipe->pipe_num, main_pipe->dvs_frame_delay); - } /* DH regular multi pipe - not continuous mode: create the next pipelines too */ - if (!stream->config.continuous) - { + if (!stream->config.continuous) { int i; for (i = 1; i < stream->num_pipes && 0 == err; i++) { @@ -2028,7 +1987,8 @@ create_host_pipeline_structure(struct ia_css_stream *stream) { /* creates a host pipeline for all pipes in a stream. Called during * stream_start. */ static int -create_host_pipeline(struct ia_css_stream *stream) { +create_host_pipeline(struct ia_css_stream *stream) +{ struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL; struct ia_css_pipe *acc_pipe = NULL; enum ia_css_pipe_id pipe_id; @@ -2037,8 +1997,7 @@ create_host_pipeline(struct ia_css_stream *stream) { unsigned int max_input_width = 0; IA_CSS_ENTER_PRIVATE("stream = %p", stream); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -2049,8 +2008,7 @@ create_host_pipeline(struct ia_css_stream *stream) { /* No continuous frame allocation for capture pipe. It uses the * "main" pipe's frames. */ if ((pipe_id == IA_CSS_PIPE_ID_PREVIEW) || - (pipe_id == IA_CSS_PIPE_ID_VIDEO)) - { + (pipe_id == IA_CSS_PIPE_ID_VIDEO)) { /* About pipe_id == IA_CSS_PIPE_ID_PREVIEW && stream->config.mode != IA_CSS_INPUT_MODE_MEMORY: * The original condition pipe_id == IA_CSS_PIPE_ID_PREVIEW is too strong. E.g. in SkyCam (with memory * based input frames) there is no continuous mode and thus no need for allocated continuous frames @@ -2068,24 +2026,21 @@ create_host_pipeline(struct ia_css_stream *stream) { #if !defined(ISP2401) /* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */ - if (pipe_id != IA_CSS_PIPE_ID_ACC) - { + if (pipe_id != IA_CSS_PIPE_ID_ACC) { err = allocate_mipi_frames(main_pipe, &stream->info); if (err) goto ERR; } #elif defined(ISP2401) if ((pipe_id != IA_CSS_PIPE_ID_ACC) && - (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) - { + (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) { err = allocate_mipi_frames(main_pipe, &stream->info); if (err) goto ERR; } #endif - switch (pipe_id) - { + switch (pipe_id) { case IA_CSS_PIPE_ID_PREVIEW: copy_pipe = main_pipe->pipe_settings.preview.copy_pipe; capture_pipe = main_pipe->pipe_settings.preview.capture_pipe; @@ -2135,31 +2090,27 @@ create_host_pipeline(struct ia_css_stream *stream) { if (err) goto ERR; - if (copy_pipe) - { + if (copy_pipe) { err = create_host_copy_pipeline(copy_pipe, max_input_width, main_pipe->continuous_frames[0]); if (err) goto ERR; } - if (capture_pipe) - { + if (capture_pipe) { err = create_host_capture_pipeline(capture_pipe); if (err) goto ERR; } - if (acc_pipe) - { + if (acc_pipe) { err = create_host_acc_pipeline(acc_pipe); if (err) goto ERR; } /* DH regular multi pipe - not continuous mode: create the next pipelines too */ - if (!stream->config.continuous) - { + if (!stream->config.continuous) { int i; for (i = 1; i < stream->num_pipes && 0 == err; i++) { @@ -2201,10 +2152,9 @@ static const struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS; static int init_pipe_defaults(enum ia_css_pipe_mode mode, struct ia_css_pipe *pipe, - bool copy_pipe) { - - if (!pipe) - { + bool copy_pipe) +{ + if (!pipe) { IA_CSS_ERROR("NULL pipe parameter"); return -EINVAL; } @@ -2213,18 +2163,17 @@ init_pipe_defaults(enum ia_css_pipe_mode mode, memcpy(pipe, &default_pipe, sizeof(default_pipe)); /* TODO: JB should not be needed, but temporary backward reference */ - switch (mode) - { + switch (mode) { case IA_CSS_PIPE_MODE_PREVIEW: pipe->mode = IA_CSS_PIPE_ID_PREVIEW; memcpy(&pipe->pipe_settings.preview, &preview, sizeof(preview)); break; case IA_CSS_PIPE_MODE_CAPTURE: - if (copy_pipe) { + if (copy_pipe) pipe->mode = IA_CSS_PIPE_ID_COPY; - } else { + else pipe->mode = IA_CSS_PIPE_ID_CAPTURE; - } + memcpy(&pipe->pipe_settings.capture, &capture, sizeof(capture)); break; case IA_CSS_PIPE_MODE_VIDEO: @@ -2254,27 +2203,25 @@ pipe_global_init(void) u8 i; my_css.pipe_counter = 0; - for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) { + for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) my_css.all_pipes[i] = NULL; - } } static int pipe_generate_pipe_num(const struct ia_css_pipe *pipe, - unsigned int *pipe_number) { + unsigned int *pipe_number) +{ const u8 INVALID_PIPE_NUM = (uint8_t)~(0); u8 pipe_num = INVALID_PIPE_NUM; u8 i; - if (!pipe) - { + if (!pipe) { IA_CSS_ERROR("NULL pipe parameter"); return -EINVAL; } /* Assign a new pipe_num .... search for empty place */ - for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) - { + for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) { if (!my_css.all_pipes[i]) { /*position is reserved */ my_css.all_pipes[i] = (struct ia_css_pipe *)pipe; @@ -2282,8 +2229,7 @@ pipe_generate_pipe_num(const struct ia_css_pipe *pipe, break; } } - if (pipe_num == INVALID_PIPE_NUM) - { + if (pipe_num == INVALID_PIPE_NUM) { /* Max number of pipes already allocated */ IA_CSS_ERROR("Max number of pipes already created"); return -ENOSPC; @@ -2309,12 +2255,12 @@ pipe_release_pipe_num(unsigned int pipe_num) static int create_pipe(enum ia_css_pipe_mode mode, struct ia_css_pipe **pipe, - bool copy_pipe) { + bool copy_pipe) +{ int err = 0; struct ia_css_pipe *me; - if (!pipe) - { + if (!pipe) { IA_CSS_ERROR("NULL pipe parameter"); return -EINVAL; } @@ -2324,15 +2270,13 @@ create_pipe(enum ia_css_pipe_mode mode, return -ENOMEM; err = init_pipe_defaults(mode, me, copy_pipe); - if (err) - { + if (err) { kfree(me); return err; } err = pipe_generate_pipe_num(me, &me->pipe_num); - if (err) - { + if (err) { kfree(me); return err; } @@ -2361,7 +2305,6 @@ static void sh_css_pipe_free_acc_binaries( struct ia_css_pipeline *pipeline; struct ia_css_pipeline_stage *stage; - assert(pipe); if (!pipe) { IA_CSS_ERROR("NULL input pointer"); return; @@ -2378,26 +2321,24 @@ static void sh_css_pipe_free_acc_binaries( } int -ia_css_pipe_destroy(struct ia_css_pipe *pipe) { +ia_css_pipe_destroy(struct ia_css_pipe *pipe) +{ int err = 0; IA_CSS_ENTER("pipe = %p", pipe); - if (!pipe) - { + if (!pipe) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } - if (pipe->stream) - { + if (pipe->stream) { IA_CSS_LOG("ia_css_stream_destroy not called!"); IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } - switch (pipe->config.mode) - { + switch (pipe->config.mode) { case IA_CSS_PIPE_MODE_PREVIEW: /* need to take into account that this function is also called on the internal copy pipe */ @@ -2461,9 +2402,8 @@ ia_css_pipe_destroy(struct ia_css_pipe *pipe) { /* Temporarily, not every sh_css_pipe has an acc_extension. */ if (pipe->config.acc_extension) - { ia_css_pipe_unload_extension(pipe, pipe->config.acc_extension); - } + kfree(pipe); IA_CSS_LEAVE("err = %d", err); return err; @@ -2493,9 +2433,9 @@ ia_css_uninit(void) ifmtr_set_if_blocking_mode_reset = true; #endif - if (!fw_explicitly_loaded) { + if (!fw_explicitly_loaded) ia_css_unload_firmware(); - } + ia_css_spctrl_unload_fw(SP0_ID); sh_css_sp_set_sp_running(false); /* check and free any remaining mipi frames */ @@ -2681,8 +2621,8 @@ static int load_copy_binary( } static int -alloc_continuous_frames( - struct ia_css_pipe *pipe, bool init_time) { +alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time) +{ int err = 0; struct ia_css_frame_info ref_info; enum ia_css_pipe_id pipe_id; @@ -2692,8 +2632,7 @@ alloc_continuous_frames( IA_CSS_ENTER_PRIVATE("pipe = %p, init_time = %d", pipe, init_time); - if ((!pipe) || (!pipe->stream)) - { + if ((!pipe) || (!pipe->stream)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -2701,26 +2640,22 @@ alloc_continuous_frames( pipe_id = pipe->mode; continuous = pipe->stream->config.continuous; - if (continuous) - { + if (continuous) { if (init_time) { num_frames = pipe->stream->config.init_num_cont_raw_buf; pipe->stream->continuous_pipe = pipe; - } else + } else { num_frames = pipe->stream->config.target_num_cont_raw_buf; - } else - { + } + } else { num_frames = NUM_ONLINE_INIT_CONTINUOUS_FRAMES; } - if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) - { + if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) { ref_info = pipe->pipe_settings.preview.preview_binary.in_frame_info; - } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) - { + } else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) { ref_info = pipe->pipe_settings.video.video_binary.in_frame_info; - } else - { + } else { /* should not happen */ IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; @@ -2736,8 +2671,7 @@ alloc_continuous_frames( #endif #if !defined(HAS_NO_PACKED_RAW_PIXELS) - if (pipe->stream->config.pack_raw_pixels) - { + if (pipe->stream->config.pack_raw_pixels) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW_PACKED\n"); ref_info.format = IA_CSS_FRAME_FORMAT_RAW_PACKED; @@ -2766,8 +2700,7 @@ alloc_continuous_frames( else idx = pipe->stream->config.init_num_cont_raw_buf; - for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) - { + for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) { /* free previous frame */ if (pipe->continuous_frames[i]) { ia_css_frame_free(pipe->continuous_frames[i]); @@ -2797,14 +2730,16 @@ alloc_continuous_frames( } int -ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream) { +ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream) +{ if (!stream) return -EINVAL; return alloc_continuous_frames(stream->continuous_pipe, false); } static int -load_preview_binaries(struct ia_css_pipe *pipe) { +load_preview_binaries(struct ia_css_pipe *pipe) +{ struct ia_css_frame_info prev_in_info, prev_bds_out_info, prev_out_info, @@ -2912,8 +2847,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) { * then the preview binary selection is done again. */ if (need_vf_pp && - (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) - { + (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) { /* Preview step 2 */ if (pipe->vf_yuv_ds_input_info.res.width) prev_vf_info = pipe->vf_yuv_ds_input_info; @@ -2938,8 +2872,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) { return err; } - if (need_vf_pp) - { + if (need_vf_pp) { struct ia_css_binary_descr vf_pp_descr; /* Viewfinder post-processing */ @@ -2970,8 +2903,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) { #endif /* Copy */ - if (need_isp_copy_binary) - { + if (need_isp_copy_binary) { err = load_copy_binary(pipe, &mycs->copy_binary, &mycs->preview_binary); @@ -2979,8 +2911,7 @@ load_preview_binaries(struct ia_css_pipe *pipe) { return err; } - if (pipe->shading_table) - { + if (pipe->shading_table) { ia_css_shading_table_free(pipe->shading_table); pipe->shading_table = NULL; } @@ -2995,11 +2926,11 @@ ia_css_binary_unload(struct ia_css_binary *binary) } static int -unload_preview_binaries(struct ia_css_pipe *pipe) { +unload_preview_binaries(struct ia_css_pipe *pipe) +{ IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) - { + if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -3052,20 +2983,19 @@ static int add_firmwares( struct ia_css_frame *in = NULL; struct ia_css_frame *vf = NULL; - if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame != 0)) { + if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame != 0)) out[0] = out_frame; - } - if (fw->info.isp.sp.enable.in_frame != 0) { + + if (fw->info.isp.sp.enable.in_frame != 0) in = in_frame; - } - if (fw->info.isp.sp.enable.out_frame != 0) { + + if (fw->info.isp.sp.enable.out_frame != 0) vf = vf_frame; - } + ia_css_pipe_get_firmwares_stage_desc(&stage_desc, binary, out, in, vf, fw, binary_mode); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - &extra_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + &extra_stage); if (err) return err; if (fw->info.isp.sp.enable.output != 0) @@ -3173,9 +3103,8 @@ static int add_yuv_scaler_stage( ia_css_pipe_get_generic_stage_desc(&stage_desc, yuv_scaler_binary, out_frames, in_frame, vf_frame); } - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - pre_vf_pp_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + pre_vf_pp_stage); if (err) return err; in_frame = (*pre_vf_pp_stage)->args.out_frame[0]; @@ -3233,9 +3162,8 @@ static int add_capture_pp_stage( ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_pp_binary, out_frames, NULL, vf_frame); } - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - capture_pp_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + capture_pp_stage); if (err) return err; err = add_firmwares(me, capture_pp_binary, pipe->output_stage, last_fw, @@ -3274,7 +3202,8 @@ static void sh_css_setup_queues(void) static int init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, - struct ia_css_frame *vf_frame, unsigned int idx) { + struct ia_css_frame *vf_frame, unsigned int idx) +{ int err = 0; unsigned int thread_id; enum sh_css_queue_id queue_id; @@ -3439,7 +3368,8 @@ ia_css_get_crop_offsets( static int init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, - struct ia_css_frame *frame, enum ia_css_frame_format format) { + struct ia_css_frame *frame, enum ia_css_frame_format format) +{ struct ia_css_frame *in_frame; int err = 0; unsigned int thread_id; @@ -3480,7 +3410,8 @@ init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe, static int init_out_frameinfo_defaults(struct ia_css_pipe *pipe, - struct ia_css_frame *out_frame, unsigned int idx) { + struct ia_css_frame *out_frame, unsigned int idx) +{ int err = 0; unsigned int thread_id; enum sh_css_queue_id queue_id; @@ -3587,9 +3518,8 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe) ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, out_frames, NULL, NULL); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - ©_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + ©_stage); if (err) goto ERR; in_frame = me->stages->args.out_frame[0]; @@ -3616,9 +3546,8 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe) ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary, out_frames, in_frame, vf_frame); } - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - &video_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + &video_stage); if (err) goto ERR; @@ -3681,13 +3610,10 @@ static int create_host_video_pipeline(struct ia_css_pipe *pipe) struct ia_css_frame *tmp_out_frame = NULL; for (i = 0; i < num_yuv_scaler; i++) { - if (is_output_stage[i]) { - tmp_out_frame = out_frame; - } else { - tmp_out_frame = NULL; - } - err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame, - NULL, + tmp_out_frame = is_output_stage[i] ? out_frame : NULL; + + err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, + tmp_out_frame, NULL, &yuv_scaler_binary[i], &yuv_scaler_stage); @@ -3711,14 +3637,14 @@ ERR: } static int -create_host_acc_pipeline(struct ia_css_pipe *pipe) { +create_host_acc_pipeline(struct ia_css_pipe *pipe) +{ int err = 0; const struct ia_css_fw_info *fw; unsigned int i; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || (!pipe->stream)) - { + if ((!pipe) || (!pipe->stream)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -3729,15 +3655,13 @@ create_host_acc_pipeline(struct ia_css_pipe *pipe) { pipe->pipeline.pipe_qos_config = 0; fw = pipe->vf_stage; - for (i = 0; fw; fw = fw->next) - { + for (i = 0; fw; fw = fw->next) { err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw); if (err) goto ERR; } - for (i = 0; i < pipe->config.num_acc_stages; i++) - { + for (i = 0; i < pipe->config.num_acc_stages; i++) { struct ia_css_fw_info *fw = pipe->config.acc_stages[i]; err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw); @@ -3754,7 +3678,8 @@ ERR: /* Create stages for preview */ static int -create_host_preview_pipeline(struct ia_css_pipe *pipe) { +create_host_preview_pipeline(struct ia_css_pipe *pipe) +{ struct ia_css_pipeline_stage *copy_stage = NULL; struct ia_css_pipeline_stage *preview_stage = NULL; struct ia_css_pipeline_stage *vf_pp_stage = NULL; @@ -3774,8 +3699,7 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) { #endif IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) - { + if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -3803,16 +3727,14 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) { /* Construct in_frame info (only in case we have dynamic input */ need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; #endif - if (need_in_frameinfo_memory) - { + if (need_in_frameinfo_memory) { err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame, IA_CSS_FRAME_FORMAT_RAW); if (err) goto ERR; in_frame = &me->in_frame; - } else - { + } else { in_frame = NULL; } @@ -3826,14 +3748,12 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) { if (pipe->pipe_settings.preview.vf_pp_binary.info) vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary; - if (pipe->pipe_settings.preview.copy_binary.info) - { + if (pipe->pipe_settings.preview.copy_binary.info) { ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, out_frames, NULL, NULL); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - ©_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + ©_stage); if (err) goto ERR; in_frame = me->stages->args.out_frame[0]; @@ -3842,42 +3762,37 @@ create_host_preview_pipeline(struct ia_css_pipe *pipe) { /* When continuous is enabled, configure in_frame with the * last pipe, which is the copy pipe. */ - if (continuous || !online) { + if (continuous || !online) in_frame = pipe->stream->last_pipe->continuous_frames[0]; - } + #else in_frame = pipe->continuous_frames[0]; #endif } - if (vf_pp_binary) - { + if (vf_pp_binary) { ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary, out_frames, in_frame, NULL); - } else - { + } else { ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary, out_frames, in_frame, NULL); } - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - &preview_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + &preview_stage); if (err) goto ERR; /* If we use copy iso preview, the input must be yuv iso raw */ preview_stage->args.copy_vf = preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY; preview_stage->args.copy_output = !preview_stage->args.copy_vf; - if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) - { + if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) { /* in case of copy, use the vf frame as output frame */ preview_stage->args.out_vf_frame = preview_stage->args.out_frame[0]; } - if (vf_pp_binary) - { + if (vf_pp_binary) { if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY) in_frame = preview_stage->args.out_vf_frame; else @@ -3917,7 +3832,8 @@ static void send_raw_frames(struct ia_css_pipe *pipe) } static int -preview_start(struct ia_css_pipe *pipe) { +preview_start(struct ia_css_pipe *pipe) +{ int err = 0; struct ia_css_pipe *copy_pipe, *capture_pipe; struct ia_css_pipe *acc_pipe; @@ -3927,8 +3843,7 @@ preview_start(struct ia_css_pipe *pipe) { const struct ia_css_isp_parameters *params = NULL; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) - { + if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -3955,8 +3870,7 @@ preview_start(struct ia_css_pipe *pipe) { ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); copy_ovrd = 1 << thread_id; - if (pipe->stream->cont_capt) - { + if (pipe->stream->cont_capt) { ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe), &thread_id); copy_ovrd |= 1 << thread_id; @@ -3969,8 +3883,7 @@ preview_start(struct ia_css_pipe *pipe) { } /* Construct and load the copy pipe */ - if (pipe->stream->config.continuous) - { + if (pipe->stream->config.continuous) { sh_css_sp_init_pipeline(©_pipe->pipeline, IA_CSS_PIPE_ID_COPY, (uint8_t)ia_css_pipe_get_pipe_num(copy_pipe), @@ -3991,8 +3904,7 @@ preview_start(struct ia_css_pipe *pipe) { } /* Construct and load the capture pipe */ - if (pipe->stream->cont_capt) - { + if (pipe->stream->cont_capt) { sh_css_sp_init_pipeline(&capture_pipe->pipeline, IA_CSS_PIPE_ID_CAPTURE, (uint8_t)ia_css_pipe_get_pipe_num(capture_pipe), @@ -4010,8 +3922,7 @@ preview_start(struct ia_css_pipe *pipe) { params); } - if (acc_pipe) - { + if (acc_pipe) { sh_css_sp_init_pipeline(&acc_pipe->pipeline, IA_CSS_PIPE_ID_ACC, (uint8_t)ia_css_pipe_get_pipe_num(acc_pipe), @@ -4037,7 +3948,8 @@ preview_start(struct ia_css_pipe *pipe) { int ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, - const struct ia_css_buffer *buffer) { + const struct ia_css_buffer *buffer) +{ int return_err = 0; unsigned int thread_id; enum sh_css_queue_id queue_id; @@ -4052,8 +3964,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer); - if ((!pipe) || (!buffer)) - { + if ((!pipe) || (!buffer)) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } @@ -4062,8 +3973,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, /* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME is removed */ #if 0 - if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) - { + if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) { bool found_pipe = false; for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { @@ -4077,8 +3987,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, if (!found_pipe) return -EINVAL; } - if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) - { + if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { bool found_pipe = false; for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { @@ -4099,36 +4008,31 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, assert(pipe_id < IA_CSS_PIPE_ID_NUM); assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE); - if ((buf_type == IA_CSS_BUFFER_TYPE_INVALID) || - (buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE) || - (pipe_id >= IA_CSS_PIPE_ID_NUM)) - { + if (buf_type == IA_CSS_BUFFER_TYPE_INVALID || + buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE || + pipe_id >= IA_CSS_PIPE_ID_NUM) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); - if (!ret_err) - { + if (!ret_err) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id); - if (!ret_err) - { + if (!ret_err) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } - if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) - { + if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } - if (!sh_css_sp_is_running()) - { + if (!sh_css_sp_is_running()) { IA_CSS_LOG("SP is not running!"); IA_CSS_LEAVE_ERR(-EBUSY); /* SP is not running. The queues are not valid */ @@ -4146,36 +4050,32 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, ddr_buffer.cookie_ptr = buffer->driver_cookie; ddr_buffer.timing_data = buffer->timing_data; - if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) - { + if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) { if (!buffer->data.stats_3a) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a); ddr_buffer.payload.s3a = *buffer->data.stats_3a; - } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) - { + } else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) { if (!buffer->data.stats_dvs) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs); ddr_buffer.payload.dis = *buffer->data.stats_dvs; - } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) - { + } else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) { if (!buffer->data.metadata) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata); ddr_buffer.payload.metadata = *buffer->data.metadata; - } else if ((buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME)) - { + } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) { if (!buffer->data.frame) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; @@ -4207,22 +4107,17 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, /* TODO: change next to correct pool for optimization */ ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf); - assert(h_vbuf); - assert(h_vbuf->vptr != 0x0); - - if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) - { + if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } hmm_store(h_vbuf->vptr, - (void *)(&ddr_buffer), - sizeof(struct sh_css_hmm_buffer)); - if ((buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) - || (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) - || (buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS)) - { + (void *)(&ddr_buffer), + sizeof(struct sh_css_hmm_buffer)); + if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS || + buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS || + buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) { if (!pipeline) { ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf); IA_CSS_LOG("pipeline is empty!"); @@ -4240,19 +4135,18 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, (uint32_t)h_vbuf->vptr); } } - } else if ((buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_METADATA)) - { + } else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_METADATA) { return_err = ia_css_bufq_enqueue_buffer(thread_id, queue_id, (uint32_t)h_vbuf->vptr); #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) - if (!(return_err) && - (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME)) { + if (!return_err && + buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) { IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d", ddr_buffer.payload.frame.frame_data, queue_id, thread_id); @@ -4260,8 +4154,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, #endif } - if (!return_err) - { + if (!return_err) { if (sh_css_hmm_buffer_record_acquire( h_vbuf, buf_type, HOST_ADDRESS(ddr_buffer.kernel_ptr))) { @@ -4276,8 +4169,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, * Tell the SP which queues are not empty, * by sending the software event. */ - if (!return_err) - { + if (!return_err) { if (!sh_css_sp_is_running()) { /* SP is not running. The queues are not valid */ IA_CSS_LOG("SP is not running!"); @@ -4289,8 +4181,7 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, (uint8_t)thread_id, queue_id, 0); - } else - { + } else { ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf); IA_CSS_ERROR("buffer not enqueued"); } @@ -4305,7 +4196,8 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, */ int ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, - struct ia_css_buffer *buffer) { + struct ia_css_buffer *buffer) +{ int return_err; enum sh_css_queue_id queue_id; ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0; @@ -4318,8 +4210,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer); - if ((!pipe) || (!buffer)) - { + if ((!pipe) || (!buffer)) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } @@ -4333,27 +4224,23 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, ddr_buffer.kernel_ptr = 0; ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); - if (!ret_err) - { + if (!ret_err) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id); - if (!ret_err) - { + if (!ret_err) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } - if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) - { + if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } - if (!sh_css_sp_is_running()) - { + if (!sh_css_sp_is_running()) { IA_CSS_LOG("SP is not running!"); IA_CSS_LEAVE_ERR(-EBUSY); /* SP is not running. The queues are not valid */ @@ -4363,8 +4250,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, return_err = ia_css_bufq_dequeue_buffer(queue_id, (uint32_t *)&ddr_buffer_addr); - if (!return_err) - { + if (!return_err) { struct ia_css_frame *frame; struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL; @@ -4389,8 +4275,8 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, } hmm_load(ddr_buffer_addr, - &ddr_buffer, - sizeof(struct sh_css_hmm_buffer)); + &ddr_buffer, + sizeof(struct sh_css_hmm_buffer)); /* if the kernel_ptr is 0 or an invalid, return an error. * do not access the buffer via the kernal_ptr. @@ -4412,8 +4298,8 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, buffer->driver_cookie = ddr_buffer.cookie_ptr; buffer->timing_data = ddr_buffer.timing_data; - if ((buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) || - (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME)) { + if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME || + buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) { buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick; } @@ -4506,8 +4392,7 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, * Tell the SP which queues are not full, * by sending the software event. */ - if (!return_err) - { + if (!return_err) { if (!sh_css_sp_is_running()) { IA_CSS_LOG("SP is not running!"); IA_CSS_LEAVE_ERR(-EBUSY); @@ -4556,12 +4441,14 @@ static enum ia_css_event_type convert_event_sp_to_host_domain[] = { }; int -ia_css_dequeue_event(struct ia_css_event *event) { +ia_css_dequeue_event(struct ia_css_event *event) +{ return ia_css_dequeue_psys_event(event); } int -ia_css_dequeue_psys_event(struct ia_css_event *event) { +ia_css_dequeue_psys_event(struct ia_css_event *event) +{ enum ia_css_pipe_id pipe_id = 0; u8 payload[4] = {0, 0, 0, 0}; int ret_err; @@ -4576,11 +4463,9 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) { if (!event) return -EINVAL; + /* SP is not running. The queues are not valid */ if (!sh_css_sp_is_running()) - { - /* SP is not running. The queues are not valid */ return -EBUSY; - } /* dequeue the event (if any) from the psys event queue */ ret_err = ia_css_bufq_dequeue_psys_event(payload); @@ -4607,8 +4492,7 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) { event->timer_code = 0; event->timer_subcode = 0; - if (event->type == IA_CSS_EVENT_TYPE_TIMER) - { + if (event->type == IA_CSS_EVENT_TYPE_TIMER) { /* timer event ??? get the 2nd event and decode the data into the event struct */ u32 tmp_data; /* 1st event: LSB 16-bit timer data and code */ @@ -4632,37 +4516,32 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) { tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8)); event->timer_data |= (tmp_data << 16); event->timer_subcode = payload[2]; - } + } else { /* It's a non timer event. So clear first half of the timer event data. * If the second part of the TIMER event is not received, we discard * the first half of the timer data and process the non timer event without * affecting the flow. So the non timer event falls through * the code. */ - else { event->timer_data = 0; event->timer_code = 0; event->timer_subcode = 0; IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded"); } } - if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) - { + if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) { event->port = (enum mipi_port_id)payload[1]; event->exp_id = payload[3]; - } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) - { + } else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) { event->fw_warning = (enum ia_css_fw_warning)payload[1]; /* exp_id is only available in these warning types */ if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED || event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED) event->exp_id = payload[3]; - } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) - { + } else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) { event->fw_assert_module_id = payload[1]; /* module */ event->fw_assert_line_no = (payload[2] << 8) + payload[3]; /* payload[2] is line_no>>8, payload[3] is line_no&0xff */ - } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) - { + } else if (event->type != IA_CSS_EVENT_TYPE_TIMER) { /* pipe related events. * payload[1] contains the pipe_num, * payload[2] contains the pipe_id. These are different. */ @@ -4712,7 +4591,8 @@ ia_css_dequeue_psys_event(struct ia_css_event *event) { } int -ia_css_dequeue_isys_event(struct ia_css_event *event) { +ia_css_dequeue_isys_event(struct ia_css_event *event) +{ u8 payload[4] = {0, 0, 0, 0}; int err = 0; @@ -4722,11 +4602,9 @@ ia_css_dequeue_isys_event(struct ia_css_event *event) { if (!event) return -EINVAL; + /* SP is not running. The queues are not valid */ if (!sh_css_sp_is_running()) - { - /* SP is not running. The queues are not valid */ return -EBUSY; - } err = ia_css_bufq_dequeue_isys_event(payload); if (err) @@ -4759,7 +4637,8 @@ acc_start(struct ia_css_pipe *pipe) } static int -sh_css_pipe_start(struct ia_css_stream *stream) { +sh_css_pipe_start(struct ia_css_stream *stream) +{ int err = 0; struct ia_css_pipe *pipe; @@ -4768,22 +4647,19 @@ sh_css_pipe_start(struct ia_css_stream *stream) { IA_CSS_ENTER_PRIVATE("stream = %p", stream); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } pipe = stream->last_pipe; - if (!pipe) - { + if (!pipe) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } pipe_id = pipe->mode; - if (stream->started) - { + if (stream->started) { IA_CSS_WARNING("Cannot start stream that is already started"); IA_CSS_LEAVE_ERR(err); return err; @@ -4791,8 +4667,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { pipe->stop_requested = false; - switch (pipe_id) - { + switch (pipe_id) { case IA_CSS_PIPE_ID_PREVIEW: err = preview_start(pipe); break; @@ -4812,8 +4687,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { err = -EINVAL; } /* DH regular multi pipe - not continuous mode: start the next pipes too */ - if (!stream->config.continuous) - { + if (!stream->config.continuous) { int i; for (i = 1; i < stream->num_pipes && 0 == err ; i++) { @@ -4843,8 +4717,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { } } } - if (err) - { + if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } @@ -4854,8 +4727,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { * don't use ISP parameters anyway. So this should be okay. * The SP binary (jpeg) copy does not use any parameters. */ - if (!copy_on_sp(pipe)) - { + if (!copy_on_sp(pipe)) { sh_css_invalidate_params(stream); err = sh_css_param_update_isp_params(pipe, stream->isp_params_configs, true, NULL); @@ -4869,8 +4741,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); - if (!sh_css_sp_is_running()) - { + if (!sh_css_sp_is_running()) { IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY); /* SP is not running. The queues are not valid */ return -EBUSY; @@ -4879,8 +4750,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { (uint8_t)thread_id, 0, 0); /* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */ - if (!stream->config.continuous) - { + if (!stream->config.continuous) { int i; for (i = 1; i < stream->num_pipes; i++) { @@ -4894,8 +4764,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { } /* in case of continuous capture mode, we also start capture thread and copy thread*/ - if (pipe->stream->config.continuous) - { + if (pipe->stream->config.continuous) { struct ia_css_pipe *copy_pipe = NULL; if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) @@ -4914,8 +4783,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { IA_CSS_PSYS_SW_EVENT_START_STREAM, (uint8_t)thread_id, 0, 0); } - if (pipe->stream->cont_capt) - { + if (pipe->stream->cont_capt) { struct ia_css_pipe *capture_pipe = NULL; if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) @@ -4936,8 +4804,7 @@ sh_css_pipe_start(struct ia_css_stream *stream) { } /* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */ - if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) - { + if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) { struct ia_css_pipe *acc_pipe = NULL; acc_pipe = pipe->pipe_settings.preview.acc_pipe; @@ -4988,7 +4855,8 @@ sh_css_continuous_is_enabled(uint8_t pipe_num) /* ISP2400 */ int ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream, - int *buffer_depth) { + int *buffer_depth) +{ if (!buffer_depth) return -EINVAL; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n"); @@ -4998,7 +4866,8 @@ ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream, } int -ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) { +ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) +{ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth); (void)stream; if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1) @@ -5012,7 +4881,8 @@ ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth) { /* ISP2401 */ int ia_css_stream_get_buffer_depth(struct ia_css_stream *stream, - int *buffer_depth) { + int *buffer_depth) +{ if (!buffer_depth) return -EINVAL; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n"); @@ -5036,18 +4906,14 @@ sh_css_pipes_stop(struct ia_css_stream *stream) enum ia_css_pipe_id main_pipe_id; int i; - assert(stream); - if (!stream) - { + if (!stream) { IA_CSS_LOG("stream does NOT exist!"); err = -EINVAL; goto ERR; } main_pipe = stream->last_pipe; - assert(main_pipe); - if (!main_pipe) - { + if (!main_pipe) { IA_CSS_LOG("main_pipe does NOT exist!"); err = -EINVAL; goto ERR; @@ -5060,11 +4926,10 @@ sh_css_pipes_stop(struct ia_css_stream *stream) * Stop all "ia_css_pipe" instances in this target * "ia_css_stream" instance. */ - for (i = 0; i < stream->num_pipes; i++) - { + for (i = 0; i < stream->num_pipes; i++) { /* send the "stop" request to the "ia_css_pipe" instance */ IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d", - stream->pipes[i]->pipeline.pipe_id); + stream->pipes[i]->pipeline.pipe_id); err = ia_css_pipeline_request_stop(&stream->pipes[i]->pipeline); /* @@ -5095,8 +4960,7 @@ sh_css_pipes_stop(struct ia_css_stream *stream) * * We need to stop this "Copy Pipe", as well. */ - if (main_pipe->stream->config.continuous) - { + if (main_pipe->stream->config.continuous) { struct ia_css_pipe *copy_pipe = NULL; /* get the reference to "Copy Pipe" */ @@ -5106,7 +4970,6 @@ sh_css_pipes_stop(struct ia_css_stream *stream) copy_pipe = main_pipe->pipe_settings.video.copy_pipe; /* return the error code if "Copy Pipe" does NOT exist */ - assert(copy_pipe); if (!copy_pipe) { IA_CSS_LOG("Copy Pipe does NOT exist!"); err = -EINVAL; @@ -5115,7 +4978,7 @@ sh_css_pipes_stop(struct ia_css_stream *stream) /* send the "stop" request to "Copy Pipe" */ IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d", - copy_pipe->pipeline.pipe_id); + copy_pipe->pipeline.pipe_id); err = ia_css_pipeline_request_stop(©_pipe->pipeline); } @@ -5141,7 +5004,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream) int i; - assert(stream); if (!stream) { IA_CSS_LOG("stream does NOT exist!"); rval = false; @@ -5149,7 +5011,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream) } main_pipe = stream->last_pipe; - assert(main_pipe); if (!main_pipe) { IA_CSS_LOG("main_pipe does NOT exist!"); @@ -5190,7 +5051,6 @@ sh_css_pipes_have_stopped(struct ia_css_stream *stream) copy_pipe = main_pipe->pipe_settings.video.copy_pipe; /* return if "Copy Pipe" does NOT exist */ - assert(copy_pipe); if (!copy_pipe) { IA_CSS_LOG("Copy Pipe does NOT exist!"); @@ -5272,8 +5132,7 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe, binary = ia_css_pipe_get_shading_correction_binary(pipe); - if (binary) - { + if (binary) { err = ia_css_binary_get_shading_info(binary, IA_CSS_SHADING_CORRECTION_TYPE_1, pipe->required_bds_factor, @@ -5283,8 +5142,7 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe, /* Other function calls can be added here when other shading correction types will be added * in the future. */ - } else - { + } else { /* When the pipe does not have a binary which has the shading * correction, this function does not need to fill the shading * information. It is not a error case, and then @@ -5297,7 +5155,8 @@ sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe, static int sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, - struct ia_css_grid_info *info) { + struct ia_css_grid_info *info) +{ int err = 0; struct ia_css_binary *binary = NULL; @@ -5308,30 +5167,27 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, binary = ia_css_pipe_get_s3a_binary(pipe); - if (binary) - { + if (binary) { err = ia_css_binary_3a_grid_info(binary, info, pipe); if (err) goto ERR; - } else + } else { memset(&info->s3a_grid, 0, sizeof(info->s3a_grid)); + } binary = ia_css_pipe_get_sdis_binary(pipe); - if (binary) - { + if (binary) { ia_css_binary_dvs_grid_info(binary, info, pipe); ia_css_binary_dvs_stat_grid_info(binary, info, pipe); - } else - { + } else { memset(&info->dvs_grid.dvs_grid_info, 0, sizeof(info->dvs_grid.dvs_grid_info)); memset(&info->dvs_grid.dvs_stat_grid_info, 0, sizeof(info->dvs_grid.dvs_stat_grid_info)); } - if (binary) - { + if (binary) { /* copy pipe does not have ISP binary*/ info->isp_in_width = binary->internal_frame_info.res.width; info->isp_in_height = binary->internal_frame_info.res.height; @@ -5351,7 +5207,8 @@ ERR : */ static int ia_css_pipe_check_format(struct ia_css_pipe *pipe, - enum ia_css_frame_format format) { + enum ia_css_frame_format format) +{ const enum ia_css_frame_format *supported_formats; int number_of_formats; int found = 0; @@ -5359,8 +5216,7 @@ ia_css_pipe_check_format(struct ia_css_pipe *pipe, IA_CSS_ENTER_PRIVATE(""); - if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) - { + if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) { IA_CSS_ERROR("Pipe or binary info is not set"); IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; @@ -5369,23 +5225,19 @@ ia_css_pipe_check_format(struct ia_css_pipe *pipe, supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats; number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format); - for (i = 0; i < number_of_formats && !found; i++) - { + for (i = 0; i < number_of_formats && !found; i++) { if (supported_formats[i] == format) { found = 1; break; } } - if (!found) - { + if (!found) { IA_CSS_ERROR("Requested format is not supported by binary"); IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; - } else - { - IA_CSS_LEAVE_ERR_PRIVATE(0); - return 0; } + IA_CSS_LEAVE_ERR_PRIVATE(0); + return 0; } static int load_video_binaries(struct ia_css_pipe *pipe) @@ -5528,10 +5380,10 @@ static int load_video_binaries(struct ia_css_pipe *pipe) &mycs->video_binary); if (err) { - if (video_vf_info) { - /* This will do another video binary lookup later for YUV_LINE format*/ + /* This will do another video binary lookup later for YUV_LINE format*/ + if (video_vf_info) need_vf_pp = true; - } else + else return err; } else if (video_vf_info) { /* The first video binary lookup is successful, but we may @@ -5694,13 +5546,13 @@ static int load_video_binaries(struct ia_css_pipe *pipe) } static int -unload_video_binaries(struct ia_css_pipe *pipe) { +unload_video_binaries(struct ia_css_pipe *pipe) +{ unsigned int i; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) - { + if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -5850,31 +5702,29 @@ static int sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width, unsigned int height, unsigned int min_width, enum ia_css_frame_format format, - unsigned int idx) { + unsigned int idx) +{ int err = 0; IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n", pipe, width, height, min_width, format, idx); - if (!pipe) - { + if (!pipe) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } err = ia_css_util_check_res(width, height); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } if (pipe->vf_output_info[idx].res.width != width || pipe->vf_output_info[idx].res.height != height || pipe->vf_output_info[idx].format != format) - { ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height, format, min_width); - } + IA_CSS_LEAVE_ERR_PRIVATE(0); return 0; } @@ -5955,7 +5805,7 @@ static bool need_capt_ldc( } static int set_num_primary_stages(unsigned int *num, - enum ia_css_pipe_version version) + enum ia_css_pipe_version version) { int err = 0; @@ -6155,10 +6005,13 @@ static int load_primary_binaries( capt_pp_in_info = &prim_out_info; ia_css_pipe_get_capturepp_binarydesc(pipe, - &capture_pp_descr, capt_pp_in_info, - &capt_pp_out_info, &vf_info); + &capture_pp_descr, + capt_pp_in_info, + &capt_pp_out_info, + &vf_info); + err = ia_css_binary_find(&capture_pp_descr, - &mycs->capture_pp_binary); + &mycs->capture_pp_binary); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -6168,11 +6021,12 @@ static int load_primary_binaries( struct ia_css_binary_descr capt_ldc_descr; ia_css_pipe_get_ldc_binarydesc(pipe, - &capt_ldc_descr, &prim_out_info, - &capt_ldc_out_info); + &capt_ldc_descr, + &prim_out_info, + &capt_ldc_out_info); err = ia_css_binary_find(&capt_ldc_descr, - &mycs->capture_ldc_binary); + &mycs->capture_ldc_binary); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -6189,8 +6043,9 @@ static int load_primary_binaries( if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && (i == mycs->num_primary_stage - 1)) local_vf_info = &vf_info; - ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i], &prim_in_info, - &prim_out_info, local_vf_info, i); + ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i], + &prim_in_info, &prim_out_info, + local_vf_info, i); err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -6242,8 +6097,8 @@ static int load_primary_binaries( /* ISP Copy */ if (need_isp_copy_binary) { err = load_copy_binary(pipe, - &mycs->copy_binary, - &mycs->primary_binary[0]); + &mycs->copy_binary, + &mycs->primary_binary[0]); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -6254,7 +6109,8 @@ static int load_primary_binaries( } static int -allocate_delay_frames(struct ia_css_pipe *pipe) { +allocate_delay_frames(struct ia_css_pipe *pipe) +{ unsigned int num_delay_frames = 0, i = 0; unsigned int dvs_frame_delay = 0; struct ia_css_frame_info ref_info; @@ -6264,8 +6120,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) { IA_CSS_ENTER_PRIVATE(""); - if (!pipe) - { + if (!pipe) { IA_CSS_ERROR("Invalid args - pipe %p", pipe); return -EINVAL; } @@ -6276,8 +6131,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) { if (dvs_frame_delay > 0) num_delay_frames = dvs_frame_delay + 1; - switch (mode) - { + switch (mode) { case IA_CSS_PIPE_ID_CAPTURE: { struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture; (void)mycs_capture; @@ -6329,8 +6183,7 @@ allocate_delay_frames(struct ia_css_pipe *pipe) { ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH; assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES); - for (i = 0; i < num_delay_frames; i++) - { + for (i = 0; i < num_delay_frames; i++) { err = ia_css_frame_allocate_from_info(&delay_frames[i], &ref_info); if (err) return err; @@ -6339,8 +6192,8 @@ allocate_delay_frames(struct ia_css_pipe *pipe) { return 0; } -static int load_advanced_binaries( - struct ia_css_pipe *pipe) { +static int load_advanced_binaries(struct ia_css_pipe *pipe) +{ struct ia_css_frame_info pre_in_info, gdc_in_info, post_in_info, post_out_info, vf_info, *vf_pp_in_info, *pipe_out_info, @@ -6353,7 +6206,7 @@ static int load_advanced_binaries( assert(pipe); assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || - pipe->mode == IA_CSS_PIPE_ID_COPY); + pipe->mode == IA_CSS_PIPE_ID_COPY); if (pipe->pipe_settings.capture.pre_isp_binary.info) return 0; pipe_out_info = &pipe->output_info[0]; @@ -6366,17 +6219,18 @@ static int load_advanced_binaries( need_pp = need_capture_pp(pipe); ia_css_frame_info_set_format(&vf_info, - IA_CSS_FRAME_FORMAT_YUV_LINE); + IA_CSS_FRAME_FORMAT_YUV_LINE); /* we build up the pipeline starting at the end */ /* Capture post-processing */ if (need_pp) { struct ia_css_binary_descr capture_pp_descr; - ia_css_pipe_get_capturepp_binarydesc(pipe, - &capture_pp_descr, &post_out_info, pipe_out_info, &vf_info); + ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr, + &post_out_info, + pipe_out_info, &vf_info); err = ia_css_binary_find(&capture_pp_descr, - &pipe->pipe_settings.capture.capture_pp_binary); + &pipe->pipe_settings.capture.capture_pp_binary); if (err) return err; } else { @@ -6387,10 +6241,11 @@ static int load_advanced_binaries( { struct ia_css_binary_descr post_gdc_descr; - ia_css_pipe_get_post_gdc_binarydesc(pipe, - &post_gdc_descr, &post_in_info, &post_out_info, &vf_info); + ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr, + &post_in_info, + &post_out_info, &vf_info); err = ia_css_binary_find(&post_gdc_descr, - &pipe->pipe_settings.capture.post_isp_binary); + &pipe->pipe_settings.capture.post_isp_binary); if (err) return err; } @@ -6400,9 +6255,9 @@ static int load_advanced_binaries( struct ia_css_binary_descr gdc_descr; ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info, - &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); + &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); err = ia_css_binary_find(&gdc_descr, - &pipe->pipe_settings.capture.anr_gdc_binary); + &pipe->pipe_settings.capture.anr_gdc_binary); if (err) return err; } @@ -6414,9 +6269,9 @@ static int load_advanced_binaries( struct ia_css_binary_descr pre_gdc_descr; ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info, - &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); + &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); err = ia_css_binary_find(&pre_gdc_descr, - &pipe->pipe_settings.capture.pre_isp_binary); + &pipe->pipe_settings.capture.pre_isp_binary); if (err) return err; } @@ -6438,7 +6293,7 @@ static int load_advanced_binaries( ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info); err = ia_css_binary_find(&vf_pp_descr, - &pipe->pipe_settings.capture.vf_pp_binary); + &pipe->pipe_settings.capture.vf_pp_binary); if (err) return err; } @@ -6450,14 +6305,14 @@ static int load_advanced_binaries( #endif if (need_isp_copy) load_copy_binary(pipe, - &pipe->pipe_settings.capture.copy_binary, - &pipe->pipe_settings.capture.pre_isp_binary); + &pipe->pipe_settings.capture.copy_binary, + &pipe->pipe_settings.capture.pre_isp_binary); return err; } -static int load_bayer_isp_binaries( - struct ia_css_pipe *pipe) { +static int load_bayer_isp_binaries(struct ia_css_pipe *pipe) +{ struct ia_css_frame_info pre_isp_in_info, *pipe_out_info; int err = 0; struct ia_css_binary_descr pre_de_descr; @@ -6465,7 +6320,7 @@ static int load_bayer_isp_binaries( IA_CSS_ENTER_PRIVATE(""); assert(pipe); assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || - pipe->mode == IA_CSS_PIPE_ID_COPY); + pipe->mode == IA_CSS_PIPE_ID_COPY); pipe_out_info = &pipe->output_info[0]; if (pipe->pipe_settings.capture.pre_isp_binary.info) @@ -6476,17 +6331,17 @@ static int load_bayer_isp_binaries( return err; ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr, - &pre_isp_in_info, - pipe_out_info); + &pre_isp_in_info, + pipe_out_info); err = ia_css_binary_find(&pre_de_descr, - &pipe->pipe_settings.capture.pre_isp_binary); + &pipe->pipe_settings.capture.pre_isp_binary); return err; } -static int load_low_light_binaries( - struct ia_css_pipe *pipe) { +static int load_low_light_binaries(struct ia_css_pipe *pipe) +{ struct ia_css_frame_info pre_in_info, anr_in_info, post_in_info, post_out_info, vf_info, *pipe_vf_out_info, *pipe_out_info, @@ -6498,7 +6353,7 @@ static int load_low_light_binaries( IA_CSS_ENTER_PRIVATE(""); assert(pipe); assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || - pipe->mode == IA_CSS_PIPE_ID_COPY); + pipe->mode == IA_CSS_PIPE_ID_COPY); if (pipe->pipe_settings.capture.pre_isp_binary.info) return 0; @@ -6513,17 +6368,18 @@ static int load_low_light_binaries( need_pp = need_capture_pp(pipe); ia_css_frame_info_set_format(&vf_info, - IA_CSS_FRAME_FORMAT_YUV_LINE); + IA_CSS_FRAME_FORMAT_YUV_LINE); /* we build up the pipeline starting at the end */ /* Capture post-processing */ if (need_pp) { struct ia_css_binary_descr capture_pp_descr; - ia_css_pipe_get_capturepp_binarydesc(pipe, - &capture_pp_descr, &post_out_info, pipe_out_info, &vf_info); + ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr, + &post_out_info, + pipe_out_info, &vf_info); err = ia_css_binary_find(&capture_pp_descr, - &pipe->pipe_settings.capture.capture_pp_binary); + &pipe->pipe_settings.capture.capture_pp_binary); if (err) return err; } else { @@ -6537,7 +6393,7 @@ static int load_low_light_binaries( ia_css_pipe_get_post_anr_binarydesc(pipe, &post_anr_descr, &post_in_info, &post_out_info, &vf_info); err = ia_css_binary_find(&post_anr_descr, - &pipe->pipe_settings.capture.post_isp_binary); + &pipe->pipe_settings.capture.post_isp_binary); if (err) return err; } @@ -6547,9 +6403,9 @@ static int load_low_light_binaries( struct ia_css_binary_descr anr_descr; ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info, - &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); + &pipe->pipe_settings.capture.post_isp_binary.in_frame_info); err = ia_css_binary_find(&anr_descr, - &pipe->pipe_settings.capture.anr_gdc_binary); + &pipe->pipe_settings.capture.anr_gdc_binary); if (err) return err; } @@ -6561,9 +6417,9 @@ static int load_low_light_binaries( struct ia_css_binary_descr pre_anr_descr; ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info, - &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); + &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info); err = ia_css_binary_find(&pre_anr_descr, - &pipe->pipe_settings.capture.pre_isp_binary); + &pipe->pipe_settings.capture.pre_isp_binary); if (err) return err; } @@ -6582,10 +6438,10 @@ static int load_low_light_binaries( { struct ia_css_binary_descr vf_pp_descr; - ia_css_pipe_get_vfpp_binarydesc(pipe, - &vf_pp_descr, vf_pp_in_info, pipe_vf_out_info); + ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, + vf_pp_in_info, pipe_vf_out_info); err = ia_css_binary_find(&vf_pp_descr, - &pipe->pipe_settings.capture.vf_pp_binary); + &pipe->pipe_settings.capture.vf_pp_binary); if (err) return err; } @@ -6597,8 +6453,8 @@ static int load_low_light_binaries( #endif if (need_isp_copy) err = load_copy_binary(pipe, - &pipe->pipe_settings.capture.copy_binary, - &pipe->pipe_settings.capture.pre_isp_binary); + &pipe->pipe_settings.capture.copy_binary, + &pipe->pipe_settings.capture.pre_isp_binary); return err; } @@ -6623,15 +6479,15 @@ static bool copy_on_sp(struct ia_css_pipe *pipe) return rval; } -static int load_capture_binaries( - struct ia_css_pipe *pipe) { +static int load_capture_binaries(struct ia_css_pipe *pipe) +{ int err = 0; bool must_be_raw; IA_CSS_ENTER_PRIVATE(""); assert(pipe); assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || - pipe->mode == IA_CSS_PIPE_ID_COPY); + pipe->mode == IA_CSS_PIPE_ID_COPY); if (pipe->pipe_settings.capture.primary_binary[0].info) { IA_CSS_LEAVE_ERR_PRIVATE(0); @@ -6692,13 +6548,14 @@ static int load_capture_binaries( } static int -unload_capture_binaries(struct ia_css_pipe *pipe) { +unload_capture_binaries(struct ia_css_pipe *pipe) +{ unsigned int i; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || ((pipe->mode != IA_CSS_PIPE_ID_CAPTURE) && (pipe->mode != IA_CSS_PIPE_ID_COPY))) - { + if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE && + pipe->mode != IA_CSS_PIPE_ID_COPY)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -6726,7 +6583,8 @@ unload_capture_binaries(struct ia_css_pipe *pipe) { static bool need_downscaling(const struct ia_css_resolution in_res, - const struct ia_css_resolution out_res) { + const struct ia_css_resolution out_res) +{ if (in_res.width > out_res.width || in_res.height > out_res.height) return true; @@ -6734,7 +6592,8 @@ need_downscaling(const struct ia_css_resolution in_res, } static bool -need_yuv_scaler_stage(const struct ia_css_pipe *pipe) { +need_yuv_scaler_stage(const struct ia_css_pipe *pipe) +{ unsigned int i; struct ia_css_resolution in_res, out_res; @@ -6773,10 +6632,11 @@ need_yuv_scaler_stage(const struct ia_css_pipe *pipe) { /* which has some hard-coded knowledge which prevents reuse of the function. */ /* Later, merge this with ia_css_pipe_create_cas_scaler_desc */ static int ia_css_pipe_create_cas_scaler_desc_single_output( - struct ia_css_frame_info *cas_scaler_in_info, - struct ia_css_frame_info *cas_scaler_out_info, - struct ia_css_frame_info *cas_scaler_vf_info, - struct ia_css_cas_binary_descr *descr) { + struct ia_css_frame_info *cas_scaler_in_info, + struct ia_css_frame_info *cas_scaler_out_info, + struct ia_css_frame_info *cas_scaler_vf_info, + struct ia_css_cas_binary_descr *descr) +{ unsigned int i; unsigned int hor_ds_factor = 0, ver_ds_factor = 0; int err = 0; @@ -6794,9 +6654,9 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output( descr->num_output_stage = 1; hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width, - cas_scaler_out_info->res.width); + cas_scaler_out_info->res.width); ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height, - cas_scaler_out_info->res.height); + cas_scaler_out_info->res.height); /* use the same horizontal and vertical downscaling factor for simplicity */ assert(hor_ds_factor == ver_ds_factor); @@ -6806,31 +6666,36 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output( i *= max_scale_factor_per_stage; } - descr->in_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), - GFP_KERNEL); + descr->in_info = kmalloc(descr->num_stage * + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->in_info) { err = -ENOMEM; goto ERR; } - descr->internal_out_info = kmalloc(descr->num_stage * sizeof( - struct ia_css_frame_info), GFP_KERNEL); + descr->internal_out_info = kmalloc(descr->num_stage * + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->internal_out_info) { err = -ENOMEM; goto ERR; } - descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), - GFP_KERNEL); + descr->out_info = kmalloc(descr->num_stage * + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->out_info) { err = -ENOMEM; goto ERR; } - descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), - GFP_KERNEL); + descr->vf_info = kmalloc(descr->num_stage * + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->vf_info) { err = -ENOMEM; goto ERR; } - descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), GFP_KERNEL); + descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), + GFP_KERNEL); if (!descr->is_output_stage) { err = -ENOMEM; goto ERR; @@ -6874,9 +6739,9 @@ static int ia_css_pipe_create_cas_scaler_desc_single_output( max_scale_factor_per_stage; descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; ia_css_frame_info_init(&descr->internal_out_info[i], - tmp_in_info.res.width / max_scale_factor_per_stage, - tmp_in_info.res.height / max_scale_factor_per_stage, - IA_CSS_FRAME_FORMAT_YUV420, 0); + tmp_in_info.res.width / max_scale_factor_per_stage, + tmp_in_info.res.height / max_scale_factor_per_stage, + IA_CSS_FRAME_FORMAT_YUV420, 0); descr->out_info[i].res.width = 0; descr->out_info[i].res.height = 0; descr->vf_info[i].res.width = 0; @@ -6892,9 +6757,10 @@ ERR: } /* FIXME: merge most of this and single output version */ -static int ia_css_pipe_create_cas_scaler_desc( - struct ia_css_pipe *pipe, - struct ia_css_cas_binary_descr *descr) { +static int +ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe, + struct ia_css_cas_binary_descr *descr) +{ struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO; struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; @@ -6951,30 +6817,35 @@ static int ia_css_pipe_create_cas_scaler_desc( descr->num_stage = num_stages; descr->in_info = kmalloc_array(descr->num_stage, - sizeof(struct ia_css_frame_info), GFP_KERNEL); + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->in_info) { err = -ENOMEM; goto ERR; } - descr->internal_out_info = kmalloc(descr->num_stage * sizeof( - struct ia_css_frame_info), GFP_KERNEL); + descr->internal_out_info = kmalloc(descr->num_stage * + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->internal_out_info) { err = -ENOMEM; goto ERR; } - descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), - GFP_KERNEL); + descr->out_info = kmalloc(descr->num_stage * + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->out_info) { err = -ENOMEM; goto ERR; } - descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), - GFP_KERNEL); + descr->vf_info = kmalloc(descr->num_stage * + sizeof(struct ia_css_frame_info), + GFP_KERNEL); if (!descr->vf_info) { err = -ENOMEM; goto ERR; } - descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), GFP_KERNEL); + descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), + GFP_KERNEL); if (!descr->is_output_stage) { err = -ENOMEM; goto ERR; @@ -6984,7 +6855,7 @@ static int ia_css_pipe_create_cas_scaler_desc( if (out_info[i]) { if (i > 0) { assert((out_info[i - 1]->res.width >= out_info[i]->res.width) && - (out_info[i - 1]->res.height >= out_info[i]->res.height)); + (out_info[i - 1]->res.height >= out_info[i]->res.height)); } } } @@ -7032,9 +6903,9 @@ static int ia_css_pipe_create_cas_scaler_desc( max_scale_factor_per_stage; descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420; ia_css_frame_info_init(&descr->internal_out_info[i], - tmp_in_info.res.width / max_scale_factor_per_stage, - tmp_in_info.res.height / max_scale_factor_per_stage, - IA_CSS_FRAME_FORMAT_YUV420, 0); + tmp_in_info.res.width / max_scale_factor_per_stage, + tmp_in_info.res.height / max_scale_factor_per_stage, + IA_CSS_FRAME_FORMAT_YUV420, 0); descr->out_info[i].res.width = 0; descr->out_info[i].res.height = 0; descr->vf_info[i].res.width = 0; @@ -7050,7 +6921,8 @@ ERR: } static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr - *descr) { + *descr) +{ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "ia_css_pipe_destroy_cas_scaler_desc() enter:\n"); kfree(descr->in_info); @@ -7068,7 +6940,8 @@ static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr } static int -load_yuvpp_binaries(struct ia_css_pipe *pipe) { +load_yuvpp_binaries(struct ia_css_pipe *pipe) +{ int err = 0; bool need_scaler = false; struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; @@ -7093,8 +6966,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { mycs = &pipe->pipe_settings.yuvpp; - for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) - { + for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { if (pipe->vf_output_info[i].res.width != 0) { err = ia_css_util_check_vf_out_info(&pipe->output_info[i], &pipe->vf_output_info[i]); @@ -7108,18 +6980,18 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { /* we build up the pipeline starting at the end */ /* Capture post-processing */ - if (need_scaler) - { + if (need_scaler) { struct ia_css_binary_descr yuv_scaler_descr; err = ia_css_pipe_create_cas_scaler_desc(pipe, - &cas_scaler_descr); + &cas_scaler_descr); if (err) goto ERR; mycs->num_output = cas_scaler_descr.num_output_stage; mycs->num_yuv_scaler = cas_scaler_descr.num_stage; mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * - sizeof(struct ia_css_binary), GFP_KERNEL); + sizeof(struct ia_css_binary), + GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; goto ERR; @@ -7133,28 +7005,25 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { for (i = 0; i < cas_scaler_descr.num_stage; i++) { mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i]; ia_css_pipe_get_yuvscaler_binarydesc(pipe, - &yuv_scaler_descr, &cas_scaler_descr.in_info[i], - &cas_scaler_descr.out_info[i], - &cas_scaler_descr.internal_out_info[i], - &cas_scaler_descr.vf_info[i]); + &yuv_scaler_descr, + &cas_scaler_descr.in_info[i], + &cas_scaler_descr.out_info[i], + &cas_scaler_descr.internal_out_info[i], + &cas_scaler_descr.vf_info[i]); err = ia_css_binary_find(&yuv_scaler_descr, - &mycs->yuv_scaler_binary[i]); + &mycs->yuv_scaler_binary[i]); if (err) goto ERR; } ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); - } else - { + } else { mycs->num_output = 1; } if (need_scaler) - { next_binary = &mycs->yuv_scaler_binary[0]; - } else - { + else next_binary = NULL; - } #if defined(ISP2401) /* @@ -7180,11 +7049,10 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { need_isp_copy_binary = true; #endif /* ISP2401 */ - if (need_isp_copy_binary) - { + if (need_isp_copy_binary) { err = load_copy_binary(pipe, - &mycs->copy_binary, - next_binary); + &mycs->copy_binary, + next_binary); if (err) goto ERR; @@ -7211,8 +7079,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { } /* Viewfinder post-processing */ - if (need_scaler) - { + if (need_scaler) { for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) { if (mycs->is_output_stage[i]) { assert(j < 2); @@ -7222,19 +7089,18 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { } } mycs->num_vf_pp = j; - } else - { + } else { vf_pp_in_info[0] = &mycs->copy_binary.vf_frame_info; - for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { + for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) vf_pp_in_info[i] = NULL; - } + mycs->num_vf_pp = 1; } - mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * sizeof(struct ia_css_binary), - GFP_KERNEL); - if (!mycs->vf_pp_binary) - { + mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * + sizeof(struct ia_css_binary), + GFP_KERNEL); + if (!mycs->vf_pp_binary) { err = -ENOMEM; goto ERR; } @@ -7242,8 +7108,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { { struct ia_css_binary_descr vf_pp_descr; - for (i = 0; i < mycs->num_vf_pp; i++) - { + for (i = 0; i < mycs->num_vf_pp; i++) { if (pipe->vf_output_info[i].res.width != 0) { ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]); @@ -7259,34 +7124,31 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) { ERR: if (need_scaler) - { ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); - } + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n", err); return err; } static int -unload_yuvpp_binaries(struct ia_css_pipe *pipe) { +unload_yuvpp_binaries(struct ia_css_pipe *pipe) +{ unsigned int i; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) - { + if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary); for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++) - { ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]); - } + for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++) - { ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]); - } + kfree(pipe->pipe_settings.yuvpp.is_output_stage); pipe->pipe_settings.yuvpp.is_output_stage = NULL; kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary); @@ -7336,25 +7198,23 @@ static int yuvpp_start(struct ia_css_pipe *pipe) } static int -sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) { +sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) +{ int err = 0; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if (!pipe) - { + if (!pipe) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } /* PIPE_MODE_COPY has no binaries, but has output frames to outside*/ - if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) - { + if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) { IA_CSS_LEAVE_ERR_PRIVATE(0); return 0; } - switch (pipe->mode) - { + switch (pipe->mode) { case IA_CSS_PIPE_ID_PREVIEW: err = unload_preview_binaries(pipe); break; @@ -7375,7 +7235,8 @@ sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe) { } static int -sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) { +sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) +{ int err = 0; assert(pipe); @@ -7385,8 +7246,7 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) { if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) return err; - switch (pipe->mode) - { + switch (pipe->mode) { case IA_CSS_PIPE_ID_PREVIEW: err = load_preview_binaries(pipe); break; @@ -7405,8 +7265,7 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) { err = -EINVAL; break; } - if (err) - { + if (err) { if (sh_css_pipe_unload_binaries(pipe)) { /* currently css does not support multiple error returns in a single function, * using -EINVAL in this case */ @@ -7417,7 +7276,8 @@ sh_css_pipe_load_binaries(struct ia_css_pipe *pipe) { } static int -create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { +create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) +{ struct ia_css_pipeline *me; int err = 0; struct ia_css_pipeline_stage *vf_pp_stage = NULL, @@ -7444,15 +7304,13 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { #endif IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); - if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) - { + if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } me = &pipe->pipeline; ia_css_pipeline_clean(me); - for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) - { + for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { out_frame[i] = NULL; vf_frame[i] = NULL; } @@ -7480,8 +7338,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { /* the input frame can come from: * a) memory: connect yuvscaler to me->in_frame * b) sensor, via copy binary: connect yuvscaler to copy binary later on */ - if (need_in_frameinfo_memory) - { + if (need_in_frameinfo_memory) { /* TODO: improve for different input formats. */ /* @@ -7530,13 +7387,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { } in_frame = &me->in_frame; - } else - { + } else { in_frame = NULL; } - for (i = 0; i < num_output_stage; i++) - { + for (i = 0; i < num_output_stage; i++) { assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE); if (pipe->output_info[i].res.width != 0) { err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i); @@ -7563,8 +7418,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary; need_scaler = need_yuv_scaler_stage(pipe); - if (pipe->pipe_settings.yuvpp.copy_binary.info) - { + if (pipe->pipe_settings.yuvpp.copy_binary.info) { struct ia_css_frame *in_frame_local = NULL; #ifdef ISP2401 @@ -7574,18 +7428,26 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { #endif if (need_scaler) { - ia_css_pipe_util_set_output_frames(bin_out_frame, 0, NULL); - ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, - bin_out_frame, in_frame_local, NULL); + ia_css_pipe_util_set_output_frames(bin_out_frame, + 0, NULL); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + copy_binary, + bin_out_frame, + in_frame_local, + NULL); } else { - ia_css_pipe_util_set_output_frames(bin_out_frame, 0, out_frame[0]); - ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, - bin_out_frame, in_frame_local, NULL); + ia_css_pipe_util_set_output_frames(bin_out_frame, + 0, out_frame[0]); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + copy_binary, + bin_out_frame, + in_frame_local, + NULL); } err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - ©_stage); + &stage_desc, + ©_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -7602,8 +7464,7 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { } } - if (need_scaler) - { + if (need_scaler) { struct ia_css_frame *tmp_out_frame = NULL; struct ia_css_frame *tmp_vf_frame = NULL; struct ia_css_frame *tmp_in_frame = in_frame; @@ -7618,10 +7479,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { tmp_vf_frame = NULL; } - err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame, - NULL, - &yuv_scaler_binary[i], - &yuv_scaler_stage); + err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, + tmp_out_frame, + NULL, + &yuv_scaler_binary[i], + &yuv_scaler_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -7632,8 +7494,10 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { if (pipe->pipe_settings.yuvpp.is_output_stage[i]) { if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) { in_frame = yuv_scaler_stage->args.out_vf_frame; - err = add_vf_pp_stage(pipe, in_frame, tmp_vf_frame, &vf_pp_binary[j], - &vf_pp_stage); + err = add_vf_pp_stage(pipe, in_frame, + tmp_vf_frame, + &vf_pp_binary[j], + &vf_pp_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -7643,12 +7507,11 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { j++; } } - } else if (copy_stage) - { + } else if (copy_stage) { if (vf_frame[0] && vf_frame[0]->info.res.width != 0) { in_frame = copy_stage->args.out_vf_frame; - err = add_vf_pp_stage(pipe, in_frame, vf_frame[0], &vf_pp_binary[0], - &vf_pp_stage); + err = add_vf_pp_stage(pipe, in_frame, vf_frame[0], + &vf_pp_binary[0], &vf_pp_stage); } if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -7656,7 +7519,8 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { } } - ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous); + ia_css_pipeline_finalize_stages(&pipe->pipeline, + pipe->stream->config.continuous); IA_CSS_LEAVE_ERR_PRIVATE(0); @@ -7665,8 +7529,9 @@ create_host_yuvpp_pipeline(struct ia_css_pipe *pipe) { static int create_host_copy_pipeline(struct ia_css_pipe *pipe, - unsigned int max_input_width, - struct ia_css_frame *out_frame) { + unsigned int max_input_width, + struct ia_css_frame *out_frame) +{ struct ia_css_pipeline *me; int err = 0; struct ia_css_pipeline_stage_desc stage_desc; @@ -7683,16 +7548,10 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe, out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE; if (copy_on_sp(pipe) && - pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) - { - ia_css_frame_info_init( - &out_frame->info, - JPEG_BYTES, - 1, - IA_CSS_FRAME_FORMAT_BINARY_8, - 0); - } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) - { + pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { + ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1, + IA_CSS_FRAME_FORMAT_BINARY_8, 0); + } else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) { out_frame->info.raw_bit_depth = ia_css_pipe_util_pipe_input_format_bpp(pipe); } @@ -7702,12 +7561,12 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe, pipe->mode = IA_CSS_PIPE_ID_COPY; ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame, - IA_CSS_PIPELINE_RAW_COPY, max_input_width); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - NULL); + IA_CSS_PIPELINE_RAW_COPY, + max_input_width); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL); - ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous); + ia_css_pipeline_finalize_stages(&pipe->pipeline, + pipe->stream->config.continuous); ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "create_host_copy_pipeline() leave:\n"); @@ -7716,7 +7575,8 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe, } static int -create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) { +create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) +{ struct ia_css_pipeline *me = &pipe->pipeline; int err = 0; struct ia_css_pipeline_stage_desc stage_desc; @@ -7745,9 +7605,10 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) { me->pipe_id = IA_CSS_PIPE_ID_CAPTURE; pipe->mode = IA_CSS_PIPE_ID_CAPTURE; ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame, - IA_CSS_PIPELINE_ISYS_COPY, max_input_width); + IA_CSS_PIPELINE_ISYS_COPY, + max_input_width); err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, &out_stage); + &stage_desc, &out_stage); if (err) return err; @@ -7760,7 +7621,8 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe) { } static int -create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { +create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) +{ struct ia_css_pipeline *me; int err = 0; enum ia_css_capture_mode mode; @@ -7798,7 +7660,8 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { IA_CSS_ENTER_PRIVATE(""); assert(pipe); assert(pipe->stream); - assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || pipe->mode == IA_CSS_PIPE_ID_COPY); + assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE || + pipe->mode == IA_CSS_PIPE_ID_COPY); me = &pipe->pipeline; mode = pipe->config.default_capture_config.mode; @@ -7824,8 +7687,7 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { /* Construct in_frame info (only in case we have dynamic input */ need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY; #endif - if (need_in_frameinfo_memory) - { + if (need_in_frameinfo_memory) { err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame, IA_CSS_FRAME_FORMAT_RAW); if (err) { @@ -7834,22 +7696,19 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { } in_frame = &me->in_frame; - } else - { + } else { in_frame = NULL; } err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } out_frame = &me->out_frame[0]; /* Construct vf_frame info (only in case we have VF) */ - if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) - { + if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) { if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) { /* These modes don't support viewfinder output */ vf_frame = NULL; @@ -7857,22 +7716,20 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0); vf_frame = &me->vf_frame[0]; } - } else - { + } else { vf_frame = NULL; } copy_binary = &pipe->pipe_settings.capture.copy_binary; num_primary_stage = pipe->pipe_settings.capture.num_primary_stage; - if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) - { + if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } + for (i = 0; i < num_primary_stage; i++) - { primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i]; - } + vf_pp_binary = &pipe->pipe_settings.capture.vf_pp_binary; pre_isp_binary = &pipe->pipe_settings.capture.pre_isp_binary; anr_gdc_binary = &pipe->pipe_settings.capture.anr_gdc_binary; @@ -7889,43 +7746,51 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info); need_ldc = (capture_ldc_binary && capture_ldc_binary->info); - if (pipe->pipe_settings.capture.copy_binary.info) - { + if (pipe->pipe_settings.capture.copy_binary.info) { if (raw) { ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); #if defined(ISP2401) if (!continuous) { - ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, - out_frames, in_frame, NULL); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + copy_binary, + out_frames, + in_frame, + NULL); } else { in_frame = pipe->stream->last_pipe->continuous_frames[0]; - ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, - out_frames, in_frame, NULL); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + copy_binary, + out_frames, + in_frame, + NULL); } #else - ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, - out_frames, NULL, NULL); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + copy_binary, + out_frames, + NULL, NULL); #endif } else { - ia_css_pipe_util_set_output_frames(out_frames, 0, in_frame); - ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary, - out_frames, NULL, NULL); + ia_css_pipe_util_set_output_frames(out_frames, 0, + in_frame); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + copy_binary, + out_frames, + NULL, NULL); } err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - ¤t_stage); + &stage_desc, + ¤t_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - } else if (pipe->stream->config.continuous) - { + } else if (pipe->stream->config.continuous) { in_frame = pipe->stream->last_pipe->continuous_frames[0]; } - if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) - { + if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) { struct ia_css_frame *local_in_frame = NULL; struct ia_css_frame *local_out_frame = NULL; @@ -7953,11 +7818,14 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { * Proper investigation should be done to come up with the clean * solution. * */ - ia_css_pipe_get_generic_stage_desc(&stage_desc, primary_binary[i], - out_frames, local_in_frame, NULL); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + primary_binary[i], + out_frames, + local_in_frame, + NULL); err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - ¤t_stage); + &stage_desc, + ¤t_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -7970,22 +7838,21 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { IA_CSS_BINARY_MODE_COPY; current_stage->args.copy_output = current_stage->args.copy_vf; } else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED || - mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) - { + mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary, - out_frames, in_frame, NULL); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, NULL); + out_frames, in_frame, NULL); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + NULL); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary, - out_frames, NULL, NULL); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, NULL); + out_frames, NULL, NULL); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + NULL); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -7993,28 +7860,31 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { if (need_pp) { ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); - ia_css_pipe_get_generic_stage_desc(&stage_desc, post_isp_binary, - out_frames, NULL, NULL); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + post_isp_binary, + out_frames, + NULL, NULL); } else { - ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); - ia_css_pipe_get_generic_stage_desc(&stage_desc, post_isp_binary, - out_frames, NULL, NULL); + ia_css_pipe_util_set_output_frames(out_frames, 0, + out_frame); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + post_isp_binary, + out_frames, + NULL, NULL); } - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, ¤t_stage); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + ¤t_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) - { + } else if (mode == IA_CSS_CAPTURE_MODE_BAYER) { ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary, - out_frames, in_frame, NULL); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - NULL); + out_frames, in_frame, NULL); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + NULL); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -8022,49 +7892,48 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { } #ifndef ISP2401 - if (need_pp && current_stage) - { + if (need_pp && current_stage) { struct ia_css_frame *local_in_frame = NULL; local_in_frame = current_stage->args.out_frame[0]; if (need_ldc) { ia_css_pipe_util_set_output_frames(out_frames, 0, NULL); - ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary, - out_frames, local_in_frame, NULL); + ia_css_pipe_get_generic_stage_desc(&stage_desc, + capture_ldc_binary, + out_frames, + local_in_frame, + NULL); err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - ¤t_stage); + &stage_desc, + ¤t_stage); local_in_frame = current_stage->args.out_frame[0]; } err = add_capture_pp_stage(pipe, me, local_in_frame, - need_yuv_pp ? NULL : out_frame, + need_yuv_pp ? NULL : out_frame, #else /* ldc and capture_pp not supported in same pipeline */ - if (need_ldc && current_stage) - { + if (need_ldc && current_stage) { in_frame = current_stage->args.out_frame[0]; ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame); ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary, - out_frames, in_frame, NULL); - err = ia_css_pipeline_create_and_add_stage(me, - &stage_desc, - NULL); - } else if (need_pp && current_stage) - { + out_frames, in_frame, NULL); + err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, + NULL); + } else if (need_pp && current_stage) { in_frame = current_stage->args.out_frame[0]; - err = add_capture_pp_stage(pipe, me, in_frame, need_yuv_pp ? NULL : out_frame, + err = add_capture_pp_stage(pipe, me, in_frame, + need_yuv_pp ? NULL : out_frame, #endif - capture_pp_binary, - ¤t_stage); + capture_pp_binary, + ¤t_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } } - if (need_yuv_pp && current_stage) - { + if (need_yuv_pp && current_stage) { struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0]; struct ia_css_frame *tmp_out_frame = NULL; @@ -8074,10 +7943,10 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { else tmp_out_frame = NULL; - err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, tmp_out_frame, - NULL, - &yuv_scaler_binary[i], - &yuv_scaler_stage); + err = add_yuv_scaler_stage(pipe, me, tmp_in_frame, + tmp_out_frame, NULL, + &yuv_scaler_binary[i], + &yuv_scaler_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -8096,11 +7965,12 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { * should not be considered as a clean solution. Proper * investigation should be done to come up with the clean solution. * */ - if (mode != IA_CSS_CAPTURE_MODE_RAW && mode != IA_CSS_CAPTURE_MODE_BAYER && current_stage && vf_frame) - { + if (mode != IA_CSS_CAPTURE_MODE_RAW && + mode != IA_CSS_CAPTURE_MODE_BAYER && + current_stage && vf_frame) { in_frame = current_stage->args.out_vf_frame; err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary, - ¤t_stage); + ¤t_stage); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -8115,7 +7985,8 @@ create_host_regular_capture_pipeline(struct ia_css_pipe *pipe) { } static int -create_host_capture_pipeline(struct ia_css_pipe *pipe) { +create_host_capture_pipeline(struct ia_css_pipe *pipe) +{ int err = 0; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); @@ -8124,8 +7995,7 @@ create_host_capture_pipeline(struct ia_css_pipe *pipe) { err = create_host_isyscopy_capture_pipeline(pipe); else err = create_host_regular_capture_pipeline(pipe); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } @@ -8135,8 +8005,8 @@ create_host_capture_pipeline(struct ia_css_pipe *pipe) { return err; } -static int capture_start( - struct ia_css_pipe *pipe) { +static int capture_start(struct ia_css_pipe *pipe) +{ struct ia_css_pipeline *me; int err = 0; @@ -8151,7 +8021,7 @@ static int capture_start( me = &pipe->pipeline; if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW || - pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) && + pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) && (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) { if (copy_on_sp(pipe)) { err = start_copy_on_sp(pipe, &me->out_frame[0]); @@ -8195,7 +8065,7 @@ static int capture_start( if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY && pipe->stream->reconfigure_css_rx) { ia_css_isys_rx_configure(&pipe->stream->csi_rx_config, - pipe->stream->config.mode); + pipe->stream->config.mode); pipe->stream->reconfigure_css_rx = false; } #endif @@ -8206,8 +8076,9 @@ static int capture_start( static int sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe, - struct ia_css_frame_info *info, - unsigned int idx) { + struct ia_css_frame_info *info, + unsigned int idx) +{ assert(pipe); assert(info); @@ -8216,8 +8087,7 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe, *info = pipe->output_info[idx]; if (copy_on_sp(pipe) && - pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) - { + pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) { ia_css_frame_info_init( info, JPEG_BYTES, @@ -8225,8 +8095,7 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe, IA_CSS_FRAME_FORMAT_BINARY_8, 0); } else if (info->format == IA_CSS_FRAME_FORMAT_RAW || - info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) - { + info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) { info->raw_bit_depth = ia_css_pipe_util_pipe_input_format_bpp(pipe); } @@ -8238,9 +8107,10 @@ sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe, void ia_css_stream_send_input_frame(const struct ia_css_stream *stream, - const unsigned short *data, - unsigned int width, - unsigned int height) { + const unsigned short *data, + unsigned int width, + unsigned int height) +{ assert(stream); ia_css_inputfifo_send_input_frame( @@ -8251,7 +8121,8 @@ ia_css_stream_send_input_frame(const struct ia_css_stream *stream, } void -ia_css_stream_start_input_frame(const struct ia_css_stream *stream) { +ia_css_stream_start_input_frame(const struct ia_css_stream *stream) +{ assert(stream); ia_css_inputfifo_start_frame( @@ -8262,21 +8133,23 @@ ia_css_stream_start_input_frame(const struct ia_css_stream *stream) { void ia_css_stream_send_input_line(const struct ia_css_stream *stream, - const unsigned short *data, - unsigned int width, - const unsigned short *data2, - unsigned int width2) { + const unsigned short *data, + unsigned int width, + const unsigned short *data2, + unsigned int width2) +{ assert(stream); ia_css_inputfifo_send_line(stream->config.channel_id, - data, width, data2, width2); + data, width, data2, width2); } void ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream, - enum atomisp_input_format format, - const unsigned short *data, - unsigned int width) { + enum atomisp_input_format format, + const unsigned short *data, + unsigned int width) +{ assert(stream); if (!data || width == 0) return; @@ -8285,14 +8158,16 @@ ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream, } void -ia_css_stream_end_input_frame(const struct ia_css_stream *stream) { +ia_css_stream_end_input_frame(const struct ia_css_stream *stream) +{ assert(stream); ia_css_inputfifo_end_frame(stream->config.channel_id); } static void -append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) { +append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) +{ IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware); if (!l) { IA_CSS_ERROR("NULL fw_info"); @@ -8307,7 +8182,8 @@ append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) { } static void -remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) { +remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware) +{ assert(*l); assert(firmware); (void)l; @@ -8349,12 +8225,12 @@ static int upload_isp_code(struct ia_css_fw_info *firmware) } static int -acc_load_extension(struct ia_css_fw_info *firmware) { +acc_load_extension(struct ia_css_fw_info *firmware) +{ int err; struct ia_css_fw_info *hd = firmware; - while (hd) - { + while (hd) { err = upload_isp_code(hd); if (err) return err; @@ -8368,7 +8244,8 @@ acc_load_extension(struct ia_css_fw_info *firmware) { } static void -acc_unload_extension(struct ia_css_fw_info *firmware) { +acc_unload_extension(struct ia_css_fw_info *firmware) +{ struct ia_css_fw_info *hd = firmware; struct ia_css_fw_info *hdn = NULL; @@ -8392,13 +8269,13 @@ acc_unload_extension(struct ia_css_fw_info *firmware) { /* Load firmware for extension */ static int ia_css_pipe_load_extension(struct ia_css_pipe *pipe, - struct ia_css_fw_info *firmware) { + struct ia_css_fw_info *firmware) +{ int err = 0; IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe); - if ((!firmware) || (!pipe)) - { + if ((!firmware) || (!pipe)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -8416,7 +8293,8 @@ ia_css_pipe_load_extension(struct ia_css_pipe *pipe, /* Unload firmware for extension */ static void ia_css_pipe_unload_extension(struct ia_css_pipe *pipe, - struct ia_css_fw_info *firmware) { + struct ia_css_fw_info *firmware) +{ IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe); if ((!firmware) || (!pipe)) { @@ -8435,7 +8313,8 @@ ia_css_pipe_unload_extension(struct ia_css_pipe *pipe, } bool -ia_css_pipeline_uses_params(struct ia_css_pipeline *me) { +ia_css_pipeline_uses_params(struct ia_css_pipeline *me) +{ struct ia_css_pipeline_stage *stage; assert(me); @@ -8456,7 +8335,8 @@ ia_css_pipeline_uses_params(struct ia_css_pipeline *me) { static int sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline, - const void *acc_fw) { + const void *acc_fw) +{ struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw; /* In QoS case, load_extension already called, so skipping */ int err = 0; @@ -8468,14 +8348,13 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline, "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n", pipeline, acc_fw); - if (!err) - { + if (!err) { struct ia_css_pipeline_stage_desc stage_desc; ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw); err = ia_css_pipeline_create_and_add_stage(pipeline, - &stage_desc, - NULL); + &stage_desc, + NULL); } ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, @@ -8488,7 +8367,8 @@ sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline, * Refer to "sh_css_internal.h" for details. */ int ia_css_stream_capture_frame(struct ia_css_stream *stream, - unsigned int exp_id) { + unsigned int exp_id) +{ struct sh_css_tag_descr tag_descr; u32 encoded_tag_descr; int err; @@ -8526,11 +8406,9 @@ int ia_css_stream_capture_frame(struct ia_css_stream *stream, * @brief Configure the continuous capture. * Refer to "sh_css_internal.h" for details. */ -int ia_css_stream_capture( - struct ia_css_stream *stream, - int num_captures, - unsigned int skip, - int offset) { +int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures, + unsigned int skip, int offset) +{ struct sh_css_tag_descr tag_descr; unsigned int encoded_tag_descr; int return_err; @@ -8593,8 +8471,9 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream) ia_css_debug_dump_sp_sw_debug_info(); ia_css_debug_dump_debug_info(NULL); } - } else + } else { IA_CSS_LOG("SP is not running!"); + } #endif ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, @@ -8602,7 +8481,8 @@ void ia_css_stream_request_flash(struct ia_css_stream *stream) } static void -sh_css_init_host_sp_control_vars(void) { +sh_css_init_host_sp_control_vars(void) +{ const struct ia_css_fw_info *fw; unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started; @@ -8643,22 +8523,22 @@ sh_css_init_host_sp_control_vars(void) { (void)HIVE_ADDR_host_sp_com; sp_dmem_store_uint32(SP0_ID, - (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started), - (uint32_t)(0)); + (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started), + (uint32_t)(0)); sp_dmem_store_uint32(SP0_ID, - (unsigned int)sp_address_of(host_sp_queues_initialized), - (uint32_t)(0)); + (unsigned int)sp_address_of(host_sp_queues_initialized), + (uint32_t)(0)); sp_dmem_store_uint32(SP0_ID, - (unsigned int)sp_address_of(sp_sleep_mode), - (uint32_t)(0)); + (unsigned int)sp_address_of(sp_sleep_mode), + (uint32_t)(0)); sp_dmem_store_uint32(SP0_ID, - (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb), - (uint32_t)(false)); + (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb), + (uint32_t)(false)); #ifndef ISP2401 sp_dmem_store_uint32(SP0_ID, - (unsigned int)sp_address_of(sp_stop_copy_preview), - my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0)); + (unsigned int)sp_address_of(sp_stop_copy_preview), + my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0)); #endif store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready); @@ -8685,8 +8565,8 @@ void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config) } void -ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config - *extra_config) { +ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config) +{ if (!extra_config) { IA_CSS_ERROR("NULL input parameter"); return; @@ -8716,11 +8596,11 @@ void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config) } static int -ia_css_acc_pipe_create(struct ia_css_pipe *pipe) { +ia_css_acc_pipe_create(struct ia_css_pipe *pipe) +{ int err = 0; - if (!pipe) - { + if (!pipe) { IA_CSS_ERROR("NULL input parameter"); return -EINVAL; } @@ -8730,9 +8610,7 @@ ia_css_acc_pipe_create(struct ia_css_pipe *pipe) { pipe->config.acc_num_execs = 1; if (pipe->config.acc_extension) - { err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension); - } return err; } @@ -8751,9 +8629,8 @@ int ia_css_pipe_create(const struct ia_css_pipe_config *config, err = ia_css_pipe_create_extra(config, NULL, pipe); - if (err == 0) { + if (err == 0) IA_CSS_LOG("pipe created successfully = %p", *pipe); - } IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -8762,8 +8639,9 @@ int ia_css_pipe_create(const struct ia_css_pipe_config *config, int ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, - const struct ia_css_pipe_extra_config *extra_config, - struct ia_css_pipe **pipe) { + const struct ia_css_pipe_extra_config *extra_config, + struct ia_css_pipe **pipe) +{ int err = -EINVAL; struct ia_css_pipe *internal_pipe = NULL; unsigned int i; @@ -8771,14 +8649,12 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe); /* do not allow to create more than the maximum limit */ - if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) - { + if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) { IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC); return -EINVAL; } - if ((!pipe) || (!config)) - { + if ((!pipe) || (!config)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -8787,8 +8663,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, ia_css_debug_dump_pipe_extra_config(extra_config); err = create_pipe(config->mode, &internal_pipe, false); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } @@ -8800,8 +8675,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, else ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config); - if (config->mode == IA_CSS_PIPE_MODE_ACC) - { + if (config->mode == IA_CSS_PIPE_MODE_ACC) { /* Temporary hack to migrate acceleration to CSS 2.0. * In the future the code for all pipe types should be * unified. */ @@ -8828,15 +8702,13 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, set bayer_ds_out_res equal to IF output resolution(IF may do cropping on sensor output) or use default decimation factor 1. */ if (internal_pipe->extra_config.enable_raw_binning && - internal_pipe->config.bayer_ds_out_res.width) - { + internal_pipe->config.bayer_ds_out_res.width) { /* fill some code here, if no code is needed, please remove it during integration */ } /* YUV downscaling */ if ((internal_pipe->config.vf_pp_in_res.width || - internal_pipe->config.capt_pp_in_res.width)) - { + internal_pipe->config.capt_pp_in_res.width)) { enum ia_css_frame_format format; if (internal_pipe->config.vf_pp_in_res.width) { @@ -8857,8 +8729,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, } } if (internal_pipe->config.vf_pp_in_res.width && - internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) - { + internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) { ia_css_frame_info_init( &internal_pipe->vf_yuv_ds_input_info, internal_pipe->config.vf_pp_in_res.width, @@ -8866,8 +8737,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, IA_CSS_FRAME_FORMAT_YUV_LINE, 0); } /* handle bayer downscaling output info */ - if (internal_pipe->config.bayer_ds_out_res.width) - { + if (internal_pipe->config.bayer_ds_out_res.width) { ia_css_frame_info_init( &internal_pipe->bds_output_info, internal_pipe->config.bayer_ds_out_res.width, @@ -8876,8 +8746,7 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, } /* handle output info, assume always needed */ - for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) - { + for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { if (internal_pipe->config.output_info[i].res.width) { err = sh_css_pipe_configure_output( internal_pipe, @@ -8913,10 +8782,9 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, } } } - if (internal_pipe->config.acc_extension) - { + if (internal_pipe->config.acc_extension) { err = ia_css_pipe_load_extension(internal_pipe, - internal_pipe->config.acc_extension); + internal_pipe->config.acc_extension); if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); kvfree(internal_pipe); @@ -8934,18 +8802,16 @@ ia_css_pipe_create_extra(const struct ia_css_pipe_config *config, int ia_css_pipe_get_info(const struct ia_css_pipe *pipe, - struct ia_css_pipe_info *pipe_info) { + struct ia_css_pipe_info *pipe_info) +{ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_get_info()\n"); - assert(pipe_info); - if (!pipe_info) - { + if (!pipe_info) { ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "ia_css_pipe_get_info: pipe_info cannot be NULL\n"); return -EINVAL; } - if (!pipe || !pipe->stream) - { + if (!pipe || !pipe->stream) { ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n"); return -EINVAL; @@ -8972,41 +8838,37 @@ bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info) int ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe, - int pin_index, - enum ia_css_frame_format new_format) { + int pin_index, + enum ia_css_frame_format new_format) +{ int err = 0; IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format); - if (!pipe) - { + if (!pipe) { IA_CSS_ERROR("pipe is not set"); err = -EINVAL; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - if (0 != pin_index && 1 != pin_index) - { + if (0 != pin_index && 1 != pin_index) { IA_CSS_ERROR("pin index is not valid"); err = -EINVAL; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) - { + if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) { IA_CSS_ERROR("new format is not valid"); err = -EINVAL; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; - } else - { + } else { err = ia_css_pipe_check_format(pipe, new_format); if (!err) { - if (pin_index == 0) { + if (pin_index == 0) pipe->output_info[0].format = new_format; - } else { + else pipe->vf_output_info[0].format = new_format; - } } } IA_CSS_LEAVE_ERR_PRIVATE(err); @@ -9016,7 +8878,8 @@ ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe, #if !defined(ISP2401) /* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */ static int -ia_css_stream_configure_rx(struct ia_css_stream *stream) { +ia_css_stream_configure_rx(struct ia_css_stream *stream) +{ struct ia_css_input_port *config; assert(stream); @@ -9045,11 +8908,10 @@ ia_css_stream_configure_rx(struct ia_css_stream *stream) { if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE) stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE; else - { /* not implemented yet, requires extension of the rx_cfg_t * struct */ return -EINVAL; - } + stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2); stream->reconfigure_css_rx = true; return 0; @@ -9057,10 +8919,9 @@ ia_css_stream_configure_rx(struct ia_css_stream *stream) { #endif static struct ia_css_pipe * -find_pipe(struct ia_css_pipe *pipes[], - unsigned int num_pipes, - enum ia_css_pipe_mode mode, - bool copy_pipe) { +find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes, + enum ia_css_pipe_mode mode, bool copy_pipe) +{ unsigned int i; assert(pipes); @@ -9076,24 +8937,21 @@ find_pipe(struct ia_css_pipe *pipes[], } static int -ia_css_acc_stream_create(struct ia_css_stream *stream) { +ia_css_acc_stream_create(struct ia_css_stream *stream) +{ int i; int err = 0; - assert(stream); IA_CSS_ENTER_PRIVATE("stream = %p", stream); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } - for (i = 0; i < stream->num_pipes; i++) - { + for (i = 0; i < stream->num_pipes; i++) { struct ia_css_pipe *pipe = stream->pipes[i]; - assert(pipe); if (!pipe) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; @@ -9104,14 +8962,12 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) { /* Map SP threads before doing anything. */ err = map_sp_threads(stream, true); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - for (i = 0; i < stream->num_pipes; i++) - { + for (i = 0; i < stream->num_pipes; i++) { struct ia_css_pipe *pipe = stream->pipes[i]; assert(pipe); @@ -9119,8 +8975,7 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) { } err = create_host_pipeline_structure(stream); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } @@ -9134,7 +8989,8 @@ ia_css_acc_stream_create(struct ia_css_stream *stream) { static int metadata_info_init(const struct ia_css_metadata_config *mdc, - struct ia_css_metadata_info *md) { + struct ia_css_metadata_info *md) +{ /* Either both width and height should be set or neither */ if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0)) return -EINVAL; @@ -9161,7 +9017,7 @@ static int check_pipe_resolutions(const struct ia_css_pipe *pipe) } if (ia_css_util_check_res(pipe->config.input_effective_res.width, - pipe->config.input_effective_res.height) != 0) { + pipe->config.input_effective_res.height) != 0) { IA_CSS_ERROR("effective resolution not supported"); err = -EINVAL; goto EXIT; @@ -9169,7 +9025,7 @@ static int check_pipe_resolutions(const struct ia_css_pipe *pipe) if (!ia_css_util_resolution_is_zero( pipe->stream->config.input_config.input_res)) { if (!ia_css_util_res_leq(pipe->config.input_effective_res, - pipe->stream->config.input_config.input_res)) { + pipe->stream->config.input_config.input_res)) { IA_CSS_ERROR("effective resolution is larger than input resolution"); err = -EINVAL; goto EXIT; @@ -9192,9 +9048,10 @@ EXIT: int ia_css_stream_create(const struct ia_css_stream_config *stream_config, - int num_pipes, - struct ia_css_pipe *pipes[], - struct ia_css_stream **stream) { + int num_pipes, + struct ia_css_pipe *pipes[], + struct ia_css_stream **stream) +{ struct ia_css_pipe *curr_pipe; struct ia_css_stream *curr_stream = NULL; bool spcopyonly; @@ -9213,8 +9070,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* some checks */ if (num_pipes == 0 || !stream || - !pipes) - { + !pipes) { err = -EINVAL; IA_CSS_LEAVE_ERR(err); return err; @@ -9223,8 +9079,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, #if !defined(ISP2401) /* We don't support metadata for JPEG stream, since they both use str2mem */ if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 && - stream_config->metadata_config.resolution.height > 0) - { + stream_config->metadata_config.resolution.height > 0) { err = -EINVAL; IA_CSS_LEAVE_ERR(err); return err; @@ -9232,8 +9087,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, #endif #ifdef ISP2401 - if (stream_config->online && stream_config->pack_raw_pixels) - { + if (stream_config->online && stream_config->pack_raw_pixels) { IA_CSS_LOG("online and pack raw is invalid on input system 2401"); err = -EINVAL; IA_CSS_LEAVE_ERR(err); @@ -9288,16 +9142,14 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* Currently we only supported metadata up to a certain size. */ err = metadata_info_init(&stream_config->metadata_config, &md_info); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR(err); return err; } /* allocate the stream instance */ curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL); - if (!curr_stream) - { + if (!curr_stream) { err = -ENOMEM; IA_CSS_LEAVE_ERR(err); return err; @@ -9308,8 +9160,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* allocate pipes */ curr_stream->num_pipes = num_pipes; curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL); - if (!curr_stream->pipes) - { + if (!curr_stream->pipes) { curr_stream->num_pipes = 0; kfree(curr_stream); curr_stream = NULL; @@ -9332,8 +9183,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, #endif #ifdef ISP2401 - if (curr_stream->config.online) - { + if (curr_stream->config.online) { curr_stream->config.source.port.num_lanes = stream_config->source.port.num_lanes; curr_stream->config.mode = IA_CSS_INPUT_MODE_BUFFERED_SENSOR; @@ -9351,8 +9201,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, curr_stream->config.lock_all); /* copy mode specific stuff */ - switch (curr_stream->config.mode) - { + switch (curr_stream->config.mode) { case IA_CSS_INPUT_MODE_SENSOR: case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: #if !defined(ISP2401) @@ -9362,11 +9211,11 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, case IA_CSS_INPUT_MODE_TPG: #if !defined(ISP2401) IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d", - curr_stream->config.source.tpg.x_mask, - curr_stream->config.source.tpg.y_mask, - curr_stream->config.source.tpg.x_delta, - curr_stream->config.source.tpg.y_delta, - curr_stream->config.source.tpg.xy_mask); + curr_stream->config.source.tpg.x_mask, + curr_stream->config.source.tpg.y_mask, + curr_stream->config.source.tpg.x_delta, + curr_stream->config.source.tpg.y_delta, + curr_stream->config.source.tpg.xy_mask); sh_css_sp_configure_tpg( curr_stream->config.source.tpg.x_mask, @@ -9391,17 +9240,14 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, } #ifdef ISP2401 - err = aspect_ratio_crop_init(curr_stream, - pipes, - &aspect_ratio_crop_enabled); - if (err) - { + err = aspect_ratio_crop_init(curr_stream, pipes, + &aspect_ratio_crop_enabled); + if (err) { IA_CSS_LEAVE_ERR(err); goto ERR; } #endif - for (i = 0; i < num_pipes; i++) - { + for (i = 0; i < num_pipes; i++) { struct ia_css_resolution effective_res; curr_pipe = pipes[i]; @@ -9432,8 +9278,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, curr_pipe->config.input_effective_res = effective_res; } IA_CSS_LOG("effective_res=%dx%d", - effective_res.width, - effective_res.height); + effective_res.width, + effective_res.height); } if (IS_ISP2401) { @@ -9441,9 +9287,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, if (pipes[i]->config.mode != IA_CSS_PIPE_MODE_ACC && pipes[i]->config.mode != IA_CSS_PIPE_MODE_COPY) { err = check_pipe_resolutions(pipes[i]); - if (err) { + if (err) goto ERR; - } } } } @@ -9453,32 +9298,28 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, goto ERR; IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs); - if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) - { + if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) { *stream = curr_stream; err = ia_css_acc_stream_create(curr_stream); goto ERR; } /* sensor binning */ - if (!spcopyonly) - { + if (!spcopyonly) { sensor_binning_changed = sh_css_params_set_binning_factor(curr_stream, - curr_stream->config.sensor_binning_factor); - } else - { + curr_stream->config.sensor_binning_factor); + } else { sensor_binning_changed = false; } IA_CSS_LOG("sensor_binning=%d, changed=%d", - curr_stream->config.sensor_binning_factor, sensor_binning_changed); + curr_stream->config.sensor_binning_factor, sensor_binning_changed); /* loop over pipes */ IA_CSS_LOG("num_pipes=%d", num_pipes); curr_stream->cont_capt = false; /* Temporary hack: we give the preview pipe a reference to the capture * pipe in continuous capture mode. */ - if (curr_stream->config.continuous) - { + if (curr_stream->config.continuous) { /* Search for the preview pipe and create the copy pipe */ struct ia_css_pipe *preview_pipe; struct ia_css_pipe *video_pipe; @@ -9496,17 +9337,18 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* Create copy pipe here, since it may not be exposed to the driver */ preview_pipe = find_pipe(pipes, num_pipes, - IA_CSS_PIPE_MODE_PREVIEW, false); + IA_CSS_PIPE_MODE_PREVIEW, false); video_pipe = find_pipe(pipes, num_pipes, - IA_CSS_PIPE_MODE_VIDEO, false); - acc_pipe = find_pipe(pipes, num_pipes, - IA_CSS_PIPE_MODE_ACC, false); + IA_CSS_PIPE_MODE_VIDEO, false); + acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC, + false); if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt) curr_stream->cont_capt = false; /* preview + QoS case will not need cont_capt switch */ if (curr_stream->cont_capt) { capture_pipe = find_pipe(pipes, num_pipes, - IA_CSS_PIPE_MODE_CAPTURE, false); + IA_CSS_PIPE_MODE_CAPTURE, + false); if (!capture_pipe) { err = -EINVAL; goto ERR; @@ -9526,9 +9368,9 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe; copy_pipe->stream = curr_stream; } - if (preview_pipe && curr_stream->cont_capt) { + if (preview_pipe && curr_stream->cont_capt) preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe; - } + if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) { err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, ©_pipe, true); if (err) @@ -9537,15 +9379,13 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, video_pipe->pipe_settings.video.copy_pipe = copy_pipe; copy_pipe->stream = curr_stream; } - if (video_pipe && curr_stream->cont_capt) { + if (video_pipe && curr_stream->cont_capt) video_pipe->pipe_settings.video.capture_pipe = capture_pipe; - } - if (preview_pipe && acc_pipe) { + + if (preview_pipe && acc_pipe) preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe; - } } - for (i = 0; i < num_pipes; i++) - { + for (i = 0; i < num_pipes; i++) { curr_pipe = pipes[i]; /* set current stream */ curr_pipe->stream = curr_stream; @@ -9566,8 +9406,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, } /* now pipes have been configured, info should be available */ - for (i = 0; i < num_pipes; i++) - { + for (i = 0; i < num_pipes; i++) { struct ia_css_pipe_info *pipe_info = NULL; curr_pipe = pipes[i]; @@ -9591,10 +9430,12 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, if (!spcopyonly) { if (!IS_ISP2401) err = sh_css_pipe_get_shading_info(curr_pipe, - &pipe_info->shading_info, NULL); + &pipe_info->shading_info, + NULL); else err = sh_css_pipe_get_shading_info(curr_pipe, - &pipe_info->shading_info, &curr_pipe->config); + &pipe_info->shading_info, + &curr_pipe->config); if (err) goto ERR; @@ -9604,7 +9445,8 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, goto ERR; for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) { sh_css_pipe_get_viewfinder_frame_info(curr_pipe, - &pipe_info->vf_output_info[j], j); + &pipe_info->vf_output_info[j], + j); if (err) goto ERR; } @@ -9617,22 +9459,19 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* Map SP threads before doing anything. */ err = map_sp_threads(curr_stream, true); - if (err) - { + if (err) { IA_CSS_LOG("map_sp_threads: return_err=%d", err); goto ERR; } - for (i = 0; i < num_pipes; i++) - { + for (i = 0; i < num_pipes; i++) { curr_pipe = pipes[i]; ia_css_pipe_map_queue(curr_pipe, true); } /* Create host side pipeline objects without stages */ err = create_host_pipeline_structure(curr_stream); - if (err) - { + if (err) { IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err); goto ERR; } @@ -9670,13 +9509,13 @@ ERR: } int -ia_css_stream_destroy(struct ia_css_stream *stream) { +ia_css_stream_destroy(struct ia_css_stream *stream) +{ int i; int err = 0; IA_CSS_ENTER_PRIVATE("stream = %p", stream); - if (!stream) - { + if (!stream) { err = -EINVAL; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -9685,8 +9524,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) { ia_css_stream_isp_parameters_uninit(stream); if ((stream->last_pipe) && - ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) - { + ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) { #if defined(ISP2401) bool free_mpi; @@ -9748,8 +9586,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) { } /* remove references from pipes to stream */ - for (i = 0; i < stream->num_pipes; i++) - { + for (i = 0; i < stream->num_pipes; i++) { struct ia_css_pipe *entry = stream->pipes[i]; assert(entry); @@ -9778,8 +9615,7 @@ ia_css_stream_destroy(struct ia_css_stream *stream) { /* working mode: take out of the seed list */ if (my_css_save.mode == sh_css_mode_working) { for (i = 0; i < MAX_ACTIVE_STREAMS; i++) { - if (my_css_save.stream_seeds[i].stream == stream) - { + if (my_css_save.stream_seeds[i].stream == stream) { IA_CSS_LOG("took out stream %d", i); my_css_save.stream_seeds[i].stream = NULL; break; @@ -9795,7 +9631,8 @@ ia_css_stream_destroy(struct ia_css_stream *stream) { int ia_css_stream_get_info(const struct ia_css_stream *stream, - struct ia_css_stream_info *stream_info) { + struct ia_css_stream_info *stream_info) +{ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n"); assert(stream); assert(stream_info); @@ -9811,59 +9648,58 @@ ia_css_stream_get_info(const struct ia_css_stream *stream, * The stream handle is used to identify the correct entry in the css_save struct */ int -ia_css_stream_load(struct ia_css_stream *stream) { - if (!IS_ISP2401) { - int i; - int err; - - assert(stream); - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n"); - for (i = 0; i < MAX_ACTIVE_STREAMS; i++) - { - if (my_css_save.stream_seeds[i].stream == stream) { - int j; - - for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) { - if ((err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j], - &my_css_save.stream_seeds[i].pipes[j])) != 0) { - if (j) { - int k; +ia_css_stream_load(struct ia_css_stream *stream) +{ + int i, j, err; - for (k = 0; k < j; k++) - ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]); - } - return err; - } - } - err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config, - my_css_save.stream_seeds[i].num_pipes, - my_css_save.stream_seeds[i].pipes, - &my_css_save.stream_seeds[i].stream); - if (err) { - ia_css_stream_destroy(stream); - for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) - ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]); - return err; - } - break; - } - } - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n"); - return 0; - } else { + if (IS_ISP2401) { /* TODO remove function - DEPRECATED */ (void)stream; return -ENOTSUPP; } + + assert(stream); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter,\n"); + for (i = 0; i < MAX_ACTIVE_STREAMS; i++) { + if (my_css_save.stream_seeds[i].stream != stream) + continue; + + for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) { + int k; + + err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j], + &my_css_save.stream_seeds[i].pipes[j]); + if (!err) + continue; + + for (k = 0; k < j; k++) + ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]); + return err; + } + err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config, + my_css_save.stream_seeds[i].num_pipes, + my_css_save.stream_seeds[i].pipes, + &my_css_save.stream_seeds[i].stream); + if (!err) + break; + + ia_css_stream_destroy(stream); + for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) + ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]); + return err; + } + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() exit,\n"); + return 0; } int -ia_css_stream_start(struct ia_css_stream *stream) { +ia_css_stream_start(struct ia_css_stream *stream) +{ int err = 0; IA_CSS_ENTER("stream = %p", stream); - if ((!stream) || (!stream->last_pipe)) - { + if ((!stream) || (!stream->last_pipe)) { IA_CSS_LEAVE_ERR(-EINVAL); return -EINVAL; } @@ -9873,8 +9709,7 @@ ia_css_stream_start(struct ia_css_stream *stream) { /* Create host side pipeline. */ err = create_host_pipeline(stream); - if (err) - { + if (err) { IA_CSS_LEAVE_ERR(err); return err; } @@ -9887,8 +9722,7 @@ ia_css_stream_start(struct ia_css_stream *stream) { #if !defined(ISP2401) /* Initialize mipi size checks */ - if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) - { + if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { unsigned int idx; unsigned int port = (unsigned int)(stream->config.source.port.port); @@ -9899,8 +9733,7 @@ ia_css_stream_start(struct ia_css_stream *stream) { } #endif - if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) - { + if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) { err = sh_css_config_input_network(stream); if (err) return err; @@ -9912,7 +9745,8 @@ ia_css_stream_start(struct ia_css_stream *stream) { } int -ia_css_stream_stop(struct ia_css_stream *stream) { +ia_css_stream_stop(struct ia_css_stream *stream) +{ int err = 0; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n"); @@ -9923,22 +9757,19 @@ ia_css_stream_stop(struct ia_css_stream *stream) { #if !defined(ISP2401) /* De-initialize mipi size checks */ - if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) - { + if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { unsigned int idx; unsigned int port = (unsigned int)(stream->config.source.port.port); - for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) { + for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0; - } } #endif - if (!IS_ISP2401) { + if (!IS_ISP2401) err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline); - } else { + else err = sh_css_pipes_stop(stream); - } if (err) return err; @@ -9951,16 +9782,16 @@ ia_css_stream_stop(struct ia_css_stream *stream) { } bool -ia_css_stream_has_stopped(struct ia_css_stream *stream) { +ia_css_stream_has_stopped(struct ia_css_stream *stream) +{ bool stopped; assert(stream); - if (!IS_ISP2401) { + if (!IS_ISP2401) stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline); - } else { + else stopped = sh_css_pipes_have_stopped(stream); - } return stopped; } @@ -9971,7 +9802,8 @@ ia_css_stream_has_stopped(struct ia_css_stream *stream) { * The stream handle is used to identify the correct entry in the css_save struct */ int -ia_css_stream_unload(struct ia_css_stream *stream) { +ia_css_stream_unload(struct ia_css_stream *stream) +{ int i; assert(stream); @@ -9979,8 +9811,7 @@ ia_css_stream_unload(struct ia_css_stream *stream) { /* some checks */ assert(stream); for (i = 0; i < MAX_ACTIVE_STREAMS; i++) - if (my_css_save.stream_seeds[i].stream == stream) - { + if (my_css_save.stream_seeds[i].stream == stream) { int j; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, @@ -10000,7 +9831,8 @@ ia_css_stream_unload(struct ia_css_stream *stream) { int ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe, - enum ia_css_pipe_id *pipe_id) { + enum ia_css_pipe_id *pipe_id) +{ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n"); if (pipe) *pipe_id = pipe->mode; @@ -10011,18 +9843,21 @@ ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe, } enum atomisp_input_format -ia_css_stream_get_format(const struct ia_css_stream *stream) { +ia_css_stream_get_format(const struct ia_css_stream *stream) +{ return stream->config.input_config.format; } bool -ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream) { +ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream) +{ return (stream->config.pixels_per_clock == 2); } struct ia_css_binary * ia_css_stream_get_shading_correction_binary(const struct ia_css_stream - *stream) { + *stream) +{ struct ia_css_pipe *pipe; assert(stream); @@ -10040,7 +9875,8 @@ ia_css_stream_get_shading_correction_binary(const struct ia_css_stream } struct ia_css_binary * -ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) { +ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) +{ int i; struct ia_css_pipe *video_pipe = NULL; @@ -10059,7 +9895,8 @@ ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream) { } struct ia_css_binary * -ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) { +ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) +{ struct ia_css_pipe *pipe; struct ia_css_binary *s3a_binary = NULL; @@ -10081,7 +9918,8 @@ ia_css_stream_get_3a_binary(const struct ia_css_stream *stream) { int ia_css_stream_set_output_padded_width(struct ia_css_stream *stream, - unsigned int output_padded_width) { + unsigned int output_padded_width) +{ struct ia_css_pipe *pipe; assert(stream); @@ -10098,7 +9936,8 @@ ia_css_stream_set_output_padded_width(struct ia_css_stream *stream, } static struct ia_css_binary * -ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) { +ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) +{ struct ia_css_binary *binary = NULL; assert(pipe); @@ -10143,7 +9982,8 @@ ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe) { } static struct ia_css_binary * -ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) { +ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) +{ struct ia_css_binary *binary = NULL; assert(pipe); @@ -10166,9 +10006,9 @@ ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) { } } } else if (pipe->config.default_capture_config.mode == - IA_CSS_CAPTURE_MODE_BAYER) + IA_CSS_CAPTURE_MODE_BAYER) { binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary; - else if (pipe->config.default_capture_config.mode == + } else if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_ADVANCED || pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) { if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1) @@ -10190,7 +10030,8 @@ ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe) { } static struct ia_css_binary * -ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) { +ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) +{ struct ia_css_binary *binary = NULL; assert(pipe); @@ -10210,14 +10051,16 @@ ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe) { } struct ia_css_pipeline * -ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe) { +ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe) +{ assert(pipe); return (struct ia_css_pipeline *)&pipe->pipeline; } unsigned int -ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) { +ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) +{ assert(pipe); /* KW was not sure this function was not returning a value @@ -10234,7 +10077,8 @@ ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe) { } unsigned int -ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) { +ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) +{ assert(pipe); return (unsigned int)pipe->config.isp_pipe_version; @@ -10243,7 +10087,8 @@ ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe) { #define SP_START_TIMEOUT_US 30000000 int -ia_css_start_sp(void) { +ia_css_start_sp(void) +{ unsigned long timeout; int err = 0; @@ -10252,13 +10097,11 @@ ia_css_start_sp(void) { /* waiting for the SP is completely started */ timeout = SP_START_TIMEOUT_US; - while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) - { + while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) { timeout--; udelay(1); } - if (timeout == 0) - { + if (timeout == 0) { IA_CSS_ERROR("timeout during SP initialization"); return -EINVAL; } @@ -10286,14 +10129,14 @@ ia_css_start_sp(void) { #define SP_SHUTDOWN_TIMEOUT_US 200000 int -ia_css_stop_sp(void) { +ia_css_stop_sp(void) +{ unsigned long timeout; int err = 0; IA_CSS_ENTER("void"); - if (!sh_css_sp_is_running()) - { + if (!sh_css_sp_is_running()) { err = -EINVAL; IA_CSS_LEAVE("SP already stopped : return_err=%d", err); @@ -10305,8 +10148,7 @@ ia_css_stop_sp(void) { if (!IS_ISP2401) { sh_css_write_host2sp_command(host2sp_cmd_terminate); } else { - if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) - { + if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) { IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed"); ia_css_debug_dump_sp_sw_debug_info(); ia_css_debug_dump_debug_info(NULL); @@ -10316,27 +10158,23 @@ ia_css_stop_sp(void) { sh_css_sp_set_sp_running(false); timeout = SP_SHUTDOWN_TIMEOUT_US; - while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) - { + while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) { timeout--; udelay(1); } if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)) IA_CSS_WARNING("SP has not terminated (SW)"); - if (timeout == 0) - { + if (timeout == 0) { IA_CSS_WARNING("SP is not idle"); ia_css_debug_dump_sp_sw_debug_info(); } timeout = SP_SHUTDOWN_TIMEOUT_US; - while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) - { + while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) { timeout--; udelay(1); } - if (timeout == 0) - { + if (timeout == 0) { IA_CSS_WARNING("ISP is not idle"); ia_css_debug_dump_sp_sw_debug_info(); } @@ -10351,7 +10189,8 @@ ia_css_stop_sp(void) { } int -ia_css_update_continuous_frames(struct ia_css_stream *stream) { +ia_css_update_continuous_frames(struct ia_css_stream *stream) +{ struct ia_css_pipe *pipe; unsigned int i; @@ -10359,8 +10198,7 @@ ia_css_update_continuous_frames(struct ia_css_stream *stream) { IA_CSS_DEBUG_TRACE, "sh_css_update_continuous_frames() enter:\n"); - if (!stream) - { + if (!stream) { ia_css_debug_dtrace( IA_CSS_DEBUG_TRACE, "sh_css_update_continuous_frames() leave: invalid stream, return_void\n"); @@ -10371,10 +10209,9 @@ ia_css_update_continuous_frames(struct ia_css_stream *stream) { for (i = stream->config.init_num_cont_raw_buf; i < stream->config.target_num_cont_raw_buf; i++) - { sh_css_update_host2sp_offline_frame(i, pipe->continuous_frames[i], pipe->cont_md_buffers[i]); - } + sh_css_update_host2sp_cont_num_raw_frames (stream->config.target_num_cont_raw_buf, true); ia_css_debug_dtrace( @@ -10500,7 +10337,8 @@ void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map) #if CONFIG_ON_FRAME_ENQUEUE() static int set_config_on_frame_enqueue(struct ia_css_frame_info - *info, struct frame_data_wrapper *frame) { + *info, struct frame_data_wrapper *frame) +{ frame->config_on_frame_enqueue.padded_width = 0; /* currently we support configuration on frame enqueue only on YUV formats */ @@ -10508,11 +10346,11 @@ static int set_config_on_frame_enqueue(struct ia_css_frame_info switch (info->format) { case IA_CSS_FRAME_FORMAT_YUV420: case IA_CSS_FRAME_FORMAT_NV12: - if (info->padded_width > info->res.width) { + if (info->padded_width > info->res.width) frame->config_on_frame_enqueue.padded_width = info->padded_width; - } else if ((info->padded_width < info->res.width) && (info->padded_width > 0)) { + else if ((info->padded_width < info->res.width) && (info->padded_width > 0)) return -EINVAL; - } + /* nothing to do if width == padded width or padded width is zeroed (the same) */ break; default: @@ -10524,22 +10362,21 @@ static int set_config_on_frame_enqueue(struct ia_css_frame_info #endif int -ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) { +ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) +{ int ret; IA_CSS_ENTER(""); /* Only continuous streams have a tagger to which we can send the * unlock message. */ - if (!stream || !stream->config.continuous) - { + if (!stream || !stream->config.continuous) { IA_CSS_ERROR("invalid stream pointer"); return -EINVAL; } if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID || - exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) - { + exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) { IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id); return -EINVAL; } @@ -10558,7 +10395,8 @@ ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id) { */ int ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, - bool enable) { + bool enable) +{ unsigned int thread_id; struct ia_css_pipeline_stage *stage; int err = 0; @@ -10566,20 +10404,16 @@ ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, IA_CSS_ENTER(""); /* Parameter Check */ - if (!pipe || !pipe->stream) - { + if (!pipe || !pipe->stream) { IA_CSS_ERROR("Invalid Pipe."); err = -EINVAL; - } else if (!(pipe->config.acc_extension)) - { + } else if (!(pipe->config.acc_extension)) { IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)"); err = -EINVAL; - } else if (!sh_css_sp_is_running()) - { + } else if (!sh_css_sp_is_running()) { IA_CSS_ERROR("Leaving: queue unavailable."); err = -EBUSY; - } else - { + } else { /* Query the threadid and stage_num for the Extension firmware*/ ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage); @@ -10607,7 +10441,8 @@ ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, */ int ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, - bool *enable) { + bool *enable) +{ struct ia_css_pipeline_stage *stage; unsigned int thread_id; int err = 0; @@ -10615,20 +10450,16 @@ ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, IA_CSS_ENTER(""); /* Parameter Check */ - if (!pipe || !pipe->stream) - { + if (!pipe || !pipe->stream) { IA_CSS_ERROR("Invalid Pipe."); err = -EINVAL; - } else if (!(pipe->config.acc_extension)) - { + } else if (!(pipe->config.acc_extension)) { IA_CSS_ERROR("Invalid Pipe (No Extension Firmware)."); err = -EINVAL; - } else if (!sh_css_sp_is_running()) - { + } else if (!sh_css_sp_is_running()) { IA_CSS_ERROR("Leaving: queue unavailable."); err = -EBUSY; - } else - { + } else { /* Query the threadid and stage_num corresponding to the Extension firmware*/ ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage); @@ -10646,9 +10477,10 @@ ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle, /* ISP2401 */ int ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe, - u32 fw_handle, - struct ia_css_isp_param_css_segments *css_seg, - struct ia_css_isp_param_isp_segments *isp_seg) { + u32 fw_handle, + struct ia_css_isp_param_css_segments *css_seg, + struct ia_css_isp_param_isp_segments *isp_seg) +{ unsigned int HIVE_ADDR_sp_group; static struct sh_css_sp_group sp_group; static struct sh_css_sp_stage sp_stage; @@ -10666,27 +10498,23 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe, fw = &sh_css_sp_fw; /* Parameter Check */ - if (!pipe || !pipe->stream) - { + if (!pipe || !pipe->stream) { IA_CSS_ERROR("Invalid Pipe."); err = -EINVAL; - } else if (!(pipe->config.acc_extension)) - { + } else if (!(pipe->config.acc_extension)) { IA_CSS_ERROR("Invalid Pipe (No Extension Firmware)."); err = -EINVAL; - } else if (!sh_css_sp_is_running()) - { + } else if (!sh_css_sp_is_running()) { IA_CSS_ERROR("Leaving: queue unavailable."); err = -EBUSY; - } else - { + } else { /* Query the thread_id and stage_num corresponding to the Extension firmware */ ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id); err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage); if (!err) { /* Get the Extension State */ enabled = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id], - stage->stage_num)) ? true : false; + stage->stage_num)) ? true : false; /* Update mapped arg only when extension stage is not enabled */ if (enabled) { IA_CSS_ERROR("Leaving: cannot update when stage is enabled."); @@ -10696,13 +10524,14 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe, HIVE_ADDR_sp_group = fw->info.sp.group; sp_dmem_load(SP0_ID, - (unsigned int)sp_address_of(sp_group), - &sp_group, sizeof(struct sh_css_sp_group)); + (unsigned int)sp_address_of(sp_group), + &sp_group, + sizeof(struct sh_css_sp_group)); hmm_load(sp_group.pipe[thread_id].sp_stage_addr[stage_num], - &sp_stage, sizeof(struct sh_css_sp_stage)); + &sp_stage, sizeof(struct sh_css_sp_stage)); hmm_load(sp_stage.isp_stage_addr, - &isp_stage, sizeof(struct sh_css_isp_stage)); + &isp_stage, sizeof(struct sh_css_isp_stage)); for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) { isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address = @@ -10718,7 +10547,8 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe, } hmm_store(sp_stage.isp_stage_addr, - &isp_stage, sizeof(struct sh_css_isp_stage)); + &isp_stage, + sizeof(struct sh_css_isp_stage)); } } } @@ -10729,8 +10559,9 @@ ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe, #ifdef ISP2401 static int aspect_ratio_crop_init(struct ia_css_stream *curr_stream, - struct ia_css_pipe *pipes[], - bool *do_crop_status) { + struct ia_css_pipe *pipes[], + bool *do_crop_status) +{ int err = 0; int i; struct ia_css_pipe *curr_pipe; @@ -10739,15 +10570,13 @@ aspect_ratio_crop_init(struct ia_css_stream *curr_stream, if ((!curr_stream) || (curr_stream->num_pipes == 0) || (!pipes) || - (!do_crop_status)) - { + (!do_crop_status)) { err = -EINVAL; IA_CSS_LEAVE_ERR(err); return err; } - for (i = 0; i < curr_stream->num_pipes; i++) - { + for (i = 0; i < curr_stream->num_pipes; i++) { curr_pipe = pipes[i]; pipe_mask |= (1 << curr_pipe->config.mode); } @@ -10761,7 +10590,8 @@ aspect_ratio_crop_init(struct ia_css_stream *curr_stream, } static bool -aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) { +aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) +{ bool status = false; if ((curr_pipe) && enabled) { @@ -10776,7 +10606,8 @@ aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe) { static int aspect_ratio_crop(struct ia_css_pipe *curr_pipe, - struct ia_css_resolution *effective_res) { + struct ia_css_resolution *effective_res) +{ int err = 0; struct ia_css_resolution crop_res; struct ia_css_resolution *in_res = NULL; @@ -10786,8 +10617,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe, bool use_capt_pp_in_res = false; if ((!curr_pipe) || - (!effective_res)) - { + (!effective_res)) { err = -EINVAL; IA_CSS_LEAVE_ERR(err); return err; @@ -10795,8 +10625,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe, if ((curr_pipe->config.mode != IA_CSS_PIPE_MODE_PREVIEW) && (curr_pipe->config.mode != IA_CSS_PIPE_MODE_VIDEO) && - (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) - { + (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) { err = -EINVAL; IA_CSS_LEAVE_ERR(err); return err; @@ -10817,8 +10646,7 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe, in_res = &curr_pipe->stream->config.input_config.effective_res; out_res = &curr_pipe->output_info[0].res; - switch (curr_pipe->config.mode) - { + switch (curr_pipe->config.mode) { case IA_CSS_PIPE_MODE_PREVIEW: if (use_bds_output_info) out_res = &curr_pipe->bds_output_info.res; @@ -10838,27 +10666,26 @@ aspect_ratio_crop(struct ia_css_pipe *curr_pipe, case IA_CSS_PIPE_MODE_YUVPP: default: IA_CSS_ERROR("aspect ratio cropping invalid args: mode[%d]\n", - curr_pipe->config.mode); + curr_pipe->config.mode); assert(0); break; } err = ia_css_frame_find_crop_resolution(in_res, out_res, &crop_res); if (!err) - { *effective_res = crop_res; - } else - { + else /* in case of error fallback to default * effective resolution from driver. */ IA_CSS_LOG("ia_css_frame_find_crop_resolution() failed with err(%d)", err); - } + return err; } #endif static void -sh_css_hmm_buffer_record_init(void) { +sh_css_hmm_buffer_record_init(void) +{ int i; for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) @@ -10866,7 +10693,8 @@ sh_css_hmm_buffer_record_init(void) { } static void -sh_css_hmm_buffer_record_uninit(void) { +sh_css_hmm_buffer_record_uninit(void) +{ int i; struct sh_css_hmm_buffer_record *buffer_record = NULL; @@ -10882,7 +10710,8 @@ sh_css_hmm_buffer_record_uninit(void) { } static void -sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) { +sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) +{ assert(buffer_record); buffer_record->in_use = false; buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID; @@ -10893,14 +10722,15 @@ sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record) { static struct sh_css_hmm_buffer_record *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf, enum ia_css_buffer_type type, - hrt_address kernel_ptr) { + hrt_address kernel_ptr) +{ int i; struct sh_css_hmm_buffer_record *buffer_record = NULL; struct sh_css_hmm_buffer_record *out_buffer_record = NULL; assert(h_vbuf); assert((type > IA_CSS_BUFFER_TYPE_INVALID) && - (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)); + (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)); assert(kernel_ptr != 0); buffer_record = &hmm_buffer_record[0]; @@ -10921,7 +10751,8 @@ static struct sh_css_hmm_buffer_record static struct sh_css_hmm_buffer_record *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr, - enum ia_css_buffer_type type) { + enum ia_css_buffer_type type) +{ int i; struct sh_css_hmm_buffer_record *buffer_record = NULL; bool found_record = false; diff --git a/drivers/staging/media/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig new file mode 100644 index 000000000000..9faf9d2d4001 --- /dev/null +++ b/drivers/staging/media/av7110/Kconfig @@ -0,0 +1,94 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DVB_AV7110_IR + bool + depends on RC_CORE=y || RC_CORE = DVB_AV7110 + default DVB_AV7110 + +config DVB_AV7110 + tristate "AV7110 cards" + depends on DVB_CORE && PCI && I2C + select TTPCI_EEPROM + select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV + select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT + select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT + select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + help + Support for SAA7146 and AV7110 based DVB cards as produced + by Fujitsu-Siemens, Technotrend, Hauppauge and others. + + This driver only supports the fullfeatured cards with + onboard MPEG2 decoder. + + This driver needs an external firmware. Please use the script + "<kerneldir>/scripts/get_dvb_firmware av7110" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + + Alternatively, you can download the file and use the kernel's + EXTRA_FIRMWARE configuration option to build it into your + kernel image by adding the filename to the EXTRA_FIRMWARE + configuration option string. + + Say Y if you own such a card and want to use it. + +config DVB_AV7110_OSD + bool "AV7110 OSD support" + depends on DVB_AV7110 + default y if DVB_AV7110=y || DVB_AV7110=m + help + The AV7110 firmware provides some code to generate an OnScreenDisplay + on the video output. This is kind of nonstandard and not guaranteed to + be maintained. + + Anyway, some popular DVB software like VDR uses this OSD to render + its menus, so say Y if you want to use this software. + + All other people say N. + +config DVB_BUDGET_PATCH + tristate "AV7110 cards with Budget Patch" + depends on DVB_BUDGET_CORE && I2C + depends on DVB_AV7110 + select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT + select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT + help + Support for Budget Patch (full TS) modification on + SAA7146+AV7110 based cards (DVB-S cards). This + driver doesn't use onboard MPEG2 decoder. The + card is driven in Budget-only mode. Card is + required to have loaded firmware to tune properly. + Firmware can be loaded by insertion and removal of + standard AV7110 driver prior to loading this + driver. + + Say Y if you own such a card and want to use it. + + To compile this driver as a module, choose M here: the + module will be called budget-patch. + +if DVB_AV7110 + +# Frontend driver that it is used only by AV7110 driver +# While technically independent, it doesn't make sense to keep +# it if we drop support for AV7110, as no other driver will use it. + +config DVB_SP8870 + tristate "Spase sp8870 based" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + This driver needs external firmware. Please use the command + "<kerneldir>/scripts/get_dvb_firmware sp8870" to + download/extract it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + +endif diff --git a/drivers/staging/media/av7110/Makefile b/drivers/staging/media/av7110/Makefile new file mode 100644 index 000000000000..307b267598ea --- /dev/null +++ b/drivers/staging/media/av7110/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the AV7110 DVB device driver +# + +dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o \ + av7110_ipack.o dvb_filter.o + +ifdef CONFIG_DVB_AV7110_IR +dvb-ttpci-objs += av7110_ir.o +endif + +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o + +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o + +obj-$(CONFIG_DVB_SP8870) += sp8870.o + +ccflags-y += -I $(srctree)/drivers/media/dvb-frontends +ccflags-y += -I $(srctree)/drivers/media/tuners +ccflags-y += -I $(srctree)/drivers/media/pci/ttpci +ccflags-y += -I $(srctree)/drivers/media/common diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO new file mode 100644 index 000000000000..60062d8441b3 --- /dev/null +++ b/drivers/staging/media/av7110/TODO @@ -0,0 +1,3 @@ +- This driver is too old and relies on a different API. + Drop it from Kernel on a couple of versions. +- Cleanup patches for the drivers here won't be accepted. diff --git a/drivers/staging/media/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst new file mode 100644 index 000000000000..33b5363317f1 --- /dev/null +++ b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst @@ -0,0 +1,58 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_BILINGUAL_CHANNEL_SELECT: + +============================== +AUDIO_BILINGUAL_CHANNEL_SELECT +============================== + +Name +---- + +AUDIO_BILINGUAL_CHANNEL_SELECT + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_BILINGUAL_CHANNEL_SELECT + +``int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct audio_channel_select *select)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_channel_select_t ch + + - Select the output format of the audio (mono left/right, stereo). + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. It has been replaced +by the V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK`` control +for MPEG decoders controlled through V4L2. + +This ioctl call asks the Audio Device to select the requested channel +for bilingual streams if possible. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst new file mode 100644 index 000000000000..74093df92a68 --- /dev/null +++ b/drivers/staging/media/av7110/audio-channel-select.rst @@ -0,0 +1,57 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_CHANNEL_SELECT: + +==================== +AUDIO_CHANNEL_SELECT +==================== + +Name +---- + +AUDIO_CHANNEL_SELECT + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_CHANNEL_SELECT + +``int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct audio_channel_select *select)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_channel_select_t ch + + - Select the output format of the audio (mono left/right, stereo). + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK`` control instead. + +This ioctl call asks the Audio Device to select the requested channel if +possible. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst new file mode 100644 index 000000000000..a0ebb0278260 --- /dev/null +++ b/drivers/staging/media/av7110/audio-clear-buffer.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_CLEAR_BUFFER: + +================== +AUDIO_CLEAR_BUFFER +================== + +Name +---- + +AUDIO_CLEAR_BUFFER + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_CLEAR_BUFFER + +``int ioctl(int fd, AUDIO_CLEAR_BUFFER)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call asks the Audio Device to clear all software and hardware +buffers of the audio decoder device. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst new file mode 100644 index 000000000000..a2e9850f37f2 --- /dev/null +++ b/drivers/staging/media/av7110/audio-continue.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_CONTINUE: + +============== +AUDIO_CONTINUE +============== + +Name +---- + +AUDIO_CONTINUE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_CONTINUE + +``int ioctl(int fd, AUDIO_CONTINUE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl restarts the decoding and playing process previously paused +with AUDIO_PAUSE command. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst new file mode 100644 index 000000000000..77857d578e83 --- /dev/null +++ b/drivers/staging/media/av7110/audio-fclose.rst @@ -0,0 +1,51 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _audio_fclose: + +======================== +Digital TV audio close() +======================== + +Name +---- + +Digital TV audio close() + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:function:: int close(int fd) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This system call closes a previously opened audio device. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst new file mode 100644 index 000000000000..774daaab3bad --- /dev/null +++ b/drivers/staging/media/av7110/audio-fopen.rst @@ -0,0 +1,103 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _audio_fopen: + +======================= +Digital TV audio open() +======================= + +Name +---- + +Digital TV audio open() + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:function:: int open(const char *deviceName, int flags) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - const char \*deviceName + + - Name of specific audio device. + + - .. row 2 + + - int flags + + - A bit-wise OR of the following flags: + + - .. row 3 + + - + - O_RDONLY read-only access + + - .. row 4 + + - + - O_RDWR read/write access + + - .. row 5 + + - + - O_NONBLOCK open in non-blocking mode + + - .. row 6 + + - + - (blocking mode is the default) + +Description +----------- + +This system call opens a named audio device (e.g. +/dev/dvb/adapter0/audio0) for subsequent use. When an open() call has +succeeded, the device will be ready for use. The significance of +blocking or non-blocking mode is described in the documentation for +functions where there is a difference. It does not affect the semantics +of the open() call itself. A device opened in blocking mode can later be +put into non-blocking mode (and vice versa) using the F_SETFL command +of the fcntl system call. This is a standard system call, documented in +the Linux manual page for fcntl. Only one user can open the Audio Device +in O_RDWR mode. All other attempts to open the device in this mode will +fail, and an error code will be returned. If the Audio Device is opened +in O_RDONLY mode, the only ioctl call that can be used is +AUDIO_GET_STATUS. All other call will return with an error code. + +Return Value +------------ + +.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``ENODEV`` + + - Device driver not loaded/available. + + - .. row 2 + + - ``EBUSY`` + + - Device or resource busy. + + - .. row 3 + + - ``EINVAL`` + + - Invalid argument. diff --git a/drivers/staging/media/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst new file mode 100644 index 000000000000..7b096ac2b6c4 --- /dev/null +++ b/drivers/staging/media/av7110/audio-fwrite.rst @@ -0,0 +1,79 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _audio_fwrite: + +========================= +Digital TV audio write() +========================= + +Name +---- + +Digital TV audio write() + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:function:: size_t write(int fd, const void *buf, size_t count) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - void \*buf + + - Pointer to the buffer containing the PES data. + + - .. row 3 + + - size_t count + + - Size of buf. + +Description +----------- + +This system call can only be used if AUDIO_SOURCE_MEMORY is selected +in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in +PES format. If O_NONBLOCK is not specified the function will block +until buffer space is available. The amount of data to be transferred is +implied by count. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode AUDIO_SOURCE_MEMORY not selected. + + - .. row 2 + + - ``ENOMEM`` + + - Attempted to write more data than the internal buffer can hold. + + - .. row 3 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst new file mode 100644 index 000000000000..6d9eb71dad17 --- /dev/null +++ b/drivers/staging/media/av7110/audio-get-capabilities.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_GET_CAPABILITIES: + +====================== +AUDIO_GET_CAPABILITIES +====================== + +Name +---- + +AUDIO_GET_CAPABILITIES + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_GET_CAPABILITIES + +``int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - unsigned int \*cap + + - Returns a bit array of supported sound formats. + +Description +----------- + +This ioctl call asks the Audio Device to tell us about the decoding +capabilities of the audio hardware. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst new file mode 100644 index 000000000000..7ae8db2e65e9 --- /dev/null +++ b/drivers/staging/media/av7110/audio-get-status.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_GET_STATUS: + +================ +AUDIO_GET_STATUS +================ + +Name +---- + +AUDIO_GET_STATUS + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_GET_STATUS + +``int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - struct audio_status \*status + + - Returns the current state of Audio Device. + +Description +----------- + +This ioctl call asks the Audio Device to return the current state of the +Audio Device. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst new file mode 100644 index 000000000000..d37d1ddce4df --- /dev/null +++ b/drivers/staging/media/av7110/audio-pause.rst @@ -0,0 +1,49 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_PAUSE: + +=========== +AUDIO_PAUSE +=========== + +Name +---- + +AUDIO_PAUSE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_PAUSE + +``int ioctl(int fd, AUDIO_PAUSE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call suspends the audio stream being played. Decoding and +playing are paused. It is then possible to restart again decoding and +playing process of the audio stream using AUDIO_CONTINUE command. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst new file mode 100644 index 000000000000..e591930b6ca7 --- /dev/null +++ b/drivers/staging/media/av7110/audio-play.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_PLAY: + +========== +AUDIO_PLAY +========== + +Name +---- + +AUDIO_PLAY + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_PLAY + +``int ioctl(int fd, AUDIO_PLAY)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call asks the Audio Device to start playing an audio stream +from the selected source. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst new file mode 100644 index 000000000000..6a0c0f365eb1 --- /dev/null +++ b/drivers/staging/media/av7110/audio-select-source.rst @@ -0,0 +1,56 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SELECT_SOURCE: + +=================== +AUDIO_SELECT_SOURCE +=================== + +Name +---- + +AUDIO_SELECT_SOURCE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SELECT_SOURCE + +``int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_stream_source_t source + + - Indicates the source that shall be used for the Audio stream. + +Description +----------- + +This ioctl call informs the audio device which source shall be used for +the input data. The possible sources are demux or memory. If +AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device +through the write command. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst new file mode 100644 index 000000000000..85a8016bf025 --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-av-sync.rst @@ -0,0 +1,58 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_AV_SYNC: + +================= +AUDIO_SET_AV_SYNC +================= + +Name +---- + +AUDIO_SET_AV_SYNC + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_AV_SYNC + +``int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - boolean state + + - Tells the Digital TV subsystem if A/V synchronization shall be ON or OFF. + + TRUE: AV-sync ON + + FALSE: AV-sync OFF + +Description +----------- + +This ioctl call asks the Audio Device to turn ON or OFF A/V +synchronization. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst new file mode 100644 index 000000000000..80d551a2053a --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-bypass-mode.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_BYPASS_MODE: + +===================== +AUDIO_SET_BYPASS_MODE +===================== + +Name +---- + +AUDIO_SET_BYPASS_MODE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_BYPASS_MODE + +``int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - boolean mode + + - Enables or disables the decoding of the current Audio stream in + the Digital TV subsystem. + + TRUE: Bypass is disabled + + FALSE: Bypass is enabled + +Description +----------- + +This ioctl call asks the Audio Device to bypass the Audio decoder and +forward the stream without decoding. This mode shall be used if streams +that can't be handled by the Digital TV system shall be decoded. Dolby +DigitalTM streams are automatically forwarded by the Digital TV subsystem if +the hardware can handle it. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst new file mode 100644 index 000000000000..39ad846d412d --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-id.rst @@ -0,0 +1,59 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_ID: + +============ +AUDIO_SET_ID +============ + +Name +---- + +AUDIO_SET_ID + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_ID + +``int ioctl(int fd, AUDIO_SET_ID, int id)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - int id + + - audio sub-stream id + +Description +----------- + +This ioctl selects which sub-stream is to be decoded if a program or +system stream is sent to the video device. If no audio stream type is +set the id has to be in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for +AC3 and in [0xA0,0xA7] for LPCM. More specifications may follow for +other stream types. If the stream type is set the id just specifies the +substream id of the audio stream and only the first 5 bits are +recognized. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst new file mode 100644 index 000000000000..45dbdf4801e0 --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-mixer.rst @@ -0,0 +1,53 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_MIXER: + +=============== +AUDIO_SET_MIXER +=============== + +Name +---- + +AUDIO_SET_MIXER + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_MIXER + +``int ioctl(int fd, AUDIO_SET_MIXER, struct audio_mixer *mix)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - audio_mixer_t \*mix + + - mixer settings. + +Description +----------- + +This ioctl lets you adjust the mixer settings of the audio decoder. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst new file mode 100644 index 000000000000..987751f92967 --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-mute.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_MUTE: + +============== +AUDIO_SET_MUTE +============== + +Name +---- + +AUDIO_SET_MUTE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_MUTE + +``int ioctl(int fd, AUDIO_SET_MUTE, boolean state)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - boolean state + + - Indicates if audio device shall mute or not. + + TRUE: Audio Mute + + FALSE: Audio Un-mute + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` with the +``V4L2_DEC_CMD_START_MUTE_AUDIO`` flag instead. + +This ioctl call asks the audio device to mute the stream that is +currently being played. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst new file mode 100644 index 000000000000..77d73c74882f --- /dev/null +++ b/drivers/staging/media/av7110/audio-set-streamtype.rst @@ -0,0 +1,66 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_SET_STREAMTYPE: + +==================== +AUDIO_SET_STREAMTYPE +==================== + +Name +---- + +AUDIO_SET_STREAMTYPE + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_SET_STREAMTYPE + +``int ioctl(fd, AUDIO_SET_STREAMTYPE, int type)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - + + - int fd + + - File descriptor returned by a previous call to open(). + + - + + - int type + + - stream type + +Description +----------- + +This ioctl tells the driver which kind of audio stream to expect. This +is useful if the stream offers several audio sub-streams like LPCM and +AC3. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EINVAL`` + + - type is not a valid or supported stream type. diff --git a/drivers/staging/media/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst new file mode 100644 index 000000000000..d77f786fd797 --- /dev/null +++ b/drivers/staging/media/av7110/audio-stop.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.audio + +.. _AUDIO_STOP: + +========== +AUDIO_STOP +========== + +Name +---- + +AUDIO_STOP + +.. attention:: This ioctl is deprecated + +Synopsis +-------- + +.. c:macro:: AUDIO_STOP + +``int ioctl(int fd, AUDIO_STOP)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This ioctl call asks the Audio Device to stop playing the current +stream. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/audio.h b/drivers/staging/media/av7110/audio.h new file mode 100644 index 000000000000..2f869da69171 --- /dev/null +++ b/drivers/staging/media/av7110/audio.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ +/* + * audio.h - DEPRECATED MPEG-TS audio decoder API + * + * NOTE: should not be used on future drivers + * + * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> + * & Marcus Metzler <marcus@convergence.de> + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Lesser Public License + * as published by the Free Software Foundation; either version 2.1 + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _DVBAUDIO_H_ +#define _DVBAUDIO_H_ + +#include <linux/types.h> + +typedef enum { + AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */ + AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */ +} audio_stream_source_t; + + +typedef enum { + AUDIO_STOPPED, /* Device is stopped */ + AUDIO_PLAYING, /* Device is currently playing */ + AUDIO_PAUSED /* Device is paused */ +} audio_play_state_t; + + +typedef enum { + AUDIO_STEREO, + AUDIO_MONO_LEFT, + AUDIO_MONO_RIGHT, + AUDIO_MONO, + AUDIO_STEREO_SWAPPED +} audio_channel_select_t; + + +typedef struct audio_mixer { + unsigned int volume_left; + unsigned int volume_right; + /* what else do we need? bass, pass-through, ... */ +} audio_mixer_t; + + +typedef struct audio_status { + int AV_sync_state; /* sync audio and video? */ + int mute_state; /* audio is muted */ + audio_play_state_t play_state; /* current playback state */ + audio_stream_source_t stream_source; /* current stream source */ + audio_channel_select_t channel_select; /* currently selected channel */ + int bypass_mode; /* pass on audio data to */ + audio_mixer_t mixer_state; /* current mixer state */ +} audio_status_t; /* separate decoder hardware */ + + +/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */ +#define AUDIO_CAP_DTS 1 +#define AUDIO_CAP_LPCM 2 +#define AUDIO_CAP_MP1 4 +#define AUDIO_CAP_MP2 8 +#define AUDIO_CAP_MP3 16 +#define AUDIO_CAP_AAC 32 +#define AUDIO_CAP_OGG 64 +#define AUDIO_CAP_SDDS 128 +#define AUDIO_CAP_AC3 256 + +#define AUDIO_STOP _IO('o', 1) +#define AUDIO_PLAY _IO('o', 2) +#define AUDIO_PAUSE _IO('o', 3) +#define AUDIO_CONTINUE _IO('o', 4) +#define AUDIO_SELECT_SOURCE _IO('o', 5) +#define AUDIO_SET_MUTE _IO('o', 6) +#define AUDIO_SET_AV_SYNC _IO('o', 7) +#define AUDIO_SET_BYPASS_MODE _IO('o', 8) +#define AUDIO_CHANNEL_SELECT _IO('o', 9) +#define AUDIO_GET_STATUS _IOR('o', 10, audio_status_t) + +#define AUDIO_GET_CAPABILITIES _IOR('o', 11, unsigned int) +#define AUDIO_CLEAR_BUFFER _IO('o', 12) +#define AUDIO_SET_ID _IO('o', 13) +#define AUDIO_SET_MIXER _IOW('o', 14, audio_mixer_t) +#define AUDIO_SET_STREAMTYPE _IO('o', 15) +#define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20) + +#endif /* _DVBAUDIO_H_ */ diff --git a/drivers/staging/media/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst new file mode 100644 index 000000000000..aa753336b31f --- /dev/null +++ b/drivers/staging/media/av7110/audio.rst @@ -0,0 +1,27 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _dvb_audio: + +####################### +Digital TV Audio Device +####################### + +The Digital TV audio device controls the MPEG2 audio decoder of the Digital +TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data +types and ioctl definitions can be accessed by including +``linux/dvb/audio.h`` in your application. + +Please note that some Digital TV cards don't have their own MPEG decoder, which +results in the omission of the audio and video device. + +These ioctls were also used by V4L2 to control MPEG decoders implemented +in V4L2. The use of these ioctls for that purpose has been made obsolete +and proper V4L2 ioctls or controls have been created to replace that +functionality. + + +.. toctree:: + :maxdepth: 1 + + audio_data_types + audio_function_calls diff --git a/drivers/staging/media/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst new file mode 100644 index 000000000000..4744529136a8 --- /dev/null +++ b/drivers/staging/media/av7110/audio_data_types.rst @@ -0,0 +1,116 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _audio_data_types: + +**************** +Audio Data Types +**************** + +This section describes the structures, data types and defines used when +talking to the audio device. + +.. c:type:: audio_stream_source + +The audio stream source is set through the AUDIO_SELECT_SOURCE call +and can take the following values, depending on whether we are replaying +from an internal (demux) or external (user write) source. + + +.. code-block:: c + + typedef enum { + AUDIO_SOURCE_DEMUX, + AUDIO_SOURCE_MEMORY + } audio_stream_source_t; + +AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the +frontend or the DVR device) as the source of the video stream. If +AUDIO_SOURCE_MEMORY is selected the stream comes from the application +through the ``write()`` system call. + + +.. c:type:: audio_play_state + +The following values can be returned by the AUDIO_GET_STATUS call +representing the state of audio playback. + + +.. code-block:: c + + typedef enum { + AUDIO_STOPPED, + AUDIO_PLAYING, + AUDIO_PAUSED + } audio_play_state_t; + + +.. c:type:: audio_channel_select + +The audio channel selected via AUDIO_CHANNEL_SELECT is determined by +the following values. + + +.. code-block:: c + + typedef enum { + AUDIO_STEREO, + AUDIO_MONO_LEFT, + AUDIO_MONO_RIGHT, + AUDIO_MONO, + AUDIO_STEREO_SWAPPED + } audio_channel_select_t; + + +.. c:type:: audio_status + +The AUDIO_GET_STATUS call returns the following structure informing +about various states of the playback operation. + + +.. code-block:: c + + typedef struct audio_status { + boolean AV_sync_state; + boolean mute_state; + audio_play_state_t play_state; + audio_stream_source_t stream_source; + audio_channel_select_t channel_select; + boolean bypass_mode; + audio_mixer_t mixer_state; + } audio_status_t; + + +.. c:type:: audio_mixer + +The following structure is used by the AUDIO_SET_MIXER call to set the +audio volume. + + +.. code-block:: c + + typedef struct audio_mixer { + unsigned int volume_left; + unsigned int volume_right; + } audio_mixer_t; + + +.. _audio_encodings: + +audio encodings +=============== + +A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the +following bits set according to the hardwares capabilities. + + +.. code-block:: c + + #define AUDIO_CAP_DTS 1 + #define AUDIO_CAP_LPCM 2 + #define AUDIO_CAP_MP1 4 + #define AUDIO_CAP_MP2 8 + #define AUDIO_CAP_MP3 16 + #define AUDIO_CAP_AAC 32 + #define AUDIO_CAP_OGG 64 + #define AUDIO_CAP_SDDS 128 + #define AUDIO_CAP_AC3 256 diff --git a/drivers/staging/media/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst new file mode 100644 index 000000000000..fa5ba9539caf --- /dev/null +++ b/drivers/staging/media/av7110/audio_function_calls.rst @@ -0,0 +1,30 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _audio_function_calls: + +******************** +Audio Function Calls +******************** + +.. toctree:: + :maxdepth: 1 + + audio-fopen + audio-fclose + audio-fwrite + audio-stop + audio-play + audio-pause + audio-continue + audio-select-source + audio-set-mute + audio-set-av-sync + audio-set-bypass-mode + audio-channel-select + audio-bilingual-channel-select + audio-get-status + audio-get-capabilities + audio-clear-buffer + audio-set-id + audio-set-mixer + audio-set-streamtype diff --git a/drivers/staging/media/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c new file mode 100644 index 000000000000..d74ee0ecfb36 --- /dev/null +++ b/drivers/staging/media/av7110/av7110.c @@ -0,0 +1,2919 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB) + * av7110.c: initialization and demux stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> + * + * the project's page is at https://linuxtv.org + */ + + +#include <linux/module.h> +#include <linux/kmod.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/timer.h> +#include <linux/poll.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/firmware.h> +#include <linux/crc32.h> +#include <linux/i2c.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <asm/unaligned.h> +#include <asm/byteorder.h> + + +#include <linux/dvb/frontend.h> + +#include <media/dvb_frontend.h> + +#include "ttpci-eeprom.h" +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" +#include "av7110_ca.h" +#include "av7110_ipack.h" + +#include "bsbe1.h" +#include "lnbp21.h" +#include "bsru6.h" + +#define TS_WIDTH 376 +#define TS_HEIGHT 512 +#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) +#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) + + +int av7110_debug; + +static int vidmode = CVBS_RGB_OUT; +static int pids_off; +static int adac = DVB_ADAC_TI; +static int hw_sections; +static int rgb_on; +static int volume = 255; +static int budgetpatch; +static int wss_cfg_4_3 = 0x4008; +static int wss_cfg_16_9 = 0x0007; +static int tv_standard; +static int full_ts; + +module_param_named(debug, av7110_debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); +module_param(vidmode, int, 0444); +MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC"); +module_param(pids_off, int, 0444); +MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed"); +module_param(adac, int, 0444); +MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)"); +module_param(hw_sections, int, 0444); +MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware"); +module_param(rgb_on, int, 0444); +MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); +module_param(volume, int, 0444); +MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); +module_param(budgetpatch, int, 0444); +MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); +module_param(full_ts, int, 0444); +MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); +module_param(wss_cfg_4_3, int, 0444); +MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(wss_cfg_16_9, int, 0444); +MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(tv_standard, int, 0444); +MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static void restart_feeds(struct av7110 *av7110); +static int budget_start_feed(struct dvb_demux_feed *feed); +static int budget_stop_feed(struct dvb_demux_feed *feed); + +static int av7110_num; + +#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \ +{\ + if (fe_func != NULL) { \ + av7110_copy = fe_func; \ + fe_func = av7110_func; \ + } \ +} + + +static void init_av7110_av(struct av7110 *av7110) +{ + int ret; + struct saa7146_dev *dev = av7110->dev; + + /* set internal volume control to maximum */ + av7110->adac_type = DVB_ADAC_TI; + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret < 0) + printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, + 1, (u16) av7110->display_ar); + if (ret < 0) + printk("dvb-ttpci: unable to set aspect ratio\n"); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, + 1, av7110->display_panscan); + if (ret < 0) + printk("dvb-ttpci: unable to set pan scan\n"); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3); + if (ret < 0) + printk("dvb-ttpci: unable to configure 4:3 wss\n"); + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9); + if (ret < 0) + printk("dvb-ttpci: unable to configure 16:9 wss\n"); + + ret = av7710_set_video_mode(av7110, vidmode); + if (ret < 0) + printk("dvb-ttpci:cannot set video mode:%d\n",ret); + + /* handle different card types */ + /* remaining inits according to card and frontend type */ + av7110->analog_tuner_flags = 0; + av7110->current_input = 0; + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on + if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { + printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_CRYSTAL; + i2c_writereg(av7110, 0x20, 0x01, 0xd2); + i2c_writereg(av7110, 0x20, 0x02, 0x49); + i2c_writereg(av7110, 0x20, 0x03, 0x00); + i2c_writereg(av7110, 0x20, 0x04, 0x00); + + /** + * some special handling for the Siemens DVB-C cards... + */ + } else if (0 == av7110_init_analog_module(av7110)) { + /* done. */ + } + else if (dev->pci->subsystem_vendor == 0x110a) { + printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_NONE; + } + else { + av7110->adac_type = adac; + printk("dvb-ttpci: adac type set to %d @ card %d\n", + av7110->adac_type, av7110->dvb_adapter.num); + } + + if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) { + // switch DVB SCART on + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0); + if (ret < 0) + printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret); + ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1); + if (ret < 0) + printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret); + if (rgb_on && + ((av7110->dev->pci->subsystem_vendor == 0x110a) || + (av7110->dev->pci->subsystem_vendor == 0x13c2)) && + (av7110->dev->pci->subsystem_device == 0x0000)) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16 + //saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8 + } + } + + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000e) + av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, SpdifSwitch, 1, 0); // SPDIF on + + ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right); + if (ret < 0) + printk("dvb-ttpci:cannot set volume :%d\n",ret); +} + +static void recover_arm(struct av7110 *av7110) +{ + dprintk(4, "%p\n",av7110); + + av7110_bootarm(av7110); + msleep(100); + + init_av7110_av(av7110); + + /* card-specific recovery */ + if (av7110->recover) + av7110->recover(av7110); + + restart_feeds(av7110); + +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) + av7110_set_ir_config(av7110); +#endif +} + +static void av7110_arm_sync(struct av7110 *av7110) +{ + if (av7110->arm_thread) + kthread_stop(av7110->arm_thread); + + av7110->arm_thread = NULL; +} + +static int arm_thread(void *data) +{ + struct av7110 *av7110 = data; + u16 newloops = 0; + int timeout; + + dprintk(4, "%p\n",av7110); + + for (;;) { + timeout = wait_event_interruptible_timeout(av7110->arm_wait, + kthread_should_stop(), 5 * HZ); + + if (-ERESTARTSYS == timeout || kthread_should_stop()) { + /* got signal or told to quit*/ + break; + } + + if (!av7110->arm_ready) + continue; + + if (mutex_lock_interruptible(&av7110->dcomlock)) + break; + newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); + mutex_unlock(&av7110->dcomlock); + + if (newloops == av7110->arm_loops || av7110->arm_errors > 3) { + printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n", + av7110->dvb_adapter.num); + + recover_arm(av7110); + + if (mutex_lock_interruptible(&av7110->dcomlock)) + break; + newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2) - 1; + mutex_unlock(&av7110->dcomlock); + } + av7110->arm_loops = newloops; + av7110->arm_errors = 0; + } + + return 0; +} + + +/**************************************************************************** + * IRQ handling + ****************************************************************************/ + +static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, + u8 *buffer2, size_t buffer2_len, + struct dvb_demux_filter *dvbdmxfilter, + struct av7110 *av7110) +{ + if (!dvbdmxfilter->feed->demux->dmx.frontend) + return 0; + if (dvbdmxfilter->feed->demux->dmx.frontend->source == DMX_MEMORY_FE) + return 0; + + switch (dvbdmxfilter->type) { + case DMX_TYPE_SEC: + if ((((buffer1[1] << 8) | buffer1[2]) & 0xfff) + 3 != buffer1_len) + return 0; + if (dvbdmxfilter->doneq) { + struct dmx_section_filter *filter = &dvbdmxfilter->filter; + int i; + u8 xor, neq = 0; + + for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { + xor = filter->filter_value[i] ^ buffer1[i]; + neq |= dvbdmxfilter->maskandnotmode[i] & xor; + } + if (!neq) + return 0; + } + return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len, + buffer2, buffer2_len, + &dvbdmxfilter->filter, NULL); + case DMX_TYPE_TS: + if (!(dvbdmxfilter->feed->ts_type & TS_PACKET)) + return 0; + if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len, + buffer2, buffer2_len, + &dvbdmxfilter->feed->feed.ts, + NULL); + else + av7110_p2t_write(buffer1, buffer1_len, + dvbdmxfilter->feed->pid, + &av7110->p2t_filter[dvbdmxfilter->index]); + return 0; + default: + return 0; + } +} + + +//#define DEBUG_TIMING +static inline void print_time(char *s) +{ +#ifdef DEBUG_TIMING + struct timespec64 ts; + ktime_get_real_ts64(&ts); + printk("%s: %lld.%09ld\n", s, (s64)ts.tv_sec, ts.tv_nsec); +#endif +} + +#define DEBI_READ 0 +#define DEBI_WRITE 1 +static inline void start_debi_dma(struct av7110 *av7110, int dir, + unsigned long addr, unsigned int len) +{ + dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len); + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); + return; + } + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */ + SAA7146_IER_ENABLE(av7110->dev, MASK_19); + if (len < 5) + len = 5; /* we want a real DEBI DMA */ + if (dir == DEBI_WRITE) + iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3); + else + irdebi(av7110, DEBISWAB, addr, 0, len); +} + +static void debiirq(struct tasklet_struct *t) +{ + struct av7110 *av7110 = from_tasklet(av7110, t, debi_tasklet); + int type = av7110->debitype; + int handle = (type >> 8) & 0x1f; + unsigned int xfer = 0; + + print_time("debi"); + dprintk(4, "type 0x%04x\n", type); + + if (type == -1) { + printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", + jiffies, saa7146_read(av7110->dev, PSR), + saa7146_read(av7110->dev, SSR)); + goto debi_done; + } + av7110->debitype = -1; + + switch (type & 0xff) { + + case DATA_TS_RECORD: + dvb_dmx_swfilter_packets(&av7110->demux, + (const u8 *) av7110->debi_virt, + av7110->debilen / 188); + xfer = RX_BUFF; + break; + + case DATA_PES_RECORD: + if (av7110->demux.recording) + av7110_record_cb(&av7110->p2t[handle], + (u8 *) av7110->debi_virt, + av7110->debilen); + xfer = RX_BUFF; + break; + + case DATA_IPMPE: + case DATA_FSECTION: + case DATA_PIPING: + if (av7110->handle2filter[handle]) + DvbDmxFilterCallback((u8 *)av7110->debi_virt, + av7110->debilen, NULL, 0, + av7110->handle2filter[handle], + av7110); + xfer = RX_BUFF; + break; + + case DATA_CI_GET: + { + u8 *data = av7110->debi_virt; + u8 data_0 = data[0]; + + if (data_0 < 2 && data[2] == 0xff) { + int flags = 0; + if (data[5] > 0) + flags |= CA_CI_MODULE_PRESENT; + if (data[5] > 5) + flags |= CA_CI_MODULE_READY; + av7110->ci_slot[data_0].flags = flags; + } else + ci_get_data(&av7110->ci_rbuffer, + av7110->debi_virt, + av7110->debilen); + xfer = RX_BUFF; + break; + } + + case DATA_COMMON_INTERFACE: + CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen); + xfer = RX_BUFF; + break; + + case DATA_DEBUG_MESSAGE: + ((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0; + printk("%s\n", (s8 *) av7110->debi_virt); + xfer = RX_BUFF; + break; + + case DATA_CI_PUT: + dprintk(4, "debi DATA_CI_PUT\n"); + xfer = TX_BUFF; + break; + case DATA_MPEG_PLAY: + dprintk(4, "debi DATA_MPEG_PLAY\n"); + xfer = TX_BUFF; + break; + case DATA_BMP_LOAD: + dprintk(4, "debi DATA_BMP_LOAD\n"); + xfer = TX_BUFF; + break; + default: + break; + } +debi_done: + spin_lock(&av7110->debilock); + if (xfer) + iwdebi(av7110, DEBINOSWAP, xfer, 0, 2); + ARM_ClearMailBox(av7110); + spin_unlock(&av7110->debilock); +} + +/* irq from av7110 firmware writing the mailbox register in the DPRAM */ +static void gpioirq(struct tasklet_struct *t) +{ + struct av7110 *av7110 = from_tasklet(av7110, t, gpio_tasklet); + u32 rxbuf, txbuf; + int len; + + if (av7110->debitype != -1) + /* we shouldn't get any irq while a debi xfer is running */ + printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", + jiffies, saa7146_read(av7110->dev, PSR), + saa7146_read(av7110->dev, SSR)); + + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__); + BUG(); /* maybe we should try resetting the debi? */ + } + + spin_lock(&av7110->debilock); + ARM_ClearIrq(av7110); + + /* see what the av7110 wants */ + av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2); + av7110->debilen = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + rxbuf = irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + txbuf = irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + len = (av7110->debilen + 3) & ~3; + + print_time("gpio"); + dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen); + + switch (av7110->debitype & 0xff) { + + case DATA_TS_PLAY: + case DATA_PES_PLAY: + break; + + case DATA_MPEG_VIDEO_EVENT: + { + u32 h_ar; + struct video_event event; + + av7110->video_size.w = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_WIDTH, 0, 2); + h_ar = irdebi(av7110, DEBINOSWAP, STATUS_MPEG_HEIGHT_AR, 0, 2); + + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + + av7110->video_size.h = h_ar & 0xfff; + + event.type = VIDEO_EVENT_SIZE_CHANGED; + event.u.size.w = av7110->video_size.w; + event.u.size.h = av7110->video_size.h; + switch ((h_ar >> 12) & 0xf) + { + case 3: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9; + event.u.size.aspect_ratio = VIDEO_FORMAT_16_9; + av7110->videostate.video_format = VIDEO_FORMAT_16_9; + break; + case 4: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_221_1; + event.u.size.aspect_ratio = VIDEO_FORMAT_221_1; + av7110->videostate.video_format = VIDEO_FORMAT_221_1; + break; + default: + av7110->video_size.aspect_ratio = VIDEO_FORMAT_4_3; + event.u.size.aspect_ratio = VIDEO_FORMAT_4_3; + av7110->videostate.video_format = VIDEO_FORMAT_4_3; + } + + dprintk(8, "GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u\n", + av7110->video_size.w, av7110->video_size.h, + av7110->video_size.aspect_ratio); + + dvb_video_add_event(av7110, &event); + break; + } + + case DATA_CI_PUT: + { + int avail; + struct dvb_ringbuffer *cibuf = &av7110->ci_wbuffer; + + avail = dvb_ringbuffer_avail(cibuf); + if (avail <= 2) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; + len |= DVB_RINGBUFFER_PEEK(cibuf, 1); + if (avail < len + 2) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + DVB_RINGBUFFER_SKIP(cibuf, 2); + + dvb_ringbuffer_read(cibuf, av7110->debi_virt, len); + + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + dprintk(8, "DMA: CI\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); + spin_unlock(&av7110->debilock); + wake_up(&cibuf->queue); + return; + } + + case DATA_MPEG_PLAY: + if (!av7110->playing) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + len = 0; + if (av7110->debitype & 0x100) { + spin_lock(&av7110->aout.lock); + len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048); + spin_unlock(&av7110->aout.lock); + } + if (len <= 0 && (av7110->debitype & 0x200) + &&av7110->videostate.play_state != VIDEO_FREEZED) { + spin_lock(&av7110->avout.lock); + len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048); + spin_unlock(&av7110->avout.lock); + } + if (len <= 0) { + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + break; + } + dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len); + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + dprintk(8, "DMA: MPEG_PLAY\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_BMP_LOAD: + len = av7110->debilen; + dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len); + if (!len) { + av7110->bmp_state = BMP_LOADED; + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); + iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); + wake_up(&av7110->bmpq); + dprintk(8, "gpio DATA_BMP_LOAD done\n"); + break; + } + if (len > av7110->bmplen) + len = av7110->bmplen; + if (len > 2 * 1024) + len = 2 * 1024; + iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); + iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); + memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); + av7110->bmpp += len; + av7110->bmplen -= len; + dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_CI_GET: + case DATA_COMMON_INTERFACE: + case DATA_FSECTION: + case DATA_IPMPE: + case DATA_PIPING: + if (!len || len > 4 * 1024) { + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + } + fallthrough; + + case DATA_TS_RECORD: + case DATA_PES_RECORD: + dprintk(8, "DMA: TS_REC etc.\n"); + start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_DEBUG_MESSAGE: + if (!len || len > 0xff) { + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + } + start_debi_dma(av7110, DEBI_READ, Reserved, len); + spin_unlock(&av7110->debilock); + return; + + case DATA_IRCOMMAND: +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) + av7110_ir_handler(av7110, + swahw32(irdebi(av7110, DEBINOSWAP, Reserved, + 0, 4))); +#endif + iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); + break; + + default: + printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n", + av7110->debitype, av7110->debilen); + break; + } + av7110->debitype = -1; + ARM_ClearMailBox(av7110); + spin_unlock(&av7110->debilock); +} + + +#ifdef CONFIG_DVB_AV7110_OSD +static int dvb_osd_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(4, "%p\n", av7110); + + if (cmd == OSD_SEND_CMD) + return av7110_osd_cmd(av7110, (osd_cmd_t *) parg); + if (cmd == OSD_GET_CAPABILITY) + return av7110_osd_capability(av7110, (osd_cap_t *) parg); + + return -EINVAL; +} + + +static const struct file_operations dvb_osd_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_osd = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_osd_fops, + .kernel_ioctl = dvb_osd_ioctl, +}; +#endif /* CONFIG_DVB_AV7110_OSD */ + + +static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid) +{ + u16 aflags = 0; + + dprintk(4, "%p\n", av7110); + + if (vpid == 0x1fff || apid == 0x1fff || + ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) { + vpid = apid = ttpid = subpid = pcrpid = 0; + av7110->pids[DMX_PES_VIDEO] = 0; + av7110->pids[DMX_PES_AUDIO] = 0; + av7110->pids[DMX_PES_TELETEXT] = 0; + av7110->pids[DMX_PES_PCR] = 0; + } + + if (av7110->audiostate.bypass_mode) + aflags |= 0x8000; + + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, MultiPID, 6, + pcrpid, vpid, apid, ttpid, subpid, aflags); +} + +int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid) +{ + int ret = 0; + dprintk(4, "%p\n", av7110); + + if (mutex_lock_interruptible(&av7110->pid_mutex)) + return -ERESTARTSYS; + + if (!(vpid & 0x8000)) + av7110->pids[DMX_PES_VIDEO] = vpid; + if (!(apid & 0x8000)) + av7110->pids[DMX_PES_AUDIO] = apid; + if (!(ttpid & 0x8000)) + av7110->pids[DMX_PES_TELETEXT] = ttpid; + if (!(pcrpid & 0x8000)) + av7110->pids[DMX_PES_PCR] = pcrpid; + + av7110->pids[DMX_PES_SUBTITLE] = 0; + + if (av7110->fe_synced) { + pcrpid = av7110->pids[DMX_PES_PCR]; + ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid); + } + + mutex_unlock(&av7110->pid_mutex); + return ret; +} + + +/****************************************************************************** + * hardware filter functions + ******************************************************************************/ + +static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) +{ + struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed; + struct av7110 *av7110 = dvbdmxfeed->demux->priv; + u16 buf[20]; + int ret, i; + u16 handle; +// u16 mode = 0x0320; + u16 mode = 0xb96a; + + dprintk(4, "%p\n", av7110); + + if (av7110->full_ts) + return 0; + + if (dvbdmxfilter->type == DMX_TYPE_SEC) { + if (hw_sections) { + buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | + dvbdmxfilter->maskandmode[0]; + for (i = 3; i < 18; i++) + buf[i + 4 - 2] = + (dvbdmxfilter->filter.filter_value[i] << 8) | + dvbdmxfilter->maskandmode[i]; + mode = 4; + } + } else if ((dvbdmxfeed->ts_type & TS_PACKET) && + !(dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)) { + av7110_p2t_init(&av7110->p2t_filter[dvbdmxfilter->index], dvbdmxfeed); + } + + buf[0] = (COMTYPE_PID_FILTER << 8) + AddPIDFilter; + buf[1] = 16; + buf[2] = dvbdmxfeed->pid; + buf[3] = mode; + + ret = av7110_fw_request(av7110, buf, 20, &handle, 1); + if (ret != 0 || handle >= 32) { + printk(KERN_ERR "dvb-ttpci: %s error buf %04x %04x %04x %04x ret %d handle %04x\n", + __func__, buf[0], buf[1], buf[2], buf[3], + ret, handle); + dvbdmxfilter->hw_handle = 0xffff; + if (!ret) + ret = -1; + return ret; + } + + av7110->handle2filter[handle] = dvbdmxfilter; + dvbdmxfilter->hw_handle = handle; + + return ret; +} + +static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) +{ + struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv; + u16 buf[3]; + u16 answ[2]; + int ret; + u16 handle; + + dprintk(4, "%p\n", av7110); + + if (av7110->full_ts) + return 0; + + handle = dvbdmxfilter->hw_handle; + if (handle >= 32) { + printk("%s tried to stop invalid filter %04x, filter type = %x\n", + __func__, handle, dvbdmxfilter->type); + return -EINVAL; + } + + av7110->handle2filter[handle] = NULL; + + buf[0] = (COMTYPE_PID_FILTER << 8) + DelPIDFilter; + buf[1] = 1; + buf[2] = handle; + ret = av7110_fw_request(av7110, buf, 3, answ, 2); + if (ret != 0 || answ[1] != handle) { + printk(KERN_ERR "dvb-ttpci: %s error cmd %04x %04x %04x ret %x resp %04x %04x pid %d\n", + __func__, buf[0], buf[1], buf[2], ret, + answ[0], answ[1], dvbdmxfilter->feed->pid); + if (!ret) + ret = -1; + } + return ret; +} + + +static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct av7110 *av7110 = dvbdmx->priv; + u16 *pid = dvbdmx->pids, npids[5]; + int i; + int ret = 0; + + dprintk(4, "%p\n", av7110); + + npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; + i = dvbdmxfeed->pes_type; + npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; + if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) { + npids[i] = 0; + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (!ret) + ret = StartHWFilter(dvbdmxfeed->filter); + return ret; + } + if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) { + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + if (ret) + return ret; + } + + if (dvbdmxfeed->pes_type < 2 && npids[0]) + if (av7110->fe_synced) + { + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + if (ret) + return ret; + } + + if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { + if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) + ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); + if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) + ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed); + } + return ret; +} + +static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct av7110 *av7110 = dvbdmx->priv; + u16 *pid = dvbdmx->pids, npids[5]; + int i; + + int ret = 0; + + dprintk(4, "%p\n", av7110); + + if (dvbdmxfeed->pes_type <= 1) { + ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO); + if (ret) + return ret; + if (!av7110->rec_mode) + dvbdmx->recording = 0; + if (!av7110->playing) + dvbdmx->playing = 0; + } + npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff; + i = dvbdmxfeed->pes_type; + switch (i) { + case 2: //teletext + if (dvbdmxfeed->ts_type & TS_PACKET) + ret = StopHWFilter(dvbdmxfeed->filter); + npids[2] = 0; + break; + case 0: + case 1: + case 4: + if (!pids_off) + return 0; + npids[i] = (pid[i]&0x8000) ? 0 : pid[i]; + break; + } + if (!ret) + ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]); + return ret; +} + +static int av7110_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = demux->priv; + int ret = 0; + + dprintk(4, "%p\n", av7110); + + if (!demux->dmx.frontend) + return -EINVAL; + + if (!av7110->full_ts && feed->pid > 0x1fff) + return -EINVAL; + + if (feed->type == DMX_TYPE_TS) { + if ((feed->ts_type & TS_DECODER) && + (feed->pes_type <= DMX_PES_PCR)) { + switch (demux->dmx.frontend->source) { + case DMX_MEMORY_FE: + if (feed->ts_type & TS_DECODER) + if (feed->pes_type < 2 && + !(demux->pids[0] & 0x8000) && + !(demux->pids[1] & 0x8000)) { + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + ret = av7110_av_start_play(av7110,RP_AV); + if (!ret) + demux->playing = 1; + } + break; + default: + ret = dvb_feed_start_pid(feed); + break; + } + } else if ((feed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE)) { + ret = StartHWFilter(feed->filter); + } + } + + if (av7110->full_ts) { + budget_start_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { + int i; + + for (i = 0; i < demux->filternum; i++) { + if (demux->filter[i].state != DMX_STATE_READY) + continue; + if (demux->filter[i].type != DMX_TYPE_SEC) + continue; + if (demux->filter[i].filter.parent != &feed->feed.sec) + continue; + demux->filter[i].state = DMX_STATE_GO; + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + ret = StartHWFilter(&demux->filter[i]); + if (ret) + break; + } + } + } + + return ret; +} + + +static int av7110_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = demux->priv; + int i, rc, ret = 0; + dprintk(4, "%p\n", av7110); + + if (feed->type == DMX_TYPE_TS) { + if (feed->ts_type & TS_DECODER) { + if (feed->pes_type >= DMX_PES_OTHER || + !demux->pesfilter[feed->pes_type]) + return -EINVAL; + demux->pids[feed->pes_type] |= 0x8000; + demux->pesfilter[feed->pes_type] = NULL; + } + if (feed->ts_type & TS_DECODER && + feed->pes_type < DMX_PES_OTHER) { + ret = dvb_feed_stop_pid(feed); + } else + if ((feed->ts_type & TS_PACKET) && + (demux->dmx.frontend->source != DMX_MEMORY_FE)) + ret = StopHWFilter(feed->filter); + } + + if (av7110->full_ts) { + budget_stop_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { + for (i = 0; i<demux->filternum; i++) { + if (demux->filter[i].state == DMX_STATE_GO && + demux->filter[i].filter.parent == &feed->feed.sec) { + demux->filter[i].state = DMX_STATE_READY; + if (demux->dmx.frontend->source != DMX_MEMORY_FE) { + rc = StopHWFilter(&demux->filter[i]); + if (!ret) + ret = rc; + /* keep going, stop as many filters as possible */ + } + } + } + } + + return ret; +} + + +static void restart_feeds(struct av7110 *av7110) +{ + struct dvb_demux *dvbdmx = &av7110->demux; + struct dvb_demux_feed *feed; + int mode; + int feeding; + int i, j; + + dprintk(4, "%p\n", av7110); + + mode = av7110->playing; + av7110->playing = 0; + av7110->rec_mode = 0; + + feeding = av7110->feeding1; /* full_ts mod */ + + for (i = 0; i < dvbdmx->feednum; i++) { + feed = &dvbdmx->feed[i]; + if (feed->state == DMX_STATE_GO) { + if (feed->type == DMX_TYPE_SEC) { + for (j = 0; j < dvbdmx->filternum; j++) { + if (dvbdmx->filter[j].type != DMX_TYPE_SEC) + continue; + if (dvbdmx->filter[j].filter.parent != &feed->feed.sec) + continue; + if (dvbdmx->filter[j].state == DMX_STATE_GO) + dvbdmx->filter[j].state = DMX_STATE_READY; + } + } + av7110_start_feed(feed); + } + } + + av7110->feeding1 = feeding; /* full_ts mod */ + + if (mode) + av7110_av_start_play(av7110, mode); +} + +static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, + uint64_t *stc, unsigned int *base) +{ + int ret; + u16 fwstc[4]; + u16 tag = ((COMTYPE_REQUEST << 8) + ReqSTC); + struct dvb_demux *dvbdemux; + struct av7110 *av7110; + + /* pointer casting paranoia... */ + BUG_ON(!demux); + dvbdemux = demux->priv; + BUG_ON(!dvbdemux); + av7110 = dvbdemux->priv; + + dprintk(4, "%p\n", av7110); + + if (num != 0) + return -EINVAL; + + ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4); + if (ret) { + printk(KERN_ERR "%s: av7110_fw_request error\n", __func__); + return ret; + } + dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", + fwstc[0], fwstc[1], fwstc[2], fwstc[3]); + + *stc = (((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) | + (((uint64_t) fwstc[1]) << 16) | ((uint64_t) fwstc[0]); + *base = 1; + + dprintk(4, "stc = %lu\n", (unsigned long)*stc); + + return 0; +} + + +/****************************************************************************** + * SEC device file operations + ******************************************************************************/ + + +static int av7110_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) +{ + struct av7110* av7110 = fe->dvb->priv; + + switch (tone) { + case SEC_TONE_ON: + return Set22K(av7110, 1); + + case SEC_TONE_OFF: + return Set22K(av7110, 0); + + default: + return -EINVAL; + } +} + +static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); +} + +static int av7110_diseqc_send_burst(struct dvb_frontend* fe, + enum fe_sec_mini_cmd minicmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + return av7110_diseqc_send(av7110, 0, NULL, minicmd); +} + +/* simplified code from budget-core.c */ +static int stop_ts_capture(struct av7110 *budget) +{ + dprintk(2, "budget: %p\n", budget); + + if (--budget->feeding1) + return budget->feeding1; + saa7146_write(budget->dev, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(budget->dev, MASK_10); + SAA7146_ISR_CLEAR(budget->dev, MASK_10); + return 0; +} + +static int start_ts_capture(struct av7110 *budget) +{ + unsigned y; + + dprintk(2, "budget: %p\n", budget); + + if (budget->feeding1) + return ++budget->feeding1; + for (y = 0; y < TS_HEIGHT; y++) + memset(budget->grabbing + y * TS_WIDTH, 0x00, TS_WIDTH); + budget->ttbp = 0; + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ + SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ + saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ + return ++budget->feeding1; +} + +static int budget_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = demux->priv; + int status; + + dprintk(2, "av7110: %p\n", budget); + + spin_lock(&budget->feedlock1); + feed->pusi_seen = false; /* have a clean section start */ + status = start_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static int budget_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = demux->priv; + int status; + + dprintk(2, "budget: %p\n", budget); + + spin_lock(&budget->feedlock1); + status = stop_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static void vpeirq(struct tasklet_struct *t) +{ + struct av7110 *budget = from_tasklet(budget, t, vpe_tasklet); + u8 *mem = (u8 *) (budget->grabbing); + u32 olddma = budget->ttbp; + u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; + + /* nearest lower position divisible by 188 */ + newdma -= newdma % 188; + + if (newdma >= TS_BUFLEN) + return; + + budget->ttbp = newdma; + + if (!budget->feeding1 || (newdma == olddma)) + return; + + /* Ensure streamed PCI data is synced to CPU */ + dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist, + budget->pt.nents, DMA_FROM_DEVICE); + +#if 0 + /* track rps1 activity */ + printk("vpeirq: %02x Event Counter 1 0x%04x\n", + mem[olddma], + saa7146_read(budget->dev, EC1R) & 0x3fff); +#endif + + if (newdma > olddma) + /* no wraparound, dump olddma..newdma */ + dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); + else { + /* wraparound, dump olddma..buflen and 0..newdma */ + dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + dvb_dmx_swfilter_packets(demux, mem, newdma / 188); + } +} + +static int av7110_register(struct av7110 *av7110) +{ + int ret, i; + struct dvb_demux *dvbdemux = &av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; + + dprintk(4, "%p\n", av7110); + + if (av7110->registered) + return -1; + + av7110->registered = 1; + + dvbdemux->priv = (void *) av7110; + + for (i = 0; i < 32; i++) + av7110->handle2filter[i] = NULL; + + dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; + dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; + dvbdemux->start_feed = av7110_start_feed; + dvbdemux->stop_feed = av7110_stop_feed; + dvbdemux->write_to_decoder = av7110_write_to_decoder; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&av7110->demux); + av7110->demux.dmx.get_stc = dvb_get_stc; + + av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; + av7110->dmxdev.demux = &dvbdemux->dmx; + av7110->dmxdev.capabilities = 0; + + dvb_dmxdev_init(&av7110->dmxdev, &av7110->dvb_adapter); + + av7110->hw_frontend.source = DMX_FRONTEND_0; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->hw_frontend); + + if (ret < 0) + return ret; + + av7110->mem_frontend.source = DMX_MEMORY_FE; + + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &av7110->mem_frontend); + + if (ret < 0) + return ret; + + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, + &av7110->hw_frontend); + if (ret < 0) + return ret; + + av7110_av_register(av7110); + av7110_ca_register(av7110); + +#ifdef CONFIG_DVB_AV7110_OSD + dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev, + &dvbdev_osd, av7110, DVB_DEVICE_OSD, 0); +#endif + + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); + + if (budgetpatch) { + /* initialize software demux1 without its own frontend + * demux1 hardware is connected to frontend0 of demux0 + */ + dvbdemux1->priv = (void *) av7110; + + dvbdemux1->filternum = 256; + dvbdemux1->feednum = 256; + dvbdemux1->start_feed = budget_start_feed; + dvbdemux1->stop_feed = budget_stop_feed; + dvbdemux1->write_to_decoder = NULL; + + dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&av7110->demux1); + + av7110->dmxdev1.filternum = 256; + av7110->dmxdev1.demux = &dvbdemux1->dmx; + av7110->dmxdev1.capabilities = 0; + + dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter); + + dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); + printk("dvb-ttpci: additional demux1 for budget-patch registered\n"); + } + return 0; +} + + +static void dvb_unregister(struct av7110 *av7110) +{ + struct dvb_demux *dvbdemux = &av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; + + dprintk(4, "%p\n", av7110); + + if (!av7110->registered) + return; + + if (budgetpatch) { + dvb_net_release(&av7110->dvb_net1); + dvbdemux->dmx.close(&dvbdemux1->dmx); + dvb_dmxdev_release(&av7110->dmxdev1); + dvb_dmx_release(&av7110->demux1); + } + + dvb_net_release(&av7110->dvb_net); + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend); + + dvb_dmxdev_release(&av7110->dmxdev); + dvb_dmx_release(&av7110->demux); + + if (av7110->fe != NULL) { + dvb_unregister_frontend(av7110->fe); + dvb_frontend_detach(av7110->fe); + } + dvb_unregister_device(av7110->osd_dev); + av7110_av_unregister(av7110); + av7110_ca_unregister(av7110); +} + + +/**************************************************************************** + * I2C client commands + ****************************************************************************/ + +int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) +{ + u8 msg[2] = { reg, val }; + struct i2c_msg msgs; + + msgs.flags = 0; + msgs.addr = id / 2; + msgs.len = 2; + msgs.buf = msg; + return i2c_transfer(&av7110->i2c_adap, &msgs, 1); +} + +u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) +{ + u8 mm1[] = {0x00}; + u8 mm2[] = {0x00}; + struct i2c_msg msgs[2]; + + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr = id / 2; + mm1[0] = reg; + msgs[0].len = 1; msgs[1].len = 1; + msgs[0].buf = mm1; msgs[1].buf = mm2; + i2c_transfer(&av7110->i2c_adap, msgs, 2); + + return mm2[0]; +} + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + + +static int check_firmware(struct av7110* av7110) +{ + u32 crc = 0, len = 0; + unsigned char *ptr; + + /* check for firmware magic */ + ptr = av7110->bin_fw; + if (ptr[0] != 'A' || ptr[1] != 'V' || + ptr[2] != 'F' || ptr[3] != 'W') { + printk("dvb-ttpci: this is not an av7110 firmware\n"); + return -EINVAL; + } + ptr += 4; + + /* check dpram file */ + crc = get_unaligned_be32(ptr); + ptr += 4; + len = get_unaligned_be32(ptr); + ptr += 4; + if (len >= 512) { + printk("dvb-ttpci: dpram file is way too big.\n"); + return -EINVAL; + } + if (crc != crc32_le(0, ptr, len)) { + printk("dvb-ttpci: crc32 of dpram file does not match.\n"); + return -EINVAL; + } + av7110->bin_dpram = ptr; + av7110->size_dpram = len; + ptr += len; + + /* check root file */ + crc = get_unaligned_be32(ptr); + ptr += 4; + len = get_unaligned_be32(ptr); + ptr += 4; + + if (len <= 200000 || len >= 300000 || + len > ((av7110->bin_fw + av7110->size_fw) - ptr)) { + printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len); + return -EINVAL; + } + if( crc != crc32_le(0, ptr, len)) { + printk("dvb-ttpci: crc32 of root file does not match.\n"); + return -EINVAL; + } + av7110->bin_root = ptr; + av7110->size_root = len; + return 0; +} + +static void put_firmware(struct av7110* av7110) +{ + vfree(av7110->bin_fw); +} + +static int get_firmware(struct av7110* av7110) +{ + int ret; + const struct firmware *fw; + + /* request the av7110 firmware, this will block until someone uploads it */ + ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev); + if (ret) { + if (ret == -ENOENT) { + printk(KERN_ERR "dvb-ttpci: could not load firmware, file not found: dvb-ttpci-01.fw\n"); + printk(KERN_ERR "dvb-ttpci: usually this should be in /usr/lib/hotplug/firmware or /lib/firmware\n"); + printk(KERN_ERR "dvb-ttpci: and can be downloaded from https://linuxtv.org/download/dvb/firmware/\n"); + } else + printk(KERN_ERR "dvb-ttpci: cannot request firmware (error %i)\n", + ret); + return -EINVAL; + } + + if (fw->size <= 200000) { + printk("dvb-ttpci: this firmware is way too small.\n"); + release_firmware(fw); + return -EINVAL; + } + + /* check if the firmware is available */ + av7110->bin_fw = vmalloc(fw->size); + if (NULL == av7110->bin_fw) { + dprintk(1, "out of memory\n"); + release_firmware(fw); + return -ENOMEM; + } + + memcpy(av7110->bin_fw, fw->data, fw->size); + av7110->size_fw = fw->size; + if ((ret = check_firmware(av7110))) + vfree(av7110->bin_fw); + + release_firmware(fw); + return ret; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (p->frequency + 479500) / 125; + + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; + else + pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (p->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (p->frequency < 174000000 ? 0x88 : p->frequency < 470000000 ? 0x84 : 0x81); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + + + + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = p->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + + + +static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u32 f = p->frequency; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (f + 36125000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config philips_cd1516_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, +}; + + + +static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div, pwr; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (p->frequency + 36200000) / 166666; + + if (p->frequency <= 782000000) + pwr = 1; + else + pwr = 2; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85; + data[3] = pwr << 6; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ +#if IS_ENABLED(CONFIG_DVB_SP8870) + struct av7110* av7110 = fe->dvb->priv; + + return request_firmware(fw, name, &av7110->dev->pci->dev); +#else + return -EINVAL; +#endif +} + +static const struct sp8870_config alps_tdlb7_config = { + + .demod_address = 0x71, + .request_firmware = alps_tdlb7_request_firmware, +}; + + +static u8 nexusca_stv0297_inittab[] = { + 0x80, 0x01, + 0x80, 0x00, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0x00, + 0x4b, 0x7b, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x10, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x04, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, + 0xff, 0xff, +}; + +static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) }; + struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; + int i; + + div = (p->frequency + 36150000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; + + if (p->frequency < 45000000) + return -EINVAL; + else if (p->frequency < 137000000) + data[3] = 0x01; + else if (p->frequency < 403000000) + data[3] = 0x02; + else if (p->frequency < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) { + printk("nexusca: pll transfer failed!\n"); + return -EIO; + } + + // wait for PLL lock + for(i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1) + if (data[0] & 0x40) break; + msleep(10); + } + + return 0; +} + +static struct stv0297_config nexusca_stv0297_config = { + + .demod_address = 0x1C, + .inittab = nexusca_stv0297_inittab, + .invert = 1, + .stop_during_read = 1, +}; + + + +static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct av7110* av7110 = fe->dvb->priv; + u32 div; + u8 cfg, cpump, band_select; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36125000 + p->frequency) / 166666; + + cfg = 0x88; + + if (p->frequency < 175000000) + cpump = 2; + else if (p->frequency < 390000000) + cpump = 1; + else if (p->frequency < 470000000) + cpump = 2; + else if (p->frequency < 750000000) + cpump = 1; + else + cpump = 3; + + if (p->frequency < 175000000) + band_select = 0x0e; + else if (p->frequency < 470000000) + band_select = 0x05; + else + band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct l64781_config grundig_29504_401_config = { + .demod_address = 0x55, +}; + + + +static int av7110_fe_lock_fix(struct av7110 *av7110, enum fe_status status) +{ + int ret = 0; + int synced = (status & FE_HAS_LOCK) ? 1 : 0; + + av7110->fe_status = status; + + if (av7110->fe_synced == synced) + return 0; + + if (av7110->playing) { + av7110->fe_synced = synced; + return 0; + } + + if (mutex_lock_interruptible(&av7110->pid_mutex)) + return -ERESTARTSYS; + + if (synced) { + ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], + av7110->pids[DMX_PES_AUDIO], + av7110->pids[DMX_PES_TELETEXT], 0, + av7110->pids[DMX_PES_PCR]); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + } else { + ret = SetPIDs(av7110, 0, 0, 0, 0, 0); + if (!ret) { + ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); + if (!ret) + ret = av7110_wait_msgstate(av7110, GPMQBusy); + } + } + + if (!ret) + av7110->fe_synced = synced; + + mutex_unlock(&av7110->pid_mutex); + return ret; +} + +static int av7110_fe_set_frontend(struct dvb_frontend *fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_set_frontend(fe); + + return ret; +} + +static int av7110_fe_init(struct dvb_frontend* fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_init(fe); + return ret; +} + +static int av7110_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct av7110* av7110 = fe->dvb->priv; + + /* call the real implementation */ + int ret = av7110->fe_read_status(fe, status); + if (!ret) + if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) + ret = av7110_fe_lock_fix(av7110, *status); + return ret; +} + +static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_diseqc_reset_overload(fe); + return ret; +} + +static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd* cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_master_cmd = *cmd; + ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); + } + return ret; +} + +static int av7110_fe_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_minicmd = minicmd; + ret = av7110->fe_diseqc_send_burst(fe, minicmd); + } + return ret; +} + +static int av7110_fe_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_tone = tone; + ret = av7110->fe_set_tone(fe, tone); + } + return ret; +} + +static int av7110_fe_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) { + av7110->saved_voltage = voltage; + ret = av7110->fe_set_voltage(fe, voltage); + } + return ret; +} + +static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd) +{ + struct av7110* av7110 = fe->dvb->priv; + + int ret = av7110_fe_lock_fix(av7110, 0); + if (!ret) + ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); + return ret; +} + +static void dvb_s_recover(struct av7110* av7110) +{ + av7110_fe_init(av7110->fe); + + av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); + if (av7110->saved_master_cmd.msg_len) { + msleep(20); + av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); + } + msleep(20); + av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); + msleep(20); + av7110_fe_set_tone(av7110->fe, av7110->saved_tone); + + av7110_fe_set_frontend(av7110->fe); +} + +static u8 read_pwm(struct av7110* av7110) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int frontend_init(struct av7110 *av7110) +{ + int ret; + + if (av7110->dev->pci->subsystem_vendor == 0x110a) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) + av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, + &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } + break; + } + + } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X + case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE + + // try the ALPS BSRV2 first of all + av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + // try the ALPS BSRU6 now + av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + // Try the grundig 29504-451 + av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + break; + } + + /* Try DVB-C cards */ + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: + /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */ + av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap, + read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } + break; + case 0x0003: + /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ + av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, + read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } + break; + } + break; + + case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X + { + struct dvb_frontend *fe; + + // try ALPS TDLB7 first, then Grundig 29504-401 + fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params; + av7110->fe = fe; + break; + } + } + fallthrough; + + case 0x0008: // Hauppauge/TT DVB-T + // Grundig 29504-401 + av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap); + if (av7110->fe) + av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + break; + + case 0x0002: // Hauppauge/TT DVB-C premium rev2.X + + av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } + break; + + case 0x0004: // Galaxis DVB-S rev1.3 + /* ALPS BSRV2 */ + av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + } + break; + + case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ + /* Grundig 29504-451 */ + av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; + av7110->recover = dvb_s_recover; + } + break; + + case 0x000A: // Hauppauge/TT Nexus-CA rev1.X + + av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; + + /* set TDA9819 into DVB mode */ + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + + /* tuner on this needs a slower i2c bus speed */ + av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + break; + } + break; + + case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ + /* ALPS BSBE1 */ + av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) { + printk("dvb-ttpci: LNBP21 not found!\n"); + if (av7110->fe->ops.release) + av7110->fe->ops.release(av7110->fe); + av7110->fe = NULL; + } else { + av7110->fe->ops.dishnetwork_send_legacy_command = NULL; + av7110->recover = dvb_s_recover; + } + } + break; + } + } + + if (!av7110->fe) { + /* FIXME: propagate the failure code from the lower layers */ + ret = -ENOMEM; + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + av7110->dev->pci->vendor, + av7110->dev->pci->device, + av7110->dev->pci->subsystem_vendor, + av7110->dev->pci->subsystem_device); + } else { + FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init); + FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage); + FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); + + ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); + if (ret < 0) { + printk("av7110: Frontend registration failed!\n"); + dvb_frontend_detach(av7110->fe); + av7110->fe = NULL; + } + } + return ret; +} + +/* Budgetpatch note: + * Original hardware design by Roberto Deza: + * There is a DVB_Wiki at + * https://linuxtv.org + * + * New software triggering design by Emard that works on + * original Roberto Deza's hardware: + * + * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin. + * GPIO3 is in budget-patch hardware connectd to port B VSYNC + * HS is an internal event of 7146, accessible with RPS + * and temporarily raised high every n lines + * (n in defined in the RPS_THRESH1 counter threshold) + * I think HS is raised high on the beginning of the n-th line + * and remains high until this n-th line that triggered + * it is completely received. When the reception of n-th line + * ends, HS is lowered. + * + * To transmit data over DMA, 7146 needs changing state at + * port B VSYNC pin. Any changing of port B VSYNC will + * cause some DMA data transfer, with more or less packets loss. + * It depends on the phase and frequency of VSYNC and + * the way of 7146 is instructed to trigger on port B (defined + * in DD1_INIT register, 3rd nibble from the right valid + * numbers are 0-7, see datasheet) + * + * The correct triggering can minimize packet loss, + * dvbtraffic should give this stable bandwidths: + * 22k transponder = 33814 kbit/s + * 27.5k transponder = 38045 kbit/s + * by experiment it is found that the best results + * (stable bandwidths and almost no packet loss) + * are obtained using DD1_INIT triggering number 2 + * (Va at rising edge of VS Fa = HS x VS-failing forced toggle) + * and a VSYNC phase that occurs in the middle of DMA transfer + * (about byte 188*512=96256 in the DMA window). + * + * Phase of HS is still not clear to me how to control, + * It just happens to be so. It can be seen if one enables + * RPS_IRQ and print Event Counter 1 in vpeirq(). Every + * time RPS_INTERRUPT is called, the Event Counter 1 will + * increment. That's how the 7146 is programmed to do event + * counting in this budget-patch.c + * I *think* HPS setting has something to do with the phase + * of HS but I can't be 100% sure in that. + * + * hardware debug note: a working budget card (including budget patch) + * with vpeirq() interrupt setup in mode "0x90" (every 64K) will + * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes + * and that means 3*25=75 Hz of interrupt frequency, as seen by + * watch cat /proc/interrupts + * + * If this frequency is 3x lower (and data received in the DMA + * buffer don't start with 0x47, but in the middle of packets, + * whose lengths appear to be like 188 292 188 104 etc. + * this means VSYNC line is not connected in the hardware. + * (check soldering pcb and pins) + * The same behaviour of missing VSYNC can be duplicated on budget + * cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. + */ +static int av7110_attach(struct saa7146_dev* dev, + struct saa7146_pci_extension_data *pci_ext) +{ + const int length = TS_WIDTH * TS_HEIGHT; + struct pci_dev *pdev = dev->pci; + struct av7110 *av7110; + struct task_struct *thread; + int ret, count = 0; + + dprintk(4, "dev: %p\n", dev); + + /* Set RPS_IRQ to 1 to track rps1 activity. + * Enabling this won't send any interrupt to PC CPU. + */ +#define RPS_IRQ 0 + + if (budgetpatch == 1) { + budgetpatch = 0; + /* autodetect the presence of budget patch + * this only works if saa7146 has been recently + * reset with 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. + * (GPIO3 should be raised high by CPU to + * test if GPIO3 will generate vertical blank signal + * in budget patch GPIO3 is connected to VSYNC_B + */ + + /* RESET SAA7146 */ + saa7146_write(dev, MC1, MASK_31); + /* autodetection success seems to be time-dependend after reset */ + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* set vsync_b triggering */ + saa7146_write(dev, DD1_STREAM_B, 0); + /* port B VSYNC at rising edge */ + saa7146_write(dev, DD1_INIT, 0x00000200); + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + saa7146_write(dev, MC2, + 1 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 1 * (MASK_10 | MASK_26) | // b + 0 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 0 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); + + /* start writing RPS1 code from beginning */ + count = 0; + /* Disable RPS1 */ + saa7146_write(dev, MC1, MASK_29); + /* RPS1 timeout disable */ + saa7146_write(dev, RPS_TOV1, 0); + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + /* issue RPS1 interrupt to increment counter */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + WRITE_RPS1(CMD_STOP); + /* Jump to begin of RPS program as safety measure (p37) */ + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 threshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Enable RPS1, (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); + + mdelay(10); + /* now send VSYNC_B to rps1 by rising GPIO3 */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(10); + /* if rps1 responded by lowering the GPIO3, + * then we have budgetpatch hardware + */ + if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) { + budgetpatch = 1; + printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n"); + } + /* Disable RPS1 */ + saa7146_write(dev, MC1, ( MASK_29 )); +#if RPS_IRQ + printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + } + + /* prepare the av7110 device struct */ + av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL); + if (!av7110) { + dprintk(1, "out of memory\n"); + return -ENOMEM; + } + + av7110->card_name = (char*) pci_ext->ext_priv; + av7110->dev = dev; + dev->ext_priv = av7110; + + ret = get_firmware(av7110); + if (ret < 0) + goto err_kfree_0; + + ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, + THIS_MODULE, &dev->pci->dev, adapter_nr); + if (ret < 0) + goto err_put_firmware_1; + + /* the Siemens DVB needs this if you want to have the i2c chips + get recognized before the main driver is fully loaded */ + saa7146_write(dev, GPIO_CTRL, 0x500000); + + strscpy(av7110->i2c_adap.name, pci_ext->ext_priv, + sizeof(av7110->i2c_adap.name)); + + saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ + + ret = i2c_add_adapter(&av7110->i2c_adap); + if (ret < 0) + goto err_dvb_unregister_adapter_2; + + ttpci_eeprom_parse_mac(&av7110->i2c_adap, + av7110->dvb_adapter.proposed_mac); + ret = -ENOMEM; + + /* full-ts mod? */ + if (full_ts) + av7110->full_ts = true; + + /* check for full-ts flag in eeprom */ + if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { + u8 flags = i2c_readreg(av7110, 0xaa, 2); + if (flags != 0xff && (flags & 0x01)) + av7110->full_ts = true; + } + + if (av7110->full_ts) { + printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x00000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, MC2, MASK_08 | MASK_24); + + /* dma3 */ + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + saa7146_write(dev, MC2, MASK_04 | MASK_20); + + tasklet_setup(&av7110->vpe_tasklet, vpeirq); + + } else if (budgetpatch) { + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, PCI_BT_V1, 0x1c1f101f); + saa7146_write(dev, BCS_CTRL, 0x80400040); + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x03000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + + /* upload all */ + saa7146_write(dev, MC2, 0x077c077c); + saa7146_write(dev, GPIO_CTRL, 0x000000); +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 threshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */ + count = 0; + + /* Wait Source Line Counter Threshold (p36) */ + WRITE_RPS1(CMD_PAUSE | EVT_HS); + /* Set GPIO3=1 (p42) */ + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + /* Wait reset Source Line Counter Threshold (p36) */ + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); + /* Set GPIO3=0 (p42) */ + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(CMD_INTERRUPT); +#endif + /* Jump to begin of RPS program (p37) */ + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Set Source Line Counter Threshold, using BRS (rCC p43) + * It generates HS event every TS_HEIGHT lines + * this is related to TS_WIDTH set in register + * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits + * are set to TS_WIDTH bytes (TS_WIDTH=2*188), + * then RPS_THRESH1 should be set to trigger + * every TS_HEIGHT (512) lines. + */ + saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); + + /* Enable RPS1 (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + /* end of budgetpatch register initialization */ + tasklet_setup(&av7110->vpe_tasklet, vpeirq); + } else { + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); + saa7146_write(dev, BCS_CTRL, 0x80400040); + + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x03000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* upload all */ + saa7146_write(dev, MC2, 0x077c077c); + saa7146_write(dev, GPIO_CTRL, 0x000000); + } + + tasklet_setup(&av7110->debi_tasklet, debiirq); + tasklet_setup(&av7110->gpio_tasklet, gpioirq); + + mutex_init(&av7110->pid_mutex); + + /* locks for data transfers from/to AV7110 */ + spin_lock_init(&av7110->debilock); + mutex_init(&av7110->dcomlock); + av7110->debitype = -1; + + /* default OSD window */ + av7110->osdwin = 1; + mutex_init(&av7110->osd_mutex); + + /* TV standard */ + av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC + : AV7110_VIDEO_MODE_PAL; + + /* ARM "watchdog" */ + init_waitqueue_head(&av7110->arm_wait); + av7110->arm_thread = NULL; + + /* allocate and init buffers */ + av7110->debi_virt = dma_alloc_coherent(&pdev->dev, 8192, + &av7110->debi_bus, GFP_KERNEL); + if (!av7110->debi_virt) + goto err_saa71466_vfree_4; + + + av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS); + if (!av7110->iobuf) + goto err_pci_free_5; + + ret = av7110_av_init(av7110); + if (ret < 0) + goto err_iobuf_vfree_6; + + /* init BMP buffer */ + av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN; + init_waitqueue_head(&av7110->bmpq); + + ret = av7110_ca_init(av7110); + if (ret < 0) + goto err_av7110_av_exit_7; + + /* load firmware into AV7110 cards */ + ret = av7110_bootarm(av7110); + if (ret < 0) + goto err_av7110_ca_exit_8; + + ret = av7110_firmversion(av7110); + if (ret < 0) + goto err_stop_arm_9; + + if (FW_VERSION(av7110->arm_app)<0x2501) + printk(KERN_WARNING + "dvb-ttpci: Warning, firmware version 0x%04x is too old. System might be unstable!\n", + FW_VERSION(av7110->arm_app)); + + thread = kthread_run(arm_thread, (void *) av7110, "arm_mon"); + if (IS_ERR(thread)) { + ret = PTR_ERR(thread); + goto err_stop_arm_9; + } + av7110->arm_thread = thread; + + /* set initial volume in mixer struct */ + av7110->mixer.volume_left = volume; + av7110->mixer.volume_right = volume; + + ret = av7110_register(av7110); + if (ret < 0) + goto err_arm_thread_stop_10; + + init_av7110_av(av7110); + + /* special case DVB-C: these cards have an analog tuner + plus need some special handling, so we have separate + saa7146_ext_vv data for these... */ + ret = av7110_init_v4l(av7110); + if (ret < 0) + goto err_av7110_unregister_11; + + av7110->dvb_adapter.priv = av7110; + ret = frontend_init(av7110); + if (ret < 0) + goto err_av7110_exit_v4l_12; + + mutex_init(&av7110->ioctl_mutex); + +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) + av7110_ir_init(av7110); +#endif + printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); + av7110_num++; +out: + return ret; + +err_av7110_exit_v4l_12: + av7110_exit_v4l(av7110); +err_av7110_unregister_11: + dvb_unregister(av7110); +err_arm_thread_stop_10: + av7110_arm_sync(av7110); +err_stop_arm_9: + /* Nothing to do. Rejoice. */ +err_av7110_ca_exit_8: + av7110_ca_exit(av7110); +err_av7110_av_exit_7: + av7110_av_exit(av7110); +err_iobuf_vfree_6: + vfree(av7110->iobuf); +err_pci_free_5: + dma_free_coherent(&pdev->dev, 8192, av7110->debi_virt, + av7110->debi_bus); +err_saa71466_vfree_4: + if (av7110->grabbing) + saa7146_vfree_destroy_pgtable(pdev, av7110->grabbing, &av7110->pt); +err_i2c_del_3: + i2c_del_adapter(&av7110->i2c_adap); +err_dvb_unregister_adapter_2: + dvb_unregister_adapter(&av7110->dvb_adapter); +err_put_firmware_1: + put_firmware(av7110); +err_kfree_0: + kfree(av7110); + goto out; +} + +static int av7110_detach(struct saa7146_dev* saa) +{ + struct av7110 *av7110 = saa->ext_priv; + dprintk(4, "%p\n", av7110); + +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) + av7110_ir_exit(av7110); +#endif + if (budgetpatch || av7110->full_ts) { + if (budgetpatch) { + /* Disable RPS1 */ + saa7146_write(saa, MC1, MASK_29); + /* VSYNC LOW (inactive) */ + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } + saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(saa, MASK_10); + SAA7146_ISR_CLEAR(saa, MASK_10); + msleep(50); + tasklet_kill(&av7110->vpe_tasklet); + saa7146_vfree_destroy_pgtable(saa->pci, av7110->grabbing, &av7110->pt); + } + av7110_exit_v4l(av7110); + + av7110_arm_sync(av7110); + + tasklet_kill(&av7110->debi_tasklet); + tasklet_kill(&av7110->gpio_tasklet); + + dvb_unregister(av7110); + + SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03); + SAA7146_ISR_CLEAR(saa, MASK_19 | MASK_03); + + av7110_ca_exit(av7110); + av7110_av_exit(av7110); + + vfree(av7110->iobuf); + dma_free_coherent(&saa->pci->dev, 8192, av7110->debi_virt, + av7110->debi_bus); + + i2c_del_adapter(&av7110->i2c_adap); + + dvb_unregister_adapter (&av7110->dvb_adapter); + + av7110_num--; + + put_firmware(av7110); + + kfree(av7110); + + saa->ext_priv = NULL; + + return 0; +} + + +static void av7110_irq(struct saa7146_dev* dev, u32 *isr) +{ + struct av7110 *av7110 = dev->ext_priv; + + //print_time("av7110_irq"); + + /* Note: Don't try to handle the DEBI error irq (MASK_18), in + * intel mode the timeout is asserted all the time... + */ + + if (*isr & MASK_19) { + //printk("av7110_irq: DEBI\n"); + /* Note 1: The DEBI irq is level triggered: We must enable it + * only after we started a DMA xfer, and disable it here + * immediately, or it will be signalled all the time while + * DEBI is idle. + * Note 2: You would think that an irq which is masked is + * not signalled by the hardware. Not so for the SAA7146: + * An irq is signalled as long as the corresponding bit + * in the ISR is set, and disabling irqs just prevents the + * hardware from setting the ISR bit. This means a) that we + * must clear the ISR *after* disabling the irq (which is why + * we must do it here even though saa7146_core did it already), + * and b) that if we were to disable an edge triggered irq + * (like the gpio irqs sadly are) temporarily we would likely + * loose some. This sucks :-( + */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); + tasklet_schedule(&av7110->debi_tasklet); + } + + if (*isr & MASK_03) { + //printk("av7110_irq: GPIO\n"); + tasklet_schedule(&av7110->gpio_tasklet); + } + + if (*isr & MASK_10) + tasklet_schedule(&av7110->vpe_tasklet); +} + + +static struct saa7146_extension av7110_extension_driver; + +#define MAKE_AV7110_INFO(x_var,x_name) \ +static struct saa7146_pci_extension_data x_var = { \ + .ext_priv = x_name, \ + .ext = &av7110_extension_driver } + +MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C"); +MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); +MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); +MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); +MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); +MAKE_AV7110_INFO(tts_2_3, "Technotrend/Hauppauge WinTV Nexus-S rev2.3"); +MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE"); +MAKE_AV7110_INFO(ttt, "Technotrend/Hauppauge DVB-T"); +MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); +MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); +MAKE_AV7110_INFO(gxs_1_3, "Galaxis DVB-S rev1.3"); + +static const struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), + MAKE_EXTENSION_PCI(tts_1_X_fsc, 0x13c2, 0x0000), + MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), + MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), + MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), + MAKE_EXTENSION_PCI(gxs_1_3, 0x13c2, 0x0004), + MAKE_EXTENSION_PCI(fss, 0x13c2, 0x0006), + MAKE_EXTENSION_PCI(ttt, 0x13c2, 0x0008), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), + MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e), + MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), + +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? + + { + .vendor = 0, + } +}; + +MODULE_DEVICE_TABLE(pci, pci_tbl); + + +static struct saa7146_extension av7110_extension_driver = { + .name = "av7110", + .flags = SAA7146_USE_I2C_IRQ, + + .module = THIS_MODULE, + .pci_tbl = &pci_tbl[0], + .attach = av7110_attach, + .detach = av7110_detach, + + .irq_mask = MASK_19 | MASK_03 | MASK_10, + .irq_func = av7110_irq, +}; + + +static int __init av7110_init(void) +{ + return saa7146_register_extension(&av7110_extension_driver); +} + + +static void __exit av7110_exit(void) +{ + saa7146_unregister_extension(&av7110_extension_driver); +} + +module_init(av7110_init); +module_exit(av7110_exit); + +MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by Siemens, Technotrend, Hauppauge"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h new file mode 100644 index 000000000000..b8e8fc8ddbe9 --- /dev/null +++ b/drivers/staging/media/av7110/av7110.h @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _AV7110_H_ +#define _AV7110_H_ + +#include <linux/interrupt.h> +#include <linux/socket.h> +#include <linux/netdevice.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/time.h> + +#include "video.h" +#include "audio.h" +#include "osd.h" + +#include <linux/dvb/dmx.h> +#include <linux/dvb/ca.h> +#include <linux/dvb/net.h> +#include <linux/mutex.h> + +#include <media/dvbdev.h> +#include <media/demux.h> +#include <media/dvb_demux.h> +#include <media/dmxdev.h> +#include "dvb_filter.h" +#include <media/dvb_net.h> +#include <media/dvb_ringbuffer.h> +#include <media/dvb_frontend.h> +#include "ves1820.h" +#include "ves1x93.h" +#include "stv0299.h" +#include "tda8083.h" +#include "sp8870.h" +#include "stv0297.h" +#include "l64781.h" + +#include <media/drv-intf/saa7146_vv.h> + + +#define ANALOG_TUNER_VES1820 1 +#define ANALOG_TUNER_STV0297 2 + +extern int av7110_debug; + +#define dprintk(level, fmt, arg...) do { \ + if (level & av7110_debug) \ + printk(KERN_DEBUG KBUILD_MODNAME ": %s(): " fmt, \ + __func__, ##arg); \ +} while (0) + +#define MAXFILT 32 + +enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; + +enum av7110_video_mode { + AV7110_VIDEO_MODE_PAL = 0, + AV7110_VIDEO_MODE_NTSC = 1 +}; + +struct av7110_p2t { + u8 pes[TS_SIZE]; + u8 counter; + long int pos; + int frags; + struct dvb_demux_feed *feed; +}; + +/* video MPEG decoder events: */ +/* (code copied from dvb_frontend.c, should maybe be factored out...) */ +#define MAX_VIDEO_EVENT 8 +struct dvb_video_events { + struct video_event events[MAX_VIDEO_EVENT]; + int eventw; + int eventr; + int overflow; + wait_queue_head_t wait_queue; + spinlock_t lock; +}; + + +struct av7110; + +/* infrared remote control */ +struct infrared { + struct rc_dev *rcdev; + char input_phys[32]; + u32 ir_config; +}; + +/* place to store all the necessary device information */ +struct av7110 { + + /* devices */ + + struct dvb_device dvb_dev; + struct dvb_net dvb_net; + + struct video_device v4l_dev; + struct video_device vbi_dev; + + struct saa7146_dev *dev; + + struct i2c_adapter i2c_adap; + + char *card_name; + + /* support for analog module of dvb-c */ + int analog_tuner_flags; + int current_input; + u32 current_freq; + + struct tasklet_struct debi_tasklet; + struct tasklet_struct gpio_tasklet; + + int adac_type; /* audio DAC type */ +#define DVB_ADAC_TI 0 +#define DVB_ADAC_CRYSTAL 1 +#define DVB_ADAC_MSP34x0 2 +#define DVB_ADAC_MSP34x5 3 +#define DVB_ADAC_NONE -1 + + + /* buffers */ + + void *iobuf; /* memory for all buffers */ + struct dvb_ringbuffer avout; /* buffer for video or A/V mux */ +#define AVOUTLEN (128*1024) + struct dvb_ringbuffer aout; /* buffer for audio */ +#define AOUTLEN (64*1024) + void *bmpbuf; +#define BMPLEN (8*32768+1024) + + /* bitmap buffers and states */ + + int bmpp; + int bmplen; + volatile int bmp_state; +#define BMP_NONE 0 +#define BMP_LOADING 1 +#define BMP_LOADED 2 + wait_queue_head_t bmpq; + + + /* DEBI and polled command interface */ + + spinlock_t debilock; + struct mutex dcomlock; + volatile int debitype; + volatile int debilen; + + + /* Recording and playback flags */ + + int rec_mode; + int playing; +#define RP_NONE 0 +#define RP_VIDEO 1 +#define RP_AUDIO 2 +#define RP_AV 3 + + + /* OSD */ + + int osdwin; /* currently active window */ + u16 osdbpp[8]; + struct mutex osd_mutex; + + /* CA */ + + struct ca_slot_info ci_slot[2]; + + enum av7110_video_mode vidmode; + struct dmxdev dmxdev; + struct dvb_demux demux; + + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + + /* for budget mode demux1 */ + struct dmxdev dmxdev1; + struct dvb_demux demux1; + struct dvb_net dvb_net1; + spinlock_t feedlock1; + int feeding1; + u32 ttbp; + unsigned char *grabbing; + struct saa7146_pgtable pt; + struct tasklet_struct vpe_tasklet; + bool full_ts; + + int fe_synced; + struct mutex pid_mutex; + + int video_blank; + struct video_status videostate; + u16 display_panscan; + int display_ar; + int trickmode; +#define TRICK_NONE 0 +#define TRICK_FAST 1 +#define TRICK_SLOW 2 +#define TRICK_FREEZE 3 + struct audio_status audiostate; + + struct dvb_demux_filter *handle2filter[32]; + struct av7110_p2t p2t_filter[MAXFILT]; + struct dvb_filter_pes2ts p2t[2]; + struct ipack ipack[2]; + u8 *kbuf[2]; + + int sinfo; + int feeding; + + int arm_errors; + int registered; + + + /* AV711X */ + + u32 arm_fw; + u32 arm_rtsl; + u32 arm_vid; + u32 arm_app; + u32 avtype; + int arm_ready; + struct task_struct *arm_thread; + wait_queue_head_t arm_wait; + u16 arm_loops; + + void *debi_virt; + dma_addr_t debi_bus; + + u16 pids[DMX_PES_OTHER]; + + struct dvb_ringbuffer ci_rbuffer; + struct dvb_ringbuffer ci_wbuffer; + + struct audio_mixer mixer; + + struct dvb_adapter dvb_adapter; + struct dvb_device *video_dev; + struct dvb_device *audio_dev; + struct dvb_device *ca_dev; + struct dvb_device *osd_dev; + + struct dvb_video_events video_events; + video_size_t video_size; + + u16 wssMode; + u16 wssData; + + struct infrared ir; + + /* firmware stuff */ + unsigned char *bin_fw; + unsigned long size_fw; + + unsigned char *bin_dpram; + unsigned long size_dpram; + + unsigned char *bin_root; + unsigned long size_root; + + struct dvb_frontend* fe; + enum fe_status fe_status; + + struct mutex ioctl_mutex; + + /* crash recovery */ + void (*recover)(struct av7110* av7110); + enum fe_sec_voltage saved_voltage; + enum fe_sec_tone_mode saved_tone; + struct dvb_diseqc_master_cmd saved_master_cmd; + enum fe_sec_mini_cmd saved_minicmd; + + int (*fe_init)(struct dvb_frontend* fe); + int (*fe_read_status)(struct dvb_frontend *fe, enum fe_status *status); + int (*fe_diseqc_reset_overload)(struct dvb_frontend *fe); + int (*fe_diseqc_send_master_cmd)(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd); + int (*fe_diseqc_send_burst)(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd); + int (*fe_set_tone)(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone); + int (*fe_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend *fe, + unsigned long cmd); + int (*fe_set_frontend)(struct dvb_frontend *fe); +}; + + +extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, + u16 subpid, u16 pcrpid); + +void av7110_ir_handler(struct av7110 *av7110, u32 ircom); +int av7110_set_ir_config(struct av7110 *av7110); +int av7110_ir_init(struct av7110 *av7110); +void av7110_ir_exit(struct av7110 *av7110); + +/* msp3400 i2c subaddresses */ +#define MSP_WR_DEM 0x10 +#define MSP_RD_DEM 0x11 +#define MSP_WR_DSP 0x12 +#define MSP_RD_DSP 0x13 + +extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val); +extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg); +extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val); + + +extern int av7110_init_analog_module(struct av7110 *av7110); +extern int av7110_init_v4l(struct av7110 *av7110); +extern int av7110_exit_v4l(struct av7110 *av7110); + +#endif /* _AV7110_H_ */ diff --git a/drivers/staging/media/av7110/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c new file mode 100644 index 000000000000..91f4866c7e59 --- /dev/null +++ b/drivers/staging/media/av7110/av7110_av.c @@ -0,0 +1,1681 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * av7110_av.c: audio and video MPEG decoder stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> + * + * the project's page is at https://linuxtv.org + */ + +#include <linux/ethtool.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/fs.h> + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" +#include "av7110_ipack.h" + +/* MPEG-2 (ISO 13818 / H.222.0) stream types */ +#define PROG_STREAM_MAP 0xBC +#define PRIVATE_STREAM1 0xBD +#define PADDING_STREAM 0xBE +#define PRIVATE_STREAM2 0xBF +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define PTS_DTS_FLAGS 0xC0 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +static void p_to_t(u8 const *buf, long int length, u16 pid, + u8 *counter, struct dvb_demux_feed *feed); +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len); + + +int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv; + + if (!(dvbdmxfeed->ts_type & TS_PACKET)) + return 0; + if (buf[3] == 0xe0) // video PES do not have a length in TS + buf[4] = buf[5] = 0; + if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) + return dvbdmxfeed->cb.ts(buf, len, NULL, 0, + &dvbdmxfeed->feed.ts, NULL); + else + return dvb_filter_pes2ts(p2t, buf, len, 1); +} + +static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) +{ + struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; + + dvbdmxfeed->cb.ts(data, 188, NULL, 0, + &dvbdmxfeed->feed.ts, NULL); + return 0; +} + +int av7110_av_start_record(struct av7110 *av7110, int av, + struct dvb_demux_feed *dvbdmxfeed) +{ + int ret = 0; + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + + dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); + + if (av7110->playing || (av7110->rec_mode & av)) + return -EBUSY; + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + dvbdmx->recording = 1; + av7110->rec_mode |= av; + + switch (av7110->rec_mode) { + case RP_AUDIO: + dvb_filter_pes2ts_init(&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[0]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + break; + + case RP_VIDEO: + dvb_filter_pes2ts_init(&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[1]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + break; + + case RP_AV: + dvb_filter_pes2ts_init(&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[0]); + dvb_filter_pes2ts_init(&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *) dvbdmx->pesfilter[1]); + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); + break; + } + return ret; +} + +int av7110_av_start_play(struct av7110 *av7110, int av) +{ + int ret = 0; + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->rec_mode) + return -EBUSY; + if (av7110->playing & av) + return -EBUSY; + + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + + if (av7110->playing == RP_NONE) { + av7110_ipack_reset(&av7110->ipack[0]); + av7110_ipack_reset(&av7110->ipack[1]); + } + + av7110->playing |= av; + switch (av7110->playing) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + av7110->sinfo = 0; + break; + case RP_AV: + av7110->sinfo = 0; + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); + break; + } + return ret; +} + +int av7110_av_stop(struct av7110 *av7110, int av) +{ + int ret = 0; + dprintk(2, "av7110:%p, \n", av7110); + + if (!(av7110->playing & av) && !(av7110->rec_mode & av)) + return 0; + av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (av7110->playing) { + av7110->playing &= ~av; + switch (av7110->playing) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); + break; + case RP_NONE: + ret = av7110_set_vidmode(av7110, av7110->vidmode); + break; + } + } else { + av7110->rec_mode &= ~av; + switch (av7110->rec_mode) { + case RP_AUDIO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); + break; + case RP_VIDEO: + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); + break; + case RP_NONE: + break; + } + } + return ret; +} + + +int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) +{ + int len; + u32 sync; + u16 blen; + + if (!dlen) { + wake_up(&buf->queue); + return -1; + } + while (1) { + len = dvb_ringbuffer_avail(buf); + if (len < 6) { + wake_up(&buf->queue); + return -1; + } + sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24; + sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16; + sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8; + sync |= DVB_RINGBUFFER_PEEK(buf, 3); + + if (((sync &~ 0x0f) == 0x000001e0) || + ((sync &~ 0x1f) == 0x000001c0) || + (sync == 0x000001bd)) + break; + printk("resync\n"); + DVB_RINGBUFFER_SKIP(buf, 1); + } + blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8; + blen |= DVB_RINGBUFFER_PEEK(buf, 5); + blen += 6; + if (len < blen || blen > dlen) { + //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen); + wake_up(&buf->queue); + return -1; + } + + dvb_ringbuffer_read(buf, dest, (size_t) blen); + + dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n", + (unsigned long) buf->pread, (unsigned long) buf->pwrite); + wake_up(&buf->queue); + return blen; +} + + +int av7110_set_volume(struct av7110 *av7110, unsigned int volleft, + unsigned int volright) +{ + unsigned int vol, val, balance = 0; + int err; + + dprintk(2, "av7110:%p, \n", av7110); + + av7110->mixer.volume_left = volleft; + av7110->mixer.volume_right = volright; + + switch (av7110->adac_type) { + case DVB_ADAC_TI: + volleft = (volleft * 256) / 1036; + volright = (volright * 256) / 1036; + if (volleft > 0x3f) + volleft = 0x3f; + if (volright > 0x3f) + volright = 0x3f; + if ((err = SendDAC(av7110, 3, 0x80 + volleft))) + return err; + return SendDAC(av7110, 4, volright); + + case DVB_ADAC_CRYSTAL: + volleft = 127 - volleft / 2; + volright = 127 - volright / 2; + i2c_writereg(av7110, 0x20, 0x03, volleft); + i2c_writereg(av7110, 0x20, 0x04, volright); + return 0; + + case DVB_ADAC_MSP34x0: + vol = (volleft > volright) ? volleft : volright; + val = (vol * 0x73 / 255) << 8; + if (vol > 0) + balance = ((volright - volleft) * 127) / vol; + msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ + msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ + return 0; + + case DVB_ADAC_MSP34x5: + vol = (volleft > volright) ? volleft : volright; + val = (vol * 0x73 / 255) << 8; + if (vol > 0) + balance = ((volright - volleft) * 127) / vol; + msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ + return 0; + } + + return 0; +} + +int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) +{ + int ret; + dprintk(2, "av7110:%p, \n", av7110); + + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); + + if (!ret && !av7110->playing) { + ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], + av7110->pids[DMX_PES_AUDIO], + av7110->pids[DMX_PES_TELETEXT], + 0, av7110->pids[DMX_PES_PCR]); + if (!ret) + ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + } + return ret; +} + + +static enum av7110_video_mode sw2mode[16] = { + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, +}; + +static int get_video_format(struct av7110 *av7110, u8 *buf, int count) +{ + int i; + int hsize, vsize; + int sw; + u8 *p; + int ret = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->sinfo) + return 0; + for (i = 7; i < count - 10; i++) { + p = buf + i; + if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) + continue; + p += 4; + hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); + vsize = ((p[1] &0x0F) << 8) | (p[2]); + sw = (p[3] & 0x0F); + ret = av7110_set_vidmode(av7110, sw2mode[sw]); + if (!ret) { + dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); + av7110->sinfo = 1; + } + break; + } + return ret; +} + + +/**************************************************************************** + * I/O buffer management and control + ****************************************************************************/ + +static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, + const u8 *buf, unsigned long count) +{ + unsigned long todo = count; + int free; + + while (todo > 0) { + if (dvb_ringbuffer_free(rbuf) < 2048) { + if (wait_event_interruptible(rbuf->queue, + (dvb_ringbuffer_free(rbuf) >= 2048))) + return count - todo; + } + free = dvb_ringbuffer_free(rbuf); + if (free > todo) + free = todo; + dvb_ringbuffer_write(rbuf, buf, free); + todo -= free; + buf += free; + } + + return count - todo; +} + +static void play_video_cb(u8 *buf, int count, void *priv) +{ + struct av7110 *av7110 = (struct av7110 *) priv; + dprintk(2, "av7110:%p, \n", av7110); + + if ((buf[3] & 0xe0) == 0xe0) { + get_video_format(av7110, buf, count); + aux_ring_buffer_write(&av7110->avout, buf, count); + } else + aux_ring_buffer_write(&av7110->aout, buf, count); +} + +static void play_audio_cb(u8 *buf, int count, void *priv) +{ + struct av7110 *av7110 = (struct av7110 *) priv; + dprintk(2, "av7110:%p, \n", av7110); + + aux_ring_buffer_write(&av7110->aout, buf, count); +} + + +#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096) + +static ssize_t ts_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + struct dvb_ringbuffer *rb; + u8 *kb; + unsigned long todo = count; + + dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count); + + rb = (type) ? &av7110->avout : &av7110->aout; + kb = av7110->kbuf[type]; + + if (!kb) + return -ENOBUFS; + + if (nonblock && !FREE_COND_TS) + return -EWOULDBLOCK; + + while (todo >= TS_SIZE) { + if (!FREE_COND_TS) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(rb->queue, FREE_COND_TS)) + return count - todo; + } + if (copy_from_user(kb, buf, TS_SIZE)) + return -EFAULT; + write_ts_to_decoder(av7110, type, kb, TS_SIZE); + todo -= TS_SIZE; + buf += TS_SIZE; + } + + return count - todo; +} + + +#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ + dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) + +static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + + if (nonblock && !FREE_COND) + return -EWOULDBLOCK; + + while (todo > 0) { + if (!FREE_COND) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->avout.queue, + FREE_COND)) + return count - todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + if (copy_from_user(av7110->kbuf[type], buf, n)) + return -EFAULT; + av7110_ipack_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + + if (nonblock && !FREE_COND) + return -EWOULDBLOCK; + + while (todo > 0) { + if (!FREE_COND) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->avout.queue, + FREE_COND)) + return count - todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf, + unsigned long count, int nonblock, int type) +{ + unsigned long todo = count, n; + dprintk(2, "av7110:%p, \n", av7110); + + if (!av7110->kbuf[type]) + return -ENOBUFS; + if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) + return -EWOULDBLOCK; + + while (todo > 0) { + if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) { + if (nonblock) + return count - todo; + if (wait_event_interruptible(av7110->aout.queue, + (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024))) + return count-todo; + } + n = todo; + if (n > IPACKS * 2) + n = IPACKS * 2; + if (copy_from_user(av7110->kbuf[type], buf, n)) + return -EFAULT; + av7110_ipack_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + todo -= n; + buf += n; + } + return count - todo; +} + +void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed) +{ + memset(p->pes, 0, TS_SIZE); + p->counter = 0; + p->pos = 0; + p->frags = 0; + if (feed) + p->feed = feed; +} + +static void clear_p2t(struct av7110_p2t *p) +{ + memset(p->pes, 0, TS_SIZE); +// p->counter = 0; + p->pos = 0; + p->frags = 0; +} + + +static int find_pes_header(u8 const *buf, long int length, int *frags) +{ + int c = 0; + int found = 0; + + *frags = 0; + + while (c < length - 3 && !found) { + if (buf[c] == 0x00 && buf[c + 1] == 0x00 && + buf[c + 2] == 0x01) { + switch ( buf[c + 3] ) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + found = 1; + break; + + default: + c++; + break; + } + } else + c++; + } + if (c == length - 3 && !found) { + if (buf[length - 1] == 0x00) + *frags = 1; + if (buf[length - 2] == 0x00 && + buf[length - 1] == 0x00) + *frags = 2; + if (buf[length - 3] == 0x00 && + buf[length - 2] == 0x00 && + buf[length - 1] == 0x01) + *frags = 3; + return -1; + } + + return c; +} + +void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p) +{ + int c, c2, l, add; + int check, rest; + + c = 0; + c2 = 0; + if (p->frags){ + check = 0; + switch(p->frags) { + case 1: + if (buf[c] == 0x00 && buf[c + 1] == 0x01) { + check = 1; + c += 2; + } + break; + case 2: + if (buf[c] == 0x01) { + check = 1; + c++; + } + break; + case 3: + check = 1; + } + if (check) { + switch (buf[c]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + p->pes[0] = 0x00; + p->pes[1] = 0x00; + p->pes[2] = 0x01; + p->pes[3] = buf[c]; + p->pos = 4; + memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos); + c += (TS_SIZE - 4) - p->pos; + p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed); + clear_p2t(p); + break; + + default: + c = 0; + break; + } + } + p->frags = 0; + } + + if (p->pos) { + c2 = find_pes_header(buf + c, length - c, &p->frags); + if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos) + l = c2+c; + else + l = (TS_SIZE - 4) - p->pos; + memcpy(p->pes + p->pos, buf, l); + c += l; + p->pos += l; + p_to_t(p->pes, p->pos, pid, &p->counter, p->feed); + clear_p2t(p); + } + + add = 0; + while (c < length) { + c2 = find_pes_header(buf + c + add, length - c - add, &p->frags); + if (c2 >= 0) { + c2 += c + add; + if (c2 > c){ + p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed); + c = c2; + clear_p2t(p); + add = 0; + } else + add = 1; + } else { + l = length - c; + rest = l % (TS_SIZE - 4); + l -= rest; + p_to_t(buf + c, l, pid, &p->counter, p->feed); + memcpy(p->pes, buf + c + l, rest); + p->pos = rest; + c = length; + } + } +} + + +static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) +{ + int i; + int c = 0; + int fill; + u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 }; + + fill = (TS_SIZE - 4) - length; + if (pes_start) + tshead[1] = 0x40; + if (fill) + tshead[3] = 0x30; + tshead[1] |= (u8)((pid & 0x1F00) >> 8); + tshead[2] |= (u8)(pid & 0x00FF); + tshead[3] |= ((*counter)++ & 0x0F); + memcpy(buf, tshead, 4); + c += 4; + + if (fill) { + buf[4] = fill - 1; + c++; + if (fill > 1) { + buf[5] = 0x00; + c++; + } + for (i = 6; i < fill + 4; i++) { + buf[i] = 0xFF; + c++; + } + } + + return c; +} + + +static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, + struct dvb_demux_feed *feed) +{ + int l, pes_start; + u8 obuf[TS_SIZE]; + long c = 0; + + pes_start = 0; + if (length > 3 && + buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) + switch (buf[3]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + pes_start = 1; + break; + + default: + break; + } + + while (c < length) { + memset(obuf, 0, TS_SIZE); + if (length - c >= (TS_SIZE - 4)){ + l = write_ts_header2(pid, counter, pes_start, + obuf, (TS_SIZE - 4)); + memcpy(obuf + l, buf + c, TS_SIZE - l); + c += TS_SIZE - l; + } else { + l = write_ts_header2(pid, counter, pes_start, + obuf, length - c); + memcpy(obuf + l, buf + c, TS_SIZE - l); + c = length; + } + feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, NULL); + pes_start = 0; + } +} + + +static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len) +{ + struct ipack *ipack = &av7110->ipack[type]; + + if (buf[1] & TRANS_ERROR) { + av7110_ipack_reset(ipack); + return -1; + } + + if (!(buf[3] & PAYLOAD)) + return -1; + + if (buf[1] & PAY_START) + av7110_ipack_flush(ipack); + + if (buf[3] & ADAPT_FIELD) { + len -= buf[4] + 1; + buf += buf[4] + 1; + if (!len) + return 0; + } + + av7110_ipack_instant_repack(buf + 4, len - 4, ipack); + return 0; +} + + +int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *av7110 = (struct av7110 *) demux->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) + return 0; + + switch (feed->pes_type) { + case 0: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + return -EINVAL; + break; + case 1: + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) + return -EINVAL; + break; + default: + return -1; + } + + return write_ts_to_decoder(av7110, feed->pes_type, buf, len); +} + + + +/****************************************************************************** + * Video MPEG decoder events + ******************************************************************************/ +void dvb_video_add_event(struct av7110 *av7110, struct video_event *event) +{ + struct dvb_video_events *events = &av7110->video_events; + int wp; + + spin_lock_bh(&events->lock); + + wp = (events->eventw + 1) % MAX_VIDEO_EVENT; + if (wp == events->eventr) { + events->overflow = 1; + events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; + } + + //FIXME: timestamp? + memcpy(&events->events[events->eventw], event, sizeof(struct video_event)); + events->eventw = wp; + + spin_unlock_bh(&events->lock); + + wake_up_interruptible(&events->wait_queue); +} + + +static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags) +{ + struct dvb_video_events *events = &av7110->video_events; + + if (events->overflow) { + events->overflow = 0; + return -EOVERFLOW; + } + if (events->eventw == events->eventr) { + int ret; + + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + + ret = wait_event_interruptible(events->wait_queue, + events->eventw != events->eventr); + if (ret < 0) + return ret; + } + + spin_lock_bh(&events->lock); + + memcpy(event, &events->events[events->eventr], + sizeof(struct video_event)); + events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; + + spin_unlock_bh(&events->lock); + + return 0; +} + +/****************************************************************************** + * DVB device file operations + ******************************************************************************/ + +static __poll_t dvb_video_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + __poll_t mask = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) + poll_wait(file, &av7110->avout.queue, wait); + + poll_wait(file, &av7110->video_events.wait_queue, wait); + + if (av7110->video_events.eventw != av7110->video_events.eventr) + mask = EPOLLPRI; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (av7110->playing) { + if (FREE_COND) + mask |= (EPOLLOUT | EPOLLWRNORM); + } else { + /* if not playing: may play if asked for */ + mask |= (EPOLLOUT | EPOLLWRNORM); + } + } + + return mask; +} + +static ssize_t dvb_video_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned char c; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return -EPERM; + + if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) + return -EPERM; + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); + else + return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); +} + +static __poll_t dvb_audio_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + __poll_t mask = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + poll_wait(file, &av7110->aout.queue, wait); + + if (av7110->playing) { + if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) + mask |= (EPOLLOUT | EPOLLWRNORM); + } else /* if not playing: may play if asked for */ + mask = (EPOLLOUT | EPOLLWRNORM); + + return mask; +} + +static ssize_t dvb_audio_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned char c; + + dprintk(2, "av7110:%p, \n", av7110); + + if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) { + printk(KERN_ERR "not audio source memory\n"); + return -EPERM; + } + + if (get_user(c, buf)) + return -EFAULT; + if (c == 0x47 && count % TS_SIZE == 0) + return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); + else + return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); +} + +static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; + +#define MIN_IFRAME 400000 + +static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock) +{ + unsigned i, n; + int progressive = 0; + int match = 0; + + dprintk(2, "av7110:%p, \n", av7110); + + if (len == 0) + return 0; + + if (!(av7110->playing & RP_VIDEO)) { + if (av7110_av_start_play(av7110, RP_VIDEO) < 0) + return -EBUSY; + } + + /* search in buf for instances of 00 00 01 b5 1? */ + for (i = 0; i < len; i++) { + unsigned char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (match == 5) { + progressive = c & 0x08; + match = 0; + } + if (c == 0x00) { + match = (match == 1 || match == 2) ? 2 : 1; + continue; + } + switch (match++) { + case 2: if (c == 0x01) + continue; + break; + case 3: if (c == 0xb5) + continue; + break; + case 4: if ((c & 0xf0) == 0x10) + continue; + break; + } + match = 0; + } + + /* setting n always > 1, fixes problems when playing stillframes + consisting of I- and P-Frames */ + n = MIN_IFRAME / len + 1; + + /* FIXME: nonblock? */ + dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1); + + for (i = 0; i < n; i++) + dvb_play(av7110, buf, len, 0, 1); + + av7110_ipack_flush(&av7110->ipack[1]); + + if (progressive) + return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + else + return 0; +} + +#ifdef CONFIG_COMPAT +struct compat_video_still_picture { + compat_uptr_t iFrame; + int32_t size; +}; +#define VIDEO_STILLPICTURE32 _IOW('o', 30, struct compat_video_still_picture) + +struct compat_video_event { + __s32 type; + /* unused, make sure to use atomic time for y2038 if it ever gets used */ + compat_long_t timestamp; + union { + video_size_t size; + unsigned int frame_rate; /* in frames per 1000sec */ + unsigned char vsync_field; /* unknown/odd/even/progressive */ + } u; +}; +#define VIDEO_GET_EVENT32 _IOR('o', 28, struct compat_video_event) + +static int dvb_compat_video_get_event(struct av7110 *av7110, + struct compat_video_event *event, int flags) +{ + struct video_event ev; + int ret; + + ret = dvb_video_get_event(av7110, &ev, flags); + + *event = (struct compat_video_event) { + .type = ev.type, + .timestamp = ev.timestamp, + .u.size = ev.u.size, + }; + + return ret; +} +#endif + +static int dvb_video_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + int ret = 0; + + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && + cmd != VIDEO_GET_SIZE ) { + return -EPERM; + } + } + + if (mutex_lock_interruptible(&av7110->ioctl_mutex)) + return -ERESTARTSYS; + + switch (cmd) { + case VIDEO_STOP: + av7110->videostate.play_state = VIDEO_STOPPED; + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) + ret = av7110_av_stop(av7110, RP_VIDEO); + else + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, + av7110->videostate.video_blank ? 0 : 1); + if (!ret) + av7110->trickmode = TRICK_NONE; + break; + + case VIDEO_PLAY: + av7110->trickmode = TRICK_NONE; + if (av7110->videostate.play_state == VIDEO_FREEZED) { + av7110->videostate.play_state = VIDEO_PLAYING; + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (ret) + break; + } + if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { + if (av7110->playing == RP_AV) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); + if (ret) + break; + av7110->playing &= ~RP_VIDEO; + } + ret = av7110_av_start_play(av7110, RP_VIDEO); + } + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) + av7110->videostate.play_state = VIDEO_PLAYING; + break; + + case VIDEO_FREEZE: + av7110->videostate.play_state = VIDEO_FREEZED; + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); + else + ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + if (!ret) + av7110->trickmode = TRICK_FREEZE; + break; + + case VIDEO_CONTINUE: + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) { + av7110->videostate.play_state = VIDEO_PLAYING; + av7110->trickmode = TRICK_NONE; + } + break; + + case VIDEO_SELECT_SOURCE: + av7110->videostate.stream_source = (video_stream_source_t) arg; + break; + + case VIDEO_SET_BLANK: + av7110->videostate.video_blank = (int) arg; + break; + + case VIDEO_GET_STATUS: + memcpy(parg, &av7110->videostate, sizeof(struct video_status)); + break; + +#ifdef CONFIG_COMPAT + case VIDEO_GET_EVENT32: + ret = dvb_compat_video_get_event(av7110, parg, file->f_flags); + break; +#endif + + case VIDEO_GET_EVENT: + ret = dvb_video_get_event(av7110, parg, file->f_flags); + break; + + case VIDEO_GET_SIZE: + memcpy(parg, &av7110->video_size, sizeof(video_size_t)); + break; + + case VIDEO_SET_DISPLAY_FORMAT: + { + video_displayformat_t format = (video_displayformat_t) arg; + switch (format) { + case VIDEO_PAN_SCAN: + av7110->display_panscan = VID_PAN_SCAN_PREF; + break; + case VIDEO_LETTER_BOX: + av7110->display_panscan = VID_VC_AND_PS_PREF; + break; + case VIDEO_CENTER_CUT_OUT: + av7110->display_panscan = VID_CENTRE_CUT_PREF; + break; + default: + ret = -EINVAL; + } + if (ret < 0) + break; + av7110->videostate.display_format = format; + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, + 1, av7110->display_panscan); + break; + } + + case VIDEO_SET_FORMAT: + if (arg > 1) { + ret = -EINVAL; + break; + } + av7110->display_ar = arg; + ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, + 1, (u16) arg); + break; + +#ifdef CONFIG_COMPAT + case VIDEO_STILLPICTURE32: + { + struct compat_video_still_picture *pic = + (struct compat_video_still_picture *) parg; + av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY; + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + ret = play_iframe(av7110, compat_ptr(pic->iFrame), + pic->size, file->f_flags & O_NONBLOCK); + break; + } +#endif + + case VIDEO_STILLPICTURE: + { + struct video_still_picture *pic = + (struct video_still_picture *) parg; + av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY; + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + ret = play_iframe(av7110, pic->iFrame, pic->size, + file->f_flags & O_NONBLOCK); + break; + } + + case VIDEO_FAST_FORWARD: + //note: arg is ignored by firmware + if (av7110->playing & RP_VIDEO) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Scan_I, 2, AV_PES, 0); + else + ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg); + if (!ret) { + av7110->trickmode = TRICK_FAST; + av7110->videostate.play_state = VIDEO_PLAYING; + } + break; + + case VIDEO_SLOWMOTION: + if (av7110->playing&RP_VIDEO) { + if (av7110->trickmode != TRICK_SLOW) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } else { + ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } + if (!ret) { + av7110->trickmode = TRICK_SLOW; + av7110->videostate.play_state = VIDEO_PLAYING; + } + break; + + case VIDEO_GET_CAPABILITIES: + *(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 | + VIDEO_CAP_SYS | VIDEO_CAP_PROG; + break; + + case VIDEO_CLEAR_BUFFER: + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + av7110_ipack_reset(&av7110->ipack[1]); + if (av7110->playing == RP_AV) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Play, 2, AV_PES, 0); + if (ret) + break; + if (av7110->trickmode == TRICK_FAST) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Scan_I, 2, AV_PES, 0); + if (av7110->trickmode == TRICK_SLOW) { + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Slow, 2, 0, 0); + if (!ret) + ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg); + } + if (av7110->trickmode == TRICK_FREEZE) + ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1); + } + break; + + case VIDEO_SET_STREAMTYPE: + break; + + default: + ret = -ENOIOCTLCMD; + break; + } + + mutex_unlock(&av7110->ioctl_mutex); + return ret; +} + +static int dvb_audio_ioctl(struct file *file, + unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + int ret = 0; + + dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd); + + if (((file->f_flags & O_ACCMODE) == O_RDONLY) && + (cmd != AUDIO_GET_STATUS)) + return -EPERM; + + if (mutex_lock_interruptible(&av7110->ioctl_mutex)) + return -ERESTARTSYS; + + switch (cmd) { + case AUDIO_STOP: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + ret = av7110_av_stop(av7110, RP_AUDIO); + else + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_STOPPED; + break; + + case AUDIO_PLAY: + if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) + ret = av7110_av_start_play(av7110, RP_AUDIO); + if (!ret) + ret = audcom(av7110, AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PLAYING; + break; + + case AUDIO_PAUSE: + ret = audcom(av7110, AUDIO_CMD_MUTE); + if (!ret) + av7110->audiostate.play_state = AUDIO_PAUSED; + break; + + case AUDIO_CONTINUE: + if (av7110->audiostate.play_state == AUDIO_PAUSED) { + av7110->audiostate.play_state = AUDIO_PLAYING; + ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16); + } + break; + + case AUDIO_SELECT_SOURCE: + av7110->audiostate.stream_source = (audio_stream_source_t) arg; + break; + + case AUDIO_SET_MUTE: + { + ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); + if (!ret) + av7110->audiostate.mute_state = (int) arg; + break; + } + + case AUDIO_SET_AV_SYNC: + av7110->audiostate.AV_sync_state = (int) arg; + ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); + break; + + case AUDIO_SET_BYPASS_MODE: + if (FW_VERSION(av7110->arm_app) < 0x2621) + ret = -EINVAL; + av7110->audiostate.bypass_mode = (int)arg; + break; + + case AUDIO_CHANNEL_SELECT: + av7110->audiostate.channel_select = (audio_channel_select_t) arg; + switch(av7110->audiostate.channel_select) { + case AUDIO_STEREO: + ret = audcom(av7110, AUDIO_CMD_STEREO); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x49); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); + } + break; + case AUDIO_MONO_LEFT: + ret = audcom(av7110, AUDIO_CMD_MONO_L); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x4a); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); + } + break; + case AUDIO_MONO_RIGHT: + ret = audcom(av7110, AUDIO_CMD_MONO_R); + if (!ret) { + if (av7110->adac_type == DVB_ADAC_CRYSTAL) + i2c_writereg(av7110, 0x20, 0x02, 0x45); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); + } + break; + default: + ret = -EINVAL; + break; + } + break; + + case AUDIO_GET_STATUS: + memcpy(parg, &av7110->audiostate, sizeof(struct audio_status)); + break; + + case AUDIO_GET_CAPABILITIES: + if (FW_VERSION(av7110->arm_app) < 0x2621) + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + else + *(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 | + AUDIO_CAP_MP1 | AUDIO_CAP_MP2; + break; + + case AUDIO_CLEAR_BUFFER: + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + av7110_ipack_reset(&av7110->ipack[0]); + if (av7110->playing == RP_AV) + ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, + __Play, 2, AV_PES, 0); + break; + + case AUDIO_SET_ID: + break; + + case AUDIO_SET_MIXER: + { + struct audio_mixer *amix = (struct audio_mixer *)parg; + ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right); + break; + } + + case AUDIO_SET_STREAMTYPE: + break; + + default: + ret = -ENOIOCTLCMD; + } + + mutex_unlock(&av7110->ioctl_mutex); + return ret; +} + + +static int dvb_video_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((err = dvb_generic_open(inode, file)) < 0) + return err; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + av7110->video_blank = 1; + av7110->audiostate.AV_sync_state = 1; + av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; + + /* empty event queue */ + av7110->video_events.eventr = av7110->video_events.eventw = 0; + } + + return 0; +} + +static int dvb_video_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + av7110_av_stop(av7110, RP_VIDEO); + } + + return dvb_generic_release(inode, file); +} + +static int dvb_audio_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err = dvb_generic_open(inode, file); + + dprintk(2, "av7110:%p, \n", av7110); + + if (err < 0) + return err; + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; + return 0; +} + +static int dvb_audio_release(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(2, "av7110:%p, \n", av7110); + + av7110_av_stop(av7110, RP_AUDIO); + return dvb_generic_release(inode, file); +} + + + +/****************************************************************************** + * driver registration + ******************************************************************************/ + +static const struct file_operations dvb_video_fops = { + .owner = THIS_MODULE, + .write = dvb_video_write, + .unlocked_ioctl = dvb_generic_ioctl, + .compat_ioctl = dvb_generic_ioctl, + .open = dvb_video_open, + .release = dvb_video_release, + .poll = dvb_video_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_video = { + .priv = NULL, + .users = 6, + .readers = 5, /* arbitrary */ + .writers = 1, + .fops = &dvb_video_fops, + .kernel_ioctl = dvb_video_ioctl, +}; + +static const struct file_operations dvb_audio_fops = { + .owner = THIS_MODULE, + .write = dvb_audio_write, + .unlocked_ioctl = dvb_generic_ioctl, + .compat_ioctl = dvb_generic_ioctl, + .open = dvb_audio_open, + .release = dvb_audio_release, + .poll = dvb_audio_poll, + .llseek = noop_llseek, +}; + +static struct dvb_device dvbdev_audio = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_audio_fops, + .kernel_ioctl = dvb_audio_ioctl, +}; + + +int av7110_av_register(struct av7110 *av7110) +{ + av7110->audiostate.AV_sync_state = 0; + av7110->audiostate.mute_state = 0; + av7110->audiostate.play_state = AUDIO_STOPPED; + av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; + av7110->audiostate.channel_select = AUDIO_STEREO; + av7110->audiostate.bypass_mode = 0; + + av7110->videostate.video_blank = 0; + av7110->videostate.play_state = VIDEO_STOPPED; + av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; + av7110->videostate.video_format = VIDEO_FORMAT_4_3; + av7110->videostate.display_format = VIDEO_LETTER_BOX; + av7110->display_ar = VIDEO_FORMAT_4_3; + av7110->display_panscan = VID_VC_AND_PS_PREF; + + init_waitqueue_head(&av7110->video_events.wait_queue); + spin_lock_init(&av7110->video_events.lock); + av7110->video_events.eventw = av7110->video_events.eventr = 0; + av7110->video_events.overflow = 0; + memset(&av7110->video_size, 0, sizeof (video_size_t)); + + dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev, + &dvbdev_video, av7110, DVB_DEVICE_VIDEO, 0); + + dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev, + &dvbdev_audio, av7110, DVB_DEVICE_AUDIO, 0); + + return 0; +} + +void av7110_av_unregister(struct av7110 *av7110) +{ + dvb_unregister_device(av7110->audio_dev); + dvb_unregister_device(av7110->video_dev); +} + +int av7110_av_init(struct av7110 *av7110) +{ + void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; + int i, ret; + + for (i = 0; i < 2; i++) { + struct ipack *ipack = av7110->ipack + i; + + ret = av7110_ipack_init(ipack, IPACKS, play[i]); + if (ret < 0) { + if (i) + av7110_ipack_free(--ipack); + goto out; + } + ipack->data = av7110; + } + + dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN); + dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN); + + av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN); + av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS; +out: + return ret; +} + +void av7110_av_exit(struct av7110 *av7110) +{ + av7110_ipack_free(&av7110->ipack[0]); + av7110_ipack_free(&av7110->ipack[1]); +} diff --git a/drivers/staging/media/av7110/av7110_av.h b/drivers/staging/media/av7110/av7110_av.h new file mode 100644 index 000000000000..71bbd4391f57 --- /dev/null +++ b/drivers/staging/media/av7110/av7110_av.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _AV7110_AV_H_ +#define _AV7110_AV_H_ + +struct av7110; + +extern int av7110_set_vidmode(struct av7110 *av7110, + enum av7110_video_mode mode); + +extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); +extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); +extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); + +extern int av7110_set_volume(struct av7110 *av7110, unsigned int volleft, + unsigned int volright); +extern int av7110_av_stop(struct av7110 *av7110, int av); +extern int av7110_av_start_record(struct av7110 *av7110, int av, + struct dvb_demux_feed *dvbdmxfeed); +extern int av7110_av_start_play(struct av7110 *av7110, int av); + +extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event); + +extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed); +extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p); + +extern int av7110_av_register(struct av7110 *av7110); +extern void av7110_av_unregister(struct av7110 *av7110); +extern int av7110_av_init(struct av7110 *av7110); +extern void av7110_av_exit(struct av7110 *av7110); + + +#endif /* _AV7110_AV_H_ */ diff --git a/drivers/staging/media/av7110/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c new file mode 100644 index 000000000000..c1338e074a3d --- /dev/null +++ b/drivers/staging/media/av7110/av7110_ca.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * av7110_ca.c: CA and CI stuff + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> + * + * the project's page is at https://linuxtv.org + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/timer.h> +#include <linux/poll.h> +#include <linux/gfp.h> + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_ca.h" + + +void CI_handle(struct av7110 *av7110, u8 *data, u16 len) +{ + dprintk(8, "av7110:%p\n",av7110); + + if (len < 3) + return; + switch (data[0]) { + case CI_MSG_CI_INFO: + if (data[2] != 1 && data[2] != 2) + break; + switch (data[1]) { + case 0: + av7110->ci_slot[data[2] - 1].flags = 0; + break; + case 1: + av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT; + break; + case 2: + av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY; + break; + } + break; + case CI_SWITCH_PRG_REPLY: + //av7110->ci_stat=data[1]; + break; + default: + break; + } +} + + +void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len) +{ + if (dvb_ringbuffer_free(cibuf) < len + 2) + return; + + DVB_RINGBUFFER_WRITE_BYTE(cibuf, len >> 8); + DVB_RINGBUFFER_WRITE_BYTE(cibuf, len & 0xff); + dvb_ringbuffer_write(cibuf, data, len); + wake_up_interruptible(&cibuf->queue); +} + + +/****************************************************************************** + * CI link layer file ops + ******************************************************************************/ + +static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size) +{ + struct dvb_ringbuffer *tab[] = { cirbuf, ciwbuf, NULL }, **p; + void *data; + + for (p = tab; *p; p++) { + data = vmalloc(size); + if (!data) { + while (p-- != tab) { + vfree(p[0]->data); + p[0]->data = NULL; + } + return -ENOMEM; + } + dvb_ringbuffer_init(*p, data, size); + } + return 0; +} + +static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +{ + dvb_ringbuffer_flush_spinlock_wakeup(cirbuf); + dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf); +} + +static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +{ + vfree(cirbuf->data); + cirbuf->data = NULL; + vfree(ciwbuf->data); + ciwbuf->data = NULL; +} + +static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, + int slots, struct ca_slot_info *slot) +{ + int i; + int len = 0; + u8 msg[8] = { 0x00, 0x06, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00 }; + + for (i = 0; i < 2; i++) { + if (slots & (1 << i)) + len += 8; + } + + if (dvb_ringbuffer_free(cibuf) < len) + return -EBUSY; + + for (i = 0; i < 2; i++) { + if (slots & (1 << i)) { + msg[2] = i; + dvb_ringbuffer_write(cibuf, msg, 8); + slot[i].flags = 0; + } + } + + return 0; +} + +static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + int free; + int non_blocking = file->f_flags & O_NONBLOCK; + u8 *page = (u8 *)__get_free_page(GFP_USER); + int res; + + if (!page) + return -ENOMEM; + + res = -EINVAL; + if (count > 2048) + goto out; + + res = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + free = dvb_ringbuffer_free(cibuf); + if (count + 2 > free) { + res = -EWOULDBLOCK; + if (non_blocking) + goto out; + res = -ERESTARTSYS; + if (wait_event_interruptible(cibuf->queue, + (dvb_ringbuffer_free(cibuf) >= count + 2))) + goto out; + } + + DVB_RINGBUFFER_WRITE_BYTE(cibuf, count >> 8); + DVB_RINGBUFFER_WRITE_BYTE(cibuf, count & 0xff); + + res = dvb_ringbuffer_write(cibuf, page, count); +out: + free_page((unsigned long)page); + return res; +} + +static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + int avail; + int non_blocking = file->f_flags & O_NONBLOCK; + ssize_t len; + + if (!cibuf->data || !count) + return 0; + if (non_blocking && (dvb_ringbuffer_empty(cibuf))) + return -EWOULDBLOCK; + if (wait_event_interruptible(cibuf->queue, + !dvb_ringbuffer_empty(cibuf))) + return -ERESTARTSYS; + avail = dvb_ringbuffer_avail(cibuf); + if (avail < 4) + return 0; + len = DVB_RINGBUFFER_PEEK(cibuf, 0) << 8; + len |= DVB_RINGBUFFER_PEEK(cibuf, 1); + if (avail < len + 2 || count < len) + return -EINVAL; + DVB_RINGBUFFER_SKIP(cibuf, 2); + + return dvb_ringbuffer_read_user(cibuf, buf, len); +} + +static int dvb_ca_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + int err = dvb_generic_open(inode, file); + + dprintk(8, "av7110:%p\n",av7110); + + if (err < 0) + return err; + ci_ll_flush(&av7110->ci_rbuffer, &av7110->ci_wbuffer); + return 0; +} + +static __poll_t dvb_ca_poll (struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer; + struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer; + __poll_t mask = 0; + + dprintk(8, "av7110:%p\n",av7110); + + poll_wait(file, &rbuf->queue, wait); + poll_wait(file, &wbuf->queue, wait); + + if (!dvb_ringbuffer_empty(rbuf)) + mask |= (EPOLLIN | EPOLLRDNORM); + + if (dvb_ringbuffer_free(wbuf) > 1024) + mask |= (EPOLLOUT | EPOLLWRNORM); + + return mask; +} + +static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + unsigned long arg = (unsigned long) parg; + int ret = 0; + + dprintk(8, "av7110:%p\n",av7110); + + if (mutex_lock_interruptible(&av7110->ioctl_mutex)) + return -ERESTARTSYS; + + switch (cmd) { + case CA_RESET: + ret = ci_ll_reset(&av7110->ci_wbuffer, file, arg, + &av7110->ci_slot[0]); + break; + case CA_GET_CAP: + { + struct ca_caps cap; + + cap.slot_num = 2; + cap.slot_type = (FW_CI_LL_SUPPORT(av7110->arm_app) ? + CA_CI_LINK : CA_CI) | CA_DESCR; + cap.descr_num = 16; + cap.descr_type = CA_ECD; + memcpy(parg, &cap, sizeof(cap)); + break; + } + + case CA_GET_SLOT_INFO: + { + struct ca_slot_info *info=(struct ca_slot_info *)parg; + + if (info->num < 0 || info->num > 1) { + mutex_unlock(&av7110->ioctl_mutex); + return -EINVAL; + } + av7110->ci_slot[info->num].num = info->num; + av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? + CA_CI_LINK : CA_CI; + memcpy(info, &av7110->ci_slot[info->num], sizeof(struct ca_slot_info)); + break; + } + + case CA_GET_MSG: + break; + + case CA_SEND_MSG: + break; + + case CA_GET_DESCR_INFO: + { + struct ca_descr_info info; + + info.num = 16; + info.type = CA_ECD; + memcpy(parg, &info, sizeof (info)); + break; + } + + case CA_SET_DESCR: + { + struct ca_descr *descr = (struct ca_descr*) parg; + + if (descr->index >= 16 || descr->parity > 1) { + mutex_unlock(&av7110->ioctl_mutex); + return -EINVAL; + } + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5, + (descr->index<<8)|descr->parity, + (descr->cw[0]<<8)|descr->cw[1], + (descr->cw[2]<<8)|descr->cw[3], + (descr->cw[4]<<8)|descr->cw[5], + (descr->cw[6]<<8)|descr->cw[7]); + break; + } + + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&av7110->ioctl_mutex); + return ret; +} + +static ssize_t dvb_ca_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(8, "av7110:%p\n",av7110); + return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos); +} + +static ssize_t dvb_ca_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct av7110 *av7110 = dvbdev->priv; + + dprintk(8, "av7110:%p\n",av7110); + return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos); +} + +static const struct file_operations dvb_ca_fops = { + .owner = THIS_MODULE, + .read = dvb_ca_read, + .write = dvb_ca_write, + .unlocked_ioctl = dvb_generic_ioctl, + .open = dvb_ca_open, + .release = dvb_generic_release, + .poll = dvb_ca_poll, + .llseek = default_llseek, +}; + +static struct dvb_device dvbdev_ca = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_ca_fops, + .kernel_ioctl = dvb_ca_ioctl, +}; + + +int av7110_ca_register(struct av7110 *av7110) +{ + return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev, + &dvbdev_ca, av7110, DVB_DEVICE_CA, 0); +} + +void av7110_ca_unregister(struct av7110 *av7110) +{ + dvb_unregister_device(av7110->ca_dev); +} + +int av7110_ca_init(struct av7110* av7110) +{ + return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192); +} + +void av7110_ca_exit(struct av7110* av7110) +{ + ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer); +} diff --git a/drivers/staging/media/av7110/av7110_ca.h b/drivers/staging/media/av7110/av7110_ca.h new file mode 100644 index 000000000000..a6e3f2955730 --- /dev/null +++ b/drivers/staging/media/av7110/av7110_ca.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _AV7110_CA_H_ +#define _AV7110_CA_H_ + +struct av7110; + +extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len); +extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len); + +extern int av7110_ca_register(struct av7110 *av7110); +extern void av7110_ca_unregister(struct av7110 *av7110); +extern int av7110_ca_init(struct av7110* av7110); +extern void av7110_ca_exit(struct av7110* av7110); + +#endif /* _AV7110_CA_H_ */ diff --git a/drivers/staging/media/av7110/av7110_hw.c b/drivers/staging/media/av7110/av7110_hw.c new file mode 100644 index 000000000000..93ca31e38ddd --- /dev/null +++ b/drivers/staging/media/av7110/av7110_hw.c @@ -0,0 +1,1204 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * av7110_hw.c: av7110 low level hardware access and firmware interface + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> + * + * the project's page is at https://linuxtv.org + */ + +/* for debugging ARM communication: */ +//#define COM_DEBUG + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <linux/fs.h> + +#include "av7110.h" +#include "av7110_hw.h" + +#define _NOHANDSHAKE + +/* + * Max transfer size done by av7110_fw_cmd() + * + * The maximum size passed to this function is 6 bytes. The buffer also + * uses two additional ones for type and size. So, 8 bytes is enough. + */ +#define MAX_XFER_SIZE 8 + +/**************************************************************************** + * DEBI functions + ****************************************************************************/ + +/* This DEBI code is based on the Stradis driver + by Nathan Laredo <laredo@gnu.org> */ + +int av7110_debiwrite(struct av7110 *av7110, u32 config, + int addr, u32 val, unsigned int count) +{ + struct saa7146_dev *dev = av7110->dev; + + if (count > 32764) { + printk("%s: invalid count %d\n", __func__, count); + return -1; + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done failed\n", __func__); + return -1; + } + saa7146_write(dev, DEBI_CONFIG, config); + if (count <= 4) /* immediate transfer */ + saa7146_write(dev, DEBI_AD, val); + else /* block transfer */ + saa7146_write(dev, DEBI_AD, av7110->debi_bus); + saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); + saa7146_write(dev, MC2, (2 << 16) | 2); + return 0; +} + +u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int count) +{ + struct saa7146_dev *dev = av7110->dev; + u32 result = 0; + + if (count > 32764) { + printk("%s: invalid count %d\n", __func__, count); + return 0; + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #1 failed\n", __func__); + return 0; + } + saa7146_write(dev, DEBI_AD, av7110->debi_bus); + saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); + + saa7146_write(dev, DEBI_CONFIG, config); + saa7146_write(dev, MC2, (2 << 16) | 2); + if (count > 4) + return count; + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #2 failed\n", __func__); + return 0; + } + + result = saa7146_read(dev, DEBI_AD); + result &= (0xffffffffUL >> ((4 - count) * 8)); + return result; +} + + + +/* av7110 ARM core boot stuff */ +#if 0 +void av7110_reset_arm(struct av7110 *av7110) +{ + saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTLO); + + /* Disable DEBI and GPIO irq */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19 | MASK_03); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + + saa7146_setgpio(av7110->dev, RESET_LINE, SAA7146_GPIO_OUTHI); + msleep(30); /* the firmware needs some time to initialize */ + + ARM_ResetMailBox(av7110); + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + SAA7146_IER_ENABLE(av7110->dev, MASK_03); + + av7110->arm_ready = 1; + dprintk(1, "reset ARM\n"); +} +#endif /* 0 */ + +static int waitdebi(struct av7110 *av7110, int adr, int state) +{ + int k; + + dprintk(4, "%p\n", av7110); + + for (k = 0; k < 100; k++) { + if (irdebi(av7110, DEBINOSWAP, adr, 0, 2) == state) + return 0; + udelay(5); + } + return -ETIMEDOUT; +} + +static int load_dram(struct av7110 *av7110, u32 *data, int len) +{ + int i; + int blocks, rest; + u32 base, bootblock = AV7110_BOOT_BLOCK; + + dprintk(4, "%p\n", av7110); + + blocks = len / AV7110_BOOT_MAX_SIZE; + rest = len % AV7110_BOOT_MAX_SIZE; + base = DRAM_START_CODE; + + for (i = 0; i < blocks; i++) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); + return -ETIMEDOUT; + } + dprintk(4, "writing DRAM block %d\n", i); + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE); + bootblock ^= 0x1400; + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + base += AV7110_BOOT_MAX_SIZE; + } + + if (rest > 0) { + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); + return -ETIMEDOUT; + } + if (rest > 4) + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest); + else + mwdebi(av7110, DEBISWAB, bootblock, + ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4); + + iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + } + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); + return -ETIMEDOUT; + } + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); + return -ETIMEDOUT; + } + return 0; +} + + +/* we cannot write av7110 DRAM directly, so load a bootloader into + * the DPRAM which implements a simple boot protocol */ +int av7110_bootarm(struct av7110 *av7110) +{ + const struct firmware *fw; + const char *fw_name = "av7110/bootcode.bin"; + struct saa7146_dev *dev = av7110->dev; + u32 ret; + int i; + + dprintk(4, "%p\n", av7110); + + av7110->arm_ready = 0; + + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); + + /* Disable DEBI and GPIO irq */ + SAA7146_IER_DISABLE(av7110->dev, MASK_03 | MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + + /* enable DEBI */ + saa7146_write(av7110->dev, MC1, 0x08800880); + saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); + saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* test DEBI */ + iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); + /* FIXME: Why does Nexus CA require 2x iwdebi for first init? */ + iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); + + if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) { + printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", + ret, 0x10325476); + return -1; + } + for (i = 0; i < 8192; i += 4) + iwdebi(av7110, DEBISWAP, DPRAM_BASE + i, 0x00, 4); + dprintk(2, "debi test OK\n"); + + /* boot */ + dprintk(1, "load boot code\n"); + saa7146_setgpio(dev, ARM_IRQ_LINE, SAA7146_GPIO_IRQLO); + //saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT); + //saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT); + + ret = request_firmware(&fw, fw_name, &dev->pci->dev); + if (ret) { + printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n", + fw_name); + return ret; + } + + mwdebi(av7110, DEBISWAB, DPRAM_BASE, fw->data, fw->size); + release_firmware(fw); + iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); + + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out\n"); + return -ETIMEDOUT; + } + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); + mdelay(1); + + dprintk(1, "load dram code\n"); + if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): load_dram() failed\n"); + return -1; + } + + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); + mdelay(1); + + dprintk(1, "load dpram code\n"); + mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); + + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out after loading DRAM\n"); + return -ETIMEDOUT; + } + saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); + msleep(30); /* the firmware needs some time to initialize */ + + //ARM_ClearIrq(av7110); + ARM_ResetMailBox(av7110); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19 | MASK_03); + SAA7146_IER_ENABLE(av7110->dev, MASK_03); + + av7110->arm_errors = 0; + av7110->arm_ready = 1; + return 0; +} +MODULE_FIRMWARE("av7110/bootcode.bin"); + +/**************************************************************************** + * DEBI command polling + ****************************************************************************/ + +int av7110_wait_msgstate(struct av7110 *av7110, u16 flags) +{ + unsigned long start; + u32 stat; + int err; + + if (FW_VERSION(av7110->arm_app) <= 0x261c) { + /* not supported by old firmware */ + msleep(50); + return 0; + } + + /* new firmware */ + start = jiffies; + for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + mutex_unlock(&av7110->dcomlock); + if ((stat & flags) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n", + __func__, stat & flags); + return -ETIMEDOUT; + } + msleep(1); + } + return 0; +} + +static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +{ + int i; + unsigned long start; + char *type = NULL; + u16 flags[2] = {0, 0}; + u32 stat; + int err; + +// dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -ENXIO; + } + + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__); + av7110->arm_errors++; + return -ETIMEDOUT; + } + msleep(1); + } + + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); + +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + + switch ((buf[0] >> 8) & 0xff) { + case COMTYPE_PIDFILTER: + case COMTYPE_ENCODER: + case COMTYPE_REC_PLAY: + case COMTYPE_MPEGDECODER: + type = "MSG"; + flags[0] = GPMQOver; + flags[1] = GPMQFull; + break; + case COMTYPE_OSD: + type = "OSD"; + flags[0] = OSDQOver; + flags[1] = OSDQFull; + break; + case COMTYPE_MISC: + if (FW_VERSION(av7110->arm_app) >= 0x261d) { + type = "MSG"; + flags[0] = GPMQOver; + flags[1] = GPMQBusy; + } + break; + default: + break; + } + + if (type != NULL) { + /* non-immediate COMMAND type */ + start = jiffies; + for (;;) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & flags[0]) { + printk(KERN_ERR "%s: %s QUEUE overflow\n", + __func__, type); + return -1; + } + if ((stat & flags[1]) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n", + __func__, type); + av7110->arm_errors++; + return -ETIMEDOUT; + } + msleep(1); + } + } + + for (i = 2; i < length; i++) + wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2); + + if (length) + wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); + else + wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2); + + wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); + + if (FW_VERSION(av7110->arm_app) <= 0x261f) + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); + +#ifdef COM_DEBUG + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n", + __func__, (buf[0] >> 8) & 0xff); + return -ETIMEDOUT; + } + msleep(1); + } + + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & GPMQOver) { + printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__); + return -ENOSPC; + } + else if (stat & OSDQOver) { + printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__); + return -ENOSPC; + } +#endif + + return 0; +} + +static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length) +{ + int ret; + +// dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -1; + } + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + ret = __av7110_send_fw_cmd(av7110, buf, length); + mutex_unlock(&av7110->dcomlock); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", + __func__, ret); + return ret; +} + +int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...) +{ + va_list args; + u16 buf[MAX_XFER_SIZE]; + int i, ret; + +// dprintk(4, "%p\n", av7110); + + if (2 + num > ARRAY_SIZE(buf)) { + printk(KERN_WARNING + "%s: %s len=%d is too big!\n", + KBUILD_MODNAME, __func__, num); + return -EINVAL; + } + + buf[0] = ((type << 8) | com); + buf[1] = num; + + if (num) { + va_start(args, num); + for (i = 0; i < num; i++) + buf[i + 2] = va_arg(args, u32); + va_end(args); + } + + ret = av7110_send_fw_cmd(av7110, buf, num + 2); + if (ret && ret != -ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); + return ret; +} + +#if 0 +int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len) +{ + int i, ret; + u16 cmd[18] = { ((COMTYPE_COMMON_IF << 8) + subcom), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(4, "%p\n", av7110); + + for(i = 0; i < len && i < 32; i++) + { + if(i % 2 == 0) + cmd[(i / 2) + 2] = (u16)(buf[i]) << 8; + else + cmd[(i / 2) + 2] |= buf[i]; + } + + ret = av7110_send_fw_cmd(av7110, cmd, 18); + if (ret && ret != -ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); + return ret; +} +#endif /* 0 */ + +int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, + int request_buf_len, u16 *reply_buf, int reply_buf_len) +{ + int err; + s16 i; + unsigned long start; +#ifdef COM_DEBUG + u32 stat; +#endif + + dprintk(4, "%p\n", av7110); + + if (!av7110->arm_ready) { + dprintk(1, "arm not ready.\n"); + return -1; + } + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) { + mutex_unlock(&av7110->dcomlock); + printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err); + return err; + } + + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_FREE); + if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } +#ifdef _NOHANDSHAKE + msleep(1); +#endif + } + +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + +#ifdef COM_DEBUG + stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); + if (stat & GPMQOver) { + printk(KERN_ERR "%s: GPMQOver\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -1; + } + else if (stat & OSDQOver) { + printk(KERN_ERR "%s: OSDQOver\n", __func__); + mutex_unlock(&av7110->dcomlock); + return -1; + } +#endif + + for (i = 0; i < reply_buf_len; i++) + reply_buf[i] = rdebi(av7110, DEBINOSWAP, COM_BUFF + 2 * i, 0, 2); + + mutex_unlock(&av7110->dcomlock); + return 0; +} + +static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length) +{ + int ret; + ret = av7110_fw_request(av7110, &tag, 0, buf, length); + if (ret) + printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret); + return ret; +} + + +/**************************************************************************** + * Firmware commands + ****************************************************************************/ + +/* get version of the firmware ROM, RTSL, video ucode and ARM application */ +int av7110_firmversion(struct av7110 *av7110) +{ + u16 buf[20]; + u16 tag = ((COMTYPE_REQUEST << 8) + ReqVersion); + + dprintk(4, "%p\n", av7110); + + if (av7110_fw_query(av7110, tag, buf, 16)) { + printk("dvb-ttpci: failed to boot firmware @ card %d\n", + av7110->dvb_adapter.num); + return -EIO; + } + + av7110->arm_fw = (buf[0] << 16) + buf[1]; + av7110->arm_rtsl = (buf[2] << 16) + buf[3]; + av7110->arm_vid = (buf[4] << 16) + buf[5]; + av7110->arm_app = (buf[6] << 16) + buf[7]; + av7110->avtype = (buf[8] << 16) + buf[9]; + + printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n", + av7110->dvb_adapter.num, av7110->arm_fw, + av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); + + /* print firmware capabilities */ + if (FW_CI_LL_SUPPORT(av7110->arm_app)) + printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n", + av7110->dvb_adapter.num); + else + printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n", + av7110->dvb_adapter.num); + + return 0; +} + + +int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst) +{ + int i, ret; + u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(4, "%p\n", av7110); + + if (len > 10) + len = 10; + + buf[1] = len + 2; + buf[2] = len; + + if (burst != -1) + buf[3] = burst ? 0x01 : 0x00; + else + buf[3] = 0xffff; + + for (i = 0; i < len; i++) + buf[i + 4] = msg[i]; + + ret = av7110_send_fw_cmd(av7110, buf, 18); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); + return ret; +} + + +#ifdef CONFIG_DVB_AV7110_OSD + +static inline int SetColorBlend(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetCBlend, 1, windownr); +} + +static inline int SetBlend_(struct av7110 *av7110, u8 windownr, + enum av7110_osd_palette_type colordepth, u16 index, u8 blending) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4, + windownr, colordepth, index, blending); +} + +static inline int SetColor_(struct av7110 *av7110, u8 windownr, + enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5, + windownr, colordepth, index, colorhi, colorlo); +} + +static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize, + u16 colorfg, u16 colorbg) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Font, 4, + windownr, fontsize, colorfg, colorbg); +} + +static int FlushText(struct av7110 *av7110) +{ + unsigned long start; + int err; + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + start = jiffies; + while (1) { + err = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (err) { + printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } + mutex_unlock(&av7110->dcomlock); + return 0; +} + +static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf) +{ + int i, ret; + unsigned long start; + int length = strlen(buf) + 1; + u16 cbuf[5] = { (COMTYPE_OSD << 8) + DText, 3, win, x, y }; + + if (mutex_lock_interruptible(&av7110->dcomlock)) + return -ERESTARTSYS; + + start = jiffies; + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_OSD); + if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0) + break; + if (ret) { + printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#ifndef _NOHANDSHAKE + start = jiffies; + while (1) { + ret = time_after(jiffies, start + ARM_WAIT_SHAKE); + if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0) + break; + if (ret) { + printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n", + __func__); + mutex_unlock(&av7110->dcomlock); + return -ETIMEDOUT; + } + msleep(1); + } +#endif + for (i = 0; i < length / 2; i++) + wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, + swab16(*(u16 *)(buf + 2 * i)), 2); + if (length & 1) + wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2); + ret = __av7110_send_fw_cmd(av7110, cbuf, 5); + mutex_unlock(&av7110->dcomlock); + if (ret && ret!=-ERESTARTSYS) + printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); + return ret; +} + +static inline int DrawLine(struct av7110 *av7110, u8 windownr, + u16 x, u16 y, u16 dx, u16 dy, u16 color) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, DLine, 6, + windownr, x, y, dx, dy, color); +} + +static inline int DrawBlock(struct av7110 *av7110, u8 windownr, + u16 x, u16 y, u16 dx, u16 dy, u16 color) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, DBox, 6, + windownr, x, y, dx, dy, color); +} + +static inline int HideWindow(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WHide, 1, windownr); +} + +static inline int MoveWindowRel(struct av7110 *av7110, u8 windownr, u16 x, u16 y) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveD, 3, windownr, x, y); +} + +static inline int MoveWindowAbs(struct av7110 *av7110, u8 windownr, u16 x, u16 y) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WMoveA, 3, windownr, x, y); +} + +static inline int DestroyOSDWindow(struct av7110 *av7110, u8 windownr) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WDestroy, 1, windownr); +} + +static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr, + osd_raw_window_t disptype, + u16 width, u16 height) +{ + return av7110_fw_cmd(av7110, COMTYPE_OSD, WCreate, 4, + windownr, disptype, width, height); +} + + +static enum av7110_osd_palette_type bpp2pal[8] = { + Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit +}; +static osd_raw_window_t bpp2bit[8] = { + OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8 +}; + +static inline int WaitUntilBmpLoaded(struct av7110 *av7110) +{ + int ret = wait_event_timeout(av7110->bmpq, + av7110->bmp_state != BMP_LOADING, 10*HZ); + if (ret == 0) { + printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", + ret, av7110->bmp_state); + av7110->bmp_state = BMP_NONE; + return -ETIMEDOUT; + } + return 0; +} + +static inline int LoadBitmap(struct av7110 *av7110, + u16 dx, u16 dy, int inc, u8 __user * data) +{ + u16 format; + int bpp; + int i; + int d, delta; + u8 c; + int ret; + + dprintk(4, "%p\n", av7110); + + format = bpp2bit[av7110->osdbpp[av7110->osdwin]]; + + av7110->bmp_state = BMP_LOADING; + if (format == OSD_BITMAP8) { + bpp=8; delta = 1; + } else if (format == OSD_BITMAP4) { + bpp=4; delta = 2; + } else if (format == OSD_BITMAP2) { + bpp=2; delta = 4; + } else if (format == OSD_BITMAP1) { + bpp=1; delta = 8; + } else { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8; + av7110->bmpp = 0; + if (av7110->bmplen > 32768) { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + for (i = 0; i < dy; i++) { + if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) { + av7110->bmp_state = BMP_NONE; + return -EINVAL; + } + } + if (format != OSD_BITMAP8) { + for (i = 0; i < dx * dy / delta; i++) { + c = ((u8 *)av7110->bmpbuf)[1024 + i * delta + delta - 1]; + for (d = delta - 2; d >= 0; d--) { + c |= (((u8 *)av7110->bmpbuf)[1024 + i * delta + d] + << ((delta - d - 1) * bpp)); + ((u8 *)av7110->bmpbuf)[1024 + i] = c; + } + } + } + av7110->bmplen += 1024; + dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); + ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); + if (!ret) + ret = WaitUntilBmpLoaded(av7110); + return ret; +} + +static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y) +{ + dprintk(4, "%p\n", av7110); + + return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0); +} + +static inline int ReleaseBitmap(struct av7110 *av7110) +{ + dprintk(4, "%p\n", av7110); + + if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e) + return -1; + if (av7110->bmp_state == BMP_LOADING) + dprintk(1,"ReleaseBitmap called while BMP_LOADING\n"); + av7110->bmp_state = BMP_NONE; + return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0); +} + +static u32 RGB2YUV(u16 R, u16 G, u16 B) +{ + u16 y, u, v; + u16 Y, Cr, Cb; + + y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */ + u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */ + v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */ + + Y = y / 256; + Cb = u / 16; + Cr = v / 16; + + return Cr | (Cb << 16) | (Y << 8); +} + +static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend) +{ + int ret; + + u16 ch, cl; + u32 yuv; + + yuv = blend ? RGB2YUV(r,g,b) : 0; + cl = (yuv & 0xffff); + ch = ((yuv >> 16) & 0xffff); + ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ch, cl); + if (!ret) + ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]], + color, ((blend >> 4) & 0x0f)); + return ret; +} + +static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last) +{ + int i; + int length = last - first + 1; + + if (length * 4 > DATA_BUFF3_SIZE) + return -EINVAL; + + for (i = 0; i < length; i++) { + u32 color, blend, yuv; + + if (get_user(color, colors + i)) + return -EFAULT; + blend = (color & 0xF0000000) >> 4; + yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF, + (color >> 16) & 0xFF) | blend : 0; + yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16); + wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4); + } + return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4, + av7110->osdwin, + bpp2pal[av7110->osdbpp[av7110->osdwin]], + first, last); +} + +static int OSDSetBlock(struct av7110 *av7110, int x0, int y0, + int x1, int y1, int inc, u8 __user * data) +{ + uint w, h, bpp, bpl, size, lpb, bnum, brest; + int i; + int rc,release_rc; + + w = x1 - x0 + 1; + h = y1 - y0 + 1; + if (inc <= 0) + inc = w; + if (w <= 0 || w > 720 || h <= 0 || h > 576) + return -EINVAL; + bpp = av7110->osdbpp[av7110->osdwin] + 1; + bpl = ((w * bpp + 7) & ~7) / 8; + size = h * bpl; + lpb = (32 * 1024) / bpl; + bnum = size / (lpb * bpl); + brest = size - bnum * lpb * bpl; + + if (av7110->bmp_state == BMP_LOADING) { + /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */ + BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e); + rc = WaitUntilBmpLoaded(av7110); + if (rc) + return rc; + /* just continue. This should work for all fw versions + * if bnum==1 && !brest && LoadBitmap was successful + */ + } + + rc = 0; + for (i = 0; i < bnum; i++) { + rc = LoadBitmap(av7110, w, lpb, inc, data); + if (rc) + break; + rc = BlitBitmap(av7110, x0, y0 + i * lpb); + if (rc) + break; + data += lpb * inc; + } + if (!rc && brest) { + rc = LoadBitmap(av7110, w, brest / bpl, inc, data); + if (!rc) + rc = BlitBitmap(av7110, x0, y0 + bnum * lpb); + } + release_rc = ReleaseBitmap(av7110); + if (!rc) + rc = release_rc; + if (rc) + dprintk(1,"returns %d\n",rc); + return rc; +} + +int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc) +{ + int ret; + + if (mutex_lock_interruptible(&av7110->osd_mutex)) + return -ERESTARTSYS; + + switch (dc->cmd) { + case OSD_Close: + ret = DestroyOSDWindow(av7110, av7110->osdwin); + break; + case OSD_Open: + av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7; + ret = CreateOSDWindow(av7110, av7110->osdwin, + bpp2bit[av7110->osdbpp[av7110->osdwin]], + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; + if (!dc->data) { + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (ret) + break; + ret = SetColorBlend(av7110, av7110->osdwin); + } + break; + case OSD_Show: + ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0); + break; + case OSD_Hide: + ret = HideWindow(av7110, av7110->osdwin); + break; + case OSD_Clear: + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0); + break; + case OSD_Fill: + ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color); + break; + case OSD_SetColor: + ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1); + break; + case OSD_SetPalette: + if (FW_VERSION(av7110->arm_app) >= 0x2618) + ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0); + else { + int i, len = dc->x0-dc->color+1; + u8 __user *colors = (u8 __user *)dc->data; + u8 r, g = 0, b = 0, blend = 0; + ret = 0; + for (i = 0; i<len; i++) { + if (get_user(r, colors + i * 4) || + get_user(g, colors + i * 4 + 1) || + get_user(b, colors + i * 4 + 2) || + get_user(blend, colors + i * 4 + 3)) { + ret = -EFAULT; + break; + } + ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend); + if (ret) + break; + } + } + break; + case OSD_SetPixel: + ret = DrawLine(av7110, av7110->osdwin, + dc->x0, dc->y0, 0, 0, dc->color); + break; + case OSD_SetRow: + dc->y1 = dc->y0; + fallthrough; + case OSD_SetBlock: + ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); + break; + case OSD_FillRow: + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + dc->x1-dc->x0+1, dc->y1, dc->color); + break; + case OSD_FillBlock: + ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color); + break; + case OSD_Line: + ret = DrawLine(av7110, av7110->osdwin, + dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color); + break; + case OSD_Text: + { + char textbuf[240]; + + if (strncpy_from_user(textbuf, dc->data, 240) < 0) { + ret = -EFAULT; + break; + } + textbuf[239] = 0; + if (dc->x1 > 3) + dc->x1 = 3; + ret = SetFont(av7110, av7110->osdwin, dc->x1, + (u16) (dc->color & 0xffff), (u16) (dc->color >> 16)); + if (!ret) + ret = FlushText(av7110); + if (!ret) + ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf); + break; + } + case OSD_SetWindow: + if (dc->x0 < 1 || dc->x0 > 7) + ret = -EINVAL; + else { + av7110->osdwin = dc->x0; + ret = 0; + } + break; + case OSD_MoveWindow: + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + break; + case OSD_OpenRaw: + if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) { + ret = -EINVAL; + break; + } + if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) + av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1; + else + av7110->osdbpp[av7110->osdwin] = 0; + ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color, + dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1); + if (ret) + break; + if (!dc->data) { + ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0); + if (!ret) + ret = SetColorBlend(av7110, av7110->osdwin); + } + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&av7110->osd_mutex); + if (ret==-ERESTARTSYS) + dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd); + else if (ret) + dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret); + + return ret; +} + +int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap) +{ + switch (cap->cmd) { + case OSD_CAP_MEMSIZE: + if (FW_4M_SDRAM(av7110->arm_app)) + cap->val = 1000000; + else + cap->val = 92000; + return 0; + default: + return -EINVAL; + } +} +#endif /* CONFIG_DVB_AV7110_OSD */ diff --git a/drivers/staging/media/av7110/av7110_hw.h b/drivers/staging/media/av7110/av7110_hw.h new file mode 100644 index 000000000000..6380d8950c69 --- /dev/null +++ b/drivers/staging/media/av7110/av7110_hw.h @@ -0,0 +1,496 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _AV7110_HW_H_ +#define _AV7110_HW_H_ + +#include "av7110.h" + +/* DEBI transfer mode defs */ + +#define DEBINOSWAP 0x000e0000 +#define DEBISWAB 0x001e0000 +#define DEBISWAP 0x002e0000 + +#define ARM_WAIT_FREE (HZ) +#define ARM_WAIT_SHAKE (HZ/5) +#define ARM_WAIT_OSD (HZ) + + +enum av7110_bootstate +{ + BOOTSTATE_BUFFER_EMPTY = 0, + BOOTSTATE_BUFFER_FULL = 1, + BOOTSTATE_AV7110_BOOT_COMPLETE = 2 +}; + +enum av7110_type_rec_play_format +{ RP_None, + AudioPES, + AudioMp2, + AudioPCM, + VideoPES, + AV_PES +}; + +enum av7110_osd_palette_type +{ + NoPalet = 0, /* No palette */ + Pal1Bit = 2, /* 2 colors for 1 Bit Palette */ + Pal2Bit = 4, /* 4 colors for 2 bit palette */ + Pal4Bit = 16, /* 16 colors for 4 bit palette */ + Pal8Bit = 256 /* 256 colors for 16 bit palette */ +}; + +/* switch defines */ +#define SB_GPIO 3 +#define SB_OFF SAA7146_GPIO_OUTLO /* SlowBlank off (TV-Mode) */ +#define SB_ON SAA7146_GPIO_INPUT /* SlowBlank on (AV-Mode) */ +#define SB_WIDE SAA7146_GPIO_OUTHI /* SlowBlank 6V (16/9-Mode) (not implemented) */ + +#define FB_GPIO 1 +#define FB_OFF SAA7146_GPIO_LO /* FastBlank off (CVBS-Mode) */ +#define FB_ON SAA7146_GPIO_OUTHI /* FastBlank on (RGB-Mode) */ +#define FB_LOOP SAA7146_GPIO_INPUT /* FastBlank loop-through (PC graphics ???) */ + +enum av7110_video_output_mode +{ + NO_OUT = 0, /* disable analog output */ + CVBS_RGB_OUT = 1, + CVBS_YC_OUT = 2, + YC_OUT = 3 +}; + +/* firmware internal msg q status: */ +#define GPMQFull 0x0001 /* Main Message Queue Full */ +#define GPMQOver 0x0002 /* Main Message Queue Overflow */ +#define HPQFull 0x0004 /* High Priority Msg Queue Full */ +#define HPQOver 0x0008 +#define OSDQFull 0x0010 /* OSD Queue Full */ +#define OSDQOver 0x0020 +#define GPMQBusy 0x0040 /* Queue not empty, FW >= 261d */ +#define HPQBusy 0x0080 +#define OSDQBusy 0x0100 + +/* hw section filter flags */ +#define SECTION_EIT 0x01 +#define SECTION_SINGLE 0x00 +#define SECTION_CYCLE 0x02 +#define SECTION_CONTINUOS 0x04 +#define SECTION_MODE 0x06 +#define SECTION_IPMPE 0x0C /* size up to 4k */ +#define SECTION_HIGH_SPEED 0x1C /* larger buffer */ +#define DATA_PIPING_FLAG 0x20 /* for Data Piping Filter */ + +#define PBUFSIZE_NONE 0x0000 +#define PBUFSIZE_1P 0x0100 +#define PBUFSIZE_2P 0x0200 +#define PBUFSIZE_1K 0x0300 +#define PBUFSIZE_2K 0x0400 +#define PBUFSIZE_4K 0x0500 +#define PBUFSIZE_8K 0x0600 +#define PBUFSIZE_16K 0x0700 +#define PBUFSIZE_32K 0x0800 + + +/* firmware command codes */ +enum av7110_osd_command { + WCreate, + WDestroy, + WMoveD, + WMoveA, + WHide, + WTop, + DBox, + DLine, + DText, + Set_Font, + SetColor, + SetBlend, + SetWBlend, + SetCBlend, + SetNonBlend, + LoadBmp, + BlitBmp, + ReleaseBmp, + SetWTrans, + SetWNoTrans, + Set_Palette +}; + +enum av7110_pid_command { + MultiPID, + VideoPID, + AudioPID, + InitFilt, + FiltError, + NewVersion, + CacheError, + AddPIDFilter, + DelPIDFilter, + Scan, + SetDescr, + SetIR, + FlushTSQueue +}; + +enum av7110_mpeg_command { + SelAudChannels +}; + +enum av7110_audio_command { + AudioDAC, + CabADAC, + ON22K, + OFF22K, + MainSwitch, + ADSwitch, + SendDiSEqC, + SetRegister, + SpdifSwitch +}; + +enum av7110_request_command { + AudioState, + AudioBuffState, + VideoState1, + VideoState2, + VideoState3, + CrashCounter, + ReqVersion, + ReqVCXO, + ReqRegister, + ReqSecFilterError, + ReqSTC +}; + +enum av7110_encoder_command { + SetVidMode, + SetTestMode, + LoadVidCode, + SetMonitorType, + SetPanScanType, + SetFreezeMode, + SetWSSConfig +}; + +enum av7110_rec_play_state { + __Record, + __Stop, + __Play, + __Pause, + __Slow, + __FF_IP, + __Scan_I, + __Continue +}; + +enum av7110_fw_cmd_misc { + AV7110_FW_VIDEO_ZOOM = 1, + AV7110_FW_VIDEO_COMMAND, + AV7110_FW_AUDIO_COMMAND +}; + +enum av7110_command_type { + COMTYPE_NOCOM, + COMTYPE_PIDFILTER, + COMTYPE_MPEGDECODER, + COMTYPE_OSD, + COMTYPE_BMP, + COMTYPE_ENCODER, + COMTYPE_AUDIODAC, + COMTYPE_REQUEST, + COMTYPE_SYSTEM, + COMTYPE_REC_PLAY, + COMTYPE_COMMON_IF, + COMTYPE_PID_FILTER, + COMTYPE_PES, + COMTYPE_TS, + COMTYPE_VIDEO, + COMTYPE_AUDIO, + COMTYPE_CI_LL, + COMTYPE_MISC = 0x80 +}; + +#define VID_NONE_PREF 0x00 /* No aspect ration processing preferred */ +#define VID_PAN_SCAN_PREF 0x01 /* Pan and Scan Display preferred */ +#define VID_VERT_COMP_PREF 0x02 /* Vertical compression display preferred */ +#define VID_VC_AND_PS_PREF 0x03 /* PanScan and vertical Compression if allowed */ +#define VID_CENTRE_CUT_PREF 0x05 /* PanScan with zero vector */ + +/* MPEG video decoder commands */ +#define AV_VIDEO_CMD_STOP 0x000e +#define AV_VIDEO_CMD_PLAY 0x000d +#define AV_VIDEO_CMD_FREEZE 0x0102 +#define AV_VIDEO_CMD_FFWD 0x0016 +#define AV_VIDEO_CMD_SLOW 0x0022 + +/* MPEG audio decoder commands */ +#define AUDIO_CMD_MUTE 0x0001 +#define AUDIO_CMD_UNMUTE 0x0002 +#define AUDIO_CMD_PCM16 0x0010 +#define AUDIO_CMD_STEREO 0x0080 +#define AUDIO_CMD_MONO_L 0x0100 +#define AUDIO_CMD_MONO_R 0x0200 +#define AUDIO_CMD_SYNC_OFF 0x000e +#define AUDIO_CMD_SYNC_ON 0x000f + +/* firmware data interface codes */ +#define DATA_NONE 0x00 +#define DATA_FSECTION 0x01 +#define DATA_IPMPE 0x02 +#define DATA_MPEG_RECORD 0x03 +#define DATA_DEBUG_MESSAGE 0x04 +#define DATA_COMMON_INTERFACE 0x05 +#define DATA_MPEG_PLAY 0x06 +#define DATA_BMP_LOAD 0x07 +#define DATA_IRCOMMAND 0x08 +#define DATA_PIPING 0x09 +#define DATA_STREAMING 0x0a +#define DATA_CI_GET 0x0b +#define DATA_CI_PUT 0x0c +#define DATA_MPEG_VIDEO_EVENT 0x0d + +#define DATA_PES_RECORD 0x10 +#define DATA_PES_PLAY 0x11 +#define DATA_TS_RECORD 0x12 +#define DATA_TS_PLAY 0x13 + +/* ancient CI command codes, only two are actually still used + * by the link level CI firmware */ +#define CI_CMD_ERROR 0x00 +#define CI_CMD_ACK 0x01 +#define CI_CMD_SYSTEM_READY 0x02 +#define CI_CMD_KEYPRESS 0x03 +#define CI_CMD_ON_TUNED 0x04 +#define CI_CMD_ON_SWITCH_PROGRAM 0x05 +#define CI_CMD_SECTION_ARRIVED 0x06 +#define CI_CMD_SECTION_TIMEOUT 0x07 +#define CI_CMD_TIME 0x08 +#define CI_CMD_ENTER_MENU 0x09 +#define CI_CMD_FAST_PSI 0x0a +#define CI_CMD_GET_SLOT_INFO 0x0b + +#define CI_MSG_NONE 0x00 +#define CI_MSG_CI_INFO 0x01 +#define CI_MSG_MENU 0x02 +#define CI_MSG_LIST 0x03 +#define CI_MSG_TEXT 0x04 +#define CI_MSG_REQUEST_INPUT 0x05 +#define CI_MSG_INPUT_COMPLETE 0x06 +#define CI_MSG_LIST_MORE 0x07 +#define CI_MSG_MENU_MORE 0x08 +#define CI_MSG_CLOSE_MMI_IMM 0x09 +#define CI_MSG_SECTION_REQUEST 0x0a +#define CI_MSG_CLOSE_FILTER 0x0b +#define CI_PSI_COMPLETE 0x0c +#define CI_MODULE_READY 0x0d +#define CI_SWITCH_PRG_REPLY 0x0e +#define CI_MSG_TEXT_MORE 0x0f + +#define CI_MSG_CA_PMT 0xe0 +#define CI_MSG_ERROR 0xf0 + + +/* base address of the dual ported RAM which serves as communication + * area between PCI bus and av7110, + * as seen by the DEBI bus of the saa7146 */ +#define DPRAM_BASE 0x4000 + +/* boot protocol area */ +#define AV7110_BOOT_STATE (DPRAM_BASE + 0x3F8) +#define AV7110_BOOT_SIZE (DPRAM_BASE + 0x3FA) +#define AV7110_BOOT_BASE (DPRAM_BASE + 0x3FC) +#define AV7110_BOOT_BLOCK (DPRAM_BASE + 0x400) +#define AV7110_BOOT_MAX_SIZE 0xc00 + +/* firmware command protocol area */ +#define IRQ_STATE (DPRAM_BASE + 0x0F4) +#define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6) +#define MSGSTATE (DPRAM_BASE + 0x0F8) +#define COMMAND (DPRAM_BASE + 0x0FC) +#define COM_BUFF (DPRAM_BASE + 0x100) +#define COM_BUFF_SIZE 0x20 + +/* various data buffers */ +#define BUFF1_BASE (DPRAM_BASE + 0x120) +#define BUFF1_SIZE 0xE0 + +#define DATA_BUFF0_BASE (DPRAM_BASE + 0x200) +#define DATA_BUFF0_SIZE 0x0800 + +#define DATA_BUFF1_BASE (DATA_BUFF0_BASE+DATA_BUFF0_SIZE) +#define DATA_BUFF1_SIZE 0x0800 + +#define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE) +#define DATA_BUFF2_SIZE 0x0800 + +#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE) +#define DATA_BUFF3_SIZE 0x0400 + +#define Reserved (DPRAM_BASE + 0x1E00) +#define Reserved_SIZE 0x1C0 + + +/* firmware status area */ +#define STATUS_BASE (DPRAM_BASE + 0x1FC0) +#define STATUS_LOOPS (STATUS_BASE + 0x08) + +#define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C) +/* ((aspect_ratio & 0xf) << 12) | (height & 0xfff) */ +#define STATUS_MPEG_HEIGHT_AR (STATUS_BASE + 0x0E) + +/* firmware data protocol area */ +#define RX_TYPE (DPRAM_BASE + 0x1FE8) +#define RX_LEN (DPRAM_BASE + 0x1FEA) +#define TX_TYPE (DPRAM_BASE + 0x1FEC) +#define TX_LEN (DPRAM_BASE + 0x1FEE) + +#define RX_BUFF (DPRAM_BASE + 0x1FF4) +#define TX_BUFF (DPRAM_BASE + 0x1FF6) + +#define HANDSHAKE_REG (DPRAM_BASE + 0x1FF8) +#define COM_IF_LOCK (DPRAM_BASE + 0x1FFA) + +#define IRQ_RX (DPRAM_BASE + 0x1FFC) +#define IRQ_TX (DPRAM_BASE + 0x1FFE) + +/* used by boot protocol to load firmware into av7110 DRAM */ +#define DRAM_START_CODE 0x2e000404 +#define DRAM_MAX_CODE_SIZE 0x00100000 + +/* saa7146 gpio lines */ +#define RESET_LINE 2 +#define DEBI_DONE_LINE 1 +#define ARM_IRQ_LINE 0 + + + +extern int av7110_bootarm(struct av7110 *av7110); +extern int av7110_firmversion(struct av7110 *av7110); +#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) +#define FW_4M_SDRAM(arm_app) ((arm_app) & 0x40000000) +#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF) + +extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags); +extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...); +extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf, + int request_buf_len, u16 *reply_buf, int reply_buf_len); + + +/* DEBI (saa7146 data extension bus interface) access */ +extern int av7110_debiwrite(struct av7110 *av7110, u32 config, + int addr, u32 val, unsigned int count); +extern u32 av7110_debiread(struct av7110 *av7110, u32 config, + int addr, unsigned int count); + + +/* DEBI during interrupt */ +/* single word writes */ +static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) +{ + av7110_debiwrite(av7110, config, addr, val, count); +} + +/* buffer writes */ +static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, + const u8 *val, int count) +{ + memcpy(av7110->debi_virt, val, count); + av7110_debiwrite(av7110, config, addr, 0, count); +} + +static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) +{ + u32 res; + + res=av7110_debiread(av7110, config, addr, count); + if (count<=4) + memcpy(av7110->debi_virt, (char *) &res, count); + return res; +} + +/* DEBI outside interrupts, only for count <= 4! */ +static inline void wdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) +{ + unsigned long flags; + + spin_lock_irqsave(&av7110->debilock, flags); + av7110_debiwrite(av7110, config, addr, val, count); + spin_unlock_irqrestore(&av7110->debilock, flags); +} + +static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, unsigned int count) +{ + unsigned long flags; + u32 res; + + spin_lock_irqsave(&av7110->debilock, flags); + res=av7110_debiread(av7110, config, addr, count); + spin_unlock_irqrestore(&av7110->debilock, flags); + return res; +} + +/* handle mailbox registers of the dual ported RAM */ +static inline void ARM_ResetMailBox(struct av7110 *av7110) +{ + unsigned long flags; + + spin_lock_irqsave(&av7110->debilock, flags); + av7110_debiread(av7110, DEBINOSWAP, IRQ_RX, 2); + av7110_debiwrite(av7110, DEBINOSWAP, IRQ_RX, 0, 2); + spin_unlock_irqrestore(&av7110->debilock, flags); +} + +static inline void ARM_ClearMailBox(struct av7110 *av7110) +{ + iwdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); +} + +static inline void ARM_ClearIrq(struct av7110 *av7110) +{ + irdebi(av7110, DEBINOSWAP, IRQ_RX, 0, 2); +} + +/**************************************************************************** + * Firmware commands + ****************************************************************************/ + +static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data) +{ + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data); +} + +static inline int av7710_set_video_mode(struct av7110 *av7110, int mode) +{ + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode); +} + +static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg) +{ + return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4, + (com>>16), (com&0xffff), + (arg>>16), (arg&0xffff)); +} + +static inline int audcom(struct av7110 *av7110, u32 com) +{ + return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2, + (com>>16), (com&0xffff)); +} + +static inline int Set22K(struct av7110 *av7110, int state) +{ + return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0); +} + + +extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst); + + +#ifdef CONFIG_DVB_AV7110_OSD +extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc); +extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap); +#endif /* CONFIG_DVB_AV7110_OSD */ + + + +#endif /* _AV7110_HW_H_ */ diff --git a/drivers/staging/media/av7110/av7110_ipack.c b/drivers/staging/media/av7110/av7110_ipack.c new file mode 100644 index 000000000000..30330ed01ce8 --- /dev/null +++ b/drivers/staging/media/av7110/av7110_ipack.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "dvb_filter.h" +#include "av7110_ipack.h" +#include <linux/string.h> /* for memcpy() */ +#include <linux/vmalloc.h> + + +void av7110_ipack_reset(struct ipack *p) +{ + p->found = 0; + p->cid = 0; + p->plength = 0; + p->flag1 = 0; + p->flag2 = 0; + p->hlength = 0; + p->mpeg = 0; + p->check = 0; + p->which = 0; + p->done = 0; + p->count = 0; +} + + +int av7110_ipack_init(struct ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)) +{ + if (!(p->buf = vmalloc(size))) { + printk(KERN_WARNING "Couldn't allocate memory for ipack\n"); + return -ENOMEM; + } + p->size = size; + p->func = func; + p->repack_subids = 0; + av7110_ipack_reset(p); + return 0; +} + + +void av7110_ipack_free(struct ipack *p) +{ + vfree(p->buf); +} + + +static void send_ipack(struct ipack *p) +{ + int off; + struct dvb_audio_info ai; + int ac3_off = 0; + int streamid = 0; + int nframes = 0; + int f = 0; + + switch (p->mpeg) { + case 2: + if (p->count < 10) + return; + p->buf[3] = p->cid; + p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); + p->buf[5] = (u8)((p->count - 6) & 0x00ff); + if (p->repack_subids && p->cid == PRIVATE_STREAM1) { + off = 9 + p->buf[8]; + streamid = p->buf[off]; + if ((streamid & 0xf8) == 0x80) { + ai.off = 0; + ac3_off = ((p->buf[off + 2] << 8)| + p->buf[off + 3]); + if (ac3_off < p->count) + f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off, + p->count - ac3_off, &ai, 0); + if (!f) { + nframes = (p->count - off - 3 - ac3_off) / + ai.framesize + 1; + p->buf[off + 2] = (ac3_off >> 8) & 0xff; + p->buf[off + 3] = (ac3_off) & 0xff; + p->buf[off + 1] = nframes; + ac3_off += nframes * ai.framesize - p->count; + } + } + } + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x80; + p->buf[7] = 0x00; + p->buf[8] = 0x00; + p->count = 9; + if (p->repack_subids && p->cid == PRIVATE_STREAM1 + && (streamid & 0xf8) == 0x80) { + p->count += 4; + p->buf[9] = streamid; + p->buf[10] = (ac3_off >> 8) & 0xff; + p->buf[11] = (ac3_off) & 0xff; + p->buf[12] = 0; + } + break; + + case 1: + if (p->count < 8) + return; + p->buf[3] = p->cid; + p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8); + p->buf[5] = (u8)((p->count - 6) & 0x00ff); + p->func(p->buf, p->count, p->data); + + p->buf[6] = 0x0f; + p->count = 7; + break; + } +} + + +void av7110_ipack_flush(struct ipack *p) +{ + if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6) + return; + p->plength = p->found - 6; + p->found = 0; + send_ipack(p); + av7110_ipack_reset(p); +} + + +static void write_ipack(struct ipack *p, const u8 *data, int count) +{ + u8 headr[3] = { 0x00, 0x00, 0x01 }; + + if (p->count < 6) { + memcpy(p->buf, headr, 3); + p->count = 6; + } + + if (p->count + count < p->size){ + memcpy(p->buf+p->count, data, count); + p->count += count; + } else { + int rest = p->size - p->count; + memcpy(p->buf+p->count, data, rest); + p->count += rest; + send_ipack(p); + if (count - rest > 0) + write_ipack(p, data + rest, count - rest); + } +} + + +int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p) +{ + int l; + int c = 0; + + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)) { + switch (p->found) { + case 0: + case 1: + if (buf[c] == 0x00) + p->found++; + else + p->found = 0; + c++; + break; + case 2: + if (buf[c] == 0x01) + p->found++; + else if (buf[c] == 0) + p->found = 2; + else + p->found = 0; + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]) { + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + p->done = 1; + fallthrough; + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + p->found = 0; + break; + } + break; + + case 4: + if (count-c > 1) { + p->plen[0] = buf[c]; + c++; + p->plen[1] = buf[c]; + c++; + p->found += 2; + p->plength = (p->plen[0] << 8) | p->plen[1]; + } else { + p->plen[0] = buf[c]; + p->found++; + return count; + } + break; + case 5: + p->plen[1] = buf[c]; + c++; + p->found++; + p->plength = (p->plen[0] << 8) | p->plen[1]; + break; + case 6: + if (!p->done) { + p->flag1 = buf[c]; + c++; + p->found++; + if ((p->flag1 & 0xc0) == 0x80) + p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; + } + } + break; + + case 7: + if (!p->done && p->mpeg == 2) { + p->flag2 = buf[c]; + c++; + p->found++; + } + break; + + case 8: + if (!p->done && p->mpeg == 2) { + p->hlength = buf[c]; + c++; + p->found++; + } + break; + } + } + + if (c == count) + return count; + + if (!p->plength) + p->plength = MMAX_PLENGTH - 6; + + if (p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7))) { + switch (p->cid) { + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + if (p->mpeg == 2 && p->found == 9) { + write_ipack(p, &p->flag1, 1); + write_ipack(p, &p->flag2, 1); + write_ipack(p, &p->hlength, 1); + } + + if (p->mpeg == 1 && p->found == 7) + write_ipack(p, &p->flag1, 1); + + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14) { + while (c < count && p->found < 14) { + p->pts[p->found - 9] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + } + if (c == count) + return count; + } + + if (p->mpeg == 1 && p->which < 2000) { + + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } + + while (!p->which && c < count && + p->check == 0xff){ + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + } + + if (c == count) + return count; + + if ((p->check & 0xc0) == 0x40 && !p->which) { + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + + p->which = 1; + if (c == count) + return count; + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if (c == count) + return count; + } + + if (p->which == 1) { + p->check = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if (c == count) + return count; + } + + if ((p->check & 0x30) && p->check != 0xff) { + p->flag2 = (p->check & 0xf0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + + if (c == count) + return count; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) { + while (c < count && p->which < 7) { + p->pts[p->which - 2] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if (c == count) + return count; + } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) { + while (c < count && p->which < 12) { + if (p->which < 7) + p->pts[p->which - 2] = buf[c]; + write_ipack(p, buf + c, 1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if (c == count) + return count; + } + p->which = 2000; + } + + } + + while (c < count && p->found < p->plength + 6) { + l = count - c; + if (l + p->found > p->plength + 6) + l = p->plength + 6 - p->found; + write_ipack(p, buf + c, l); + p->found += l; + c += l; + } + break; + } + + + if (p->done) { + if (p->found + count - c < p->plength + 6) { + p->found += count - c; + c = count; + } else { + c += p->plength + 6 - p->found; + p->found = p->plength + 6; + } + } + + if (p->plength && p->found == p->plength + 6) { + send_ipack(p); + av7110_ipack_reset(p); + if (c < count) + av7110_ipack_instant_repack(buf + c, count - c, p); + } + } + return count; +} diff --git a/drivers/staging/media/av7110/av7110_ipack.h b/drivers/staging/media/av7110/av7110_ipack.h new file mode 100644 index 000000000000..943ec899bb93 --- /dev/null +++ b/drivers/staging/media/av7110/av7110_ipack.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _AV7110_IPACK_H_ +#define _AV7110_IPACK_H_ + +extern int av7110_ipack_init(struct ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)); + +extern void av7110_ipack_reset(struct ipack *p); +extern int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p); +extern void av7110_ipack_free(struct ipack * p); +extern void av7110_ipack_flush(struct ipack *p); + +#endif diff --git a/drivers/staging/media/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c new file mode 100644 index 000000000000..a851ba328e4a --- /dev/null +++ b/drivers/staging/media/av7110/av7110_ir.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for the remote control of SAA7146 based AV7110 cards + * + * Copyright (C) 1999-2003 Holger Waechtler <holger@convergence.de> + * Copyright (C) 2003-2007 Oliver Endriss <o.endriss@gmx.de> + * Copyright (C) 2019 Sean Young <sean@mess.org> + */ + +#include <linux/kernel.h> +#include <media/rc-core.h> + +#include "av7110.h" +#include "av7110_hw.h" + +#define IR_RC5 0 +#define IR_RCMM 1 +#define IR_RC5_EXT 2 /* internal only */ + +/* interrupt handler */ +void av7110_ir_handler(struct av7110 *av7110, u32 ircom) +{ + struct rc_dev *rcdev = av7110->ir.rcdev; + enum rc_proto proto; + u32 command, addr, scancode; + u32 toggle; + + dprintk(4, "ir command = %08x\n", ircom); + + if (rcdev) { + switch (av7110->ir.ir_config) { + case IR_RC5: /* RC5: 5 bits device address, 6 bits command */ + command = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + scancode = RC_SCANCODE_RC5(addr, command); + toggle = ircom & 0x0800; + proto = RC_PROTO_RC5; + break; + + case IR_RCMM: /* RCMM: 32 bits scancode */ + scancode = ircom & ~0x8000; + toggle = ircom & 0x8000; + proto = RC_PROTO_RCMM32; + break; + + case IR_RC5_EXT: + /* + * extended RC5: 5 bits device address, 7 bits command + * + * Extended RC5 uses only one start bit. The second + * start bit is re-assigned bit 6 of the command bit. + */ + command = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + if (!(ircom & 0x1000)) + command |= 0x40; + scancode = RC_SCANCODE_RC5(addr, command); + toggle = ircom & 0x0800; + proto = RC_PROTO_RC5; + break; + default: + dprintk(2, "unknown ir config %d\n", + av7110->ir.ir_config); + return; + } + + rc_keydown(rcdev, proto, scancode, toggle != 0); + } +} + +int av7110_set_ir_config(struct av7110 *av7110) +{ + dprintk(4, "ir config = %08x\n", av7110->ir.ir_config); + + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, + av7110->ir.ir_config); +} + +static int change_protocol(struct rc_dev *rcdev, u64 *rc_type) +{ + struct av7110 *av7110 = rcdev->priv; + u32 ir_config; + + if (*rc_type & RC_PROTO_BIT_RCMM32) { + ir_config = IR_RCMM; + *rc_type = RC_PROTO_BIT_RCMM32; + } else if (*rc_type & RC_PROTO_BIT_RC5) { + if (FW_VERSION(av7110->arm_app) >= 0x2620) + ir_config = IR_RC5_EXT; + else + ir_config = IR_RC5; + *rc_type = RC_PROTO_BIT_RC5; + } else { + return -EINVAL; + } + + if (ir_config == av7110->ir.ir_config) + return 0; + + av7110->ir.ir_config = ir_config; + + return av7110_set_ir_config(av7110); +} + +int av7110_ir_init(struct av7110 *av7110) +{ + struct rc_dev *rcdev; + struct pci_dev *pci; + int ret; + + rcdev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rcdev) + return -ENOMEM; + + pci = av7110->dev->pci; + + snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), + "pci-%s/ir0", pci_name(pci)); + + rcdev->device_name = av7110->card_name; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->input_phys = av7110->ir.input_phys; + rcdev->input_id.bustype = BUS_PCI; + rcdev->input_id.version = 2; + if (pci->subsystem_vendor) { + rcdev->input_id.vendor = pci->subsystem_vendor; + rcdev->input_id.product = pci->subsystem_device; + } else { + rcdev->input_id.vendor = pci->vendor; + rcdev->input_id.product = pci->device; + } + + rcdev->dev.parent = &pci->dev; + rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RCMM32; + rcdev->change_protocol = change_protocol; + rcdev->map_name = RC_MAP_HAUPPAUGE; + rcdev->priv = av7110; + + av7110->ir.rcdev = rcdev; + av7110->ir.ir_config = IR_RC5; + av7110_set_ir_config(av7110); + + ret = rc_register_device(rcdev); + if (ret) { + av7110->ir.rcdev = NULL; + rc_free_device(rcdev); + } + + return ret; +} + +void av7110_ir_exit(struct av7110 *av7110) +{ + rc_unregister_device(av7110->ir.rcdev); +} + +//MODULE_AUTHOR("Holger Waechtler <holger@convergence.de>, Oliver Endriss <o.endriss@gmx.de>"); +//MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/av7110/av7110_v4l.c b/drivers/staging/media/av7110/av7110_v4l.c new file mode 100644 index 000000000000..c89f536f699c --- /dev/null +++ b/drivers/staging/media/av7110/av7110_v4l.c @@ -0,0 +1,952 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * originally based on code by: + * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> + * + * the project's page is at https://linuxtv.org + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/timer.h> +#include <linux/poll.h> + +#include "av7110.h" +#include "av7110_hw.h" +#include "av7110_av.h" + +int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) +{ + u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; + struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; + + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs.addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs.addr = 0x42; + break; + default: + return 0; + } + + if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { + dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", + av7110->dvb_adapter.num, reg, val); + return -EIO; + } + return 0; +} + +static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) +{ + u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; + u8 msg2[2]; + struct i2c_msg msgs[2] = { + { .flags = 0 , .len = 3, .buf = msg1 }, + { .flags = I2C_M_RD, .len = 2, .buf = msg2 } + }; + + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs[0].addr = 0x40; + msgs[1].addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs[0].addr = 0x42; + msgs[1].addr = 0x42; + break; + default: + return 0; + } + + if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { + dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", + av7110->dvb_adapter.num, reg); + return -EIO; + } + *val = (msg2[0] << 8) | msg2[1]; + return 0; +} + +static struct v4l2_input inputs[4] = { + { + .index = 0, + .name = "DVB", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 1, + .tuner = 0, /* ignored */ + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 1, + .name = "Television", + .type = V4L2_INPUT_TYPE_TUNER, + .audioset = 1, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 2, + .name = "Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + }, { + .index = 3, + .name = "Y/C", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, + .status = 0, + .capabilities = V4L2_IN_CAP_STD, + } +}; + +static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data) +{ + struct av7110 *av7110 = dev->ext_priv; + u8 buf[] = { 0x00, reg, data }; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 }; + + dprintk(4, "dev: %p\n", dev); + + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) + return -1; + return 0; +} + +static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4]) +{ + struct av7110 *av7110 = dev->ext_priv; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; + + dprintk(4, "dev: %p\n", dev); + + if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1)) + return -1; + return 0; +} + +static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq) +{ + u32 div; + u8 config; + u8 buf[4]; + + dprintk(4, "freq: 0x%08x\n", freq); + + /* magic number: 614. tuning with the frequency given by v4l2 + is always off by 614*62.5 = 38375 kHz...*/ + div = freq + 614; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x8e; + + if (freq < 16U * 16825 / 100) + config = 0xa0; + else if (freq < 16U * 44725 / 100) + config = 0x90; + else + config = 0x30; + config &= ~0x02; + + buf[3] = config; + + return tuner_write(dev, 0x61, buf); +} + +static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq) +{ + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u32 div; + u8 data[4]; + + div = (freq + 38900000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; + + if (freq < 45000000) + return -EINVAL; + else if (freq < 137000000) + data[3] = 0x01; + else if (freq < 403000000) + data[3] = 0x02; + else if (freq < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + if (av7110->fe->ops.i2c_gate_ctrl) + av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1); + return tuner_write(dev, 0x63, data); +} + + + +static struct saa7146_standard analog_standard[]; +static struct saa7146_standard dvb_standard[]; +static struct saa7146_standard standard[]; + +static const struct v4l2_audio msp3400_v4l2_audio = { + .index = 0, + .name = "Television", + .capability = V4L2_AUDCAP_STEREO +}; + +static int av7110_dvb_c_switch(struct saa7146_fh *fh) +{ + struct saa7146_dev *dev = fh->dev; + struct saa7146_vv *vv = dev->vv_data; + struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u16 adswitch; + int source, sync, err; + + dprintk(4, "%p\n", av7110); + + if ((vv->video_status & STATUS_OVERLAY) != 0) { + vv->ov_suspend = vv->video_fh; + err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ + if (err != 0) { + dprintk(2, "suspending video failed\n"); + vv->ov_suspend = NULL; + } + } + + if (0 != av7110->current_input) { + dprintk(1, "switching to analog TV:\n"); + adswitch = 1; + source = SAA7146_HPS_SOURCE_PORT_B; + sync = SAA7146_HPS_SYNC_PORT_B; + memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2); + + switch (av7110->current_input) { + case 1: + dprintk(1, "switching SAA7113 to Analog Tuner Input\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x60)) + dprintk(1, "setting band in demodulator failed\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF) + } + if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 2: + dprintk(1, "switching SAA7113 to Video AV CVBS Input\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + case 3: + dprintk(1, "switching SAA7113 to Video AV Y/C Input\n"); + if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1) + dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num); + break; + default: + dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n"); + } + } else { + adswitch = 0; + source = SAA7146_HPS_SOURCE_PORT_A; + sync = SAA7146_HPS_SYNC_PORT_A; + memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); + dprintk(1, "switching DVB mode\n"); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume + + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) + dprintk(1, "setting band in demodulator failed\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + } + } + + /* hmm, this does not do anything!? */ + if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch)) + dprintk(1, "ADSwitch error\n"); + + saa7146_set_hps_source_and_sync(dev, source, sync); + + if (vv->ov_suspend != NULL) { + saa7146_start_preview(vv->ov_suspend); + vv->ov_suspend = NULL; + } + + return 0; +} + +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 stereo_det; + s8 stereo; + + dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); + + if (!av7110->analog_tuner_flags || t->index != 0) + return -EINVAL; + + memset(t, 0, sizeof(*t)); + strscpy((char *)t->name, "Television", sizeof(t->name)); + + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ + t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ + /* FIXME: add the real signal strength here */ + t->signal = 0xffff; + t->afc = 0; + + /* FIXME: standard / stereo detection is still broken */ + msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); + msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); + dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); + stereo = (s8)(stereo_det >> 8); + if (stereo > 0x10) { + /* stereo */ + t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + t->audmode = V4L2_TUNER_MODE_STEREO; + } else if (stereo < -0x10) { + /* bilingual */ + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1; + } else /* mono */ + t->rxsubchans = V4L2_TUNER_SUB_MONO; + + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + u16 fm_matrix, src; + dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + switch (t->audmode) { + case V4L2_TUNER_MODE_STEREO: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); + fm_matrix = 0x3001; /* stereo */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); + fm_matrix = 0x3000; /* bilingual */ + src = 0x0020; + break; + case V4L2_TUNER_MODE_LANG1: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0000; + break; + case V4L2_TUNER_MODE_LANG2: + dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0010; + break; + default: /* case V4L2_TUNER_MODE_MONO: */ + dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); + fm_matrix = 0x3000; /* mono */ + src = 0x0030; + break; + } + msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); + msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); + msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); + msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + memset(f, 0, sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = av7110->current_freq; + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency); + + if (!av7110->analog_tuner_flags || av7110->current_input != 1) + return -EINVAL; + + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); + + /* tune in desired frequency */ + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) + ves1820_set_tv_freq(dev, f->frequency); + else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) + stv0297_set_tv_freq(dev, f->frequency); + av7110->current_freq = f->frequency; + + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */ + msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */ + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */ + return 0; +} + +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); + + if (av7110->analog_tuner_flags) { + if (i->index >= 4) + return -EINVAL; + } else { + if (i->index != 0) + return -EINVAL; + } + + memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); + + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + *input = av7110->current_input; + dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_INPUT: %d\n", input); + + if (!av7110->analog_tuner_flags) + return input ? -EINVAL : 0; + + if (input >= 4) + return -EINVAL; + + av7110->current_input = input; + return av7110_dvb_c_switch(fh); +} + +static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) +{ + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); + if (a->index != 0) + return -EINVAL; + *a = msp3400_v4l2_audio; + return 0; +} + +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); + if (a->index != 0) + return -EINVAL; + if (av7110->current_input >= 2) + return -EINVAL; + *a = msp3400_v4l2_audio; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); + if (av7110->current_input >= 2) + return -EINVAL; + return a->index ? -EINVAL : 0; +} + +static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, + struct v4l2_sliced_vbi_cap *cap) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); + if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) + return -EINVAL; + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + cap->service_set = V4L2_SLICED_WSS_625; + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + } + return 0; +} + +static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_G_FMT:\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); + if (av7110->wssMode) { + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); + } + return 0; +} + +static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; + + dprintk(2, "VIDIOC_S_FMT\n"); + if (FW_VERSION(av7110->arm_app) < 0x2623) + return -EINVAL; + if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && + f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + /* WSS controlled by firmware */ + av7110->wssMode = 0; + av7110->wssData = 0; + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, + SetWSSConfig, 1, 0); + } else { + memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); + f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; + f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; + f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); + /* WSS controlled by userspace */ + av7110->wssMode = 1; + av7110->wssData = 0; + } + return 0; +} + +static int av7110_vbi_reset(struct file *file) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + + dprintk(2, "%s\n", __func__); + av7110->wssMode = 0; + av7110->wssData = 0; + if (FW_VERSION(av7110->arm_app) < 0x2623) + return 0; + else + return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0); +} + +static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) +{ + struct saa7146_fh *fh = file->private_data; + struct saa7146_dev *dev = fh->dev; + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + struct v4l2_sliced_vbi_data d; + int rc; + + dprintk(2, "%s\n", __func__); + if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d) + return -EINVAL; + if (copy_from_user(&d, data, count)) + return -EFAULT; + if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23) + return -EINVAL; + if (d.id) + av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0]; + else + av7110->wssData = 0x8000; + rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData); + return (rc < 0) ? rc : count; +} + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + +static u8 saa7113_init_regs[] = { + 0x02, 0xd0, + 0x03, 0x23, + 0x04, 0x00, + 0x05, 0x00, + 0x06, 0xe9, + 0x07, 0x0d, + 0x08, 0x98, + 0x09, 0x02, + 0x0a, 0x80, + 0x0b, 0x40, + 0x0c, 0x40, + 0x0d, 0x00, + 0x0e, 0x01, + 0x0f, 0x7c, + 0x10, 0x48, + 0x11, 0x0c, + 0x12, 0x8b, + 0x13, 0x1a, + 0x14, 0x00, + 0x15, 0x00, + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1b, 0x00, + 0x1c, 0x00, + 0x1d, 0x00, + 0x1e, 0x00, + + 0x41, 0x77, + 0x42, 0x77, + 0x43, 0x77, + 0x44, 0x77, + 0x45, 0x77, + 0x46, 0x77, + 0x47, 0x77, + 0x48, 0x77, + 0x49, 0x77, + 0x4a, 0x77, + 0x4b, 0x77, + 0x4c, 0x77, + 0x4d, 0x77, + 0x4e, 0x77, + 0x4f, 0x77, + 0x50, 0x77, + 0x51, 0x77, + 0x52, 0x77, + 0x53, 0x77, + 0x54, 0x77, + 0x55, 0x77, + 0x56, 0x77, + 0x57, 0xff, + + 0xff +}; + + +static struct saa7146_ext_vv av7110_vv_data_st; +static struct saa7146_ext_vv av7110_vv_data_c; + +int av7110_init_analog_module(struct av7110 *av7110) +{ + u16 version1, version2; + + if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { + pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x0; + } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { + pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x5; + } else + return -ENODEV; + + msleep(100); // the probing above resets the msp... + msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); + msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); + dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", + av7110->dvb_adapter.num, version1, version2); + msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source + msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source + msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume + msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source + msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume + msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART + + if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { + pr_info("saa7113 not accessible\n"); + } else { + u8 *i = saa7113_init_regs; + + if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) { + /* Fujitsu/Siemens DVB-Cable */ + av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; + } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) { + /* Hauppauge/TT DVB-C premium */ + av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820; + } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) { + /* Hauppauge/TT DVB-C premium */ + av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297; + } + + /* setup for DVB by default */ + if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { + if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) + dprintk(1, "setting band in demodulator failed\n"); + } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) + saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) + } + + /* init the saa7113 */ + while (*i != 0xff) { + if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) { + dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num); + break; + } + i += 2; + } + /* setup msp for analog sound: B/G Dual-FM */ + msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2 + msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG + msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz + msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI + msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz + msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI + msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2 + } + + memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2); + /* set dd1 stream a & b */ + saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000); + saa7146_write(av7110->dev, DD1_INIT, 0x03000700); + saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + return 0; +} + +int av7110_init_v4l(struct av7110 *av7110) +{ + struct saa7146_dev* dev = av7110->dev; + struct saa7146_ext_vv *vv_data; + int ret; + + /* special case DVB-C: these cards have an analog tuner + plus need some special handling, so we have separate + saa7146_ext_vv data for these... */ + if (av7110->analog_tuner_flags) + vv_data = &av7110_vv_data_c; + else + vv_data = &av7110_vv_data_st; + ret = saa7146_vv_init(dev, vv_data); + + if (ret) { + ERR("cannot init capture device. skipping\n"); + return -ENODEV; + } + vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input; + vv_data->vid_ops.vidioc_g_input = vidioc_g_input; + vv_data->vid_ops.vidioc_s_input = vidioc_s_input; + vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio; + vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio; + vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio; + vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL; + + vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL; + vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; + vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; + vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; + + if (FW_VERSION(av7110->arm_app) < 0x2623) + vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT; + + if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_VIDEO)) { + ERR("cannot register capture device. skipping\n"); + saa7146_vv_release(dev); + return -ENODEV; + } + if (FW_VERSION(av7110->arm_app) >= 0x2623) { + if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) + ERR("cannot register vbi v4l2 device. skipping\n"); + } + return 0; +} + +int av7110_exit_v4l(struct av7110 *av7110) +{ + struct saa7146_dev* dev = av7110->dev; + + saa7146_unregister_device(&av7110->v4l_dev, av7110->dev); + saa7146_unregister_device(&av7110->vbi_dev, av7110->dev); + + saa7146_vv_release(dev); + + return 0; +} + + + +/* FIXME: these values are experimental values that look better than the + values from the latest "official" driver -- at least for me... (MiHu) */ +static struct saa7146_standard standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x15, .v_field = 288, + .h_offset = 0x48, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static struct saa7146_standard analog_standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x1b, .v_field = 288, + .h_offset = 0x08, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static struct saa7146_standard dvb_standard[] = { + { + .name = "PAL", .id = V4L2_STD_PAL_BG, + .v_offset = 0x14, .v_field = 288, + .h_offset = 0x48, .h_pixels = 708, + .v_max_out = 576, .h_max_out = 768, + }, { + .name = "NTSC", .id = V4L2_STD_NTSC, + .v_offset = 0x10, .v_field = 244, + .h_offset = 0x40, .h_pixels = 708, + .v_max_out = 480, .h_max_out = 640, + } +}; + +static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) +{ + struct av7110 *av7110 = (struct av7110*) dev->ext_priv; + + if (std->id & V4L2_STD_PAL) { + av7110->vidmode = AV7110_VIDEO_MODE_PAL; + av7110_set_vidmode(av7110, av7110->vidmode); + } + else if (std->id & V4L2_STD_NTSC) { + av7110->vidmode = AV7110_VIDEO_MODE_NTSC; + av7110_set_vidmode(av7110, av7110->vidmode); + } + else + return -1; + + return 0; +} + + +static struct saa7146_ext_vv av7110_vv_data_st = { + .inputs = 1, + .audios = 1, + .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, + .flags = 0, + + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), + .std_callback = &std_callback, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, +}; + +static struct saa7146_ext_vv av7110_vv_data_c = { + .inputs = 1, + .audios = 1, + .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO, + .flags = SAA7146_USE_PORT_B_FOR_VBI, + + .stds = &standard[0], + .num_stds = ARRAY_SIZE(standard), + .std_callback = &std_callback, + + .vbi_fops.open = av7110_vbi_reset, + .vbi_fops.release = av7110_vbi_reset, + .vbi_fops.write = av7110_vbi_write, +}; + diff --git a/drivers/staging/media/av7110/budget-patch.c b/drivers/staging/media/av7110/budget-patch.c new file mode 100644 index 000000000000..d173c8ade6a7 --- /dev/null +++ b/drivers/staging/media/av7110/budget-patch.c @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * budget-patch.c: driver for Budget Patch, + * hardware modification of DVB-S cards enabling full TS + * + * Written by Emard <emard@softhome.net> + * + * Original idea by Roberto Deza <rdeza@unav.es> + * + * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic + * and Metzlerbros + * + * the project's page is at https://linuxtv.org + */ + +#include "av7110.h" +#include "av7110_hw.h" +#include "budget.h" +#include "stv0299.h" +#include "ves1x93.h" +#include "tda8083.h" + +#include "bsru6.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define budget_patch budget + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); +//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); + +static const struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), +// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + { + .vendor = 0, + } +}; + +/* those lines are for budget-patch to be tried +** on a true budget card and observe the +** behaviour of VSYNC generated by rps1. +** this code was shamelessly copy/pasted from budget.c +*/ +static void gpio_Set22K (struct budget *budget, int state) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); +} + +/* Diseqc functions only for TT Budget card */ +/* taken from the Skyvision DVB driver by + Ralph Metzler <rjkm@metzlerbros.de> */ + +static void DiseqcSendBit (struct budget *budget, int data) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(data ? 500 : 1000); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + udelay(data ? 1000 : 500); +} + +static void DiseqcSendByte (struct budget *budget, int data) +{ + int i, par=1, d; + + dprintk(2, "budget: %p\n", budget); + + for (i=7; i>=0; i--) { + d = (data>>i)&1; + par ^= d; + DiseqcSendBit(budget, d); + } + + DiseqcSendBit(budget, par); +} + +static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) +{ + struct saa7146_dev *dev=budget->dev; + int i; + + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + mdelay(16); + + for (i=0; i<len; i++) + DiseqcSendByte(budget, msg[i]); + + mdelay(16); + + if (burst!=-1) { + if (burst) + DiseqcSendByte(budget, 0xff); + else { + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(12); + udelay(500); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + } + msleep(20); + } + + return 0; +} + +/* shamelessly copy/pasted from budget.c */ +static int budget_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + switch (tone) { + case SEC_TONE_ON: + gpio_Set22K (budget, 1); + break; + + case SEC_TONE_OFF: + gpio_Set22K (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, 0, NULL, minicmd); + + return 0; +} + +static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length) +{ + int i; + + dprintk(2, "budget: %p\n", budget); + + for (i = 2; i < length; i++) + { + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0); + msleep(5); + } + if (length) + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0); + else + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0); + msleep(5); + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0); + msleep(5); + return 0; +} + +static void av7110_set22k(struct budget_patch *budget, int state) +{ + u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0}; + + dprintk(2, "budget: %p\n", budget); + budget_av7110_send_fw_cmd(budget, buf, 2); +} + +static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst) +{ + int i; + u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + dprintk(2, "budget: %p\n", budget); + + if (len>10) + len=10; + + buf[1] = len+2; + buf[2] = len; + + if (burst != -1) + buf[3]=burst ? 0x01 : 0x00; + else + buf[3]=0xffff; + + for (i=0; i<len; i++) + buf[i+4]=msg[i]; + + budget_av7110_send_fw_cmd(budget, buf, 18); + return 0; +} + +static int budget_patch_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + switch (tone) { + case SEC_TONE_ON: + av7110_set22k (budget, 1); + break; + + case SEC_TONE_OFF: + av7110_set22k (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); + + return 0; +} + +static int budget_patch_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + av7110_send_diseqc_msg (budget, 0, NULL, minicmd); + + return 0; +} + +static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (p->frequency + 479500) / 125; + + if (p->frequency > 2000000) + pwr = 3; + else if (p->frequency > 1800000) + pwr = 2; + else if (p->frequency > 1600000) + pwr = 1; + else if (p->frequency > 1200000) + pwr = 0; + else if (p->frequency >= 1100000) + pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, +}; + +static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = p->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, +}; + +static void frontend_init(struct budget_patch* budget) +{ + switch(budget->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x1013: // SATELCO Multimedia PCI + + // try the ALPS BSRV2 first of all + budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_patch_set_tone; + break; + } + + // try the ALPS BSRU6 now + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + + // Try the grundig 29504-451 + budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; + break; + } + break; + } + + if (budget->dvb_frontend == NULL) { + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", + budget->dev->pci->vendor, + budget->dev->pci->device, + budget->dev->pci->subsystem_vendor, + budget->dev->pci->subsystem_device); + } else { + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { + printk("budget-av: Frontend registration failed!\n"); + dvb_frontend_detach(budget->dvb_frontend); + budget->dvb_frontend = NULL; + } + } +} + +/* written by Emard */ +static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct budget_patch *budget; + int err; + int count = 0; + int detected = 0; + +#define PATCH_RESET 0 +#define RPS_IRQ 0 +#define HPS_SETUP 0 +#if PATCH_RESET + saa7146_write(dev, MC1, MASK_31); + msleep(40); +#endif +#if HPS_SETUP + // initialize registers. Better to have it like this + // than leaving something unconfigured + saa7146_write(dev, DD1_STREAM_B, 0); + // port B VSYNC at rising edge + saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too! + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + + // debi config + // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18); + + // zero all HPS registers + saa7146_write(dev, HPS_H_PRESCALE, 0); // r68 + saa7146_write(dev, HPS_H_SCALE, 0); // r6c + saa7146_write(dev, BCS_CTRL, 0); // r70 + saa7146_write(dev, HPS_V_SCALE, 0); // r60 + saa7146_write(dev, HPS_V_GAIN, 0); // r64 + saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74 + saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78 + // Set HPS prescaler for port B input + saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) ); + saa7146_write(dev, MC2, + 0 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 0 * (MASK_10 | MASK_26) | // b + 1 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 1 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); +#endif + // Disable RPS1 and RPS0 + saa7146_write(dev, MC1, ( MASK_29 | MASK_28)); + // RPS1 timeout disable + saa7146_write(dev, RPS_TOV1, 0); + + // code for autodetection + // will wait for VBI_B event (vertical blank at port B) + // and will reset GPIO3 after VBI_B is detected. + // (GPIO3 should be raised high by CPU to + // test if GPIO3 will generate vertical blank signal + // in budget patch GPIO3 is connected to VSYNC_B + count = 0; +#if 0 + WRITE_RPS1(CMD_UPLOAD | + MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ); +#endif + WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + // issue RPS1 interrupt to increment counter + WRITE_RPS1(CMD_INTERRUPT); + // at least a NOP is neede between two interrupts + WRITE_RPS1(CMD_NOP); + // interrupt again + WRITE_RPS1(CMD_INTERRUPT); +#endif + WRITE_RPS1(CMD_STOP); + +#if RPS_IRQ + // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + // set event counter 1 threshold to maximum allowed value (rEC p55) + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + // Enable RPS1, (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); + + + mdelay(50); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(150); + + + if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) + detected = 1; + +#if RPS_IRQ + printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + // Disable RPS1 + saa7146_write(dev, MC1, ( MASK_29 )); + + if(detected == 0) + printk("budget-patch not detected or saa7146 in non-default state.\n" + "try enabling resetting of 7146 with MASK_31 in MC1 register\n"); + + else + printk("BUDGET-PATCH DETECTED.\n"); + + +/* OLD (Original design by Roberto Deza): +** This code will setup the SAA7146_RPS1 to generate a square +** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of +** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; +** then, this GPIO3 output which is connected to the D1B_VSYNC +** input, will trigger the acquisition of the alternate field +** and so on. +** Currently, the TT_budget / WinTV_Nova cards have two ICs +** (74HCT4040, LVC74) for the generation of this VSYNC signal, +** which seems that can be done perfectly without this :-)). +*/ + +/* New design (By Emard) +** this rps1 code will copy internal HS event to GPIO3 pin. +** GPIO3 is in budget-patch hardware connected to port B VSYNC + +** HS is an internal event of 7146, accessible with RPS +** and temporarily raised high every n lines +** (n in defined in the RPS_THRESH1 counter threshold) +** I think HS is raised high on the beginning of the n-th line +** and remains high until this n-th line that triggered +** it is completely received. When the reception of n-th line +** ends, HS is lowered. + +** To transmit data over DMA, 7146 needs changing state at +** port B VSYNC pin. Any changing of port B VSYNC will +** cause some DMA data transfer, with more or less packets loss. +** It depends on the phase and frequency of VSYNC and +** the way of 7146 is instructed to trigger on port B (defined +** in DD1_INIT register, 3rd nibble from the right valid +** numbers are 0-7, see datasheet) +** +** The correct triggering can minimize packet loss, +** dvbtraffic should give this stable bandwidths: +** 22k transponder = 33814 kbit/s +** 27.5k transponder = 38045 kbit/s +** by experiment it is found that the best results +** (stable bandwidths and almost no packet loss) +** are obtained using DD1_INIT triggering number 2 +** (Va at rising edge of VS Fa = HS x VS-failing forced toggle) +** and a VSYNC phase that occurs in the middle of DMA transfer +** (about byte 188*512=96256 in the DMA window). +** +** Phase of HS is still not clear to me how to control, +** It just happens to be so. It can be seen if one enables +** RPS_IRQ and print Event Counter 1 in vpeirq(). Every +** time RPS_INTERRUPT is called, the Event Counter 1 will +** increment. That's how the 7146 is programmed to do event +** counting in this budget-patch.c +** I *think* HPS setting has something to do with the phase +** of HS but I can't be 100% sure in that. + +** hardware debug note: a working budget card (including budget patch) +** with vpeirq() interrupt setup in mode "0x90" (every 64K) will +** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes +** and that means 3*25=75 Hz of interrupt frequency, as seen by +** watch cat /proc/interrupts +** +** If this frequency is 3x lower (and data received in the DMA +** buffer don't start with 0x47, but in the middle of packets, +** whose lengths appear to be like 188 292 188 104 etc. +** this means VSYNC line is not connected in the hardware. +** (check soldering pcb and pins) +** The same behaviour of missing VSYNC can be duplicated on budget +** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. +*/ + + // Setup RPS1 "program" (p35) + count = 0; + + + // Wait Source Line Counter Threshold (p36) + WRITE_RPS1(CMD_PAUSE | EVT_HS); + // Set GPIO3=1 (p42) + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(CMD_INTERRUPT); +#endif + // Wait reset Source Line Counter Threshold (p36) + WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); + // Set GPIO3=0 (p42) + WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + WRITE_RPS1(GPIO3_MSK); + WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(CMD_INTERRUPT); +#endif + // Jump to begin of RPS program (p37) + WRITE_RPS1(CMD_JUMP); + WRITE_RPS1(dev->d_rps1.dma_handle); + + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + + if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) + return -ENOMEM; + + dprintk(2, "budget: %p\n", budget); + + err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); + if (err) { + kfree(budget); + return err; + } + + // Set Source Line Counter Threshold, using BRS (rCC p43) + // It generates HS event every TS_HEIGHT lines + // this is related to TS_WIDTH set in register + // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE + // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 + //,then RPS_THRESH1 + // should be set to trigger every TS_HEIGHT (512) lines. + // + saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); + + // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); + // Enable RPS1 (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + + dev->ext_priv = budget; + + budget->dvb_adapter.priv = budget; + frontend_init(budget); + + ttpci_budget_init_hooks(budget); + + return 0; +} + +static int budget_patch_detach (struct saa7146_dev* dev) +{ + struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; + int err; + + if (budget->dvb_frontend) { + dvb_unregister_frontend(budget->dvb_frontend); + dvb_frontend_detach(budget->dvb_frontend); + } + err = ttpci_budget_deinit (budget); + + kfree (budget); + + return err; +} + +static int __init budget_patch_init(void) +{ + return saa7146_register_extension(&budget_extension); +} + +static void __exit budget_patch_exit(void) +{ + saa7146_unregister_extension(&budget_extension); +} + +static struct saa7146_extension budget_extension = { + .name = "budget_patch dvb", + .flags = 0, + + .module = THIS_MODULE, + .pci_tbl = pci_tbl, + .attach = budget_patch_attach, + .detach = budget_patch_detach, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + +module_init(budget_patch_init); +module_exit(budget_patch_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); +MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 based so-called Budget Patch cards"); diff --git a/drivers/staging/media/av7110/dvb_filter.c b/drivers/staging/media/av7110/dvb_filter.c new file mode 100644 index 000000000000..8c2eca5dcdc9 --- /dev/null +++ b/drivers/staging/media/av7110/dvb_filter.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/string.h> +#include "dvb_filter.h" + +static u32 freq[4] = {480, 441, 320, 0}; + +static unsigned int ac3_bitrates[32] = + {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, + 0,0,0,0,0,0,0,0,0,0,0,0,0}; + +static u32 ac3_frames[3][32] = + {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, + 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, + 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, + 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + +int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) +{ + u8 *headr; + int found = 0; + int c = 0; + u8 frame = 0; + int fr = 0; + + while ( !found && c < count){ + u8 *b = mbuf+c; + + if ( b[0] == 0x0b && b[1] == 0x77 ) + found = 1; + else { + c++; + } + } + + if (!found) return -1; + if (pr) + printk(KERN_DEBUG "Audiostream: AC3"); + + ai->off = c; + if (c+5 >= count) return -1; + + ai->layer = 0; // 0 for AC3 + headr = mbuf+c+2; + + frame = (headr[2]&0x3f); + ai->bit_rate = ac3_bitrates[frame >> 1]*1000; + + if (pr) + printk(KERN_CONT " BRate: %d kb/s", (int) ai->bit_rate/1000); + + ai->frequency = (headr[2] & 0xc0 ) >> 6; + fr = (headr[2] & 0xc0 ) >> 6; + ai->frequency = freq[fr]*100; + if (pr) + printk(KERN_CONT " Freq: %d Hz\n", (int) ai->frequency); + + ai->framesize = ac3_frames[fr][frame >> 1]; + if ((frame & 1) && (fr == 1)) ai->framesize++; + ai->framesize = ai->framesize << 1; + if (pr) + printk(KERN_DEBUG " Framesize %d\n", (int) ai->framesize); + + return 0; +} + +void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv) +{ + unsigned char *buf=p2ts->buf; + + buf[0]=0x47; + buf[1]=(pid>>8); + buf[2]=pid&0xff; + p2ts->cc=0; + p2ts->cb=cb; + p2ts->priv=priv; +} + +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start) +{ + unsigned char *buf=p2ts->buf; + int ret=0, rest; + + //len=6+((pes[4]<<8)|pes[5]); + + if (payload_start) + buf[1]|=0x40; + else + buf[1]&=~0x40; + while (len>=184) { + buf[3]=0x10|((p2ts->cc++)&0x0f); + memcpy(buf+4, pes, 184); + if ((ret=p2ts->cb(p2ts->priv, buf))) + return ret; + len-=184; pes+=184; + buf[1]&=~0x40; + } + if (!len) + return 0; + buf[3]=0x30|((p2ts->cc++)&0x0f); + rest=183-len; + if (rest) { + buf[5]=0x00; + if (rest-1) + memset(buf+6, 0xff, rest-1); + } + buf[4]=rest; + memcpy(buf+5+rest, pes, len); + return p2ts->cb(p2ts->priv, buf); +} diff --git a/drivers/staging/media/av7110/dvb_filter.h b/drivers/staging/media/av7110/dvb_filter.h new file mode 100644 index 000000000000..67a3c6333bca --- /dev/null +++ b/drivers/staging/media/av7110/dvb_filter.h @@ -0,0 +1,242 @@ +/* + * dvb_filter.h + * + * Copyright (C) 2003 Convergence GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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 _DVB_FILTER_H_ +#define _DVB_FILTER_H_ + +#include <linux/slab.h> + +#include <media/demux.h> + +typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); + +struct dvb_filter_pes2ts { + unsigned char buf[188]; + unsigned char cc; + dvb_filter_pes2ts_cb_t *cb; + void *priv; +}; + +void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv); + +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start); + + +#define PROG_STREAM_MAP 0xBC +#define PRIVATE_STREAM1 0xBD +#define PADDING_STREAM 0xBE +#define PRIVATE_STREAM2 0xBF +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define DVB_PICTURE_START 0x00 +#define DVB_USER_START 0xb2 +#define DVB_SEQUENCE_HEADER 0xb3 +#define DVB_SEQUENCE_ERROR 0xb4 +#define DVB_EXTENSION_START 0xb5 +#define DVB_SEQUENCE_END 0xb7 +#define DVB_GOP_START 0xb8 +#define DVB_EXCEPT_SLICE 0xb0 + +#define SEQUENCE_EXTENSION 0x01 +#define SEQUENCE_DISPLAY_EXTENSION 0x02 +#define PICTURE_CODING_EXTENSION 0x08 +#define QUANT_MATRIX_EXTENSION 0x03 +#define PICTURE_DISPLAY_EXTENSION 0x07 + +#define I_FRAME 0x01 +#define B_FRAME 0x02 +#define P_FRAME 0x03 + +/* Initialize sequence_data */ +#define INIT_HORIZONTAL_SIZE 720 +#define INIT_VERTICAL_SIZE 576 +#define INIT_ASPECT_RATIO 0x02 +#define INIT_FRAME_RATE 0x03 +#define INIT_DISP_HORIZONTAL_SIZE 540 +#define INIT_DISP_VERTICAL_SIZE 576 + + +//flags2 +#define PTS_DTS_FLAGS 0xC0 +#define ESCR_FLAG 0x20 +#define ES_RATE_FLAG 0x10 +#define DSM_TRICK_FLAG 0x08 +#define ADD_CPY_FLAG 0x04 +#define PES_CRC_FLAG 0x02 +#define PES_EXT_FLAG 0x01 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 + +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +#define MAX_PLENGTH 0xFFFF +#define MMAX_PLENGTH (256*MAX_PLENGTH) + +#ifndef IPACKS +#define IPACKS 2048 +#endif + +struct ipack { + int size; + int found; + u8 *buf; + u8 cid; + u32 plength; + u8 plen[2]; + u8 flag1; + u8 flag2; + u8 hlength; + u8 pts[5]; + u16 *pid; + int mpeg; + u8 check; + int which; + int done; + void *data; + void (*func)(u8 *buf, int size, void *priv); + int count; + int repack_subids; +}; + +struct dvb_video_info { + u32 horizontal_size; + u32 vertical_size; + u32 aspect_ratio; + u32 framerate; + u32 video_format; + u32 bit_rate; + u32 comp_bit_rate; + u32 vbv_buffer_size; + s16 vbv_delay; + u32 CSPF; + u32 off; +}; + +#define OFF_SIZE 4 +#define FIRST_FIELD 0 +#define SECOND_FIELD 1 +#define VIDEO_FRAME_PICTURE 0x03 + +struct mpg_picture { + int channel; + struct dvb_video_info vinfo; + u32 *sequence_gop_header; + u32 *picture_header; + s32 time_code; + int low_delay; + int closed_gop; + int broken_link; + int sequence_header_flag; + int gop_flag; + int sequence_end_flag; + + u8 profile_and_level; + s32 picture_coding_parameter; + u32 matrix[32]; + s8 matrix_change_flag; + + u8 picture_header_parameter; + /* bit 0 - 2: bwd f code + bit 3 : fpb vector + bit 4 - 6: fwd f code + bit 7 : fpf vector */ + + int mpeg1_flag; + int progressive_sequence; + int sequence_display_extension_flag; + u32 sequence_header_data; + s16 last_frame_centre_horizontal_offset; + s16 last_frame_centre_vertical_offset; + + u32 pts[2]; /* [0] 1st field, [1] 2nd field */ + int top_field_first; + int repeat_first_field; + int progressive_frame; + int bank; + int forward_bank; + int backward_bank; + int compress; + s16 frame_centre_horizontal_offset[OFF_SIZE]; + /* [0-2] 1st field, [3] 2nd field */ + s16 frame_centre_vertical_offset[OFF_SIZE]; + /* [0-2] 1st field, [3] 2nd field */ + s16 temporal_reference[2]; + /* [0] 1st field, [1] 2nd field */ + + s8 picture_coding_type[2]; + /* [0] 1st field, [1] 2nd field */ + s8 picture_structure[2]; + /* [0] 1st field, [1] 2nd field */ + s8 picture_display_extension_flag[2]; + /* [0] 1st field, [1] 2nd field */ + /* picture_display_extenion() 0:no 1:exit*/ + s8 pts_flag[2]; + /* [0] 1st field, [1] 2nd field */ +}; + +struct dvb_audio_info { + int layer; + u32 bit_rate; + u32 frequency; + u32 mode; + u32 mode_extension ; + u32 emphasis; + u32 framesize; + u32 off; +}; + +int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr); + + +#endif diff --git a/drivers/staging/media/av7110/osd.h b/drivers/staging/media/av7110/osd.h new file mode 100644 index 000000000000..858997c74043 --- /dev/null +++ b/drivers/staging/media/av7110/osd.h @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ +/* + * osd.h - DEPRECATED On Screen Display API + * + * NOTE: should not be used on future drivers + * + * Copyright (C) 2001 Ralph Metzler <ralph@convergence.de> + * & Marcus Metzler <marcus@convergence.de> + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Lesser Public License + * as published by the Free Software Foundation; either version 2.1 + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _DVBOSD_H_ +#define _DVBOSD_H_ + +#include <linux/compiler.h> + +typedef enum { + /* All functions return -2 on "not open" */ + OSD_Close = 1, /* () */ + /* + * Disables OSD and releases the buffers + * returns 0 on success + */ + OSD_Open, /* (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) */ + /* + * Opens OSD with this size and bit depth + * returns 0 on success, -1 on DRAM allocation error, -2 on "already open" + */ + OSD_Show, /* () */ + /* + * enables OSD mode + * returns 0 on success + */ + OSD_Hide, /* () */ + /* + * disables OSD mode + * returns 0 on success + */ + OSD_Clear, /* () */ + /* + * Sets all pixel to color 0 + * returns 0 on success + */ + OSD_Fill, /* (color) */ + /* + * Sets all pixel to color <col> + * returns 0 on success + */ + OSD_SetColor, /* (color,R{x0},G{y0},B{x1},opacity{y1}) */ + /* + * set palette entry <num> to <r,g,b>, <mix> and <trans> apply + * R,G,B: 0..255 + * R=Red, G=Green, B=Blue + * opacity=0: pixel opacity 0% (only video pixel shows) + * opacity=1..254: pixel opacity as specified in header + * opacity=255: pixel opacity 100% (only OSD pixel shows) + * returns 0 on success, -1 on error + */ + OSD_SetPalette, /* (firstcolor{color},lastcolor{x0},data) */ + /* + * Set a number of entries in the palette + * sets the entries "firstcolor" through "lastcolor" from the array "data" + * data has 4 byte for each color: + * R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel + */ + OSD_SetTrans, /* (transparency{color}) */ + /* + * Sets transparency of mixed pixel (0..15) + * returns 0 on success + */ + OSD_SetPixel, /* (x0,y0,color) */ + /* + * sets pixel <x>,<y> to color number <col> + * returns 0 on success, -1 on error + */ + OSD_GetPixel, /* (x0,y0) */ + /* returns color number of pixel <x>,<y>, or -1 */ + OSD_SetRow, /* (x0,y0,x1,data) */ + /* + * fills pixels x0,y through x1,y with the content of data[] + * returns 0 on success, -1 on clipping all pixel (no pixel drawn) + */ + OSD_SetBlock, /* (x0,y0,x1,y1,increment{color},data) */ + /* + * fills pixels x0,y0 through x1,y1 with the content of data[] + * inc contains the width of one line in the data block, + * inc<=0 uses blockwidth as linewidth + * returns 0 on success, -1 on clipping all pixel + */ + OSD_FillRow, /* (x0,y0,x1,color) */ + /* + * fills pixels x0,y through x1,y with the color <col> + * returns 0 on success, -1 on clipping all pixel + */ + OSD_FillBlock, /* (x0,y0,x1,y1,color) */ + /* + * fills pixels x0,y0 through x1,y1 with the color <col> + * returns 0 on success, -1 on clipping all pixel + */ + OSD_Line, /* (x0,y0,x1,y1,color) */ + /* + * draw a line from x0,y0 to x1,y1 with the color <col> + * returns 0 on success + */ + OSD_Query, /* (x0,y0,x1,y1,xasp{color}}), yasp=11 */ + /* + * fills parameters with the picture dimensions and the pixel aspect ratio + * returns 0 on success + */ + OSD_Test, /* () */ + /* + * draws a test picture. for debugging purposes only + * returns 0 on success + * TODO: remove "test" in final version + */ + OSD_Text, /* (x0,y0,size,color,text) */ + OSD_SetWindow, /* (x0) set window with number 0<x0<8 as current */ + OSD_MoveWindow, /* move current window to (x0, y0) */ + OSD_OpenRaw, /* Open other types of OSD windows */ +} OSD_Command; + +typedef struct osd_cmd_s { + OSD_Command cmd; + int x0; + int y0; + int x1; + int y1; + int color; + void __user *data; +} osd_cmd_t; + +/* OSD_OpenRaw: set 'color' to desired window type */ +typedef enum { + OSD_BITMAP1, /* 1 bit bitmap */ + OSD_BITMAP2, /* 2 bit bitmap */ + OSD_BITMAP4, /* 4 bit bitmap */ + OSD_BITMAP8, /* 8 bit bitmap */ + OSD_BITMAP1HR, /* 1 Bit bitmap half resolution */ + OSD_BITMAP2HR, /* 2 bit bitmap half resolution */ + OSD_BITMAP4HR, /* 4 bit bitmap half resolution */ + OSD_BITMAP8HR, /* 8 bit bitmap half resolution */ + OSD_YCRCB422, /* 4:2:2 YCRCB Graphic Display */ + OSD_YCRCB444, /* 4:4:4 YCRCB Graphic Display */ + OSD_YCRCB444HR, /* 4:4:4 YCRCB graphic half resolution */ + OSD_VIDEOTSIZE, /* True Size Normal MPEG Video Display */ + OSD_VIDEOHSIZE, /* MPEG Video Display Half Resolution */ + OSD_VIDEOQSIZE, /* MPEG Video Display Quarter Resolution */ + OSD_VIDEODSIZE, /* MPEG Video Display Double Resolution */ + OSD_VIDEOTHSIZE, /* True Size MPEG Video Display Half Resolution */ + OSD_VIDEOTQSIZE, /* True Size MPEG Video Display Quarter Resolution*/ + OSD_VIDEOTDSIZE, /* True Size MPEG Video Display Double Resolution */ + OSD_VIDEONSIZE, /* Full Size MPEG Video Display */ + OSD_CURSOR /* Cursor */ +} osd_raw_window_t; + +typedef struct osd_cap_s { + int cmd; +#define OSD_CAP_MEMSIZE 1 /* memory size */ + long val; +} osd_cap_t; + + +#define OSD_SEND_CMD _IOW('o', 160, osd_cmd_t) +#define OSD_GET_CAPABILITY _IOR('o', 161, osd_cap_t) + +#endif diff --git a/drivers/staging/media/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c new file mode 100644 index 000000000000..9767159aeb9b --- /dev/null +++ b/drivers/staging/media/av7110/sp8870.c @@ -0,0 +1,609 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + Driver for Spase SP8870 demodulator + + Copyright (C) 1999 Juergen Peitz + + +*/ +/* + * This driver needs external firmware. Please use the command + * "<kerneldir>/scripts/get_dvb_firmware alps_tdlb7" to + * download/extract it, and then copy it to /usr/lib/hotplug/firmware + * or /lib/firmware (depending on configuration of firmware hotplug). + */ +#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> + +#include <media/dvb_frontend.h> +#include "sp8870.h" + + +struct sp8870_state { + + struct i2c_adapter* i2c; + + const struct sp8870_config* config; + + struct dvb_frontend frontend; + + /* demodulator private data */ + u8 initialised:1; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "sp8870: " args); \ + } while (0) + +/* firmware size for sp8870 */ +#define SP8870_FIRMWARE_SIZE 16382 + +/* starting point for firmware in file 'Sc_main.mc' */ +#define SP8870_FIRMWARE_OFFSET 0x0A + +static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data) +{ + u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 }; + int err; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static int sp8870_readreg (struct sp8870_state* state, u16 reg) +{ + int ret; + u8 b0 [] = { reg >> 8 , reg & 0xff }; + u8 b1 [] = { 0, 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) { + dprintk("%s: readreg error (ret == %i)\n", __func__, ret); + return -1; + } + + return (b1[0] << 8 | b1[1]); +} + +static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw) +{ + struct i2c_msg msg; + const char *fw_buf = fw->data; + int fw_pos; + u8 tx_buf[255]; + int tx_len; + int err = 0; + + dprintk ("%s: ...\n", __func__); + + if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET) + return -EINVAL; + + // system controller stop + sp8870_writereg(state, 0x0F00, 0x0000); + + // instruction RAM register hiword + sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF)); + + // instruction RAM MWR + sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16)); + + // do firmware upload + fw_pos = SP8870_FIRMWARE_OFFSET; + while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){ + tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos; + // write register 0xCF0A + tx_buf[0] = 0xCF; + tx_buf[1] = 0x0A; + memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len); + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.buf = tx_buf; + msg.len = tx_len + 2; + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk("%s: firmware upload failed!\n", __func__); + printk ("%s: i2c error (err == %i)\n", __func__, err); + return err; + } + fw_pos += tx_len; + } + + dprintk ("%s: done!\n", __func__); + return 0; +}; + +static void sp8870_microcontroller_stop (struct sp8870_state* state) +{ + sp8870_writereg(state, 0x0F08, 0x000); + sp8870_writereg(state, 0x0F09, 0x000); + + // microcontroller STOP + sp8870_writereg(state, 0x0F00, 0x000); +} + +static void sp8870_microcontroller_start (struct sp8870_state* state) +{ + sp8870_writereg(state, 0x0F08, 0x000); + sp8870_writereg(state, 0x0F09, 0x000); + + // microcontroller START + sp8870_writereg(state, 0x0F00, 0x001); + // not documented but if we don't read 0x0D01 out here + // we don't get a correct data valid signal + sp8870_readreg(state, 0x0D01); +} + +static int sp8870_read_data_valid_signal(struct sp8870_state* state) +{ + return (sp8870_readreg(state, 0x0D02) > 0); +} + +static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) +{ + int known_parameters = 1; + + *reg0xc05 = 0x000; + + switch (p->modulation) { + case QPSK: + break; + case QAM_16: + *reg0xc05 |= (1 << 10); + break; + case QAM_64: + *reg0xc05 |= (2 << 10); + break; + case QAM_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + } + + switch (p->hierarchy) { + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + *reg0xc05 |= (1 << 7); + break; + case HIERARCHY_2: + *reg0xc05 |= (2 << 7); + break; + case HIERARCHY_4: + *reg0xc05 |= (3 << 7); + break; + case HIERARCHY_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + } + + switch (p->code_rate_HP) { + case FEC_1_2: + break; + case FEC_2_3: + *reg0xc05 |= (1 << 3); + break; + case FEC_3_4: + *reg0xc05 |= (2 << 3); + break; + case FEC_5_6: + *reg0xc05 |= (3 << 3); + break; + case FEC_7_8: + *reg0xc05 |= (4 << 3); + break; + case FEC_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + } + + if (known_parameters) + *reg0xc05 |= (2 << 1); /* use specified parameters */ + else + *reg0xc05 |= (1 << 1); /* enable autoprobing */ + + return 0; +} + +static int sp8870_wake_up(struct sp8870_state* state) +{ + // enable TS output and interface pins + return sp8870_writereg(state, 0xC18, 0x00D); +} + +static int sp8870_set_frontend_parameters(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct sp8870_state* state = fe->demodulator_priv; + int err; + u16 reg0xc05; + + if ((err = configure_reg0xc05(p, ®0xc05))) + return err; + + // system controller stop + sp8870_microcontroller_stop(state); + + // set tuner parameters + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + + // sample rate correction bit [23..17] + sp8870_writereg(state, 0x0319, 0x000A); + + // sample rate correction bit [16..0] + sp8870_writereg(state, 0x031A, 0x0AAB); + + // integer carrier offset + sp8870_writereg(state, 0x0309, 0x0400); + + // fractional carrier offset + sp8870_writereg(state, 0x030A, 0x0000); + + // filter for 6/7/8 Mhz channel + if (p->bandwidth_hz == 6000000) + sp8870_writereg(state, 0x0311, 0x0002); + else if (p->bandwidth_hz == 7000000) + sp8870_writereg(state, 0x0311, 0x0001); + else + sp8870_writereg(state, 0x0311, 0x0000); + + // scan order: 2k first = 0x0000, 8k first = 0x0001 + if (p->transmission_mode == TRANSMISSION_MODE_2K) + sp8870_writereg(state, 0x0338, 0x0000); + else + sp8870_writereg(state, 0x0338, 0x0001); + + sp8870_writereg(state, 0xc05, reg0xc05); + + // read status reg in order to clear pending irqs + err = sp8870_readreg(state, 0x200); + if (err < 0) + return err; + + // system controller start + sp8870_microcontroller_start(state); + + return 0; +} + +static int sp8870_init (struct dvb_frontend* fe) +{ + struct sp8870_state* state = fe->demodulator_priv; + const struct firmware *fw = NULL; + + sp8870_wake_up(state); + if (state->initialised) return 0; + state->initialised = 1; + + dprintk ("%s\n", __func__); + + + /* request the firmware, this will block until someone uploads it */ + printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE); + if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) { + printk("sp8870: no firmware upload (timeout or file not found?)\n"); + return -EIO; + } + + if (sp8870_firmware_upload(state, fw)) { + printk("sp8870: writing firmware to device failed\n"); + release_firmware(fw); + return -EIO; + } + release_firmware(fw); + printk("sp8870: firmware upload complete\n"); + + /* enable TS output and interface pins */ + sp8870_writereg(state, 0xc18, 0x00d); + + // system controller stop + sp8870_microcontroller_stop(state); + + // ADC mode + sp8870_writereg(state, 0x0301, 0x0003); + + // Reed Solomon parity bytes passed to output + sp8870_writereg(state, 0x0C13, 0x0001); + + // MPEG clock is suppressed if no valid data + sp8870_writereg(state, 0x0C14, 0x0001); + + /* bit 0x010: enable data valid signal */ + sp8870_writereg(state, 0x0D00, 0x010); + sp8870_writereg(state, 0x0D01, 0x000); + + return 0; +} + +static int sp8870_read_status(struct dvb_frontend *fe, + enum fe_status *fe_status) +{ + struct sp8870_state* state = fe->demodulator_priv; + int status; + int signal; + + *fe_status = 0; + + status = sp8870_readreg (state, 0x0200); + if (status < 0) + return -EIO; + + signal = sp8870_readreg (state, 0x0303); + if (signal < 0) + return -EIO; + + if (signal > 0x0F) + *fe_status |= FE_HAS_SIGNAL; + if (status & 0x08) + *fe_status |= FE_HAS_SYNC; + if (status & 0x04) + *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI; + + return 0; +} + +static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) +{ + struct sp8870_state* state = fe->demodulator_priv; + int ret; + u32 tmp; + + *ber = 0; + + ret = sp8870_readreg(state, 0xC08); + if (ret < 0) + return -EIO; + + tmp = ret & 0x3F; + + ret = sp8870_readreg(state, 0xC07); + if (ret < 0) + return -EIO; + + tmp = ret << 6; + if (tmp >= 0x3FFF0) + tmp = ~0; + + *ber = tmp; + + return 0; +} + +static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal) +{ + struct sp8870_state* state = fe->demodulator_priv; + int ret; + u16 tmp; + + *signal = 0; + + ret = sp8870_readreg (state, 0x306); + if (ret < 0) + return -EIO; + + tmp = ret << 8; + + ret = sp8870_readreg (state, 0x303); + if (ret < 0) + return -EIO; + + tmp |= ret; + + if (tmp) + *signal = 0xFFFF - tmp; + + return 0; +} + +static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks) +{ + struct sp8870_state* state = fe->demodulator_priv; + int ret; + + *ublocks = 0; + + ret = sp8870_readreg(state, 0xC0C); + if (ret < 0) + return -EIO; + + if (ret == 0xFFFF) + ret = ~0; + + *ublocks = ret; + + return 0; +} + +/* number of trials to recover from lockup */ +#define MAXTRIALS 5 +/* maximum checks for data valid signal */ +#define MAXCHECKS 100 + +/* only for debugging: counter for detected lockups */ +static int lockups; +/* only for debugging: counter for channel switches */ +static int switches; + +static int sp8870_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct sp8870_state* state = fe->demodulator_priv; + + /* + The firmware of the sp8870 sometimes locks up after setting frontend parameters. + We try to detect this by checking the data valid signal. + If it is not set after MAXCHECKS we try to recover the lockup by setting + the frontend parameters again. + */ + + int err = 0; + int valid = 0; + int trials = 0; + int check_count = 0; + + dprintk("%s: frequency = %i\n", __func__, p->frequency); + + for (trials = 1; trials <= MAXTRIALS; trials++) { + + err = sp8870_set_frontend_parameters(fe); + if (err) + return err; + + for (check_count = 0; check_count < MAXCHECKS; check_count++) { +// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0); + valid = sp8870_read_data_valid_signal(state); + if (valid) { + dprintk("%s: delay = %i usec\n", + __func__, check_count * 10); + break; + } + udelay(10); + } + if (valid) + break; + } + + if (!valid) { + printk("%s: firmware crash!!!!!!\n", __func__); + return -EIO; + } + + if (debug) { + if (valid) { + if (trials > 1) { + printk("%s: firmware lockup!!!\n", __func__); + printk("%s: recovered after %i trial(s))\n", __func__, trials - 1); + lockups++; + } + } + switches++; + printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups); + } + + return 0; +} + +static int sp8870_sleep(struct dvb_frontend* fe) +{ + struct sp8870_state* state = fe->demodulator_priv; + + // tristate TS output and disable interface pins + return sp8870_writereg(state, 0xC18, 0x000); +} + +static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 350; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct sp8870_state* state = fe->demodulator_priv; + + if (enable) { + return sp8870_writereg(state, 0x206, 0x001); + } else { + return sp8870_writereg(state, 0x206, 0x000); + } +} + +static void sp8870_release(struct dvb_frontend* fe) +{ + struct sp8870_state* state = fe->demodulator_priv; + kfree(state); +} + +static const struct dvb_frontend_ops sp8870_ops; + +struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c) +{ + struct sp8870_state* state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->initialised = 0; + + /* check if the demod is there */ + if (sp8870_readreg(state, 0x0200) < 0) goto error; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} + +static const struct dvb_frontend_ops sp8870_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Spase SP8870 DVB-T", + .frequency_min_hz = 470 * MHz, + .frequency_max_hz = 860 * MHz, + .frequency_stepsize_hz = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER + }, + + .release = sp8870_release, + + .init = sp8870_init, + .sleep = sp8870_sleep, + .i2c_gate_ctrl = sp8870_i2c_gate_ctrl, + + .set_frontend = sp8870_set_frontend, + .get_tune_settings = sp8870_get_tune_settings, + + .read_status = sp8870_read_status, + .read_ber = sp8870_read_ber, + .read_signal_strength = sp8870_read_signal_strength, + .read_ucblocks = sp8870_read_uncorrected_blocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver"); +MODULE_AUTHOR("Juergen Peitz"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(sp8870_attach); diff --git a/drivers/staging/media/av7110/sp8870.h b/drivers/staging/media/av7110/sp8870.h new file mode 100644 index 000000000000..5eacf39f425e --- /dev/null +++ b/drivers/staging/media/av7110/sp8870.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + Driver for Spase SP8870 demodulator + + Copyright (C) 1999 Juergen Peitz + + +*/ + +#ifndef SP8870_H +#define SP8870_H + +#include <linux/dvb/frontend.h> +#include <linux/firmware.h> + +struct sp8870_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +#if IS_REACHABLE(CONFIG_DVB_SP8870) +extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c); +#else +static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif // CONFIG_DVB_SP8870 + +#endif // SP8870_H diff --git a/drivers/staging/media/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst new file mode 100644 index 000000000000..a7730559bbb2 --- /dev/null +++ b/drivers/staging/media/av7110/video-clear-buffer.rst @@ -0,0 +1,54 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_CLEAR_BUFFER: + +================== +VIDEO_CLEAR_BUFFER +================== + +Name +---- + +VIDEO_CLEAR_BUFFER + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_CLEAR_BUFFER + +``int ioctl(fd, VIDEO_CLEAR_BUFFER)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_CLEAR_BUFFER for this command. + +Description +----------- + +This ioctl call clears all video buffers in the driver and in the +decoder hardware. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst new file mode 100644 index 000000000000..cae9445eb3af --- /dev/null +++ b/drivers/staging/media/av7110/video-command.rst @@ -0,0 +1,96 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_COMMAND: + +============= +VIDEO_COMMAND +============= + +Name +---- + +VIDEO_COMMAND + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_COMMAND + +``int ioctl(int fd, VIDEO_COMMAND, struct video_command *cmd)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_COMMAND for this command. + + - .. row 3 + + - struct video_command \*cmd + + - Commands the decoder. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the +:ref:`VIDIOC_DECODER_CMD` ioctl. + +This ioctl commands the decoder. The ``video_command`` struct is a +subset of the ``v4l2_decoder_cmd`` struct, so refer to the +:ref:`VIDIOC_DECODER_CMD` documentation for +more information. + +.. c:type:: video_command + +.. code-block:: c + + /* The structure must be zeroed before use by the application + This ensures it can be extended safely in the future. */ + struct video_command { + __u32 cmd; + __u32 flags; + union { + struct { + __u64 pts; + } stop; + + struct { + /* 0 or 1000 specifies normal speed, + 1 specifies forward single stepping, + -1 specifies backward single stepping, + >1: playback at speed/1000 of the normal speed, + <-1: reverse playback at (-speed/1000) of the normal speed. */ + __s32 speed; + __u32 format; + } play; + + struct { + __u32 data[16]; + } raw; + }; + }; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst new file mode 100644 index 000000000000..bc34bf3989e4 --- /dev/null +++ b/drivers/staging/media/av7110/video-continue.rst @@ -0,0 +1,57 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_CONTINUE: + +============== +VIDEO_CONTINUE +============== + +Name +---- + +VIDEO_CONTINUE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_CONTINUE + +``int ioctl(fd, VIDEO_CONTINUE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_CONTINUE for this command. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call restarts decoding and playing processes of the video +stream which was played before a call to VIDEO_FREEZE was made. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst new file mode 100644 index 000000000000..e71fa8d6965b --- /dev/null +++ b/drivers/staging/media/av7110/video-fast-forward.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_FAST_FORWARD: + +================== +VIDEO_FAST_FORWARD +================== + +Name +---- + +VIDEO_FAST_FORWARD + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_FAST_FORWARD + +``int ioctl(fd, VIDEO_FAST_FORWARD, int nFrames)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_FAST_FORWARD for this command. + + - .. row 3 + + - int nFrames + + - The number of frames to skip. + +Description +----------- + +This ioctl call asks the Video Device to skip decoding of N number of +I-frames. This call can only be used if VIDEO_SOURCE_MEMORY is +selected. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/drivers/staging/media/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst new file mode 100644 index 000000000000..01d24d548439 --- /dev/null +++ b/drivers/staging/media/av7110/video-fclose.rst @@ -0,0 +1,51 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _video_fclose: + +================= +dvb video close() +================= + +Name +---- + +dvb video close() + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:function:: int close(int fd) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + +Description +----------- + +This system call closes a previously opened video device. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst new file mode 100644 index 000000000000..1371b083e4e8 --- /dev/null +++ b/drivers/staging/media/av7110/video-fopen.rst @@ -0,0 +1,111 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _video_fopen: + +================ +dvb video open() +================ + +Name +---- + +dvb video open() + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:function:: int open(const char *deviceName, int flags) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - const char \*deviceName + + - Name of specific video device. + + - .. row 2 + + - int flags + + - A bit-wise OR of the following flags: + + - .. row 3 + + - + - O_RDONLY read-only access + + - .. row 4 + + - + - O_RDWR read/write access + + - .. row 5 + + - + - O_NONBLOCK open in non-blocking mode + + - .. row 6 + + - + - (blocking mode is the default) + +Description +----------- + +This system call opens a named video device (e.g. +/dev/dvb/adapter0/video0) for subsequent use. + +When an open() call has succeeded, the device will be ready for use. The +significance of blocking or non-blocking mode is described in the +documentation for functions where there is a difference. It does not +affect the semantics of the open() call itself. A device opened in +blocking mode can later be put into non-blocking mode (and vice versa) +using the F_SETFL command of the fcntl system call. This is a standard +system call, documented in the Linux manual page for fcntl. Only one +user can open the Video Device in O_RDWR mode. All other attempts to +open the device in this mode will fail, and an error-code will be +returned. If the Video Device is opened in O_RDONLY mode, the only +ioctl call that can be used is VIDEO_GET_STATUS. All other call will +return an error code. + +Return Value +------------ + +.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``ENODEV`` + + - Device driver not loaded/available. + + - .. row 2 + + - ``EINTERNAL`` + + - Internal error. + + - .. row 3 + + - ``EBUSY`` + + - Device or resource busy. + + - .. row 4 + + - ``EINVAL`` + + - Invalid argument. diff --git a/drivers/staging/media/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst new file mode 100644 index 000000000000..4321f257cb70 --- /dev/null +++ b/drivers/staging/media/av7110/video-freeze.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_FREEZE: + +============ +VIDEO_FREEZE +============ + +Name +---- + +VIDEO_FREEZE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_FREEZE + +``int ioctl(fd, VIDEO_FREEZE)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_FREEZE for this command. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call suspends the live video stream being played. Decoding +and playing are frozen. It is then possible to restart the decoding and +playing process of the video stream using the VIDEO_CONTINUE command. +If VIDEO_SOURCE_MEMORY is selected in the ioctl call +VIDEO_SELECT_SOURCE, the Digital TV subsystem will not decode any more data +until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst new file mode 100644 index 000000000000..a07fd7d7a40e --- /dev/null +++ b/drivers/staging/media/av7110/video-fwrite.rst @@ -0,0 +1,79 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _video_fwrite: + +================= +dvb video write() +================= + +Name +---- + +dvb video write() + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:function:: size_t write(int fd, const void *buf, size_t count) + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - void \*buf + + - Pointer to the buffer containing the PES data. + + - .. row 3 + + - size_t count + + - Size of buf. + +Description +----------- + +This system call can only be used if VIDEO_SOURCE_MEMORY is selected +in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in +PES format, unless the capability allows other formats. If O_NONBLOCK +is not specified the function will block until buffer space is +available. The amount of data to be transferred is implied by count. + +Return Value +------------ + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode VIDEO_SOURCE_MEMORY not selected. + + - .. row 2 + + - ``ENOMEM`` + + - Attempted to write more data than the internal buffer can hold. + + - .. row 3 + + - ``EBADF`` + + - fd is not a valid open file descriptor. diff --git a/drivers/staging/media/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst new file mode 100644 index 000000000000..01e09f56656c --- /dev/null +++ b/drivers/staging/media/av7110/video-get-capabilities.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_CAPABILITIES: + +====================== +VIDEO_GET_CAPABILITIES +====================== + +Name +---- + +VIDEO_GET_CAPABILITIES + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_CAPABILITIES + +``int ioctl(fd, VIDEO_GET_CAPABILITIES, unsigned int *cap)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_CAPABILITIES for this command. + + - .. row 3 + + - unsigned int \*cap + + - Pointer to a location where to store the capability information. + +Description +----------- + +This ioctl call asks the video device about its decoding capabilities. +On success it returns and integer which has bits set according to the +defines in section ??. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst new file mode 100644 index 000000000000..90382bc36cfe --- /dev/null +++ b/drivers/staging/media/av7110/video-get-event.rst @@ -0,0 +1,105 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_EVENT: + +=============== +VIDEO_GET_EVENT +=============== + +Name +---- + +VIDEO_GET_EVENT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_EVENT + +``int ioctl(fd, VIDEO_GET_EVENT, struct video_event *ev)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_EVENT for this command. + + - .. row 3 + + - struct video_event \*ev + + - Points to the location where the event, if any, is to be stored. + +Description +----------- + +This ioctl is for Digital TV devices only. To get events from a V4L2 decoder +use the V4L2 :ref:`VIDIOC_DQEVENT` ioctl instead. + +This ioctl call returns an event of type video_event if available. If +an event is not available, the behavior depends on whether the device is +in blocking or non-blocking mode. In the latter case, the call fails +immediately with errno set to ``EWOULDBLOCK``. In the former case, the call +blocks until an event becomes available. The standard Linux poll() +and/or select() system calls can be used with the device file descriptor +to watch for new events. For select(), the file descriptor should be +included in the exceptfds argument, and for poll(), POLLPRI should be +specified as the wake-up condition. Read-only permissions are sufficient +for this ioctl call. + +.. c:type:: video_event + +.. code-block:: c + + struct video_event { + __s32 type; + #define VIDEO_EVENT_SIZE_CHANGED 1 + #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 + #define VIDEO_EVENT_DECODER_STOPPED 3 + #define VIDEO_EVENT_VSYNC 4 + long timestamp; + union { + video_size_t size; + unsigned int frame_rate; /* in frames per 1000sec */ + unsigned char vsync_field; /* unknown/odd/even/progressive */ + } u; + }; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EWOULDBLOCK`` + + - There is no event pending, and the device is in non-blocking mode. + + - .. row 2 + + - ``EOVERFLOW`` + + - Overflow in event queue - one or more events were lost. diff --git a/drivers/staging/media/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst new file mode 100644 index 000000000000..b48ac8c58a41 --- /dev/null +++ b/drivers/staging/media/av7110/video-get-frame-count.rst @@ -0,0 +1,65 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_FRAME_COUNT: + +===================== +VIDEO_GET_FRAME_COUNT +===================== + +Name +---- + +VIDEO_GET_FRAME_COUNT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_FRAME_COUNT + +``int ioctl(int fd, VIDEO_GET_FRAME_COUNT, __u64 *pts)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_FRAME_COUNT for this command. + + - .. row 3 + + - __u64 \*pts + + - Returns the number of frames displayed since the decoder was + started. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_FRAME`` +control. + +This ioctl call asks the Video Device to return the number of displayed +frames since the decoder was started. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst new file mode 100644 index 000000000000..fedaff41be0b --- /dev/null +++ b/drivers/staging/media/av7110/video-get-pts.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_PTS: + +============= +VIDEO_GET_PTS +============= + +Name +---- + +VIDEO_GET_PTS + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_PTS + +``int ioctl(int fd, VIDEO_GET_PTS, __u64 *pts)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_PTS for this command. + + - .. row 3 + + - __u64 \*pts + + - Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / + ISO/IEC 13818-1. + + The PTS should belong to the currently played frame if possible, + but may also be a value close to it like the PTS of the last + decoded frame or the last PTS extracted by the PES parser. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_PTS`` +control. + +This ioctl call asks the Video Device to return the current PTS +timestamp. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst new file mode 100644 index 000000000000..de34331c5bd1 --- /dev/null +++ b/drivers/staging/media/av7110/video-get-size.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_SIZE: + +============== +VIDEO_GET_SIZE +============== + +Name +---- + +VIDEO_GET_SIZE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_SIZE + +``int ioctl(int fd, VIDEO_GET_SIZE, video_size_t *size)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_SIZE for this command. + + - .. row 3 + + - video_size_t \*size + + - Returns the size and aspect ratio. + +Description +----------- + +This ioctl returns the size and aspect ratio. + +.. c:type:: video_size_t + +.. code-block::c + + typedef struct { + int w; + int h; + video_format_t aspect_ratio; + } video_size_t; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst new file mode 100644 index 000000000000..9b86fbf411d4 --- /dev/null +++ b/drivers/staging/media/av7110/video-get-status.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_GET_STATUS: + +================ +VIDEO_GET_STATUS +================ + +Name +---- + +VIDEO_GET_STATUS + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_GET_STATUS + +``int ioctl(fd, VIDEO_GET_STATUS, struct video_status *status)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_GET_STATUS for this command. + + - .. row 3 + + - struct video_status \*status + + - Returns the current status of the Video Device. + +Description +----------- + +This ioctl call asks the Video Device to return the current status of +the device. + +.. c:type:: video_status + +.. code-block:: c + + struct video_status { + int video_blank; /* blank video on freeze? */ + video_play_state_t play_state; /* current state of playback */ + video_stream_source_t stream_source; /* current source (demux/memory) */ + video_format_t video_format; /* current aspect ratio of stream*/ + video_displayformat_t display_format;/* selected cropping mode */ + }; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst new file mode 100644 index 000000000000..35ac8b98fdbf --- /dev/null +++ b/drivers/staging/media/av7110/video-play.rst @@ -0,0 +1,57 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_PLAY: + +========== +VIDEO_PLAY +========== + +Name +---- + +VIDEO_PLAY + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_PLAY + +``int ioctl(fd, VIDEO_PLAY)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_PLAY for this command. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call asks the Video Device to start playing a video stream +from the selected source. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst new file mode 100644 index 000000000000..929a20985d53 --- /dev/null +++ b/drivers/staging/media/av7110/video-select-source.rst @@ -0,0 +1,76 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SELECT_SOURCE: + +=================== +VIDEO_SELECT_SOURCE +=================== + +Name +---- + +VIDEO_SELECT_SOURCE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SELECT_SOURCE + +``int ioctl(fd, VIDEO_SELECT_SOURCE, video_stream_source_t source)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SELECT_SOURCE for this command. + + - .. row 3 + + - video_stream_source_t source + + - Indicates which source shall be used for the Video stream. + +Description +----------- + +This ioctl is for Digital TV devices only. This ioctl was also supported by the +V4L2 ivtv driver, but that has been replaced by the ivtv-specific +``IVTV_IOC_PASSTHROUGH_MODE`` ioctl. + +This ioctl call informs the video device which source shall be used for +the input data. The possible sources are demux or memory. If memory is +selected, the data is fed to the video device through the write command. + +.. c:type:: video_stream_source_t + +.. code-block:: c + + typedef enum { + VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ + VIDEO_SOURCE_MEMORY /* If this source is selected, the stream + comes from the user through the write + system call */ + } video_stream_source_t; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst new file mode 100644 index 000000000000..70249a6ba125 --- /dev/null +++ b/drivers/staging/media/av7110/video-set-blank.rst @@ -0,0 +1,64 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_BLANK: + +=============== +VIDEO_SET_BLANK +=============== + +Name +---- + +VIDEO_SET_BLANK + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_BLANK + +``int ioctl(fd, VIDEO_SET_BLANK, boolean mode)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_BLANK for this command. + + - .. row 3 + + - boolean mode + + - TRUE: Blank screen when stop. + + - .. row 4 + + - + - FALSE: Show last decoded frame. + +Description +----------- + +This ioctl call asks the Video Device to blank out the picture. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst new file mode 100644 index 000000000000..1de4f40ae732 --- /dev/null +++ b/drivers/staging/media/av7110/video-set-display-format.rst @@ -0,0 +1,60 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_DISPLAY_FORMAT: + +======================== +VIDEO_SET_DISPLAY_FORMAT +======================== + +Name +---- + +VIDEO_SET_DISPLAY_FORMAT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_DISPLAY_FORMAT + +``int ioctl(fd, VIDEO_SET_DISPLAY_FORMAT)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_DISPLAY_FORMAT for this command. + + - .. row 3 + + - video_display_format_t format + + - Selects the video format to be used. + +Description +----------- + +This ioctl call asks the Video Device to select the video format to be +applied by the MPEG chip on the video. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst new file mode 100644 index 000000000000..bb64e37ae081 --- /dev/null +++ b/drivers/staging/media/av7110/video-set-format.rst @@ -0,0 +1,82 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_FORMAT: + +================ +VIDEO_SET_FORMAT +================ + +Name +---- + +VIDEO_SET_FORMAT + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_FORMAT + +``int ioctl(fd, VIDEO_SET_FORMAT, video_format_t format)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_FORMAT for this command. + + - .. row 3 + + - video_format_t format + + - video format of TV as defined in section ??. + +Description +----------- + +This ioctl sets the screen format (aspect ratio) of the connected output +device (TV) so that the output of the decoder can be adjusted +accordingly. + +.. c:type:: video_format_t + +.. code-block:: c + + typedef enum { + VIDEO_FORMAT_4_3, /* Select 4:3 format */ + VIDEO_FORMAT_16_9, /* Select 16:9 format. */ + VIDEO_FORMAT_221_1 /* 2.21:1 */ + } video_format_t; + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EINVAL`` + + - format is not a valid video format. diff --git a/drivers/staging/media/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst new file mode 100644 index 000000000000..1f31c048bdbc --- /dev/null +++ b/drivers/staging/media/av7110/video-set-streamtype.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SET_STREAMTYPE: + +==================== +VIDEO_SET_STREAMTYPE +==================== + +Name +---- + +VIDEO_SET_STREAMTYPE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SET_STREAMTYPE + +``int ioctl(fd, VIDEO_SET_STREAMTYPE, int type)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SET_STREAMTYPE for this command. + + - .. row 3 + + - int type + + - stream type + +Description +----------- + +This ioctl tells the driver which kind of stream to expect being written +to it. If this call is not used the default of video PES is used. Some +drivers might not support this call and always expect PES. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst new file mode 100644 index 000000000000..1478fcc30cb8 --- /dev/null +++ b/drivers/staging/media/av7110/video-slowmotion.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_SLOWMOTION: + +================ +VIDEO_SLOWMOTION +================ + +Name +---- + +VIDEO_SLOWMOTION + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_SLOWMOTION + +``int ioctl(fd, VIDEO_SLOWMOTION, int nFrames)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_SLOWMOTION for this command. + + - .. row 3 + + - int nFrames + + - The number of times to repeat each frame. + +Description +----------- + +This ioctl call asks the video device to repeat decoding frames N number +of times. This call can only be used if VIDEO_SOURCE_MEMORY is +selected. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - ``EPERM`` + + - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/drivers/staging/media/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst new file mode 100644 index 000000000000..d25384222a20 --- /dev/null +++ b/drivers/staging/media/av7110/video-stillpicture.rst @@ -0,0 +1,61 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_STILLPICTURE: + +================== +VIDEO_STILLPICTURE +================== + +Name +---- + +VIDEO_STILLPICTURE + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_STILLPICTURE + +``int ioctl(fd, VIDEO_STILLPICTURE, struct video_still_picture *sp)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_STILLPICTURE for this command. + + - .. row 3 + + - struct video_still_picture \*sp + + - Pointer to a location where an I-frame and size is stored. + +Description +----------- + +This ioctl call asks the Video Device to display a still picture +(I-frame). The input data shall contain an I-frame. If the pointer is +NULL, then the current displayed still picture is blanked. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst new file mode 100644 index 000000000000..96f61c5b48a2 --- /dev/null +++ b/drivers/staging/media/av7110/video-stop.rst @@ -0,0 +1,74 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_STOP: + +========== +VIDEO_STOP +========== + +Name +---- + +VIDEO_STOP + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_STOP + +``int ioctl(fd, VIDEO_STOP, boolean mode)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_STOP for this command. + + - .. row 3 + + - Boolean mode + + - Indicates how the screen shall be handled. + + - .. row 4 + + - + - TRUE: Blank screen when stop. + + - .. row 5 + + - + - FALSE: Show last decoded frame. + +Description +----------- + +This ioctl is for Digital TV devices only. To control a V4L2 decoder use the +V4L2 :ref:`VIDIOC_DECODER_CMD` instead. + +This ioctl call asks the Video Device to stop playing the current +stream. Depending on the input parameter, the screen can be blanked out +or displaying the last decoded frame. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst new file mode 100644 index 000000000000..79bf3dfb8a32 --- /dev/null +++ b/drivers/staging/media/av7110/video-try-command.rst @@ -0,0 +1,66 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later +.. c:namespace:: DTV.video + +.. _VIDEO_TRY_COMMAND: + +================= +VIDEO_TRY_COMMAND +================= + +Name +---- + +VIDEO_TRY_COMMAND + +.. attention:: This ioctl is deprecated. + +Synopsis +-------- + +.. c:macro:: VIDEO_TRY_COMMAND + +``int ioctl(int fd, VIDEO_TRY_COMMAND, struct video_command *cmd)`` + +Arguments +--------- + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + - .. row 1 + + - int fd + + - File descriptor returned by a previous call to open(). + + - .. row 2 + + - int request + + - Equals VIDEO_TRY_COMMAND for this command. + + - .. row 3 + + - struct video_command \*cmd + + - Try a decoder command. + +Description +----------- + +This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders +this ioctl has been replaced by the +:ref:`VIDIOC_TRY_DECODER_CMD <VIDIOC_DECODER_CMD>` ioctl. + +This ioctl tries a decoder command. The ``video_command`` struct is a +subset of the ``v4l2_decoder_cmd`` struct, so refer to the +:ref:`VIDIOC_TRY_DECODER_CMD <VIDIOC_DECODER_CMD>` documentation +for more information. + +Return Value +------------ + +On success 0 is returned, on error -1 and the ``errno`` variable is set +appropriately. The generic error codes are described at the +:ref:`Generic Error Codes <gen-errors>` chapter. diff --git a/drivers/staging/media/av7110/video.h b/drivers/staging/media/av7110/video.h new file mode 100644 index 000000000000..179f1ec60af6 --- /dev/null +++ b/drivers/staging/media/av7110/video.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ +/* + * video.h - DEPRECATED MPEG-TS video decoder API + * + * NOTE: should not be used on future drivers + * + * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de> + * & Ralph Metzler <ralph@convergence.de> + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * 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. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _UAPI_DVBVIDEO_H_ +#define _UAPI_DVBVIDEO_H_ + +#include <linux/types.h> +#ifndef __KERNEL__ +#include <time.h> +#endif + +typedef enum { + VIDEO_FORMAT_4_3, /* Select 4:3 format */ + VIDEO_FORMAT_16_9, /* Select 16:9 format. */ + VIDEO_FORMAT_221_1 /* 2.21:1 */ +} video_format_t; + + +typedef enum { + VIDEO_PAN_SCAN, /* use pan and scan format */ + VIDEO_LETTER_BOX, /* use letterbox format */ + VIDEO_CENTER_CUT_OUT /* use center cut out format */ +} video_displayformat_t; + +typedef struct { + int w; + int h; + video_format_t aspect_ratio; +} video_size_t; + +typedef enum { + VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ + VIDEO_SOURCE_MEMORY /* If this source is selected, the stream + comes from the user through the write + system call */ +} video_stream_source_t; + + +typedef enum { + VIDEO_STOPPED, /* Video is stopped */ + VIDEO_PLAYING, /* Video is currently playing */ + VIDEO_FREEZED /* Video is freezed */ +} video_play_state_t; + + +/* Decoder commands */ +#define VIDEO_CMD_PLAY (0) +#define VIDEO_CMD_STOP (1) +#define VIDEO_CMD_FREEZE (2) +#define VIDEO_CMD_CONTINUE (3) + +/* Flags for VIDEO_CMD_FREEZE */ +#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0) + +/* Flags for VIDEO_CMD_STOP */ +#define VIDEO_CMD_STOP_TO_BLACK (1 << 0) +#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1) + +/* Play input formats: */ +/* The decoder has no special format requirements */ +#define VIDEO_PLAY_FMT_NONE (0) +/* The decoder requires full GOPs */ +#define VIDEO_PLAY_FMT_GOP (1) + +/* The structure must be zeroed before use by the application + This ensures it can be extended safely in the future. */ +struct video_command { + __u32 cmd; + __u32 flags; + union { + struct { + __u64 pts; + } stop; + + struct { + /* 0 or 1000 specifies normal speed, + 1 specifies forward single stepping, + -1 specifies backward single stepping, + >1: playback at speed/1000 of the normal speed, + <-1: reverse playback at (-speed/1000) of the normal speed. */ + __s32 speed; + __u32 format; + } play; + + struct { + __u32 data[16]; + } raw; + }; +}; + +/* FIELD_UNKNOWN can be used if the hardware does not know whether + the Vsync is for an odd, even or progressive (i.e. non-interlaced) + field. */ +#define VIDEO_VSYNC_FIELD_UNKNOWN (0) +#define VIDEO_VSYNC_FIELD_ODD (1) +#define VIDEO_VSYNC_FIELD_EVEN (2) +#define VIDEO_VSYNC_FIELD_PROGRESSIVE (3) + +struct video_event { + __s32 type; +#define VIDEO_EVENT_SIZE_CHANGED 1 +#define VIDEO_EVENT_FRAME_RATE_CHANGED 2 +#define VIDEO_EVENT_DECODER_STOPPED 3 +#define VIDEO_EVENT_VSYNC 4 + /* unused, make sure to use atomic time for y2038 if it ever gets used */ + long timestamp; + union { + video_size_t size; + unsigned int frame_rate; /* in frames per 1000sec */ + unsigned char vsync_field; /* unknown/odd/even/progressive */ + } u; +}; + + +struct video_status { + int video_blank; /* blank video on freeze? */ + video_play_state_t play_state; /* current state of playback */ + video_stream_source_t stream_source; /* current source (demux/memory) */ + video_format_t video_format; /* current aspect ratio of stream*/ + video_displayformat_t display_format;/* selected cropping mode */ +}; + + +struct video_still_picture { + char __user *iFrame; /* pointer to a single iframe in memory */ + __s32 size; +}; + + +typedef __u16 video_attributes_t; +/* bits: descr. */ +/* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */ +/* 13-12 TV system (0=525/60, 1=625/50) */ +/* 11-10 Aspect ratio (0=4:3, 3=16:9) */ +/* 9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca */ +/* 7 line 21-1 data present in GOP (1=yes, 0=no) */ +/* 6 line 21-2 data present in GOP (1=yes, 0=no) */ +/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */ +/* 2 source letterboxed (1=yes, 0=no) */ +/* 0 film/camera mode (0= + *camera, 1=film (625/50 only)) */ + + +/* bit definitions for capabilities: */ +/* can the hardware decode MPEG1 and/or MPEG2? */ +#define VIDEO_CAP_MPEG1 1 +#define VIDEO_CAP_MPEG2 2 +/* can you send a system and/or program stream to video device? + (you still have to open the video and the audio device but only + send the stream to the video device) */ +#define VIDEO_CAP_SYS 4 +#define VIDEO_CAP_PROG 8 +/* can the driver also handle SPU, NAVI and CSS encoded data? + (CSS API is not present yet) */ +#define VIDEO_CAP_SPU 16 +#define VIDEO_CAP_NAVI 32 +#define VIDEO_CAP_CSS 64 + + +#define VIDEO_STOP _IO('o', 21) +#define VIDEO_PLAY _IO('o', 22) +#define VIDEO_FREEZE _IO('o', 23) +#define VIDEO_CONTINUE _IO('o', 24) +#define VIDEO_SELECT_SOURCE _IO('o', 25) +#define VIDEO_SET_BLANK _IO('o', 26) +#define VIDEO_GET_STATUS _IOR('o', 27, struct video_status) +#define VIDEO_GET_EVENT _IOR('o', 28, struct video_event) +#define VIDEO_SET_DISPLAY_FORMAT _IO('o', 29) +#define VIDEO_STILLPICTURE _IOW('o', 30, struct video_still_picture) +#define VIDEO_FAST_FORWARD _IO('o', 31) +#define VIDEO_SLOWMOTION _IO('o', 32) +#define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int) +#define VIDEO_CLEAR_BUFFER _IO('o', 34) +#define VIDEO_SET_STREAMTYPE _IO('o', 36) +#define VIDEO_SET_FORMAT _IO('o', 37) +#define VIDEO_GET_SIZE _IOR('o', 55, video_size_t) + +/** + * VIDEO_GET_PTS + * + * Read the 33 bit presentation time stamp as defined + * in ITU T-REC-H.222.0 / ISO/IEC 13818-1. + * + * The PTS should belong to the currently played + * frame if possible, but may also be a value close to it + * like the PTS of the last decoded frame or the last PTS + * extracted by the PES parser. + */ +#define VIDEO_GET_PTS _IOR('o', 57, __u64) + +/* Read the number of displayed frames since the decoder was started */ +#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64) + +#define VIDEO_COMMAND _IOWR('o', 59, struct video_command) +#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command) + +#endif /* _UAPI_DVBVIDEO_H_ */ diff --git a/drivers/staging/media/av7110/video.rst b/drivers/staging/media/av7110/video.rst new file mode 100644 index 000000000000..808705b769a1 --- /dev/null +++ b/drivers/staging/media/av7110/video.rst @@ -0,0 +1,36 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _dvb_video: + +####################### +Digital TV Video Device +####################### + +The Digital TV video device controls the MPEG2 video decoder of the Digital +TV hardware. It can be accessed through **/dev/dvb/adapter0/video0**. Data +types and ioctl definitions can be accessed by including +**linux/dvb/video.h** in your application. + +Note that the Digital TV video device only controls decoding of the MPEG video +stream, not its presentation on the TV or computer screen. On PCs this +is typically handled by an associated video4linux device, e.g. +**/dev/video**, which allows scaling and defining output windows. + +Some Digital TV cards don't have their own MPEG decoder, which results in the +omission of the audio and video device as well as the video4linux +device. + +The ioctls that deal with SPUs (sub picture units) and navigation +packets are only supported on some MPEG decoders made for DVD playback. + +These ioctls were also used by V4L2 to control MPEG decoders implemented +in V4L2. The use of these ioctls for that purpose has been made obsolete +and proper V4L2 ioctls or controls have been created to replace that +functionality. + + +.. toctree:: + :maxdepth: 1 + + video_types + video_function_calls diff --git a/drivers/staging/media/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst new file mode 100644 index 000000000000..20a897be5dca --- /dev/null +++ b/drivers/staging/media/av7110/video_function_calls.rst @@ -0,0 +1,35 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _video_function_calls: + +******************** +Video Function Calls +******************** + +.. toctree:: + :maxdepth: 1 + + video-fopen + video-fclose + video-fwrite + video-stop + video-play + video-freeze + video-continue + video-select-source + video-set-blank + video-get-status + video-get-frame-count + video-get-pts + video-get-event + video-command + video-try-command + video-get-size + video-set-display-format + video-stillpicture + video-fast-forward + video-slowmotion + video-get-capabilities + video-clear-buffer + video-set-streamtype + video-set-format diff --git a/drivers/staging/media/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst new file mode 100644 index 000000000000..c4557d328b7a --- /dev/null +++ b/drivers/staging/media/av7110/video_types.rst @@ -0,0 +1,248 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _video_types: + +**************** +Video Data Types +**************** + + +.. _video-format-t: + +video_format_t +============== + +The ``video_format_t`` data type defined by + + +.. code-block:: c + + typedef enum { + VIDEO_FORMAT_4_3, /* Select 4:3 format */ + VIDEO_FORMAT_16_9, /* Select 16:9 format. */ + VIDEO_FORMAT_221_1 /* 2.21:1 */ + } video_format_t; + +is used in the VIDEO_SET_FORMAT function (??) to tell the driver which +aspect ratio the output hardware (e.g. TV) has. It is also used in the +data structures video_status (??) returned by VIDEO_GET_STATUS (??) +and video_event (??) returned by VIDEO_GET_EVENT (??) which report +about the display format of the current video stream. + + +.. _video-displayformat-t: + +video_displayformat_t +===================== + +In case the display format of the video stream and of the display +hardware differ the application has to specify how to handle the +cropping of the picture. This can be done using the +VIDEO_SET_DISPLAY_FORMAT call (??) which accepts + + +.. code-block:: c + + typedef enum { + VIDEO_PAN_SCAN, /* use pan and scan format */ + VIDEO_LETTER_BOX, /* use letterbox format */ + VIDEO_CENTER_CUT_OUT /* use center cut out format */ + } video_displayformat_t; + +as argument. + + +.. _video-stream-source-t: + +video_stream_source_t +===================== + +The video stream source is set through the VIDEO_SELECT_SOURCE call +and can take the following values, depending on whether we are replaying +from an internal (demuxer) or external (user write) source. + + +.. code-block:: c + + typedef enum { + VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ + VIDEO_SOURCE_MEMORY /* If this source is selected, the stream + comes from the user through the write + system call */ + } video_stream_source_t; + +VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the +frontend or the DVR device) as the source of the video stream. If +VIDEO_SOURCE_MEMORY is selected the stream comes from the application +through the **write()** system call. + + +.. _video-play-state-t: + +video_play_state_t +================== + +The following values can be returned by the VIDEO_GET_STATUS call +representing the state of video playback. + + +.. code-block:: c + + typedef enum { + VIDEO_STOPPED, /* Video is stopped */ + VIDEO_PLAYING, /* Video is currently playing */ + VIDEO_FREEZED /* Video is freezed */ + } video_play_state_t; + + +.. c:type:: video_command + +struct video_command +==================== + +The structure must be zeroed before use by the application This ensures +it can be extended safely in the future. + + +.. code-block:: c + + struct video_command { + __u32 cmd; + __u32 flags; + union { + struct { + __u64 pts; + } stop; + + struct { + /* 0 or 1000 specifies normal speed, + 1 specifies forward single stepping, + -1 specifies backward single stepping, + >>1: playback at speed/1000 of the normal speed, + <-1: reverse playback at (-speed/1000) of the normal speed. */ + __s32 speed; + __u32 format; + } play; + + struct { + __u32 data[16]; + } raw; + }; + }; + + +.. _video-size-t: + +video_size_t +============ + + +.. code-block:: c + + typedef struct { + int w; + int h; + video_format_t aspect_ratio; + } video_size_t; + + +.. c:type:: video_event + +struct video_event +================== + +The following is the structure of a video event as it is returned by the +VIDEO_GET_EVENT call. + + +.. code-block:: c + + struct video_event { + __s32 type; + #define VIDEO_EVENT_SIZE_CHANGED 1 + #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 + #define VIDEO_EVENT_DECODER_STOPPED 3 + #define VIDEO_EVENT_VSYNC 4 + long timestamp; + union { + video_size_t size; + unsigned int frame_rate; /* in frames per 1000sec */ + unsigned char vsync_field; /* unknown/odd/even/progressive */ + } u; + }; + + +.. c:type:: video_status + +struct video_status +=================== + +The VIDEO_GET_STATUS call returns the following structure informing +about various states of the playback operation. + + +.. code-block:: c + + struct video_status { + int video_blank; /* blank video on freeze? */ + video_play_state_t play_state; /* current state of playback */ + video_stream_source_t stream_source; /* current source (demux/memory) */ + video_format_t video_format; /* current aspect ratio of stream */ + video_displayformat_t display_format;/* selected cropping mode */ + }; + +If video_blank is set video will be blanked out if the channel is +changed or if playback is stopped. Otherwise, the last picture will be +displayed. play_state indicates if the video is currently frozen, +stopped, or being played back. The stream_source corresponds to the +selected source for the video stream. It can come either from the +demultiplexer or from memory. The video_format indicates the aspect +ratio (one of 4:3 or 16:9) of the currently played video stream. +Finally, display_format corresponds to the selected cropping mode in +case the source video format is not the same as the format of the output +device. + + +.. c:type:: video_still_picture + +struct video_still_picture +========================== + +An I-frame displayed via the VIDEO_STILLPICTURE call is passed on +within the following structure. + + +.. code-block:: c + + /* pointer to and size of a single iframe in memory */ + struct video_still_picture { + char *iFrame; /* pointer to a single iframe in memory */ + int32_t size; + }; + + +.. _video_caps: + +video capabilities +================== + +A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the +following bits set according to the hardwares capabilities. + + +.. code-block:: c + + /* bit definitions for capabilities: */ + /* can the hardware decode MPEG1 and/or MPEG2? */ + #define VIDEO_CAP_MPEG1 1 + #define VIDEO_CAP_MPEG2 2 + /* can you send a system and/or program stream to video device? + (you still have to open the video and the audio device but only + send the stream to the video device) */ + #define VIDEO_CAP_SYS 4 + #define VIDEO_CAP_PROG 8 + /* can the driver also handle SPU, NAVI and CSS encoded data? + (CSS API is not present yet) */ + #define VIDEO_CAP_SPU 16 + #define VIDEO_CAP_NAVI 32 + #define VIDEO_CAP_CSS 64 diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig index 5b6cf9f62b1a..20b1f6d7b69c 100644 --- a/drivers/staging/media/hantro/Kconfig +++ b/drivers/staging/media/hantro/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config VIDEO_HANTRO tristate "Hantro VPU driver" - depends on ARCH_MXC || ARCH_ROCKCHIP || COMPILE_TEST + depends on ARCH_MXC || ARCH_ROCKCHIP || ARCH_AT91 || COMPILE_TEST depends on VIDEO_DEV && VIDEO_V4L2 select MEDIA_CONTROLLER select MEDIA_CONTROLLER_REQUEST_API @@ -24,6 +24,14 @@ config VIDEO_HANTRO_IMX8M help Enable support for i.MX8M SoCs. +config VIDEO_HANTRO_SAMA5D4 + bool "Hantro VDEC SAMA5D4 support" + depends on VIDEO_HANTRO + depends on ARCH_AT91 || COMPILE_TEST + default y + help + Enable support for Microchip SAMA5D4 SoCs. + config VIDEO_HANTRO_ROCKCHIP bool "Hantro VPU Rockchip support" depends on VIDEO_HANTRO diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index 743ce08eb184..287370188d2a 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -7,20 +7,25 @@ hantro-vpu-y += \ hantro_v4l2.o \ hantro_postproc.o \ hantro_h1_jpeg_enc.o \ + hantro_g1.o \ hantro_g1_h264_dec.o \ hantro_g1_mpeg2_dec.o \ + hantro_g2_hevc_dec.o \ hantro_g1_vp8_dec.o \ - rk3399_vpu_hw_jpeg_enc.o \ - rk3399_vpu_hw_mpeg2_dec.o \ - rk3399_vpu_hw_vp8_dec.o \ + rockchip_vpu2_hw_jpeg_enc.o \ + rockchip_vpu2_hw_mpeg2_dec.o \ + rockchip_vpu2_hw_vp8_dec.o \ hantro_jpeg.o \ hantro_h264.o \ + hantro_hevc.o \ hantro_mpeg2.o \ hantro_vp8.o hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \ imx8m_vpu_hw.o +hantro-vpu-$(CONFIG_VIDEO_HANTRO_SAMA5D4) += \ + sama5d4_vdec_hw.o + hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \ - rk3288_vpu_hw.o \ - rk3399_vpu_hw.o + rockchip_vpu_hw.o diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 6c1b888abe75..a70c386de6f1 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -34,6 +34,7 @@ struct hantro_codec_ops; #define HANTRO_MPEG2_DECODER BIT(16) #define HANTRO_VP8_DECODER BIT(17) #define HANTRO_H264_DECODER BIT(18) +#define HANTRO_HEVC_DECODER BIT(19) #define HANTRO_DECODERS 0xffff0000 /** @@ -99,6 +100,7 @@ struct hantro_variant { * @HANTRO_MODE_H264_DEC: H264 decoder. * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder. * @HANTRO_MODE_VP8_DEC: VP8 decoder. + * @HANTRO_MODE_HEVC_DEC: HEVC decoder. */ enum hantro_codec_mode { HANTRO_MODE_NONE = -1, @@ -106,6 +108,7 @@ enum hantro_codec_mode { HANTRO_MODE_H264_DEC, HANTRO_MODE_MPEG2_DEC, HANTRO_MODE_VP8_DEC, + HANTRO_MODE_HEVC_DEC, }; /* @@ -218,6 +221,7 @@ struct hantro_dev { * @jpeg_enc: JPEG-encoding context. * @mpeg2_dec: MPEG-2-decoding context. * @vp8_dec: VP8-decoding context. + * @hevc_dec: HEVC-decoding context. */ struct hantro_ctx { struct hantro_dev *dev; @@ -244,6 +248,7 @@ struct hantro_ctx { struct hantro_jpeg_enc_hw_ctx jpeg_enc; struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; struct hantro_vp8_dec_hw_ctx vp8_dec; + struct hantro_hevc_dec_hw_ctx hevc_dec; }; }; @@ -410,12 +415,8 @@ hantro_get_dst_buf(struct hantro_ctx *ctx) return v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); } -static inline bool -hantro_needs_postproc(const struct hantro_ctx *ctx, - const struct hantro_fmt *fmt) -{ - return !ctx->is_encoder && fmt->fourcc != V4L2_PIX_FMT_NV12; -} +bool hantro_needs_postproc(const struct hantro_ctx *ctx, + const struct hantro_fmt *fmt); static inline dma_addr_t hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb) diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 595e82a82728..31d8449ca1d2 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -56,16 +56,12 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) return hantro_get_dec_buf_addr(ctx, buf); } -static void hantro_job_finish(struct hantro_dev *vpu, - struct hantro_ctx *ctx, - enum vb2_buffer_state result) +static void hantro_job_finish_no_pm(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + enum vb2_buffer_state result) { struct vb2_v4l2_buffer *src, *dst; - pm_runtime_mark_last_busy(vpu->dev); - pm_runtime_put_autosuspend(vpu->dev); - clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); - src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -81,6 +77,18 @@ static void hantro_job_finish(struct hantro_dev *vpu, result); } +static void hantro_job_finish(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + enum vb2_buffer_state result) +{ + pm_runtime_mark_last_busy(vpu->dev); + pm_runtime_put_autosuspend(vpu->dev); + + clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); + + hantro_job_finish_no_pm(vpu, ctx, result); +} + void hantro_irq_done(struct hantro_dev *vpu, enum vb2_buffer_state result) { @@ -152,20 +160,23 @@ static void device_run(void *priv) src = hantro_get_src_buf(ctx); dst = hantro_get_dst_buf(ctx); + ret = pm_runtime_resume_and_get(ctx->dev->dev); + if (ret < 0) + goto err_cancel_job; + ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks); if (ret) goto err_cancel_job; - ret = pm_runtime_get_sync(ctx->dev->dev); - if (ret < 0) - goto err_cancel_job; v4l2_m2m_buf_copy_metadata(src, dst, true); - ctx->codec_ops->run(ctx); + if (ctx->codec_ops->run(ctx)) + goto err_cancel_job; + return; err_cancel_job: - hantro_job_finish(ctx->dev, ctx, VB2_BUF_STATE_ERROR); + hantro_job_finish_no_pm(ctx->dev, ctx, VB2_BUF_STATE_ERROR); } static struct v4l2_m2m_ops vpu_m2m_ops = { @@ -243,6 +254,18 @@ 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) { + const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; + + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) + /* Luma and chroma bit depth mismatch */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != 0) + /* Only 8-bit is supported */ + return -EINVAL; + if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) + /* No scaling support */ + return -EINVAL; } return 0; } @@ -267,6 +290,26 @@ static int hantro_jpeg_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } +static int hantro_hevc_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; + break; + default: + return -EINVAL; + } + + return 0; +} + static const struct v4l2_ctrl_ops hantro_ctrl_ops = { .try_ctrl = hantro_try_ctrl, }; @@ -275,6 +318,10 @@ 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 hantro_ctrl controls[] = { { .codec = HANTRO_JPEG_ENCODER, @@ -289,12 +336,17 @@ static const struct hantro_ctrl controls[] = { }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, + .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE, + }, + }, { + .codec = HANTRO_MPEG2_DECODER, + .cfg = { + .id = V4L2_CID_STATELESS_MPEG2_PICTURE, }, }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION, }, }, { .codec = HANTRO_VP8_DECODER, @@ -349,6 +401,64 @@ static const struct hantro_ctrl controls[] = { .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, } }, { + .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, + }, + }, { + .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, + }, + }, { + .codec = HANTRO_HEVC_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + }, + }, { + .codec = HANTRO_HEVC_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + }, + }, { + .codec = HANTRO_HEVC_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, + .ops = &hantro_ctrl_ops, + }, + }, { + .codec = HANTRO_HEVC_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, + }, + }, { + .codec = HANTRO_HEVC_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS, + }, + }, { + .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, + }, }, }; @@ -472,12 +582,18 @@ static const struct v4l2_file_operations hantro_fops = { static const struct of_device_id of_hantro_match[] = { #ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP - { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, - { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, + { .compatible = "rockchip,rk3036-vpu", .data = &rk3036_vpu_variant, }, + { .compatible = "rockchip,rk3066-vpu", .data = &rk3066_vpu_variant, }, { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, + { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, + { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, #endif #ifdef CONFIG_VIDEO_HANTRO_IMX8M { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, + { .compatible = "nxp,imx8mq-vpu-g2", .data = &imx8mq_vpu_g2_variant }, +#endif +#ifdef CONFIG_VIDEO_HANTRO_SAMA5D4 + { .compatible = "microchip,sama5d4-vdec", .data = &sama5d4_vdec_variant, }, #endif { /* sentinel */ } }; @@ -752,12 +868,23 @@ static int hantro_probe(struct platform_device *pdev) if (!vpu->clocks) return -ENOMEM; - for (i = 0; i < vpu->variant->num_clocks; i++) - vpu->clocks[i].id = vpu->variant->clk_names[i]; - ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks, - vpu->clocks); - if (ret) - return ret; + if (vpu->variant->num_clocks > 1) { + for (i = 0; i < vpu->variant->num_clocks; i++) + vpu->clocks[i].id = vpu->variant->clk_names[i]; + + ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks, + vpu->clocks); + if (ret) + return ret; + } else { + /* + * If the driver has a single clk, chances are there will be no + * actual name in the DT bindings. + */ + vpu->clocks[0].clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(vpu->clocks[0].clk)) + return PTR_ERR(vpu->clocks[0].clk); + } num_bases = vpu->variant->num_regs ?: 1; vpu->reg_bases = devm_kcalloc(&pdev->dev, num_bases, @@ -785,13 +912,23 @@ static int hantro_probe(struct platform_device *pdev) vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); for (i = 0; i < vpu->variant->num_irqs; i++) { - const char *irq_name = vpu->variant->irqs[i].name; + const char *irq_name; int irq; if (!vpu->variant->irqs[i].handler) continue; - irq = platform_get_irq_byname(vpu->pdev, irq_name); + if (vpu->variant->num_clocks > 1) { + irq_name = vpu->variant->irqs[i].name; + irq = platform_get_irq_byname(vpu->pdev, irq_name); + } else { + /* + * If the driver has a single IRQ, chances are there + * will be no actual name in the DT bindings. + */ + irq_name = "default"; + irq = platform_get_irq(vpu->pdev, 0); + } if (irq <= 0) return -ENXIO; diff --git a/drivers/staging/media/hantro/hantro_g1.c b/drivers/staging/media/hantro/hantro_g1.c new file mode 100644 index 000000000000..0ab1cee62218 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Jeffy Chen <jeffy.chen@rock-chips.com> + * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix.de> + * Copyright (C) 2021 Collabora Ltd, Emil Velikov <emil.velikov@collabora.com> + */ + +#include "hantro.h" +#include "hantro_g1_regs.h" + +irqreturn_t hantro_g1_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, G1_REG_INTERRUPT); + state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vdpu_write(vpu, 0, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + + hantro_irq_done(vpu, state); + + return IRQ_HANDLED; +} + +void hantro_g1_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + vdpu_write(vpu, 1, G1_REG_SOFT_RESET); +} diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index 845bef73d218..5c792b7bcb79 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -273,13 +273,15 @@ static void set_buffers(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE); } -void hantro_g1_h264_dec_run(struct hantro_ctx *ctx) +int hantro_g1_h264_dec_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; + int ret; /* Prepare the H264 decoder context. */ - if (hantro_h264_dec_prepare_run(ctx)) - return; + ret = hantro_h264_dec_prepare_run(ctx); + if (ret) + return ret; /* Configure hardware registers. */ set_params(ctx); @@ -301,4 +303,6 @@ void hantro_g1_h264_dec_run(struct hantro_ctx *ctx) G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); + + return 0; } diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index 6386a3989bfe..9aea331e1a3c 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -10,6 +10,7 @@ #include <media/v4l2-mem2mem.h> #include "hantro.h" #include "hantro_hw.h" +#include "hantro_g1_regs.h" #define G1_SWREG(nr) ((nr) * 4) @@ -20,7 +21,6 @@ #define G1_REG_REFER2_BASE G1_SWREG(16) #define G1_REG_REFER3_BASE G1_SWREG(17) #define G1_REG_QTABLE_BASE G1_SWREG(40) -#define G1_REG_DEC_E(v) ((v) ? BIT(0) : 0) #define G1_REG_DEC_AXI_RD_ID(v) (((v) << 24) & GENMASK(31, 24)) #define G1_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(23) : 0) @@ -77,43 +77,33 @@ #define G1_REG_APF_THRESHOLD(v) (((v) << 0) & GENMASK(13, 0)) -#define PICT_TOP_FIELD 1 -#define PICT_BOTTOM_FIELD 2 -#define PICT_FRAME 3 - static void -hantro_g1_mpeg2_dec_set_quantization(struct hantro_dev *vpu, +hantro_g1_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, struct hantro_ctx *ctx) { - struct v4l2_ctrl_mpeg2_quantization *quantization; - - quantization = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); - hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, - quantization); - vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, - G1_REG_QTABLE_BASE); + struct v4l2_ctrl_mpeg2_quantisation *q; + + q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, G1_REG_QTABLE_BASE); } static void hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *sequence, - const struct v4l2_mpeg2_picture *picture, - const struct v4l2_ctrl_mpeg2_slice_params *slice_params) + const struct v4l2_ctrl_mpeg2_sequence *seq, + const struct v4l2_ctrl_mpeg2_picture *pic) { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; - switch (picture->picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: - backward_addr = hantro_get_ref(ctx, - slice_params->backward_ref_ts); + switch (pic->picture_coding_type) { + case V4L2_MPEG2_PIC_CODING_TYPE_B: + backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts); fallthrough; - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - forward_addr = hantro_get_ref(ctx, - slice_params->forward_ref_ts); + case V4L2_MPEG2_PIC_CODING_TYPE_P: + forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts); } /* Source bitstream buffer */ @@ -124,7 +114,7 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, addr = hantro_get_dec_buf_addr(ctx, dst_buf); current_addr = addr; - if (picture->picture_structure == PICT_BOTTOM_FIELD) + if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) addr += ALIGN(ctx->dst_fmt.width, 16); vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE); @@ -134,18 +124,18 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, backward_addr = current_addr; /* Set forward ref frame (top/bottom field) */ - if (picture->picture_structure == PICT_FRAME || - picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || - (picture->picture_structure == PICT_TOP_FIELD && - picture->top_field_first) || - (picture->picture_structure == PICT_BOTTOM_FIELD && - !picture->top_field_first)) { + if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME || + pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B || + (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD && + pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST) || + (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD && + !(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST))) { vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_TOP_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) { vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) { vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); } @@ -155,13 +145,12 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER3_BASE); } -void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) +int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - const struct v4l2_mpeg2_picture *picture; + const struct v4l2_ctrl_mpeg2_sequence *seq; + const struct v4l2_ctrl_mpeg2_picture *pic; u32 reg; src_buf = hantro_get_src_buf(ctx); @@ -170,10 +159,10 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) /* Apply request controls if any */ hantro_start_prepare_run(ctx); - slice_params = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - sequence = &slice_params->sequence; - picture = &slice_params->picture; + seq = hantro_get_ctrl(ctx, + V4L2_CID_STATELESS_MPEG2_SEQUENCE); + pic = hantro_get_ctrl(ctx, + V4L2_CID_STATELESS_MPEG2_PICTURE); reg = G1_REG_DEC_AXI_RD_ID(0) | G1_REG_DEC_TIMEOUT_E(1) | @@ -193,11 +182,11 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) reg = G1_REG_DEC_MODE(5) | G1_REG_RLC_MODE_E(0) | - G1_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | - G1_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | - G1_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | - G1_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | - G1_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + G1_REG_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) | + G1_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) | + G1_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) | + G1_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) | + G1_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) | G1_REG_FWD_INTERLACE_E(0) | G1_REG_FILTERING_DIS(1) | G1_REG_WRITE_MVS_E(0) | @@ -206,27 +195,27 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | - G1_REG_ALT_SCAN_E(picture->alternate_scan) | - G1_REG_TOPFIELDFIRST_E(picture->top_field_first); + G1_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + G1_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST); vdpu_write_relaxed(vpu, reg, G1_SWREG(4)); - reg = G1_REG_STRM_START_BIT(slice_params->data_bit_offset) | - G1_REG_QSCALE_TYPE(picture->q_scale_type) | - G1_REG_CON_MV_E(picture->concealment_motion_vectors) | - G1_REG_INTRA_DC_PREC(picture->intra_dc_precision) | - G1_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | - G1_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + reg = G1_REG_STRM_START_BIT(0) | + G1_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) | + G1_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) | + G1_REG_INTRA_DC_PREC(pic->intra_dc_precision) | + G1_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) | + G1_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT); vdpu_write_relaxed(vpu, reg, G1_SWREG(5)); reg = G1_REG_INIT_QP(1) | - G1_REG_STREAM_LEN(slice_params->bit_size >> 3); + G1_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); vdpu_write_relaxed(vpu, reg, G1_SWREG(6)); - reg = G1_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | - G1_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | - G1_REG_FCODE_FWD_VER(picture->f_code[0][1]) | - G1_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | - G1_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + reg = G1_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + G1_REG_FCODE_FWD_HOR(pic->f_code[0][0]) | + G1_REG_FCODE_FWD_VER(pic->f_code[0][1]) | + G1_REG_FCODE_BWD_HOR(pic->f_code[1][0]) | + G1_REG_FCODE_BWD_VER(pic->f_code[1][1]) | G1_REG_MV_ACCURACY_FWD(1) | G1_REG_MV_ACCURACY_BWD(1); vdpu_write_relaxed(vpu, reg, G1_SWREG(18)); @@ -238,14 +227,14 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) reg = G1_REG_APF_THRESHOLD(8); vdpu_write_relaxed(vpu, reg, G1_SWREG(55)); - hantro_g1_mpeg2_dec_set_quantization(vpu, ctx); - + hantro_g1_mpeg2_dec_set_quantisation(vpu, ctx); hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, &dst_buf->vb2_buf, - sequence, picture, slice_params); + seq, pic); hantro_end_prepare_run(ctx); - reg = G1_REG_DEC_E(1); - vdpu_write(vpu, reg, G1_SWREG(1)); + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); + + return 0; } diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 57002ba70176..96622a7f8279 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -425,7 +425,7 @@ static void cfg_buffers(struct hantro_ctx *ctx, vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST); } -void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) +int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) { const struct v4l2_ctrl_vp8_frame *hdr; struct hantro_dev *vpu = ctx->dev; @@ -438,7 +438,7 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) hdr = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_VP8_FRAME); if (WARN_ON(!hdr)) - return; + return -EINVAL; /* Reset segment_map buffer in keyframe */ if (V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu) @@ -498,4 +498,6 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) hantro_end_prepare_run(ctx); vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); + + return 0; } diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c new file mode 100644 index 000000000000..340efb57fd18 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU HEVC codec driver + * + * Copyright (C) 2020 Safran Passenger Innovations LLC + */ + +#include "hantro_hw.h" +#include "hantro_g2_regs.h" + +#define HEVC_DEC_MODE 0xC + +#define BUS_WIDTH_32 0 +#define BUS_WIDTH_64 1 +#define BUS_WIDTH_128 2 +#define BUS_WIDTH_256 3 + +static inline void hantro_write_addr(struct hantro_dev *vpu, + unsigned long offset, + dma_addr_t addr) +{ + vdpu_write(vpu, addr & 0xffffffff, offset); +} + +static void prepare_tile_info_buffer(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + u16 *p = (u16 *)((u8 *)ctx->hevc_dec.tile_sizes.cpu); + unsigned int num_tile_rows = pps->num_tile_rows_minus1 + 1; + unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1; + unsigned int pic_width_in_ctbs, pic_height_in_ctbs; + unsigned int max_log2_ctb_size, ctb_size; + bool tiles_enabled, uniform_spacing; + u32 no_chroma = 0; + + tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED); + uniform_spacing = !!(pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING); + + hantro_reg_write(vpu, &g2_tile_e, tiles_enabled); + + max_log2_ctb_size = sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size; + pic_width_in_ctbs = (sps->pic_width_in_luma_samples + + (1 << max_log2_ctb_size) - 1) >> max_log2_ctb_size; + pic_height_in_ctbs = (sps->pic_height_in_luma_samples + (1 << max_log2_ctb_size) - 1) + >> max_log2_ctb_size; + ctb_size = 1 << max_log2_ctb_size; + + vpu_debug(1, "Preparing tile sizes buffer for %dx%d CTBs (CTB size %d)\n", + pic_width_in_ctbs, pic_height_in_ctbs, ctb_size); + + if (tiles_enabled) { + unsigned int i, j, h; + + vpu_debug(1, "Tiles enabled! %dx%d\n", num_tile_cols, num_tile_rows); + + hantro_reg_write(vpu, &g2_num_tile_rows, num_tile_rows); + hantro_reg_write(vpu, &g2_num_tile_cols, num_tile_cols); + + /* write width + height for each tile in pic */ + if (!uniform_spacing) { + u32 tmp_w = 0, tmp_h = 0; + + for (i = 0; i < num_tile_rows; i++) { + if (i == num_tile_rows - 1) + h = pic_height_in_ctbs - tmp_h; + else + h = pps->row_height_minus1[i] + 1; + tmp_h += h; + if (i == 0 && h == 1 && ctb_size == 16) + no_chroma = 1; + for (j = 0, tmp_w = 0; j < num_tile_cols - 1; j++) { + tmp_w += pps->column_width_minus1[j] + 1; + *p++ = pps->column_width_minus1[j + 1]; + *p++ = h; + if (i == 0 && h == 1 && ctb_size == 16) + no_chroma = 1; + } + /* last column */ + *p++ = pic_width_in_ctbs - tmp_w; + *p++ = h; + } + } else { /* uniform spacing */ + u32 tmp, prev_h, prev_w; + + for (i = 0, prev_h = 0; i < num_tile_rows; i++) { + tmp = (i + 1) * pic_height_in_ctbs / num_tile_rows; + h = tmp - prev_h; + prev_h = tmp; + if (i == 0 && h == 1 && ctb_size == 16) + no_chroma = 1; + for (j = 0, prev_w = 0; j < num_tile_cols; j++) { + tmp = (j + 1) * pic_width_in_ctbs / num_tile_cols; + *p++ = tmp - prev_w; + *p++ = h; + if (j == 0 && + (pps->column_width_minus1[0] + 1) == 1 && + ctb_size == 16) + no_chroma = 1; + prev_w = tmp; + } + } + } + } else { + hantro_reg_write(vpu, &g2_num_tile_rows, 1); + hantro_reg_write(vpu, &g2_num_tile_cols, 1); + + /* There's one tile, with dimensions equal to pic size. */ + p[0] = pic_width_in_ctbs; + p[1] = pic_height_in_ctbs; + } + + if (no_chroma) + vpu_debug(1, "%s: no chroma!\n", __func__); +} + +static void set_params(struct hantro_ctx *ctx) +{ + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps; + const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params; + struct hantro_dev *vpu = ctx->dev; + u32 min_log2_cb_size, max_log2_ctb_size, min_cb_size, max_ctb_size; + u32 pic_width_in_min_cbs, pic_height_in_min_cbs; + u32 pic_width_aligned, pic_height_aligned; + u32 partial_ctb_x, partial_ctb_y; + + hantro_reg_write(vpu, &g2_bit_depth_y_minus8, sps->bit_depth_luma_minus8); + hantro_reg_write(vpu, &g2_bit_depth_c_minus8, sps->bit_depth_chroma_minus8); + + hantro_reg_write(vpu, &g2_output_8_bits, 0); + + hantro_reg_write(vpu, &g2_hdr_skip_length, ctrls->hevc_hdr_skip_length); + + 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; + + hantro_reg_write(vpu, &g2_min_cb_size, min_log2_cb_size); + hantro_reg_write(vpu, &g2_max_cb_size, max_log2_ctb_size); + + min_cb_size = 1 << min_log2_cb_size; + max_ctb_size = 1 << max_log2_ctb_size; + + pic_width_in_min_cbs = sps->pic_width_in_luma_samples / min_cb_size; + pic_height_in_min_cbs = sps->pic_height_in_luma_samples / min_cb_size; + pic_width_aligned = ALIGN(sps->pic_width_in_luma_samples, max_ctb_size); + pic_height_aligned = ALIGN(sps->pic_height_in_luma_samples, max_ctb_size); + + partial_ctb_x = !!(sps->pic_width_in_luma_samples != pic_width_aligned); + partial_ctb_y = !!(sps->pic_height_in_luma_samples != pic_height_aligned); + + hantro_reg_write(vpu, &g2_partial_ctb_x, partial_ctb_x); + hantro_reg_write(vpu, &g2_partial_ctb_y, partial_ctb_y); + + hantro_reg_write(vpu, &g2_pic_width_in_cbs, pic_width_in_min_cbs); + hantro_reg_write(vpu, &g2_pic_height_in_cbs, pic_height_in_min_cbs); + + hantro_reg_write(vpu, &g2_pic_width_4x4, + (pic_width_in_min_cbs * min_cb_size) / 4); + hantro_reg_write(vpu, &g2_pic_height_4x4, + (pic_height_in_min_cbs * min_cb_size) / 4); + + hantro_reg_write(vpu, &hevc_max_inter_hierdepth, + sps->max_transform_hierarchy_depth_inter); + hantro_reg_write(vpu, &hevc_max_intra_hierdepth, + sps->max_transform_hierarchy_depth_intra); + hantro_reg_write(vpu, &hevc_min_trb_size, + sps->log2_min_luma_transform_block_size_minus2 + 2); + hantro_reg_write(vpu, &hevc_max_trb_size, + sps->log2_min_luma_transform_block_size_minus2 + 2 + + sps->log2_diff_max_min_luma_transform_block_size); + + hantro_reg_write(vpu, &g2_tempor_mvp_e, + !!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) && + !(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC)); + hantro_reg_write(vpu, &g2_strong_smooth_e, + !!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED)); + hantro_reg_write(vpu, &g2_asym_pred_e, + !!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED)); + hantro_reg_write(vpu, &g2_sao_e, + !!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET)); + hantro_reg_write(vpu, &g2_sign_data_hide, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED)); + + if (pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED) { + hantro_reg_write(vpu, &g2_cu_qpd_e, 1); + hantro_reg_write(vpu, &g2_max_cu_qpd_depth, pps->diff_cu_qp_delta_depth); + } else { + hantro_reg_write(vpu, &g2_cu_qpd_e, 0); + hantro_reg_write(vpu, &g2_max_cu_qpd_depth, 0); + } + + if (pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT) { + hantro_reg_write(vpu, &g2_cb_qp_offset, pps->pps_cb_qp_offset); + hantro_reg_write(vpu, &g2_cr_qp_offset, pps->pps_cr_qp_offset); + } else { + hantro_reg_write(vpu, &g2_cb_qp_offset, 0); + hantro_reg_write(vpu, &g2_cr_qp_offset, 0); + } + + hantro_reg_write(vpu, &g2_filt_offset_beta, pps->pps_beta_offset_div2); + hantro_reg_write(vpu, &g2_filt_offset_tc, pps->pps_tc_offset_div2); + hantro_reg_write(vpu, &g2_slice_hdr_ext_e, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT)); + hantro_reg_write(vpu, &g2_slice_hdr_ext_bits, pps->num_extra_slice_header_bits); + hantro_reg_write(vpu, &g2_slice_chqp_present, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT)); + hantro_reg_write(vpu, &g2_weight_bipr_idc, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED)); + hantro_reg_write(vpu, &g2_transq_bypass, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED)); + hantro_reg_write(vpu, &g2_list_mod_e, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT)); + hantro_reg_write(vpu, &g2_entropy_sync_e, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED)); + hantro_reg_write(vpu, &g2_cabac_init_present, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT)); + hantro_reg_write(vpu, &g2_idr_pic_e, + !!(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC)); + hantro_reg_write(vpu, &hevc_parallel_merge, + pps->log2_parallel_merge_level_minus2 + 2); + hantro_reg_write(vpu, &g2_pcm_filt_d, + !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED)); + hantro_reg_write(vpu, &g2_pcm_e, + !!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)); + if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) { + hantro_reg_write(vpu, &g2_max_pcm_size, + sps->log2_diff_max_min_pcm_luma_coding_block_size + + sps->log2_min_pcm_luma_coding_block_size_minus3 + 3); + hantro_reg_write(vpu, &g2_min_pcm_size, + sps->log2_min_pcm_luma_coding_block_size_minus3 + 3); + hantro_reg_write(vpu, &g2_bit_depth_pcm_y, + sps->pcm_sample_bit_depth_luma_minus1 + 1); + hantro_reg_write(vpu, &g2_bit_depth_pcm_c, + sps->pcm_sample_bit_depth_chroma_minus1 + 1); + } else { + hantro_reg_write(vpu, &g2_max_pcm_size, 0); + hantro_reg_write(vpu, &g2_min_pcm_size, 0); + hantro_reg_write(vpu, &g2_bit_depth_pcm_y, 0); + hantro_reg_write(vpu, &g2_bit_depth_pcm_c, 0); + } + + hantro_reg_write(vpu, &g2_start_code_e, 1); + hantro_reg_write(vpu, &g2_init_qp, pps->init_qp_minus26 + 26); + hantro_reg_write(vpu, &g2_weight_pred_e, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED)); + hantro_reg_write(vpu, &g2_cabac_init_present, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT)); + hantro_reg_write(vpu, &g2_const_intra_e, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED)); + hantro_reg_write(vpu, &g2_transform_skip, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED)); + hantro_reg_write(vpu, &g2_out_filtering_dis, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER)); + hantro_reg_write(vpu, &g2_filt_ctrl_pres, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT)); + hantro_reg_write(vpu, &g2_dependent_slice, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED)); + hantro_reg_write(vpu, &g2_filter_override, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED)); + hantro_reg_write(vpu, &g2_refidx0_active, + pps->num_ref_idx_l0_default_active_minus1 + 1); + hantro_reg_write(vpu, &g2_refidx1_active, + pps->num_ref_idx_l1_default_active_minus1 + 1); + hantro_reg_write(vpu, &g2_apf_threshold, 8); +} + +static int find_ref_pic_index(const struct v4l2_hevc_dpb_entry *dpb, int pic_order_cnt) +{ + int i; + + for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) { + if (dpb[i].pic_order_cnt[0] == pic_order_cnt) + return i; + } + + return 0x0; +} + +static void set_ref_pic_list(struct hantro_ctx *ctx) +{ + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + struct hantro_dev *vpu = ctx->dev; + const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params; + const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb; + u32 list0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {}; + u32 list1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {}; + static const struct hantro_reg ref_pic_regs0[] = { + hevc_rlist_f0, + hevc_rlist_f1, + hevc_rlist_f2, + hevc_rlist_f3, + hevc_rlist_f4, + hevc_rlist_f5, + hevc_rlist_f6, + hevc_rlist_f7, + hevc_rlist_f8, + hevc_rlist_f9, + hevc_rlist_f10, + hevc_rlist_f11, + hevc_rlist_f12, + hevc_rlist_f13, + hevc_rlist_f14, + hevc_rlist_f15, + }; + static const struct hantro_reg ref_pic_regs1[] = { + hevc_rlist_b0, + hevc_rlist_b1, + hevc_rlist_b2, + hevc_rlist_b3, + hevc_rlist_b4, + hevc_rlist_b5, + hevc_rlist_b6, + hevc_rlist_b7, + hevc_rlist_b8, + hevc_rlist_b9, + hevc_rlist_b10, + hevc_rlist_b11, + hevc_rlist_b12, + hevc_rlist_b13, + hevc_rlist_b14, + hevc_rlist_b15, + }; + unsigned int i, j; + + /* List 0 contains: short term before, short term after and long term */ + j = 0; + for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list0); i++) + list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]); + for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list0); i++) + list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]); + for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list0); i++) + list0[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]); + + /* Fill the list, copying over and over */ + i = 0; + while (j < ARRAY_SIZE(list0)) + list0[j++] = list0[i++]; + + j = 0; + for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list1); i++) + list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]); + for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list1); i++) + list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]); + for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list1); i++) + list1[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]); + + i = 0; + while (j < ARRAY_SIZE(list1)) + list1[j++] = list1[i++]; + + for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) { + hantro_reg_write(vpu, &ref_pic_regs0[i], list0[i]); + hantro_reg_write(vpu, &ref_pic_regs1[i], list1[i]); + } +} + +static int set_ref(struct hantro_ctx *ctx) +{ + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps; + const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params; + const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb; + dma_addr_t luma_addr, chroma_addr, mv_addr = 0; + struct hantro_dev *vpu = ctx->dev; + size_t cr_offset = hantro_hevc_chroma_offset(sps); + size_t mv_offset = hantro_hevc_motion_vectors_offset(sps); + u32 max_ref_frames; + u16 dpb_longterm_e; + static const struct hantro_reg cur_poc[] = { + hevc_cur_poc_00, + hevc_cur_poc_01, + hevc_cur_poc_02, + hevc_cur_poc_03, + hevc_cur_poc_04, + hevc_cur_poc_05, + hevc_cur_poc_06, + hevc_cur_poc_07, + hevc_cur_poc_08, + hevc_cur_poc_09, + hevc_cur_poc_10, + hevc_cur_poc_11, + hevc_cur_poc_12, + hevc_cur_poc_13, + hevc_cur_poc_14, + hevc_cur_poc_15, + }; + unsigned int i; + + max_ref_frames = decode_params->num_poc_lt_curr + + decode_params->num_poc_st_curr_before + + decode_params->num_poc_st_curr_after; + /* + * Set max_ref_frames to non-zero to avoid HW hang when decoding + * badly marked I-frames. + */ + max_ref_frames = max_ref_frames ? max_ref_frames : 1; + hantro_reg_write(vpu, &g2_num_ref_frames, max_ref_frames); + hantro_reg_write(vpu, &g2_filter_over_slices, + !!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED)); + hantro_reg_write(vpu, &g2_filter_over_tiles, + !!(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. + */ + 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]; + + hantro_reg_write(vpu, &cur_poc[i], poc_diff); + } + + if (i < ARRAY_SIZE(cur_poc)) { + /* + * After the references, fill one entry pointing to itself, + * i.e. difference is zero. + */ + hantro_reg_write(vpu, &cur_poc[i], 0); + i++; + } + + /* Fill the rest with the current picture */ + for (; i < ARRAY_SIZE(cur_poc); i++) + hantro_reg_write(vpu, &cur_poc[i], decode_params->pic_order_cnt_val); + + set_ref_pic_list(ctx); + + /* We will only keep the references picture that are still used */ + ctx->hevc_dec.ref_bufs_used = 0; + + /* Set up addresses of DPB buffers */ + 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]); + if (!luma_addr) + return -ENOMEM; + + chroma_addr = luma_addr + cr_offset; + mv_addr = luma_addr + mv_offset; + + if (dpb[i].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR) + dpb_longterm_e |= BIT(V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1 - i); + + hantro_write_addr(vpu, G2_REG_ADDR_REF(i), luma_addr); + hantro_write_addr(vpu, G2_REG_CHR_REF(i), chroma_addr); + hantro_write_addr(vpu, G2_REG_DMV_REF(i), mv_addr); + } + + luma_addr = hantro_hevc_get_ref_buf(ctx, decode_params->pic_order_cnt_val); + if (!luma_addr) + return -ENOMEM; + + chroma_addr = luma_addr + cr_offset; + mv_addr = luma_addr + mv_offset; + + hantro_write_addr(vpu, G2_REG_ADDR_REF(i), luma_addr); + hantro_write_addr(vpu, G2_REG_CHR_REF(i), chroma_addr); + hantro_write_addr(vpu, G2_REG_DMV_REF(i++), mv_addr); + + hantro_write_addr(vpu, G2_ADDR_DST, luma_addr); + hantro_write_addr(vpu, G2_ADDR_DST_CHR, chroma_addr); + hantro_write_addr(vpu, G2_ADDR_DST_MV, mv_addr); + + hantro_hevc_ref_remove_unused(ctx); + + for (; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) { + hantro_write_addr(vpu, G2_REG_ADDR_REF(i), 0); + hantro_write_addr(vpu, G2_REG_CHR_REF(i), 0); + hantro_write_addr(vpu, G2_REG_DMV_REF(i), 0); + } + + hantro_reg_write(vpu, &g2_refer_lterm_e, dpb_longterm_e); + + return 0; +} + +static void set_buffers(struct hantro_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct hantro_dev *vpu = ctx->dev; + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + size_t cr_offset = hantro_hevc_chroma_offset(sps); + dma_addr_t src_dma, dst_dma; + u32 src_len, src_buf_len; + + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); + + /* Source (stream) buffer. */ + src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + src_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + src_buf_len = vb2_plane_size(&src_buf->vb2_buf, 0); + + hantro_write_addr(vpu, G2_ADDR_STR, src_dma); + hantro_reg_write(vpu, &g2_stream_len, src_len); + hantro_reg_write(vpu, &g2_strm_buffer_len, src_buf_len); + hantro_reg_write(vpu, &g2_strm_start_offset, 0); + hantro_reg_write(vpu, &g2_write_mvs_e, 1); + + /* Destination (decoded frame) buffer. */ + dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); + + hantro_write_addr(vpu, G2_RASTER_SCAN, dst_dma); + hantro_write_addr(vpu, G2_RASTER_SCAN_CHR, dst_dma + cr_offset); + hantro_write_addr(vpu, G2_ADDR_TILE_SIZE, ctx->hevc_dec.tile_sizes.dma); + hantro_write_addr(vpu, G2_TILE_FILTER, ctx->hevc_dec.tile_filter.dma); + hantro_write_addr(vpu, G2_TILE_SAO, ctx->hevc_dec.tile_sao.dma); + hantro_write_addr(vpu, G2_TILE_BSD, ctx->hevc_dec.tile_bsd.dma); +} + +static void hantro_g2_check_idle(struct hantro_dev *vpu) +{ + int i; + + for (i = 0; i < 3; i++) { + u32 status; + + /* Make sure the VPU is idle */ + status = vdpu_read(vpu, G2_REG_INTERRUPT); + if (status & G2_REG_INTERRUPT_DEC_E) { + dev_warn(vpu->dev, "device still running, aborting"); + status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; + vdpu_write(vpu, status, G2_REG_INTERRUPT); + } + } +} + +int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + int ret; + + hantro_g2_check_idle(vpu); + + /* Prepare HEVC decoder context. */ + ret = hantro_hevc_dec_prepare_run(ctx); + if (ret) + return ret; + + /* Configure hardware registers. */ + set_params(ctx); + + /* set reference pictures */ + ret = set_ref(ctx); + if (ret) + return ret; + + set_buffers(ctx); + prepare_tile_info_buffer(ctx); + + hantro_end_prepare_run(ctx); + + hantro_reg_write(vpu, &g2_mode, HEVC_DEC_MODE); + hantro_reg_write(vpu, &g2_clk_gate_e, 1); + + /* Don't disable output */ + hantro_reg_write(vpu, &g2_out_dis, 0); + + /* Don't compress buffers */ + hantro_reg_write(vpu, &g2_ref_compress_bypass, 1); + + /* use NV12 as output format */ + hantro_reg_write(vpu, &g2_out_rs_e, 1); + + /* Bus width and max burst */ + hantro_reg_write(vpu, &g2_buswidth, BUS_WIDTH_128); + hantro_reg_write(vpu, &g2_max_burst, 16); + + /* Swap */ + hantro_reg_write(vpu, &g2_strm_swap, 0xf); + hantro_reg_write(vpu, &g2_dirmv_swap, 0xf); + hantro_reg_write(vpu, &g2_compress_swap, 0xf); + + /* Start decoding! */ + vdpu_write(vpu, G2_REG_INTERRUPT_DEC_E, G2_REG_INTERRUPT); + + return 0; +} diff --git a/drivers/staging/media/hantro/hantro_g2_regs.h b/drivers/staging/media/hantro/hantro_g2_regs.h new file mode 100644 index 000000000000..bb22fa921914 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g2_regs.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021, Collabora + * + * Author: Benjamin Gaignard <benjamin.gaignard@collabora.com> + */ + +#ifndef HANTRO_G2_REGS_H_ +#define HANTRO_G2_REGS_H_ + +#include "hantro.h" + +#define G2_SWREG(nr) ((nr) * 4) + +#define G2_DEC_REG(b, s, m) \ + ((const struct hantro_reg) { \ + .base = G2_SWREG(b), \ + .shift = s, \ + .mask = m, \ + }) + +#define G2_REG_VERSION G2_SWREG(0) + +#define G2_REG_INTERRUPT G2_SWREG(1) +#define G2_REG_INTERRUPT_DEC_RDY_INT BIT(12) +#define G2_REG_INTERRUPT_DEC_ABORT_E BIT(5) +#define G2_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) +#define G2_REG_INTERRUPT_DEC_E BIT(0) + +#define g2_strm_swap G2_DEC_REG(2, 28, 0xf) +#define g2_dirmv_swap G2_DEC_REG(2, 20, 0xf) + +#define g2_mode G2_DEC_REG(3, 27, 0x1f) +#define g2_compress_swap G2_DEC_REG(3, 20, 0xf) +#define g2_ref_compress_bypass G2_DEC_REG(3, 17, 0x1) +#define g2_out_rs_e G2_DEC_REG(3, 16, 0x1) +#define g2_out_dis G2_DEC_REG(3, 15, 0x1) +#define g2_out_filtering_dis G2_DEC_REG(3, 14, 0x1) +#define g2_write_mvs_e G2_DEC_REG(3, 12, 0x1) + +#define g2_pic_width_in_cbs G2_DEC_REG(4, 19, 0x1fff) +#define g2_pic_height_in_cbs G2_DEC_REG(4, 6, 0x1fff) +#define g2_num_ref_frames G2_DEC_REG(4, 0, 0x1f) + +#define g2_scaling_list_e G2_DEC_REG(5, 24, 0x1) +#define g2_cb_qp_offset G2_DEC_REG(5, 19, 0x1f) +#define g2_cr_qp_offset G2_DEC_REG(5, 14, 0x1f) +#define g2_sign_data_hide G2_DEC_REG(5, 12, 0x1) +#define g2_tempor_mvp_e G2_DEC_REG(5, 11, 0x1) +#define g2_max_cu_qpd_depth G2_DEC_REG(5, 5, 0x3f) +#define g2_cu_qpd_e G2_DEC_REG(5, 4, 0x1) + +#define g2_stream_len G2_DEC_REG(6, 0, 0xffffffff) + +#define g2_cabac_init_present G2_DEC_REG(7, 31, 0x1) +#define g2_weight_pred_e G2_DEC_REG(7, 28, 0x1) +#define g2_weight_bipr_idc G2_DEC_REG(7, 26, 0x3) +#define g2_filter_over_slices G2_DEC_REG(7, 25, 0x1) +#define g2_filter_over_tiles G2_DEC_REG(7, 24, 0x1) +#define g2_asym_pred_e G2_DEC_REG(7, 23, 0x1) +#define g2_sao_e G2_DEC_REG(7, 22, 0x1) +#define g2_pcm_filt_d G2_DEC_REG(7, 21, 0x1) +#define g2_slice_chqp_present G2_DEC_REG(7, 20, 0x1) +#define g2_dependent_slice G2_DEC_REG(7, 19, 0x1) +#define g2_filter_override G2_DEC_REG(7, 18, 0x1) +#define g2_strong_smooth_e G2_DEC_REG(7, 17, 0x1) +#define g2_filt_offset_beta G2_DEC_REG(7, 12, 0x1f) +#define g2_filt_offset_tc G2_DEC_REG(7, 7, 0x1f) +#define g2_slice_hdr_ext_e G2_DEC_REG(7, 6, 0x1) +#define g2_slice_hdr_ext_bits G2_DEC_REG(7, 3, 0x7) + +#define g2_const_intra_e G2_DEC_REG(8, 31, 0x1) +#define g2_filt_ctrl_pres G2_DEC_REG(8, 30, 0x1) +#define g2_idr_pic_e G2_DEC_REG(8, 16, 0x1) +#define g2_bit_depth_pcm_y G2_DEC_REG(8, 12, 0xf) +#define g2_bit_depth_pcm_c G2_DEC_REG(8, 8, 0xf) +#define g2_bit_depth_y_minus8 G2_DEC_REG(8, 6, 0x3) +#define g2_bit_depth_c_minus8 G2_DEC_REG(8, 4, 0x3) +#define g2_output_8_bits G2_DEC_REG(8, 3, 0x1) + +#define g2_refidx1_active G2_DEC_REG(9, 19, 0x1f) +#define g2_refidx0_active G2_DEC_REG(9, 14, 0x1f) +#define g2_hdr_skip_length G2_DEC_REG(9, 0, 0x3fff) + +#define g2_start_code_e G2_DEC_REG(10, 31, 0x1) +#define g2_init_qp G2_DEC_REG(10, 24, 0x3f) +#define g2_num_tile_cols G2_DEC_REG(10, 19, 0x1f) +#define g2_num_tile_rows G2_DEC_REG(10, 14, 0x1f) +#define g2_tile_e G2_DEC_REG(10, 1, 0x1) +#define g2_entropy_sync_e G2_DEC_REG(10, 0, 0x1) + +#define g2_refer_lterm_e G2_DEC_REG(12, 16, 0xffff) +#define g2_min_cb_size G2_DEC_REG(12, 13, 0x7) +#define g2_max_cb_size G2_DEC_REG(12, 10, 0x7) +#define g2_min_pcm_size G2_DEC_REG(12, 7, 0x7) +#define g2_max_pcm_size G2_DEC_REG(12, 4, 0x7) +#define g2_pcm_e G2_DEC_REG(12, 3, 0x1) +#define g2_transform_skip G2_DEC_REG(12, 2, 0x1) +#define g2_transq_bypass G2_DEC_REG(12, 1, 0x1) +#define g2_list_mod_e G2_DEC_REG(12, 0, 0x1) + +#define hevc_min_trb_size G2_DEC_REG(13, 13, 0x7) +#define hevc_max_trb_size G2_DEC_REG(13, 10, 0x7) +#define hevc_max_intra_hierdepth G2_DEC_REG(13, 7, 0x7) +#define hevc_max_inter_hierdepth G2_DEC_REG(13, 4, 0x7) +#define hevc_parallel_merge G2_DEC_REG(13, 0, 0xf) + +#define hevc_rlist_f0 G2_DEC_REG(14, 0, 0x1f) +#define hevc_rlist_f1 G2_DEC_REG(14, 10, 0x1f) +#define hevc_rlist_f2 G2_DEC_REG(14, 20, 0x1f) +#define hevc_rlist_b0 G2_DEC_REG(14, 5, 0x1f) +#define hevc_rlist_b1 G2_DEC_REG(14, 15, 0x1f) +#define hevc_rlist_b2 G2_DEC_REG(14, 25, 0x1f) + +#define hevc_rlist_f3 G2_DEC_REG(15, 0, 0x1f) +#define hevc_rlist_f4 G2_DEC_REG(15, 10, 0x1f) +#define hevc_rlist_f5 G2_DEC_REG(15, 20, 0x1f) +#define hevc_rlist_b3 G2_DEC_REG(15, 5, 0x1f) +#define hevc_rlist_b4 G2_DEC_REG(15, 15, 0x1f) +#define hevc_rlist_b5 G2_DEC_REG(15, 25, 0x1f) + +#define hevc_rlist_f6 G2_DEC_REG(16, 0, 0x1f) +#define hevc_rlist_f7 G2_DEC_REG(16, 10, 0x1f) +#define hevc_rlist_f8 G2_DEC_REG(16, 20, 0x1f) +#define hevc_rlist_b6 G2_DEC_REG(16, 5, 0x1f) +#define hevc_rlist_b7 G2_DEC_REG(16, 15, 0x1f) +#define hevc_rlist_b8 G2_DEC_REG(16, 25, 0x1f) + +#define hevc_rlist_f9 G2_DEC_REG(17, 0, 0x1f) +#define hevc_rlist_f10 G2_DEC_REG(17, 10, 0x1f) +#define hevc_rlist_f11 G2_DEC_REG(17, 20, 0x1f) +#define hevc_rlist_b9 G2_DEC_REG(17, 5, 0x1f) +#define hevc_rlist_b10 G2_DEC_REG(17, 15, 0x1f) +#define hevc_rlist_b11 G2_DEC_REG(17, 25, 0x1f) + +#define hevc_rlist_f12 G2_DEC_REG(18, 0, 0x1f) +#define hevc_rlist_f13 G2_DEC_REG(18, 10, 0x1f) +#define hevc_rlist_f14 G2_DEC_REG(18, 20, 0x1f) +#define hevc_rlist_b12 G2_DEC_REG(18, 5, 0x1f) +#define hevc_rlist_b13 G2_DEC_REG(18, 15, 0x1f) +#define hevc_rlist_b14 G2_DEC_REG(18, 25, 0x1f) + +#define hevc_rlist_f15 G2_DEC_REG(19, 0, 0x1f) +#define hevc_rlist_b15 G2_DEC_REG(19, 5, 0x1f) + +#define g2_partial_ctb_x G2_DEC_REG(20, 31, 0x1) +#define g2_partial_ctb_y G2_DEC_REG(20, 30, 0x1) +#define g2_pic_width_4x4 G2_DEC_REG(20, 16, 0xfff) +#define g2_pic_height_4x4 G2_DEC_REG(20, 0, 0xfff) +#define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff) +#define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff) +#define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff) +#define hevc_cur_poc_03 G2_DEC_REG(46, 0, 0xff) + +#define hevc_cur_poc_04 G2_DEC_REG(47, 24, 0xff) +#define hevc_cur_poc_05 G2_DEC_REG(47, 16, 0xff) +#define hevc_cur_poc_06 G2_DEC_REG(47, 8, 0xff) +#define hevc_cur_poc_07 G2_DEC_REG(47, 0, 0xff) + +#define hevc_cur_poc_08 G2_DEC_REG(48, 24, 0xff) +#define hevc_cur_poc_09 G2_DEC_REG(48, 16, 0xff) +#define hevc_cur_poc_10 G2_DEC_REG(48, 8, 0xff) +#define hevc_cur_poc_11 G2_DEC_REG(48, 0, 0xff) + +#define hevc_cur_poc_12 G2_DEC_REG(49, 24, 0xff) +#define hevc_cur_poc_13 G2_DEC_REG(49, 16, 0xff) +#define hevc_cur_poc_14 G2_DEC_REG(49, 8, 0xff) +#define hevc_cur_poc_15 G2_DEC_REG(49, 0, 0xff) + +#define g2_apf_threshold G2_DEC_REG(55, 0, 0xffff) + +#define g2_clk_gate_e G2_DEC_REG(58, 16, 0x1) +#define g2_buswidth G2_DEC_REG(58, 8, 0x7) +#define g2_max_burst G2_DEC_REG(58, 0, 0xff) + +#define G2_REG_CONFIG G2_SWREG(58) +#define G2_REG_CONFIG_DEC_CLK_GATE_E BIT(16) +#define G2_REG_CONFIG_DEC_CLK_GATE_IDLE_E BIT(17) + +#define G2_ADDR_DST (G2_SWREG(65)) +#define G2_REG_ADDR_REF(i) (G2_SWREG(67) + ((i) * 0x8)) +#define G2_ADDR_DST_CHR (G2_SWREG(99)) +#define G2_REG_CHR_REF(i) (G2_SWREG(101) + ((i) * 0x8)) +#define G2_ADDR_DST_MV (G2_SWREG(133)) +#define G2_REG_DMV_REF(i) (G2_SWREG(135) + ((i) * 0x8)) +#define G2_ADDR_TILE_SIZE (G2_SWREG(167)) +#define G2_ADDR_STR (G2_SWREG(169)) +#define HEVC_SCALING_LIST (G2_SWREG(171)) +#define G2_RASTER_SCAN (G2_SWREG(175)) +#define G2_RASTER_SCAN_CHR (G2_SWREG(177)) +#define G2_TILE_FILTER (G2_SWREG(179)) +#define G2_TILE_SAO (G2_SWREG(181)) +#define G2_TILE_BSD (G2_SWREG(183)) + +#define g2_strm_buffer_len G2_DEC_REG(258, 0, 0xffffffff) +#define g2_strm_start_offset G2_DEC_REG(259, 0, 0xffffffff) + +#endif diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index b88dc4ed06db..56cf261a8e95 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -88,7 +88,7 @@ hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu, } } -void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) +int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -136,6 +136,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) hantro_end_prepare_run(ctx); vepu_write(vpu, reg, H1_REG_ENC_CTRL); + + return 0; } void hantro_jpeg_enc_done(struct hantro_ctx *ctx) diff --git a/drivers/staging/media/hantro/hantro_hevc.c b/drivers/staging/media/hantro/hantro_hevc.c new file mode 100644 index 000000000000..5347f5a41c2a --- /dev/null +++ b/drivers/staging/media/hantro/hantro_hevc.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU HEVC codec driver + * + * Copyright (C) 2020 Safran Passenger Innovations LLC + */ + +#include <linux/types.h> +#include <media/v4l2-mem2mem.h> + +#include "hantro.h" +#include "hantro_hw.h" + +#define VERT_FILTER_RAM_SIZE 8 /* bytes per pixel row */ +/* + * BSD control data of current picture at tile border + * 128 bits per 4x4 tile = 128/(8*4) bytes per row + */ +#define BSD_CTRL_RAM_SIZE 4 /* bytes per pixel row */ +/* tile border coefficients of filter */ +#define VERT_SAO_RAM_SIZE 48 /* bytes per pixel */ + +#define MAX_TILE_COLS 20 +#define MAX_TILE_ROWS 22 + +#define UNUSED_REF -1 + +#define G2_ALIGN 16 + +size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps) +{ + int bytes_per_pixel = sps->bit_depth_luma_minus8 == 0 ? 1 : 2; + + return sps->pic_width_in_luma_samples * + sps->pic_height_in_luma_samples * bytes_per_pixel; +} + +size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps) +{ + size_t cr_offset = hantro_hevc_chroma_offset(sps); + + return ALIGN((cr_offset * 3) / 2, G2_ALIGN); +} + +static size_t hantro_hevc_mv_size(const struct v4l2_ctrl_hevc_sps *sps) +{ + u32 min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; + u32 ctb_log2_size_y = min_cb_log2_size_y + sps->log2_diff_max_min_luma_coding_block_size; + u32 pic_width_in_ctbs_y = (sps->pic_width_in_luma_samples + (1 << ctb_log2_size_y) - 1) + >> ctb_log2_size_y; + u32 pic_height_in_ctbs_y = (sps->pic_height_in_luma_samples + (1 << ctb_log2_size_y) - 1) + >> ctb_log2_size_y; + size_t mv_size; + + mv_size = pic_width_in_ctbs_y * pic_height_in_ctbs_y * + (1 << (2 * (ctb_log2_size_y - 4))) * 16; + + vpu_debug(4, "%dx%d (CTBs) %zu MV bytes\n", + pic_width_in_ctbs_y, pic_height_in_ctbs_y, mv_size); + + return mv_size; +} + +static size_t hantro_hevc_ref_size(struct hantro_ctx *ctx) +{ + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + + return hantro_hevc_motion_vectors_offset(sps) + hantro_hevc_mv_size(sps); +} + +static void hantro_hevc_ref_free(struct hantro_ctx *ctx) +{ + struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; + struct hantro_dev *vpu = ctx->dev; + int i; + + for (i = 0; i < NUM_REF_PICTURES; i++) { + if (hevc_dec->ref_bufs[i].cpu) + dma_free_coherent(vpu->dev, hevc_dec->ref_bufs[i].size, + hevc_dec->ref_bufs[i].cpu, + hevc_dec->ref_bufs[i].dma); + } +} + +static void hantro_hevc_ref_init(struct hantro_ctx *ctx) +{ + struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; + int i; + + for (i = 0; i < NUM_REF_PICTURES; i++) + hevc_dec->ref_bufs_poc[i] = UNUSED_REF; +} + +dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, + int poc) +{ + struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; + int i; + + /* Find the reference buffer in already know ones */ + for (i = 0; i < NUM_REF_PICTURES; i++) { + if (hevc_dec->ref_bufs_poc[i] == poc) { + hevc_dec->ref_bufs_used |= 1 << i; + return hevc_dec->ref_bufs[i].dma; + } + } + + /* Allocate a new reference buffer */ + for (i = 0; i < NUM_REF_PICTURES; i++) { + if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF) { + if (!hevc_dec->ref_bufs[i].cpu) { + struct hantro_dev *vpu = ctx->dev; + + /* + * Allocate the space needed for the raw data + + * motion vector data. Optimizations could be to + * allocate raw data in non coherent memory and only + * clear the motion vector data. + */ + hevc_dec->ref_bufs[i].cpu = + dma_alloc_coherent(vpu->dev, + hantro_hevc_ref_size(ctx), + &hevc_dec->ref_bufs[i].dma, + GFP_KERNEL); + if (!hevc_dec->ref_bufs[i].cpu) + return 0; + + hevc_dec->ref_bufs[i].size = hantro_hevc_ref_size(ctx); + } + hevc_dec->ref_bufs_used |= 1 << i; + memset(hevc_dec->ref_bufs[i].cpu, 0, hantro_hevc_ref_size(ctx)); + hevc_dec->ref_bufs_poc[i] = poc; + + return hevc_dec->ref_bufs[i].dma; + } + } + + return 0; +} + +void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx) +{ + struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; + int i; + + /* Just tag buffer as unused, do not free them */ + for (i = 0; i < NUM_REF_PICTURES; i++) { + if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF) + continue; + + if (hevc_dec->ref_bufs_used & (1 << i)) + continue; + + hevc_dec->ref_bufs_poc[i] = UNUSED_REF; + } +} + +static int tile_buffer_reallocate(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; + const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; + const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps; + const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; + unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1; + unsigned int height64 = (sps->pic_height_in_luma_samples + 63) & ~63; + unsigned int size; + + if (num_tile_cols <= 1 || + num_tile_cols <= hevc_dec->num_tile_cols_allocated) + return 0; + + /* Need to reallocate due to tiles passed via PPS */ + if (hevc_dec->tile_filter.cpu) { + dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size, + hevc_dec->tile_filter.cpu, + hevc_dec->tile_filter.dma); + hevc_dec->tile_filter.cpu = NULL; + } + + if (hevc_dec->tile_sao.cpu) { + dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size, + hevc_dec->tile_sao.cpu, + hevc_dec->tile_sao.dma); + hevc_dec->tile_sao.cpu = NULL; + } + + if (hevc_dec->tile_bsd.cpu) { + dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size, + hevc_dec->tile_bsd.cpu, + hevc_dec->tile_bsd.dma); + hevc_dec->tile_bsd.cpu = NULL; + } + + size = VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1); + hevc_dec->tile_filter.cpu = dma_alloc_coherent(vpu->dev, size, + &hevc_dec->tile_filter.dma, + GFP_KERNEL); + if (!hevc_dec->tile_filter.cpu) + goto err_free_tile_buffers; + hevc_dec->tile_filter.size = size; + + size = VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1); + hevc_dec->tile_sao.cpu = dma_alloc_coherent(vpu->dev, size, + &hevc_dec->tile_sao.dma, + GFP_KERNEL); + if (!hevc_dec->tile_sao.cpu) + goto err_free_tile_buffers; + hevc_dec->tile_sao.size = size; + + size = BSD_CTRL_RAM_SIZE * height64 * (num_tile_cols - 1); + hevc_dec->tile_bsd.cpu = dma_alloc_coherent(vpu->dev, size, + &hevc_dec->tile_bsd.dma, + GFP_KERNEL); + if (!hevc_dec->tile_bsd.cpu) + goto err_free_tile_buffers; + hevc_dec->tile_bsd.size = size; + + hevc_dec->num_tile_cols_allocated = num_tile_cols; + + return 0; + +err_free_tile_buffers: + if (hevc_dec->tile_filter.cpu) + dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size, + hevc_dec->tile_filter.cpu, + hevc_dec->tile_filter.dma); + hevc_dec->tile_filter.cpu = NULL; + + if (hevc_dec->tile_sao.cpu) + dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size, + hevc_dec->tile_sao.cpu, + hevc_dec->tile_sao.dma); + hevc_dec->tile_sao.cpu = NULL; + + if (hevc_dec->tile_bsd.cpu) + dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size, + hevc_dec->tile_bsd.cpu, + hevc_dec->tile_bsd.dma); + hevc_dec->tile_bsd.cpu = NULL; + + return -ENOMEM; +} + +int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx) +{ + struct hantro_hevc_dec_hw_ctx *hevc_ctx = &ctx->hevc_dec; + struct hantro_hevc_dec_ctrls *ctrls = &hevc_ctx->ctrls; + int ret; + + hantro_start_prepare_run(ctx); + + ctrls->decode_params = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS); + if (WARN_ON(!ctrls->decode_params)) + return -EINVAL; + + ctrls->sps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS); + if (WARN_ON(!ctrls->sps)) + return -EINVAL; + + ctrls->pps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_PPS); + if (WARN_ON(!ctrls->pps)) + return -EINVAL; + + ret = tile_buffer_reallocate(ctx); + if (ret) + return ret; + + return 0; +} + +void hantro_hevc_dec_exit(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; + + if (hevc_dec->tile_sizes.cpu) + dma_free_coherent(vpu->dev, hevc_dec->tile_sizes.size, + hevc_dec->tile_sizes.cpu, + hevc_dec->tile_sizes.dma); + hevc_dec->tile_sizes.cpu = NULL; + + if (hevc_dec->tile_filter.cpu) + dma_free_coherent(vpu->dev, hevc_dec->tile_filter.size, + hevc_dec->tile_filter.cpu, + hevc_dec->tile_filter.dma); + hevc_dec->tile_filter.cpu = NULL; + + if (hevc_dec->tile_sao.cpu) + dma_free_coherent(vpu->dev, hevc_dec->tile_sao.size, + hevc_dec->tile_sao.cpu, + hevc_dec->tile_sao.dma); + hevc_dec->tile_sao.cpu = NULL; + + if (hevc_dec->tile_bsd.cpu) + dma_free_coherent(vpu->dev, hevc_dec->tile_bsd.size, + hevc_dec->tile_bsd.cpu, + hevc_dec->tile_bsd.dma); + hevc_dec->tile_bsd.cpu = NULL; + + hantro_hevc_ref_free(ctx); +} + +int hantro_hevc_dec_init(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; + unsigned int size; + + memset(hevc_dec, 0, sizeof(*hevc_dec)); + + /* + * Maximum number of tiles times width and height (2 bytes each), + * rounding up to next 16 bytes boundary + one extra 16 byte + * chunk (HW guys wanted to have this). + */ + size = round_up(MAX_TILE_COLS * MAX_TILE_ROWS * 4 * sizeof(u16) + 16, 16); + hevc_dec->tile_sizes.cpu = dma_alloc_coherent(vpu->dev, size, + &hevc_dec->tile_sizes.dma, + GFP_KERNEL); + if (!hevc_dec->tile_sizes.cpu) + return -ENOMEM; + + hevc_dec->tile_sizes.size = size; + + hantro_hevc_ref_init(ctx); + + return 0; +} diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 83b3e42b63a3..5dcf65805396 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -20,6 +20,8 @@ #define MB_WIDTH(w) DIV_ROUND_UP(w, MB_DIM) #define MB_HEIGHT(h) DIV_ROUND_UP(h, MB_DIM) +#define NUM_REF_PICTURES (V4L2_HEVC_DPB_ENTRIES_NUM_MAX + 1) + struct hantro_dev; struct hantro_ctx; struct hantro_buf; @@ -96,6 +98,46 @@ struct hantro_h264_dec_hw_ctx { }; /** + * struct hantro_hevc_dec_ctrls + * @decode_params: Decode params + * @sps: SPS info + * @pps: PPS info + * @hevc_hdr_skip_length: the number of data (in bits) to skip in the + * slice segment header syntax after 'slice type' + * token + */ +struct hantro_hevc_dec_ctrls { + const struct v4l2_ctrl_hevc_decode_params *decode_params; + const struct v4l2_ctrl_hevc_sps *sps; + const struct v4l2_ctrl_hevc_pps *pps; + u32 hevc_hdr_skip_length; +}; + +/** + * struct hantro_hevc_dec_hw_ctx + * @tile_sizes: Tile sizes buffer + * @tile_filter: Tile vertical filter buffer + * @tile_sao: Tile SAO buffer + * @tile_bsd: Tile BSD control buffer + * @ref_bufs: Internal reference buffers + * @ref_bufs_poc: Internal reference buffers picture order count + * @ref_bufs_used: Bitfield of used reference buffers + * @ctrls: V4L2 controls attached to a run + * @num_tile_cols_allocated: number of allocated tiles + */ +struct hantro_hevc_dec_hw_ctx { + struct hantro_aux_buf tile_sizes; + struct hantro_aux_buf tile_filter; + struct hantro_aux_buf tile_sao; + struct hantro_aux_buf tile_bsd; + struct hantro_aux_buf ref_bufs[NUM_REF_PICTURES]; + int ref_bufs_poc[NUM_REF_PICTURES]; + u32 ref_bufs_used; + struct hantro_hevc_dec_ctrls ctrls; + unsigned int num_tile_cols_allocated; +}; + +/** * struct hantro_mpeg2_dec_hw_ctx * * @qtable: Quantization table @@ -133,14 +175,15 @@ struct hantro_postproc_ctx { * Optional and called from process context. * @run: Start single {en,de)coding job. Called from atomic context * to indicate that a pair of buffers is ready and the hardware - * should be programmed and started. + * should be programmed and started. Returns zero if OK, a + * negative value in error cases. * @done: Read back processing results and additional data from hardware. * @reset: Reset the hardware in case of a timeout. */ struct hantro_codec_ops { int (*init)(struct hantro_ctx *ctx); void (*exit)(struct hantro_ctx *ctx); - void (*run)(struct hantro_ctx *ctx); + int (*run)(struct hantro_ctx *ctx); void (*done)(struct hantro_ctx *ctx); void (*reset)(struct hantro_ctx *ctx); }; @@ -148,22 +191,26 @@ struct hantro_codec_ops { /** * enum hantro_enc_fmt - source format ID for hardware registers. * - * @RK3288_VPU_ENC_FMT_YUV420P: Y/CbCr 4:2:0 planar format - * @RK3288_VPU_ENC_FMT_YUV420SP: Y/CbCr 4:2:0 semi-planar format - * @RK3288_VPU_ENC_FMT_YUYV422: YUV 4:2:2 packed format (YUYV) - * @RK3288_VPU_ENC_FMT_UYVY422: YUV 4:2:2 packed format (UYVY) + * @ROCKCHIP_VPU_ENC_FMT_YUV420P: Y/CbCr 4:2:0 planar format + * @ROCKCHIP_VPU_ENC_FMT_YUV420SP: Y/CbCr 4:2:0 semi-planar format + * @ROCKCHIP_VPU_ENC_FMT_YUYV422: YUV 4:2:2 packed format (YUYV) + * @ROCKCHIP_VPU_ENC_FMT_UYVY422: YUV 4:2:2 packed format (UYVY) */ enum hantro_enc_fmt { - RK3288_VPU_ENC_FMT_YUV420P = 0, - RK3288_VPU_ENC_FMT_YUV420SP = 1, - RK3288_VPU_ENC_FMT_YUYV422 = 2, - RK3288_VPU_ENC_FMT_UYVY422 = 3, + ROCKCHIP_VPU_ENC_FMT_YUV420P = 0, + ROCKCHIP_VPU_ENC_FMT_YUV420SP = 1, + ROCKCHIP_VPU_ENC_FMT_YUYV422 = 2, + ROCKCHIP_VPU_ENC_FMT_UYVY422 = 3, }; -extern const struct hantro_variant rk3399_vpu_variant; -extern const struct hantro_variant rk3328_vpu_variant; -extern const struct hantro_variant rk3288_vpu_variant; +extern const struct hantro_variant imx8mq_vpu_g2_variant; extern const struct hantro_variant imx8mq_vpu_variant; +extern const struct hantro_variant rk3036_vpu_variant; +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 sama5d4_vdec_variant; extern const struct hantro_postproc_regs hantro_g1_postproc_regs; @@ -176,8 +223,11 @@ void hantro_irq_done(struct hantro_dev *vpu, void hantro_start_prepare_run(struct hantro_ctx *ctx); void hantro_end_prepare_run(struct hantro_ctx *ctx); -void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); -void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); +irqreturn_t hantro_g1_irq(int irq, void *dev_id); +void hantro_g1_reset(struct hantro_ctx *ctx); + +int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); +int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx); int hantro_jpeg_enc_init(struct hantro_ctx *ctx); void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); void hantro_jpeg_enc_done(struct hantro_ctx *ctx); @@ -185,10 +235,19 @@ void hantro_jpeg_enc_done(struct hantro_ctx *ctx); dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, unsigned int dpb_idx); int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); -void hantro_g1_h264_dec_run(struct hantro_ctx *ctx); +int hantro_g1_h264_dec_run(struct hantro_ctx *ctx); int hantro_h264_dec_init(struct hantro_ctx *ctx); void hantro_h264_dec_exit(struct hantro_ctx *ctx); +int hantro_hevc_dec_init(struct hantro_ctx *ctx); +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); +dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, int poc); +void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx); +size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps); +size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps); + static inline size_t hantro_h264_mv_size(unsigned int width, unsigned int height) { @@ -216,15 +275,15 @@ hantro_h264_mv_size(unsigned int width, unsigned int height) return 64 * MB_WIDTH(width) * MB_WIDTH(height) + 32; } -void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); -void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx); +int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); +int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx); void hantro_mpeg2_dec_copy_qtable(u8 *qtable, - const struct v4l2_ctrl_mpeg2_quantization *ctrl); + const struct v4l2_ctrl_mpeg2_quantisation *ctrl); int hantro_mpeg2_dec_init(struct hantro_ctx *ctx); void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx); -void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx); -void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx); +int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx); +int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx); int hantro_vp8_dec_init(struct hantro_ctx *ctx); void hantro_vp8_dec_exit(struct hantro_ctx *ctx); void hantro_vp8_prob_update(struct hantro_ctx *ctx, diff --git a/drivers/staging/media/hantro/hantro_mpeg2.c b/drivers/staging/media/hantro/hantro_mpeg2.c index 1d334e6fcd06..04e545eb0a83 100644 --- a/drivers/staging/media/hantro/hantro_mpeg2.c +++ b/drivers/staging/media/hantro/hantro_mpeg2.c @@ -19,7 +19,7 @@ static const u8 zigzag[64] = { }; void hantro_mpeg2_dec_copy_qtable(u8 *qtable, - const struct v4l2_ctrl_mpeg2_quantization *ctrl) + const struct v4l2_ctrl_mpeg2_quantisation *ctrl) { int i, n; diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/staging/media/hantro/hantro_postproc.c index 6d2a8f2a8f0b..ed8916c950a4 100644 --- a/drivers/staging/media/hantro/hantro_postproc.c +++ b/drivers/staging/media/hantro/hantro_postproc.c @@ -50,6 +50,20 @@ const struct hantro_postproc_regs hantro_g1_postproc_regs = { .display_width = {G1_REG_PP_DISPLAY_WIDTH, 0, 0xfff}, }; +bool hantro_needs_postproc(const struct hantro_ctx *ctx, + const struct hantro_fmt *fmt) +{ + struct hantro_dev *vpu = ctx->dev; + + if (ctx->is_encoder) + return false; + + if (!vpu->variant->postproc_fmts) + return false; + + return fmt->fourcc != V4L2_PIX_FMT_NV12; +} + void hantro_postproc_enable(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index 1bc118e375a1..bcb0bdff4a9a 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -55,7 +55,9 @@ static const struct hantro_fmt * hantro_get_postproc_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts) { - if (ctx->is_encoder) { + struct hantro_dev *vpu = ctx->dev; + + if (ctx->is_encoder || !vpu->variant->postproc_fmts) { *num_fmts = 0; return NULL; } @@ -390,6 +392,7 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) case V4L2_PIX_FMT_MPEG2_SLICE: case V4L2_PIX_FMT_VP8_FRAME: case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_HEVC_SLICE: ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; break; default: @@ -639,7 +642,14 @@ static int hantro_buf_prepare(struct vb2_buffer *vb) ret = hantro_buf_plane_check(vb, pix_fmt); if (ret) return ret; - vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage); + /* + * Buffer's bytesused must be written by driver for CAPTURE buffers. + * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets + * it to buffer length). + */ + if (V4L2_TYPE_IS_CAPTURE(vq->type)) + vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage); + return 0; } diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c index c222de075ef4..ea919bfb9891 100644 --- a/drivers/staging/media/hantro/imx8m_vpu_hw.c +++ b/drivers/staging/media/hantro/imx8m_vpu_hw.c @@ -11,6 +11,7 @@ #include "hantro.h" #include "hantro_jpeg.h" #include "hantro_g1_regs.h" +#include "hantro_g2_regs.h" #define CTRL_SOFT_RESET 0x00 #define RESET_G1 BIT(1) @@ -109,10 +110,10 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = { .frmsize = { .min_width = 48, .max_width = 3840, - .step_width = 16, + .step_width = MB_DIM, .min_height = 48, .max_height = 2160, - .step_height = 16, + .step_height = MB_DIM, }, }, { @@ -130,6 +131,26 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = { }, }; +static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .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, + }, + }, +}; + static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) { struct hantro_dev *vpu = dev_id; @@ -148,9 +169,26 @@ static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t imx8m_vpu_g2_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, G2_REG_INTERRUPT); + state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vdpu_write(vpu, 0, G2_REG_INTERRUPT); + vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG); + + hantro_irq_done(vpu, state); + + return IRQ_HANDLED; +} + static int imx8mq_vpu_hw_init(struct hantro_dev *vpu) { - vpu->dec_base = vpu->reg_bases[0]; vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1]; return 0; @@ -163,6 +201,13 @@ static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx) imx8m_soft_reset(vpu, RESET_G1); } +static void imx8m_vpu_g2_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + imx8m_soft_reset(vpu, RESET_G2); +} + /* * Supported codec ops. */ @@ -188,13 +233,25 @@ static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = { }, }; +static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { + [HANTRO_MODE_HEVC_DEC] = { + .run = hantro_g2_hevc_dec_run, + .reset = imx8m_vpu_g2_reset, + .init = hantro_hevc_dec_init, + .exit = hantro_hevc_dec_exit, + }, +}; + /* * VPU variants. */ static const struct hantro_irq imx8mq_irqs[] = { { "g1", imx8m_vpu_g1_irq }, - { "g2", NULL /* TODO: imx8m_vpu_g2_irq */ }, +}; + +static const struct hantro_irq imx8mq_g2_irqs[] = { + { "g2", imx8m_vpu_g2_irq }, }; static const char * const imx8mq_clk_names[] = { "g1", "g2", "bus" }; @@ -218,3 +275,17 @@ const struct hantro_variant imx8mq_vpu_variant = { .reg_names = imx8mq_reg_names, .num_regs = ARRAY_SIZE(imx8mq_reg_names) }; + +const struct hantro_variant imx8mq_vpu_g2_variant = { + .dec_offset = 0x0, + .dec_fmts = imx8m_vpu_g2_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_g2_dec_fmts), + .codec = HANTRO_HEVC_DECODER, + .codec_ops = imx8mq_vpu_g2_codec_ops, + .init = imx8mq_vpu_hw_init, + .runtime_resume = imx8mq_runtime_resume, + .irqs = imx8mq_g2_irqs, + .num_irqs = ARRAY_SIZE(imx8mq_g2_irqs), + .clk_names = imx8mq_clk_names, + .num_clocks = ARRAY_SIZE(imx8mq_clk_names), +}; diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c deleted file mode 100644 index 7b299ee3e93d..000000000000 --- a/drivers/staging/media/hantro/rk3288_vpu_hw.c +++ /dev/null @@ -1,236 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Hantro VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Jeffy Chen <jeffy.chen@rock-chips.com> - */ - -#include <linux/clk.h> - -#include "hantro.h" -#include "hantro_jpeg.h" -#include "hantro_g1_regs.h" -#include "hantro_h1_regs.h" - -#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) - -/* - * Supported formats. - */ - -static const struct hantro_fmt rk3288_vpu_enc_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, - }, - { - .fourcc = V4L2_PIX_FMT_JPEG, - .codec_mode = HANTRO_MODE_JPEG_ENC, - .max_depth = 2, - .header_size = JPEG_HEADER_SIZE, - .frmsize = { - .min_width = 96, - .max_width = 8192, - .step_width = MB_DIM, - .min_height = 32, - .max_height = 8192, - .step_height = MB_DIM, - }, - }, -}; - -static const struct hantro_fmt rk3288_vpu_postproc_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = HANTRO_MODE_NONE, - }, -}; - -static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .codec_mode = HANTRO_MODE_NONE, - }, - { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .codec_mode = HANTRO_MODE_H264_DEC, - .max_depth = 2, - .frmsize = { - .min_width = 48, - .max_width = 4096, - .step_width = MB_DIM, - .min_height = 48, - .max_height = 2304, - .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, - .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, - .step_height = MB_DIM, - }, - }, - { - .fourcc = V4L2_PIX_FMT_VP8_FRAME, - .codec_mode = HANTRO_MODE_VP8_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, - }, - }, -}; - -static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) -{ - struct hantro_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status; - - status = vepu_read(vpu, H1_REG_INTERRUPT); - state = (status & H1_REG_INTERRUPT_FRAME_RDY) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vepu_write(vpu, 0, H1_REG_INTERRUPT); - vepu_write(vpu, 0, H1_REG_AXI_CTRL); - - hantro_irq_done(vpu, state); - - return IRQ_HANDLED; -} - -static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) -{ - struct hantro_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status; - - status = vdpu_read(vpu, G1_REG_INTERRUPT); - state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vdpu_write(vpu, 0, G1_REG_INTERRUPT); - vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); - - hantro_irq_done(vpu, state); - - return IRQ_HANDLED; -} - -static int rk3288_vpu_hw_init(struct hantro_dev *vpu) -{ - /* Bump ACLK to max. possible freq. to improve performance. */ - clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); - return 0; -} - -static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx) -{ - struct hantro_dev *vpu = ctx->dev; - - vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT); - vepu_write(vpu, 0, H1_REG_ENC_CTRL); - vepu_write(vpu, 0, H1_REG_AXI_CTRL); -} - -static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx) -{ - struct hantro_dev *vpu = ctx->dev; - - vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT); - vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); - vdpu_write(vpu, 1, G1_REG_SOFT_RESET); -} - -/* - * Supported codec ops. - */ - -static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { - [HANTRO_MODE_JPEG_ENC] = { - .run = hantro_h1_jpeg_enc_run, - .reset = rk3288_vpu_enc_reset, - .init = hantro_jpeg_enc_init, - .done = hantro_jpeg_enc_done, - .exit = hantro_jpeg_enc_exit, - }, - [HANTRO_MODE_H264_DEC] = { - .run = hantro_g1_h264_dec_run, - .reset = rk3288_vpu_dec_reset, - .init = hantro_h264_dec_init, - .exit = hantro_h264_dec_exit, - }, - [HANTRO_MODE_MPEG2_DEC] = { - .run = hantro_g1_mpeg2_dec_run, - .reset = rk3288_vpu_dec_reset, - .init = hantro_mpeg2_dec_init, - .exit = hantro_mpeg2_dec_exit, - }, - [HANTRO_MODE_VP8_DEC] = { - .run = hantro_g1_vp8_dec_run, - .reset = rk3288_vpu_dec_reset, - .init = hantro_vp8_dec_init, - .exit = hantro_vp8_dec_exit, - }, -}; - -/* - * VPU variant. - */ - -static const struct hantro_irq rk3288_irqs[] = { - { "vepu", rk3288_vepu_irq }, - { "vdpu", rk3288_vdpu_irq }, -}; - -static const char * const rk3288_clk_names[] = { - "aclk", "hclk" -}; - -const struct hantro_variant rk3288_vpu_variant = { - .enc_offset = 0x0, - .enc_fmts = rk3288_vpu_enc_fmts, - .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), - .dec_offset = 0x400, - .dec_fmts = rk3288_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts), - .postproc_fmts = rk3288_vpu_postproc_fmts, - .num_postproc_fmts = ARRAY_SIZE(rk3288_vpu_postproc_fmts), - .postproc_regs = &hantro_g1_postproc_regs, - .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | - HANTRO_VP8_DECODER | HANTRO_H264_DECODER, - .codec_ops = rk3288_vpu_codec_ops, - .irqs = rk3288_irqs, - .num_irqs = ARRAY_SIZE(rk3288_irqs), - .init = rk3288_vpu_hw_init, - .clk_names = rk3288_clk_names, - .num_clocks = ARRAY_SIZE(rk3288_clk_names) -}; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c deleted file mode 100644 index 7a7962cf771e..000000000000 --- a/drivers/staging/media/hantro/rk3399_vpu_hw.c +++ /dev/null @@ -1,222 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Hantro VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Jeffy Chen <jeffy.chen@rock-chips.com> - */ - -#include <linux/clk.h> - -#include "hantro.h" -#include "hantro_jpeg.h" -#include "rk3399_vpu_regs.h" - -#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000) - -/* - * Supported formats. - */ - -static const struct hantro_fmt rk3399_vpu_enc_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .codec_mode = HANTRO_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, - }, - { - .fourcc = V4L2_PIX_FMT_JPEG, - .codec_mode = HANTRO_MODE_JPEG_ENC, - .max_depth = 2, - .header_size = JPEG_HEADER_SIZE, - .frmsize = { - .min_width = 96, - .max_width = 8192, - .step_width = MB_DIM, - .min_height = 32, - .max_height = 8192, - .step_height = MB_DIM, - }, - }, -}; - -static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .codec_mode = HANTRO_MODE_NONE, - }, - { - .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, - .codec_mode = HANTRO_MODE_MPEG2_DEC, - .max_depth = 2, - .frmsize = { - .min_width = 48, - .max_width = 1920, - .step_width = MB_DIM, - .min_height = 48, - .max_height = 1088, - .step_height = MB_DIM, - }, - }, - { - .fourcc = V4L2_PIX_FMT_VP8_FRAME, - .codec_mode = HANTRO_MODE_VP8_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, - }, - }, -}; - -static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) -{ - struct hantro_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status; - - status = vepu_read(vpu, VEPU_REG_INTERRUPT); - state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vepu_write(vpu, 0, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); - - hantro_irq_done(vpu, state); - - return IRQ_HANDLED; -} - -static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id) -{ - struct hantro_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status; - - status = vdpu_read(vpu, VDPU_REG_INTERRUPT); - state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); - vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL); - - hantro_irq_done(vpu, state); - - return IRQ_HANDLED; -} - -static int rk3399_vpu_hw_init(struct hantro_dev *vpu) -{ - /* Bump ACLK to max. possible freq. to improve performance. */ - clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ); - return 0; -} - -static void rk3399_vpu_enc_reset(struct hantro_ctx *ctx) -{ - struct hantro_dev *vpu = ctx->dev; - - vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_ENCODE_START); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); -} - -static void rk3399_vpu_dec_reset(struct hantro_ctx *ctx) -{ - struct hantro_dev *vpu = ctx->dev; - - vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); - vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS); - vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET); -} - -/* - * Supported codec ops. - */ - -static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { - [HANTRO_MODE_JPEG_ENC] = { - .run = rk3399_vpu_jpeg_enc_run, - .reset = rk3399_vpu_enc_reset, - .init = hantro_jpeg_enc_init, - .exit = hantro_jpeg_enc_exit, - }, - [HANTRO_MODE_MPEG2_DEC] = { - .run = rk3399_vpu_mpeg2_dec_run, - .reset = rk3399_vpu_dec_reset, - .init = hantro_mpeg2_dec_init, - .exit = hantro_mpeg2_dec_exit, - }, - [HANTRO_MODE_VP8_DEC] = { - .run = rk3399_vpu_vp8_dec_run, - .reset = rk3399_vpu_dec_reset, - .init = hantro_vp8_dec_init, - .exit = hantro_vp8_dec_exit, - }, -}; - -/* - * VPU variant. - */ - -static const struct hantro_irq rk3399_irqs[] = { - { "vepu", rk3399_vepu_irq }, - { "vdpu", rk3399_vdpu_irq }, -}; - -static const char * const rk3399_clk_names[] = { - "aclk", "hclk" -}; - -const struct hantro_variant rk3399_vpu_variant = { - .enc_offset = 0x0, - .enc_fmts = rk3399_vpu_enc_fmts, - .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts), - .dec_offset = 0x400, - .dec_fmts = rk3399_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), - .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | - HANTRO_VP8_DECODER, - .codec_ops = rk3399_vpu_codec_ops, - .irqs = rk3399_irqs, - .num_irqs = ARRAY_SIZE(rk3399_irqs), - .init = rk3399_vpu_hw_init, - .clk_names = rk3399_clk_names, - .num_clocks = ARRAY_SIZE(rk3399_clk_names) -}; - -static const struct hantro_irq rk3328_irqs[] = { - { "vdpu", rk3399_vdpu_irq }, -}; - -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), - .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER, - .codec_ops = rk3399_vpu_codec_ops, - .irqs = rk3328_irqs, - .num_irqs = ARRAY_SIZE(rk3328_irqs), - .init = rk3399_vpu_hw_init, - .clk_names = rk3399_clk_names, - .num_clocks = ARRAY_SIZE(rk3399_clk_names), -}; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c index 3498e6124acd..991213ce1610 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c @@ -28,12 +28,12 @@ #include "hantro.h" #include "hantro_v4l2.h" #include "hantro_hw.h" -#include "rk3399_vpu_regs.h" +#include "rockchip_vpu2_regs.h" #define VEPU_JPEG_QUANT_TABLE_COUNT 16 -static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu, - struct hantro_ctx *ctx) +static void rockchip_vpu2_set_src_img_ctrl(struct hantro_dev *vpu, + struct hantro_ctx *ctx) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; u32 reg; @@ -59,9 +59,9 @@ static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu, vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1); } -static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu, - struct hantro_ctx *ctx, - struct vb2_buffer *src_buf) +static void rockchip_vpu2_jpeg_enc_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + struct vb2_buffer *src_buf) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; dma_addr_t src[3]; @@ -92,9 +92,9 @@ static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu, } static void -rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu, - unsigned char *luma_qtable, - unsigned char *chroma_qtable) +rockchip_vpu2_jpeg_enc_set_qtable(struct hantro_dev *vpu, + unsigned char *luma_qtable, + unsigned char *chroma_qtable) { u32 reg, i; __be32 *luma_qtable_p; @@ -118,7 +118,7 @@ rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu, } } -void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) +int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -141,11 +141,11 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG, VEPU_REG_ENCODE_START); - rk3399_vpu_set_src_img_ctrl(vpu, ctx); - rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); - rk3399_vpu_jpeg_enc_set_qtable(vpu, - hantro_jpeg_get_qtable(0), - hantro_jpeg_get_qtable(1)); + rockchip_vpu2_set_src_img_ctrl(vpu, ctx); + rockchip_vpu2_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); + rockchip_vpu2_jpeg_enc_set_qtable(vpu, + hantro_jpeg_get_qtable(0), + hantro_jpeg_get_qtable(1)); reg = VEPU_REG_OUTPUT_SWAP32 | VEPU_REG_OUTPUT_SWAP16 @@ -168,4 +168,6 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) /* Kick the watchdog and start encoding */ hantro_end_prepare_run(ctx); vepu_write(vpu, reg, VEPU_REG_ENCODE_START); + + return 0; } diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c index f610fa5b4335..b66737fab46b 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c @@ -79,43 +79,34 @@ #define VDPU_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) #define VDPU_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) -#define PICT_TOP_FIELD 1 -#define PICT_BOTTOM_FIELD 2 -#define PICT_FRAME 3 - static void -rk3399_vpu_mpeg2_dec_set_quantization(struct hantro_dev *vpu, - struct hantro_ctx *ctx) +rockchip_vpu2_mpeg2_dec_set_quantisation(struct hantro_dev *vpu, + struct hantro_ctx *ctx) { - struct v4l2_ctrl_mpeg2_quantization *quantization; + struct v4l2_ctrl_mpeg2_quantisation *q; - quantization = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); - hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, quantization); - vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, - VDPU_REG_QTABLE_BASE); + q = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_MPEG2_QUANTISATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, q); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, VDPU_REG_QTABLE_BASE); } static void -rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, - struct hantro_ctx *ctx, - struct vb2_buffer *src_buf, - struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *sequence, - const struct v4l2_mpeg2_picture *picture, - const struct v4l2_ctrl_mpeg2_slice_params *slice_params) +rockchip_vpu2_mpeg2_dec_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf, + const struct v4l2_ctrl_mpeg2_sequence *seq, + const struct v4l2_ctrl_mpeg2_picture *pic) { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; - switch (picture->picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: - backward_addr = hantro_get_ref(ctx, - slice_params->backward_ref_ts); + switch (pic->picture_coding_type) { + case V4L2_MPEG2_PIC_CODING_TYPE_B: + backward_addr = hantro_get_ref(ctx, pic->backward_ref_ts); fallthrough; - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - forward_addr = hantro_get_ref(ctx, - slice_params->forward_ref_ts); + case V4L2_MPEG2_PIC_CODING_TYPE_P: + forward_addr = hantro_get_ref(ctx, pic->forward_ref_ts); } /* Source bitstream buffer */ @@ -126,7 +117,7 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); current_addr = addr; - if (picture->picture_structure == PICT_BOTTOM_FIELD) + if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) addr += ALIGN(ctx->dst_fmt.width, 16); vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE); @@ -136,18 +127,18 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, backward_addr = current_addr; /* Set forward ref frame (top/bottom field) */ - if (picture->picture_structure == PICT_FRAME || - picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || - (picture->picture_structure == PICT_TOP_FIELD && - picture->top_field_first) || - (picture->picture_structure == PICT_BOTTOM_FIELD && - !picture->top_field_first)) { + if (pic->picture_structure == V4L2_MPEG2_PIC_FRAME || + pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B || + (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD && + pic->flags & V4L2_MPEG2_PIC_TOP_FIELD) || + (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD && + !(pic->flags & V4L2_MPEG2_PIC_TOP_FIELD))) { vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_TOP_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) { vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + } else if (pic->picture_structure == V4L2_MPEG2_PIC_BOTTOM_FIELD) { vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE); vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); } @@ -157,13 +148,12 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE); } -void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) +int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - const struct v4l2_mpeg2_picture *picture; + const struct v4l2_ctrl_mpeg2_sequence *seq; + const struct v4l2_ctrl_mpeg2_picture *pic; u32 reg; src_buf = hantro_get_src_buf(ctx); @@ -171,10 +161,10 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) hantro_start_prepare_run(ctx); - slice_params = hantro_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - sequence = &slice_params->sequence; - picture = &slice_params->picture; + seq = hantro_get_ctrl(ctx, + V4L2_CID_STATELESS_MPEG2_SEQUENCE); + pic = hantro_get_ctrl(ctx, + V4L2_CID_STATELESS_MPEG2_PICTURE); reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | VDPU_REG_DEC_SCMD_DIS(0) | @@ -183,7 +173,7 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50)); reg = VDPU_REG_INIT_QP(1) | - VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3); + VDPU_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51)); reg = VDPU_REG_APF_THRESHOLD(8) | @@ -209,11 +199,11 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); reg = VDPU_REG_RLC_MODE_E(0) | - VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | - VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | - VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | - VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | - VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + VDPU_REG_PIC_INTERLACE_E(!(seq->flags & V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE)) | + VDPU_REG_PIC_FIELDMODE_E(pic->picture_structure != V4L2_MPEG2_PIC_FRAME) | + VDPU_REG_PIC_B_E(pic->picture_coding_type == V4L2_MPEG2_PIC_CODING_TYPE_B) | + VDPU_REG_PIC_INTER_E(pic->picture_coding_type != V4L2_MPEG2_PIC_CODING_TYPE_I) | + VDPU_REG_PIC_TOPFIELD_E(pic->picture_structure == V4L2_MPEG2_PIC_TOP_FIELD) | VDPU_REG_FWD_INTERLACE_E(0) | VDPU_REG_WRITE_MVS_E(0) | VDPU_REG_DEC_TIMEOUT_E(1) | @@ -222,36 +212,37 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) reg = VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | - VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | - VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); + VDPU_REG_ALT_SCAN_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + VDPU_REG_TOPFIELDFIRST_E(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120)); - reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) | - VDPU_REG_QSCALE_TYPE(picture->q_scale_type) | - VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) | - VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) | - VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | - VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + reg = VDPU_REG_STRM_START_BIT(0) | + VDPU_REG_QSCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE) | + VDPU_REG_CON_MV_E(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV) | + VDPU_REG_INTRA_DC_PREC(pic->intra_dc_precision) | + VDPU_REG_INTRA_VLC_TAB(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC) | + VDPU_REG_FRAME_PRED_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(122)); - reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | - VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | - VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) | - VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | - VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + reg = VDPU_REG_ALT_SCAN_FLAG_E(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN) | + VDPU_REG_FCODE_FWD_HOR(pic->f_code[0][0]) | + VDPU_REG_FCODE_FWD_VER(pic->f_code[0][1]) | + VDPU_REG_FCODE_BWD_HOR(pic->f_code[1][0]) | + VDPU_REG_FCODE_BWD_VER(pic->f_code[1][1]) | VDPU_REG_MV_ACCURACY_FWD(1) | VDPU_REG_MV_ACCURACY_BWD(1); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136)); - rk3399_vpu_mpeg2_dec_set_quantization(vpu, ctx); + rockchip_vpu2_mpeg2_dec_set_quantisation(vpu, ctx); - rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, - &dst_buf->vb2_buf, - sequence, picture, slice_params); + rockchip_vpu2_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, + &dst_buf->vb2_buf, seq, pic); /* Kick the watchdog and start decoding */ hantro_end_prepare_run(ctx); reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); vdpu_write(vpu, reg, VDPU_SWREG(57)); + + return 0; } diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c index 8661a3cc1e6b..951b55f58a61 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c @@ -503,7 +503,7 @@ static void cfg_buffers(struct hantro_ctx *ctx, vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST); } -void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx) +int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx) { const struct v4l2_ctrl_vp8_frame *hdr; struct hantro_dev *vpu = ctx->dev; @@ -516,7 +516,7 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx) hdr = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_VP8_FRAME); if (WARN_ON(!hdr)) - return; + return -EINVAL; /* Reset segment_map buffer in keyframe */ if (V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu) @@ -589,4 +589,6 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx) hantro_end_prepare_run(ctx); hantro_reg_write(vpu, &vp8_dec_start_dec, 1); + + return 0; } diff --git a/drivers/staging/media/hantro/rk3399_vpu_regs.h b/drivers/staging/media/hantro/rockchip_vpu2_regs.h index 88d096920f30..49e40889545b 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_regs.h +++ b/drivers/staging/media/hantro/rockchip_vpu2_regs.h @@ -6,8 +6,8 @@ * Alpha Lin <alpha.lin@rock-chips.com> */ -#ifndef RK3399_VPU_REGS_H_ -#define RK3399_VPU_REGS_H_ +#ifndef ROCKCHIP_VPU2_REGS_H_ +#define ROCKCHIP_VPU2_REGS_H_ /* Encoder registers. */ #define VEPU_REG_VP8_QUT_1ST(i) (0x000 + ((i) * 0x24)) @@ -597,4 +597,4 @@ #define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_3(x) (((x) & 0x3ff) << 12) #define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_0(x) (((x) & 0x3ff) << 2) -#endif /* RK3399_VPU_REGS_H_ */ +#endif /* ROCKCHIP_VPU2_REGS_H_ */ diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c new file mode 100644 index 000000000000..3ccc16413f42 --- /dev/null +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -0,0 +1,526 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Jeffy Chen <jeffy.chen@rock-chips.com> + */ + +#include <linux/clk.h> + +#include "hantro.h" +#include "hantro_jpeg.h" +#include "hantro_g1_regs.h" +#include "hantro_h1_regs.h" +#include "rockchip_vpu2_regs.h" + +#define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000) +#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) + +/* + * Supported formats. + */ + +static const struct hantro_fmt rockchip_vpu_enc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420P, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420SP, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUYV422, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_UYVY422, + }, + { + .fourcc = V4L2_PIX_FMT_JPEG, + .codec_mode = HANTRO_MODE_JPEG_ENC, + .max_depth = 2, + .header_size = JPEG_HEADER_SIZE, + .frmsize = { + .min_width = 96, + .max_width = 8192, + .step_width = MB_DIM, + .min_height = 32, + .max_height = 8192, + .step_height = MB_DIM, + }, + }, +}; + +static const struct hantro_fmt rockchip_vpu1_postproc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + }, +}; + +static const struct hantro_fmt rk3066_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = HANTRO_MODE_H264_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 1088, + .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, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MB_DIM, + }, + }, +}; + +static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = HANTRO_MODE_H264_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 4096, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 2304, + .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, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_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, + }, + }, +}; + +static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, + .codec_mode = HANTRO_MODE_MPEG2_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_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, + }, + }, +}; + +static irqreturn_t rockchip_vpu1_vepu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vepu_read(vpu, H1_REG_INTERRUPT); + state = (status & H1_REG_INTERRUPT_FRAME_RDY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); + + hantro_irq_done(vpu, state); + + return IRQ_HANDLED; +} + +static irqreturn_t rockchip_vpu2_vdpu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, VDPU_REG_INTERRUPT); + state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL); + + hantro_irq_done(vpu, state); + + return IRQ_HANDLED; +} + +static irqreturn_t rockchip_vpu2_vepu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vepu_read(vpu, VEPU_REG_INTERRUPT); + state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); + + hantro_irq_done(vpu, state); + + return IRQ_HANDLED; +} + +static int rk3036_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLK to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3066_ACLK_MAX_FREQ); + return 0; +} + +static int rk3066_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLKs to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3066_ACLK_MAX_FREQ); + clk_set_rate(vpu->clocks[2].clk, RK3066_ACLK_MAX_FREQ); + return 0; +} + +static int rockchip_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLK to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); + return 0; +} + +static void rk3066_vpu_dec_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); +} + +static void rockchip_vpu1_enc_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_ENC_CTRL); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); +} + +static void rockchip_vpu2_dec_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS); + vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET); +} + +static void rockchip_vpu2_enc_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_ENCODE_START); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); +} + +/* + * Supported codec ops. + */ +static const struct hantro_codec_ops rk3036_vpu_codec_ops[] = { + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .reset = hantro_g1_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = hantro_g1_mpeg2_dec_run, + .reset = hantro_g1_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .reset = hantro_g1_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, +}; + +static const struct hantro_codec_ops rk3066_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = hantro_h1_jpeg_enc_run, + .reset = rockchip_vpu1_enc_reset, + .init = hantro_jpeg_enc_init, + .done = hantro_jpeg_enc_done, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .reset = rk3066_vpu_dec_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = hantro_g1_mpeg2_dec_run, + .reset = rk3066_vpu_dec_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .reset = rk3066_vpu_dec_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, +}; + +static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = hantro_h1_jpeg_enc_run, + .reset = rockchip_vpu1_enc_reset, + .init = hantro_jpeg_enc_init, + .done = hantro_jpeg_enc_done, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .reset = hantro_g1_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = hantro_g1_mpeg2_dec_run, + .reset = hantro_g1_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .reset = hantro_g1_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, +}; + +static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = rockchip_vpu2_jpeg_enc_run, + .reset = rockchip_vpu2_enc_reset, + .init = hantro_jpeg_enc_init, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = rockchip_vpu2_mpeg2_dec_run, + .reset = rockchip_vpu2_dec_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, + [HANTRO_MODE_VP8_DEC] = { + .run = rockchip_vpu2_vp8_dec_run, + .reset = rockchip_vpu2_dec_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, +}; + +/* + * VPU variant. + */ + +static const struct hantro_irq rockchip_vdpu1_irqs[] = { + { "vdpu", hantro_g1_irq }, +}; + +static const struct hantro_irq rockchip_vpu1_irqs[] = { + { "vepu", rockchip_vpu1_vepu_irq }, + { "vdpu", hantro_g1_irq }, +}; + +static const struct hantro_irq rockchip_vdpu2_irqs[] = { + { "vdpu", rockchip_vpu2_vdpu_irq }, +}; + +static const struct hantro_irq rockchip_vpu2_irqs[] = { + { "vepu", rockchip_vpu2_vepu_irq }, + { "vdpu", rockchip_vpu2_vdpu_irq }, +}; + +static const char * const rk3066_vpu_clk_names[] = { + "aclk_vdpu", "hclk_vdpu", + "aclk_vepu", "hclk_vepu" +}; + +static const char * const rockchip_vpu_clk_names[] = { + "aclk", "hclk" +}; + +const struct hantro_variant rk3036_vpu_variant = { + .dec_offset = 0x400, + .dec_fmts = rk3066_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3066_vpu_dec_fmts), + .postproc_fmts = rockchip_vpu1_postproc_fmts, + .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts), + .postproc_regs = &hantro_g1_postproc_regs, + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | + HANTRO_H264_DECODER, + .codec_ops = rk3036_vpu_codec_ops, + .irqs = rockchip_vdpu1_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vdpu1_irqs), + .init = rk3036_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) +}; + +/* + * Despite this variant has separate clocks for decoder and encoder, + * it's still required to enable all four of them for either decoding + * or encoding and we can't split it in separate g1/h1 variants. + */ +const struct hantro_variant rk3066_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rockchip_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts), + .dec_offset = 0x400, + .dec_fmts = rk3066_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3066_vpu_dec_fmts), + .postproc_fmts = rockchip_vpu1_postproc_fmts, + .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts), + .postproc_regs = &hantro_g1_postproc_regs, + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER | HANTRO_H264_DECODER, + .codec_ops = rk3066_vpu_codec_ops, + .irqs = rockchip_vpu1_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs), + .init = rk3066_vpu_hw_init, + .clk_names = rk3066_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rk3066_vpu_clk_names) +}; + +const struct hantro_variant rk3288_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rockchip_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts), + .dec_offset = 0x400, + .dec_fmts = rk3288_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts), + .postproc_fmts = rockchip_vpu1_postproc_fmts, + .num_postproc_fmts = ARRAY_SIZE(rockchip_vpu1_postproc_fmts), + .postproc_regs = &hantro_g1_postproc_regs, + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER | HANTRO_H264_DECODER, + .codec_ops = rk3288_vpu_codec_ops, + .irqs = rockchip_vpu1_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs), + .init = rockchip_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) +}; + +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), + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rockchip_vdpu2_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vdpu2_irqs), + .init = rockchip_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names), +}; + +const struct hantro_variant rk3399_vpu_variant = { + .enc_offset = 0x0, + .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), + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rockchip_vpu2_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vpu2_irqs), + .init = rockchip_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) +}; diff --git a/drivers/staging/media/hantro/sama5d4_vdec_hw.c b/drivers/staging/media/hantro/sama5d4_vdec_hw.c new file mode 100644 index 000000000000..58ae72c2b723 --- /dev/null +++ b/drivers/staging/media/hantro/sama5d4_vdec_hw.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VDEC driver + * + * Copyright (C) 2021 Collabora Ltd, Emil Velikov <emil.velikov@collabora.com> + */ + +#include "hantro.h" + +/* + * Supported formats. + */ + +static const struct hantro_fmt sama5d4_vdec_postproc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + }, +}; + +static const struct hantro_fmt sama5d4_vdec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, + .codec_mode = HANTRO_MODE_MPEG2_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1280, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 720, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1280, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 720, + .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 = 1280, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 720, + .step_height = MB_DIM, + }, + }, +}; + +static int sama5d4_hw_init(struct hantro_dev *vpu) +{ + return 0; +} + +/* + * Supported codec ops. + */ + +static const struct hantro_codec_ops sama5d4_vdec_codec_ops[] = { + [HANTRO_MODE_MPEG2_DEC] = { + .run = hantro_g1_mpeg2_dec_run, + .reset = hantro_g1_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .reset = hantro_g1_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .reset = hantro_g1_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, +}; + +static const struct hantro_irq sama5d4_irqs[] = { + { "vdec", hantro_g1_irq }, +}; + +static const char * const sama5d4_clk_names[] = { "vdec_clk" }; + +const struct hantro_variant sama5d4_vdec_variant = { + .dec_fmts = sama5d4_vdec_fmts, + .num_dec_fmts = ARRAY_SIZE(sama5d4_vdec_fmts), + .postproc_fmts = sama5d4_vdec_postproc_fmts, + .num_postproc_fmts = ARRAY_SIZE(sama5d4_vdec_postproc_fmts), + .postproc_regs = &hantro_g1_postproc_regs, + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | + HANTRO_H264_DECODER, + .codec_ops = sama5d4_vdec_codec_ops, + .init = sama5d4_hw_init, + .irqs = sama5d4_irqs, + .num_irqs = ARRAY_SIZE(sama5d4_irqs), + .clk_names = sama5d4_clk_names, + .num_clocks = ARRAY_SIZE(sama5d4_clk_names), +}; diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index f21ed881295f..ac5fb332088e 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -79,13 +79,13 @@ static void prp_stop(struct prp_priv *priv) } static struct v4l2_mbus_framefmt * -__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg, +__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { struct imx_ic_priv *ic_priv = priv->ic_priv; if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad); + return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad); else return &priv->format_mbus; } @@ -95,7 +95,7 @@ __prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg, */ static int prp_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { struct prp_priv *priv = sd_to_priv(sd); @@ -115,7 +115,8 @@ static int prp_enum_mbus_code(struct v4l2_subdev *sd, ret = -EINVAL; goto out; } - infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, code->which); + infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD, + code->which); code->code = infmt->code; break; default: @@ -127,7 +128,7 @@ out: } static int prp_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct prp_priv *priv = sd_to_priv(sd); @@ -139,7 +140,7 @@ static int prp_get_fmt(struct v4l2_subdev *sd, mutex_lock(&priv->lock); - fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); if (!fmt) { ret = -EINVAL; goto out; @@ -152,7 +153,7 @@ out: } static int prp_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct prp_priv *priv = sd_to_priv(sd); @@ -171,7 +172,7 @@ static int prp_set_fmt(struct v4l2_subdev *sd, goto out; } - infmt = __prp_get_fmt(priv, cfg, PRP_SINK_PAD, sdformat->which); + infmt = __prp_get_fmt(priv, sd_state, PRP_SINK_PAD, sdformat->which); switch (sdformat->pad) { case PRP_SINK_PAD: @@ -201,7 +202,7 @@ static int prp_set_fmt(struct v4l2_subdev *sd, imx_media_try_colorimetry(&sdformat->format, true); - fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); *fmt = sdformat->format; out: mutex_unlock(&priv->lock); diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index d990553de87b..9b81cfbcd777 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -787,13 +787,13 @@ static void prp_stop(struct prp_priv *priv) } static struct v4l2_mbus_framefmt * -__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_pad_config *cfg, +__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which) { struct imx_ic_priv *ic_priv = priv->ic_priv; if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ic_priv->sd, cfg, pad); + return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad); else return &priv->format_mbus[pad]; } @@ -841,7 +841,7 @@ static bool prp_bound_align_output(struct v4l2_mbus_framefmt *outfmt, */ static int prp_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad >= PRPENCVF_NUM_PADS) @@ -852,7 +852,7 @@ static int prp_enum_mbus_code(struct v4l2_subdev *sd, } static int prp_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct prp_priv *priv = sd_to_priv(sd); @@ -864,7 +864,7 @@ static int prp_get_fmt(struct v4l2_subdev *sd, mutex_lock(&priv->lock); - fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); if (!fmt) { ret = -EINVAL; goto out; @@ -877,7 +877,7 @@ out: } static void prp_try_fmt(struct prp_priv *priv, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat, const struct imx_media_pixfmt **cc) { @@ -894,7 +894,8 @@ static void prp_try_fmt(struct prp_priv *priv, sdformat->format.code = (*cc)->codes[0]; } - infmt = __prp_get_fmt(priv, cfg, PRPENCVF_SINK_PAD, sdformat->which); + infmt = __prp_get_fmt(priv, sd_state, PRPENCVF_SINK_PAD, + sdformat->which); if (sdformat->pad == PRPENCVF_SRC_PAD) { sdformat->format.field = infmt->field; @@ -920,7 +921,7 @@ static void prp_try_fmt(struct prp_priv *priv, } static int prp_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct prp_priv *priv = sd_to_priv(sd); @@ -938,9 +939,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd, goto out; } - prp_try_fmt(priv, cfg, sdformat, &cc); + prp_try_fmt(priv, sd_state, sdformat, &cc); - fmt = __prp_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __prp_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); *fmt = sdformat->format; /* propagate a default format to source pad */ @@ -952,9 +953,9 @@ static int prp_set_fmt(struct v4l2_subdev *sd, format.pad = PRPENCVF_SRC_PAD; format.which = sdformat->which; format.format = sdformat->format; - prp_try_fmt(priv, cfg, &format, &outcc); + prp_try_fmt(priv, sd_state, &format, &outcc); - outfmt = __prp_get_fmt(priv, cfg, PRPENCVF_SRC_PAD, + outfmt = __prp_get_fmt(priv, sd_state, PRPENCVF_SRC_PAD, sdformat->which); *outfmt = format.format; if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) @@ -970,7 +971,7 @@ out: } static int prp_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { struct prp_priv *priv = sd_to_priv(sd); @@ -988,7 +989,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd, format.format.code = fse->code; format.format.width = 1; format.format.height = 1; - prp_try_fmt(priv, cfg, &format, &cc); + prp_try_fmt(priv, sd_state, &format, &cc); fse->min_width = format.format.width; fse->min_height = format.format.height; @@ -1000,7 +1001,7 @@ static int prp_enum_frame_size(struct v4l2_subdev *sd, format.format.code = fse->code; format.format.width = -1; format.format.height = -1; - prp_try_fmt(priv, cfg, &format, &cc); + prp_try_fmt(priv, sd_state, &format, &cc); fse->max_width = format.format.width; fse->max_height = format.format.height; out: diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index e3bfd635a89a..bb1305c9daaf 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -750,9 +750,10 @@ static int csi_setup(struct csi_priv *priv) static int csi_start(struct csi_priv *priv) { - struct v4l2_fract *output_fi; + struct v4l2_fract *input_fi, *output_fi; int ret; + input_fi = &priv->frame_interval[CSI_SINK_PAD]; output_fi = &priv->frame_interval[priv->active_output_pad]; /* start upstream */ @@ -761,6 +762,17 @@ static int csi_start(struct csi_priv *priv) if (ret) return ret; + /* Skip first few frames from a BT.656 source */ + if (priv->upstream_ep.bus_type == V4L2_MBUS_BT656) { + u32 delay_usec, bad_frames = 20; + + delay_usec = DIV_ROUND_UP_ULL((u64)USEC_PER_SEC * + input_fi->numerator * bad_frames, + input_fi->denominator); + + usleep_range(delay_usec, delay_usec + 1000); + } + if (priv->dest == IPU_CSI_DEST_IDMAC) { ret = csi_idmac_start(priv); if (ret) @@ -1139,31 +1151,32 @@ static int csi_link_validate(struct v4l2_subdev *sd, } static struct v4l2_mbus_framefmt * -__csi_get_fmt(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg, +__csi_get_fmt(struct csi_priv *priv, 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(&priv->sd, cfg, pad); + return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad); else return &priv->format_mbus[pad]; } static struct v4l2_rect * -__csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg, +__csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(&priv->sd, cfg, CSI_SINK_PAD); + return v4l2_subdev_get_try_crop(&priv->sd, sd_state, + CSI_SINK_PAD); else return &priv->crop; } static struct v4l2_rect * -__csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg, +__csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_compose(&priv->sd, cfg, + return v4l2_subdev_get_try_compose(&priv->sd, sd_state, CSI_SINK_PAD); else return &priv->compose; @@ -1171,7 +1184,7 @@ __csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_pad_config *cfg, static void csi_try_crop(struct csi_priv *priv, struct v4l2_rect *crop, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_mbus_framefmt *infmt, struct v4l2_fwnode_endpoint *upstream_ep) { @@ -1210,7 +1223,7 @@ static void csi_try_crop(struct csi_priv *priv, } static int csi_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1221,7 +1234,7 @@ static int csi_enum_mbus_code(struct v4l2_subdev *sd, mutex_lock(&priv->lock); - infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, code->which); + infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, code->which); incc = imx_media_find_mbus_format(infmt->code, PIXFMT_SEL_ANY); switch (code->pad) { @@ -1263,7 +1276,7 @@ out: } static int csi_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1282,7 +1295,7 @@ static int csi_enum_frame_size(struct v4l2_subdev *sd, fse->min_height = MIN_H; fse->max_height = MAX_H; } else { - crop = __csi_get_crop(priv, cfg, fse->which); + crop = __csi_get_crop(priv, sd_state, fse->which); fse->min_width = fse->index & 1 ? crop->width / 2 : crop->width; @@ -1297,7 +1310,7 @@ static int csi_enum_frame_size(struct v4l2_subdev *sd, } static int csi_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1313,7 +1326,7 @@ static int csi_enum_frame_interval(struct v4l2_subdev *sd, mutex_lock(&priv->lock); input_fi = &priv->frame_interval[CSI_SINK_PAD]; - crop = __csi_get_crop(priv, cfg, fie->which); + crop = __csi_get_crop(priv, sd_state, fie->which); if ((fie->width != crop->width && fie->width != crop->width / 2) || (fie->height != crop->height && fie->height != crop->height / 2)) { @@ -1333,7 +1346,7 @@ out: } static int csi_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1345,7 +1358,7 @@ static int csi_get_fmt(struct v4l2_subdev *sd, mutex_lock(&priv->lock); - fmt = __csi_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __csi_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); if (!fmt) { ret = -EINVAL; goto out; @@ -1358,11 +1371,11 @@ out: } static void csi_try_field(struct csi_priv *priv, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct v4l2_mbus_framefmt *infmt = - __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which); + __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sdformat->which); /* * no restrictions on sink pad field type except must @@ -1408,7 +1421,7 @@ static void csi_try_field(struct csi_priv *priv, static void csi_try_fmt(struct csi_priv *priv, struct v4l2_fwnode_endpoint *upstream_ep, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat, struct v4l2_rect *crop, struct v4l2_rect *compose, @@ -1418,7 +1431,7 @@ static void csi_try_fmt(struct csi_priv *priv, struct v4l2_mbus_framefmt *infmt; u32 code; - infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sdformat->which); + infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sdformat->which); switch (sdformat->pad) { case CSI_SRC_PAD_DIRECT: @@ -1445,7 +1458,7 @@ static void csi_try_fmt(struct csi_priv *priv, } } - csi_try_field(priv, cfg, sdformat); + csi_try_field(priv, sd_state, sdformat); /* propagate colorimetry from sink */ sdformat->format.colorspace = infmt->colorspace; @@ -1469,7 +1482,7 @@ static void csi_try_fmt(struct csi_priv *priv, sdformat->format.code = (*cc)->codes[0]; } - csi_try_field(priv, cfg, sdformat); + csi_try_field(priv, sd_state, sdformat); /* Reset crop and compose rectangles */ crop->left = 0; @@ -1478,7 +1491,8 @@ static void csi_try_fmt(struct csi_priv *priv, crop->height = sdformat->format.height; if (sdformat->format.field == V4L2_FIELD_ALTERNATE) crop->height *= 2; - csi_try_crop(priv, crop, cfg, &sdformat->format, upstream_ep); + csi_try_crop(priv, crop, sd_state, &sdformat->format, + upstream_ep); compose->left = 0; compose->top = 0; compose->width = crop->width; @@ -1492,7 +1506,7 @@ static void csi_try_fmt(struct csi_priv *priv, } static int csi_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1518,12 +1532,13 @@ static int csi_set_fmt(struct v4l2_subdev *sd, goto out; } - crop = __csi_get_crop(priv, cfg, sdformat->which); - compose = __csi_get_compose(priv, cfg, sdformat->which); + crop = __csi_get_crop(priv, sd_state, sdformat->which); + compose = __csi_get_compose(priv, sd_state, sdformat->which); - csi_try_fmt(priv, &upstream_ep, cfg, sdformat, crop, compose, &cc); + csi_try_fmt(priv, &upstream_ep, sd_state, sdformat, crop, compose, + &cc); - fmt = __csi_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __csi_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); *fmt = sdformat->format; if (sdformat->pad == CSI_SINK_PAD) { @@ -1538,10 +1553,11 @@ static int csi_set_fmt(struct v4l2_subdev *sd, format.pad = pad; format.which = sdformat->which; format.format = sdformat->format; - csi_try_fmt(priv, &upstream_ep, cfg, &format, + csi_try_fmt(priv, &upstream_ep, sd_state, &format, NULL, compose, &outcc); - outfmt = __csi_get_fmt(priv, cfg, pad, sdformat->which); + outfmt = __csi_get_fmt(priv, sd_state, pad, + sdformat->which); *outfmt = format.format; if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) @@ -1558,7 +1574,7 @@ out: } static int csi_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1571,9 +1587,9 @@ static int csi_get_selection(struct v4l2_subdev *sd, mutex_lock(&priv->lock); - infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sel->which); - crop = __csi_get_crop(priv, cfg, sel->which); - compose = __csi_get_compose(priv, cfg, sel->which); + infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sel->which); + crop = __csi_get_crop(priv, sd_state, sel->which); + compose = __csi_get_compose(priv, sd_state, sel->which); switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: @@ -1622,7 +1638,7 @@ static int csi_set_scale(u32 *compose, u32 crop, u32 flags) } static int csi_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1647,9 +1663,9 @@ static int csi_set_selection(struct v4l2_subdev *sd, goto out; } - infmt = __csi_get_fmt(priv, cfg, CSI_SINK_PAD, sel->which); - crop = __csi_get_crop(priv, cfg, sel->which); - compose = __csi_get_compose(priv, cfg, sel->which); + infmt = __csi_get_fmt(priv, sd_state, CSI_SINK_PAD, sel->which); + crop = __csi_get_crop(priv, sd_state, sel->which); + compose = __csi_get_compose(priv, sd_state, sel->which); switch (sel->target) { case V4L2_SEL_TGT_CROP: @@ -1665,7 +1681,7 @@ static int csi_set_selection(struct v4l2_subdev *sd, goto out; } - csi_try_crop(priv, &sel->r, cfg, infmt, &upstream_ep); + csi_try_crop(priv, &sel->r, sd_state, infmt, &upstream_ep); *crop = sel->r; @@ -1706,7 +1722,7 @@ static int csi_set_selection(struct v4l2_subdev *sd, for (pad = CSI_SINK_PAD + 1; pad < CSI_NUM_PADS; pad++) { struct v4l2_mbus_framefmt *outfmt; - outfmt = __csi_get_fmt(priv, cfg, pad, sel->which); + outfmt = __csi_get_fmt(priv, sd_state, pad, sel->which); outfmt->width = compose->width; outfmt->height = compose->height; } diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 5128915a5d6f..6f90acf9c725 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -429,7 +429,7 @@ EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt); * of a subdev. Can be used as the .init_cfg pad operation. */ int imx_media_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg) + struct v4l2_subdev_state *sd_state) { struct v4l2_mbus_framefmt *mf_try; struct v4l2_subdev_format format; @@ -445,7 +445,7 @@ int imx_media_init_cfg(struct v4l2_subdev *sd, if (ret) continue; - mf_try = v4l2_subdev_get_try_format(sd, cfg, pad); + mf_try = v4l2_subdev_get_try_format(sd, sd_state, pad); *mf_try = format.format; } diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index abf290bda98d..3c2093c520ba 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -532,17 +532,17 @@ out: } static struct v4l2_mbus_framefmt * -__vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_pad_config *cfg, +__vdic_get_fmt(struct vdic_priv *priv, 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(&priv->sd, cfg, pad); + return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad); else return &priv->format_mbus[pad]; } static int vdic_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad >= VDIC_NUM_PADS) @@ -553,7 +553,7 @@ static int vdic_enum_mbus_code(struct v4l2_subdev *sd, } static int vdic_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct vdic_priv *priv = v4l2_get_subdevdata(sd); @@ -565,7 +565,7 @@ static int vdic_get_fmt(struct v4l2_subdev *sd, mutex_lock(&priv->lock); - fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); if (!fmt) { ret = -EINVAL; goto out; @@ -578,7 +578,7 @@ out: } static void vdic_try_fmt(struct vdic_priv *priv, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat, const struct imx_media_pixfmt **cc) { @@ -594,7 +594,7 @@ static void vdic_try_fmt(struct vdic_priv *priv, sdformat->format.code = (*cc)->codes[0]; } - infmt = __vdic_get_fmt(priv, cfg, priv->active_input_pad, + infmt = __vdic_get_fmt(priv, sd_state, priv->active_input_pad, sdformat->which); switch (sdformat->pad) { @@ -620,7 +620,7 @@ static void vdic_try_fmt(struct vdic_priv *priv, } static int vdic_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct vdic_priv *priv = v4l2_get_subdevdata(sd); @@ -638,9 +638,9 @@ static int vdic_set_fmt(struct v4l2_subdev *sd, goto out; } - vdic_try_fmt(priv, cfg, sdformat, &cc); + vdic_try_fmt(priv, sd_state, sdformat, &cc); - fmt = __vdic_get_fmt(priv, cfg, sdformat->pad, sdformat->which); + fmt = __vdic_get_fmt(priv, sd_state, sdformat->pad, sdformat->which); *fmt = sdformat->format; /* propagate format to source pad */ @@ -653,9 +653,9 @@ static int vdic_set_fmt(struct v4l2_subdev *sd, format.pad = VDIC_SRC_PAD_DIRECT; format.which = sdformat->which; format.format = sdformat->format; - vdic_try_fmt(priv, cfg, &format, &outcc); + vdic_try_fmt(priv, sd_state, &format, &outcc); - outfmt = __vdic_get_fmt(priv, cfg, VDIC_SRC_PAD_DIRECT, + outfmt = __vdic_get_fmt(priv, sd_state, VDIC_SRC_PAD_DIRECT, sdformat->which); *outfmt = format.format; if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 492d9a64e704..6740e7917458 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -193,7 +193,7 @@ int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus, u32 width, u32 height, u32 code, u32 field, const struct imx_media_pixfmt **cc); int imx_media_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg); + struct v4l2_subdev_state *sd_state); void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt, bool ic_route); int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index fc2378ac04b7..9de0ebd439dc 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -508,17 +508,17 @@ out: } static struct v4l2_mbus_framefmt * -__csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_pad_config *cfg, +__csi2_get_fmt(struct csi2_dev *csi2, 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(&csi2->sd, cfg, pad); + return v4l2_subdev_get_try_format(&csi2->sd, sd_state, pad); else return &csi2->format_mbus; } static int csi2_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct csi2_dev *csi2 = sd_to_dev(sd); @@ -526,7 +526,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd, mutex_lock(&csi2->lock); - fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which); + fmt = __csi2_get_fmt(csi2, sd_state, sdformat->pad, sdformat->which); sdformat->format = *fmt; @@ -536,7 +536,7 @@ static int csi2_get_fmt(struct v4l2_subdev *sd, } static int csi2_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct csi2_dev *csi2 = sd_to_dev(sd); @@ -557,7 +557,7 @@ static int csi2_set_fmt(struct v4l2_subdev *sd, if (sdformat->pad != CSI2_SINK_PAD) sdformat->format = csi2->format_mbus; - fmt = __csi2_get_fmt(csi2, cfg, sdformat->pad, sdformat->which); + fmt = __csi2_get_fmt(csi2, sd_state, sdformat->pad, sdformat->which); *fmt = sdformat->format; out: diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index f85a2f5f1413..894c4de31790 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -724,7 +724,7 @@ out_unlock: } static int imx7_csi_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg) + struct v4l2_subdev_state *sd_state) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; @@ -732,7 +732,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd, int i; for (i = 0; i < IMX7_CSI_PADS_NUM; i++) { - mf = v4l2_subdev_get_try_format(sd, cfg, i); + mf = v4l2_subdev_get_try_format(sd, sd_state, i); ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE, &csi->cc[i]); @@ -745,18 +745,18 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd, static struct v4l2_mbus_framefmt * imx7_csi_get_format(struct imx7_csi *csi, - struct v4l2_subdev_pad_config *cfg, + 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, cfg, pad); + return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad); return &csi->format_mbus[pad]; } static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); @@ -765,7 +765,8 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd, mutex_lock(&csi->lock); - in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK, code->which); + in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK, + code->which); switch (code->pad) { case IMX7_CSI_PAD_SINK: @@ -791,7 +792,7 @@ out_unlock: } static int imx7_csi_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); @@ -800,7 +801,8 @@ static int imx7_csi_get_fmt(struct v4l2_subdev *sd, mutex_lock(&csi->lock); - fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which); + fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad, + sdformat->which); if (!fmt) { ret = -EINVAL; goto out_unlock; @@ -815,7 +817,7 @@ out_unlock: } static int imx7_csi_try_fmt(struct imx7_csi *csi, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat, const struct imx_media_pixfmt **cc) { @@ -823,7 +825,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, struct v4l2_mbus_framefmt *in_fmt; u32 code; - in_fmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SINK, + in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK, sdformat->which); if (!in_fmt) return -EINVAL; @@ -868,7 +870,7 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, } static int imx7_csi_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { struct imx7_csi *csi = v4l2_get_subdevdata(sd); @@ -889,11 +891,12 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, goto out_unlock; } - ret = imx7_csi_try_fmt(csi, cfg, sdformat, &cc); + ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc); if (ret < 0) goto out_unlock; - fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which); + fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad, + sdformat->which); if (!fmt) { ret = -EINVAL; goto out_unlock; @@ -906,11 +909,11 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, format.pad = IMX7_CSI_PAD_SRC; format.which = sdformat->which; format.format = sdformat->format; - if (imx7_csi_try_fmt(csi, cfg, &format, &outcc)) { + if (imx7_csi_try_fmt(csi, sd_state, &format, &outcc)) { ret = -EINVAL; goto out_unlock; } - outfmt = imx7_csi_get_format(csi, cfg, IMX7_CSI_PAD_SRC, + outfmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SRC, sdformat->which); *outfmt = format.format; diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index 025fdc488bd6..ead696eb4610 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> @@ -166,15 +167,11 @@ #define MIPI_CSIS_ISP_CONFIG_CH(n) (0x40 + (n) * 0x10) #define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24) #define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) ((x) << 24) -#define MIPI_CSIS_ISPCFG_DOUBLE_CMPNT BIT(12) +#define MIPI_CSIS_ISPCFG_PIXEL_MODE_SINGLE (0 << 12) +#define MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL (1 << 12) +#define MIPI_CSIS_ISPCFG_PIXEL_MODE_QUAD (2 << 12) /* i.MX8M[MNP] only */ #define MIPI_CSIS_ISPCFG_ALIGN_32BIT BIT(11) -#define MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT (0x1e << 2) -#define MIPI_CSIS_ISPCFG_FMT_RAW8 (0x2a << 2) -#define MIPI_CSIS_ISPCFG_FMT_RAW10 (0x2b << 2) -#define MIPI_CSIS_ISPCFG_FMT_RAW12 (0x2c << 2) -#define MIPI_CSIS_ISPCFG_FMT_RAW14 (0x2d << 2) -/* User defined formats, x = 1...4 */ -#define MIPI_CSIS_ISPCFG_FMT_USER(x) ((0x30 + (x) - 1) << 2) +#define MIPI_CSIS_ISPCFG_FMT(fmt) ((fmt) << 2) #define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2) /* ISP Image Resolution register */ @@ -195,6 +192,24 @@ /* Debug control register */ #define MIPI_CSIS_DBG_CTRL 0xc0 +#define MIPI_CSIS_DBG_INTR_MSK 0xc4 +#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25) +#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24) +#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE BIT(20) +#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME BIT(16) +#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE BIT(12) +#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS BIT(8) +#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL BIT(4) +#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE BIT(0) +#define MIPI_CSIS_DBG_INTR_SRC 0xc8 +#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25) +#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24) +#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE BIT(20) +#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME BIT(16) +#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE BIT(12) +#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS BIT(8) +#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL BIT(4) +#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0) /* Non-image packet data buffers */ #define MIPI_CSIS_PKTDATA_ODD 0x2000 @@ -203,6 +218,25 @@ #define DEFAULT_SCLK_CSIS_FREQ 166000000UL +/* MIPI CSI-2 Data Types */ +#define MIPI_CSI2_DATA_TYPE_YUV420_8 0x18 +#define MIPI_CSI2_DATA_TYPE_YUV420_10 0x19 +#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8 0x1a +#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8 0x1c +#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10 0x1d +#define MIPI_CSI2_DATA_TYPE_YUV422_8 0x1e +#define MIPI_CSI2_DATA_TYPE_YUV422_10 0x1f +#define MIPI_CSI2_DATA_TYPE_RGB565 0x22 +#define MIPI_CSI2_DATA_TYPE_RGB666 0x23 +#define MIPI_CSI2_DATA_TYPE_RGB888 0x24 +#define MIPI_CSI2_DATA_TYPE_RAW6 0x28 +#define MIPI_CSI2_DATA_TYPE_RAW7 0x29 +#define MIPI_CSI2_DATA_TYPE_RAW8 0x2a +#define MIPI_CSI2_DATA_TYPE_RAW10 0x2b +#define MIPI_CSI2_DATA_TYPE_RAW12 0x2c +#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d +#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x)) + enum { ST_POWERED = 1, ST_STREAMING = 2, @@ -210,6 +244,7 @@ enum { }; struct mipi_csis_event { + bool debug; u32 mask; const char * const name; unsigned int counter; @@ -217,22 +252,30 @@ struct mipi_csis_event { static const struct mipi_csis_event mipi_csis_events[] = { /* Errors */ - { MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" }, - { MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" }, - { MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" }, - { MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" }, - { MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" }, - { MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" }, - { MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" }, - { MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" }, + { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" }, + { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" }, + { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" }, + { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" }, + { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" }, + { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" }, /* Non-image data receive events */ - { MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" }, - { MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" }, - { MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" }, - { MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" }, + { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" }, + { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" }, + { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" }, + { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" }, /* Frame start/end */ - { MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" }, - { MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" }, + { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" }, + { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" }, + { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" }, + { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" }, }; #define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) @@ -241,63 +284,63 @@ enum mipi_csis_clk { MIPI_CSIS_CLK_PCLK, MIPI_CSIS_CLK_WRAP, MIPI_CSIS_CLK_PHY, + MIPI_CSIS_CLK_AXI, }; static const char * const mipi_csis_clk_id[] = { "pclk", "wrap", "phy", + "axi", }; -struct csis_hw_reset { - struct regmap *src; - u8 req_src; - u8 rst_bit; +enum mipi_csis_version { + MIPI_CSIS_V3_3, + MIPI_CSIS_V3_6_3, +}; + +struct mipi_csis_info { + enum mipi_csis_version version; + unsigned int num_clocks; }; struct csi_state { - /* lock elements below */ - struct mutex lock; - /* lock for event handler */ - spinlock_t slock; struct device *dev; + void __iomem *regs; + struct clk_bulk_data *clks; + struct reset_control *mrst; + struct regulator *mipi_phy_regulator; + const struct mipi_csis_info *info; + u8 index; + + struct v4l2_subdev sd; struct media_pad pads[CSIS_PADS_NUM]; - struct v4l2_subdev mipi_sd; struct v4l2_async_notifier notifier; struct v4l2_subdev *src_sd; - u8 index; - struct platform_device *pdev; - struct phy *phy; - void __iomem *regs; - int irq; - u32 flags; - - struct dentry *debugfs_root; - bool debug; - - int num_clks; - struct clk_bulk_data *clks; - + struct v4l2_fwnode_bus_mipi_csi2 bus; u32 clk_frequency; u32 hs_settle; + u32 clk_settle; - struct reset_control *mrst; - + struct mutex lock; /* Protect csis_fmt, format_mbus and state */ const struct csis_pix_format *csis_fmt; struct v4l2_mbus_framefmt format_mbus; + u32 state; - struct v4l2_fwnode_bus_mipi_csi2 bus; - + spinlock_t slock; /* Protect events */ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; - - struct csis_hw_reset hw_reset; - struct regulator *mipi_phy_regulator; + struct dentry *debugfs_root; + bool debug; }; +/* ----------------------------------------------------------------------------- + * Format helpers + */ + struct csis_pix_format { u32 code; - u32 fmt_reg; + u32 data_type; u8 width; }; @@ -305,156 +348,117 @@ static const struct csis_pix_format mipi_csis_formats[] = { /* YUV formats. */ { .code = MEDIA_BUS_FMT_UYVY8_1X16, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT, + .data_type = MIPI_CSI2_DATA_TYPE_YUV422_8, .width = 16, }, /* RAW (Bayer and greyscale) formats. */ { .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_Y8_1X8, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, .width = 8, }, { .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_Y10_1X10, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, .width = 10, }, { .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_Y12_1X12, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, .width = 12, }, { .code = MEDIA_BUS_FMT_SBGGR14_1X14, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, .width = 14, }, { .code = MEDIA_BUS_FMT_SGBRG14_1X14, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, .width = 14, }, { .code = MEDIA_BUS_FMT_SGRBG14_1X14, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, .width = 14, }, { .code = MEDIA_BUS_FMT_SRGGB14_1X14, - .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, .width = 14, } }; -static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val) -{ - writel(val, state->regs + reg); -} - -static inline u32 mipi_csis_read(struct csi_state *state, u32 reg) -{ - return readl(state->regs + reg); -} - -static int mipi_csis_dump_regs(struct csi_state *state) +static const struct csis_pix_format *find_csis_format(u32 code) { - struct device *dev = &state->pdev->dev; unsigned int i; - u32 cfg; - static const struct { - u32 offset; - const char * const name; - } registers[] = { - { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" }, - { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" }, - { MIPI_CSIS_INT_MSK, "INT_MSK" }, - { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" }, - { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" }, - { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" }, - { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" }, - { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" }, - { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" }, - { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" }, - { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" }, - { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" }, - }; - dev_info(dev, "--- REGISTERS ---\n"); - - for (i = 0; i < ARRAY_SIZE(registers); i++) { - cfg = mipi_csis_read(state, registers[i].offset); - dev_info(dev, "%14s: 0x%08x\n", registers[i].name, cfg); - } - - return 0; + for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++) + if (code == mipi_csis_formats[i].code) + return &mipi_csis_formats[i]; + return NULL; } -static struct csi_state * -mipi_notifier_to_csis_state(struct v4l2_async_notifier *n) -{ - return container_of(n, struct csi_state, notifier); -} +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ -static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev) +static inline u32 mipi_csis_read(struct csi_state *state, u32 reg) { - return container_of(sdev, struct csi_state, mipi_sd); + return readl(state->regs + reg); } -static const struct csis_pix_format *find_csis_format(u32 code) +static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++) - if (code == mipi_csis_formats[i].code) - return &mipi_csis_formats[i]; - return NULL; + writel(val, state->regs + reg); } static void mipi_csis_enable_interrupts(struct csi_state *state, bool on) { mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); + mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); } static void mipi_csis_sw_reset(struct csi_state *state) @@ -466,25 +470,6 @@ static void mipi_csis_sw_reset(struct csi_state *state) usleep_range(10, 20); } -static int mipi_csis_phy_init(struct csi_state *state) -{ - state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy"); - if (IS_ERR(state->mipi_phy_regulator)) - return PTR_ERR(state->mipi_phy_regulator); - - return regulator_set_voltage(state->mipi_phy_regulator, 1000000, - 1000000); -} - -static void mipi_csis_phy_reset(struct csi_state *state) -{ - reset_control_assert(state->mrst); - - msleep(20); - - reset_control_deassert(state->mrst); -} - static void mipi_csis_system_enable(struct csi_state *state, int on) { u32 val, mask; @@ -514,7 +499,7 @@ static void __mipi_csis_set_format(struct csi_state *state) /* Color format */ val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0)); val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK); - val |= state->csis_fmt->fmt_reg; + val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type); mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val); /* Pixel resolution */ @@ -546,11 +531,15 @@ static int mipi_csis_calculate_params(struct csi_state *state) /* * The HSSETTLE counter value is document in a table, but can also - * easily be calculated. + * easily be calculated. Hardcode the CLKSETTLE value to 0 for now + * (which is documented as corresponding to CSI-2 v0.87 to v1.00) until + * we figure out how to compute it correctly. */ state->hs_settle = (lane_rate - 5000000) / 45000000; - dev_dbg(state->dev, "lane rate %u, Ths_settle %u\n", - lane_rate, state->hs_settle); + state->clk_settle = 0; + + dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", + lane_rate, state->clk_settle, state->hs_settle); return 0; } @@ -563,13 +552,15 @@ static void mipi_csis_set_params(struct csi_state *state) val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; - val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; + if (state->info->version == MIPI_CSIS_V3_3) + val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); __mipi_csis_set_format(state); mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, - MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle)); + MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) | + MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle)); val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET) | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET) @@ -601,31 +592,30 @@ static void mipi_csis_set_params(struct csi_state *state) static int mipi_csis_clk_enable(struct csi_state *state) { - return clk_bulk_prepare_enable(state->num_clks, state->clks); + return clk_bulk_prepare_enable(state->info->num_clocks, state->clks); } static void mipi_csis_clk_disable(struct csi_state *state) { - clk_bulk_disable_unprepare(state->num_clks, state->clks); + clk_bulk_disable_unprepare(state->info->num_clocks, state->clks); } static int mipi_csis_clk_get(struct csi_state *state) { - struct device *dev = &state->pdev->dev; unsigned int i; int ret; - state->num_clks = ARRAY_SIZE(mipi_csis_clk_id); - state->clks = devm_kcalloc(dev, state->num_clks, sizeof(*state->clks), - GFP_KERNEL); + state->clks = devm_kcalloc(state->dev, state->info->num_clocks, + sizeof(*state->clks), GFP_KERNEL); if (!state->clks) return -ENOMEM; - for (i = 0; i < state->num_clks; i++) + for (i = 0; i < state->info->num_clocks; i++) state->clks[i].id = mipi_csis_clk_id[i]; - ret = devm_clk_bulk_get(dev, state->num_clks, state->clks); + ret = devm_clk_bulk_get(state->dev, state->info->num_clocks, + state->clks); if (ret < 0) return ret; @@ -633,8 +623,8 @@ static int mipi_csis_clk_get(struct csi_state *state) ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk, state->clk_frequency); if (ret < 0) - dev_err(dev, "set rate=%d failed: %d\n", state->clk_frequency, - ret); + dev_err(state->dev, "set rate=%d failed: %d\n", + state->clk_frequency, ret); return ret; } @@ -653,6 +643,89 @@ static void mipi_csis_stop_stream(struct csi_state *state) mipi_csis_system_enable(state, false); } +static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) +{ + struct csi_state *state = dev_id; + unsigned long flags; + unsigned int i; + u32 status; + u32 dbg_status; + + status = mipi_csis_read(state, MIPI_CSIS_INT_SRC); + dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC); + + spin_lock_irqsave(&state->slock, flags); + + /* Update the event/error counters */ + if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) { + for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { + struct mipi_csis_event *event = &state->events[i]; + + if ((!event->debug && (status & event->mask)) || + (event->debug && (dbg_status & event->mask))) + event->counter++; + } + } + spin_unlock_irqrestore(&state->slock, flags); + + mipi_csis_write(state, MIPI_CSIS_INT_SRC, status); + mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status); + + return IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * PHY regulator and reset + */ + +static int mipi_csis_phy_enable(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return 0; + + return regulator_enable(state->mipi_phy_regulator); +} + +static int mipi_csis_phy_disable(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return 0; + + return regulator_disable(state->mipi_phy_regulator); +} + +static void mipi_csis_phy_reset(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return; + + reset_control_assert(state->mrst); + msleep(20); + reset_control_deassert(state->mrst); +} + +static int mipi_csis_phy_init(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return 0; + + /* Get MIPI PHY reset and regulator. */ + state->mrst = devm_reset_control_get_exclusive(state->dev, NULL); + if (IS_ERR(state->mrst)) + return PTR_ERR(state->mrst); + + state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy"); + if (IS_ERR(state->mipi_phy_regulator)) + return PTR_ERR(state->mipi_phy_regulator); + + return regulator_set_voltage(state->mipi_phy_regulator, 1000000, + 1000000); +} + +/* ----------------------------------------------------------------------------- + * Debug + */ + static void mipi_csis_clear_counters(struct csi_state *state) { unsigned long flags; @@ -666,26 +739,90 @@ static void mipi_csis_clear_counters(struct csi_state *state) static void mipi_csis_log_counters(struct csi_state *state, bool non_errors) { - int i = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 4; - struct device *dev = &state->pdev->dev; + unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS + : MIPI_CSIS_NUM_EVENTS - 8; unsigned long flags; + unsigned int i; spin_lock_irqsave(&state->slock, flags); - for (i--; i >= 0; i--) { + for (i = 0; i < num_events; ++i) { if (state->events[i].counter > 0 || state->debug) - dev_info(dev, "%s events: %d\n", state->events[i].name, + dev_info(state->dev, "%s events: %d\n", + state->events[i].name, state->events[i].counter); } spin_unlock_irqrestore(&state->slock, flags); } -/* +static int mipi_csis_dump_regs(struct csi_state *state) +{ + static const struct { + u32 offset; + const char * const name; + } registers[] = { + { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" }, + { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" }, + { MIPI_CSIS_INT_MSK, "INT_MSK" }, + { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" }, + { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" }, + { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" }, + { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" }, + { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" }, + { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" }, + { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" }, + { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" }, + { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" }, + }; + + unsigned int i; + u32 cfg; + + dev_info(state->dev, "--- REGISTERS ---\n"); + + for (i = 0; i < ARRAY_SIZE(registers); i++) { + cfg = mipi_csis_read(state, registers[i].offset); + dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg); + } + + return 0; +} + +static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) +{ + struct csi_state *state = m->private; + + return mipi_csis_dump_regs(state); +} +DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); + +static void mipi_csis_debugfs_init(struct csi_state *state) +{ + state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL); + + debugfs_create_bool("debug_enable", 0600, state->debugfs_root, + &state->debug); + debugfs_create_file("dump_regs", 0600, state->debugfs_root, state, + &mipi_csis_dump_regs_fops); +} + +static void mipi_csis_debugfs_exit(struct csi_state *state) +{ + debugfs_remove_recursive(state->debugfs_root); +} + +/* ----------------------------------------------------------------------------- * V4L2 subdev operations */ -static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable) + +static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev) { - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + return container_of(sdev, struct csi_state, sd); +} + +static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct csi_state *state = mipi_sd_to_csis_state(sd); int ret; if (enable) { @@ -695,11 +832,10 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable) mipi_csis_clear_counters(state); - ret = pm_runtime_get_sync(&state->pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&state->pdev->dev); + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) return ret; - } + ret = v4l2_subdev_call(state->src_sd, core, s_power, 1); if (ret < 0 && ret != -ENOIOCTLCMD) goto done; @@ -708,7 +844,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable) mutex_lock(&state->lock); if (enable) { - if (state->flags & ST_SUSPENDED) { + if (state->state & ST_SUSPENDED) { ret = -EBUSY; goto unlock; } @@ -720,14 +856,14 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable) mipi_csis_log_counters(state, true); - state->flags |= ST_STREAMING; + state->state |= ST_STREAMING; } else { v4l2_subdev_call(state->src_sd, video, s_stream, 0); ret = v4l2_subdev_call(state->src_sd, core, s_power, 0); if (ret == -ENOIOCTLCMD) ret = 0; mipi_csis_stop_stream(state); - state->flags &= ~ST_STREAMING; + state->state &= ~ST_STREAMING; if (state->debug) mipi_csis_log_counters(state, true); } @@ -737,62 +873,33 @@ unlock: done: if (!enable || ret < 0) - pm_runtime_put(&state->pdev->dev); + pm_runtime_put(state->dev); return ret; } -static int mipi_csis_link_setup(struct media_entity *entity, - const struct media_pad *local_pad, - const struct media_pad *remote_pad, u32 flags) -{ - struct v4l2_subdev *mipi_sd = media_entity_to_v4l2_subdev(entity); - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); - struct v4l2_subdev *remote_sd; - - dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name, - local_pad->entity->name); - - /* We only care about the link to the source. */ - if (!(local_pad->flags & MEDIA_PAD_FL_SINK)) - return 0; - - remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); - - if (flags & MEDIA_LNK_FL_ENABLED) { - if (state->src_sd) - return -EBUSY; - - state->src_sd = remote_sd; - } else { - state->src_sd = NULL; - } - - return 0; -} - static struct v4l2_mbus_framefmt * mipi_csis_get_format(struct csi_state *state, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which, unsigned int pad) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&state->mipi_sd, cfg, pad); + return v4l2_subdev_get_try_format(&state->sd, sd_state, pad); return &state->format_mbus; } -static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd, - struct v4l2_subdev_pad_config *cfg) +static int mipi_csis_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) { - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + struct csi_state *state = mipi_sd_to_csis_state(sd); struct v4l2_mbus_framefmt *fmt_sink; struct v4l2_mbus_framefmt *fmt_source; enum v4l2_subdev_format_whence which; - which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink = mipi_csis_get_format(state, cfg, which, CSIS_PAD_SINK); + which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt_sink = mipi_csis_get_format(state, sd_state, which, CSIS_PAD_SINK); fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; @@ -811,35 +918,38 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *mipi_sd, * configuration, cfg is NULL, which indicates there's no source pad * configuration to set. */ - if (!cfg) + if (!sd_state) return 0; - fmt_source = mipi_csis_get_format(state, cfg, which, CSIS_PAD_SOURCE); + fmt_source = mipi_csis_get_format(state, sd_state, which, + CSIS_PAD_SOURCE); *fmt_source = *fmt_sink; return 0; } -static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd, - struct v4l2_subdev_pad_config *cfg, +static int mipi_csis_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + struct csi_state *state = mipi_sd_to_csis_state(sd); struct v4l2_mbus_framefmt *fmt; + fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + sdformat->pad); + mutex_lock(&state->lock); - fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad); sdformat->format = *fmt; mutex_unlock(&state->lock); return 0; } -static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd, - struct v4l2_subdev_pad_config *cfg, +static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + struct csi_state *state = mipi_sd_to_csis_state(sd); /* * The CSIS can't transcode in any way, the source format is identical @@ -851,7 +961,8 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd, if (code->index > 0) return -EINVAL; - fmt = mipi_csis_get_format(state, cfg, code->which, code->pad); + fmt = mipi_csis_get_format(state, sd_state, code->which, + code->pad); code->code = fmt->code; return 0; } @@ -867,11 +978,11 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd, return 0; } -static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd, - struct v4l2_subdev_pad_config *cfg, +static int mipi_csis_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + struct csi_state *state = mipi_sd_to_csis_state(sd); struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *fmt; unsigned int align; @@ -881,29 +992,22 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd, * modified. */ if (sdformat->pad == CSIS_PAD_SOURCE) - return mipi_csis_get_fmt(mipi_sd, cfg, sdformat); + return mipi_csis_get_fmt(sd, sd_state, sdformat); if (sdformat->pad != CSIS_PAD_SINK) return -EINVAL; - fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad); - - mutex_lock(&state->lock); - - /* Validate the media bus code and clamp the size. */ - csis_fmt = find_csis_format(sdformat->format.code); - if (!csis_fmt) - csis_fmt = &mipi_csis_formats[0]; - - fmt->code = csis_fmt->code; - fmt->width = sdformat->format.width; - fmt->height = sdformat->format.height; - /* + * Validate the media bus code and clamp and align the size. + * * The total number of bits per line must be a multiple of 8. We thus * need to align the width for formats that are not multiples of 8 * bits. */ + csis_fmt = find_csis_format(sdformat->format.code); + if (!csis_fmt) + csis_fmt = &mipi_csis_formats[0]; + switch (csis_fmt->width % 8) { case 0: align = 0; @@ -923,13 +1027,24 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd, break; } - v4l_bound_align_image(&fmt->width, 1, CSIS_MAX_PIX_WIDTH, align, - &fmt->height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0); + v4l_bound_align_image(&sdformat->format.width, 1, + CSIS_MAX_PIX_WIDTH, align, + &sdformat->format.height, 1, + CSIS_MAX_PIX_HEIGHT, 0, 0); + + fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + sdformat->pad); + + mutex_lock(&state->lock); + + fmt->code = csis_fmt->code; + fmt->width = sdformat->format.width; + fmt->height = sdformat->format.height; sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = mipi_csis_get_format(state, cfg, sdformat->which, + fmt = mipi_csis_get_format(state, sd_state, sdformat->which, CSIS_PAD_SOURCE); *fmt = sdformat->format; @@ -942,55 +1057,23 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd, return 0; } -static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd) +static int mipi_csis_log_status(struct v4l2_subdev *sd) { - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + struct csi_state *state = mipi_sd_to_csis_state(sd); mutex_lock(&state->lock); mipi_csis_log_counters(state, true); - if (state->debug && (state->flags & ST_POWERED)) + if (state->debug && (state->state & ST_POWERED)) mipi_csis_dump_regs(state); mutex_unlock(&state->lock); return 0; } -static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) -{ - struct csi_state *state = dev_id; - unsigned long flags; - unsigned int i; - u32 status; - - status = mipi_csis_read(state, MIPI_CSIS_INT_SRC); - - spin_lock_irqsave(&state->slock, flags); - - /* Update the event/error counters */ - if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) { - for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { - if (!(status & state->events[i].mask)) - continue; - state->events[i].counter++; - } - } - spin_unlock_irqrestore(&state->slock, flags); - - mipi_csis_write(state, MIPI_CSIS_INT_SRC, status); - - return IRQ_HANDLED; -} - static const struct v4l2_subdev_core_ops mipi_csis_core_ops = { .log_status = mipi_csis_log_status, }; -static const struct media_entity_operations mipi_csis_entity_ops = { - .link_setup = mipi_csis_link_setup, - .link_validate = v4l2_subdev_link_validate, - .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, -}; - static const struct v4l2_subdev_video_ops mipi_csis_video_ops = { .s_stream = mipi_csis_s_stream, }; @@ -1008,31 +1091,61 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { .pad = &mipi_csis_pad_ops, }; -static int mipi_csis_parse_dt(struct platform_device *pdev, - struct csi_state *state) +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +static int mipi_csis_link_setup(struct media_entity *entity, + const struct media_pad *local_pad, + const struct media_pad *remote_pad, u32 flags) { - struct device_node *node = pdev->dev.of_node; + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct csi_state *state = mipi_sd_to_csis_state(sd); + struct v4l2_subdev *remote_sd; - if (of_property_read_u32(node, "clock-frequency", - &state->clk_frequency)) - state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name, + local_pad->entity->name); - /* Get MIPI PHY resets */ - state->mrst = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(state->mrst)) - return PTR_ERR(state->mrst); + /* We only care about the link to the source. */ + if (!(local_pad->flags & MEDIA_PAD_FL_SINK)) + return 0; + + remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); + + if (flags & MEDIA_LNK_FL_ENABLED) { + if (state->src_sd) + return -EBUSY; + + state->src_sd = remote_sd; + } else { + state->src_sd = NULL; + } return 0; } -static int mipi_csis_pm_resume(struct device *dev, bool runtime); +static const struct media_entity_operations mipi_csis_entity_ops = { + .link_setup = mipi_csis_link_setup, + .link_validate = v4l2_subdev_link_validate, + .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, +}; + +/* ----------------------------------------------------------------------------- + * Async subdev notifier + */ + +static struct csi_state * +mipi_notifier_to_csis_state(struct v4l2_async_notifier *n) +{ + return container_of(n, struct csi_state, notifier); +} static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { struct csi_state *state = mipi_notifier_to_csis_state(notifier); - struct media_pad *sink = &state->mipi_sd.entity.pads[CSIS_PAD_SINK]; + struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK]; return v4l2_create_fwnode_links_to_pad(sd, sink, 0); } @@ -1041,38 +1154,6 @@ static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = { .bound = mipi_csis_notify_bound, }; -static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd, - struct platform_device *pdev, - const struct v4l2_subdev_ops *ops) -{ - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); - - v4l2_subdev_init(mipi_sd, ops); - mipi_sd->owner = THIS_MODULE; - snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d", - CSIS_SUBDEV_NAME, state->index); - - mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - mipi_sd->ctrl_handler = NULL; - - mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; - mipi_sd->entity.ops = &mipi_csis_entity_ops; - - mipi_sd->dev = &pdev->dev; - - state->csis_fmt = &mipi_csis_formats[0]; - mipi_csis_init_cfg(mipi_sd, NULL); - - v4l2_set_subdevdata(mipi_sd, &pdev->dev); - - state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK - | MEDIA_PAD_FL_MUST_CONNECT; - state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE - | MEDIA_PAD_FL_MUST_CONNECT; - return media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM, - state->pads); -} - static int mipi_csis_async_register(struct csi_state *state) { struct v4l2_fwnode_endpoint vep = { @@ -1080,6 +1161,7 @@ static int mipi_csis_async_register(struct csi_state *state) }; struct v4l2_async_subdev *asd; struct fwnode_handle *ep; + unsigned int i; int ret; v4l2_async_notifier_init(&state->notifier); @@ -1093,6 +1175,15 @@ static int mipi_csis_async_register(struct csi_state *state) if (ret) goto err_parse; + for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) { + if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) { + dev_err(state->dev, + "data lanes reordering is not supported"); + ret = -EINVAL; + goto err_parse; + } + } + state->bus = vep.bus.mipi_csi2; dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes); @@ -1109,12 +1200,11 @@ static int mipi_csis_async_register(struct csi_state *state) state->notifier.ops = &mipi_csis_notify_ops; - ret = v4l2_async_subdev_notifier_register(&state->mipi_sd, - &state->notifier); + ret = v4l2_async_subdev_notifier_register(&state->sd, &state->notifier); if (ret) return ret; - return v4l2_async_register_subdev(&state->mipi_sd); + return v4l2_async_register_subdev(&state->sd); err_parse: fwnode_handle_put(ep); @@ -1122,98 +1212,209 @@ err_parse: return ret; } -static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) +/* ----------------------------------------------------------------------------- + * Suspend/resume + */ + +static int mipi_csis_pm_suspend(struct device *dev, bool runtime) { - struct csi_state *state = m->private; + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csis_state(sd); + int ret = 0; - return mipi_csis_dump_regs(state); + mutex_lock(&state->lock); + if (state->state & ST_POWERED) { + mipi_csis_stop_stream(state); + ret = mipi_csis_phy_disable(state); + if (ret) + goto unlock; + mipi_csis_clk_disable(state); + state->state &= ~ST_POWERED; + if (!runtime) + state->state |= ST_SUSPENDED; + } + +unlock: + mutex_unlock(&state->lock); + + return ret ? -EAGAIN : 0; } -DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); -static void mipi_csis_debugfs_init(struct csi_state *state) +static int mipi_csis_pm_resume(struct device *dev, bool runtime) { - state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csis_state(sd); + int ret = 0; - debugfs_create_bool("debug_enable", 0600, state->debugfs_root, - &state->debug); - debugfs_create_file("dump_regs", 0600, state->debugfs_root, state, - &mipi_csis_dump_regs_fops); + mutex_lock(&state->lock); + if (!runtime && !(state->state & ST_SUSPENDED)) + goto unlock; + + if (!(state->state & ST_POWERED)) { + ret = mipi_csis_phy_enable(state); + if (ret) + goto unlock; + + state->state |= ST_POWERED; + mipi_csis_clk_enable(state); + } + if (state->state & ST_STREAMING) + mipi_csis_start_stream(state); + + state->state &= ~ST_SUSPENDED; + +unlock: + mutex_unlock(&state->lock); + + return ret ? -EAGAIN : 0; } -static void mipi_csis_debugfs_exit(struct csi_state *state) +static int __maybe_unused mipi_csis_suspend(struct device *dev) { - debugfs_remove_recursive(state->debugfs_root); + return mipi_csis_pm_suspend(dev, false); +} + +static int __maybe_unused mipi_csis_resume(struct device *dev) +{ + return mipi_csis_pm_resume(dev, false); +} + +static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) +{ + return mipi_csis_pm_suspend(dev, true); +} + +static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) +{ + return mipi_csis_pm_resume(dev, true); +} + +static const struct dev_pm_ops mipi_csis_pm_ops = { + SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume) +}; + +/* ----------------------------------------------------------------------------- + * Probe/remove & platform driver + */ + +static int mipi_csis_subdev_init(struct csi_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + + v4l2_subdev_init(sd, &mipi_csis_subdev_ops); + sd->owner = THIS_MODULE; + snprintf(sd->name, sizeof(sd->name), "%s.%d", + CSIS_SUBDEV_NAME, state->index); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->ctrl_handler = NULL; + + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->entity.ops = &mipi_csis_entity_ops; + + sd->dev = state->dev; + + state->csis_fmt = &mipi_csis_formats[0]; + mipi_csis_init_cfg(sd, NULL); + + state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK + | MEDIA_PAD_FL_MUST_CONNECT; + state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE + | MEDIA_PAD_FL_MUST_CONNECT; + return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, + state->pads); +} + +static int mipi_csis_parse_dt(struct csi_state *state) +{ + struct device_node *node = state->dev->of_node; + + if (of_property_read_u32(node, "clock-frequency", + &state->clk_frequency)) + state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + + return 0; } static int mipi_csis_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct csi_state *state; + int irq; int ret; state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; + mutex_init(&state->lock); spin_lock_init(&state->slock); - state->pdev = pdev; state->dev = dev; + state->info = of_device_get_match_data(dev); + + memcpy(state->events, mipi_csis_events, sizeof(state->events)); - ret = mipi_csis_parse_dt(pdev, state); + /* Parse DT properties. */ + ret = mipi_csis_parse_dt(state); if (ret < 0) { dev_err(dev, "Failed to parse device tree: %d\n", ret); return ret; } - ret = mipi_csis_phy_init(state); - if (ret < 0) - return ret; - - mipi_csis_phy_reset(state); - + /* Acquire resources. */ state->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(state->regs)) return PTR_ERR(state->regs); - state->irq = platform_get_irq(pdev, 0); - if (state->irq < 0) - return state->irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = mipi_csis_phy_init(state); + if (ret < 0) + return ret; ret = mipi_csis_clk_get(state); if (ret < 0) return ret; + /* Reset PHY and enable the clocks. */ + mipi_csis_phy_reset(state); + ret = mipi_csis_clk_enable(state); if (ret < 0) { dev_err(state->dev, "failed to enable clocks: %d\n", ret); return ret; } - ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler, - 0, dev_name(dev), state); + /* Now that the hardware is initialized, request the interrupt. */ + ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0, + dev_name(dev), state); if (ret) { dev_err(dev, "Interrupt request failed\n"); goto disable_clock; } - platform_set_drvdata(pdev, &state->mipi_sd); - - mutex_init(&state->lock); - ret = mipi_csis_subdev_init(&state->mipi_sd, pdev, - &mipi_csis_subdev_ops); + /* Initialize and register the subdev. */ + ret = mipi_csis_subdev_init(state); if (ret < 0) goto disable_clock; + platform_set_drvdata(pdev, &state->sd); + ret = mipi_csis_async_register(state); if (ret < 0) { - dev_err(&pdev->dev, "async register failed: %d\n", ret); + dev_err(dev, "async register failed: %d\n", ret); goto cleanup; } - memcpy(state->events, mipi_csis_events, sizeof(state->events)); - + /* Initialize debugfs. */ mipi_csis_debugfs_init(state); + + /* Enable runtime PM. */ pm_runtime_enable(dev); if (!pm_runtime_enabled(dev)) { ret = mipi_csis_pm_resume(dev, true); @@ -1221,7 +1422,7 @@ static int mipi_csis_probe(struct platform_device *pdev) goto unregister_all; } - dev_info(&pdev->dev, "lanes: %d, freq: %u\n", + dev_info(dev, "lanes: %d, freq: %u\n", state->bus.num_data_lanes, state->clk_frequency); return 0; @@ -1229,10 +1430,10 @@ static int mipi_csis_probe(struct platform_device *pdev) unregister_all: mipi_csis_debugfs_exit(state); cleanup: - media_entity_cleanup(&state->mipi_sd.entity); + media_entity_cleanup(&state->sd.entity); v4l2_async_notifier_unregister(&state->notifier); v4l2_async_notifier_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->mipi_sd); + v4l2_async_unregister_subdev(&state->sd); disable_clock: mipi_csis_clk_disable(state); mutex_destroy(&state->lock); @@ -1240,107 +1441,40 @@ disable_clock: return ret; } -static int mipi_csis_pm_suspend(struct device *dev, bool runtime) -{ - struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); - int ret = 0; - - mutex_lock(&state->lock); - if (state->flags & ST_POWERED) { - mipi_csis_stop_stream(state); - ret = regulator_disable(state->mipi_phy_regulator); - if (ret) - goto unlock; - mipi_csis_clk_disable(state); - state->flags &= ~ST_POWERED; - if (!runtime) - state->flags |= ST_SUSPENDED; - } - -unlock: - mutex_unlock(&state->lock); - - return ret ? -EAGAIN : 0; -} - -static int mipi_csis_pm_resume(struct device *dev, bool runtime) -{ - struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); - int ret = 0; - - mutex_lock(&state->lock); - if (!runtime && !(state->flags & ST_SUSPENDED)) - goto unlock; - - if (!(state->flags & ST_POWERED)) { - ret = regulator_enable(state->mipi_phy_regulator); - if (ret) - goto unlock; - - state->flags |= ST_POWERED; - mipi_csis_clk_enable(state); - } - if (state->flags & ST_STREAMING) - mipi_csis_start_stream(state); - - state->flags &= ~ST_SUSPENDED; - -unlock: - mutex_unlock(&state->lock); - - return ret ? -EAGAIN : 0; -} - -static int __maybe_unused mipi_csis_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, false); -} - -static int __maybe_unused mipi_csis_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, false); -} - -static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, true); -} - -static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, true); -} - static int mipi_csis_remove(struct platform_device *pdev) { - struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev); - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csi_state *state = mipi_sd_to_csis_state(sd); mipi_csis_debugfs_exit(state); v4l2_async_notifier_unregister(&state->notifier); v4l2_async_notifier_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->mipi_sd); + v4l2_async_unregister_subdev(&state->sd); pm_runtime_disable(&pdev->dev); mipi_csis_pm_suspend(&pdev->dev, true); mipi_csis_clk_disable(state); - media_entity_cleanup(&state->mipi_sd.entity); + media_entity_cleanup(&state->sd.entity); mutex_destroy(&state->lock); pm_runtime_set_suspended(&pdev->dev); return 0; } -static const struct dev_pm_ops mipi_csis_pm_ops = { - SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume) -}; - static const struct of_device_id mipi_csis_of_match[] = { - { .compatible = "fsl,imx7-mipi-csi2", }, + { + .compatible = "fsl,imx7-mipi-csi2", + .data = &(const struct mipi_csis_info){ + .version = MIPI_CSIS_V3_3, + .num_clocks = 3, + }, + }, { + .compatible = "fsl,imx8mm-mipi-csi2", + .data = &(const struct mipi_csis_info){ + .version = MIPI_CSIS_V3_6_3, + .num_clocks = 4, + }, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, mipi_csis_of_match); @@ -1357,6 +1491,6 @@ static struct platform_driver mipi_csis_driver = { module_platform_driver(mipi_csis_driver); -MODULE_DESCRIPTION("i.MX7 MIPI CSI-2 Receiver driver"); +MODULE_DESCRIPTION("i.MX7 & i.MX8 MIPI CSI-2 receiver driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:imx7-mipi-csi2"); diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h index 9b644fb23dde..fa3d6ee5adf2 100644 --- a/drivers/staging/media/ipu3/include/intel-ipu3.h +++ b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h @@ -9,8 +9,10 @@ /* from /drivers/staging/media/ipu3/include/videodev2.h */ /* Vendor specific - used for IPU3 camera sub-system */ -#define V4L2_META_FMT_IPU3_PARAMS v4l2_fourcc('i', 'p', '3', 'p') /* IPU3 processing parameters */ -#define V4L2_META_FMT_IPU3_STAT_3A v4l2_fourcc('i', 'p', '3', 's') /* IPU3 3A statistics */ +/* IPU3 processing parameters */ +#define V4L2_META_FMT_IPU3_PARAMS v4l2_fourcc('i', 'p', '3', 'p') +/* IPU3 3A statistics */ +#define V4L2_META_FMT_IPU3_STAT_3A v4l2_fourcc('i', 'p', '3', 's') /* from include/uapi/linux/v4l2-controls.h */ #define V4L2_CID_INTEL_IPU3_BASE (V4L2_CID_USER_BASE + 0x10c0) @@ -74,7 +76,6 @@ struct ipu3_uapi_grid_config { (IPU3_UAPI_AWB_MAX_SETS * \ (IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES)) - /** * struct ipu3_uapi_awb_raw_buffer - AWB raw buffer * @@ -244,8 +245,8 @@ struct ipu3_uapi_ae_ccm { */ struct ipu3_uapi_ae_config { struct ipu3_uapi_ae_grid_config grid_cfg __attribute__((aligned(32))); - struct ipu3_uapi_ae_weight_elem weights[ - IPU3_UAPI_AE_WEIGHTS] __attribute__((aligned(32))); + struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS] + __attribute__((aligned(32))); struct ipu3_uapi_ae_ccm ae_ccm __attribute__((aligned(32))); } __packed; @@ -630,7 +631,7 @@ struct ipu3_uapi_bnr_static_config_wb_gains_thr_config { * @cg: Gain coefficient for threshold calculation, [0, 31], default 8. * @ci: Intensity coefficient for threshold calculation. range [0, 0x1f] * default 6. - * format: u3.2 (3 most significant bits represent whole number, + * format: u3.2 (3 most significant bits represent whole number, * 2 least significant bits represent the fractional part * with each count representing 0.25) * e.g. 6 in binary format is 00110, that translates to 1.5 diff --git a/drivers/staging/media/ipu3/ipu3-abi.h b/drivers/staging/media/ipu3/ipu3-abi.h index e1185602c7fd..c76935b436d7 100644 --- a/drivers/staging/media/ipu3/ipu3-abi.h +++ b/drivers/staging/media/ipu3/ipu3-abi.h @@ -4,7 +4,7 @@ #ifndef __IPU3_ABI_H #define __IPU3_ABI_H -#include "include/intel-ipu3.h" +#include "include/uapi/intel-ipu3.h" /******************* IMGU Hardware information *******************/ diff --git a/drivers/staging/media/ipu3/ipu3-css-pool.h b/drivers/staging/media/ipu3/ipu3-css-pool.h index 35519a08c08c..3f9e32e0e9a7 100644 --- a/drivers/staging/media/ipu3/ipu3-css-pool.h +++ b/drivers/staging/media/ipu3/ipu3-css-pool.h @@ -15,6 +15,7 @@ struct imgu_device; * @size: size of the buffer in bytes. * @vaddr: kernel virtual address. * @daddr: iova dma address to access IPU3. + * @pages: pages mapped to this buffer */ struct imgu_css_map { size_t size; diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index 6d9c49b39531..38a240764509 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -36,7 +36,7 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) /* Initialize try_fmt */ for (i = 0; i < IMGU_NODE_NUM; i++) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->pad, i); + v4l2_subdev_get_try_format(sd, fh->state, i); try_fmt->width = try_crop.width; try_fmt->height = try_crop.height; @@ -44,8 +44,8 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) try_fmt->field = V4L2_FIELD_NONE; } - *v4l2_subdev_get_try_crop(sd, fh->pad, IMGU_NODE_IN) = try_crop; - *v4l2_subdev_get_try_compose(sd, fh->pad, IMGU_NODE_IN) = try_crop; + *v4l2_subdev_get_try_crop(sd, fh->state, IMGU_NODE_IN) = try_crop; + *v4l2_subdev_get_try_compose(sd, fh->state, IMGU_NODE_IN) = try_crop; return 0; } @@ -120,7 +120,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable) } static int imgu_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct imgu_device *imgu = v4l2_get_subdevdata(sd); @@ -136,7 +136,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { fmt->format = imgu_pipe->nodes[pad].pad_fmt; } else { - mf = v4l2_subdev_get_try_format(sd, cfg, pad); + mf = v4l2_subdev_get_try_format(sd, sd_state, pad); fmt->format = *mf; } @@ -144,7 +144,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd, } static int imgu_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct imgu_media_pipe *imgu_pipe; @@ -161,7 +161,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd, imgu_pipe = &imgu->imgu_pipe[pipe]; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - mf = v4l2_subdev_get_try_format(sd, cfg, pad); + mf = v4l2_subdev_get_try_format(sd, sd_state, pad); else mf = &imgu_pipe->nodes[pad].pad_fmt; @@ -189,7 +189,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd, } static int imgu_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { struct v4l2_rect *try_sel, *r; @@ -202,11 +202,11 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); r = &imgu_sd->rect.eff; break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad); r = &imgu_sd->rect.bds; break; default: @@ -222,7 +222,7 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd, } static int imgu_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { struct imgu_device *imgu = v4l2_get_subdevdata(sd); @@ -241,11 +241,11 @@ static int imgu_subdev_set_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); rect = &imgu_sd->rect.eff; break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad); rect = &imgu_sd->rect.bds; break; default: diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c index ee1bba6bdcac..8e1e9e46e604 100644 --- a/drivers/staging/media/ipu3/ipu3.c +++ b/drivers/staging/media/ipu3/ipu3.c @@ -392,10 +392,9 @@ int imgu_s_stream(struct imgu_device *imgu, int enable) } /* Set Power */ - r = pm_runtime_get_sync(dev); + r = pm_runtime_resume_and_get(dev); if (r < 0) { dev_err(dev, "failed to set imgu power\n"); - pm_runtime_put(dev); return r; } diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c index 7f07a9175815..b9125c295d1d 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.c +++ b/drivers/staging/media/meson/vdec/vdec_helpers.c @@ -183,7 +183,7 @@ int amvdec_set_canvases(struct amvdec_session *sess, u32 pixfmt = sess->pixfmt_cap; u32 width = ALIGN(sess->width, 32); u32 height = ALIGN(sess->height, 32); - u32 reg_cur = reg_base[0]; + u32 reg_cur; u32 reg_num_cur = 0; u32 reg_base_cur = 0; int i = 0; diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h index b88f9529683c..3f587e000729 100644 --- a/drivers/staging/media/omap4iss/iss.h +++ b/drivers/staging/media/omap4iss/iss.h @@ -119,9 +119,6 @@ struct iss_device { unsigned int isp_subclk_resources; }; -#define v4l2_dev_to_iss_device(dev) \ - container_of(dev, struct iss_device, v4l2_dev) - int omap4iss_get_external_info(struct iss_pipeline *pipe, struct media_link *link); diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index a6dc2d2b1228..124ab2f44fbf 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -825,19 +825,20 @@ static const struct iss_video_operations csi2_issvideo_ops = { static struct v4l2_mbus_framefmt * __csi2_get_format(struct iss_csi2_device *csi2, - struct v4l2_subdev_pad_config *cfg, + 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(&csi2->subdev, cfg, pad); + return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, + pad); return &csi2->formats[pad]; } static void csi2_try_format(struct iss_csi2_device *csi2, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) @@ -868,7 +869,8 @@ csi2_try_format(struct iss_csi2_device *csi2, * compression. */ pixelcode = fmt->code; - format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which); + format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK, + which); memcpy(fmt, format, sizeof(*fmt)); /* @@ -894,7 +896,7 @@ csi2_try_format(struct iss_csi2_device *csi2, * return -EINVAL or zero on success */ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -907,7 +909,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, code->code = csi2_input_fmts[code->index]; } else { - format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, + format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK, code->which); switch (code->index) { case 0: @@ -931,7 +933,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, } static int csi2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -943,7 +945,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); + csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -953,7 +955,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); + csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -968,13 +970,13 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, * return -EINVAL or zero on success */ static int csi2_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; @@ -990,25 +992,26 @@ static int csi2_get_format(struct v4l2_subdev *sd, * return -EINVAL or zero on success */ static int csi2_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; - csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which); + csi2_try_format(csi2, sd_state, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CSI2_PAD_SINK) { - format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE, + format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SOURCE, fmt->which); *format = fmt->format; - csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which); + csi2_try_format(csi2, sd_state, CSI2_PAD_SOURCE, format, + fmt->which); } return 0; @@ -1050,7 +1053,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - csi2_set_format(sd, fh ? fh->pad : NULL, &format); + csi2_set_format(sd, fh ? fh->state : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c index 26be078b69f3..23f707cb336f 100644 --- a/drivers/staging/media/omap4iss/iss_ipipe.c +++ b/drivers/staging/media/omap4iss/iss_ipipe.c @@ -21,7 +21,7 @@ static struct v4l2_mbus_framefmt * __ipipe_get_format(struct iss_ipipe_device *ipipe, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, unsigned int pad, enum v4l2_subdev_format_whence which); @@ -175,12 +175,13 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) static struct v4l2_mbus_framefmt * __ipipe_get_format(struct iss_ipipe_device *ipipe, - struct v4l2_subdev_pad_config *cfg, + 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(&ipipe->subdev, cfg, pad); + return v4l2_subdev_get_try_format(&ipipe->subdev, sd_state, + pad); return &ipipe->formats[pad]; } @@ -194,7 +195,7 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe, */ static void ipipe_try_format(struct iss_ipipe_device *ipipe, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) @@ -222,7 +223,8 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, break; case IPIPE_PAD_SOURCE_VP: - format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SINK, which); + format = __ipipe_get_format(ipipe, sd_state, IPIPE_PAD_SINK, + which); memcpy(fmt, format, sizeof(*fmt)); fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; @@ -243,7 +245,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, * return -EINVAL or zero on success */ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -270,7 +272,7 @@ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, } static int ipipe_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); @@ -282,7 +284,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); + ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -292,7 +294,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); + ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -309,13 +311,13 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, * to the format type. */ static int ipipe_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; @@ -333,25 +335,26 @@ static int ipipe_get_format(struct v4l2_subdev *sd, * to the format type. */ static int ipipe_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; - ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); + ipipe_try_format(ipipe, sd_state, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == IPIPE_PAD_SINK) { - format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, + format = __ipipe_get_format(ipipe, sd_state, + IPIPE_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ipipe_try_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, format, + ipipe_try_format(ipipe, sd_state, IPIPE_PAD_SOURCE_VP, format, fmt->which); } @@ -392,7 +395,7 @@ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ipipe_set_format(sd, fh ? fh->pad : NULL, &format); + ipipe_set_format(sd, fh ? fh->state : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c index c2978d02e797..5e7f25cd53ac 100644 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ b/drivers/staging/media/omap4iss/iss_ipipeif.c @@ -357,11 +357,12 @@ static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) static struct v4l2_mbus_framefmt * __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, + 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(&ipipeif->subdev, cfg, pad); + return v4l2_subdev_get_try_format(&ipipeif->subdev, sd_state, + pad); return &ipipeif->formats[pad]; } @@ -374,7 +375,7 @@ __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, */ static void ipipeif_try_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, + struct v4l2_subdev_state *sd_state, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -403,7 +404,8 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, break; case IPIPEIF_PAD_SOURCE_ISIF_SF: - format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, sd_state, + IPIPEIF_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -418,7 +420,8 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, break; case IPIPEIF_PAD_SOURCE_VP: - format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, sd_state, + IPIPEIF_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -442,7 +445,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, * return -EINVAL or zero on success */ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -462,7 +465,8 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, sd_state, + IPIPEIF_PAD_SINK, code->which); code->code = format->code; @@ -476,7 +480,7 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, } static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -488,7 +492,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); + ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -498,7 +502,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); + ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -515,13 +519,13 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, * to the format type. */ static int ipipeif_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; @@ -539,33 +543,36 @@ static int ipipeif_get_format(struct v4l2_subdev *sd, * to the format type. */ static int ipipeif_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; - ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); + ipipeif_try_format(ipipeif, sd_state, fmt->pad, &fmt->format, + fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == IPIPEIF_PAD_SINK) { - format = __ipipeif_get_format(ipipeif, cfg, + format = __ipipeif_get_format(ipipeif, sd_state, IPIPEIF_PAD_SOURCE_ISIF_SF, fmt->which); *format = fmt->format; - ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF, + ipipeif_try_format(ipipeif, sd_state, + IPIPEIF_PAD_SOURCE_ISIF_SF, format, fmt->which); - format = __ipipeif_get_format(ipipeif, cfg, + format = __ipipeif_get_format(ipipeif, sd_state, IPIPEIF_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, format, + ipipeif_try_format(ipipeif, sd_state, IPIPEIF_PAD_SOURCE_VP, + format, fmt->which); } @@ -608,7 +615,7 @@ static int ipipeif_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ipipeif_set_format(sd, fh ? fh->pad : NULL, &format); + ipipeif_set_format(sd, fh ? fh->state : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c index 3b6875cbca9b..a5f8f9f1ab16 100644 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ b/drivers/staging/media/omap4iss/iss_resizer.c @@ -416,11 +416,12 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) static struct v4l2_mbus_framefmt * __resizer_get_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, + 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(&resizer->subdev, cfg, pad); + return v4l2_subdev_get_try_format(&resizer->subdev, sd_state, + pad); return &resizer->formats[pad]; } @@ -433,7 +434,7 @@ __resizer_get_format(struct iss_resizer_device *resizer, */ static void resizer_try_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, + struct v4l2_subdev_state *sd_state, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -461,7 +462,8 @@ resizer_try_format(struct iss_resizer_device *resizer, case RESIZER_PAD_SOURCE_MEM: pixelcode = fmt->code; - format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK, + format = __resizer_get_format(resizer, sd_state, + RESIZER_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -492,7 +494,7 @@ resizer_try_format(struct iss_resizer_device *resizer, * return -EINVAL or zero on success */ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); @@ -507,7 +509,8 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, break; case RESIZER_PAD_SOURCE_MEM: - format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK, + format = __resizer_get_format(resizer, sd_state, + RESIZER_PAD_SINK, code->which); if (code->index == 0) { @@ -537,7 +540,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, } static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); @@ -549,7 +552,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - resizer_try_format(resizer, cfg, fse->pad, &format, fse->which); + resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -559,7 +562,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - resizer_try_format(resizer, cfg, fse->pad, &format, fse->which); + resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -576,13 +579,13 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, * to the format type. */ static int resizer_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which); + format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; @@ -600,26 +603,28 @@ static int resizer_get_format(struct v4l2_subdev *sd, * to the format type. */ static int resizer_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which); + format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which); if (!format) return -EINVAL; - resizer_try_format(resizer, cfg, fmt->pad, &fmt->format, fmt->which); + resizer_try_format(resizer, sd_state, fmt->pad, &fmt->format, + fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == RESIZER_PAD_SINK) { - format = __resizer_get_format(resizer, cfg, + format = __resizer_get_format(resizer, sd_state, RESIZER_PAD_SOURCE_MEM, fmt->which); *format = fmt->format; - resizer_try_format(resizer, cfg, RESIZER_PAD_SOURCE_MEM, format, + resizer_try_format(resizer, sd_state, RESIZER_PAD_SOURCE_MEM, + format, fmt->which); } @@ -662,7 +667,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_1X16; format.format.width = 4096; format.format.height = 4096; - resizer_set_format(sd, fh ? fh->pad : NULL, &format); + resizer_set_format(sd, fh ? fh->state : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 930f638f51eb..d0da083deed5 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -399,7 +399,7 @@ static void iss_video_buf_queue(struct vb2_buffer *vb) if (start) omap4iss_pipeline_set_stream(pipe, - ISS_PIPELINE_STREAM_SINGLESHOT); + ISS_PIPELINE_STREAM_SINGLESHOT); } } @@ -960,7 +960,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) unsigned long flags; ret = omap4iss_pipeline_set_stream(pipe, - ISS_PIPELINE_STREAM_CONTINUOUS); + ISS_PIPELINE_STREAM_CONTINUOUS); if (ret < 0) goto err_omap4iss_set_stream; spin_lock_irqsave(&video->qlock, flags); diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index d821661d30f3..7131156c1f2c 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -481,7 +481,15 @@ static int rkvdec_buf_prepare(struct vb2_buffer *vb) if (vb2_plane_size(vb, i) < sizeimage) return -EINVAL; } - vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage); + + /* + * Buffer's bytesused must be written by driver for CAPTURE buffers. + * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets + * it to buffer length). + */ + if (V4L2_TYPE_IS_CAPTURE(vq->type)) + vb2_set_plane_payload(vb, 0, f->fmt.pix_mp.plane_fmt[0].sizeimage); + return 0; } @@ -658,7 +666,7 @@ static void rkvdec_device_run(void *priv) if (WARN_ON(!desc)) return; - ret = pm_runtime_get_sync(rkvdec->dev); + ret = pm_runtime_resume_and_get(rkvdec->dev); if (ret < 0) { rkvdec_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR); return; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 92812d1a39d4..c0d005dafc6c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -31,13 +31,19 @@ static const struct cedrus_control cedrus_controls[] = { { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, + .id = V4L2_CID_STATELESS_MPEG2_SEQUENCE, }, .codec = CEDRUS_CODEC_MPEG2, }, { .cfg = { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + .id = V4L2_CID_STATELESS_MPEG2_PICTURE, + }, + .codec = CEDRUS_CODEC_MPEG2, + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_MPEG2_QUANTISATION, }, .codec = CEDRUS_CODEC_MPEG2, }, @@ -151,6 +157,12 @@ static const struct cedrus_control cedrus_controls[] = { }, .codec = CEDRUS_CODEC_VP8, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS, + }, + .codec = CEDRUS_CODEC_H265, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 15f147dad4cb..88afba17b78b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -68,14 +68,16 @@ struct cedrus_h264_run { }; struct cedrus_mpeg2_run { - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_ctrl_mpeg2_quantization *quantization; + const struct v4l2_ctrl_mpeg2_sequence *sequence; + const struct v4l2_ctrl_mpeg2_picture *picture; + const struct v4l2_ctrl_mpeg2_quantisation *quantisation; }; struct cedrus_h265_run { const struct v4l2_ctrl_hevc_sps *sps; const struct v4l2_ctrl_hevc_pps *pps; const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_ctrl_hevc_decode_params *decode_params; }; struct cedrus_vp8_run { diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index d696b3ec70c0..40e8c4123f76 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -40,10 +40,12 @@ void cedrus_device_run(void *priv) switch (ctx->src_fmt.pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: - run.mpeg2.slice_params = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - run.mpeg2.quantization = cedrus_find_control_data(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); + run.mpeg2.sequence = cedrus_find_control_data(ctx, + V4L2_CID_STATELESS_MPEG2_SEQUENCE); + run.mpeg2.picture = cedrus_find_control_data(ctx, + V4L2_CID_STATELESS_MPEG2_PICTURE); + run.mpeg2.quantisation = cedrus_find_control_data(ctx, + V4L2_CID_STATELESS_MPEG2_QUANTISATION); break; case V4L2_PIX_FMT_H264_SLICE: @@ -68,6 +70,8 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_HEVC_PPS); run.h265.slice_params = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); + run.h265.decode_params = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS); break; case V4L2_PIX_FMT_VP8_FRAME: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index ce497d0197df..6821e3d05d34 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -245,6 +245,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps; const struct v4l2_ctrl_hevc_pps *pps; const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_ctrl_hevc_decode_params *decode_params; const struct v4l2_hevc_pred_weight_table *pred_weight_table; dma_addr_t src_buf_addr; dma_addr_t src_buf_end_addr; @@ -256,6 +257,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, sps = run->h265.sps; pps = run->h265.pps; slice_params = run->h265.slice_params; + decode_params = run->h265.decode_params; pred_weight_table = &slice_params->pred_weight_table; /* MV column buffer size and allocation. */ @@ -477,8 +479,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, slice_params->flags); reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_DEPENDENT_SLICE_SEGMENT, - V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT, - pps->flags); + V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, + slice_params->flags); /* FIXME: For multi-slice support. */ reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC; @@ -487,7 +489,7 @@ 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(slice_params->num_rps_poc_st_curr_after == 0) | + 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); @@ -527,8 +529,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, cedrus_write(dev, VE_DEC_H265_NEIGHBOR_INFO_ADDR, reg); /* Write decoded picture buffer in pic list. */ - cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb, - slice_params->num_active_dpb_entries); + cedrus_h265_frame_info_write_dpb(ctx, decode_params->dpb, + decode_params->num_active_dpb_entries); /* Output frame. */ @@ -545,7 +547,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Reference picture list 0 (for P/B frames). */ if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_I) { - cedrus_h265_ref_pic_list_write(dev, slice_params->dpb, + cedrus_h265_ref_pic_list_write(dev, decode_params->dpb, slice_params->ref_idx_l0, slice_params->num_ref_idx_l0_active_minus1 + 1, VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST0); @@ -564,7 +566,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, /* Reference picture list 1 (for B frames). */ if (slice_params->slice_type == V4L2_HEVC_SLICE_TYPE_B) { - cedrus_h265_ref_pic_list_write(dev, slice_params->dpb, + cedrus_h265_ref_pic_list_write(dev, decode_params->dpb, slice_params->ref_idx_l1, slice_params->num_ref_idx_l1_active_minus1 + 1, VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST1); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 8bcd6b8f9e2d..5dad2f296c6d 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -13,30 +13,6 @@ #include "cedrus_hw.h" #include "cedrus_regs.h" -/* Default MPEG-2 quantization coefficients, from the specification. */ - -static const u8 intra_quantization_matrix_default[64] = { - 8, 16, 16, 19, 16, 19, 22, 22, - 22, 22, 22, 22, 26, 24, 26, 27, - 27, 27, 26, 26, 26, 26, 27, 27, - 27, 29, 29, 29, 34, 34, 34, 29, - 29, 29, 27, 27, 29, 29, 32, 32, - 34, 34, 37, 38, 37, 35, 35, 34, - 35, 38, 38, 40, 40, 40, 48, 48, - 46, 46, 56, 56, 58, 69, 69, 83 -}; - -static const u8 non_intra_quantization_matrix_default[64] = { - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16 -}; - static enum cedrus_irq_status cedrus_mpeg2_irq_status(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; @@ -74,10 +50,9 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx) static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) { - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - const struct v4l2_mpeg2_picture *picture; - const struct v4l2_ctrl_mpeg2_quantization *quantization; + const struct v4l2_ctrl_mpeg2_sequence *seq; + const struct v4l2_ctrl_mpeg2_picture *pic; + const struct v4l2_ctrl_mpeg2_quantisation *quantisation; dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr; dma_addr_t fwd_luma_addr, fwd_chroma_addr; dma_addr_t bwd_luma_addr, bwd_chroma_addr; @@ -89,22 +64,16 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) unsigned int i; u32 reg; - slice_params = run->mpeg2.slice_params; - sequence = &slice_params->sequence; - picture = &slice_params->picture; + seq = run->mpeg2.sequence; + pic = run->mpeg2.picture; - quantization = run->mpeg2.quantization; + quantisation = run->mpeg2.quantisation; /* Activate MPEG engine. */ cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2); - /* Set intra quantization matrix. */ - - if (quantization && quantization->load_intra_quantiser_matrix) - matrix = quantization->intra_quantiser_matrix; - else - matrix = intra_quantization_matrix_default; - + /* Set intra quantisation matrix. */ + matrix = quantisation->intra_quantiser_matrix; for (i = 0; i < 64; i++) { reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]); reg |= VE_DEC_MPEG_IQMINPUT_FLAG_INTRA; @@ -112,13 +81,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) cedrus_write(dev, VE_DEC_MPEG_IQMINPUT, reg); } - /* Set non-intra quantization matrix. */ - - if (quantization && quantization->load_non_intra_quantiser_matrix) - matrix = quantization->non_intra_quantiser_matrix; - else - matrix = non_intra_quantization_matrix_default; - + /* Set non-intra quantisation matrix. */ + matrix = quantisation->non_intra_quantiser_matrix; for (i = 0; i < 64; i++) { reg = VE_DEC_MPEG_IQMINPUT_WEIGHT(i, matrix[i]); reg |= VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA; @@ -128,19 +92,19 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) /* Set MPEG picture header. */ - reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(picture->picture_coding_type); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, picture->f_code[0][0]); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, picture->f_code[0][1]); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, picture->f_code[1][0]); - reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, picture->f_code[1][1]); - reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(picture->intra_dc_precision); - reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(picture->picture_structure); - reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(picture->top_field_first); - reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(picture->frame_pred_frame_dct); - reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(picture->concealment_motion_vectors); - reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(picture->q_scale_type); - reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(picture->intra_vlc_format); - reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(picture->alternate_scan); + reg = VE_DEC_MPEG_MP12HDR_SLICE_TYPE(pic->picture_coding_type); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 0, pic->f_code[0][0]); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(0, 1, pic->f_code[0][1]); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 0, pic->f_code[1][0]); + reg |= VE_DEC_MPEG_MP12HDR_F_CODE(1, 1, pic->f_code[1][1]); + reg |= VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(pic->intra_dc_precision); + reg |= VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(pic->picture_structure); + reg |= VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(pic->flags & V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST); + reg |= VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(pic->flags & V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT); + reg |= VE_DEC_MPEG_MP12HDR_CONCEALMENT_MOTION_VECTORS(pic->flags & V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV); + reg |= VE_DEC_MPEG_MP12HDR_Q_SCALE_TYPE(pic->flags & V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE); + reg |= VE_DEC_MPEG_MP12HDR_INTRA_VLC_FORMAT(pic->flags & V4L2_MPEG2_PIC_FLAG_INTRA_VLC); + reg |= VE_DEC_MPEG_MP12HDR_ALTERNATE_SCAN(pic->flags & V4L2_MPEG2_PIC_FLAG_ALT_SCAN); reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_FORWARD_VECTOR(0); reg |= VE_DEC_MPEG_MP12HDR_FULL_PEL_BACKWARD_VECTOR(0); @@ -148,8 +112,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) /* Set frame dimensions. */ - reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(sequence->horizontal_size); - reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(sequence->vertical_size); + reg = VE_DEC_MPEG_PICCODEDSIZE_WIDTH(seq->horizontal_size); + reg |= VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(seq->vertical_size); cedrus_write(dev, VE_DEC_MPEG_PICCODEDSIZE, reg); @@ -162,14 +126,14 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - forward_idx = vb2_find_timestamp(vq, slice_params->forward_ref_ts, 0); + forward_idx = vb2_find_timestamp(vq, pic->forward_ref_ts, 0); fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0); fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1); cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr); cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr); - backward_idx = vb2_find_timestamp(vq, slice_params->backward_ref_ts, 0); + backward_idx = vb2_find_timestamp(vq, pic->backward_ref_ts, 0); bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0); bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1); @@ -186,10 +150,9 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) /* Source offset and length in bits. */ - cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET, - slice_params->data_bit_offset); + cedrus_write(dev, VE_DEC_MPEG_VLD_OFFSET, 0); - reg = slice_params->bit_size - slice_params->data_bit_offset; + reg = vb2_get_plane_payload(&run->src->vb2_buf, 0) * 8; cedrus_write(dev, VE_DEC_MPEG_VLD_LEN, reg); /* Source beginning and end addresses. */ @@ -203,7 +166,7 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) cedrus_write(dev, VE_DEC_MPEG_VLD_ADDR, reg); - reg = src_buf_addr + DIV_ROUND_UP(slice_params->bit_size, 8); + reg = src_buf_addr + vb2_get_plane_payload(&run->src->vb2_buf, 0); cedrus_write(dev, VE_DEC_MPEG_VLD_END_ADDR, reg); /* Macroblock address: start at the beginning. */ diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index b62eb8e84057..32c13ecb22d8 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -457,7 +457,13 @@ static int cedrus_buf_prepare(struct vb2_buffer *vb) if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage) return -EINVAL; - vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage); + /* + * Buffer's bytesused must be written by driver for CAPTURE buffers. + * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets + * it to buffer length). + */ + if (V4L2_TYPE_IS_CAPTURE(vq->type)) + vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage); return 0; } @@ -490,11 +496,9 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) } if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) { - pm_runtime_put_noidle(dev->dev); + ret = pm_runtime_resume_and_get(dev->dev); + if (ret < 0) goto err_cleanup; - } if (dev->dec_ops[ctx->current_codec]->start) { ret = dev->dec_ops[ctx->current_codec]->start(ctx); diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c index 28845b5bafaf..ed4c1250b303 100644 --- a/drivers/staging/media/tegra-vde/vde.c +++ b/drivers/staging/media/tegra-vde/vde.c @@ -775,9 +775,9 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, if (ret) goto release_dpb_frames; - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) - goto put_runtime_pm; + goto unlock; /* * We rely on the VDE registers reset value, otherwise VDE @@ -843,6 +843,8 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, put_runtime_pm: pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + +unlock: mutex_unlock(&vde->lock); release_dpb_frames: @@ -1069,11 +1071,20 @@ static int tegra_vde_probe(struct platform_device *pdev) * power-cycle it in order to put hardware into a predictable lower * power state. */ - pm_runtime_get_sync(dev); + err = pm_runtime_resume_and_get(dev); + if (err) + goto err_pm_runtime; + pm_runtime_put(dev); return 0; +err_pm_runtime: + misc_deregister(&vde->miscdev); + + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_disable(dev); + err_deinit_iommu: tegra_vde_iommu_deinit(vde); @@ -1089,7 +1100,12 @@ static int tegra_vde_remove(struct platform_device *pdev) struct tegra_vde *vde = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + /* + * As it increments RPM usage_count even on errors, we don't need to + * check the returned code here. + */ pm_runtime_get_sync(dev); + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c index 033a6935c26d..b26e44adb2be 100644 --- a/drivers/staging/media/tegra-video/csi.c +++ b/drivers/staging/media/tegra-video/csi.c @@ -64,7 +64,7 @@ static const struct v4l2_frmsize_discrete tegra_csi_tpg_sizes[] = { * V4L2 Subdevice Pad Operations */ static int csi_enum_bus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG)) @@ -79,7 +79,7 @@ static int csi_enum_bus_code(struct v4l2_subdev *subdev, } static int csi_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct tegra_csi_channel *csi_chan = to_csi_chan(subdev); @@ -127,7 +127,7 @@ static void csi_chan_update_blank_intervals(struct tegra_csi_channel *csi_chan, } static int csi_enum_framesizes(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { unsigned int i; @@ -154,7 +154,7 @@ static int csi_enum_framesizes(struct v4l2_subdev *subdev, } static int csi_enum_frameintervals(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval_enum *fie) { struct tegra_csi_channel *csi_chan = to_csi_chan(subdev); @@ -181,7 +181,7 @@ static int csi_enum_frameintervals(struct v4l2_subdev *subdev, } static int csi_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct tegra_csi_channel *csi_chan = to_csi_chan(subdev); @@ -298,10 +298,9 @@ static int tegra_csi_enable_stream(struct v4l2_subdev *subdev) struct tegra_csi *csi = csi_chan->csi; int ret, err; - ret = pm_runtime_get_sync(csi->dev); + ret = pm_runtime_resume_and_get(csi->dev); if (ret < 0) { dev_err(csi->dev, "failed to get runtime PM: %d\n", ret); - pm_runtime_put_noidle(csi->dev); return ret; } diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index df5ca3596470..89709cd06d4d 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -297,10 +297,9 @@ static int tegra_channel_start_streaming(struct vb2_queue *vq, u32 count) struct tegra_vi_channel *chan = vb2_get_drv_priv(vq); int ret; - ret = pm_runtime_get_sync(chan->vi->dev); + ret = pm_runtime_resume_and_get(chan->vi->dev); if (ret < 0) { dev_err(chan->vi->dev, "failed to get runtime PM: %d\n", ret); - pm_runtime_put_noidle(chan->vi->dev); return ret; } @@ -494,7 +493,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, const struct tegra_video_format *fmtinfo; struct v4l2_subdev *subdev; struct v4l2_subdev_format fmt; - struct v4l2_subdev_pad_config *pad_cfg; + struct v4l2_subdev_state *sd_state; struct v4l2_subdev_frame_size_enum fse = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -508,8 +507,8 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, if (!subdev) return -ENODEV; - pad_cfg = v4l2_subdev_alloc_pad_config(subdev); - if (!pad_cfg) + sd_state = v4l2_subdev_alloc_state(subdev); + if (!sd_state) return -ENOMEM; /* * Retrieve the format information and if requested format isn't @@ -533,33 +532,33 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, * If not available, try to get crop boundary from subdev. */ fse.code = fmtinfo->code; - ret = v4l2_subdev_call(subdev, pad, enum_frame_size, pad_cfg, &fse); + ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse); if (ret) { if (!v4l2_subdev_has_op(subdev, pad, get_selection)) { - pad_cfg->try_crop.width = 0; - pad_cfg->try_crop.height = 0; + sd_state->pads->try_crop.width = 0; + sd_state->pads->try_crop.height = 0; } else { ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel); if (ret) return -EINVAL; - pad_cfg->try_crop.width = sdsel.r.width; - pad_cfg->try_crop.height = sdsel.r.height; + sd_state->pads->try_crop.width = sdsel.r.width; + sd_state->pads->try_crop.height = sdsel.r.height; } } else { - pad_cfg->try_crop.width = fse.max_width; - pad_cfg->try_crop.height = fse.max_height; + sd_state->pads->try_crop.width = fse.max_width; + sd_state->pads->try_crop.height = fse.max_height; } - ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt); + ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt); if (ret < 0) return ret; v4l2_fill_pix_format(pix, &fmt.format); tegra_channel_fmt_align(chan, pix, fmtinfo->bpp); - v4l2_subdev_free_pad_config(pad_cfg); + v4l2_subdev_free_state(sd_state); return 0; } @@ -1812,8 +1811,8 @@ static int tegra_vi_graph_parse_one(struct tegra_vi_channel *chan, continue; } - tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier, - remote, struct tegra_vi_graph_entity); + tvge = v4l2_async_notifier_add_fwnode_subdev(&chan->notifier, remote, + struct tegra_vi_graph_entity); if (IS_ERR(tvge)) { ret = PTR_ERR(tvge); dev_err(vi->dev, diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h index e7fe8da7732c..b1ad2a2b914c 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -158,7 +158,6 @@ struct zoran_jpg_settings { struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */ }; - struct zoran; /* zoran_fh contains per-open() settings */ diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index dfc60e2e9dd7..f259585b0689 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -37,9 +37,10 @@ module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "Card type"); /* - * The video mem address of the video card. The driver has a little database for some videocards - * to determine it from there. If your video card is not in there you have either to give it to - * the driver as a parameter or set in in a VIDIOCSFBUF ioctl + * The video mem address of the video card. The driver has a little database + * for some videocards to determine it from there. If your video card is not + * in there you have either to give it to the driver as a parameter or set + * in a VIDIOCSFBUF ioctl */ static unsigned long vidmem; /* default = 0 - Video memory base address */ diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/media/zoran/zoran_device.c index cf788d9cd1df..5b12a730a229 100644 --- a/drivers/staging/media/zoran/zoran_device.c +++ b/drivers/staging/media/zoran/zoran_device.c @@ -148,71 +148,6 @@ int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg) } /* - * detect guests - */ - -static void dump_guests(struct zoran *zr) -{ - if (zr36067_debug > 2) { - int i, guest[8]; - - /* do not print random data */ - guest[0] = 0; - - for (i = 1; i < 8; i++) /* Don't read jpeg codec here */ - guest[i] = post_office_read(zr, i, 0); - - pci_info(zr->pci_dev, "Guests: %*ph\n", 8, guest); - } -} - -void detect_guest_activity(struct zoran *zr) -{ - int timeout, i, j, res, guest[8], guest0[8], change[8][3]; - ktime_t t0, t1; - - /* do not print random data */ - guest[0] = 0; - guest0[0] = 0; - - dump_guests(zr); - pci_info(zr->pci_dev, "Detecting guests activity, please wait...\n"); - for (i = 1; i < 8; i++) /* Don't read jpeg codec here */ - guest0[i] = guest[i] = post_office_read(zr, i, 0); - - timeout = 0; - j = 0; - t0 = ktime_get(); - while (timeout < 10000) { - udelay(10); - timeout++; - for (i = 1; (i < 8) && (j < 8); i++) { - res = post_office_read(zr, i, 0); - if (res != guest[i]) { - t1 = ktime_get(); - change[j][0] = ktime_to_us(ktime_sub(t1, t0)); - t0 = t1; - change[j][1] = i; - change[j][2] = res; - j++; - guest[i] = res; - } - } - if (j >= 8) - break; - } - - pci_info(zr->pci_dev, "Guests: %*ph\n", 8, guest0); - - if (j == 0) { - pci_info(zr->pci_dev, "No activity detected.\n"); - return; - } - for (i = 0; i < j; i++) - pci_info(zr->pci_dev, "%6d: %d => 0x%02x\n", change[i][0], change[i][1], change[i][2]); -} - -/* * JPEG Codec access */ diff --git a/drivers/staging/media/zoran/zoran_device.h b/drivers/staging/media/zoran/zoran_device.h index 24be19a61b6d..6c5d70238228 100644 --- a/drivers/staging/media/zoran/zoran_device.h +++ b/drivers/staging/media/zoran/zoran_device.h @@ -20,8 +20,6 @@ extern int post_office_wait(struct zoran *zr); extern int post_office_write(struct zoran *zr, unsigned int guest, unsigned int reg, unsigned int value); extern int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg); -extern void detect_guest_activity(struct zoran *zr); - extern void jpeg_codec_sleep(struct zoran *zr, int sleep); extern int jpeg_codec_reset(struct zoran *zr); diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index e8902f824d6c..46382e43f1bf 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -678,12 +678,14 @@ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selectio sel->r.height = zr->jpg_settings.img_height; break; case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.top = sel->r.left = 0; + sel->r.top = 0; + sel->r.left = 0; sel->r.width = BUZ_MIN_WIDTH; sel->r.height = BUZ_MIN_HEIGHT; break; case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.top = sel->r.left = 0; + sel->r.top = 0; + sel->r.left = 0; sel->r.width = BUZ_MAX_WIDTH; sel->r.height = BUZ_MAX_HEIGHT; break; diff --git a/drivers/staging/media/zoran/zr36016.c b/drivers/staging/media/zoran/zr36016.c index 2d7dc7abde79..9b350a885879 100644 --- a/drivers/staging/media/zoran/zr36016.c +++ b/drivers/staging/media/zoran/zr36016.c @@ -361,7 +361,8 @@ static int zr36016_setup(struct videocodec *codec) return -ENOSPC; } //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36016), GFP_KERNEL); + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + codec->data = ptr; if (!ptr) return -ENOMEM; diff --git a/drivers/staging/media/zoran/zr36050.c b/drivers/staging/media/zoran/zr36050.c index 2826f4e5d37b..c62af27f2683 100644 --- a/drivers/staging/media/zoran/zr36050.c +++ b/drivers/staging/media/zoran/zr36050.c @@ -16,7 +16,7 @@ #include <linux/wait.h> /* I/O commands, error codes */ -#include <asm/io.h> +#include <linux/io.h> /* headerfile of this module */ #include "zr36050.h" @@ -754,7 +754,8 @@ static int zr36050_setup(struct videocodec *codec) return -ENOSPC; } //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36050), GFP_KERNEL); + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + codec->data = ptr; if (!ptr) return -ENOMEM; diff --git a/drivers/staging/media/zoran/zr36057.h b/drivers/staging/media/zoran/zr36057.h index 71b651add35a..a2a75fd9f535 100644 --- a/drivers/staging/media/zoran/zr36057.h +++ b/drivers/staging/media/zoran/zr36057.h @@ -30,13 +30,13 @@ #define ZR36057_VFESPFR_HOR_DCM 14 #define ZR36057_VFESPFR_VER_DCM 8 #define ZR36057_VFESPFR_DISP_MODE 6 -#define ZR36057_VFESPFR_YUV422 (0<<3) -#define ZR36057_VFESPFR_RGB888 (1<<3) -#define ZR36057_VFESPFR_RGB565 (2<<3) -#define ZR36057_VFESPFR_RGB555 (3<<3) -#define ZR36057_VFESPFR_ERR_DIF (1<<2) -#define ZR36057_VFESPFR_PACK24 (1<<1) -#define ZR36057_VFESPFR_LITTLE_ENDIAN (1<<0) +#define ZR36057_VFESPFR_YUV422 (0 << 3) +#define ZR36057_VFESPFR_RGB888 (1 << 3) +#define ZR36057_VFESPFR_RGB565 (2 << 3) +#define ZR36057_VFESPFR_RGB555 (3 << 3) +#define ZR36057_VFESPFR_ERR_DIF (1 << 2) +#define ZR36057_VFESPFR_PACK24 (1 << 1) +#define ZR36057_VFESPFR_LITTLE_ENDIAN (1 << 0) #define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ diff --git a/drivers/staging/media/zoran/zr36060.c b/drivers/staging/media/zoran/zr36060.c index 4f9eb9ff2c42..1c3af11b5f24 100644 --- a/drivers/staging/media/zoran/zr36060.c +++ b/drivers/staging/media/zoran/zr36060.c @@ -790,7 +790,8 @@ static int zr36060_setup(struct videocodec *codec) return -ENOSPC; } //mem structure init - codec->data = ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + codec->data = ptr; if (!ptr) return -ENOMEM; |