From 8b6faacd759933841c531c662c7eaa3046676fcc Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Mon, 1 Oct 2012 08:52:48 -0300 Subject: [media] media: davinci: vpfe: fix build error recent patch with commit id 4f996594ceaf6c3f9bc42b40c40b0f7f87b79c86 which makes vidioc_s_crop const, was causing a following build error. vpfe_capture.c: In function 'vpfe_s_crop': vpfe_capture.c:1695: error: assignment of read-only location '*crop' vpfe_capture.c:1706: warning: passing argument 1 of 'ccdc_dev->hw_ops.set_image_window' discards qualifiers from pointer target type vpfe_capture.c:1706: note: expected 'struct v4l2_rect *' but argument is of type 'const struct v4l2_rect *' make[4]: *** [drivers/media/platform/davinci/vpfe_capture.o] Error 1 Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 48052cb..8be492c 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1669,6 +1669,7 @@ static int vpfe_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) { struct vpfe_device *vpfe_dev = video_drvdata(file); + struct v4l2_rect rect = crop->c; int ret = 0; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); @@ -1684,7 +1685,7 @@ static int vpfe_s_crop(struct file *file, void *priv, if (ret) return ret; - if (crop->c.top < 0 || crop->c.left < 0) { + if (rect.top < 0 || rect.left < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "doesn't support negative values for top & left\n"); ret = -EINVAL; @@ -1692,26 +1693,26 @@ static int vpfe_s_crop(struct file *file, void *priv, } /* adjust the width to 16 pixel boundary */ - crop->c.width = ((crop->c.width + 15) & ~0xf); + rect.width = ((rect.width + 15) & ~0xf); /* make sure parameters are valid */ - if ((crop->c.left + crop->c.width > + if ((rect.left + rect.width > vpfe_dev->std_info.active_pixels) || - (crop->c.top + crop->c.height > + (rect.top + rect.height > vpfe_dev->std_info.active_lines)) { v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); ret = -EINVAL; goto unlock_out; } - ccdc_dev->hw_ops.set_image_window(&crop->c); - vpfe_dev->fmt.fmt.pix.width = crop->c.width; - vpfe_dev->fmt.fmt.pix.height = crop->c.height; + ccdc_dev->hw_ops.set_image_window(&rect); + vpfe_dev->fmt.fmt.pix.width = rect.width; + vpfe_dev->fmt.fmt.pix.height = rect.height; vpfe_dev->fmt.fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); vpfe_dev->fmt.fmt.pix.sizeimage = vpfe_dev->fmt.fmt.pix.bytesperline * vpfe_dev->fmt.fmt.pix.height; - vpfe_dev->crop = crop->c; + vpfe_dev->crop = rect; unlock_out: mutex_unlock(&vpfe_dev->lock); return ret; -- cgit v0.10.2 From 182b967e1119d22889e334c8f1c1b75df41f9165 Mon Sep 17 00:00:00 2001 From: Hans-Frieder Vogt Date: Wed, 3 Oct 2012 05:25:40 -0300 Subject: [media] af9033: prevent unintended underflow As spotted by Dan Carpenter (thanks!), we have improperly used an unsigned variable in a calculation that may result in a negative number. This may cause an unintended underflow if the interface frequency of the tuner is > approx. 40MHz. This patch should resolve the issue, following an approach similar to what is used in af9013.c. [crope@iki.fi: add Reported-by] Reported-by: Dan Carpenter Signed-off-by: Hans-Frieder Vogt Reviewed-by: Antti Palosaari Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 8162d93..464ad87 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -408,7 +408,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) { struct af9033_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i, spec_inv; + int ret, i, spec_inv, sampling_freq; u8 tmp, buf[3], bandwidth_reg_val; u32 if_frequency, freq_cw, adc_freq; @@ -465,18 +465,20 @@ static int af9033_set_frontend(struct dvb_frontend *fe) else if_frequency = 0; - while (if_frequency > (adc_freq / 2)) - if_frequency -= adc_freq; + sampling_freq = if_frequency; - if (if_frequency >= 0) + while (sampling_freq > (adc_freq / 2)) + sampling_freq -= adc_freq; + + if (sampling_freq >= 0) spec_inv *= -1; else - if_frequency *= -1; + sampling_freq *= -1; - freq_cw = af9033_div(state, if_frequency, adc_freq, 23ul); + freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul); if (spec_inv == -1) - freq_cw *= -1; + freq_cw = 0x800000 - freq_cw; /* get adc multiplies */ ret = af9033_rd_reg(state, 0x800045, &tmp); -- cgit v0.10.2 From 368640827c0be2582d836cd74ae2cff03e6bfc02 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 1 Oct 2012 11:39:46 -0300 Subject: [media] dm644x: replace the obsolete preset API by the timings API This patch replaces the preset API by the timings API, and appropriate changes in board file. Signed-off-by: Hans Verkuil Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index d34ed55..3baf56d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -620,7 +621,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "ntsc", .timings_type = VPBE_ENC_STD, - .timings = {V4L2_STD_525_60}, + .std_id = V4L2_STD_525_60, .interlaced = 1, .xres = 720, .yres = 480, @@ -632,7 +633,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "pal", .timings_type = VPBE_ENC_STD, - .timings = {V4L2_STD_625_50}, + .std_id = V4L2_STD_625_50, .interlaced = 1, .xres = 720, .yres = 576, @@ -647,8 +648,8 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { { .name = "480p59_94", - .timings_type = VPBE_ENC_DV_PRESET, - .timings = {V4L2_DV_480P59_94}, + .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, .interlaced = 0, .xres = 720, .yres = 480, @@ -659,8 +660,8 @@ static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { }, { .name = "576p50", - .timings_type = VPBE_ENC_DV_PRESET, - .timings = {V4L2_DV_576P50}, + .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X576P50, .interlaced = 0, .xres = 720, .yres = 576, @@ -698,7 +699,7 @@ static struct vpbe_output dm644xevm_vpbe_outputs[] = { .index = 1, .name = "Component", .type = V4L2_OUTPUT_TYPE_ANALOG, - .capabilities = V4L2_OUT_CAP_PRESETS, + .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS, }, .subdev_name = VPBE_VENC_SUBDEV_NAME, .default_mode = "480p59_94", diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index c8b8666..79d2880 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -701,7 +701,7 @@ static struct resource dm644x_venc_resources[] = { #define DM644X_VPSS_DACCLKEN BIT(4) static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, - unsigned int mode) + unsigned int pclock) { int ret = 0; u32 v = DM644X_VPSS_VENCLKEN; @@ -711,27 +711,18 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); break; - case VPBE_ENC_DV_PRESET: - switch (mode) { - case V4L2_DV_480P59_94: - case V4L2_DV_576P50: + case VPBE_ENC_CUSTOM_TIMINGS: + if (pclock <= 27000000) { v |= DM644X_VPSS_MUXSEL_PLL2_MODE | DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); - break; - case V4L2_DV_720P60: - case V4L2_DV_1080I60: - case V4L2_DV_1080P30: + } else { /* * For HD, use external clock source since * HD requires higher clock rate */ v |= DM644X_VPSS_MUXSEL_VPBECLK_MODE; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); - break; - default: - ret = -EINVAL; - break; } break; default: diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index c4a82a1..d03f452 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -174,26 +174,6 @@ static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, return 0; } -static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, - unsigned int dv_preset) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; - int i; - - for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if ((var.timings_type & VPBE_ENC_DV_PRESET) && - (var.timings.dv_preset == dv_preset)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - /* Get std by std id */ static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) @@ -206,7 +186,7 @@ static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { var = cfg->outputs[curr_output].modes[i]; if ((var.timings_type & VPBE_ENC_STD) && - (var.timings.std_id & std_id)) { + (var.std_id & std_id)) { vpbe_dev->current_timings = var; return 0; } @@ -344,38 +324,42 @@ static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) } /** - * vpbe_s_dv_preset - Set the given preset timings in the encoder + * vpbe_s_dv_timings - Set the given preset timings in the encoder * - * Sets the preset if supported by the current encoder. Return the status. + * Sets the timings if supported by the current encoder. Return the status. * 0 - success & -EINVAL on error */ -static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset) +static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &cfg->outputs[out_index]; int sd_index = vpbe_dev->current_sd_index; - int ret; + int ret, i; if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_PRESETS)) + V4L2_OUT_CAP_CUSTOM_TIMINGS)) return -EINVAL; - ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); - - if (ret) - return ret; - + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS && + !memcmp(&output->modes[i].dv_timings, + dv_timings, sizeof(*dv_timings))) + break; + } + if (i >= output->num_modes) + return -EINVAL; + vpbe_dev->current_timings = output->modes[i]; mutex_lock(&vpbe_dev->lock); - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_dv_preset, dv_preset); + s_dv_timings, dv_timings); if (!ret && (vpbe_dev->amp != NULL)) { /* Call amplifier subdevice */ ret = v4l2_subdev_call(vpbe_dev->amp, video, - s_dv_preset, dv_preset); + s_dv_timings, dv_timings); } /* set the lcd controller output for the given mode */ if (!ret) { @@ -392,17 +376,17 @@ static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, } /** - * vpbe_g_dv_preset - Get the preset in the current encoder + * vpbe_g_dv_timings - Get the timings in the current encoder * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ -static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset) +static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings) { if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_PRESET) { - dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + VPBE_ENC_CUSTOM_TIMINGS) { + *dv_timings = vpbe_dev->current_timings.dv_timings; return 0; } @@ -410,13 +394,13 @@ static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, } /** - * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * vpbe_enum_dv_timings - Enumerate the dv timings in the current encoder * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ -static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, - struct v4l2_dv_enum_preset *preset_info) +static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_enum_dv_timings *timings) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; @@ -424,12 +408,12 @@ static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, int j = 0; int i; - if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + if (!(output->output.capabilities & V4L2_OUT_CAP_CUSTOM_TIMINGS)) return -EINVAL; for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { - if (j == preset_info->index) + if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS) { + if (j == timings->index) break; j++; } @@ -437,9 +421,8 @@ static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, if (i == output->num_modes) return -EINVAL; - - return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, - preset_info); + timings->timings = output->modes[i].dv_timings; + return 0; } /** @@ -489,10 +472,10 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) */ static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) { - struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + struct vpbe_enc_mode_info *cur_timings = &vpbe_dev->current_timings; - if (cur_timings.timings_type & VPBE_ENC_STD) { - *std_id = cur_timings.timings.std_id; + if (cur_timings->timings_type & VPBE_ENC_STD) { + *std_id = cur_timings->std_id; return 0; } @@ -511,7 +494,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, { struct vpbe_enc_mode_info *preset_mode = NULL; struct vpbe_config *cfg = vpbe_dev->cfg; - struct v4l2_dv_preset dv_preset; + struct v4l2_dv_timings dv_timings; struct osd_state *osd_device; int out_index = vpbe_dev->current_out_index; int ret = 0; @@ -530,11 +513,12 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, */ if (preset_mode->timings_type & VPBE_ENC_STD) return vpbe_s_std(vpbe_dev, - &preset_mode->timings.std_id); - if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { - dv_preset.preset = - preset_mode->timings.dv_preset; - return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + &preset_mode->std_id); + if (preset_mode->timings_type & + VPBE_ENC_CUSTOM_TIMINGS) { + dv_timings = + preset_mode->dv_timings; + return vpbe_s_dv_timings(vpbe_dev, &dv_timings); } } } @@ -810,9 +794,9 @@ static struct vpbe_device_ops vpbe_dev_ops = { .enum_outputs = vpbe_enum_outputs, .set_output = vpbe_set_output, .get_output = vpbe_get_output, - .s_dv_preset = vpbe_s_dv_preset, - .g_dv_preset = vpbe_g_dv_preset, - .enum_dv_presets = vpbe_enum_dv_presets, + .s_dv_timings = vpbe_s_dv_timings, + .g_dv_timings = vpbe_g_dv_timings, + .enum_dv_timings = vpbe_enum_dv_timings, .s_std = vpbe_s_std, .g_std = vpbe_g_std, .initialize = vpbe_initialize, diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 239f37b..1b238fe 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -393,7 +393,7 @@ vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, int h_scale; int v_scale; - v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; + v4l2_std_id standard_id = vpbe_dev->current_timings.std_id; /* * Application initially set the image format. Current display @@ -943,7 +943,7 @@ static int vpbe_display_g_std(struct file *file, void *priv, /* Get the standard from the current encoder */ if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { - *std_id = vpbe_dev->current_timings.timings.std_id; + *std_id = vpbe_dev->current_timings.std_id; return 0; } @@ -1029,29 +1029,29 @@ static int vpbe_display_g_output(struct file *file, void *priv, } /** - * vpbe_display_enum_dv_presets - Enumerate the dv presets + * vpbe_display_enum_dv_timings - Enumerate the dv timings * - * enum the preset in the current encoder. Return the status. 0 - success + * enum the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_enum_dv_presets(struct file *file, void *priv, - struct v4l2_dv_enum_preset *preset) +vpbe_display_enum_dv_timings(struct file *file, void *priv, + struct v4l2_enum_dv_timings *timings) { struct vpbe_fh *fh = priv; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n"); /* Enumerate outputs */ - if (NULL == vpbe_dev->ops.enum_dv_presets) + if (NULL == vpbe_dev->ops.enum_dv_timings) return -EINVAL; - ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); + ret = vpbe_dev->ops.enum_dv_timings(vpbe_dev, timings); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to enumerate dv presets info\n"); + "Failed to enumerate dv timings info\n"); return -EINVAL; } @@ -1059,21 +1059,21 @@ vpbe_display_enum_dv_presets(struct file *file, void *priv, } /** - * vpbe_display_s_dv_preset - Set the dv presets + * vpbe_display_s_dv_timings - Set the dv timings * - * Set the preset in the current encoder. Return the status. 0 - success + * Set the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_s_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) +vpbe_display_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) { struct vpbe_fh *fh = priv; struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_TIMINGS\n"); /* If streaming is started, return error */ @@ -1083,13 +1083,13 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /* Set the given standard in the encoder */ - if (!vpbe_dev->ops.s_dv_preset) + if (!vpbe_dev->ops.s_dv_timings) return -EINVAL; - ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); + ret = vpbe_dev->ops.s_dv_timings(vpbe_dev, timings); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set the dv presets info\n"); + "Failed to set the dv timings info\n"); return -EINVAL; } /* set the current norm to zero to be consistent. If STD is used @@ -1101,26 +1101,25 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /** - * vpbe_display_g_dv_preset - Set the dv presets + * vpbe_display_g_dv_timings - Set the dv timings * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_g_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *dv_preset) +vpbe_display_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *dv_timings) { struct vpbe_fh *fh = priv; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_TIMINGS\n"); /* Get the given standard in the encoder */ if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_PRESET) { - dv_preset->preset = - vpbe_dev->current_timings.timings.dv_preset; + VPBE_ENC_CUSTOM_TIMINGS) { + *dv_timings = vpbe_dev->current_timings.dv_timings; } else { return -EINVAL; } @@ -1572,9 +1571,9 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { .vidioc_enum_output = vpbe_display_enum_output, .vidioc_s_output = vpbe_display_s_output, .vidioc_g_output = vpbe_display_g_output, - .vidioc_s_dv_preset = vpbe_display_s_dv_preset, - .vidioc_g_dv_preset = vpbe_display_g_dv_preset, - .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, + .vidioc_s_dv_timings = vpbe_display_s_dv_timings, + .vidioc_g_dv_timings = vpbe_display_g_dv_timings, + .vidioc_enum_dv_timings = vpbe_display_enum_dv_timings, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vpbe_display_g_register, .vidioc_s_register = vpbe_display_s_register, @@ -1639,8 +1638,7 @@ static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev, VPBE_ENC_STD) { vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); vbd->current_norm = - disp_dev->vpbe_dev-> - current_timings.timings.std_id; + disp_dev->vpbe_dev->current_timings.std_id; } else vbd->current_norm = 0; diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index b21ecc8..86d47c3 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -298,7 +298,7 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -345,7 +345,7 @@ static int venc_set_576p50(struct v4l2_subdev *sd) (pdata->venc_type != VPBE_VERSION_2)) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -385,7 +385,7 @@ static int venc_set_720p60_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -413,7 +413,7 @@ static int venc_set_1080i30_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080P30) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -446,26 +446,27 @@ static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) return -EINVAL; } -static int venc_s_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *dv_preset) +static int venc_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) { struct venc_state *venc = to_state(sd); + u32 height = dv_timings->bt.height; int ret; - v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); + v4l2_dbg(debug, 1, sd, "venc_s_dv_timings\n"); - if (dv_preset->preset == V4L2_DV_576P50) + if (height == 576) return venc_set_576p50(sd); - else if (dv_preset->preset == V4L2_DV_480P59_94) + else if (height == 480) return venc_set_480p59_94(sd); - else if ((dv_preset->preset == V4L2_DV_720P60) && + else if ((height == 720) && (venc->pdata->venc_type == VPBE_VERSION_2)) { /* TBD setup internal 720p mode here */ ret = venc_set_720p60_internal(sd); /* for DM365 VPBE, there is DAC inside */ vdaccfg_write(sd, VDAC_CONFIG_HD_V2); return ret; - } else if ((dv_preset->preset == V4L2_DV_1080I30) && + } else if ((height == 1080) && (venc->pdata->venc_type == VPBE_VERSION_2)) { /* TBD setup internal 1080i mode here */ ret = venc_set_1080i30_internal(sd); @@ -518,7 +519,7 @@ static const struct v4l2_subdev_core_ops venc_core_ops = { static const struct v4l2_subdev_video_ops venc_video_ops = { .s_routing = venc_s_routing, .s_std_output = venc_s_std_output, - .s_dv_preset = venc_s_dv_preset, + .s_dv_timings = venc_s_dv_timings, }; static const struct v4l2_subdev_ops venc_ops = { diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index 8bc1b3c..a7ca488 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -35,7 +35,7 @@ struct osd_config_info { struct vpbe_output { struct v4l2_output output; /* - * If output capabilities include dv_preset, list supported presets + * If output capabilities include dv_timings, list supported timings * below */ char *subdev_name; @@ -120,16 +120,16 @@ struct vpbe_device_ops { unsigned int (*get_output)(struct vpbe_device *vpbe_dev); /* Set DV preset at current output */ - int (*s_dv_preset)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset); + int (*s_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings); /* Get DV presets supported at the output */ - int (*g_dv_preset)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset); + int (*g_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings); /* Enumerate the DV Presets supported at the output */ - int (*enum_dv_presets)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_enum_preset *preset_info); + int (*enum_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_enum_dv_timings *timings_info); /* Set std at the output */ int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h index 727f551..9b85396 100644 --- a/include/media/davinci/vpbe_types.h +++ b/include/media/davinci/vpbe_types.h @@ -32,11 +32,6 @@ enum vpbe_enc_timings_type { VPBE_ENC_TIMINGS_INVALID = 0x8, }; -union vpbe_timings { - v4l2_std_id std_id; - unsigned int dv_preset; -}; - /* * struct vpbe_enc_mode_info * @name: ptr to name string of the standard, "NTSC", "PAL" etc @@ -73,7 +68,8 @@ union vpbe_timings { struct vpbe_enc_mode_info { unsigned char *name; enum vpbe_enc_timings_type timings_type; - union vpbe_timings timings; + v4l2_std_id std_id; + struct v4l2_dv_timings dv_timings; unsigned int interlaced; unsigned int xres; unsigned int yres; diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h index 6b57334..cc78c2e 100644 --- a/include/media/davinci/vpbe_venc.h +++ b/include/media/davinci/vpbe_venc.h @@ -32,7 +32,7 @@ struct venc_platform_data { int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type, int field); int (*setup_clock)(enum vpbe_enc_timings_type type, - unsigned int mode); + unsigned int pixclock); int (*setup_if_config)(enum v4l2_mbus_pixelcode pixcode); /* Number of LCD outputs supported */ int num_lcd_outputs; -- cgit v0.10.2 From ad7dcb334a0dbba9ac611d43c4e0ff7973eaa1cf Mon Sep 17 00:00:00 2001 From: Manjunath Hadli Date: Mon, 1 Oct 2012 11:46:35 -0300 Subject: [media] ths7303: enable THS7303 for HD modes add filter settings for high def modes like 1080i, 1080p,720p and others and implementing dv_timings. Signed-off-by: Manjunath Hadli Signed-off-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index e5c0eed..c31cc04 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -28,6 +28,18 @@ #include #include +#define THS7303_CHANNEL_1 1 +#define THS7303_CHANNEL_2 2 +#define THS7303_CHANNEL_3 3 + +enum ths7303_filter_mode { + THS7303_FILTER_MODE_480I_576I, + THS7303_FILTER_MODE_480P_576P, + THS7303_FILTER_MODE_720P_1080I, + THS7303_FILTER_MODE_1080P, + THS7303_FILTER_MODE_DISABLE +}; + MODULE_DESCRIPTION("TI THS7303 video amplifier driver"); MODULE_AUTHOR("Chaithrika U S"); MODULE_LICENSE("GPL"); @@ -37,35 +49,96 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level 0-1"); /* following function is used to set ths7303 */ -static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std) +int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode) { + u8 input_bias_chroma = 3; + u8 input_bias_luma = 3; + int disable = 0; int err = 0; - u8 val; - struct i2c_client *client; + u8 val = 0; + u8 temp; - client = v4l2_get_subdevdata(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { - val = 0x02; - v4l2_dbg(1, debug, sd, "setting value for SDTV format\n"); - } else { - val = 0x00; - v4l2_dbg(1, debug, sd, "disabling all channels\n"); + if (!client) + return -EINVAL; + + switch (mode) { + case THS7303_FILTER_MODE_1080P: + val = (3 << 6); + val |= (3 << 3); + break; + case THS7303_FILTER_MODE_720P_1080I: + val = (2 << 6); + val |= (2 << 3); + break; + case THS7303_FILTER_MODE_480P_576P: + val = (1 << 6); + val |= (1 << 3); + break; + case THS7303_FILTER_MODE_480I_576I: + break; + case THS7303_FILTER_MODE_DISABLE: + pr_info("mode disabled\n"); + /* disable all channels */ + disable = 1; + default: + /* disable all channels */ + disable = 1; } + /* Setup channel 2 - Luma - Green */ + temp = val; + if (!disable) + val |= input_bias_luma; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_2, val); + if (err) + goto out; - err |= i2c_smbus_write_byte_data(client, 0x01, val); - err |= i2c_smbus_write_byte_data(client, 0x02, val); - err |= i2c_smbus_write_byte_data(client, 0x03, val); + /* setup two chroma channels */ + if (!disable) + temp |= input_bias_chroma; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_1, temp); if (err) - v4l2_err(sd, "write failed\n"); + goto out; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_3, temp); + if (err) + goto out; + return err; +out: + pr_info("write byte data failed\n"); return err; } static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) { - return ths7303_setvalue(sd, norm); + if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) + return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I); + else + return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); +} + +/* for setting filter for HD output */ +static int ths7303_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) +{ + u32 height = dv_timings->bt.height; + int interlaced = dv_timings->bt.interlaced; + int res = 0; + + if (height == 1080 && !interlaced) + res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P); + else if ((height == 720 && !interlaced) || + (height == 1080 && interlaced)) + res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I); + else if ((height == 480 || height == 576) && !interlaced) + res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P); + else + /* disable all channels */ + res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); + + return res; } static int ths7303_g_chip_ident(struct v4l2_subdev *sd, @@ -78,6 +151,7 @@ static int ths7303_g_chip_ident(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops ths7303_video_ops = { .s_std_output = ths7303_s_std_output, + .s_dv_timings = ths7303_s_dv_timings, }; static const struct v4l2_subdev_core_ops ths7303_core_ops = { @@ -107,7 +181,7 @@ static int ths7303_probe(struct i2c_client *client, v4l2_i2c_subdev_init(sd, client, &ths7303_ops); - return ths7303_setvalue(sd, std_id); + return ths7303_s_std_output(sd, std_id); } static int ths7303_remove(struct i2c_client *client) -- cgit v0.10.2 From fabc4e948b0ebe128ec54687bae01f216e34bb41 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 3 Oct 2012 02:13:28 -0300 Subject: [media] media: davinci: vpbe: fix build warning recent patch with commit id 4f996594ceaf6c3f9bc42b40c40b0f7f87b79c86 which makes vidioc_s_crop const, was causing a following build warning, vpbe_display.c: In function 'vpbe_display_s_crop': vpbe_display.c:640: warning: initialization discards qualifiers from pointer target type This patch fixes the above build warning. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 1b238fe..161c776 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -637,7 +637,7 @@ static int vpbe_display_s_crop(struct file *file, void *priv, struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; struct osd_layer_config *cfg = &layer->layer_info.config; struct osd_state *osd_device = disp_dev->osd_device; - struct v4l2_rect *rect = &crop->c; + struct v4l2_rect rect = crop->c; int ret; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, @@ -648,21 +648,21 @@ static int vpbe_display_s_crop(struct file *file, void *priv, return -EINVAL; } - if (rect->top < 0) - rect->top = 0; - if (rect->left < 0) - rect->left = 0; + if (rect.top < 0) + rect.top = 0; + if (rect.left < 0) + rect.left = 0; - vpbe_disp_check_window_params(disp_dev, rect); + vpbe_disp_check_window_params(disp_dev, &rect); osd_device->ops.get_layer_config(osd_device, layer->layer_info.id, cfg); vpbe_disp_calculate_scale_factor(disp_dev, layer, - rect->width, - rect->height); - vpbe_disp_adj_position(disp_dev, layer, rect->top, - rect->left); + rect.width, + rect.height); + vpbe_disp_adj_position(disp_dev, layer, rect.top, + rect.left); ret = osd_device->ops.set_layer_config(osd_device, layer->layer_info.id, cfg); if (ret < 0) { -- cgit v0.10.2 From e32087bcc4daa29fd30cf7742ef9b522625a1690 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 3 Oct 2012 02:25:42 -0300 Subject: [media] davinci: vpbe: replace V4L2_OUT_CAP_CUSTOM_TIMINGS with V4L2_OUT_CAP_DV_TIMINGS This patch replaces V4L2_OUT_CAP_CUSTOM_TIMINGS macro with V4L2_OUT_CAP_DV_TIMINGS. As V4L2_OUT_CAP_CUSTOM_TIMINGS is being phased out. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 3baf56d..a79dc1e 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -699,7 +699,7 @@ static struct vpbe_output dm644xevm_vpbe_outputs[] = { .index = 1, .name = "Component", .type = V4L2_OUTPUT_TYPE_ANALOG, - .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS, + .capabilities = V4L2_OUT_CAP_DV_TIMINGS, }, .subdev_name = VPBE_VENC_SUBDEV_NAME, .default_mode = "480p59_94", diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index d03f452..9b623bc 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -340,7 +340,7 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_CUSTOM_TIMINGS)) + V4L2_OUT_CAP_DV_TIMINGS)) return -EINVAL; for (i = 0; i < output->num_modes; i++) { @@ -408,7 +408,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, int j = 0; int i; - if (!(output->output.capabilities & V4L2_OUT_CAP_CUSTOM_TIMINGS)) + if (!(output->output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)) return -EINVAL; for (i = 0; i < output->num_modes; i++) { -- cgit v0.10.2 From 1309b33683addabe4700e0bcce422de70f6dc4c8 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 1 Oct 2012 04:26:15 -0300 Subject: [media] technisat-usb2: add a MODULE_DEVICE_TABLE for udev autoload This patch adds a module-device-table-entry to the technisat-usb2-driver which will help udev to on-demand load the driver. This was obviously forgotten during initial commit. Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index acefaa8..7a8c8c1 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -677,6 +677,7 @@ static struct usb_device_id technisat_usb2_id_table[] = { { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, { 0 } /* Terminating entry */ }; +MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table); /* device description */ static struct dvb_usb_device_properties technisat_usb2_devices = { -- cgit v0.10.2 From 2c4c03f3819dc6c0e294d47558ed8c07cd3fb15e Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Tue, 2 Oct 2012 20:55:02 -0300 Subject: [media] s5p-jpeg: use clk_prepare_enable and clk_disable_unprepare Convert clk_enable/clk_disable to clk_prepare_enable/clk_disable_unprepare calls as required by common clock framework. Signed-off-by: Thomas Abraham Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 394775a..17983c4 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1353,7 +1353,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) return ret; } dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); - clk_enable(jpeg->clk); + clk_prepare_enable(jpeg->clk); /* v4l2 device */ ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); @@ -1460,7 +1460,7 @@ device_register_rollback: v4l2_device_unregister(&jpeg->v4l2_dev); clk_get_rollback: - clk_disable(jpeg->clk); + clk_disable_unprepare(jpeg->clk); clk_put(jpeg->clk); return ret; @@ -1480,7 +1480,7 @@ static int s5p_jpeg_remove(struct platform_device *pdev) v4l2_m2m_release(jpeg->m2m_dev); v4l2_device_unregister(&jpeg->v4l2_dev); - clk_disable(jpeg->clk); + clk_disable_unprepare(jpeg->clk); clk_put(jpeg->clk); return 0; -- cgit v0.10.2 From 21ec9c97e4ee568aad169327256c768947e57c1e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Sep 2012 05:10:48 -0300 Subject: [media] s5p-g2d: fix compiler warning drivers/media/platform/s5p-g2d/g2d.c:535:2: warning: passing argument 3 of 'vidioc_try_crop' discards 'const' qualifier from pointer target type [enabled by default] drivers/media/platform/s5p-g2d/g2d.c:510:12: note: expected 'struct v4l2_crop *' but argument is of type 'const struct v4l2_crop *' This is fall-out from this commit: commit 4f996594ceaf6c3f9bc42b40c40b0f7f87b79c86 Author: Hans Verkuil [media] v4l2: make vidioc_s_crop const Signed-off-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 1e3b9dd..1bfbc32 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -507,7 +507,7 @@ static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr) return 0; } -static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr) +static int vidioc_try_crop(struct file *file, void *prv, const struct v4l2_crop *cr) { struct g2d_ctx *ctx = prv; struct g2d_dev *dev = ctx->dev; -- cgit v0.10.2 From 24c54f7757659cdab9089dbd416c58f0da1557b0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Sep 2012 05:10:48 -0300 Subject: [media] s5p-fimc: fix compiler warning drivers/media/platform/s5p-fimc/fimc-m2m.c:561:2: warning: passing argument 2 of 'fimc_m2m_try_crop' discards 'const' qualifier from pointer target type [enabled by default] drivers/media/platform/s5p-fimc/fimc-m2m.c:502:12: note: expected 'struct v4l2_crop *' but argument is of type 'const struct v4l2_crop *' This is fall-out from this commit: commit 4f996594ceaf6c3f9bc42b40c40b0f7f87b79c86 Author: Hans Verkuil [media] v4l2: make vidioc_s_crop const Signed-off-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index 6b71d95..4500e44 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -551,30 +551,31 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) return 0; } -static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr) +static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_crop cr = *crop; struct fimc_frame *f; int ret; - ret = fimc_m2m_try_crop(ctx, cr); + ret = fimc_m2m_try_crop(ctx, &cr); if (ret) return ret; - f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? + f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->s_frame : &ctx->d_frame; /* Check to see if scaling ratio is within supported range */ if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = fimc_check_scaler_ratio(ctx, cr->c.width, - cr->c.height, ctx->d_frame.width, + if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = fimc_check_scaler_ratio(ctx, cr.c.width, + cr.c.height, ctx->d_frame.width, ctx->d_frame.height, ctx->rotation); } else { ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, - ctx->s_frame.height, cr->c.width, - cr->c.height, ctx->rotation); + ctx->s_frame.height, cr.c.width, + cr.c.height, ctx->rotation); } if (ret) { v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); @@ -582,10 +583,10 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop * } } - f->offs_h = cr->c.left; - f->offs_v = cr->c.top; - f->width = cr->c.width; - f->height = cr->c.height; + f->offs_h = cr.c.left; + f->offs_v = cr.c.top; + f->width = cr.c.width; + f->height = cr.c.height; fimc_ctx_state_set(FIMC_PARAMS, ctx); -- cgit v0.10.2 From a375e1dfefdb951e0591394ac1796d88a712877f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 13 Sep 2012 13:08:19 -0300 Subject: [media] V4L: Add s_rx_buffer subdev video operation The s_rx_buffer callback allows the host to set buffer for a data being received by the subdev, e.g. non-image frame (meta) data. This callback can be implemented by subdevice like a MIPI CSI2 receiver, allowing the host driver to gather additional data into frame buffer passed to user space. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 2ecd737..abf1a0e 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -274,6 +274,10 @@ struct v4l2_subdev_audio_ops { s_mbus_config: set a certain mediabus configuration. This operation is added for compatibility with soc-camera drivers and should not be used by new software. + + s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev + can adjust @size to a lower value and must not write more data to the + buffer starting at @data than the original value of @size. */ struct v4l2_subdev_video_ops { int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); @@ -327,6 +331,8 @@ struct v4l2_subdev_video_ops { struct v4l2_mbus_config *cfg); int (*s_mbus_config)(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg); + int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, + unsigned int *size); }; /* -- cgit v0.10.2 From 291031192426bfc6ad4ab2eb9fa986025a926598 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 17 May 2012 14:33:30 -0300 Subject: [media] V4L: Add [get/set]_frame_desc subdev callbacks Add subdev callbacks for setting up parameters of the frame on media bus that are not exposed to user space directly. This is just an initial, mostly stub implementation. struct v4l2_mbus_frame_desc is intended to be extended with sub-structures specific to a particular hardware media bus. For now these new callbacks are used only to query or specify maximum size of a compressed or hybrid (container) media bus frame in octets. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index abf1a0e..b137a5e 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -21,6 +21,7 @@ #ifndef _V4L2_SUBDEV_H #define _V4L2_SUBDEV_H +#include #include #include #include @@ -45,6 +46,7 @@ struct v4l2_fh; struct v4l2_subdev; struct v4l2_subdev_fh; struct tuner_setup; +struct v4l2_mbus_frame_desc; /* decode_vbi_line */ struct v4l2_decode_vbi_line { @@ -226,6 +228,36 @@ struct v4l2_subdev_audio_ops { int (*s_stream)(struct v4l2_subdev *sd, int enable); }; +/* Indicates the @length field specifies maximum data length. */ +#define V4L2_MBUS_FRAME_DESC_FL_LEN_MAX (1U << 0) +/* Indicates user defined data format, i.e. non standard frame format. */ +#define V4L2_MBUS_FRAME_DESC_FL_BLOB (1U << 1) + +/** + * struct v4l2_mbus_frame_desc_entry - media bus frame description structure + * @flags: V4L2_MBUS_FRAME_DESC_FL_* flags + * @pixelcode: media bus pixel code, valid if FRAME_DESC_FL_BLOB is not set + * @length: number of octets per frame, valid for compressed or unspecified + * formats + */ +struct v4l2_mbus_frame_desc_entry { + u16 flags; + u32 pixelcode; + u32 length; +}; + +#define V4L2_FRAME_DESC_ENTRY_MAX 4 + +/** + * struct v4l2_mbus_frame_desc - media bus data frame description + * @entry: frame descriptors array + * @num_entries: number of entries in @entry array + */ +struct v4l2_mbus_frame_desc { + struct v4l2_mbus_frame_desc_entry entry[V4L2_FRAME_DESC_ENTRY_MAX]; + unsigned short num_entries; +}; + /* s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by video input devices. @@ -461,6 +493,12 @@ struct v4l2_subdev_ir_ops { struct v4l2_subdev_ir_parameters *params); }; +/** + * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations + * @get_frame_desc: get the current low level media bus frame parameters. + * @get_frame_desc: set the low level media bus frame parameters, @fd array + * may be adjusted by the subdev driver to device capabilities. + */ struct v4l2_subdev_pad_ops { int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code); @@ -489,6 +527,10 @@ struct v4l2_subdev_pad_ops { struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt); #endif /* CONFIG_MEDIA_CONTROLLER */ + int (*get_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd); + int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd); }; struct v4l2_subdev_ops { -- cgit v0.10.2 From d2642485d694027ad8c918844cee0e547cc11bcb Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 16 Feb 2012 14:23:54 -0300 Subject: [media] V4L: Add V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 media bus format This patch adds media bus pixel code for the interleaved JPEG/UYVY image format used by S5C73MX Samsung cameras. This interleaved image data is transferred on MIPI-CSI2 bus as User Defined Byte-based Data. It also defines an experimental vendor and device specific media bus formats section and adds related DocBook documentation. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index c6ae4c9..4fdf6b5 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2582,6 +2582,10 @@ ioctls. Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl. + + Vendor and device specific media bus pixel formats. + . + diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 49c532e..a0a9364 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -2565,5 +2565,49 @@ + +
+ Vendor and Device Specific Formats + + + Experimental + This is an experimental +interface and may change in the future. + + + This section lists complex data formats that are either vendor or + device specific. + + + The following table lists the existing vendor and device specific + formats. + + + Vendor and device specific formats + + + + + + + Identifier + Code + Comments + + + + + V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 + 0x5001 + + Interleaved raw UYVY and JPEG image format with embedded + meta-data used by Samsung S3C73MX camera sensors. + + + + +
+
+ diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h index 5ea7f75..7d64e0e 100644 --- a/include/linux/v4l2-mediabus.h +++ b/include/linux/v4l2-mediabus.h @@ -92,6 +92,11 @@ enum v4l2_mbus_pixelcode { /* JPEG compressed formats - next is 0x4002 */ V4L2_MBUS_FMT_JPEG_1X8 = 0x4001, + + /* Vendor specific formats - next is 0x5002 */ + + /* S5C73M3 sensor specific interleaved UYVY and JPEG */ + V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 = 0x5001, }; /** -- cgit v0.10.2 From c3010097a79fc741d27b07e068598fd9468ca41f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 3 Oct 2012 07:44:53 -0300 Subject: [media] V4L: Add V4L2_PIX_FMT_S5C_UYVY_JPG fourcc definition This patch adds definition of the Samsung S5C73M3 camera specific image format. V4L2_PIX_FMT_S5C_UYVY_JPG is a two-planar format, the first plane contains interleaved UYVY and JPEG data followed by meta-data. The second plane contains additional meta-data needed for extracting JPEG and UYVY data stream from the first plane. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 1ddbfab..fce1437 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -996,6 +996,34 @@ the other bits are set to 0. Old 6-bit greyscale format. Only the most significant 6 bits of each byte are used, the other bits are set to 0. + + V4L2_PIX_FMT_S5C_UYVY_JPG + 'S5CI' + Two-planar format used by Samsung S5C73MX cameras. The +first plane contains interleaved JPEG and UYVY image data, followed by meta data +in form of an array of offsets to the UYVY data blocks. The actual pointer array +follows immediately the interleaved JPEG/UYVY data, the number of entries in +this array equals the height of the UYVY image. Each entry is a 4-byte unsigned +integer in big endian order and it's an offset to a single pixel line of the +UYVY image. The first plane can start either with JPEG or UYVY data chunk. The +size of a single UYVY block equals the UYVY image's width multiplied by 2. The +size of a JPEG chunk depends on the image and can vary with each line. +The second plane, at an offset of 4084 bytes, contains a 4-byte offset to +the pointer array in the first plane. This offset is followed by a 4-byte value +indicating size of the pointer array. All numbers in the second plane are also +in big endian order. Remaining data in the second plane is undefined. The +information in the second plane allows to easily find location of the pointer +array, which can be different for each frame. The size of the pointer array is +constant for given UYVY image height. +In order to extract UYVY and JPEG frames an application can initially set +a data pointer to the start of first plane and then add an offset from the first +entry of the pointers table. Such a pointer indicates start of an UYVY image +pixel line. Whole UYVY line can be copied to a separate buffer. These steps +should be repeated for each line, i.e. the number of entries in the pointer +array. Anything what's in between the UYVY lines is JPEG data and should be +concatenated to form the JPEG stream. + + diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 61395ef..80977d6 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -437,6 +437,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ #define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ #define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ +#define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */ /* * F O R M A T E N U M E R A T I O N -- cgit v0.10.2 From 36fa80927638babe523dce14f3408f9fdefa86d3 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 21 Sep 2012 15:18:41 -0300 Subject: [media] s5p-csis: Add support for non-image data packets capture MIPI-CSI has internal memory mapped buffers for the frame embedded (non-image) data. There are two buffers, for even and odd frames which need to be saved after an interrupt is raised. The packet data buffers size is 4 KiB and there is no status register in the hardware where the actual non-image data size can be read from. Hence the driver copies whole packet data buffer into a buffer provided by the FIMC driver. This will form a separate plane in the user buffer. When FIMC DMA engine is stopped by the driver due the to user space not keeping up with buffer de-queuing the MIPI-CSIS will still run, however it must discard data which is not captured by FIMC. Which frames are actually capture by MIPI-CSIS is determined by means of the s_tx_buffer subdev callback. When it is not called after a single embedded data frame has been captured and copied and before next embedded data frame interrupt occurrs, subsequent embedded data frames will be dropped. Signed-off-by: Sylwester Nawrocki Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index 8e4eed8..acf4ce2 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -98,6 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); #define CSIS_MAX_PIX_WIDTH 0xffff #define CSIS_MAX_PIX_HEIGHT 0xffff +/* Non-image packet data buffers */ +#define S5PCSIS_PKTDATA_ODD 0x2000 +#define S5PCSIS_PKTDATA_EVEN 0x3000 +#define S5PCSIS_PKTDATA_SIZE SZ_4K + enum { CSIS_CLK_MUX, CSIS_CLK_GATE, @@ -144,6 +149,11 @@ static const struct s5pcsis_event s5pcsis_events[] = { }; #define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) +struct csis_pktbuf { + u32 *data; + unsigned int len; +}; + /** * struct csis_state - the driver's internal state data structure * @lock: mutex serializing the subdev and power management operations, @@ -159,6 +169,7 @@ static const struct s5pcsis_event s5pcsis_events[] = { * @csis_fmt: current CSIS pixel format * @format: common media bus format for the source and sink pad * @slock: spinlock protecting structure members below + * @pkt_buf: the frame embedded (non-image) data buffer * @events: MIPI-CSIS event (error) counters */ struct csis_state { @@ -175,6 +186,7 @@ struct csis_state { struct v4l2_mbus_framefmt format; struct spinlock slock; + struct csis_pktbuf pkt_buf; struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; }; @@ -529,6 +541,22 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } +static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf, + unsigned int *size) +{ + struct csis_state *state = sd_to_csis_state(sd); + unsigned long flags; + + *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE); + + spin_lock_irqsave(&state->slock, flags); + state->pkt_buf.data = buf; + state->pkt_buf.len = *size; + spin_unlock_irqrestore(&state->slock, flags); + + return 0; +} + static int s5pcsis_log_status(struct v4l2_subdev *sd) { struct csis_state *state = sd_to_csis_state(sd); @@ -566,6 +594,7 @@ static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = { }; static struct v4l2_subdev_video_ops s5pcsis_video_ops = { + .s_rx_buffer = s5pcsis_s_rx_buffer, .s_stream = s5pcsis_s_stream, }; @@ -578,13 +607,26 @@ static struct v4l2_subdev_ops s5pcsis_subdev_ops = { static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) { struct csis_state *state = dev_id; + struct csis_pktbuf *pktbuf = &state->pkt_buf; unsigned long flags; u32 status; status = s5pcsis_read(state, S5PCSIS_INTSRC); - spin_lock_irqsave(&state->slock, flags); + if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { + u32 offset; + + if (status & S5PCSIS_INTSRC_EVEN) + offset = S5PCSIS_PKTDATA_EVEN; + else + offset = S5PCSIS_PKTDATA_ODD; + + memcpy(pktbuf->data, state->regs + offset, pktbuf->len); + pktbuf->data = NULL; + rmb(); + } + /* Update the event/error counters */ if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { int i; -- cgit v0.10.2 From 14783d253625618744c200945c29769b3cbcc896 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 24 Sep 2012 11:08:45 -0300 Subject: [media] s5p-fimc: Add support for V4L2_PIX_FMT_S5C_UYVY_JPG fourcc The V4L2_PIX_FMT_S5C_YUYV_JPG image formats consists of 2 planes, the first containing interleaved JPEG/YUYV data and the second containing meta data describing the interleaving method. The image data is transferred with MIPI-CSI "User Defined Byte-Based Data 1" type and is captured to memory by FIMC DMA engine. The meta data is transferred using MIPI-CSI2 "Embedded 8-bit non Image Data" and it is captured in the MIPI-CSI slave device and copied to the bridge provided buffer. To make sure the size of allocated buffers is correct for the subdevs configuration when VIDIOC_STREAMON ioctl is invoked, an additional check is added at the video pipeline validation function. Flag FMT_FLAGS_COMPRESSED indicates the buffer size must be retrieved from a sensor subdev. Signed-off-by: Sylwester Nawrocki Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index dded988..367efd1 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -177,7 +177,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) { + struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_frame *f = &cap->ctx->d_frame; struct fimc_vid_buffer *v_buf; struct timeval *tv; struct timespec ts; @@ -216,6 +218,25 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } + /* + * Set up a buffer at MIPI-CSIS if current image format + * requires the frame embedded data capture. + */ + if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) { + unsigned int plane = ffs(f->fmt->mdataplanes) - 1; + unsigned int size = f->payload[plane]; + s32 index = fimc_hw_get_frame_index(fimc); + void *vaddr; + + list_for_each_entry(v_buf, &cap->active_buf_q, list) { + if (v_buf->index != index) + continue; + vaddr = vb2_plane_vaddr(&v_buf->vb, plane); + v4l2_subdev_call(csis, video, s_rx_buffer, + vaddr, &size); + break; + } + } if (cap->active_buf_cnt == 0) { if (deq_buf) @@ -351,6 +372,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, unsigned int size = (wh * fmt->depth[i]) / 8; if (pixm) sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); + else if (fimc_fmt_is_user_defined(fmt->color)) + sizes[i] = frame->payload[i]; else sizes[i] = max_t(u32, size, frame->payload[i]); @@ -611,10 +634,10 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, u32 mask = FMT_FLAGS_CAM; struct fimc_fmt *ffmt; - /* Color conversion from/to JPEG is not supported */ + /* Conversion from/to JPEG or User Defined format is not supported */ if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && - fimc_fmt_is_jpeg(ctx->s_frame.fmt->color)) - *code = V4L2_MBUS_FMT_JPEG_1X8; + fimc_fmt_is_user_defined(ctx->s_frame.fmt->color)) + *code = ctx->s_frame.fmt->mbus_code; if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK) mask |= FMT_FLAGS_M2M; @@ -628,18 +651,19 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, *fourcc = ffmt->fourcc; if (pad == FIMC_SD_PAD_SINK) { - max_w = fimc_fmt_is_jpeg(ffmt->color) ? + max_w = fimc_fmt_is_user_defined(ffmt->color) ? pl->scaler_dis_w : pl->scaler_en_w; /* Apply the camera input interface pixel constraints */ v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, height, max_t(u32, *height, 32), FIMC_CAMIF_MAX_HEIGHT, - fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1, + fimc_fmt_is_user_defined(ffmt->color) ? + 3 : 1, 0); return ffmt; } /* Can't scale or crop in transparent (JPEG) transfer mode */ - if (fimc_fmt_is_jpeg(ffmt->color)) { + if (fimc_fmt_is_user_defined(ffmt->color)) { *width = ctx->s_frame.f_width; *height = ctx->s_frame.f_height; return ffmt; @@ -684,7 +708,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, u32 max_sc_h, max_sc_v; /* In JPEG transparent transfer mode cropping is not supported */ - if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) { + if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) { r->width = sink->f_width; r->height = sink->f_height; r->left = r->top = 0; @@ -847,6 +871,48 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, return 0; } +/** + * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters + * @sensor: pointer to the sensor subdev + * @plane_fmt: provides plane sizes corresponding to the frame layout entries + * @try: true to set the frame parameters, false to query only + * + * This function is used by this driver only for compressed/blob data formats. + */ +static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor, + struct v4l2_plane_pix_format *plane_fmt, + unsigned int num_planes, bool try) +{ + struct v4l2_mbus_frame_desc fd; + int i, ret; + + for (i = 0; i < num_planes; i++) + fd.entry[i].length = plane_fmt[i].sizeimage; + + if (try) + ret = v4l2_subdev_call(sensor, pad, set_frame_desc, 0, &fd); + else + ret = v4l2_subdev_call(sensor, pad, get_frame_desc, 0, &fd); + + if (ret < 0) + return ret; + + if (num_planes != fd.num_entries) + return -EINVAL; + + for (i = 0; i < num_planes; i++) + plane_fmt[i].sizeimage = fd.entry[i].length; + + if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) { + v4l2_err(sensor->v4l2_dev, "Unsupported buffer size: %u\n", + fd.entry[0].length); + + return -EINVAL; + } + + return 0; +} + static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { @@ -865,7 +931,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct v4l2_mbus_framefmt mf; struct fimc_fmt *ffmt = NULL; - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SINK); @@ -879,25 +945,32 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, return -EINVAL; if (!fimc->vid_cap.user_subdev_api) { - mf.width = pix->width; + mf.width = pix->width; mf.height = pix->height; - mf.code = ffmt->mbus_code; + mf.code = ffmt->mbus_code; fimc_md_graph_lock(fimc); fimc_pipeline_try_format(ctx, &mf, &ffmt, false); fimc_md_graph_unlock(fimc); - - pix->width = mf.width; - pix->height = mf.height; + pix->width = mf.width; + pix->height = mf.height; if (ffmt) pix->pixelformat = ffmt->fourcc; } fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); + + if (ffmt->flags & FMT_FLAGS_COMPRESSED) + fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ffmt->memplanes, true); + return 0; } -static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg) +static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, + enum fimc_color_fmt color) { + bool jpeg = fimc_fmt_is_user_defined(color); + ctx->scaler.enabled = !jpeg; fimc_ctrls_activate(ctx, !jpeg); @@ -920,7 +993,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) return -EBUSY; /* Pre-configure format at camera interface input, for JPEG only */ - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SINK); @@ -953,7 +1026,16 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) } fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); - for (i = 0; i < ff->fmt->colplanes; i++) + + if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { + ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ff->fmt->memplanes, + true); + if (ret < 0) + return ret; + } + + for (i = 0; i < ff->fmt->memplanes; i++) ff->payload[i] = pix->plane_fmt[i].sizeimage; set_frame_bounds(ff, pix->width, pix->height); @@ -961,7 +1043,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) if (!(ctx->state & FIMC_COMPOSE)) set_frame_crop(ff, 0, 0, pix->width, pix->height); - fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color)); + fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color); /* Reset cropping and set format at the camera interface input */ if (!fimc->vid_cap.user_subdev_api) { @@ -1063,6 +1145,23 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) src_fmt.format.height != sink_fmt.format.height || src_fmt.format.code != sink_fmt.format.code) return -EPIPE; + + if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && + fimc_user_defined_mbus_fmt(src_fmt.format.code)) { + struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; + struct fimc_frame *frame = &vid_cap->ctx->d_frame; + unsigned int i; + + ret = fimc_get_sensor_frame_desc(sd, plane_fmt, + frame->fmt->memplanes, + false); + if (ret < 0) + return -EPIPE; + + for (i = 0; i < frame->fmt->memplanes; i++) + if (frame->payload[i] < plane_fmt[i].sizeimage) + return -EPIPE; + } } return 0; } @@ -1424,7 +1523,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, /* Update RGB Alpha control state and value range */ fimc_alpha_ctrl_update(ctx); - fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); + fimc_capture_mark_jpeg_xfer(ctx, ffmt->color); ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame; diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 1a44540..8d0d2b9 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -184,7 +184,17 @@ static struct fimc_fmt fimc_formats[] = { .memplanes = 1, .colplanes = 1, .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, - .flags = FMT_FLAGS_CAM, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, + }, { + .name = "S5C73MX interleaved UYVY/JPEG", + .fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG, + .color = FIMC_FMT_YUYV_JPEG, + .depth = { 8 }, + .memplanes = 2, + .colplanes = 1, + .mdataplanes = 0x2, /* plane 1 holds frame meta data */ + .mbus_code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, }, }; @@ -371,7 +381,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, default: return -EINVAL; } - } else { + } else if (!frame->fmt->mdataplanes) { if (frame->fmt->memplanes >= 2) paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); @@ -698,6 +708,11 @@ int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f) if (frame->fmt->colplanes == 1) /* packed formats */ bpl = (bpl * frame->fmt->depth[0]) / 8; pixm->plane_fmt[i].bytesperline = bpl; + + if (frame->fmt->flags & FMT_FLAGS_COMPRESSED) { + pixm->plane_fmt[i].sizeimage = frame->payload[i]; + continue; + } pixm->plane_fmt[i].sizeimage = (frame->o_width * frame->o_height * frame->fmt->depth[i]) / 8; } diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index cd716ba..c0040d79 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -40,6 +40,8 @@ #define SCALER_MAX_VRATIO 64 #define DMA_MIN_SIZE 8 #define FIMC_CAMIF_MAX_HEIGHT 0x2000 +#define FIMC_MAX_JPEG_BUF_SIZE (10 * SZ_1M) +#define FIMC_MAX_PLANES 3 /* indices to the clocks array */ enum { @@ -83,7 +85,7 @@ enum fimc_datapath { }; enum fimc_color_fmt { - FIMC_FMT_RGB444 = 0x10, + FIMC_FMT_RGB444 = 0x10, FIMC_FMT_RGB555, FIMC_FMT_RGB565, FIMC_FMT_RGB666, @@ -95,14 +97,15 @@ enum fimc_color_fmt { FIMC_FMT_CBYCRY422, FIMC_FMT_CRYCBY422, FIMC_FMT_YCBCR444_LOCAL, - FIMC_FMT_JPEG = 0x40, - FIMC_FMT_RAW8 = 0x80, + FIMC_FMT_RAW8 = 0x40, FIMC_FMT_RAW10, FIMC_FMT_RAW12, + FIMC_FMT_JPEG = 0x80, + FIMC_FMT_YUYV_JPEG = 0x100, }; +#define fimc_fmt_is_user_defined(x) (!!((x) & 0x180)) #define fimc_fmt_is_rgb(x) (!!((x) & 0x10)) -#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40)) #define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -139,6 +142,7 @@ enum fimc_color_fmt { * @memplanes: number of physically non-contiguous data planes * @colplanes: number of physically contiguous data planes * @depth: per plane driver's private 'number of bits per pixel' + * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no) * @flags: flags indicating which operation mode format applies to */ struct fimc_fmt { @@ -149,12 +153,14 @@ struct fimc_fmt { u16 memplanes; u16 colplanes; u8 depth[VIDEO_MAX_PLANES]; + u16 mdataplanes; u16 flags; #define FMT_FLAGS_CAM (1 << 0) #define FMT_FLAGS_M2M_IN (1 << 1) #define FMT_FLAGS_M2M_OUT (1 << 2) #define FMT_FLAGS_M2M (1 << 1 | 1 << 2) #define FMT_HAS_ALPHA (1 << 3) +#define FMT_FLAGS_COMPRESSED (1 << 4) }; /** @@ -272,7 +278,7 @@ struct fimc_frame { u32 offs_v; u32 width; u32 height; - unsigned long payload[VIDEO_MAX_PLANES]; + unsigned int payload[VIDEO_MAX_PLANES]; struct fimc_addr paddr; struct fimc_dma_offset dma_offset; struct fimc_fmt *fmt; @@ -577,6 +583,18 @@ static inline int tiled_fmt(struct fimc_fmt *fmt) return fmt->fourcc == V4L2_PIX_FMT_NV12MT; } +static inline bool fimc_jpeg_fourcc(u32 pixelformat) +{ + return (pixelformat == V4L2_PIX_FMT_JPEG || + pixelformat == V4L2_PIX_FMT_S5C_UYVY_JPG); +} + +static inline bool fimc_user_defined_mbus_fmt(u32 code) +{ + return (code == V4L2_MBUS_FMT_JPEG_1X8 || + code == V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8); +} + /* Return the alpha component bit mask */ static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) { diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c index 783408f..2c9d0c0 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-reg.c @@ -625,7 +625,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; } /* else defaults to ITU-R BT.656 8-bit */ } else if (cam->bus_type == FIMC_MIPI_CSI2) { - if (fimc_fmt_is_jpeg(f->fmt->color)) + if (fimc_fmt_is_user_defined(f->fmt->color)) cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; } @@ -680,6 +680,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; break; case V4L2_MBUS_FMT_JPEG_1X8: + case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8: tmp = FIMC_REG_CSIIMGFMT_USER(1); cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; break; @@ -744,13 +745,13 @@ void fimc_hw_dis_capture(struct fimc_dev *dev) } /* Return an index to the buffer actually being written. */ -u32 fimc_hw_get_frame_index(struct fimc_dev *dev) +s32 fimc_hw_get_frame_index(struct fimc_dev *dev) { - u32 reg; + s32 reg; if (dev->variant->has_cistatus2) { - reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3F; - return reg > 0 ? --reg : reg; + reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; + return reg - 1; } reg = readl(dev->regs + FIMC_REG_CISTATUS); @@ -759,6 +760,18 @@ u32 fimc_hw_get_frame_index(struct fimc_dev *dev) FIMC_REG_CISTATUS_FRAMECNT_SHIFT; } +/* Return an index to the buffer being written previously. */ +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) +{ + s32 reg; + + if (!dev->variant->has_cistatus2) + return -1; + + reg = readl(dev->regs + FIMC_REG_CISTATUS2); + return ((reg >> 7) & 0x3f) - 1; +} + /* Locking: the caller holds fimc->slock */ void fimc_activate_capture(struct fimc_ctx *ctx) { diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h index 579ac8a..b6abfc7 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.h +++ b/drivers/media/platform/s5p-fimc/fimc-reg.h @@ -307,7 +307,8 @@ void fimc_hw_clear_irq(struct fimc_dev *dev); void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on); void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on); void fimc_hw_dis_capture(struct fimc_dev *dev); -u32 fimc_hw_get_frame_index(struct fimc_dev *dev); +s32 fimc_hw_get_frame_index(struct fimc_dev *dev); +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev); void fimc_activate_capture(struct fimc_ctx *ctx); void fimc_deactivate_capture(struct fimc_dev *fimc); diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index acf4ce2..9555ded 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -214,7 +214,11 @@ static const struct csis_pix_format s5pcsis_formats[] = { .code = V4L2_MBUS_FMT_JPEG_1X8, .fmt_reg = S5PCSIS_CFG_FMT_USER(1), .data_alignment = 32, - }, + }, { + .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .fmt_reg = S5PCSIS_CFG_FMT_USER(1), + .data_alignment = 32, + } }; #define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) @@ -278,7 +282,7 @@ static void __s5pcsis_set_format(struct csis_state *state) struct v4l2_mbus_framefmt *mf = &state->format; u32 val; - v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n", + v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n", mf->code, mf->width, mf->height); /* Color format */ -- cgit v0.10.2 From ab7ef22419927910e563170db41f0a428d20b0a2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 18 Sep 2012 06:18:43 -0300 Subject: [media] m5mols: Implement .get_frame_desc subdev callback .get_frame_desc can be used by host interface driver to query properties of captured frames, e.g. required memory buffer size. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h index 86c815b..4ab8b37 100644 --- a/drivers/media/i2c/m5mols/m5mols.h +++ b/drivers/media/i2c/m5mols/m5mols.h @@ -19,6 +19,13 @@ #include #include "m5mols_reg.h" + +/* An amount of data transmitted in addition to the value + * determined by CAPP_JPEG_SIZE_MAX register. + */ +#define M5MOLS_JPEG_TAGS_SIZE 0x20000 +#define M5MOLS_MAIN_JPEG_SIZE_MAX (5 * SZ_1M) + extern int m5mols_debug; enum m5mols_restype { @@ -67,12 +74,14 @@ struct m5mols_exif { /** * struct m5mols_capture - Structure for the capture capability * @exif: EXIF information + * @buf_size: internal JPEG frame buffer size, in bytes * @main: size in bytes of the main image * @thumb: size in bytes of the thumb image, if it was accompanied * @total: total size in bytes of the produced image */ struct m5mols_capture { struct m5mols_exif exif; + unsigned int buf_size; u32 main; u32 thumb; u32 total; diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c index cb243bd..ab34cce 100644 --- a/drivers/media/i2c/m5mols/m5mols_capture.c +++ b/drivers/media/i2c/m5mols/m5mols_capture.c @@ -105,6 +105,7 @@ static int m5mols_capture_info(struct m5mols_info *info) int m5mols_start_capture(struct m5mols_info *info) { + unsigned int framesize = info->cap.buf_size - M5MOLS_JPEG_TAGS_SIZE; struct v4l2_subdev *sd = &info->sd; int ret; @@ -121,6 +122,8 @@ int m5mols_start_capture(struct m5mols_info *info) if (!ret) ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution); if (!ret) + ret = m5mols_write(sd, CAPP_JPEG_SIZE_MAX, framesize); + if (!ret) ret = m5mols_set_mode(info, REG_CAPTURE); if (!ret) /* Wait until a frame is captured to ISP internal memory */ diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 2f490ef..8131d65 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -599,6 +599,51 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } +static int m5mols_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct m5mols_info *info = to_m5mols(sd); + + if (pad != 0 || fd == NULL) + return -EINVAL; + + mutex_lock(&info->lock); + /* + * .get_frame_desc is only used for compressed formats, + * thus we always return the capture frame parameters here. + */ + fd->entry[0].length = info->cap.buf_size; + fd->entry[0].pixelcode = info->ffmt[M5MOLS_RESTYPE_CAPTURE].code; + mutex_unlock(&info->lock); + + fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->num_entries = 1; + + return 0; +} + +static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct m5mols_info *info = to_m5mols(sd); + struct v4l2_mbus_framefmt *mf = &info->ffmt[M5MOLS_RESTYPE_CAPTURE]; + + if (pad != 0 || fd == NULL) + return -EINVAL; + + fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->num_entries = 1; + fd->entry[0].length = clamp_t(u32, fd->entry[0].length, + mf->width * mf->height, + M5MOLS_MAIN_JPEG_SIZE_MAX); + mutex_lock(&info->lock); + info->cap.buf_size = fd->entry[0].length; + mutex_unlock(&info->lock); + + return 0; +} + + static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code) @@ -615,6 +660,8 @@ static struct v4l2_subdev_pad_ops m5mols_pad_ops = { .enum_mbus_code = m5mols_enum_mbus_code, .get_fmt = m5mols_get_fmt, .set_fmt = m5mols_set_fmt, + .get_frame_desc = m5mols_get_frame_desc, + .set_frame_desc = m5mols_set_frame_desc, }; /** diff --git a/drivers/media/i2c/m5mols/m5mols_reg.h b/drivers/media/i2c/m5mols/m5mols_reg.h index 14d4be7..58d8027 100644 --- a/drivers/media/i2c/m5mols/m5mols_reg.h +++ b/drivers/media/i2c/m5mols/m5mols_reg.h @@ -310,6 +310,7 @@ #define REG_JPEG 0x10 #define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1) +#define CAPP_JPEG_SIZE_MAX I2C_REG(CAT_CAPT_PARM, 0x0f, 4) #define CAPP_JPEG_RATIO I2C_REG(CAT_CAPT_PARM, 0x17, 1) #define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1) -- cgit v0.10.2 From 5ebef0fbe0f72fa911088800c5d0bc7a872c35de Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Mon, 1 Oct 2012 08:17:36 -0300 Subject: [media] media: v4l2-ctrls: add control for test pattern add V4L2_CID_TEST_PATTERN of type menu, which determines the internal test pattern selected by the device. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 272a5f7..a84a08c 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -4267,6 +4267,16 @@ interface and may change in the future. pixels / second. + + V4L2_CID_TEST_PATTERN + menu + + + Some capture/display/sensor devices have + the capability to generate test pattern images. These hardware + specific test patterns can be used to test if a device is working + properly. + diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 631cdc0..0bcef2b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -749,6 +749,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls"; case V4L2_CID_LINK_FREQ: return "Link Frequency"; case V4L2_CID_PIXEL_RATE: return "Pixel Rate"; + case V4L2_CID_TEST_PATTERN: return "Test Pattern"; /* DV controls */ case V4L2_CID_DV_CLASS: return "Digital Video Controls"; @@ -862,6 +863,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_TX_MODE: case V4L2_CID_DV_TX_RGB_RANGE: case V4L2_CID_DV_RX_RGB_RANGE: + case V4L2_CID_TEST_PATTERN: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h index 421d24c..e1b3680 100644 --- a/include/linux/v4l2-controls.h +++ b/include/linux/v4l2-controls.h @@ -757,5 +757,6 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_LINK_FREQ (V4L2_CID_IMAGE_PROC_CLASS_BASE + 1) #define V4L2_CID_PIXEL_RATE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 2) +#define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3) #endif -- cgit v0.10.2 From 117a711a2c37a0309a3e39fbd13486642b63453b Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 18 Sep 2012 15:54:38 -0300 Subject: [media] media: v4l2-ctrl: add a helper function to add standard control with driver specific menu Add helper function v4l2_ctrl_new_std_menu_items(), which adds a standard menu control, with driver specific menu. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 54270df..cfe52c7 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -136,11 +136,25 @@ Or alternatively for integer menu controls, by calling v4l2_ctrl_new_int_menu: const struct v4l2_ctrl_ops *ops, u32 id, s32 max, s32 def, const s64 *qmenu_int); +Standard menu controls with a driver specific menu are added by calling +v4l2_ctrl_new_std_menu_items: + + struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items( + struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 skip_mask, s32 def, const char * const *qmenu); + These functions are typically called right after the v4l2_ctrl_handler_init: static const s64 exp_bias_qmenu[] = { -2, -1, 0, 1, 2 }; + static const char * const test_pattern[] = { + "Disabled", + "Vertical Bars", + "Solid Black", + "Solid White", + }; v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls); v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops, @@ -156,6 +170,9 @@ These functions are typically called right after the v4l2_ctrl_handler_init: ARRAY_SIZE(exp_bias_qmenu) - 1, ARRAY_SIZE(exp_bias_qmenu) / 2 - 1, exp_bias_qmenu); + v4l2_ctrl_new_std_menu_items(&foo->ctrl_handler, &foo_ctrl_ops, + V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0, + 0, test_pattern); ... if (foo->ctrl_handler.error) { int err = foo->ctrl_handler.error; @@ -185,6 +202,13 @@ v4l2_ctrl_new_std_menu in that it doesn't have the mask argument and takes as the last argument an array of signed 64-bit integers that form an exact menu item list. +The v4l2_ctrl_new_std_menu_items function is very similar to +v4l2_ctrl_new_std_menu but takes an extra parameter qmenu, which is the driver +specific menu for an otherwise standard menu control. A good example for this +control is the test pattern control for capture/display/sensors devices that +have the capability to generate test patterns. These test patterns are hardware +specific, so the contents of the menu will vary from device to device. + Note that if something fails, the function will return NULL or an error and set ctrl_handler->error to the error code. If ctrl_handler->error was already set, then it will just return and do nothing. This is also true for diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 0bcef2b..207bcd8 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1650,6 +1650,36 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, } EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); +/* Helper function for standard menu controls with driver defined menu */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 mask, s32 def, const char * const *qmenu) +{ + enum v4l2_ctrl_type type; + const char *name; + u32 flags; + s32 step; + s32 min; + + /* v4l2_ctrl_new_std_menu_items() should only be called for + * standard controls without a standard menu. + */ + if (v4l2_ctrl_get_menu(id)) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, id, name, type, 0, max, mask, def, + flags, qmenu, NULL, NULL); + +} +EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items); + /* Helper function for standard integer menu controls */ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 801adb4..9650911 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -351,6 +351,29 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, s32 max, s32 mask, s32 def); +/** v4l2_ctrl_new_std_menu_items() - Create a new standard V4L2 menu control + * with driver specific menu. + * @hdl: The control handler. + * @ops: The control ops. + * @id: The control ID. + * @max: The control's maximum value. + * @mask: The control's skip mask for menu controls. This makes it + * easy to skip menu items that are not valid. If bit X is set, + * then menu item X is skipped. Of course, this only works for + * menus with <= 32 menu items. There are no menus that come + * close to that number, so this is OK. Should we ever need more, + * then this will have to be extended to a u64 or a bit array. + * @def: The control's default value. + * @qmenu: The new menu. + * + * Same as v4l2_ctrl_new_std_menu(), but @qmenu will be the driver specific + * menu of this control. + * + */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 mask, s32 def, const char * const *qmenu); + /** v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control. * @hdl: The control handler. * @ops: The control ops. -- cgit v0.10.2 From b28d70176e9f05fb94256678b4ff5b3527e81b7f Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 25 Sep 2012 09:35:43 -0300 Subject: [media] media: mt9p031/mt9t001/mt9v032: use V4L2_CID_TEST_PATTERN for test pattern control V4L2_CID_TEST_PATTERN is now a standard control. This patch replaces the user defined control for test pattern to make use of standard control V4L2_CID_TEST_PATTERN. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 2c0f407..e328332 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -574,7 +574,6 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) #define V4L2_CID_BLC_AUTO (V4L2_CID_USER_BASE | 0x1002) #define V4L2_CID_BLC_TARGET_LEVEL (V4L2_CID_USER_BASE | 0x1003) #define V4L2_CID_BLC_ANALOG_OFFSET (V4L2_CID_USER_BASE | 0x1004) @@ -740,18 +739,6 @@ static const char * const mt9p031_test_pattern_menu[] = { static const struct v4l2_ctrl_config mt9p031_ctrls[] = { { .ops = &mt9p031_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Test Pattern", - .min = 0, - .max = ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, - .step = 0, - .def = 0, - .flags = 0, - .menu_skip_mask = 0, - .qmenu = mt9p031_test_pattern_menu, - }, { - .ops = &mt9p031_ctrl_ops, .id = V4L2_CID_BLC_AUTO, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "BLC, Auto", @@ -950,7 +937,7 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->model = did->driver_data; mt9p031->reset = -1; - v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5); + v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN, @@ -966,6 +953,10 @@ static int mt9p031_probe(struct i2c_client *client, v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_PIXEL_RATE, pdata->target_freq, pdata->target_freq, 1, pdata->target_freq); + v4l2_ctrl_new_std_menu_items(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, 0, + 0, mt9p031_test_pattern_menu); for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i) v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL); diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index 6d343ad..2e189d8 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -371,7 +371,7 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) #define V4L2_CID_BLACK_LEVEL_AUTO (V4L2_CID_USER_BASE | 0x1002) #define V4L2_CID_BLACK_LEVEL_OFFSET (V4L2_CID_USER_BASE | 0x1003) #define V4L2_CID_BLACK_LEVEL_CALIBRATE (V4L2_CID_USER_BASE | 0x1004) @@ -487,12 +487,11 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl) ctrl->val >> 16); case V4L2_CID_TEST_PATTERN: - ret = mt9t001_set_output_control(mt9t001, + return mt9t001_set_output_control(mt9t001, ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA, ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0); - if (ret < 0) - return ret; + case V4L2_CID_TEST_PATTERN_COLOR: return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2); case V4L2_CID_BLACK_LEVEL_AUTO: @@ -533,12 +532,17 @@ static struct v4l2_ctrl_ops mt9t001_ctrl_ops = { .s_ctrl = mt9t001_s_ctrl, }; +static const char * const mt9t001_test_pattern_menu[] = { + "Disabled", + "Enabled", +}; + static const struct v4l2_ctrl_config mt9t001_ctrls[] = { { .ops = &mt9t001_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, + .id = V4L2_CID_TEST_PATTERN_COLOR, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern", + .name = "Test Pattern Color", .min = 0, .max = 1023, .step = 1, @@ -741,7 +745,7 @@ static int mt9t001_probe(struct i2c_client *client, return -ENOMEM; v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) + - ARRAY_SIZE(mt9t001_gains) + 3); + ARRAY_SIZE(mt9t001_gains) + 4); v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN, @@ -752,6 +756,10 @@ static int mt9t001_probe(struct i2c_client *client, v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk, 1, pdata->ext_clk); + v4l2_ctrl_new_std_menu_items(&mt9t001->ctrls, &mt9t001_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9t001_test_pattern_menu) - 1, 0, + 0, mt9t001_test_pattern_menu); for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i) v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL); diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index e217740..3f356cb 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -141,6 +141,10 @@ struct mt9v032 { u16 chip_control; u16 aec_agc; u16 hblank; + struct { + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *test_pattern_color; + }; }; static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd) @@ -500,7 +504,7 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) { @@ -545,7 +549,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_TEST_PATTERN: - switch (ctrl->val) { + switch (mt9v032->test_pattern->val) { case 0: data = 0; break; @@ -562,13 +566,13 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) | MT9V032_TEST_PATTERN_ENABLE; break; default: - data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT) + data = (mt9v032->test_pattern_color->val << + MT9V032_TEST_PATTERN_DATA_SHIFT) | MT9V032_TEST_PATTERN_USE_DATA | MT9V032_TEST_PATTERN_ENABLE | MT9V032_TEST_PATTERN_FLIP; break; } - return mt9v032_write(client, MT9V032_TEST_PATTERN, data); } @@ -579,18 +583,24 @@ static struct v4l2_ctrl_ops mt9v032_ctrl_ops = { .s_ctrl = mt9v032_s_ctrl, }; -static const struct v4l2_ctrl_config mt9v032_ctrls[] = { - { - .ops = &mt9v032_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern", - .min = 0, - .max = 1023, - .step = 1, - .def = 0, - .flags = 0, - } +static const char * const mt9v032_test_pattern_menu[] = { + "Disabled", + "Gray Vertical Shade", + "Gray Horizontal Shade", + "Gray Diagonal Shade", + "Plain", +}; + +static const struct v4l2_ctrl_config mt9v032_test_pattern_color = { + .ops = &mt9v032_ctrl_ops, + .id = V4L2_CID_TEST_PATTERN_COLOR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Test Pattern Color", + .min = 0, + .max = 1023, + .step = 1, + .def = 0, + .flags = 0, }; /* ----------------------------------------------------------------------------- @@ -741,7 +751,7 @@ static int mt9v032_probe(struct i2c_client *client, mutex_init(&mt9v032->power_lock); mt9v032->pdata = pdata; - v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 8); + v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); @@ -763,6 +773,14 @@ static int mt9v032_probe(struct i2c_client *client, V4L2_CID_VBLANK, MT9V032_VERTICAL_BLANKING_MIN, MT9V032_VERTICAL_BLANKING_MAX, 1, MT9V032_VERTICAL_BLANKING_DEF); + mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls, + &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9v032_test_pattern_menu) - 1, 0, 0, + mt9v032_test_pattern_menu); + mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls, + &mt9v032_test_pattern_color, NULL); + + v4l2_ctrl_cluster(2, &mt9v032->test_pattern); mt9v032->pixel_rate = v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, @@ -784,8 +802,6 @@ static int mt9v032_probe(struct i2c_client *client, v4l2_ctrl_cluster(2, &mt9v032->link_freq); } - for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i) - v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL); mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; -- cgit v0.10.2 From 99b32b24889a4671244f4ef99fed779e017ce8be Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Sep 2012 10:26:45 -0300 Subject: [media] fsl-viu: fix compiler warning drivers/media/platform/fsl-viu.c: In function 'vidioc_s_fbuf': drivers/media/platform/fsl-viu.c:867:32: warning: initialization discards 'const' qualifier from pointer target type [enabled by default] This is fall-out from this commit: commit e6eb28c2207b9397d0ab56e238865a4ee95b7ef9 Author: Hans Verkuil [media] v4l2: make vidioc_s_fbuf const Signed-off-by: Hans Verkuil Acked-by: Anatolij Gustschin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 897250b..31ac4dc 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -864,7 +864,7 @@ int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer * { struct viu_fh *fh = priv; struct viu_dev *dev = fh->dev; - struct v4l2_framebuffer *fb = arg; + const struct v4l2_framebuffer *fb = arg; struct viu_fmt *fmt; if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) -- cgit v0.10.2 From f4ad8d74e1ab54861bf084052a032c708dd0e227 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 27 Sep 2012 02:33:12 -0300 Subject: [media] media: davinci: vpif: add check for NULL handler for da850/omap-l138, there is no need to setup_input_channel_mode() and set_clock(), to avoid adding dummy code in board file just returning zero add a check in the driver itself to call the handler only if its not NULL. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 0bafeca..8dbbd4b 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -311,12 +311,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) } /* configure 1 or 2 channel mode */ - ret = vpif_config_data->setup_input_channel_mode - (vpif->std_info.ycmux_mode); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set vpif channel mode\n"); - return ret; + if (vpif_config_data->setup_input_channel_mode) { + ret = vpif_config_data-> + setup_input_channel_mode(vpif->std_info.ycmux_mode); + if (ret < 0) { + vpif_dbg(1, debug, "can't set vpif channel mode\n"); + return ret; + } } /* Call vpif_set_params function to set the parameters and addresses */ diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index a5b8868..7493683 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -280,12 +280,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) } /* clock settings */ - ret = - vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, - ch->vpifparams.std_info.hd_sd); - if (ret < 0) { - vpif_err("can't set clock\n"); - return ret; + if (vpif_config_data->set_clock) { + ret = vpif_config_data->set_clock(ch->vpifparams.std_info. + ycmux_mode, ch->vpifparams.std_info.hd_sd); + if (ret < 0) { + vpif_err("can't set clock\n"); + return ret; + } } /* set the parameters and addresses */ -- cgit v0.10.2 From 154d54a8ce9953197a662ffd24f4bb6aaeb236f4 Mon Sep 17 00:00:00 2001 From: Manjunath Hadli Date: Mon, 23 Jan 2012 06:17:24 -0300 Subject: [media] ARM: davinci: da850: Add SoC related definitions for VPIF Add clock, pin mux definitions and registration function for VPIF capture and display driver on DA850/OMAP-L138 SoC. Signed-off-by: Manjunath Hadli Signed-off-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index b44dc84..20d16ff 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -347,6 +347,13 @@ static struct clk spi1_clk = { .flags = DA850_CLK_ASYNC3, }; +static struct clk vpif_clk = { + .name = "vpif", + .parent = &pll0_sysclk2, + .lpsc = DA850_LPSC1_VPIF, + .gpsc = 1, +}; + static struct clk sata_clk = { .name = "sata", .parent = &pll0_sysclk2, @@ -397,6 +404,7 @@ static struct clk_lookup da850_clks[] = { CLK(NULL, "usb20", &usb20_clk), CLK("spi_davinci.0", NULL, &spi0_clk), CLK("spi_davinci.1", NULL, &spi1_clk), + CLK("vpif", NULL, &vpif_clk), CLK("ahci", NULL, &sata_clk), CLK(NULL, NULL, NULL), }; @@ -573,6 +581,46 @@ static const struct mux_config da850_pins[] = { MUX_CFG(DA850, GPIO6_10, 13, 20, 15, 8, false) MUX_CFG(DA850, GPIO6_13, 13, 8, 15, 8, false) MUX_CFG(DA850, RTC_ALARM, 0, 28, 15, 2, false) + /* VPIF Capture */ + MUX_CFG(DA850, VPIF_DIN0, 15, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN1, 15, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN2, 14, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN3, 14, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN4, 14, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN5, 14, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN6, 14, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN7, 14, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN8, 16, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN9, 16, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN10, 15, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN11, 15, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN12, 15, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN13, 15, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN14, 15, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN15, 15, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN0, 14, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN1, 14, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN2, 19, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN3, 19, 16, 15, 1, false) + /* VPIF Display */ + MUX_CFG(DA850, VPIF_DOUT0, 17, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT1, 17, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT2, 16, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT3, 16, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT4, 16, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT5, 16, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT6, 16, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT7, 16, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT8, 18, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT9, 18, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT10, 17, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT11, 17, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT12, 17, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT13, 17, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT14, 17, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT15, 17, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKO2, 19, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKO3, 19, 20, 15, 1, false) #endif }; @@ -595,6 +643,26 @@ const short da850_lcdcntl_pins[] __initdata = { -1 }; +const short da850_vpif_capture_pins[] __initdata = { + DA850_VPIF_DIN0, DA850_VPIF_DIN1, DA850_VPIF_DIN2, DA850_VPIF_DIN3, + DA850_VPIF_DIN4, DA850_VPIF_DIN5, DA850_VPIF_DIN6, DA850_VPIF_DIN7, + DA850_VPIF_DIN8, DA850_VPIF_DIN9, DA850_VPIF_DIN10, DA850_VPIF_DIN11, + DA850_VPIF_DIN12, DA850_VPIF_DIN13, DA850_VPIF_DIN14, DA850_VPIF_DIN15, + DA850_VPIF_CLKIN0, DA850_VPIF_CLKIN1, DA850_VPIF_CLKIN2, + DA850_VPIF_CLKIN3, + -1 +}; + +const short da850_vpif_display_pins[] __initdata = { + DA850_VPIF_DOUT0, DA850_VPIF_DOUT1, DA850_VPIF_DOUT2, DA850_VPIF_DOUT3, + DA850_VPIF_DOUT4, DA850_VPIF_DOUT5, DA850_VPIF_DOUT6, DA850_VPIF_DOUT7, + DA850_VPIF_DOUT8, DA850_VPIF_DOUT9, DA850_VPIF_DOUT10, + DA850_VPIF_DOUT11, DA850_VPIF_DOUT12, DA850_VPIF_DOUT13, + DA850_VPIF_DOUT14, DA850_VPIF_DOUT15, DA850_VPIF_CLKO2, + DA850_VPIF_CLKO3, + -1 +}; + /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = { [IRQ_DA8XX_COMMTX] = 7, @@ -1064,6 +1132,90 @@ no_ddrpll_mem: return ret; } +/* VPIF resource, platform data */ +static u64 da850_vpif_dma_mask = DMA_BIT_MASK(32); + +static struct resource da850_vpif_resource[] = { + { + .start = DA8XX_VPIF_BASE, + .end = DA8XX_VPIF_BASE + 0xfff, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device da850_vpif_dev = { + .name = "vpif", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_resource, + .num_resources = ARRAY_SIZE(da850_vpif_resource), +}; + +static struct resource da850_vpif_display_resource[] = { + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device da850_vpif_display_dev = { + .name = "vpif_display", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_display_resource, + .num_resources = ARRAY_SIZE(da850_vpif_display_resource), +}; + +static struct resource da850_vpif_capture_resource[] = { + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device da850_vpif_capture_dev = { + .name = "vpif_capture", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_capture_resource, + .num_resources = ARRAY_SIZE(da850_vpif_capture_resource), +}; + +int __init da850_register_vpif(void) +{ + return platform_device_register(&da850_vpif_dev); +} + +int __init da850_register_vpif_display(struct vpif_display_config + *display_config) +{ + da850_vpif_display_dev.dev.platform_data = display_config; + return platform_device_register(&da850_vpif_display_dev); +} + +int __init da850_register_vpif_capture(struct vpif_capture_config + *capture_config) +{ + da850_vpif_capture_dev.dev.platform_data = capture_config; + return platform_device_register(&da850_vpif_capture_dev); +} + static struct davinci_soc_info davinci_soc_info_da850 = { .io_desc = da850_io_desc, .io_desc_num = ARRAY_SIZE(da850_io_desc), diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index a2f1f27..8eecbce 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,8 @@ #include #include +#include + extern void __iomem *da8xx_syscfg0_base; extern void __iomem *da8xx_syscfg1_base; @@ -63,6 +66,7 @@ extern unsigned int da850_max_speed; #define DA8XX_PLL0_BASE 0x01c11000 #define DA8XX_TIMER64P0_BASE 0x01c20000 #define DA8XX_TIMER64P1_BASE 0x01c21000 +#define DA8XX_VPIF_BASE 0x01e17000 #define DA8XX_GPIO_BASE 0x01e26000 #define DA8XX_PSC1_BASE 0x01e27000 #define DA8XX_AEMIF_CS2_BASE 0x60000000 @@ -92,6 +96,11 @@ int da8xx_register_cpuidle(void); void __iomem * __init da8xx_get_mem_ctlr(void); int da850_register_pm(struct platform_device *pdev); int __init da850_register_sata(unsigned long refclkpn); +int __init da850_register_vpif(void); +int __init da850_register_vpif_display + (struct vpif_display_config *display_config); +int __init da850_register_vpif_capture + (struct vpif_capture_config *capture_config); void da8xx_restart(char mode, const char *cmd); extern struct platform_device da8xx_serial_device; @@ -126,6 +135,8 @@ extern const short da830_ecap1_pins[]; extern const short da830_ecap2_pins[]; extern const short da830_eqep0_pins[]; extern const short da830_eqep1_pins[]; +extern const short da850_vpif_capture_pins[]; +extern const short da850_vpif_display_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h index a7e92fc..9e95b8a 100644 --- a/arch/arm/mach-davinci/include/mach/mux.h +++ b/arch/arm/mach-davinci/include/mach/mux.h @@ -928,6 +928,48 @@ enum davinci_da850_index { DA850_GPIO6_10, DA850_GPIO6_13, DA850_RTC_ALARM, + + /* VPIF Capture */ + DA850_VPIF_DIN0, + DA850_VPIF_DIN1, + DA850_VPIF_DIN2, + DA850_VPIF_DIN3, + DA850_VPIF_DIN4, + DA850_VPIF_DIN5, + DA850_VPIF_DIN6, + DA850_VPIF_DIN7, + DA850_VPIF_DIN8, + DA850_VPIF_DIN9, + DA850_VPIF_DIN10, + DA850_VPIF_DIN11, + DA850_VPIF_DIN12, + DA850_VPIF_DIN13, + DA850_VPIF_DIN14, + DA850_VPIF_DIN15, + DA850_VPIF_CLKIN0, + DA850_VPIF_CLKIN1, + DA850_VPIF_CLKIN2, + DA850_VPIF_CLKIN3, + + /* VPIF Display */ + DA850_VPIF_DOUT0, + DA850_VPIF_DOUT1, + DA850_VPIF_DOUT2, + DA850_VPIF_DOUT3, + DA850_VPIF_DOUT4, + DA850_VPIF_DOUT5, + DA850_VPIF_DOUT6, + DA850_VPIF_DOUT7, + DA850_VPIF_DOUT8, + DA850_VPIF_DOUT9, + DA850_VPIF_DOUT10, + DA850_VPIF_DOUT11, + DA850_VPIF_DOUT12, + DA850_VPIF_DOUT13, + DA850_VPIF_DOUT14, + DA850_VPIF_DOUT15, + DA850_VPIF_CLKO2, + DA850_VPIF_CLKO3, }; enum davinci_tnetv107x_index { diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 405318e..40a0027 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -166,6 +166,7 @@ #define DA830_LPSC1_McASP1 8 #define DA850_LPSC1_SATA 8 #define DA830_LPSC1_McASP2 9 +#define DA850_LPSC1_VPIF 9 #define DA8XX_LPSC1_SPI1 10 #define DA8XX_LPSC1_I2C 11 #define DA8XX_LPSC1_UART1 12 -- cgit v0.10.2 From 1e046d17b59046ac1333b59f8bab6db140ca5d56 Mon Sep 17 00:00:00 2001 From: Manjunath Hadli Date: Mon, 23 Jul 2012 08:00:58 -0300 Subject: [media] ARM: davinci: da850 evm: Add EVM specific code for VPIF to work Include the expander settings to select VPIF peripheral on UI card and add registration call in EVM init. Also add platform data to configure display and capture devices. Signed-off-by: Manjunath Hadli Signed-off-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index ab99c3c..026b4b2 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -186,6 +186,13 @@ config DA850_UI_RMII NOTE: Please take care while choosing this option, MII PHY will not be functional if RMII mode is selected. +config DA850_UI_SD_VIDEO_PORT + bool "Video Port Interface" + help + Say Y if you want to use Video Port Interface (VPIF) on the + DA850/OMAP-L138 EVM. The Video decoders/encoders are found on the + UI daughter card that is supplied with the EVM. + endchoice config DA850_WL12XX diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 0149fb4..d0954a2 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -45,6 +45,8 @@ #include #include +#include + #define DA850_EVM_PHY_ID "davinci_mdio-0:00" #define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8) #define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15) @@ -452,6 +454,15 @@ static void da850_evm_ui_keys_init(unsigned gpio) } } +#ifdef CONFIG_DA850_UI_SD_VIDEO_PORT +static inline void da850_evm_setup_video_port(int video_sel) +{ + gpio_set_value_cansleep(video_sel, 0); +} +#else +static inline void da850_evm_setup_video_port(int video_sel) { } +#endif + static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *c) { @@ -497,6 +508,8 @@ static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio, da850_evm_setup_emac_rmii(sel_a); + da850_evm_setup_video_port(sel_c); + return 0; exp_setup_keys_fail: @@ -1149,6 +1162,147 @@ static __init int da850_evm_init_cpufreq(void) static __init int da850_evm_init_cpufreq(void) { return 0; } #endif +#if defined(CONFIG_DA850_UI_SD_VIDEO_PORT) + +#define TVP5147_CH0 "tvp514x-0" +#define TVP5147_CH1 "tvp514x-1" + +/* VPIF capture configuration */ +static struct tvp514x_platform_data tvp5146_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1, +}; + +#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +static const struct vpif_input da850_ch0_inputs[] = { + { + .input = { + .index = 0, + .name = "Composite", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, + .subdev_name = TVP5147_CH0, + }, +}; + +static const struct vpif_input da850_ch1_inputs[] = { + { + .input = { + .index = 0, + .name = "S-Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .std = TVP514X_STD_ALL, + }, + .subdev_name = TVP5147_CH1, + }, +}; + +static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { + { + .name = TVP5147_CH0, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5d), + .platform_data = &tvp5146_pdata, + }, + .input = INPUT_CVBS_VI2B, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .can_route = 1, + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + { + .name = TVP5147_CH1, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5c), + .platform_data = &tvp5146_pdata, + }, + .input = INPUT_SVIDEO_VI2C_VI1C, + .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .can_route = 1, + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, +}; + +static struct vpif_capture_config da850_vpif_capture_config = { + .subdev_info = da850_vpif_capture_sdev_info, + .subdev_count = ARRAY_SIZE(da850_vpif_capture_sdev_info), + .chan_config[0] = { + .inputs = da850_ch0_inputs, + .input_count = ARRAY_SIZE(da850_ch0_inputs), + }, + .chan_config[1] = { + .inputs = da850_ch1_inputs, + .input_count = ARRAY_SIZE(da850_ch1_inputs), + }, + .card_name = "DA850/OMAP-L138 Video Capture", +}; + +/* VPIF display configuration */ +static struct vpif_subdev_info da850_vpif_subdev[] = { + { + .name = "adv7343", + .board_info = { + I2C_BOARD_INFO("adv7343", 0x2a), + }, + }, +}; + +static const char const *vpif_output[] = { + "Composite", + "S-Video", +}; + +static struct vpif_display_config da850_vpif_display_config = { + .subdevinfo = da850_vpif_subdev, + .subdev_count = ARRAY_SIZE(da850_vpif_subdev), + .output = vpif_output, + .output_count = ARRAY_SIZE(vpif_output), + .card_name = "DA850/OMAP-L138 Video Display", +}; + +static __init void da850_vpif_init(void) +{ + int ret; + + ret = da850_register_vpif(); + if (ret) + pr_warn("da850_evm_init: VPIF setup failed: %d\n", ret); + + ret = davinci_cfg_reg_list(da850_vpif_capture_pins); + if (ret) + pr_warn("da850_evm_init: VPIF capture mux setup failed: %d\n", + ret); + + ret = da850_register_vpif_capture(&da850_vpif_capture_config); + if (ret) + pr_warn("da850_evm_init: VPIF capture setup failed: %d\n", ret); + + ret = davinci_cfg_reg_list(da850_vpif_display_pins); + if (ret) + pr_warn("da850_evm_init: VPIF display mux setup failed: %d\n", + ret); + + ret = da850_register_vpif_display(&da850_vpif_display_config); + if (ret) + pr_warn("da850_evm_init: VPIF display setup failed: %d\n", ret); +} + +#else +static __init void da850_vpif_init(void) {} +#endif + #ifdef CONFIG_DA850_WL12XX static void wl12xx_set_power(int index, bool power_on) @@ -1375,6 +1529,8 @@ static __init void da850_evm_init(void) pr_warning("da850_evm_init: suspend registration failed: %d\n", ret); + da850_vpif_init(); + ret = da8xx_register_spi(1, da850evm_spi_info, ARRAY_SIZE(da850evm_spi_info)); if (ret) -- cgit v0.10.2 From 822f0fd36281c0d56501d6153d10555dc2e2ba52 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:20 -0300 Subject: [media] vpif_capture: remove unused data structure Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index d24efc1..1bc9d8b 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h @@ -159,10 +159,6 @@ struct vpif_config_params { u32 video_limit[VPIF_CAPTURE_NUM_CHANNELS]; u8 max_device_type; }; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; -}; + #endif /* End of __KERNEL__ */ #endif /* VPIF_CAPTURE_H */ -- cgit v0.10.2 From 3cfee2daf9fe9dc514c29f7e7fb35c17136771d2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:21 -0300 Subject: [media] vpif_display: remove unused data structures Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index f628ebc..b90a164 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h @@ -65,12 +65,6 @@ struct video_obj { u32 output_id; /* Current output id */ }; -struct vbi_obj { - int num_services; - struct vpif_vbi_params vbiparams; /* vpif parameters for the raw - * vbi data */ -}; - struct vpif_disp_buffer { struct vb2_buffer vb; struct list_head list; @@ -136,7 +130,6 @@ struct channel_obj { struct vpif_params vpifparams; struct common_obj common[VPIF_NUMOBJECTS]; struct video_obj video; - struct vbi_obj vbi; }; /* File handle structure */ @@ -168,12 +161,4 @@ struct vpif_config_params { u8 min_numbuffers; }; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; - u16 enc_service_id; - u8 bytestowrite; -}; - #endif /* DAVINCIHD_DISPLAY_H */ -- cgit v0.10.2 From 6f47c6c69cd45d9e57458e31528628af2d346f73 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:22 -0300 Subject: [media] vpif_capture: move input_idx to channel_obj input_idx does not belong to video_obj. Move it where it belongs. Also remove the bogus code in the open() function that suddenly changes the input to 0 for no reason. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 8dbbd4b..8345106 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -888,8 +888,6 @@ static int vpif_open(struct file *filep) if (vpif_obj.sd[i]) { /* the sub device is registered */ ch->curr_subdev_info = &config->subdev_info[i]; - /* make first input as the current input */ - vid_ch->input_idx = 0; break; } } @@ -1442,10 +1440,8 @@ static int vpif_g_input(struct file *file, void *priv, unsigned int *index) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - *index = vid_ch->input_idx; + *index = ch->input_idx; return 0; } @@ -1462,7 +1458,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; struct vpif_subdev_info *subdev_info; int ret = 0, sd_index = 0; u32 input = 0, output = 0; @@ -1517,7 +1512,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) return ret; } } - vid_ch->input_idx = index; + ch->input_idx = index; ch->curr_subdev_info = subdev_info; ch->curr_sd_index = sd_index; /* copy interface parameters to vpif */ diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index 1bc9d8b..760964c 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h @@ -54,8 +54,6 @@ struct video_obj { /* Currently selected or default standard */ v4l2_std_id stdid; struct v4l2_dv_timings dv_timings; - /* This is to track the last input that is passed to application */ - u32 input_idx; }; struct vpif_cap_buffer { @@ -121,6 +119,8 @@ struct channel_obj { enum vpif_channel_id channel_id; /* index into sd table */ int curr_sd_index; + /* Current input */ + u32 input_idx; /* ptr to current sub device information */ struct vpif_subdev_info *curr_subdev_info; /* vpif configuration params */ -- cgit v0.10.2 From 311673ee9b6746aa366cc19049899308ce8bd01f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:23 -0300 Subject: [media] vpif_display: move output_id to channel_obj The output index does not belong to video_obj, it belongs to channel_obj. Also rename to output_idx to be consistent with the input_idx name used in vpif_capture. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 7493683..2d90328 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1231,7 +1231,6 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; int ret = 0; @@ -1246,7 +1245,7 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i) if (ret < 0) vpif_err("Failed to set output standard\n"); - vid_ch->output_id = i; + ch->output_idx = i; return ret; } @@ -1254,9 +1253,8 @@ static int vpif_g_output(struct file *file, void *priv, unsigned int *i) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - *i = vid_ch->output_id; + *i = ch->output_idx; return 0; } @@ -1291,9 +1289,8 @@ vpif_enum_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + return v4l2_subdev_call(vpif_obj.sd[ch->output_idx], video, enum_dv_timings, timings); } @@ -1320,7 +1317,7 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], + ret = v4l2_subdev_call(vpif_obj.sd[ch->output_idx], video, s_dv_timings, timings); if (ret == -ENOIOCTLCMD) { vpif_dbg(2, debug, "Custom DV timings not supported by " @@ -1451,9 +1448,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg){ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, + return v4l2_subdev_call(vpif_obj.sd[ch->output_idx], core, g_register, reg); } @@ -1470,9 +1466,8 @@ static int vpif_dbg_s_register(struct file *file, void *priv, struct v4l2_dbg_register *reg){ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, + return v4l2_subdev_call(vpif_obj.sd[ch->output_idx], core, s_register, reg); } #endif diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index b90a164..532ee9e 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h @@ -62,7 +62,6 @@ struct video_obj { v4l2_std_id stdid; /* Currently selected or default * standard */ struct v4l2_dv_timings dv_timings; - u32 output_id; /* Current output id */ }; struct vpif_disp_buffer { @@ -125,6 +124,7 @@ struct channel_obj { * which is being displayed */ u8 initialized; /* flag to indicate whether * encoder is initialized */ + u32 output_idx; /* Current output index */ enum vpif_channel_id channel_id;/* Identifies channel */ struct vpif_params vpifparams; -- cgit v0.10.2 From 33bf1786602d819dc0467e77816dfa3f2a7e459d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:24 -0300 Subject: [media] vpif_capture: remove unnecessary can_route flag Calling a subdev op that isn't implemented will just return -ENOIOCTLCMD No need to have a flag for that. Signed-off-by: Hans Verkuil Acked-by: Sekhar Nori Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index d0954a2..d92e0ab 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1209,7 +1209,6 @@ static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { }, .input = INPUT_CVBS_VI2B, .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, @@ -1225,7 +1224,6 @@ static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { }, .input = INPUT_SVIDEO_VI2C_VI1C, .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 958679a..a0be63b 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -603,7 +603,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { }, .input = INPUT_CVBS_VI2B, .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, @@ -619,7 +618,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { }, .input = INPUT_SVIDEO_VI2C_VI1C, .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 8345106..d90e235 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1502,15 +1502,13 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) } } - if (subdev_info->can_route) { - input = subdev_info->input; - output = subdev_info->output; - ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, - input, output, 0); - if (ret < 0) { - vpif_dbg(1, debug, "Failed to set input\n"); - return ret; - } + input = subdev_info->input; + output = subdev_info->output; + ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, + input, output, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + vpif_dbg(1, debug, "Failed to set input\n"); + return ret; } ch->input_idx = index; ch->curr_subdev_info = subdev_info; @@ -1520,7 +1518,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) /* update tvnorms from the sub device input info */ ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; - return ret; + return 0; } /** diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h index d8f6ab1..1fe46a5 100644 --- a/include/media/davinci/vpif_types.h +++ b/include/media/davinci/vpif_types.h @@ -39,7 +39,6 @@ struct vpif_subdev_info { struct i2c_board_info board_info; u32 input; u32 output; - unsigned can_route:1; struct vpif_interface vpif_if; }; -- cgit v0.10.2 From 7aaad13124598580dbce98d33618e9356412274c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:25 -0300 Subject: [media] vpif_capture: move routing info from subdev to input Routing information is a property of the input, not of the subdev. One subdev may provide multiple inputs, each with its own routing information. Signed-off-by: Hans Verkuil Acked-by: Sekhar Nori Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index d92e0ab..87bd249 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1182,8 +1182,11 @@ static const struct vpif_input da850_ch0_inputs[] = { .index = 0, .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, + .input_route = INPUT_CVBS_VI2B, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, .subdev_name = TVP5147_CH0, }, }; @@ -1194,8 +1197,11 @@ static const struct vpif_input da850_ch1_inputs[] = { .index = 0, .name = "S-Video", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, + .input_route = INPUT_SVIDEO_VI2C_VI1C, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, .subdev_name = TVP5147_CH1, }, }; @@ -1207,8 +1213,6 @@ static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5d), .platform_data = &tvp5146_pdata, }, - .input = INPUT_CVBS_VI2B, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, @@ -1222,8 +1226,6 @@ static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5c), .platform_data = &tvp5146_pdata, }, - .input = INPUT_SVIDEO_VI2C_VI1C, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index a0be63b..6f329ca 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -601,8 +601,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5d), .platform_data = &tvp5146_pdata, }, - .input = INPUT_CVBS_VI2B, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, @@ -616,8 +614,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5c), .platform_data = &tvp5146_pdata, }, - .input = INPUT_SVIDEO_VI2C_VI1C, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, .vpif_if = { .if_type = VPIF_IF_BT656, .hd_pol = 1, @@ -633,9 +629,12 @@ static const struct vpif_input dm6467_ch0_inputs[] = { .index = 0, .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, .subdev_name = TVP5147_CH0, + .input_route = INPUT_CVBS_VI2B, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, }, }; @@ -645,9 +644,12 @@ static const struct vpif_input dm6467_ch1_inputs[] = { .index = 0, .name = "S-Video", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, .subdev_name = TVP5147_CH1, + .input_route = INPUT_SVIDEO_VI2C_VI1C, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, }, }; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index d90e235..d668a3a 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1464,6 +1464,9 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) chan_cfg = &config->chan_config[ch->channel_id]; + if (index >= chan_cfg->input_count) + return -EINVAL; + if (common->started) { vpif_err("Streaming in progress\n"); return -EBUSY; @@ -1502,8 +1505,8 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) } } - input = subdev_info->input; - output = subdev_info->output; + input = chan_cfg->inputs[index].input_route; + output = chan_cfg->inputs[index].output_route; ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, input, output, 0); if (ret < 0 && ret != -ENOIOCTLCMD) { diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h index 1fe46a5..a422ed0 100644 --- a/include/media/davinci/vpif_types.h +++ b/include/media/davinci/vpif_types.h @@ -37,8 +37,6 @@ struct vpif_interface { struct vpif_subdev_info { const char *name; struct i2c_board_info board_info; - u32 input; - u32 output; struct vpif_interface vpif_if; }; @@ -56,6 +54,8 @@ struct vpif_display_config { struct vpif_input { struct v4l2_input input; const char *subdev_name; + u32 input_route; + u32 output_route; }; struct vpif_capture_chan_config { -- cgit v0.10.2 From b65814e546b2b6d76a299b0ee605c10d0b84bb96 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:26 -0300 Subject: [media] vpif_capture: first init subdevs, then register device nodes When device nodes are registered they must be ready for use immediately, so make sure the subdevs are loaded first. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index d668a3a..00fdb17 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -2139,24 +2139,6 @@ static __init int vpif_probe(struct platform_device *pdev) } } - for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { - ch = vpif_obj.dev[j]; - ch->channel_id = j; - common = &(ch->common[VPIF_VIDEO_INDEX]); - spin_lock_init(&common->irqlock); - mutex_init(&common->lock); - ch->video_dev->lock = &common->lock; - /* Initialize prio member of channel object */ - v4l2_prio_init(&ch->prio); - err = video_register_device(ch->video_dev, - VFL_TYPE_GRABBER, (j ? 1 : 0)); - if (err) - goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - - } - i2c_adap = i2c_get_adapter(1); config = pdev->dev.platform_data; @@ -2166,7 +2148,7 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; - goto probe_out; + goto vpif_dev_alloc_err; } for (i = 0; i < subdev_count; i++) { @@ -2183,19 +2165,27 @@ static __init int vpif_probe(struct platform_device *pdev) } v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", subdevdata->name); - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; } + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + common = &(ch->common[VPIF_VIDEO_INDEX]); + spin_lock_init(&common->irqlock); + mutex_init(&common->lock); + ch->video_dev->lock = &common->lock; + /* Initialize prio member of channel object */ + v4l2_prio_init(&ch->prio); + video_set_drvdata(ch->video_dev, ch); + + err = video_register_device(ch->video_dev, + VFL_TYPE_GRABBER, (j ? 1 : 0)); + if (err) + goto probe_out; + } v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n"); return 0; -probe_subdev_out: - /* free sub devices memory */ - kfree(vpif_obj.sd); - - j = VPIF_CAPTURE_MAX_DEVICES; probe_out: for (k = 0; k < j; k++) { /* Get the pointer to the channel object */ @@ -2203,6 +2193,9 @@ probe_out: /* Unregister video device */ video_unregister_device(ch->video_dev); } +probe_subdev_out: + /* free sub devices memory */ + kfree(vpif_obj.sd); vpif_dev_alloc_err: k = VPIF_CAPTURE_MAX_DEVICES-1; -- cgit v0.10.2 From e6067f8b1e3edd731cbcffb642d166d81767a30a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:27 -0300 Subject: [media] vpif_display: first init subdevs, then register device nodes When device nodes are registered they must be ready for use immediately, so make sure the subdevs are loaded first. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 2d90328..f5b5c8d 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1690,6 +1690,32 @@ static __init int vpif_probe(struct platform_device *pdev) } } + i2c_adap = i2c_get_adapter(1); + config = pdev->dev.platform_data; + subdev_count = config->subdev_count; + subdevdata = config->subdevinfo; + vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, + GFP_KERNEL); + if (vpif_obj.sd == NULL) { + vpif_err("unable to allocate memory for subdevice pointers\n"); + err = -ENOMEM; + goto vpif_int_err; + } + + for (i = 0; i < subdev_count; i++) { + vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, + i2c_adap, + &subdevdata[i].board_info, + NULL); + if (!vpif_obj.sd[i]) { + vpif_err("Error registering v4l2 subdevice\n"); + goto probe_subdev_out; + } + + if (vpif_obj.sd[i]) + vpif_obj.sd[i]->grp_id = 1 << i; + } + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; /* Initialize field of the channel objects */ @@ -1725,6 +1751,7 @@ static __init int vpif_probe(struct platform_device *pdev) ch->common[VPIF_VIDEO_INDEX].fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ch->video_dev->lock = &common->lock; + video_set_drvdata(ch->video_dev, ch); /* register video device */ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", @@ -1734,42 +1761,12 @@ static __init int vpif_probe(struct platform_device *pdev) VFL_TYPE_GRABBER, (j ? 3 : 2)); if (err < 0) goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - } - - i2c_adap = i2c_get_adapter(1); - config = pdev->dev.platform_data; - subdev_count = config->subdev_count; - subdevdata = config->subdevinfo; - vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); - if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); - err = -ENOMEM; - goto probe_out; - } - - for (i = 0; i < subdev_count; i++) { - vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, - &subdevdata[i].board_info, - NULL); - if (!vpif_obj.sd[i]) { - vpif_err("Error registering v4l2 subdevice\n"); - goto probe_subdev_out; - } - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; } v4l2_info(&vpif_obj.v4l2_dev, " VPIF display driver initialized\n"); return 0; -probe_subdev_out: - kfree(vpif_obj.sd); probe_out: for (k = 0; k < j; k++) { ch = vpif_obj.dev[k]; @@ -1777,6 +1774,8 @@ probe_out: video_device_release(ch->video_dev); ch->video_dev = NULL; } +probe_subdev_out: + kfree(vpif_obj.sd); vpif_int_err: v4l2_device_unregister(&vpif_obj.v4l2_dev); vpif_err("VPIF IRQ request failed\n"); -- cgit v0.10.2 From 01b1d975597dd051515fe90e5b0b09cc700e6aa0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:28 -0300 Subject: [media] vpif_display: fix cleanup code The cleanup sequence was incorrect and could cause a kernel oops. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index f5b5c8d..4e28000 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1607,7 +1607,8 @@ static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct vpif_display_config *config; - int i, j = 0, k, q, m, err = 0; + int i, j = 0, k, err = 0; + int res_idx = 0; struct i2c_adapter *i2c_adap; struct common_obj *common; struct channel_obj *ch; @@ -1630,21 +1631,22 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { for (i = res->start; i <= res->end; i++) { if (request_irq(i, vpif_channel_isr, IRQF_SHARED, - "VPIF_Display", - (void *)(&vpif_obj.dev[k]->channel_id))) { + "VPIF_Display", (void *) + (&vpif_obj.dev[res_idx]->channel_id))) { err = -EBUSY; + for (j = 0; j < i; j++) + free_irq(j, (void *) + (&vpif_obj.dev[res_idx]->channel_id)); goto vpif_int_err; } } - k++; + res_idx++; } for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ ch = vpif_obj.dev[i]; @@ -1699,7 +1701,7 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; - goto vpif_int_err; + goto vpif_sd_error; } for (i = 0; i < subdev_count; i++) { @@ -1776,14 +1778,19 @@ probe_out: } probe_subdev_out: kfree(vpif_obj.sd); +vpif_sd_error: + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + ch = vpif_obj.dev[i]; + /* Note: does nothing if ch->video_dev == NULL */ + video_device_release(ch->video_dev); + } vpif_int_err: v4l2_device_unregister(&vpif_obj.v4l2_dev); vpif_err("VPIF IRQ request failed\n"); - for (q = k; k >= 0; k--) { - for (m = i; m >= res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); - res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); - m = res->end; + for (i = 0; i < res_idx; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + for (j = res->start; j <= res->end; j++) + free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id)); } return err; -- cgit v0.10.2 From 5be452c343331dadf237bed0053fdc7d623e8049 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:29 -0300 Subject: [media] vpif_capture: fix cleanup code The cleanup sequence was incorrect and could cause a kernel oops. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 00fdb17..bcd2a78 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -2060,7 +2060,8 @@ static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct vpif_capture_config *config; - int i, j, k, m, q, err; + int i, j, k, err; + int res_idx = 0; struct i2c_adapter *i2c_adap; struct channel_obj *ch; struct common_obj *common; @@ -2083,18 +2084,19 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { for (i = res->start; i <= res->end; i++) { if (request_irq(i, vpif_channel_isr, IRQF_SHARED, - "VPIF_Capture", - (void *)(&vpif_obj.dev[k]->channel_id))) { + "VPIF_Capture", (void *) + (&vpif_obj.dev[res_idx]->channel_id))) { err = -EBUSY; - i--; + for (j = 0; j < i; j++) + free_irq(j, (void *) + (&vpif_obj.dev[res_idx]->channel_id)); goto vpif_int_err; } } - k++; + res_idx++; } for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { @@ -2108,7 +2110,7 @@ static __init int vpif_probe(struct platform_device *pdev) video_device_release(ch->video_dev); } err = -ENOMEM; - goto vpif_dev_alloc_err; + goto vpif_int_err; } /* Initialize field of video device */ @@ -2148,7 +2150,7 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; - goto vpif_dev_alloc_err; + goto vpif_sd_error; } for (i = 0; i < subdev_count; i++) { @@ -2197,21 +2199,19 @@ probe_subdev_out: /* free sub devices memory */ kfree(vpif_obj.sd); -vpif_dev_alloc_err: - k = VPIF_CAPTURE_MAX_DEVICES-1; - res = platform_get_resource(pdev, IORESOURCE_IRQ, k); - i = res->end; - -vpif_int_err: - for (q = k; q >= 0; q--) { - for (m = i; m >= (int)res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); - if (res) - i = res->end; +vpif_sd_error: + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + ch = vpif_obj.dev[i]; + /* Note: does nothing if ch->video_dev == NULL */ + video_device_release(ch->video_dev); } +vpif_int_err: v4l2_device_unregister(&vpif_obj.v4l2_dev); + for (i = 0; i < res_idx; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + for (j = res->start; j <= res->end; j++) + free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id)); + } return err; } -- cgit v0.10.2 From 178cce1262762b636bcde6685a014c70640b15cc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:30 -0300 Subject: [media] vpif_capture: separate subdev from input vpif_capture relied on a 1-1 mapping of input and subdev. This is not necessarily the case. Separate the two. So there is a list of subdevs and a list of inputs. Each input refers to a subdev and has routing information. An input does not have to have a subdev. The initial input for each channel is set to the fist input. Currently missing is support for associating multiple subdevs with an input. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index bcd2a78..c4db0ef 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -864,13 +864,11 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait) */ static int vpif_open(struct file *filep) { - struct vpif_capture_config *config = vpif_dev->platform_data; struct video_device *vdev = video_devdata(filep); struct common_obj *common; struct video_obj *vid_ch; struct channel_obj *ch; struct vpif_fh *fh; - int i; vpif_dbg(2, debug, "vpif_open\n"); @@ -879,24 +877,6 @@ static int vpif_open(struct file *filep) vid_ch = &ch->video; common = &ch->common[VPIF_VIDEO_INDEX]; - if (NULL == ch->curr_subdev_info) { - /** - * search through the sub device to see a registered - * sub device and make it as current sub device - */ - for (i = 0; i < config->subdev_count; i++) { - if (vpif_obj.sd[i]) { - /* the sub device is registered */ - ch->curr_subdev_info = &config->subdev_info[i]; - break; - } - } - if (i == config->subdev_count) { - vpif_err("No sub device registered\n"); - return -ENOENT; - } - } - /* Allocate memory for the file handle object */ fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); if (NULL == fh) { @@ -1174,10 +1154,9 @@ static int vpif_streamon(struct file *file, void *priv, return ret; /* Enable streamon on the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 1); + ret = v4l2_subdev_call(ch->sd, video, s_stream, 1); - if (ret && (ret != -ENOIOCTLCMD)) { + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "stream on failed in subdev\n"); return ret; } @@ -1237,73 +1216,105 @@ static int vpif_streamoff(struct file *file, void *priv, common->started = 0; - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 0); + ret = v4l2_subdev_call(ch->sd, video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) vpif_dbg(1, debug, "stream off failed in subdev\n"); return vb2_streamoff(&common->buffer_queue, buftype); } /** - * vpif_map_sub_device_to_input() - Maps sub device to input - * @ch - ptr to channel - * @config - ptr to capture configuration + * vpif_input_to_subdev() - Maps input to sub device + * @vpif_cfg - global config ptr + * @chan_cfg - channel config ptr * @input_index - Given input index from application - * @sub_device_index - index into sd table * * lookup the sub device information for a given input index. * we report all the inputs to application. inputs table also * has sub device name for the each input */ -static struct vpif_subdev_info *vpif_map_sub_device_to_input( - struct channel_obj *ch, - struct vpif_capture_config *vpif_cfg, - int input_index, - int *sub_device_index) +static int vpif_input_to_subdev( + struct vpif_capture_config *vpif_cfg, + struct vpif_capture_chan_config *chan_cfg, + int input_index) { - struct vpif_capture_chan_config *chan_cfg; - struct vpif_subdev_info *subdev_info = NULL; - const char *subdev_name = NULL; + struct vpif_subdev_info *subdev_info; + const char *subdev_name; int i; - vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); + vpif_dbg(2, debug, "vpif_input_to_subdev\n"); - chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - - /** - * search through the inputs to find the sub device supporting - * the input - */ - for (i = 0; i < chan_cfg->input_count; i++) { - /* For each sub device, loop through input */ - if (i == input_index) { - subdev_name = chan_cfg->inputs[i].subdev_name; - break; - } - } - - /* if reached maximum. return null */ - if (i == chan_cfg->input_count || (NULL == subdev_name)) - return subdev_info; + subdev_name = chan_cfg->inputs[input_index].subdev_name; + if (subdev_name == NULL) + return -1; /* loop through the sub device list to get the sub device info */ for (i = 0; i < vpif_cfg->subdev_count; i++) { subdev_info = &vpif_cfg->subdev_info[i]; if (!strcmp(subdev_info->name, subdev_name)) - break; + return i; } + return -1; +} - if (i == vpif_cfg->subdev_count) - return subdev_info; +/** + * vpif_set_input() - Select an input + * @vpif_cfg - global config ptr + * @ch - channel + * @_index - Given input index from application + * + * Select the given input. + */ +static int vpif_set_input( + struct vpif_capture_config *vpif_cfg, + struct channel_obj *ch, + int index) +{ + struct vpif_capture_chan_config *chan_cfg = + &vpif_cfg->chan_config[ch->channel_id]; + struct vpif_subdev_info *subdev_info = NULL; + struct v4l2_subdev *sd = NULL; + u32 input = 0, output = 0; + int sd_index; + int ret; - /* check if the sub device is registered */ - if (NULL == vpif_obj.sd[i]) - return NULL; + sd_index = vpif_input_to_subdev(vpif_cfg, chan_cfg, index); + if (sd_index >= 0) { + sd = vpif_obj.sd[sd_index]; + subdev_info = &vpif_cfg->subdev_info[sd_index]; + } - *sub_device_index = i; - return subdev_info; + /* first setup input path from sub device to vpif */ + if (sd && vpif_cfg->setup_input_path) { + ret = vpif_cfg->setup_input_path(ch->channel_id, + subdev_info->name); + if (ret < 0) { + vpif_dbg(1, debug, "couldn't setup input path for the" \ + " sub device %s, for input index %d\n", + subdev_info->name, index); + return ret; + } + } + + if (sd) { + input = chan_cfg->inputs[index].input_route; + output = chan_cfg->inputs[index].output_route; + ret = v4l2_subdev_call(sd, video, s_routing, + input, output, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + vpif_dbg(1, debug, "Failed to set input\n"); + return ret; + } + } + ch->input_idx = index; + ch->sd = sd; + /* copy interface parameters to vpif */ + ch->vpifparams.iface = subdev_info->vpif_if; + + /* update tvnorms from the sub device input info */ + ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; + return 0; } /** @@ -1323,12 +1334,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) vpif_dbg(2, debug, "vpif_querystd\n"); /* Call querystd function of decoder device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - querystd, std_id); - if (ret < 0) - vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); + ret = v4l2_subdev_call(ch->sd, video, querystd, std_id); - return ret; + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + return -ENODATA; + if (ret) { + vpif_dbg(1, debug, "Failed to query standard for sub devices\n"); + return ret; + } + + return 0; } /** @@ -1396,11 +1411,12 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) vpif_config_format(ch); /* set standard in the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_std, *std_id); - if (ret < 0) + ret = v4l2_subdev_call(ch->sd, core, s_std, *std_id); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - return ret; + return ret; + } + return 0; } /** @@ -1458,9 +1474,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct vpif_subdev_info *subdev_info; - int ret = 0, sd_index = 0; - u32 input = 0, output = 0; + int ret; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1485,43 +1499,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) return ret; fh->initialized = 1; - subdev_info = vpif_map_sub_device_to_input(ch, config, index, - &sd_index); - if (NULL == subdev_info) { - vpif_dbg(1, debug, - "couldn't lookup sub device for the input index\n"); - return -EINVAL; - } - - /* first setup input path from sub device to vpif */ - if (config->setup_input_path) { - ret = config->setup_input_path(ch->channel_id, - subdev_info->name); - if (ret < 0) { - vpif_dbg(1, debug, "couldn't setup input path for the" - " sub device %s, for input index %d\n", - subdev_info->name, index); - return ret; - } - } - - input = chan_cfg->inputs[index].input_route; - output = chan_cfg->inputs[index].output_route; - ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, - input, output, 0); - if (ret < 0 && ret != -ENOIOCTLCMD) { - vpif_dbg(1, debug, "Failed to set input\n"); - return ret; - } - ch->input_idx = index; - ch->curr_subdev_info = subdev_info; - ch->curr_sd_index = sd_index; - /* copy interface parameters to vpif */ - ch->vpifparams.iface = subdev_info->vpif_if; - - /* update tvnorms from the sub device input info */ - ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; - return 0; + return vpif_set_input(config, ch, index); } /** @@ -1727,9 +1705,12 @@ vpif_enum_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; + int ret; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, enum_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -EINVAL; + return ret; } /** @@ -1744,9 +1725,12 @@ vpif_query_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; + int ret; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, query_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, query_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -ENODATA; + return ret; } /** @@ -1772,13 +1756,9 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -EINVAL; - } + ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + ret = 0; if (ret < 0) { vpif_dbg(2, debug, "Error setting custom DV timings\n"); return ret; @@ -1903,8 +1883,7 @@ static int vpif_dbg_g_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - g_register, reg); + return v4l2_subdev_call(ch->sd, core, g_register, reg); } /* @@ -1921,8 +1900,7 @@ static int vpif_dbg_s_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_register, reg); + return v4l2_subdev_call(ch->sd, core, s_register, reg); } #endif @@ -2180,6 +2158,11 @@ static __init int vpif_probe(struct platform_device *pdev) v4l2_prio_init(&ch->prio); video_set_drvdata(ch->video_dev, ch); + /* select input 0 */ + err = vpif_set_input(config, ch, 0); + if (err) + goto probe_out; + err = video_register_device(ch->video_dev, VFL_TYPE_GRABBER, (j ? 1 : 0)); if (err) diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index 760964c..3d3c1e5 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h @@ -117,12 +117,10 @@ struct channel_obj { u8 initialized; /* Identifies channel */ enum vpif_channel_id channel_id; - /* index into sd table */ - int curr_sd_index; /* Current input */ u32 input_idx; - /* ptr to current sub device information */ - struct vpif_subdev_info *curr_subdev_info; + /* subdev corresponding to the current input, may be NULL */ + struct v4l2_subdev *sd; /* vpif configuration params */ struct vpif_params vpifparams; /* common object array */ -- cgit v0.10.2 From 882084ad0f9791f2e8386ba3f9f3836f0c3e9fa6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:31 -0300 Subject: [media] vpif_display: use a v4l2_subdev pointer to call a subdev This makes it easier to have outputs without subdevs. This needs more work. The way the outputs are configured should be identical to how inputs are configured. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 4e28000..6229e48 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1246,6 +1246,8 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i) vpif_err("Failed to set output standard\n"); ch->output_idx = i; + if (vpif_obj.sd[i]) + ch->sd = vpif_obj.sd[i]; return ret; } @@ -1317,14 +1319,13 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->output_idx], - video, s_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); if (ret == -ENOIOCTLCMD) { vpif_dbg(2, debug, "Custom DV timings not supported by " "subdevice\n"); - return -EINVAL; + return -ENODATA; } - if (ret < 0) { + if (ret < 0 && ret != -ENODEV) { vpif_dbg(2, debug, "Error setting custom DV timings\n"); return ret; } @@ -1449,8 +1450,7 @@ static int vpif_dbg_g_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->output_idx], core, - g_register, reg); + return v4l2_subdev_call(ch->sd, core, g_register, reg); } /* @@ -1467,8 +1467,7 @@ static int vpif_dbg_s_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->output_idx], core, - s_register, reg); + return v4l2_subdev_call(ch->sd, core, s_register, reg); } #endif @@ -1739,6 +1738,8 @@ static __init int vpif_probe(struct platform_device *pdev) } ch->initialized = 0; + if (subdev_count) + ch->sd = vpif_obj.sd[0]; ch->channel_id = j; if (j < 2) ch->common[VPIF_VIDEO_INDEX].numbuffers = diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index 532ee9e..a5a18f7 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h @@ -125,6 +125,7 @@ struct channel_obj { u8 initialized; /* flag to indicate whether * encoder is initialized */ u32 output_idx; /* Current output index */ + struct v4l2_subdev *sd; /* Current output subdev(may be NULL) */ enum vpif_channel_id channel_id;/* Identifies channel */ struct vpif_params vpifparams; -- cgit v0.10.2 From 0d4f35f3f0044303abfff57441dd1e98f96ea935 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:32 -0300 Subject: [media] davinci: move struct vpif_interface to chan_cfg struct vpif_interface is channel specific, not subdev specific. Move it to the channel config. Signed-off-by: Hans Verkuil Acked-by: Sekhar Nori Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 87bd249..8663df3 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1213,12 +1213,6 @@ static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5d), .platform_data = &tvp5146_pdata, }, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, { .name = TVP5147_CH1, @@ -1226,12 +1220,6 @@ static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5c), .platform_data = &tvp5146_pdata, }, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, }; @@ -1241,10 +1229,22 @@ static struct vpif_capture_config da850_vpif_capture_config = { .chan_config[0] = { .inputs = da850_ch0_inputs, .input_count = ARRAY_SIZE(da850_ch0_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, .chan_config[1] = { .inputs = da850_ch1_inputs, .input_count = ARRAY_SIZE(da850_ch1_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, .card_name = "DA850/OMAP-L138 Video Capture", }; diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 6f329ca..2647b89 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -601,12 +601,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5d), .platform_data = &tvp5146_pdata, }, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, { .name = TVP5147_CH1, @@ -614,12 +608,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5c), .platform_data = &tvp5146_pdata, }, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, }; @@ -661,10 +649,22 @@ static struct vpif_capture_config dm646x_vpif_capture_cfg = { .chan_config[0] = { .inputs = dm6467_ch0_inputs, .input_count = ARRAY_SIZE(dm6467_ch0_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, .chan_config[1] = { .inputs = dm6467_ch1_inputs, .input_count = ARRAY_SIZE(dm6467_ch1_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, }; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index c4db0ef..83b80baf 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1310,7 +1310,7 @@ static int vpif_set_input( ch->input_idx = index; ch->sd = sd; /* copy interface parameters to vpif */ - ch->vpifparams.iface = subdev_info->vpif_if; + ch->vpifparams.iface = chan_cfg->vpif_if; /* update tvnorms from the sub device input info */ ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h index a422ed0..65e8fe1 100644 --- a/include/media/davinci/vpif_types.h +++ b/include/media/davinci/vpif_types.h @@ -37,7 +37,6 @@ struct vpif_interface { struct vpif_subdev_info { const char *name; struct i2c_board_info board_info; - struct vpif_interface vpif_if; }; struct vpif_display_config { @@ -59,6 +58,7 @@ struct vpif_input { }; struct vpif_capture_chan_config { + struct vpif_interface vpif_if; const struct vpif_input *inputs; int input_count; }; -- cgit v0.10.2 From c389648a927bada928c854dccccf0301317784eb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Sep 2012 09:06:33 -0300 Subject: [media] tvp514x: s_routing should just change routing, not try to detect a signal The s_routing function should not try to detect a signal. It is a really bad idea to try to detect a valid video signal and return an error if you can't. Changing input should do just that and nothing more. Also don't power on the ADCs on s_routing, instead do that on querystd. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Tested-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 1f3943b..d5e1021 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -519,6 +519,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) *std_id = V4L2_STD_UNKNOWN; + /* To query the standard the TVP514x must power on the ADCs. */ + if (!decoder->streaming) { + tvp514x_s_stream(sd, 1); + msleep(LOCK_RETRY_DELAY); + } + /* query the current standard */ current_std = tvp514x_query_current_std(sd); if (current_std == STD_INVALID) @@ -625,25 +631,12 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, int err; enum tvp514x_input input_sel; enum tvp514x_output output_sel; - u8 sync_lock_status, lock_mask; - int try_count = LOCK_RETRY_COUNT; if ((input >= INPUT_INVALID) || (output >= OUTPUT_INVALID)) /* Index out of bound */ return -EINVAL; - /* - * For the sequence streamon -> streamoff and again s_input - * it fails to lock the signal, since streamoff puts TVP514x - * into power off state which leads to failure in sub-sequent s_input. - * - * So power up the TVP514x device here, since it is important to lock - * the signal at this stage. - */ - if (!decoder->streaming) - tvp514x_s_stream(sd, 1); - input_sel = input; output_sel = output; @@ -660,64 +653,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel; decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel; - - /* Clear status */ - msleep(LOCK_RETRY_DELAY); - err = - tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01); - if (err) - return err; - - switch (input_sel) { - case INPUT_CVBS_VI1A: - case INPUT_CVBS_VI1B: - case INPUT_CVBS_VI1C: - case INPUT_CVBS_VI2A: - case INPUT_CVBS_VI2B: - case INPUT_CVBS_VI2C: - case INPUT_CVBS_VI3A: - case INPUT_CVBS_VI3B: - case INPUT_CVBS_VI3C: - case INPUT_CVBS_VI4A: - lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT | - STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - - case INPUT_SVIDEO_VI2A_VI1A: - case INPUT_SVIDEO_VI2B_VI1B: - case INPUT_SVIDEO_VI2C_VI1C: - case INPUT_SVIDEO_VI2A_VI3A: - case INPUT_SVIDEO_VI2B_VI3B: - case INPUT_SVIDEO_VI2C_VI3C: - case INPUT_SVIDEO_VI4A_VI1A: - case INPUT_SVIDEO_VI4A_VI1B: - case INPUT_SVIDEO_VI4A_VI1C: - case INPUT_SVIDEO_VI4A_VI3A: - case INPUT_SVIDEO_VI4A_VI3B: - case INPUT_SVIDEO_VI4A_VI3C: - lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - /* Need to add other interfaces*/ - default: - return -EINVAL; - } - - while (try_count-- > 0) { - /* Allow decoder to sync up with new input */ - msleep(LOCK_RETRY_DELAY); - - sync_lock_status = tvp514x_read_reg(sd, - REG_STATUS1); - if (lock_mask == (sync_lock_status & lock_mask)) - /* Input detected */ - break; - } - - if (try_count < 0) - return -EINVAL; - decoder->input = input; decoder->output = output; -- cgit v0.10.2 From 2bd4e58c9d00325b7a850b2ac73fd902e9148b77 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 25 Sep 2012 08:11:49 -0300 Subject: [media] media: davinci: vpif: display: separate out subdev from output vpif_display relied on a 1-1 mapping of output and subdev. This is not necessarily the case. Separate the two. So there is a list of subdevs and a list of outputs. Each output refers to a subdev and has routing information. An output does not have to have a subdev. The initial output for each channel is set to the fist output. Currently missing is support for associating multiple subdevs with an output. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 8663df3..bc6b8c7 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -46,6 +46,7 @@ #include #include +#include #define DA850_EVM_PHY_ID "davinci_mdio-0:00" #define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8) @@ -1259,16 +1260,38 @@ static struct vpif_subdev_info da850_vpif_subdev[] = { }, }; -static const char const *vpif_output[] = { - "Composite", - "S-Video", +static const struct vpif_output da850_ch0_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPOSITE_ID, + }, + { + .output = { + .index = 1, + .name = "S-Video", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_SVIDEO_ID, + }, }; static struct vpif_display_config da850_vpif_display_config = { .subdevinfo = da850_vpif_subdev, .subdev_count = ARRAY_SIZE(da850_vpif_subdev), - .output = vpif_output, - .output_count = ARRAY_SIZE(vpif_output), + .chan_config[0] = { + .outputs = da850_ch0_outputs, + .output_count = ARRAY_SIZE(da850_ch0_outputs), + }, .card_name = "DA850/OMAP-L138 Video Display", }; diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 2647b89..fac92f5 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -496,18 +497,49 @@ static struct vpif_subdev_info dm646x_vpif_subdev[] = { }, }; -static const char *output[] = { - "Composite", - "Component", - "S-Video", +static const struct vpif_output dm6467_ch0_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPOSITE_ID, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPONENT_ID, + }, + { + .output = { + .index = 2, + .name = "S-Video", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_SVIDEO_ID, + }, }; static struct vpif_display_config dm646x_vpif_display_config = { .set_clock = set_vpif_clock, .subdevinfo = dm646x_vpif_subdev, .subdev_count = ARRAY_SIZE(dm646x_vpif_subdev), - .output = output, - .output_count = ARRAY_SIZE(output), + .chan_config[0] = { + .outputs = dm6467_ch0_outputs, + .output_count = ARRAY_SIZE(dm6467_ch0_outputs), + }, .card_name = "DM646x EVM", }; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 6229e48..ae8329d 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -308,7 +308,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) channel2_intr_assert(); channel2_intr_enable(1); enable_channel2(1); - if (vpif_config_data->ch2_clip_en) + if (vpif_config_data->chan_config[VPIF_CHANNEL2_VIDEO].clip_en) channel2_clipping_enable(1); } @@ -317,7 +317,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) channel3_intr_assert(); channel3_intr_enable(1); enable_channel3(1); - if (vpif_config_data->ch3_clip_en) + if (vpif_config_data->chan_config[VPIF_CHANNEL3_VIDEO].clip_en) channel3_clipping_enable(1); } @@ -1174,14 +1174,16 @@ static int vpif_streamoff(struct file *file, void *priv, if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - if (vpif_config_data->ch2_clip_en) + if (vpif_config_data-> + chan_config[VPIF_CHANNEL2_VIDEO].clip_en) channel2_clipping_enable(0); enable_channel2(0); channel2_intr_enable(0); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (2 == common->started)) { - if (vpif_config_data->ch3_clip_en) + if (vpif_config_data-> + chan_config[VPIF_CHANNEL3_VIDEO].clip_en) channel3_clipping_enable(0); enable_channel3(0); channel3_intr_enable(0); @@ -1214,41 +1216,118 @@ static int vpif_enum_output(struct file *file, void *fh, { struct vpif_display_config *config = vpif_dev->platform_data; + struct vpif_display_chan_config *chan_cfg; + struct vpif_fh *vpif_handler = fh; + struct channel_obj *ch = vpif_handler->channel; - if (output->index >= config->output_count) { + chan_cfg = &config->chan_config[ch->channel_id]; + if (output->index >= chan_cfg->output_count) { vpif_dbg(1, debug, "Invalid output index\n"); return -EINVAL; } - strcpy(output->name, config->output[output->index]); - output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->std = VPIF_V4L2_STD; + *output = chan_cfg->outputs[output->index].output; + return 0; +} + +/** + * vpif_output_to_subdev() - Maps output to sub device + * @vpif_cfg - global config ptr + * @chan_cfg - channel config ptr + * @index - Given output index from application + * + * lookup the sub device information for a given output index. + * we report all the output to application. output table also + * has sub device name for the each output + */ +static int +vpif_output_to_subdev(struct vpif_display_config *vpif_cfg, + struct vpif_display_chan_config *chan_cfg, int index) +{ + struct vpif_subdev_info *subdev_info; + const char *subdev_name; + int i; + + vpif_dbg(2, debug, "vpif_output_to_subdev\n"); + + if (chan_cfg->outputs == NULL) + return -1; + + subdev_name = chan_cfg->outputs[index].subdev_name; + if (subdev_name == NULL) + return -1; + + /* loop through the sub device list to get the sub device info */ + for (i = 0; i < vpif_cfg->subdev_count; i++) { + subdev_info = &vpif_cfg->subdevinfo[i]; + if (!strcmp(subdev_info->name, subdev_name)) + return i; + } + return -1; +} + +/** + * vpif_set_output() - Select an output + * @vpif_cfg - global config ptr + * @ch - channel + * @index - Given output index from application + * + * Select the given output. + */ +static int vpif_set_output(struct vpif_display_config *vpif_cfg, + struct channel_obj *ch, int index) +{ + struct vpif_display_chan_config *chan_cfg = + &vpif_cfg->chan_config[ch->channel_id]; + struct vpif_subdev_info *subdev_info = NULL; + struct v4l2_subdev *sd = NULL; + u32 input = 0, output = 0; + int sd_index; + int ret; + + sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index); + if (sd_index >= 0) { + sd = vpif_obj.sd[sd_index]; + subdev_info = &vpif_cfg->subdevinfo[sd_index]; + } + if (sd) { + input = chan_cfg->outputs[index].input_route; + output = chan_cfg->outputs[index].output_route; + ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + vpif_err("Failed to set output\n"); + return ret; + } + + } + ch->output_idx = index; + ch->sd = sd; + if (chan_cfg->outputs != NULL) + /* update tvnorms from the sub device output info */ + ch->video_dev->tvnorms = chan_cfg->outputs[index].output.std; return 0; } static int vpif_s_output(struct file *file, void *priv, unsigned int i) { + struct vpif_display_config *config = vpif_dev->platform_data; + struct vpif_display_chan_config *chan_cfg; struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; + + chan_cfg = &config->chan_config[ch->channel_id]; + + if (i >= chan_cfg->output_count) + return -EINVAL; if (common->started) { vpif_err("Streaming in progress\n"); return -EBUSY; } - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_routing, 0, i, 0); - - if (ret < 0) - vpif_err("Failed to set output standard\n"); - - ch->output_idx = i; - if (vpif_obj.sd[i]) - ch->sd = vpif_obj.sd[i]; - return ret; + return vpif_set_output(config, ch, i); } static int vpif_g_output(struct file *file, void *priv, unsigned int *i) @@ -1291,9 +1370,12 @@ vpif_enum_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; + int ret; - return v4l2_subdev_call(vpif_obj.sd[ch->output_idx], - video, enum_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -EINVAL; + return ret; } /** @@ -1320,12 +1402,9 @@ static int vpif_s_dv_timings(struct file *file, void *priv, /* Configure subdevice timings, if any */ ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -ENODATA; - } - if (ret < 0 && ret != -ENODEV) { + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + ret = 0; + if (ret < 0) { vpif_dbg(2, debug, "Error setting custom DV timings\n"); return ret; } @@ -1531,9 +1610,6 @@ static struct video_device vpif_video_template = { .name = "vpif", .fops = &vpif_fops, .ioctl_ops = &vpif_ioctl_ops, - .tvnorms = VPIF_V4L2_STD, - .current_norm = V4L2_STD_625_50, - }; /*Configure the channels, buffer sizei, request irq */ @@ -1756,6 +1832,11 @@ static __init int vpif_probe(struct platform_device *pdev) ch->video_dev->lock = &common->lock; video_set_drvdata(ch->video_dev, ch); + /* select output 0 */ + err = vpif_set_output(config, ch, 0); + if (err) + goto probe_out; + /* register video device */ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", (int)ch, (int)&ch->video_dev); diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h index 65e8fe1..3882e06 100644 --- a/include/media/davinci/vpif_types.h +++ b/include/media/davinci/vpif_types.h @@ -20,6 +20,7 @@ #include #define VPIF_CAPTURE_MAX_CHANNELS 2 +#define VPIF_DISPLAY_MAX_CHANNELS 2 enum vpif_if_type { VPIF_IF_BT656, @@ -39,15 +40,25 @@ struct vpif_subdev_info { struct i2c_board_info board_info; }; +struct vpif_output { + struct v4l2_output output; + const char *subdev_name; + u32 input_route; + u32 output_route; +}; + +struct vpif_display_chan_config { + const struct vpif_output *outputs; + int output_count; + bool clip_en; +}; + struct vpif_display_config { int (*set_clock)(int, int); struct vpif_subdev_info *subdevinfo; int subdev_count; - const char **output; - int output_count; + struct vpif_display_chan_config chan_config[VPIF_DISPLAY_MAX_CHANNELS]; const char *card_name; - bool ch2_clip_en; - bool ch3_clip_en; }; struct vpif_input { -- cgit v0.10.2 From b4a711e7bf59e556d5f692e0c65ef12c6dad6cf8 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 3 Oct 2012 10:01:07 -0300 Subject: [media] media: davinci: vpif: Add return code check at vb2_queue_init() from commit with id 896f38f582730a19eb49677105b4fe4c0270b82e it's mandatory to check the return code of vb2_queue_init(). Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 83b80baf..cabd5a2 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -976,6 +976,7 @@ static int vpif_reqbufs(struct file *file, void *priv, struct common_obj *common; u8 index = 0; struct vb2_queue *q; + int ret; vpif_dbg(2, debug, "vpif_reqbufs\n"); @@ -1015,8 +1016,12 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_cap_buffer); - vb2_queue_init(q); - + ret = vb2_queue_init(q); + if (ret) { + vpif_err("vpif_capture: vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); + return ret; + } /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; /* Increment io usrs member of channel object to 1 */ diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index ae8329d..7f20ca5 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -936,6 +936,7 @@ static int vpif_reqbufs(struct file *file, void *priv, enum v4l2_field field; struct vb2_queue *q; u8 index = 0; + int ret; /* This file handle has not initialized the channel, It is not allowed to do settings */ @@ -981,8 +982,12 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_disp_buffer); - vb2_queue_init(q); - + ret = vb2_queue_init(q); + if (ret) { + vpif_err("vpif_display: vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); + return ret; + } /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; /* Increment io usrs member of channel object to 1 */ -- cgit v0.10.2 From 626d533f8cb63b6c0cd6b83e1ce7e7656ccaba84 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 25 Sep 2012 11:21:55 -0300 Subject: [media] media: davinci: vpif: set device capabilities set device_caps and also change the driver and bus_info to proper values as per standard. Signed-off-by: Lad, Prabhakar Signed-off-by: Manjunath Hadli Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index cabd5a2..fcabc02 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1635,9 +1635,11 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_capture_config *config = vpif_dev->platform_data; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); - strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(vpif_dev)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 7f20ca5..b716fbd 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -827,9 +827,11 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_display_config *config = vpif_dev->platform_data; - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); - strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(vpif_dev)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; -- cgit v0.10.2 From 32a772603173f9e1bf675c01e4649e3fe3b794bc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 28 Sep 2012 06:12:53 -0300 Subject: [media] videobuf2-core: move plane verification out of __fill_v4l2/vb_buffer The plane verification should be done before actually queuing or dequeuing buffers, so move it out of __fill_v4l2_buffer and __fill_vb_buffer and call it as a separate step. This also makes it possible to change the return type of __fill_v4l2/vb_buffer to void. The dqbuf case took some special care: before removing a buffer from the done_list you have to verify that the receiving v4l2_buffer has enough room for all the planes. The number of planes can differ between buffers due to the fact that buffers for other formats can be prepared using VIDIOC_PREPARE_BUF. Signed-off-by: Hans Verkuil Reviewed-by: Sylwester Nawrocki Tested-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index e6a26b4..5a132b2 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -276,6 +276,9 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) */ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) { + if (!V4L2_TYPE_IS_MULTIPLANAR(b->type)) + return 0; + /* Is memory for copying plane information present? */ if (NULL == b->m.planes) { dprintk(1, "Multi-planar buffer passed but " @@ -331,10 +334,9 @@ static bool __buffers_in_use(struct vb2_queue *q) * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace */ -static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) +static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - int ret; /* Copy back data such as timestamp, flags, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); @@ -342,13 +344,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->reserved = vb->v4l2_buf.reserved; if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - /* * Fill in plane-related data if userspace provided an array - * for it. The memory and size is verified above. + * for it. The caller has already verified memory and size. */ memcpy(b->m.planes, vb->v4l2_planes, b->length * sizeof(struct v4l2_plane)); @@ -391,8 +389,6 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) if (__buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; - - return 0; } /** @@ -411,6 +407,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) { struct vb2_buffer *vb; + int ret; if (b->type != q->type) { dprintk(1, "querybuf: wrong buffer type\n"); @@ -422,8 +419,10 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) return -EINVAL; } vb = q->bufs[b->index]; - - return __fill_v4l2_buffer(vb, b); + ret = __verify_planes_array(vb, b); + if (!ret) + __fill_v4l2_buffer(vb, b); + return ret; } EXPORT_SYMBOL(vb2_querybuf); @@ -813,24 +812,16 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) EXPORT_SYMBOL_GPL(vb2_buffer_done); /** - * __fill_vb2_buffer() - fill a vb2_buffer with information provided in - * a v4l2_buffer by the userspace + * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a + * v4l2_buffer by the userspace. The caller has already verified that struct + * v4l2_buffer has a valid number of planes. */ -static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, +static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, struct v4l2_plane *v4l2_planes) { unsigned int plane; - int ret; if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { - /* - * Verify that the userspace gave us a valid array for - * plane information. - */ - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - /* Fill in driver-provided information for OUTPUT types */ if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* @@ -872,8 +863,6 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; - - return 0; } /** @@ -888,10 +877,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); - /* Verify and copy relevant information provided by the userspace */ - ret = __fill_vb2_buffer(vb, b, planes); - if (ret) - return ret; + /* Copy relevant information provided by the userspace */ + __fill_vb2_buffer(vb, b, planes); for (plane = 0; plane < vb->num_planes; ++plane) { /* Skip the plane if already verified */ @@ -966,7 +953,8 @@ err: */ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) { - return __fill_vb2_buffer(vb, b, vb->v4l2_planes); + __fill_vb2_buffer(vb, b, vb->v4l2_planes); + return 0; } /** @@ -1059,7 +1047,9 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); return -EINVAL; } - + ret = __verify_planes_array(vb, b); + if (ret < 0) + return ret; ret = __buf_prepare(vb, b); if (ret < 0) return ret; @@ -1147,6 +1137,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) ret = -EINVAL; goto unlock; } + ret = __verify_planes_array(vb, b); + if (ret) + goto unlock; switch (vb->state) { case VB2_BUF_STATE_DEQUEUED: @@ -1243,8 +1236,10 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * the locks or return an error if one occurred. */ call_qop(q, wait_finish, q); - if (ret) + if (ret) { + dprintk(1, "Sleep was interrupted\n"); return ret; + } } return 0; } @@ -1255,7 +1250,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * Will sleep if required for nonblocking == false. */ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, - int nonblocking) + struct v4l2_buffer *b, int nonblocking) { unsigned long flags; int ret; @@ -1273,10 +1268,16 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, */ spin_lock_irqsave(&q->done_lock, flags); *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); - list_del(&(*vb)->done_entry); + /* + * Only remove the buffer from done_list if v4l2_buffer can handle all + * the planes. + */ + ret = __verify_planes_array(*vb, b); + if (!ret) + list_del(&(*vb)->done_entry); spin_unlock_irqrestore(&q->done_lock, flags); - return 0; + return ret; } /** @@ -1335,12 +1336,9 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) dprintk(1, "dqbuf: invalid buffer type\n"); return -EINVAL; } - - ret = __vb2_get_done_vb(q, &vb, nonblocking); - if (ret < 0) { - dprintk(1, "dqbuf: error getting next done buffer\n"); + ret = __vb2_get_done_vb(q, &vb, b, nonblocking); + if (ret < 0) return ret; - } ret = call_qop(q, buf_finish, vb); if (ret) { -- cgit v0.10.2 From 3c0b60618118745220bc0f9bf27e51e37367427c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 28 Sep 2012 06:24:18 -0300 Subject: [media] videobuf2-core: fill in length field for multiplanar buffers length should be set to num_planes in __fill_v4l2_buffer(). That way the caller knows how many planes there are in the buffer. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 5a132b2..432df11 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -348,6 +348,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) * Fill in plane-related data if userspace provided an array * for it. The caller has already verified memory and size. */ + b->length = vb->num_planes; memcpy(b->m.planes, vb->v4l2_planes, b->length * sizeof(struct v4l2_plane)); } else { -- cgit v0.10.2 From 96b1a70226cd43f69c63a7ba2a769bece08cf64e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 19 Sep 2012 10:14:41 -0300 Subject: [media] v4l2-ioctl.c: handle PREPARE_BUF like QUERYBUF The core code for PREPARE_BUF didn't take the multiplanar case into account, which might cause page faults. Handle PREPARE_BUF just like QUERYBUF and QBUF/DQBUF. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 9d3e46c..16205d9 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2188,6 +2188,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, int ret = 0; switch (cmd) { + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: { -- cgit v0.10.2 From e3b1b4e732e18befcfa428bac1c487f681fbc36a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 19 Sep 2012 11:14:39 -0300 Subject: [media] DocBook: various updates w.r.t. v4l2_buffer and multiplanar Clarify the behavior of v4l2_buffer in the multiplanar case, including fixing a false statement: you can't set m.planes to NULL when calling DQBUF. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 97f785a..b5d1cbd 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -677,8 +677,10 @@ memory, set by the application. See for details. length Size of the buffer (not the payload) in bytes for the - single-planar API. For the multi-planar API should contain the - number of elements in the planes array. + single-planar API. For the multi-planar API the application sets + this to the number of elements in the planes + array. The driver will fill in the actual number of valid elements in + that array. diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml index 6a821a6..2d37abe 100644 --- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml @@ -121,8 +121,7 @@ remaining fields or returns an error code. The driver may also set field. It indicates a non-critical (recoverable) streaming error. In such case the application may continue as normal, but should be aware that data in the dequeued buffer might be corrupted. When using the multi-planar API, the -planes array does not have to be passed; the m.planes -member must be set to NULL in that case. +planes array must be passed in as well. By default VIDIOC_DQBUF blocks when no buffer is in the outgoing queue. When the diff --git a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml index 6e414d7..a597155 100644 --- a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml @@ -48,8 +48,8 @@ Description - This ioctl is part of the memory -mapping I/O method. It can be used to query the status of a + This ioctl is part of the streaming + I/O method. It can be used to query the status of a buffer at any time after buffers have been allocated with the &VIDIOC-REQBUFS; ioctl. @@ -71,6 +71,7 @@ the structure. In the flags field the V4L2_BUF_FLAG_MAPPED, +V4L2_BUF_FLAG_PREPARED, V4L2_BUF_FLAG_QUEUED and V4L2_BUF_FLAG_DONE flags will be valid. The memory field will be set to the current @@ -79,8 +80,10 @@ contains the offset of the buffer from the start of the device memory, the length field its size. For the multi-planar API, fields m.mem_offset and length in the m.planes -array elements will be used instead. The driver may or may not set the remaining -fields and flags, they are meaningless in this context. +array elements will be used instead and the length +field of &v4l2-buffer; is set to the number of filled-in array elements. +The driver may or may not set the remaining fields and flags, they are +meaningless in this context. The v4l2_buffer structure is specified in . -- cgit v0.10.2 From 73f56c239f341f14cd1591fb0c3aafc673f4d409 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 17 Sep 2012 06:02:31 -0300 Subject: [media] ARM: samsung: Remove unused fields from FIMC and CSIS platform data The MIPI-CSI2 bus data alignment is now being derived from the media bus pixel code, the drivers don't use the corresponding structure fields, so remove them. Also remove the s5p_csis_phy_enable callback which is now used directly by s5p-csis driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Kukjin Kim Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index ea785fc..12ff01d 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1180,9 +1180,7 @@ static struct platform_device cam_8m_12v_fixed_rdev = { static struct s5p_platform_mipi_csis mipi_csis_platdata = { .clk_rate = 166000000UL, .lanes = 2, - .alignment = 32, .hs_settle = 12, - .phy_enable = s5p_csis_phy_enable, }; #define GPIO_CAM_MEGA_RST EXYNOS4_GPY3(7) /* ISP_RESET */ @@ -1226,7 +1224,6 @@ static struct s5p_fimc_isp_info nuri_camera_sensors[] = { .bus_type = FIMC_MIPI_CSI2, .board_info = &m5mols_board_info, .clk_frequency = 24000000UL, - .csi_data_align = 32, }, }; diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 4d1f40d..acd2e9d 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -942,9 +942,7 @@ static struct platform_device cam_s_if_fixed_reg_dev = { static struct s5p_platform_mipi_csis mipi_csis_platdata = { .clk_rate = 166000000UL, .lanes = 2, - .alignment = 32, .hs_settle = 12, - .phy_enable = s5p_csis_phy_enable, }; #define GPIO_CAM_LEVEL_EN(n) EXYNOS4_GPE4(n + 3) @@ -1008,7 +1006,6 @@ static struct s5p_fimc_isp_info universal_camera_sensors[] = { .board_info = &m5mols_board_info, .i2c_bus_num = 0, .clk_frequency = 24000000UL, - .csi_data_align = 32, }, }; -- cgit v0.10.2 From 69a3d4f7b3f976192f8ac1ab760a026c737d0d56 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 17 Sep 2012 06:02:48 -0300 Subject: [media] ARM: samsung: Change __s5p_mipi_phy_control() function signature Replace pdev argument __s5p_mipi_phy_control() helper with plain int so MIPI-CSIS hardware instance index can be passed directly making the function usable on platforms instantiated from device tree. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Kukjin Kim Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/plat-samsung/setup-mipiphy.c b/arch/arm/plat-samsung/setup-mipiphy.c index 683c466..1474593 100644 --- a/arch/arm/plat-samsung/setup-mipiphy.c +++ b/arch/arm/plat-samsung/setup-mipiphy.c @@ -14,24 +14,18 @@ #include #include -static int __s5p_mipi_phy_control(struct platform_device *pdev, - bool on, u32 reset) +static int __s5p_mipi_phy_control(int id, bool on, u32 reset) { static DEFINE_SPINLOCK(lock); void __iomem *addr; unsigned long flags; - int pid; u32 cfg; - if (!pdev) + id = max(0, id); + if (id > 1) return -EINVAL; - pid = (pdev->id == -1) ? 0 : pdev->id; - - if (pid != 0 && pid != 1) - return -EINVAL; - - addr = S5P_MIPI_DPHY_CONTROL(pid); + addr = S5P_MIPI_DPHY_CONTROL(id); spin_lock_irqsave(&lock, flags); @@ -52,12 +46,12 @@ static int __s5p_mipi_phy_control(struct platform_device *pdev, return 0; } -int s5p_csis_phy_enable(struct platform_device *pdev, bool on) +int s5p_csis_phy_enable(int id, bool on) { - return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_SRESETN); + return __s5p_mipi_phy_control(id, on, S5P_MIPI_DPHY_SRESETN); } int s5p_dsim_phy_enable(struct platform_device *pdev, bool on) { - return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_MRESETN); + return __s5p_mipi_phy_control(pdev->id, on, S5P_MIPI_DPHY_MRESETN); } -- cgit v0.10.2 From 29de2337f9816865c8ac1894fdb16aacefe6c9ed Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 17 Sep 2012 06:03:50 -0300 Subject: [media] s5p-csis: Change regulator supply names Rename the regulator supply names to more meaningful ones. It's a prerequisite for adding device tree support. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index 9555ded..3438ccf 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -2,7 +2,7 @@ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver * * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki, + * Sylwester Nawrocki * * 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 @@ -115,8 +115,8 @@ static char *csi_clock_name[] = { #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) static const char * const csis_supply_name[] = { - "vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */ - "vdd18", /* VDD 1.8V and MIPI CSI PLL supply */ + "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ + "vddio", /* CSIS I/O and PLL (1.8V) supply */ }; #define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) -- cgit v0.10.2 From c421a1e418b191c8fb632dc5261b61acec6541ca Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 17 Sep 2012 06:04:12 -0300 Subject: [media] ARM: EXYNOS: Change MIPI-CSIS device regulator supply names Rename MIPI-CSIS regulator supply names to match definitions in the driver after commit "s5p-csis: Change regulator supply names". Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Kukjin Kim Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 12ff01d..16109b5 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -378,10 +378,10 @@ static struct regulator_consumer_supply __initdata max8997_ldo1_[] = { }; static struct regulator_consumer_supply __initdata max8997_ldo3_[] = { REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"), /* USB */ - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata max8997_ldo4_[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata max8997_ldo5_[] = { REGULATOR_SUPPLY("vhsic", "modemctl"), /* MODEM */ diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 4e574c2..a54ce4e 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -96,12 +96,12 @@ static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { }; static struct regulator_consumer_supply __initdata ldo3_consumer[] = { - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), /* MIPI */ REGULATOR_SUPPLY("vdd", "exynos4-hdmi"), /* HDMI */ REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"), /* HDMI */ }; static struct regulator_consumer_supply __initdata ldo6_consumer[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata ldo7_consumer[] = { REGULATOR_SUPPLY("avdd", "alc5625"), /* Realtek ALC5625 */ diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index acd2e9d..1cb7c11 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -209,7 +209,7 @@ static struct regulator_consumer_supply lp3974_ldo3_consumer[] = { REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"), REGULATOR_SUPPLY("vdd", "exynos4-hdmi"), REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"), - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), }; static struct regulator_init_data lp3974_ldo3_data = { @@ -273,7 +273,7 @@ static struct regulator_init_data lp3974_ldo6_data = { }; static struct regulator_consumer_supply lp3974_ldo7_consumer[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), }; static struct regulator_init_data lp3974_ldo7_data = { -- cgit v0.10.2 From ccbfd1d49dc0d6a6edab827ab4888cf93348f249 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 17 Sep 2012 06:03:10 -0300 Subject: [media] s5p-csis: Replace phy_enable platform data callback with direct call The phy_enable callback is common for all Samsung SoC platforms, replace it with direct function call so the MIPI-CSI2 DPHY control is also possible on device tree instantiated platforms. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index 22bdf21..983e81f 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -160,6 +160,7 @@ struct csis_pktbuf { * protecting @format and @flags members * @pads: CSIS pads array * @sd: v4l2_subdev associated with CSIS device instance + * @index: the hardware instance index * @pdev: CSIS platform device * @regs: mmaped I/O registers memory * @supplies: CSIS regulator supplies @@ -176,6 +177,7 @@ struct csis_state { struct mutex lock; struct media_pad pads[CSIS_PADS_NUM]; struct v4l2_subdev sd; + u8 index; struct platform_device *pdev; void __iomem *regs; struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; @@ -666,14 +668,15 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) spin_lock_init(&state->slock); state->pdev = pdev; + state->index = max(0, pdev->id); pdata = pdev->dev.platform_data; - if (pdata == NULL || pdata->phy_enable == NULL) { + if (pdata == NULL) { dev_err(&pdev->dev, "Platform data not fully specified\n"); return -EINVAL; } - if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || + if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) || pdata->lanes > CSIS0_MAX_LANES) { dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", pdata->lanes); @@ -756,7 +759,6 @@ e_clkput: static int s5pcsis_pm_suspend(struct device *dev, bool runtime) { - struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csis_state *state = sd_to_csis_state(sd); @@ -768,7 +770,7 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime) mutex_lock(&state->lock); if (state->flags & ST_POWERED) { s5pcsis_stop_stream(state); - ret = pdata->phy_enable(state->pdev, false); + ret = s5p_csis_phy_enable(state->index, false); if (ret) goto unlock; ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, @@ -787,7 +789,6 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime) static int s5pcsis_pm_resume(struct device *dev, bool runtime) { - struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csis_state *state = sd_to_csis_state(sd); @@ -805,7 +806,7 @@ static int s5pcsis_pm_resume(struct device *dev, bool runtime) state->supplies); if (ret) goto unlock; - ret = pdata->phy_enable(state->pdev, true); + ret = s5p_csis_phy_enable(state->index, true); if (!ret) { state->flags |= ST_POWERED; } else { diff --git a/include/linux/platform_data/mipi-csis.h b/include/linux/platform_data/mipi-csis.h index c45b1e8..2e59e43 100644 --- a/include/linux/platform_data/mipi-csis.h +++ b/include/linux/platform_data/mipi-csis.h @@ -11,8 +11,6 @@ #ifndef __PLAT_SAMSUNG_MIPI_CSIS_H_ #define __PLAT_SAMSUNG_MIPI_CSIS_H_ __FILE__ -struct platform_device; - /** * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver * @clk_rate: bus clock frequency @@ -34,10 +32,11 @@ struct s5p_platform_mipi_csis { /** * s5p_csis_phy_enable - global MIPI-CSI receiver D-PHY control - * @pdev: MIPI-CSIS platform device - * @on: true to enable D-PHY and deassert its reset - * false to disable D-PHY + * @id: MIPI-CSIS harware instance index (0...1) + * @on: true to enable D-PHY and deassert its reset + * false to disable D-PHY + * @return: 0 on success, or negative error code on failure */ -int s5p_csis_phy_enable(struct platform_device *pdev, bool on); +int s5p_csis_phy_enable(int id, bool on); #endif /* __PLAT_SAMSUNG_MIPI_CSIS_H_ */ -- cgit v0.10.2 From 09ff034047cb3846090215358f20e0e94c60b901 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 17 Sep 2012 06:03:25 -0300 Subject: [media] s5p-fimc: Remove unused platform data structure fields alignment, fixed_phy_vdd and phy_enable fields are now unused so removed them. The data alignment is now derived directly from media bus pixel code, phy_enable callback has been replaced with direct function call and fixed_phy_vdd was dropped in commit 438df3ebe5f0ce408490a777a758d5905f0dd58f "[media] s5p-csis: Handle all available power supplies". Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/include/linux/platform_data/mipi-csis.h b/include/linux/platform_data/mipi-csis.h index 2e59e43..8b703e1 100644 --- a/include/linux/platform_data/mipi-csis.h +++ b/include/linux/platform_data/mipi-csis.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. * - * S5P series MIPI CSI slave device support + * Samsung S5P/Exynos SoC series MIPI CSIS device support * * 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 @@ -13,21 +13,14 @@ /** * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver - * @clk_rate: bus clock frequency - * @lanes: number of data lanes used - * @alignment: data alignment in bits - * @hs_settle: HS-RX settle time - * @fixed_phy_vdd: false to enable external D-PHY regulator management in the - * driver or true in case this regulator has no enable function - * @phy_enable: pointer to a callback controlling D-PHY enable/reset + * @clk_rate: bus clock frequency + * @lanes: number of data lanes used + * @hs_settle: HS-RX settle time */ struct s5p_platform_mipi_csis { unsigned long clk_rate; u8 lanes; - u8 alignment; u8 hs_settle; - bool fixed_phy_vdd; - int (*phy_enable)(struct platform_device *pdev, bool on); }; /** diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 09421a6..eaea62a 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -30,7 +30,6 @@ struct i2c_board_info; * @board_info: pointer to I2C subdevice's board info * @clk_frequency: frequency of the clock the host interface provides to sensor * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc. - * @csi_data_align: MIPI-CSI interface data alignment in bits * @i2c_bus_num: i2c control bus id the sensor is attached to * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU) * @clk_id: index of the SoC peripheral clock for sensors @@ -40,7 +39,6 @@ struct s5p_fimc_isp_info { struct i2c_board_info *board_info; unsigned long clk_frequency; enum cam_bus_type bus_type; - u16 csi_data_align; u16 i2c_bus_num; u16 mux_id; u16 flags; -- cgit v0.10.2 From 65214a8603e3ec3b1c2bc4104e6806e7cf6d23ed Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 17 Sep 2012 06:03:38 -0300 Subject: [media] s5p-csis: Allow to specify pixel clock's source through platform data Depending on the sensor configuration it might be required to adjust the CSIS's output pixel clock so it is greater than its input pixel clock, in order to avoid the input data FIFO overflow. Use platform data to select SCLK_CSIS clock from CMU as a source, rather than CSI APB clock. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index 983e81f..4c961b1 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -322,8 +322,10 @@ static void s5pcsis_set_params(struct csis_state *state) val |= S5PCSIS_CTRL_ALIGN_32BIT; else /* 24-bits */ val &= ~S5PCSIS_CTRL_ALIGN_32BIT; - /* Not using external clock. */ + val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; + if (pdata->wclk_source) + val |= S5PCSIS_CTRL_WCLK_EXTCLK; s5pcsis_write(state, S5PCSIS_CTRL, val); /* Update the shadow register. */ diff --git a/include/linux/platform_data/mipi-csis.h b/include/linux/platform_data/mipi-csis.h index 8b703e1..bf34e17 100644 --- a/include/linux/platform_data/mipi-csis.h +++ b/include/linux/platform_data/mipi-csis.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. * * Samsung S5P/Exynos SoC series MIPI CSIS device support * @@ -14,11 +14,13 @@ /** * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver * @clk_rate: bus clock frequency + * @wclk_source: CSI wrapper clock selection: 0 - bus clock, 1 - ext. SCLK_CAM * @lanes: number of data lanes used * @hs_settle: HS-RX settle time */ struct s5p_platform_mipi_csis { unsigned long clk_rate; + u8 wclk_source; u8 lanes; u8 hs_settle; }; -- cgit v0.10.2 From 4d08f670e63200cc092724de8c95f81df606b1a5 Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Wed, 3 Oct 2012 22:19:05 -0300 Subject: [media] v4l: Add fourcc definitions for new formats Add the following new fourcc definitions, for multiplanar YCbCr: V4L2_PIX_FMT_NV21M, V4L2_PIX_FMT_NV12MT_16X16 and compressed formats: V4L2_PIX_FMT_H264_MVC, V4L2_PIX_FMT_VP8. Signed-off-by: Jeongtae Park Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Arun Kumar K Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml index 5274c24..a990b34 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml @@ -1,11 +1,13 @@ - + - V4L2_PIX_FMT_NV12M ('NM12') + V4L2_PIX_FMT_NV12M ('NM12'), V4L2_PIX_FMT_NV21M ('NM21'), V4L2_PIX_FMT_NV12MT_16X16 &manvol; - V4L2_PIX_FMT_NV12M - Variation of V4L2_PIX_FMT_NV12 with planes + V4L2_PIX_FMT_NV12M + V4L2_PIX_FMT_NV21M + V4L2_PIX_FMT_NV12MT_16X16 + Variation of V4L2_PIX_FMT_NV12 and V4L2_PIX_FMT_NV21 with planes non contiguous in memory. @@ -22,7 +24,12 @@ The CbCr plane is the same width, in bytes, as the Y plane (and of the image), but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example, Cb0/Cr0 belongs to Y'00, Y'01, -Y'10, Y'11. +Y'10, Y'11. +V4L2_PIX_FMT_NV12MT_16X16 is the tiled version of +V4L2_PIX_FMT_NV12M with 16x16 macroblock tiles. Here pixels +are arranged in 16x16 2D tiles and tiles are arranged in linear order in memory. +V4L2_PIX_FMT_NV21M is the same as V4L2_PIX_FMT_NV12M +except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte. V4L2_PIX_FMT_NV12M is intended to be used only in drivers and applications that support the multi-planar API, diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index fce1437..bf94f41 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -758,6 +758,11 @@ extended control V4L2_CID_MPEG_STREAM_TYPE, see 'AVC1' H264 video elementary stream without start codes. + + V4L2_PIX_FMT_H264_MVC + 'MVC' + H264 MVC video elementary stream. + V4L2_PIX_FMT_H263 'H263' @@ -793,6 +798,11 @@ extended control V4L2_CID_MPEG_STREAM_TYPE, see 'VC1L' VC1, SMPTE 421M Annex L compliant stream. + + V4L2_PIX_FMT_VP8 + 'VP8' + VP8 video elementary stream. + diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 80977d6..873adbe 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -366,7 +366,9 @@ struct v4l2_pix_format { /* two non contiguous planes - one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */ #define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ +#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 macroblocks */ /* three non contiguous planes - Y, Cb, Cr */ #define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ @@ -403,6 +405,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */ #define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */ #define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */ +#define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */ #define V4L2_PIX_FMT_H263 v4l2_fourcc('H', '2', '6', '3') /* H263 */ #define V4L2_PIX_FMT_MPEG1 v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES */ #define V4L2_PIX_FMT_MPEG2 v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES */ @@ -410,6 +413,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_XVID v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid */ #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */ #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */ +#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ -- cgit v0.10.2 From 2e81dde94316dfaa19f0b6f9d4131ef7eaf124a3 Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Wed, 3 Oct 2012 22:19:06 -0300 Subject: [media] v4l: Add control definitions for new H264 encoder features New controls are added for supporting H264 encoding features like: - MVC frame packing, - flexible macroblock ordering, - arbitrary slice ordering, - hierarchical coding. Signed-off-by: Jeongtae Park Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Arun Kumar K Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index a84a08c..7fe5be1 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -1586,7 +1586,6 @@ frame counter of the frame that is currently displayed (decoded). This value is the decoder is started. - V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE  @@ -2270,6 +2269,14 @@ Applicable to the MPEG1, MPEG2, MPEG4 encoders. + + V4L2_CID_MPEG_VIDEO_VBV_DELAY  + integer + Sets the initial delay in milliseconds for +VBV buffer control. + + + V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE  integer @@ -2334,6 +2341,265 @@ Applicable to the MPEG4 decoder. vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder. + + + V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING  + boolean + + Enable generation of frame packing supplemental enhancement information in the encoded bitstream. +The frame packing SEI message contains the arrangement of L and R planes for 3D viewing. Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0  + boolean + + Sets current frame as frame0 in frame packing SEI. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE  + enum v4l2_mpeg_video_h264_sei_fp_arrangement_type + + Frame packing arrangement type for H264 SEI. +Applicable to the H264 encoder. +Possible values are: + + + + + + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHEKERBOARD  + Pixels are alternatively from L and R. + + + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN  + L and R are interlaced by column. + + + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW  + L and R are interlaced by row. + + + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE  + L is on the left, R on the right. + + + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM  + L is on top, R on bottom. + + + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL  + One view per frame. + + + + + + + + V4L2_CID_MPEG_VIDEO_H264_FMO  + boolean + + Enables flexible macroblock ordering in the encoded bitstream. It is a technique +used for restructuring the ordering of macroblocks in pictures. Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE  + enum v4l2_mpeg_video_h264_fmo_map_type + + When using FMO, the map type divides the image in different scan patterns of macroblocks. +Applicable to the H264 encoder. +Possible values are: + + + + + + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES  + Slices are interleaved one after other with macroblocks in run length order. + + + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES  + Scatters the macroblocks based on a mathematical function known to both encoder and decoder. + + + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER  + Macroblocks arranged in rectangular areas or regions of interest. + + + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT  + Slice groups grow in a cyclic way from centre to outwards. + + + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN  + Slice groups grow in raster scan pattern from left to right. + + + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN  + Slice groups grow in wipe scan pattern from top to bottom. + + + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT  + User defined map type. + + + + + + + + V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP  + integer + + Number of slice groups in FMO. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION  + enum v4l2_mpeg_video_h264_fmo_change_dir + + Specifies a direction of the slice group change for raster and wipe maps. +Applicable to the H264 encoder. +Possible values are: + + + + + + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT  + Raster scan or wipe right. + + + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT  + Reverse raster scan or wipe left. + + + + + + + + V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE  + integer + + Specifies the size of the first slice group for raster and wipe map. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH  + integer + + Specifies the number of consecutive macroblocks for the interleaved map. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_ASO  + boolean + + Enables arbitrary slice ordering in encoded bitstream. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER  + integer + Specifies the slice order in ASO. Applicable to the H264 encoder. +The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit): + + + + + + Bit 0:15 + Slice ID + + + Bit 16:32 + Slice position or order + + + + + + + + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING  + boolean + + Enables H264 hierarchical coding. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE  + enum v4l2_mpeg_video_h264_hierarchical_coding_type + + Specifies the hierarchical coding type. +Applicable to the H264 encoder. +Possible values are: + + + + + + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B  + Hierarchical B coding. + + + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P  + Hierarchical P coding. + + + + + + + + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER  + integer + + Specifies the number of hierarchical coding layers. +Applicable to the H264 encoder. + + + + + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP  + integer + Specifies a user defined QP for each layer. Applicable to the H264 encoder. +The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit): + + + + + + Bit 0:15 + QP value + + + Bit 16:32 + Layer number + + + + + diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 207bcd8..f6ee201 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -384,6 +384,25 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Extended SAR", NULL, }; + static const char * const h264_fp_arrangement_type[] = { + "Checkerboard", + "Column", + "Row", + "Side by Side", + "Top Bottom", + "Temporal", + NULL, + }; + static const char * const h264_fmo_map_type[] = { + "Interleaved Slices", + "Scattered Slices", + "Foreground with Leftover", + "Box Out", + "Raster Scan", + "Wipe Scan", + "Explicit", + NULL, + }; static const char * const mpeg_mpeg4_level[] = { "0", "0b", @@ -508,6 +527,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_profile; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return vui_sar_idc; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + return h264_fp_arrangement_type; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + return h264_fmo_map_type; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return mpeg_mpeg4_level; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: @@ -643,6 +666,22 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: return "Horizontal Size of SAR"; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable"; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: return "H264 Enable Frame Packing SEI"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: return "H264 Set Curr. Frame as Frame0"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: return "H264 FP Arrangement Type"; + case V4L2_CID_MPEG_VIDEO_H264_FMO: return "H264 Flexible MB Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return "H264 Map Type for FMO"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: return "H264 FMO Number of Slice Groups"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: return "H264 FMO Direction of Change"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: return "H264 FMO Size of 1st Slice Grp"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: return "H264 FMO No. of Consecutive MBs"; + case V4L2_CID_MPEG_VIDEO_H264_ASO: return "H264 Arbitrary Slice Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: return "H264 ASO Slice Order"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: return "Enable H264 Hierarchical Coding"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: + return "H264 Set QP Value for HC Layers"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -657,6 +696,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; /* CAMERA controls */ /* Keep the order of the 'case's the same as in videodev2.h! */ @@ -854,6 +894,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: case V4L2_CID_MPEG_VIDEO_H264_PROFILE: case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h index e1b3680..f56c945 100644 --- a/include/linux/v4l2-controls.h +++ b/include/linux/v4l2-controls.h @@ -349,6 +349,7 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) #define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) +#define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_BASE+225) #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) @@ -439,6 +440,46 @@ enum v4l2_mpeg_video_h264_vui_sar_idc { V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 = 16, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED = 17, }; +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING (V4L2_CID_MPEG_BASE+368) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0 (V4L2_CID_MPEG_BASE+369) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE (V4L2_CID_MPEG_BASE+370) +enum v4l2_mpeg_video_h264_sei_fp_arrangement_type { + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHECKERBOARD = 0, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN = 1, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW = 2, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE = 3, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM = 4, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL = 5, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO (V4L2_CID_MPEG_BASE+371) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE (V4L2_CID_MPEG_BASE+372) +enum v4l2_mpeg_video_h264_fmo_map_type { + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES = 0, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES = 1, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER = 2, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT = 3, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN = 4, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN = 5, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT = 6, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP (V4L2_CID_MPEG_BASE+373) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION (V4L2_CID_MPEG_BASE+374) +enum v4l2_mpeg_video_h264_fmo_change_dir { + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT = 0, + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT = 1, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE (V4L2_CID_MPEG_BASE+375) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH (V4L2_CID_MPEG_BASE+376) +#define V4L2_CID_MPEG_VIDEO_H264_ASO (V4L2_CID_MPEG_BASE+377) +#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER (V4L2_CID_MPEG_BASE+378) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING (V4L2_CID_MPEG_BASE+379) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE (V4L2_CID_MPEG_BASE+380) +enum v4l2_mpeg_video_h264_hierarchical_coding_type { + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B = 0, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P = 1, +}; +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER (V4L2_CID_MPEG_BASE+381) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP (V4L2_CID_MPEG_BASE+382) #define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_MPEG_BASE+400) #define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_MPEG_BASE+401) #define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_MPEG_BASE+402) -- cgit v0.10.2 From 77a788fc2d4089c64eb355a004f1f16b22eb3ab1 Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Wed, 3 Oct 2012 22:19:07 -0300 Subject: [media] s5p-mfc: Prepare driver for callback based re-architecture The patch renames hardware specific opr and cmd files to opr_v5 and cmd_v5 respectively. This is done for accomodating firmware v6. Also the shared memory management files are removed and the functionality is added to the opr_v5 file. Signed-off-by: Arun Kumar K Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index d066340..39496b8 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o -s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o +s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr_v5.o s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o -s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o -s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_shm.o +s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd_v5.o +s5p-mfc-y += s5p_mfc_pm.o diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 5587ef1..74bb284 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -28,9 +28,8 @@ #include "s5p_mfc_dec.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" #include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" #define S5P_MFC_NAME "s5p-mfc" #define S5P_MFC_DEC_NAME "s5p-mfc-dec" @@ -213,8 +212,8 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = (ctx->sequence++); - if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == - s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) + if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) == + s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED; @@ -285,8 +284,8 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = ctx->sequence; - if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == - s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) + if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) == + s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c deleted file mode 100644 index 91a4155..0000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include "regs-mfc.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" - -/* This function is used to send a command to the MFC */ -static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) -{ - int cur_cmd; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while waiting for hardware\n"); - return -EIO; - } - cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); - } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); - mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); - mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); - mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); - mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); - /* Issue the command */ - mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); - return 0; -} - -/* Initialize the MFC */ -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = dev->fw_size; - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); -} - -/* Suspend the MFC hardware */ -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); -} - -/* Wake up the MFC hardware */ -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args); -} - - -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - /* Preparing decoding - getting instance number */ - mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->codec_mode; - h2r_args.arg[1] = 0; /* no crc & no pixelcache */ - h2r_args.arg[2] = ctx->ctx_ofs; - h2r_args.arg[3] = ctx->ctx_size; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to create a new instance\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - if (ctx->state == MFCINST_FREE) { - mfc_err("Instance already returned\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - /* Closing decoding instance */ - mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->inst_no; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to return an instance\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - return 0; -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h deleted file mode 100644 index 8b090d3..0000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef S5P_MFC_CMD_H_ -#define S5P_MFC_CMD_H_ - -#include "s5p_mfc_common.h" - -#define MAX_H2R_ARG 4 - -struct s5p_mfc_cmd_args { - unsigned int arg[MAX_H2R_ARG]; -}; - -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx); -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx); - -#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c new file mode 100644 index 0000000..cdd02b9 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -0,0 +1,120 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "regs-mfc.h" +#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" + +/* This function is used to send a command to the MFC */ +static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + int cur_cmd; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while waiting for hardware\n"); + return -EIO; + } + cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); + } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); + mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); + mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); + mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); + mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); + return 0; +} + +/* Initialize the MFC */ +int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = dev->fw_size; + return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); +} + +/* Suspend the MFC hardware */ +int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); +} + +/* Wake up the MFC hardware */ +int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args); +} + + +int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + /* Preparing decoding - getting instance number */ + mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = ctx->codec_mode; + h2r_args.arg[1] = 0; /* no crc & no pixelcache */ + h2r_args.arg[2] = ctx->ctx_ofs; + h2r_args.arg[3] = ctx->ctx_size; + ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to create a new instance\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + if (ctx->state == MFCINST_FREE) { + mfc_err("Instance already returned\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + /* Closing decoding instance */ + mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = ctx->inst_no; + ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to return an instance\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + return 0; +} + diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h new file mode 100644 index 0000000..8b090d3 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h @@ -0,0 +1,30 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5P_MFC_CMD_H_ +#define S5P_MFC_CMD_H_ + +#include "s5p_mfc_common.h" + +#define MAX_H2R_ARG 4 + +struct s5p_mfc_cmd_args { + unsigned int arg[MAX_H2R_ARG]; +}; + +int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev); +int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev); +int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev); +int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx); +int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 0deba6b..f31bff9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -16,7 +16,7 @@ #include #include #include "regs-mfc.h" -#include "s5p_mfc_cmd.h" +#include "s5p_mfc_cmd_v5.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 6ee21bb..653f14b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -28,9 +28,8 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_dec.h" #include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" #include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" static struct s5p_mfc_fmt formats[] = { { @@ -695,10 +694,10 @@ static int vidioc_g_crop(struct file *file, void *priv, return -EINVAL; } if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { - left = s5p_mfc_read_shm(ctx, CROP_INFO_H); + left = s5p_mfc_read_info_v5(ctx, CROP_INFO_H); right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; - top = s5p_mfc_read_shm(ctx, CROP_INFO_V); + top = s5p_mfc_read_info_v5(ctx, CROP_INFO_V); bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; cr->c.left = left; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 179e4db..f5f7e3c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -30,7 +30,7 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" static struct s5p_mfc_fmt formats[] = { { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c deleted file mode 100644 index 767a512..0000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ /dev/null @@ -1,1425 +0,0 @@ -/* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.c - * - * Samsung MFC (Multi Function Codec - FIMV) driver - * This file contains hw related functions. - * - * Kamil Debski, Copyright (c) 2011 Samsung Electronics - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include "regs-mfc.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_common.h" -#include "s5p_mfc_ctrl.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) -#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) - -/* Allocate temporary buffers for decoding */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx) -{ - void *desc_virt; - struct s5p_mfc_dev *dev = ctx->dev; - - ctx->desc_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE); - if (IS_ERR_VALUE((int)ctx->desc_buf)) { - ctx->desc_buf = NULL; - mfc_err("Allocating DESC buffer failed\n"); - return -ENOMEM; - } - ctx->desc_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf); - BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf); - if (desc_virt == NULL) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; - mfc_err("Remapping DESC buffer failed\n"); - return -ENOMEM; - } - memset(desc_virt, 0, DESC_BUF_SIZE); - wmb(); - return 0; -} - -/* Release temporary buffers for decoding */ -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx) -{ - if (ctx->desc_phys) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; - } -} - -/* Allocate codec buffers */ -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int enc_ref_y_size = 0; - unsigned int enc_ref_c_size = 0; - unsigned int guard_width, guard_height; - - if (ctx->type == MFCINST_DECODER) { - mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", - ctx->luma_size, ctx->chroma_size, ctx->mv_size); - mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); - } else if (ctx->type == MFCINST_ENCODER) { - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height >> 1, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, - S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "recon luma size: %d chroma size: %d\n", - enc_ref_y_size, enc_ref_c_size); - } else { - return -EINVAL; - } - /* Codecs have different memory requirements */ - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + - S5P_FIMV_DEC_VERT_NB_MV_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; - break; - case S5P_FIMV_CODEC_MPEG4_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_STX_PARSER_SIZE + - S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_VC1RCV_DEC: - case S5P_FIMV_CODEC_VC1_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE + - 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_MPEG2_DEC: - ctx->bank1_size = 0; - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_H263_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_H264_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_INTRAMD_SIZE + - S5P_FIMV_ENC_NBORINFO_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4) + - S5P_FIMV_ENC_INTRAPRED_SIZE; - break; - case S5P_FIMV_CODEC_MPEG4_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - case S5P_FIMV_CODEC_H263_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - default: - break; - } - /* Allocate only if memory from bank 1 is necessary */ - if (ctx->bank1_size > 0) { - ctx->bank1_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); - if (IS_ERR(ctx->bank1_buf)) { - ctx->bank1_buf = NULL; - printk(KERN_ERR - "Buf alloc for decoding failed (port A)\n"); - return -ENOMEM; - } - ctx->bank1_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); - BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - } - /* Allocate only if memory from bank 2 is necessary */ - if (ctx->bank2_size > 0) { - ctx->bank2_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size); - if (IS_ERR(ctx->bank2_buf)) { - ctx->bank2_buf = NULL; - mfc_err("Buf alloc for decoding failed (port B)\n"); - return -ENOMEM; - } - ctx->bank2_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf); - BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); - } - return 0; -} - -/* Release buffers allocated for codec */ -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx) -{ - if (ctx->bank1_buf) { - vb2_dma_contig_memops.put(ctx->bank1_buf); - ctx->bank1_buf = NULL; - ctx->bank1_phys = 0; - ctx->bank1_size = 0; - } - if (ctx->bank2_buf) { - vb2_dma_contig_memops.put(ctx->bank2_buf); - ctx->bank2_buf = NULL; - ctx->bank2_phys = 0; - ctx->bank2_size = 0; - } -} - -/* Allocate memory for instance data buffer */ -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx) -{ - void *context_virt; - struct s5p_mfc_dev *dev = ctx->dev; - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) - ctx->ctx_size = MFC_H264_CTX_BUF_SIZE; - else - ctx->ctx_size = MFC_CTX_BUF_SIZE; - ctx->ctx_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size); - if (IS_ERR(ctx->ctx_buf)) { - mfc_err("Allocating context buffer failed\n"); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - ctx->ctx_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf); - BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->ctx_ofs = OFFSETA(ctx->ctx_phys); - context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf); - if (context_virt == NULL) { - mfc_err("Remapping instance buffer failed\n"); - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - /* Zero content of the allocated memory */ - memset(context_virt, 0, ctx->ctx_size); - wmb(); - if (s5p_mfc_init_shm(ctx) < 0) { - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - return 0; -} - -/* Release instance buffer */ -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx) -{ - if (ctx->ctx_buf) { - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - } - if (ctx->shm_alloc) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_alloc = NULL; - ctx->shm = NULL; - } -} - -/* Set registers for decoding temporary buffers */ -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR); - mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE); -} - -/* Set registers for shared buffer */ -static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); -} - -/* Set registers for decoding stream buffer */ -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, unsigned int buf_size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); - mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); - mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); - s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM); - return 0; -} - -/* Set decoding frame buffer */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) -{ - unsigned int frame_size, i; - unsigned int frame_size_ch, frame_size_mv; - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - size_t buf_addr1, buf_addr2; - int buf_size1, buf_size2; - - buf_addr1 = ctx->bank1_phys; - buf_size1 = ctx->bank1_size; - buf_addr2 = ctx->bank2_phys; - buf_size2 = ctx->bank2_size; - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~S5P_FIMV_DPB_COUNT_MASK; - mfc_write(dev, ctx->total_dpb_count | dpb, - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - s5p_mfc_set_shared_buffer(ctx); - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_VERT_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; - break; - case S5P_FIMV_CODEC_MPEG4_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); - buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; - buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - break; - case S5P_FIMV_CODEC_H263_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - break; - case S5P_FIMV_CODEC_VC1_DEC: - case S5P_FIMV_CODEC_VC1RCV_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - break; - case S5P_FIMV_CODEC_MPEG2_DEC: - break; - default: - mfc_err("Unknown codec for decoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - break; - } - frame_size = ctx->luma_size; - frame_size_ch = ctx->chroma_size; - frame_size_mv = ctx->mv_size; - mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, - frame_size_mv); - for (i = 0; i < ctx->total_dpb_count; i++) { - /* Bank2 */ - mfc_debug(2, "Luma %d: %x\n", i, - ctx->dst_bufs[i].cookie.raw.luma); - mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), - S5P_FIMV_DEC_LUMA_ADR + i * 4); - mfc_debug(2, "\tChroma %d: %x\n", i, - ctx->dst_bufs[i].cookie.raw.chroma); - mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), - S5P_FIMV_DEC_CHROMA_ADR + i * 4); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { - mfc_debug(2, "\tBuf2: %x, size: %d\n", - buf_addr2, buf_size2); - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_MV_ADR + i * 4); - buf_addr2 += frame_size_mv; - buf_size2 -= frame_size_mv; - } - } - mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); - mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", - buf_size1, buf_size2, ctx->total_dpb_count); - if (buf_size1 < 0 || buf_size2 < 0) { - mfc_debug(2, "Not enough memory has been allocated\n"); - return -ENOMEM; - } - s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); - s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) - s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE); - mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) - << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Set registers for encoding stream buffer */ -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); - mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); - return 0; -} - -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); - mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); -} - -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) - << MFC_OFFSET_SHIFT); - *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) - << MFC_OFFSET_SHIFT); -} - -/* Set encoding ref & codec buffer */ -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - size_t buf_addr1, buf_addr2; - size_t buf_size1, buf_size2; - unsigned int enc_ref_y_size, enc_ref_c_size; - unsigned int guard_width, guard_height; - int i; - - buf_addr1 = ctx->bank1_phys; - buf_size1 = ctx->bank1_size; - buf_addr2 = ctx->bank2_phys; - buf_size2 = ctx->bank2_size; - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_UP_INTRA_MD_ADR); - buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; - buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_UP_INTRA_PRED_ADR); - buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; - buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_NBOR_INFO_ADR); - buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; - buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - case S5P_FIMV_CODEC_MPEG4_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - case S5P_FIMV_CODEC_H263_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - default: - mfc_err("Unknown codec set for encoding: %d\n", - ctx->codec_mode); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - unsigned int reg; - unsigned int shm; - - /* width */ - mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); - /* height */ - mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); - /* pictype : enable, IDR period */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - reg |= (1 << 18); - reg &= ~(0xFFFF); - reg |= p->gop_size; - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); - /* multi-slice control */ - /* multi-slice MB number or bit size */ - mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { - mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { - mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); - } - /* cyclic intra refresh */ - mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - /* padding control & value */ - reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); - if (p->pad) { - /** enable */ - reg |= (1 << 31); - /** cr value */ - reg &= ~(0xFF << 16); - reg |= (p->pad_cr << 16); - /** cb value */ - reg &= ~(0xFF << 8); - reg |= (p->pad_cb << 8); - /** y value */ - reg &= ~(0xFF); - reg |= (p->pad_luma); - } else { - /** disable & all value clear */ - reg = 0; - } - mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /** frame-level rate control */ - reg &= ~(0x1 << 9); - reg |= (p->rc_frame << 9); - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* bit rate */ - if (p->rc_frame) - mfc_write(dev, p->rc_bitrate, - S5P_FIMV_ENC_RC_BIT_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); - /* reaction coefficient */ - if (p->rc_frame) - mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* seq header ctrl */ - shm &= ~(0x1 << 3); - shm |= (p->seq_hdr_mode << 3); - /* frame skip mode */ - shm &= ~(0x3 << 1); - shm |= (p->frame_skip_mode << 1); - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - /* fixed target bit */ - s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); - return 0; -} - -static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_264->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_264->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* interlace */ - mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT); - /* height */ - if (p->interlace) - mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); - /* loopfilter ctrl */ - mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); - /* loopfilter alpha offset */ - if (p_264->loop_filter_alpha < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_alpha) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_alpha & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); - /* loopfilter beta offset */ - if (p_264->loop_filter_beta < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_beta) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_beta & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); - /* entropy coding mode */ - if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) - mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); - /* number of ref. picture */ - reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* num of ref. pictures of P */ - reg &= ~(0x3 << 5); - reg |= (p_264->num_ref_pic_4p << 5); - /* max number of ref. pictures */ - reg &= ~(0x1F); - reg |= p_264->max_ref_pic; - mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* 8x8 transform enable */ - mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= (p_264->rc_mb << 8); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_264->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_264->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_264->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* macroblock adaptive scaling features */ - if (p_264->rc_mb) { - reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); - /* dark region */ - reg &= ~(0x1 << 3); - reg |= (p_264->rc_mb_dark << 3); - /* smooth region */ - reg &= ~(0x1 << 2); - reg |= (p_264->rc_mb_smooth << 2); - /* static region */ - reg &= ~(0x1 << 1); - reg |= (p_264->rc_mb_static << 1); - /* high activity region */ - reg &= ~(0x1); - reg |= p_264->rc_mb_activity; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); - } - if (!p->rc_frame && - !p_264->rc_mb) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_264->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* AR VUI control */ - shm &= ~(0x1 << 15); - shm |= (p_264->vui_sar << 1); - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - if (p_264->vui_sar) { - /* aspect ration IDC */ - shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC); - shm &= ~(0xFF); - shm |= p_264->vui_sar_idc; - s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); - if (p_264->vui_sar_idc == 0xFF) { - /* sample AR info */ - shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR); - shm &= ~(0xFFFFFFFF); - shm |= p_264->vui_ext_sar_width << 16; - shm |= p_264->vui_ext_sar_height; - s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR); - } - } - /* intra picture period for H.264 */ - shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD); - /* control */ - shm &= ~(0x1 << 16); - shm |= (p_264->open_gop << 16); - /* value */ - if (p_264->open_gop) { - shm &= ~(0xFFFF); - shm |= p_264->open_gop_size; - } - s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p_264->cpb_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - unsigned int framerate; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_mpeg4->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_mpeg4->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* quarter_pixel */ - mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame) { - if (p->rc_framerate_denom > 0) { - framerate = p->rc_framerate_num * 1000 / - p->rc_framerate_denom; - mfc_write(dev, framerate, - S5P_FIMV_ENC_RC_FRAME_RATE); - shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING); - shm &= ~(0xFFFFFFFF); - shm |= (1 << 31); - shm |= ((p->rc_framerate_num & 0x7FFF) << 16); - shm |= (p->rc_framerate_denom & 0xFFFF); - s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING); - } - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - } - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_mpeg4->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= (p_h263->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_h263->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -/* Initialize decoding */ -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_shared_buffer(ctx); - /* Setup loop filter, for decoding this is only valid for MPEG4 */ - if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) - mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); - else - mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); - mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << - S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << - S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & - S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - mfc_write(dev, - ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - - if (flush) - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( - S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - else - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); -} - -/* Decode a single frame */ -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); - s5p_mfc_set_shared_buffer(ctx); - s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); - /* Issue different commands to instance basing on whether it - * is the last frame or not. */ - switch (last_frame) { - case MFC_DEC_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_LAST_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_RES_CHANGE: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & - S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - break; - } - mfc_debug(2, "Decoding a usual frame\n"); - return 0; -} - -int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) - s5p_mfc_set_enc_params_h264(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC) - s5p_mfc_set_enc_params_mpeg4(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC) - s5p_mfc_set_enc_params_h263(ctx); - else { - mfc_err("Unknown codec for encoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - } - s5p_mfc_set_shared_buffer(ctx); - mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | - (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Encode a single frame */ -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - int cmd; - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - s5p_mfc_set_shared_buffer(ctx); - - if (ctx->state == MFCINST_FINISHING) - cmd = S5P_FIMV_CH_LAST_FRAME; - else - cmd = S5P_FIMV_CH_FRAME_START; - mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - - return 0; -} - -static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) -{ - unsigned long flags; - int new_ctx; - int cnt; - - spin_lock_irqsave(&dev->condlock, flags); - new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; - cnt = 0; - while (!test_bit(new_ctx, &dev->ctx_work_bits)) { - new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; - if (++cnt > MFC_NUM_CONTEXTS) { - /* No contexts to run */ - spin_unlock_irqrestore(&dev->condlock, flags); - return -EAGAIN; - } - } - spin_unlock_irqrestore(&dev->condlock, flags); - return new_ctx; -} - -static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE); -} - -static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - unsigned long flags; - unsigned int index; - - spin_lock_irqsave(&dev->irqlock, flags); - /* Frames are being decoded */ - if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "No src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - /* Get the next source buffer */ - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - temp_vb->flags |= MFC_BUF_FLAG_USED; - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, - temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - index = temp_vb->b->v4l2_buf.index; - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - if (temp_vb->b->v4l2_planes[0].bytesused == 0) { - last_frame = MFC_DEC_LAST_FRAME; - mfc_debug(2, "Setting ctx->state to FINISHING\n"); - ctx->state = MFCINST_FINISHING; - } - s5p_mfc_decode_one_frame(ctx, last_frame); - return 0; -} - -static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *dst_mb; - struct s5p_mfc_buf *src_mb; - unsigned long src_y_addr, src_c_addr, dst_addr; - unsigned int dst_size; - - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { - mfc_debug(2, "no src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - if (list_empty(&ctx->dst_queue)) { - mfc_debug(2, "no dst buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - if (list_empty(&ctx->src_queue)) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, dev->bank2); - src_mb = NULL; - } else { - src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); - src_mb->flags |= MFC_BUF_FLAG_USED; - if (src_mb->b->v4l2_planes[0].bytesused == 0) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, - dev->bank2); - ctx->state = MFCINST_FINISHING; - } else { - src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, - 0); - src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, - 1); - s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, - src_c_addr); - if (src_mb->flags & MFC_BUF_FLAG_EOS) - ctx->state = MFCINST_FINISHING; - } - } - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_mb->flags |= MFC_BUF_FLAG_USED; - dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); - dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - mfc_debug(2, "encoding buffer with index=%d state=%d", - src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); - s5p_mfc_encode_one_frame(ctx); - return 0; -} - -static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *temp_vb; - - /* Initializing decoding - parsing header */ - spin_lock_irqsave(&dev->irqlock, flags); - mfc_debug(2, "Preparing to init decoding\n"); - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - s5p_mfc_set_dec_desc_buffer(ctx); - mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), - 0, temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_decode(ctx); -} - -static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *dst_mb; - unsigned long dst_addr; - unsigned int dst_size; - - s5p_mfc_set_enc_ref_buffer(ctx); - spin_lock_irqsave(&dev->irqlock, flags); - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); - dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_encode(ctx); -} - -static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *temp_vb; - int ret; - - /* - * Header was parsed now starting processing - * First set the output frame buffers - */ - if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destionation buffers were " - "mmaped\nMFC requires that all destination are mmaped " - "before starting processing\n"); - return -EAGAIN; - } - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue)) { - mfc_err("Header has been deallocated in the middle of" - " initialization\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EIO; - } - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), - 0, temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_set_dec_frame_buffer(ctx); - if (ret) { - mfc_err("Failed to alloc frame mem\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -/* Try running an operation on hardware */ -void s5p_mfc_try_run(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_ctx *ctx; - int new_ctx; - unsigned int ret = 0; - - if (test_bit(0, &dev->enter_suspend)) { - mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); - return; - } - /* Check whether hardware is not running */ - if (test_and_set_bit(0, &dev->hw_lock) != 0) { - /* This is perfectly ok, the scheduled ctx should wait */ - mfc_debug(1, "Couldn't lock HW\n"); - return; - } - /* Choose the context to run */ - new_ctx = s5p_mfc_get_new_ctx(dev); - if (new_ctx < 0) { - /* No contexts to run */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) { - mfc_err("Failed to unlock hardware\n"); - return; - } - mfc_debug(1, "No ctx is scheduled to be run\n"); - return; - } - ctx = dev->ctx[new_ctx]; - /* Got context to run in ctx */ - /* - * Last frame has already been sent to MFC. - * Now obtaining frames from MFC buffer - */ - s5p_mfc_clock_on(); - if (ctx->type == MFCINST_DECODER) { - s5p_mfc_set_dec_desc_buffer(ctx); - switch (ctx->state) { - case MFCINST_FINISHING: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); - break; - case MFCINST_RUNNING: - ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); - break; - case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_dec(ctx); - break; - case MFCINST_HEAD_PARSED: - ret = s5p_mfc_run_init_dec_buffers(ctx); - mfc_debug(1, "head parsed\n"); - break; - case MFCINST_RES_CHANGE_INIT: - s5p_mfc_run_res_change(ctx); - break; - case MFCINST_RES_CHANGE_FLUSH: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_RES_CHANGE_END: - mfc_debug(2, "Finished remaining frames after resolution change\n"); - ctx->capture_state = QUEUE_FREE; - mfc_debug(2, "Will re-init the codec\n"); - s5p_mfc_run_init_dec(ctx); - break; - default: - ret = -EAGAIN; - } - } else if (ctx->type == MFCINST_ENCODER) { - switch (ctx->state) { - case MFCINST_FINISHING: - case MFCINST_RUNNING: - ret = s5p_mfc_run_enc_frame(ctx); - break; - case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); - break; - case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_enc(ctx); - break; - default: - ret = -EAGAIN; - } - } else { - mfc_err("Invalid context type: %d\n", ctx->type); - ret = -EAGAIN; - } - - if (ret) { - /* Free hardware lock */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - mfc_err("Failed to unlock hardware\n"); - - /* This is in deed imporant, as no operation has been - * scheduled, reduce the clock count as no one will - * ever do this, because no interrupt related to this try_run - * will ever come from hardware. */ - s5p_mfc_clock_off(); - } -} - - -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) -{ - struct s5p_mfc_buf *b; - int i; - - while (!list_empty(lh)) { - b = list_entry(lh->next, struct s5p_mfc_buf, list); - for (i = 0; i < b->b->num_planes; i++) - vb2_set_plane_payload(b->b, i, 0); - vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h deleted file mode 100644 index 2ad3def..0000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.h - * - * Header file for Samsung MFC (Multi Function Codec - FIMV) driver - * Contains declarations of hw related functions. - * - * Kamil Debski, Copyright (C) 2011 Samsung Electronics - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef S5P_MFC_OPR_H_ -#define S5P_MFC_OPR_H_ - -#include "s5p_mfc_common.h" - -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx); -int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx); - -/* Decoding functions */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx); -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, - unsigned int buf_size); - -/* Encoding functions */ -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr); -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size); -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr); -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx); - -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame); -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx); - -/* Memory allocation */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx); - -void s5p_mfc_try_run(struct s5p_mfc_dev *dev); -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); - -#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_STATUS) -#define s5p_mfc_get_dec_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_STATUS) -#define s5p_mfc_get_frame_type() (readl(dev->regs_base + \ - S5P_FIMV_DECODE_FRAME_TYPE) \ - & S5P_FIMV_DECODE_FRAME_MASK) -#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ - S5P_FIMV_SI_CONSUMED_BYTES) -#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_CMD) & \ - S5P_FIMV_RISC2HOST_CMD_MASK) -#define s5p_mfc_get_int_err() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG2) -#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \ - S5P_FIMV_ERR_DEC_SHIFT) -#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \ - S5P_FIMV_ERR_DSPL_SHIFT) -#define s5p_mfc_get_img_width() readl(dev->regs_base + \ - S5P_FIMV_SI_HRESOL) -#define s5p_mfc_get_img_height() readl(dev->regs_base + \ - S5P_FIMV_SI_VRESOL) -#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \ - S5P_FIMV_SI_BUF_NUMBER) -#define s5p_mfc_get_inst_no() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG1) -#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_STRM_SIZE) -#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_SLICE_TYPE) - -#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c new file mode 100644 index 0000000..baa05af6 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -0,0 +1,1456 @@ +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Kamil Debski, Copyright (c) 2011 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "regs-mfc.h" +#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_ctrl.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_pm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) +#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) + +/* Allocate temporary buffers for decoding */ +int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx) +{ + void *desc_virt; + struct s5p_mfc_dev *dev = ctx->dev; + + ctx->desc_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE); + if (IS_ERR_VALUE((int)ctx->desc_buf)) { + ctx->desc_buf = NULL; + mfc_err("Allocating DESC buffer failed\n"); + return -ENOMEM; + } + ctx->desc_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf); + BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf); + if (desc_virt == NULL) { + vb2_dma_contig_memops.put(ctx->desc_buf); + ctx->desc_phys = 0; + ctx->desc_buf = NULL; + mfc_err("Remapping DESC buffer failed\n"); + return -ENOMEM; + } + memset(desc_virt, 0, DESC_BUF_SIZE); + wmb(); + return 0; +} + +/* Release temporary buffers for decoding */ +void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx) +{ + if (ctx->desc_phys) { + vb2_dma_contig_memops.put(ctx->desc_buf); + ctx->desc_phys = 0; + ctx->desc_buf = NULL; + } +} + +/* Allocate codec buffers */ +int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int enc_ref_y_size = 0; + unsigned int enc_ref_c_size = 0; + unsigned int guard_width, guard_height; + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, + S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height >> 1, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, + S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "recon luma size: %d chroma size: %d\n", + enc_ref_y_size, enc_ref_c_size); + } else { + return -EINVAL; + } + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_FIMV_CODEC_H264_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + + S5P_FIMV_DEC_VERT_NB_MV_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; + break; + case S5P_FIMV_CODEC_MPEG4_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_STX_PARSER_SIZE + + S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_FIMV_CODEC_VC1RCV_DEC: + case S5P_FIMV_CODEC_VC1_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE + + 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_FIMV_CODEC_MPEG2_DEC: + ctx->bank1_size = 0; + ctx->bank2_size = 0; + break; + case S5P_FIMV_CODEC_H263_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_FIMV_CODEC_H264_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_INTRAMD_SIZE + + S5P_FIMV_ENC_NBORINFO_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4) + + S5P_FIMV_ENC_INTRAPRED_SIZE; + break; + case S5P_FIMV_CODEC_MPEG4_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + case S5P_FIMV_CODEC_H263_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + default: + break; + } + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1_size > 0) { + ctx->bank1_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); + if (IS_ERR(ctx->bank1_buf)) { + ctx->bank1_buf = NULL; + printk(KERN_ERR + "Buf alloc for decoding failed (port A)\n"); + return -ENOMEM; + } + ctx->bank1_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); + BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + /* Allocate only if memory from bank 2 is necessary */ + if (ctx->bank2_size > 0) { + ctx->bank2_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size); + if (IS_ERR(ctx->bank2_buf)) { + ctx->bank2_buf = NULL; + mfc_err("Buf alloc for decoding failed (port B)\n"); + return -ENOMEM; + } + ctx->bank2_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf); + BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); + } + return 0; +} + +/* Release buffers allocated for codec */ +void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx) +{ + if (ctx->bank1_buf) { + vb2_dma_contig_memops.put(ctx->bank1_buf); + ctx->bank1_buf = NULL; + ctx->bank1_phys = 0; + ctx->bank1_size = 0; + } + if (ctx->bank2_buf) { + vb2_dma_contig_memops.put(ctx->bank2_buf); + ctx->bank2_buf = NULL; + ctx->bank2_phys = 0; + ctx->bank2_size = 0; + } +} + +/* Allocate memory for instance data buffer */ +int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx) +{ + void *context_virt; + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) + ctx->ctx_size = MFC_H264_CTX_BUF_SIZE; + else + ctx->ctx_size = MFC_CTX_BUF_SIZE; + ctx->ctx_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size); + if (IS_ERR(ctx->ctx_buf)) { + mfc_err("Allocating context buffer failed\n"); + ctx->ctx_phys = 0; + ctx->ctx_buf = NULL; + return -ENOMEM; + } + ctx->ctx_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf); + BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + ctx->ctx_ofs = OFFSETA(ctx->ctx_phys); + context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf); + if (context_virt == NULL) { + mfc_err("Remapping instance buffer failed\n"); + vb2_dma_contig_memops.put(ctx->ctx_buf); + ctx->ctx_phys = 0; + ctx->ctx_buf = NULL; + return -ENOMEM; + } + /* Zero content of the allocated memory */ + memset(context_virt, 0, ctx->ctx_size); + wmb(); + + /* Initialize shared memory */ + ctx->shm_alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], SHARED_BUF_SIZE); + if (IS_ERR(ctx->shm_alloc)) { + mfc_err("failed to allocate shared memory\n"); + return PTR_ERR(ctx->shm_alloc); + } + /* shared memory offset only keeps the offset from base (port a) */ + ctx->shm_ofs = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->shm_alloc) + - dev->bank1; + BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + + ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc); + if (!ctx->shm) { + vb2_dma_contig_memops.put(ctx->shm_alloc); + ctx->shm_ofs = 0; + ctx->shm_alloc = NULL; + mfc_err("failed to virt addr of shared memory\n"); + return -ENOMEM; + } + memset((void *)ctx->shm, 0, SHARED_BUF_SIZE); + wmb(); + return 0; +} + +/* Release instance buffer */ +void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx) +{ + if (ctx->ctx_buf) { + vb2_dma_contig_memops.put(ctx->ctx_buf); + ctx->ctx_phys = 0; + ctx->ctx_buf = NULL; + } + if (ctx->shm_alloc) { + vb2_dma_contig_memops.put(ctx->shm_alloc); + ctx->shm_alloc = NULL; + ctx->shm = NULL; + } +} + +void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs) +{ + writel(data, (ctx->shm + ofs)); + wmb(); +} + +unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, + unsigned int ofs) +{ + rmb(); + return readl(ctx->shm + ofs); +} + +/* Set registers for decoding temporary buffers */ +void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR); + mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE); +} + +/* Set registers for shared buffer */ +static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); +} + +/* Set registers for decoding stream buffer */ +int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, + unsigned int start_num_byte, unsigned int buf_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); + mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); + mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); + s5p_mfc_write_info_v5(ctx, start_num_byte, START_BYTE_NUM); + return 0; +} + +/* Set decoding frame buffer */ +int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + size_t buf_addr1, buf_addr2; + int buf_size1, buf_size2; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + buf_addr2 = ctx->bank2_phys; + buf_size2 = ctx->bank2_size; + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~S5P_FIMV_DPB_COUNT_MASK; + mfc_write(dev, ctx->total_dpb_count | dpb, + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + s5p_mfc_set_shared_buffer(ctx); + switch (ctx->codec_mode) { + case S5P_FIMV_CODEC_H264_DEC: + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_VERT_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; + break; + case S5P_FIMV_CODEC_MPEG4_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); + buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; + buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + break; + case S5P_FIMV_CODEC_H263_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + break; + case S5P_FIMV_CODEC_VC1_DEC: + case S5P_FIMV_CODEC_VC1RCV_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + break; + case S5P_FIMV_CODEC_MPEG2_DEC: + break; + default: + mfc_err("Unknown codec for decoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + break; + } + frame_size = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, + frame_size_mv); + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), + S5P_FIMV_DEC_LUMA_ADR + i * 4); + mfc_debug(2, "\tChroma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), + S5P_FIMV_DEC_CHROMA_ADR + i * 4); + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { + mfc_debug(2, "\tBuf2: %x, size: %d\n", + buf_addr2, buf_size2); + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_MV_ADR + i * 4); + buf_addr2 += frame_size_mv; + buf_size2 -= frame_size_mv; + } + } + mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); + mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", + buf_size1, buf_size2, ctx->total_dpb_count); + if (buf_size1 < 0 || buf_size2 < 0) { + mfc_debug(2, "Not enough memory has been allocated\n"); + return -ENOMEM; + } + s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); + s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) + s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); + mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) + << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Set registers for encoding stream buffer */ +int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); + mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); + return 0; +} + +void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); + mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); +} + +void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) + << MFC_OFFSET_SHIFT); + *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) + << MFC_OFFSET_SHIFT); +} + +/* Set encoding ref & codec buffer */ +int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1, buf_addr2; + size_t buf_size1, buf_size2; + unsigned int enc_ref_y_size, enc_ref_c_size; + unsigned int guard_width, guard_height; + int i; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + buf_addr2 = ctx->bank2_phys; + buf_size2 = ctx->bank2_size; + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); + switch (ctx->codec_mode) { + case S5P_FIMV_CODEC_H264_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_UP_INTRA_MD_ADR); + buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; + buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_UP_INTRA_PRED_ADR); + buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; + buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_NBOR_INFO_ADR); + buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; + buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + case S5P_FIMV_CODEC_MPEG4_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + case S5P_FIMV_CODEC_H263_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + default: + mfc_err("Unknown codec set for encoding: %d\n", + ctx->codec_mode); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg; + unsigned int shm; + + /* width */ + mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); + /* height */ + mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); + /* pictype : enable, IDR period */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + reg |= (1 << 18); + reg &= ~(0xFFFF); + reg |= p->gop_size; + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); + /* multi-slice control */ + /* multi-slice MB number or bit size */ + mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); + } + /* cyclic intra refresh */ + mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + /* padding control & value */ + reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); + if (p->pad) { + /** enable */ + reg |= (1 << 31); + /** cr value */ + reg &= ~(0xFF << 16); + reg |= (p->pad_cr << 16); + /** cb value */ + reg &= ~(0xFF << 8); + reg |= (p->pad_cb << 8); + /** y value */ + reg &= ~(0xFF); + reg |= (p->pad_luma); + } else { + /** disable & all value clear */ + reg = 0; + } + mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /** frame-level rate control */ + reg &= ~(0x1 << 9); + reg |= (p->rc_frame << 9); + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* bit rate */ + if (p->rc_frame) + mfc_write(dev, p->rc_bitrate, + S5P_FIMV_ENC_RC_BIT_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); + /* reaction coefficient */ + if (p->rc_frame) + mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* seq header ctrl */ + shm &= ~(0x1 << 3); + shm |= (p->seq_hdr_mode << 3); + /* frame skip mode */ + shm &= ~(0x3 << 1); + shm |= (p->frame_skip_mode << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + /* fixed target bit */ + s5p_mfc_write_info_v5(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_264->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_264->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* interlace */ + mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT); + /* height */ + if (p->interlace) + mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); + /* loopfilter ctrl */ + mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); + /* loopfilter alpha offset */ + if (p_264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_alpha & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); + /* loopfilter beta offset */ + if (p_264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_beta & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); + /* entropy coding mode */ + if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); + /* number of ref. picture */ + reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* num of ref. pictures of P */ + reg &= ~(0x3 << 5); + reg |= (p_264->num_ref_pic_4p << 5); + /* max number of ref. pictures */ + reg &= ~(0x1F); + reg |= p_264->max_ref_pic; + mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* 8x8 transform enable */ + mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p_264->rc_mb << 8); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_264->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_264->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_264->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* macroblock adaptive scaling features */ + if (p_264->rc_mb) { + reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); + /* dark region */ + reg &= ~(0x1 << 3); + reg |= (p_264->rc_mb_dark << 3); + /* smooth region */ + reg &= ~(0x1 << 2); + reg |= (p_264->rc_mb_smooth << 2); + /* static region */ + reg &= ~(0x1 << 1); + reg |= (p_264->rc_mb_static << 1); + /* high activity region */ + reg &= ~(0x1); + reg |= p_264->rc_mb_activity; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); + } + if (!p->rc_frame && + !p_264->rc_mb) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_264->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* AR VUI control */ + shm &= ~(0x1 << 15); + shm |= (p_264->vui_sar << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + if (p_264->vui_sar) { + /* aspect ration IDC */ + shm = s5p_mfc_read_info_v5(ctx, SAMPLE_ASPECT_RATIO_IDC); + shm &= ~(0xFF); + shm |= p_264->vui_sar_idc; + s5p_mfc_write_info_v5(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); + if (p_264->vui_sar_idc == 0xFF) { + /* sample AR info */ + shm = s5p_mfc_read_info_v5(ctx, EXTENDED_SAR); + shm &= ~(0xFFFFFFFF); + shm |= p_264->vui_ext_sar_width << 16; + shm |= p_264->vui_ext_sar_height; + s5p_mfc_write_info_v5(ctx, shm, EXTENDED_SAR); + } + } + /* intra picture period for H.264 */ + shm = s5p_mfc_read_info_v5(ctx, H264_I_PERIOD); + /* control */ + shm &= ~(0x1 << 16); + shm |= (p_264->open_gop << 16); + /* value */ + if (p_264->open_gop) { + shm &= ~(0xFFFF); + shm |= p_264->open_gop_size; + } + s5p_mfc_write_info_v5(ctx, shm, H264_I_PERIOD); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p_264->cpb_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + unsigned int framerate; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_mpeg4->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_mpeg4->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* quarter_pixel */ + mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame) { + if (p->rc_framerate_denom > 0) { + framerate = p->rc_framerate_num * 1000 / + p->rc_framerate_denom; + mfc_write(dev, framerate, + S5P_FIMV_ENC_RC_FRAME_RATE); + shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING); + shm &= ~(0xFFFFFFFF); + shm |= (1 << 31); + shm |= ((p->rc_framerate_num & 0x7FFF) << 16); + shm |= (p->rc_framerate_denom & 0xFFFF); + s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING); + } + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + } + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_mpeg4->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= (p_h263->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_h263->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +/* Initialize decoding */ +int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_shared_buffer(ctx); + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) + mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); + else + mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); + mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << + S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << + S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & + S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + mfc_write(dev, + ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + + if (flush) + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( + S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + else + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); +} + +/* Decode a single frame */ +int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); + s5p_mfc_set_shared_buffer(ctx); + s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case MFC_DEC_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_LAST_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_RES_CHANGE: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & + S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + break; + } + mfc_debug(2, "Decoding a usual frame\n"); + return 0; +} + +int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else { + mfc_err("Unknown codec for encoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + } + s5p_mfc_set_shared_buffer(ctx); + mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | + (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Encode a single frame */ +int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int cmd; + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + s5p_mfc_set_shared_buffer(ctx); + + if (ctx->state == MFCINST_FINISHING) + cmd = S5P_FIMV_CH_LAST_FRAME; + else + cmd = S5P_FIMV_CH_FRAME_START; + mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + + return 0; +} + +static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int new_ctx; + int cnt; + + spin_lock_irqsave(&dev->condlock, flags); + new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; + cnt = 0; + while (!test_bit(new_ctx, &dev->ctx_work_bits)) { + new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; + if (++cnt > MFC_NUM_CONTEXTS) { + /* No contexts to run */ + spin_unlock_irqrestore(&dev->condlock, flags); + return -EAGAIN; + } + } + spin_unlock_irqrestore(&dev->condlock, flags); + return new_ctx; +} + +static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE); +} + +static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, + temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + index = temp_vb->b->v4l2_buf.index; + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + if (temp_vb->b->v4l2_planes[0].bytesused == 0) { + last_frame = MFC_DEC_LAST_FRAME; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame(ctx, last_frame); + return 0; +} + +static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + unsigned int dst_size; + + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { + mfc_debug(2, "no src buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + if (list_empty(&ctx->src_queue)) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, dev->bank2); + src_mb = NULL; + } else { + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, + list); + src_mb->flags |= MFC_BUF_FLAG_USED; + if (src_mb->b->v4l2_planes[0].bytesused == 0) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, + dev->bank2); + ctx->state = MFCINST_FINISHING; + } else { + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, + 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, + 1); + s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, + src_c_addr); + if (src_mb->flags & MFC_BUF_FLAG_EOS) + ctx->state = MFCINST_FINISHING; + } + } + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + mfc_debug(2, "encoding buffer with index=%d state=%d", + src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); + s5p_mfc_encode_one_frame(ctx); + return 0; +} + +static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + spin_lock_irqsave(&dev->irqlock, flags); + mfc_debug(2, "Preparing to init decoding\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + s5p_mfc_set_dec_desc_buffer(ctx); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + 0, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_decode(ctx); +} + +static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + s5p_mfc_set_enc_ref_buffer(ctx); + spin_lock_irqsave(&dev->irqlock, flags); + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_encode(ctx); +} + +static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + int ret; + + /* + * Header was parsed now starting processing + * First set the output frame buffers + */ + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destionation buffers were " + "mmaped\nMFC requires that all destination are mmaped " + "before starting processing\n"); + return -EAGAIN; + } + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue)) { + mfc_err("Header has been deallocated in the middle of" + " initialization\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EIO; + } + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + 0, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_dec_frame_buffer(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +void s5p_mfc_try_run(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + if (test_bit(0, &dev->enter_suspend)) { + mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); + return; + } + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW\n"); + return; + } + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware\n"); + return; + } + mfc_debug(1, "No ctx is scheduled to be run\n"); + return; + } + ctx = dev->ctx[new_ctx]; + /* Got context to run in ctx */ + /* + * Last frame has already been sent to MFC. + * Now obtaining frames from MFC buffer + */ + s5p_mfc_clock_on(); + if (ctx->type == MFCINST_DECODER) { + s5p_mfc_set_dec_desc_buffer(ctx); + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_open_inst_cmd(ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_close_inst_cmd(ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + mfc_debug(1, "head parsed\n"); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_res_change(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_open_inst_cmd(ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_close_inst_cmd(ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("Invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware\n"); + + /* This is in deed imporant, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + + +void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->num_planes; i++) + vb2_set_plane_payload(b->b, i, 0); + vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h new file mode 100644 index 0000000..97c1ecaf --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h @@ -0,0 +1,163 @@ +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Kamil Debski, Copyright (C) 2011 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef S5P_MFC_OPR_H_ +#define S5P_MFC_OPR_H_ + +#include "s5p_mfc_common.h" + +enum MFC_SHM_OFS { + EXTENEDED_DECODE_STATUS = 0x00, /* D */ + SET_FRAME_TAG = 0x04, /* D */ + GET_FRAME_TAG_TOP = 0x08, /* D */ + GET_FRAME_TAG_BOT = 0x0C, /* D */ + PIC_TIME_TOP = 0x10, /* D */ + PIC_TIME_BOT = 0x14, /* D */ + START_BYTE_NUM = 0x18, /* D */ + + CROP_INFO_H = 0x20, /* D */ + CROP_INFO_V = 0x24, /* D */ + EXT_ENC_CONTROL = 0x28, /* E */ + ENC_PARAM_CHANGE = 0x2C, /* E */ + RC_VOP_TIMING = 0x30, /* E, MPEG4 */ + HEC_PERIOD = 0x34, /* E, MPEG4 */ + METADATA_ENABLE = 0x38, /* C */ + METADATA_STATUS = 0x3C, /* C */ + METADATA_DISPLAY_INDEX = 0x40, /* C */ + EXT_METADATA_START_ADDR = 0x44, /* C */ + PUT_EXTRADATA = 0x48, /* C */ + EXTRADATA_ADDR = 0x4C, /* C */ + + ALLOC_LUMA_DPB_SIZE = 0x64, /* D */ + ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */ + ALLOC_MV_SIZE = 0x6C, /* D */ + P_B_FRAME_QP = 0x70, /* E */ + SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on + ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ + EXTENDED_SAR = 0x78, /* E, H.264, depned on + ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ + DISP_PIC_PROFILE = 0x7C, /* D */ + FLUSH_CMD_TYPE = 0x80, /* C */ + FLUSH_CMD_INBUF1 = 0x84, /* C */ + FLUSH_CMD_INBUF2 = 0x88, /* C */ + FLUSH_CMD_OUTBUF = 0x8C, /* E */ + NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8) + depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */ + NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0) + depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */ + NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504) + depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */ + H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */ + RC_CONTROL_CONFIG = 0xA0, /* E */ + BATCH_INPUT_ADDR = 0xA4, /* E */ + BATCH_OUTPUT_ADDR = 0xA8, /* E */ + BATCH_OUTPUT_SIZE = 0xAC, /* E */ + MIN_LUMA_DPB_SIZE = 0xB0, /* D */ + DEVICE_FORMAT_ID = 0xB4, /* C */ + H264_POC_TYPE = 0xB8, /* D */ + MIN_CHROMA_DPB_SIZE = 0xBC, /* D */ + DISP_PIC_FRAME_TYPE = 0xC0, /* D */ + FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */ + ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */ + EXTENDED_PAR = 0xCC, /* D, MPEG4 */ + DBG_HISTORY_INPUT0 = 0xD0, /* C */ + DBG_HISTORY_INPUT1 = 0xD4, /* C */ + DBG_HISTORY_OUTPUT = 0xD8, /* C */ + HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */ + FRAME_PACK_SEI_ENABLE = 0x168, /* C */ + FRAME_PACK_SEI_AVAIL = 0x16c, /* D */ + FRAME_PACK_SEI_INFO = 0x17c, /* E */ +}; + +int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx); +int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx); + +/* Decoding functions */ +int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx); +int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, + unsigned int start_num_byte, + unsigned int buf_size); + +/* Encoding functions */ +void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr); +int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size); +void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr); +int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx); + +int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame); +int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx); + +/* Memory allocation */ +int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx); +void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx); +void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx); + +int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx); +void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx); + +int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx); +void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx); + +void s5p_mfc_try_run(struct s5p_mfc_dev *dev); +void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); + +/* Shared memory ops */ +void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs); + +unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, + unsigned int ofs); + +#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \ + S5P_FIMV_SI_DISPLAY_Y_ADR) << \ + MFC_OFFSET_SHIFT) +#define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \ + S5P_FIMV_SI_DECODE_Y_ADR) << \ + MFC_OFFSET_SHIFT) +#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \ + S5P_FIMV_SI_DISPLAY_STATUS) +#define s5p_mfc_get_dec_status() readl(dev->regs_base + \ + S5P_FIMV_SI_DECODE_STATUS) +#define s5p_mfc_get_frame_type() (readl(dev->regs_base + \ + S5P_FIMV_DECODE_FRAME_TYPE) \ + & S5P_FIMV_DECODE_FRAME_MASK) +#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ + S5P_FIMV_SI_CONSUMED_BYTES) +#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ + S5P_FIMV_RISC2HOST_CMD) & \ + S5P_FIMV_RISC2HOST_CMD_MASK) +#define s5p_mfc_get_int_err() readl(dev->regs_base + \ + S5P_FIMV_RISC2HOST_ARG2) +#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \ + S5P_FIMV_ERR_DEC_SHIFT) +#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \ + S5P_FIMV_ERR_DSPL_SHIFT) +#define s5p_mfc_get_img_width() readl(dev->regs_base + \ + S5P_FIMV_SI_HRESOL) +#define s5p_mfc_get_img_height() readl(dev->regs_base + \ + S5P_FIMV_SI_VRESOL) +#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \ + S5P_FIMV_SI_BUF_NUMBER) +#define s5p_mfc_get_inst_no() readl(dev->regs_base + \ + S5P_FIMV_RISC2HOST_ARG1) +#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ + S5P_FIMV_ENC_SI_STRM_SIZE) +#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ + S5P_FIMV_ENC_SI_SLICE_TYPE) + +#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c deleted file mode 100644 index b5933d2..0000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifdef CONFIG_ARCH_EXYNOS4 -#include -#endif -#include -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" - -int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; - - ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx, - SHARED_BUF_SIZE); - if (IS_ERR(ctx->shm_alloc)) { - mfc_err("failed to allocate shared memory\n"); - return PTR_ERR(ctx->shm_alloc); - } - /* shm_ofs only keeps the offset from base (port a) */ - ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc) - - dev->bank1; - BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc); - if (!ctx->shm) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_ofs = 0; - ctx->shm_alloc = NULL; - mfc_err("failed to virt addr of shared memory\n"); - return -ENOMEM; - } - memset((void *)ctx->shm, 0, SHARED_BUF_SIZE); - wmb(); - return 0; -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h deleted file mode 100644 index 416ebd7..0000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef S5P_MFC_SHM_H_ -#define S5P_MFC_SHM_H_ - -enum MFC_SHM_OFS { - EXTENEDED_DECODE_STATUS = 0x00, /* D */ - SET_FRAME_TAG = 0x04, /* D */ - GET_FRAME_TAG_TOP = 0x08, /* D */ - GET_FRAME_TAG_BOT = 0x0C, /* D */ - PIC_TIME_TOP = 0x10, /* D */ - PIC_TIME_BOT = 0x14, /* D */ - START_BYTE_NUM = 0x18, /* D */ - - CROP_INFO_H = 0x20, /* D */ - CROP_INFO_V = 0x24, /* D */ - EXT_ENC_CONTROL = 0x28, /* E */ - ENC_PARAM_CHANGE = 0x2C, /* E */ - RC_VOP_TIMING = 0x30, /* E, MPEG4 */ - HEC_PERIOD = 0x34, /* E, MPEG4 */ - METADATA_ENABLE = 0x38, /* C */ - METADATA_STATUS = 0x3C, /* C */ - METADATA_DISPLAY_INDEX = 0x40, /* C */ - EXT_METADATA_START_ADDR = 0x44, /* C */ - PUT_EXTRADATA = 0x48, /* C */ - EXTRADATA_ADDR = 0x4C, /* C */ - - ALLOC_LUMA_DPB_SIZE = 0x64, /* D */ - ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */ - ALLOC_MV_SIZE = 0x6C, /* D */ - P_B_FRAME_QP = 0x70, /* E */ - SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on - ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ - EXTENDED_SAR = 0x78, /* E, H.264, depned on - ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ - DISP_PIC_PROFILE = 0x7C, /* D */ - FLUSH_CMD_TYPE = 0x80, /* C */ - FLUSH_CMD_INBUF1 = 0x84, /* C */ - FLUSH_CMD_INBUF2 = 0x88, /* C */ - FLUSH_CMD_OUTBUF = 0x8C, /* E */ - NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8) - depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */ - NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0) - depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */ - NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504) - depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */ - H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */ - RC_CONTROL_CONFIG = 0xA0, /* E */ - BATCH_INPUT_ADDR = 0xA4, /* E */ - BATCH_OUTPUT_ADDR = 0xA8, /* E */ - BATCH_OUTPUT_SIZE = 0xAC, /* E */ - MIN_LUMA_DPB_SIZE = 0xB0, /* D */ - DEVICE_FORMAT_ID = 0xB4, /* C */ - H264_POC_TYPE = 0xB8, /* D */ - MIN_CHROMA_DPB_SIZE = 0xBC, /* D */ - DISP_PIC_FRAME_TYPE = 0xC0, /* D */ - FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */ - ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */ - EXTENDED_PAR = 0xCC, /* D, MPEG4 */ - DBG_HISTORY_INPUT0 = 0xD0, /* C */ - DBG_HISTORY_INPUT1 = 0xD4, /* C */ - DBG_HISTORY_OUTPUT = 0xD8, /* C */ - HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */ -}; - -int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx); - -#define s5p_mfc_write_shm(ctx, x, ofs) \ - do { \ - writel(x, (ctx->shm + ofs)); \ - wmb(); \ - } while (0) - -static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs) -{ - rmb(); - return readl(ctx->shm + ofs); -} - -#endif /* S5P_MFC_SHM_H_ */ -- cgit v0.10.2 From 43a1ea1f90382a6a8fcf5ed94835b8518ebdefc8 Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Wed, 3 Oct 2012 22:19:08 -0300 Subject: [media] s5p-mfc: Update MFCv5 driver for callback based architecture Modifies the driver to use a callback based architecture for hardware dependent calls. This architecture is suitable for supporting co-existence with newer versions of MFC hardware. Signed-off-by: Arun Kumar K Signed-off-by: Naveen Krishna Chatradhi Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index 39496b8..cfb9ee9 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o -s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr_v5.o +s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o -s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd_v5.o +s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o s5p-mfc-y += s5p_mfc_pm.o +s5p-mfc-y += s5p_mfc_opr_v5.o s5p_mfc_cmd_v5.o diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 74bb284..d711b0f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,13 +22,14 @@ #include #include #include -#include "regs-mfc.h" +#include "s5p_mfc_common.h" #include "s5p_mfc_ctrl.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_dec.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" -#include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_pm.h" #define S5P_MFC_NAME "s5p-mfc" @@ -148,10 +149,12 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) if (!ctx) continue; ctx->state = MFCINST_ERROR; - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); clear_work_bit(ctx); - wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0); + wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0); } clear_bit(0, &dev->hw_lock); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -198,6 +201,7 @@ static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_buf *dst_buf; + struct s5p_mfc_dev *dev = ctx->dev; ctx->state = MFCINST_FINISHED; ctx->sequence++; @@ -212,8 +216,8 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = (ctx->sequence++); - if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) == - s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT)) + if (s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_bot, ctx)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED; @@ -227,8 +231,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_buf, *src_buf; - size_t dec_y_addr = s5p_mfc_get_dec_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dec_y_addr; + unsigned int frame_type; + + dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); /* Copy timestamp / timecode from decoded src to dst and set appropraite flags */ @@ -264,10 +271,13 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_buf; - size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dspl_y_addr; + unsigned int frame_type; unsigned int index; + dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); + /* If frame is same as previous then skip and do not dequeue */ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { if (!ctx->after_packed_pb) @@ -284,8 +294,10 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = ctx->sequence; - if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) == - s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT)) + if (s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_bot, ctx)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = @@ -316,21 +328,21 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, unsigned int index; - dst_frame_status = s5p_mfc_get_dspl_status() + dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; - res_change = s5p_mfc_get_dspl_status() + res_change = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK; mfc_debug(2, "Frame Status: %x\n", dst_frame_status); if (ctx->state == MFCINST_RES_CHANGE_INIT) ctx->state = MFCINST_RES_CHANGE_FLUSH; if (res_change) { ctx->state = MFCINST_RES_CHANGE_INIT; - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return; } if (ctx->dpb_flush_flag) @@ -364,9 +376,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, && !list_empty(&ctx->src_queue)) { src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - ctx->consumed_stream += s5p_mfc_get_consumed_stream(); - if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC && - s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME + ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops, + get_consumed_stream, dev); + if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC && + s5p_mfc_hw_call(dev->mfc_ops, + get_dec_frame_type, dev) == + S5P_FIMV_DECODE_FRAME_P_FRAME && ctx->consumed_stream + STUFF_BYTE < src_buf->b->v4l2_planes[0].bytesused) { /* Run MFC again on the same buffer */ @@ -378,7 +393,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, ctx->consumed_stream = 0; list_del(&src_buf->list); ctx->src_queue_cnt--; - if (s5p_mfc_err_dec(err) > 0) + if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0) vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR); else vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE); @@ -389,12 +404,12 @@ leave_handle_frame: if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) || ctx->dst_queue_cnt < ctx->dpb_count) clear_work_bit(ctx); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Error handling for interrupt */ @@ -411,7 +426,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, dev = ctx->dev; mfc_err("Interrupt Error: %08x\n", err); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); /* Error recovery is dependent on the state of context */ @@ -440,9 +455,11 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, ctx->state = MFCINST_ERROR; /* Mark all dst buffers as having an error */ spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); /* Mark all src buffers as having an error */ - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); spin_unlock_irqrestore(&dev->irqlock, flags); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -469,8 +486,10 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, if (ctx->c_ops->post_seq_start(ctx)) mfc_err("post_seq_start() failed\n"); } else { - ctx->img_width = s5p_mfc_get_img_width(); - ctx->img_height = s5p_mfc_get_img_height(); + ctx->img_width = s5p_mfc_hw_call(dev->mfc_ops, get_img_width, + dev); + ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, + dev); ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); @@ -506,18 +525,19 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, guard_height, S5P_FIMV_DEC_BUF_ALIGN); ctx->mv_size = 0; } - ctx->dpb_count = s5p_mfc_get_dpb_count(); + ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, + dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else ctx->state = MFCINST_HEAD_PARSED; } - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); } @@ -532,7 +552,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, if (ctx == NULL) return; dev = ctx->dev; - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -559,7 +579,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -601,7 +621,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Interrupt processing */ @@ -617,81 +637,83 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) atomic_set(&dev->watchdog_cnt, 0); ctx = dev->ctx[dev->curr_ctx]; /* Get the reason of interrupt and the error code */ - reason = s5p_mfc_get_int_reason(); - err = s5p_mfc_get_int_err(); + reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev); + err = s5p_mfc_hw_call(dev->mfc_ops, get_int_err, dev); mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err); switch (reason) { - case S5P_FIMV_R2H_CMD_ERR_RET: + case S5P_MFC_R2H_CMD_ERR_RET: /* An error has occured */ if (ctx->state == MFCINST_RUNNING && - s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START) + s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= + dev->warn_start) s5p_mfc_handle_frame(ctx, reason, err); else s5p_mfc_handle_error(ctx, reason, err); clear_bit(0, &dev->enter_suspend); break; - case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: - case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + case S5P_MFC_R2H_CMD_SLICE_DONE_RET: + case S5P_MFC_R2H_CMD_FIELD_DONE_RET: + case S5P_MFC_R2H_CMD_FRAME_DONE_RET: if (ctx->c_ops->post_frame_start) { if (ctx->c_ops->post_frame_start(ctx)) mfc_err("post_frame_start() failed\n"); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { s5p_mfc_handle_frame(ctx, reason, err); } break; - case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: + case S5P_MFC_R2H_CMD_SEQ_DONE_RET: s5p_mfc_handle_seq_done(ctx, reason, err); break; - case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: - ctx->inst_no = s5p_mfc_get_inst_no(); + case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: + ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); ctx->state = MFCINST_GOT_INST; clear_work_bit(ctx); wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: clear_work_bit(ctx); ctx->state = MFCINST_FREE; wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_SYS_INIT_RET: - case S5P_FIMV_R2H_CMD_FW_STATUS_RET: - case S5P_FIMV_R2H_CMD_SLEEP_RET: - case S5P_FIMV_R2H_CMD_WAKEUP_RET: + case S5P_MFC_R2H_CMD_SYS_INIT_RET: + case S5P_MFC_R2H_CMD_FW_STATUS_RET: + case S5P_MFC_R2H_CMD_SLEEP_RET: + case S5P_MFC_R2H_CMD_WAKEUP_RET: if (ctx) clear_work_bit(ctx); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); clear_bit(0, &dev->hw_lock); clear_bit(0, &dev->enter_suspend); break; - case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: + case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: s5p_mfc_handle_init_buffers(ctx, reason, err); break; - case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: + case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET: s5p_mfc_handle_stream_complete(ctx, reason, err); break; default: mfc_debug(2, "Unknown int reason\n"); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); } mfc_debug_leave(); return IRQ_HANDLED; irq_cleanup_hw: - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -700,7 +722,7 @@ irq_cleanup_hw: s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); mfc_debug(2, "Exit via irq_cleanup_hw\n"); return IRQ_HANDLED; } @@ -748,6 +770,7 @@ static int s5p_mfc_open(struct file *file) if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { ctx->type = MFCINST_DECODER; ctx->c_ops = get_dec_codec_ops(); + s5p_mfc_dec_init(ctx); /* Setup ctrl handler */ ret = s5p_mfc_dec_ctrls_setup(ctx); if (ret) { @@ -760,6 +783,7 @@ static int s5p_mfc_open(struct file *file) /* only for encoder */ INIT_LIST_HEAD(&ctx->ref_queue); ctx->ref_queue_cnt = 0; + s5p_mfc_enc_init(ctx); /* Setup ctrl handler */ ret = s5p_mfc_enc_ctrls_setup(ctx); if (ret) { @@ -885,19 +909,20 @@ static int s5p_mfc_release(struct file *file) ctx->state = MFCINST_RETURN_INST; set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); /* Wait until instance is returned or timeout occured */ if (s5p_mfc_wait_for_done_ctx - (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { + (ctx, S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { s5p_mfc_clock_off(); mfc_err("Err returning instance\n"); } mfc_debug(2, "After free instance\n"); /* Free resources */ - s5p_mfc_release_codec_buffers(ctx); - s5p_mfc_release_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); if (ctx->type == MFCINST_DECODER) - s5p_mfc_release_dec_desc_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, + ctx); ctx->inst_no = MFC_NO_INSTANCE_SET; } @@ -909,6 +934,7 @@ static int s5p_mfc_release(struct file *file) mfc_debug(2, "Last instance - release firmware\n"); /* reset <-> F/W release */ s5p_mfc_reset(dev); + s5p_mfc_deinit_hw(dev); s5p_mfc_release_firmware(dev); del_timer_sync(&dev->watchdog_timer); if (s5p_mfc_power_off() < 0) @@ -1159,6 +1185,10 @@ static int s5p_mfc_probe(struct platform_device *pdev) dev->watchdog_timer.data = (unsigned long)dev; dev->watchdog_timer.function = s5p_mfc_watchdog; + /* Initialize HW ops and commands based on MFC version */ + s5p_mfc_init_hw_ops(dev); + s5p_mfc_init_hw_cmds(dev); + pr_debug("%s--\n", __func__); return 0; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c new file mode 100644 index 0000000..8ea304b --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c @@ -0,0 +1,24 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_cmd_v5.h" + +static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; + +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) +{ + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); + dev->mfc_cmds = s5p_mfc_cmds; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h new file mode 100644 index 0000000..282e6c7 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h @@ -0,0 +1,35 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5P_MFC_CMD_H_ +#define S5P_MFC_CMD_H_ + +#include "s5p_mfc_common.h" + +#define MAX_H2R_ARG 4 + +struct s5p_mfc_cmd_args { + unsigned int arg[MAX_H2R_ARG]; +}; + +struct s5p_mfc_hw_cmds { + int (*cmd_host2risc)(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args); + int (*sys_init_cmd)(struct s5p_mfc_dev *dev); + int (*sleep_cmd)(struct s5p_mfc_dev *dev); + int (*wakeup_cmd)(struct s5p_mfc_dev *dev); + int (*open_inst_cmd)(struct s5p_mfc_ctx *ctx); + int (*close_inst_cmd)(struct s5p_mfc_ctx *ctx); +}; + +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev); +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index cdd02b9..e4eb956 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -1,5 +1,5 @@ /* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c * * Copyright (C) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ @@ -11,13 +11,13 @@ */ #include "regs-mfc.h" -#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" /* This function is used to send a command to the MFC */ -static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) +int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) { int cur_cmd; unsigned long timeout; @@ -41,35 +41,37 @@ static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, } /* Initialize the MFC */ -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) +int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = dev->fw_size; - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, + &h2r_args); } /* Suspend the MFC hardware */ -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev) +int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); } /* Wake up the MFC hardware */ -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) +int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP, + &h2r_args); } -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) +int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; @@ -79,11 +81,41 @@ int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); dev->curr_ctx = ctx->num; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->codec_mode; + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_DEC; + break; + case S5P_MFC_CODEC_VC1_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1_DEC; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_DEC; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG2_DEC; + break; + case S5P_MFC_CODEC_H263_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_DEC; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1RCV_DEC; + break; + case S5P_MFC_CODEC_H264_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_ENC; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_ENC; + break; + case S5P_MFC_CODEC_H263_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_ENC; + break; + default: + h2r_args.arg[0] = S5P_FIMV_CODEC_NONE; + }; h2r_args.arg[1] = 0; /* no crc & no pixelcache */ h2r_args.arg[2] = ctx->ctx_ofs; h2r_args.arg[3] = ctx->ctx_size; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, &h2r_args); if (ret) { mfc_err("Failed to create a new instance\n"); @@ -92,7 +124,7 @@ int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) return ret; } -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) +int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; @@ -108,7 +140,7 @@ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) dev->curr_ctx = ctx->num; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); h2r_args.arg[0] = ctx->inst_no; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, &h2r_args); if (ret) { mfc_err("Failed to return an instance\n"); @@ -118,3 +150,17 @@ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) return 0; } +/* Initialize cmd function pointers for MFC v5 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v5, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v5, + .sleep_cmd = s5p_mfc_sleep_cmd_v5, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v5, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v5, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v5, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) +{ + return &s5p_mfc_cmds_v5; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h index 8b090d3..6928a55 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h @@ -1,5 +1,5 @@ /* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h * * Copyright (C) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ @@ -10,21 +10,11 @@ * (at your option) any later version. */ -#ifndef S5P_MFC_CMD_H_ -#define S5P_MFC_CMD_H_ +#ifndef S5P_MFC_CMD_V5_H_ +#define S5P_MFC_CMD_V5_H_ #include "s5p_mfc_common.h" -#define MAX_H2R_ARG 4 - -struct s5p_mfc_cmd_args { - unsigned int arg[MAX_H2R_ARG]; -}; - -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx); -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx); +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void); #endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 519b0d6..82931d4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -74,7 +74,40 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) #define MFC_ENC_CAP_PLANE_COUNT 1 #define MFC_ENC_OUT_PLANE_COUNT 2 #define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 64 +#define MFC_MAX_CTRLS 70 + +#define S5P_MFC_CODEC_NONE -1 +#define S5P_MFC_CODEC_H264_DEC 0 +#define S5P_MFC_CODEC_H264_MVC_DEC 1 +#define S5P_MFC_CODEC_VC1_DEC 2 +#define S5P_MFC_CODEC_MPEG4_DEC 3 +#define S5P_MFC_CODEC_MPEG2_DEC 4 +#define S5P_MFC_CODEC_H263_DEC 5 +#define S5P_MFC_CODEC_VC1RCV_DEC 6 +#define S5P_MFC_CODEC_VP8_DEC 7 + +#define S5P_MFC_CODEC_H264_ENC 20 +#define S5P_MFC_CODEC_H264_MVC_ENC 21 +#define S5P_MFC_CODEC_MPEG4_ENC 22 +#define S5P_MFC_CODEC_H263_ENC 23 + +#define S5P_MFC_R2H_CMD_EMPTY 0 +#define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 +#define S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET 2 +#define S5P_MFC_R2H_CMD_SEQ_DONE_RET 3 +#define S5P_MFC_R2H_CMD_INIT_BUFFERS_RET 4 +#define S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET 6 +#define S5P_MFC_R2H_CMD_SLEEP_RET 7 +#define S5P_MFC_R2H_CMD_WAKEUP_RET 8 +#define S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET 9 +#define S5P_MFC_R2H_CMD_DPB_FLUSH_RET 10 +#define S5P_MFC_R2H_CMD_NAL_ABORT_RET 11 +#define S5P_MFC_R2H_CMD_FW_STATUS_RET 12 +#define S5P_MFC_R2H_CMD_FRAME_DONE_RET 13 +#define S5P_MFC_R2H_CMD_FIELD_DONE_RET 14 +#define S5P_MFC_R2H_CMD_SLICE_DONE_RET 15 +#define S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET 16 +#define S5P_MFC_R2H_CMD_ERR_RET 32 #define mfc_read(dev, offset) readl(dev->regs_base + (offset)) #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ @@ -212,6 +245,9 @@ struct s5p_mfc_pm { * @watchdog_work: worker for the watchdog * @alloc_ctx: videobuf2 allocator contexts for two memory banks * @enter_suspend: flag set when entering suspend + * @warn_start: hardware error code from which warnings start + * @mfc_ops: ops structure holding HW operation function pointers + * @mfc_cmds: cmd structure holding HW commands function pointers * */ struct s5p_mfc_dev { @@ -248,6 +284,10 @@ struct s5p_mfc_dev { struct work_struct watchdog_work; void *alloc_ctx[2]; unsigned long enter_suspend; + + int warn_start; + struct s5p_mfc_hw_ops *mfc_ops; + struct s5p_mfc_hw_cmds *mfc_cmds; }; /** @@ -565,6 +605,9 @@ struct mfc_control { __u8 is_volatile; }; +/* Macro for making hardware specific calls */ +#define s5p_mfc_hw_call(f, op, args...) \ + ((f && f->op) ? f->op(args) : -ENODEV) #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) #define ctrl_to_ctx(__ctrl) \ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index f31bff9..7666e94 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -15,11 +15,11 @@ #include #include #include -#include "regs-mfc.h" -#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" static void *s5p_mfc_bitproc_buf; @@ -230,7 +230,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clean_dev_int_flags(dev); mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); @@ -238,7 +238,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } s5p_mfc_clean_dev_int_flags(dev); /* 4. Initialize firmware */ - ret = s5p_mfc_sys_init_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); s5p_mfc_reset(dev); @@ -246,7 +246,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) return ret; } mfc_debug(2, "Ok, now will write a command to init the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); @@ -254,7 +254,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_SYS_INIT_RET) { + S5P_MFC_R2H_CMD_SYS_INIT_RET) { /* Failure. */ mfc_err("Failed to init firmware - error: %d int: %d\n", dev->int_err, dev->int_type); @@ -271,6 +271,17 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } +/* Deinitialize hardware */ +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) +{ + s5p_mfc_clock_on(); + + s5p_mfc_reset(dev); + s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); + + s5p_mfc_clock_off(); +} + int s5p_mfc_sleep(struct s5p_mfc_dev *dev) { int ret; @@ -278,19 +289,19 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) mfc_debug_enter(); s5p_mfc_clock_on(); s5p_mfc_clean_dev_int_flags(dev); - ret = s5p_mfc_sleep_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); return ret; } - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) { mfc_err("Failed to sleep\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_SLEEP_RET) { + S5P_MFC_R2H_CMD_SLEEP_RET) { /* Failure. */ mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err, dev->int_type); @@ -320,7 +331,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Initialize firmware */ - ret = s5p_mfc_wakeup_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); return ret; @@ -328,14 +339,14 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) /* 4. Release reset signal to the RISC */ mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { mfc_err("Failed to load firmware\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_WAKEUP_RET) { + S5P_MFC_R2H_CMD_WAKEUP_RET) { /* Failure. */ mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, dev->int_type); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h index e1e0c54..90aa9b9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h @@ -20,6 +20,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev); int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev); int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev); int s5p_mfc_sleep(struct s5p_mfc_dev *dev); int s5p_mfc_wakeup(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 653f14b..107609c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -23,82 +23,84 @@ #include #include #include -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_dec.h" #include "s5p_mfc_intr.h" -#include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" +#define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264 +#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT + static struct s5p_mfc_fmt formats[] = { { .name = "4:2:0 2 Planes 64x32 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_FIMV_CODEC_NONE, + .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - }, + }, { .name = "4:2:0 2 Planes", .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_FIMV_CODEC_NONE, + .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, }, { .name = "H264 Encoded Stream", .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_FIMV_CODEC_H264_DEC, + .codec_mode = S5P_MFC_CODEC_H264_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, { .name = "H263 Encoded Stream", .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_FIMV_CODEC_H263_DEC, + .codec_mode = S5P_MFC_CODEC_H263_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, { .name = "MPEG1 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG1, - .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, { .name = "MPEG2 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG2, - .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, { .name = "MPEG4 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, { .name = "XviD Encoded Stream", .fourcc = V4L2_PIX_FMT_XVID, - .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, { .name = "VC1 Encoded Stream", .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, - .codec_mode = S5P_FIMV_CODEC_VC1_DEC, + .codec_mode = S5P_MFC_CODEC_VC1_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, { .name = "VC1 RCV Encoded Stream", .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, - .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC, + .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, .type = MFC_FMT_DEC, .num_planes = 1, }, @@ -296,7 +298,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) /* If the MFC is parsing the header, * so wait until it is finished */ s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET, + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && @@ -379,7 +381,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) goto out; } fmt = find_format(f, MFC_FMT_DEC); - if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) { + if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { mfc_err("Unknown codec\n"); ret = -EINVAL; goto out; @@ -475,7 +477,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, return -ENOMEM; } ctx->total_dpb_count = reqbufs->count; - ret = s5p_mfc_alloc_codec_buffers(ctx); + ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx); if (ret) { mfc_err("Failed to allocate decoding buffers\n"); reqbufs->count = 0; @@ -491,15 +493,16 @@ static int vidioc_reqbufs(struct file *file, void *priv, reqbufs->count = 0; s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - s5p_mfc_release_codec_buffers(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, + ctx); s5p_mfc_clock_off(); return -ENOMEM; } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0); + S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0); } return ret; } @@ -581,18 +584,22 @@ static int vidioc_streamon(struct file *file, void *priv, ctx->src_bufs_cnt = 0; ctx->capture_state = QUEUE_FREE; ctx->output_state = QUEUE_FREE; - s5p_mfc_alloc_instance_buffer(ctx); - s5p_mfc_alloc_dec_temp_buffers(ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, + ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_dec_temp_buffers, + ctx); set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) { + S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { /* Error or timeout */ mfc_err("Error getting instance from hardware\n"); - s5p_mfc_release_instance_buffer(ctx); - s5p_mfc_release_dec_desc_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, + release_instance_buffer, ctx); + s5p_mfc_hw_call(dev->mfc_ops, + release_dec_desc_buffer, ctx); return -EIO; } mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); @@ -661,7 +668,7 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) /* Should wait for the header to be parsed */ s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0); + S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); if (ctx->state >= MFCINST_HEAD_PARSED && ctx->state < MFCINST_ABORT) { ctrl->val = ctx->dpb_count; @@ -685,6 +692,7 @@ static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *cr) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_dev *dev = ctx->dev; u32 left, right, top, bottom; if (ctx->state != MFCINST_HEAD_PARSED && @@ -694,10 +702,10 @@ static int vidioc_g_crop(struct file *file, void *priv, return -EINVAL; } if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { - left = s5p_mfc_read_info_v5(ctx, CROP_INFO_H); + left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; - top = s5p_mfc_read_info_v5(ctx, CROP_INFO_V); + top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx); bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; cr->c.left = left; @@ -875,7 +883,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -891,19 +899,21 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q) dev->curr_ctx == ctx->num && dev->hw_lock) { ctx->state = MFCINST_ABORT; s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0); + S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); aborted = 1; } spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; ctx->dpb_flush_flag = 1; ctx->dec_dst_flag = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; } @@ -943,7 +953,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_dec_qops = { @@ -1027,3 +1037,13 @@ void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) ctx->ctrls[i] = NULL; } +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_DEC; + ctx->src_fmt = find_format(&f, MFC_FMT_DEC); + f.fmt.pix_mp.pixelformat = DEF_DST_FMT_DEC; + ctx->dst_fmt = find_format(&f, MFC_FMT_RAW); + mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n", + (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt); +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h index fdf1d99..d06a7ca 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h @@ -19,5 +19,6 @@ const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_dec_def_fmt(bool src); int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx); #endif /* S5P_MFC_DEC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index f5f7e3c..3b0e594 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -25,46 +25,48 @@ #include #include #include -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" -#include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_opr.h" + +#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12MT +#define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264 static struct s5p_mfc_fmt formats[] = { { .name = "4:2:0 2 Planes 64x32 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_FIMV_CODEC_NONE, + .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, }, { .name = "4:2:0 2 Planes", .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_FIMV_CODEC_NONE, + .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, }, { .name = "H264 Encoded Stream", .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_FIMV_CODEC_H264_ENC, + .codec_mode = S5P_MFC_CODEC_H264_ENC, .type = MFC_FMT_ENC, .num_planes = 1, }, { .name = "MPEG4 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC, + .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, .type = MFC_FMT_ENC, .num_planes = 1, }, { .name = "H263 Encoded Stream", .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_FIMV_CODEC_H263_ENC, + .codec_mode = S5P_MFC_CODEC_H263_ENC, .type = MFC_FMT_ENC, .num_planes = 1, }, @@ -619,7 +621,8 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); return 0; } @@ -638,14 +641,14 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) list_del(&dst_mb->list); ctx->dst_queue_cnt--; vb2_set_plane_payload(dst_mb->b, 0, - s5p_mfc_get_enc_strm_size()); + s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev)); vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); spin_unlock_irqrestore(&dev->irqlock, flags); } ctx->state = MFCINST_RUNNING; if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -662,14 +665,16 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); - s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr, + src_c_addr); spin_unlock_irqrestore(&dev->irqlock, flags); spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); return 0; @@ -685,15 +690,16 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) unsigned int strm_size; unsigned long flags; - slice_type = s5p_mfc_get_enc_slice_type(); - strm_size = s5p_mfc_get_enc_strm_size(); + slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev); + strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev); mfc_debug(2, "Encoded slice type: %d", slice_type); mfc_debug(2, "Encoded stream size: %d", strm_size); mfc_debug(2, "Display order: %d", mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); spin_lock_irqsave(&dev->irqlock, flags); if (slice_type >= 0) { - s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr); + s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, + &enc_y_addr, &enc_c_addr); list_for_each_entry(mb_entry, &ctx->src_queue, list) { mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); @@ -939,15 +945,16 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) pix_fmt_mp->plane_fmt[0].bytesperline = 0; ctx->dst_bufs_cnt = 0; ctx->capture_state = QUEUE_FREE; - s5p_mfc_alloc_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx); set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, \ - S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) { + S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 1)) { /* Error or timeout */ mfc_err("Error getting instance from hardware\n"); - s5p_mfc_release_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, + ctx); ret = -EIO; goto out; } @@ -1042,7 +1049,8 @@ static int vidioc_reqbufs(struct file *file, void *priv, return ret; } ctx->capture_state = QUEUE_BUFS_REQUESTED; - ret = s5p_mfc_alloc_codec_buffers(ctx); + ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, alloc_codec_buffers, + ctx); if (ret) { mfc_err("Failed to allocate encoding buffers\n"); reqbufs->count = 0; @@ -1500,7 +1508,7 @@ int vidioc_encoder_cmd(struct file *file, void *priv, mfc_debug(2, "EOS: empty src queue, entering finishing state"); ctx->state = MFCINST_FINISHING; spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { mfc_debug(2, "EOS: marking last buffer of stream"); buf = list_entry(ctx->src_queue.prev, @@ -1715,7 +1723,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -1729,19 +1737,21 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q) ctx->state == MFCINST_RUNNING) && dev->curr_ctx == ctx->num && dev->hw_lock) { ctx->state = MFCINST_ABORT; - s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET, + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); } ctx->state = MFCINST_FINISHED; spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { cleanup_ref_queue(ctx); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; } @@ -1782,7 +1792,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_enc_qops = { @@ -1880,3 +1890,13 @@ void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx) for (i = 0; i < NUM_CTRLS; i++) ctx->ctrls[i] = NULL; } + +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_ENC; + ctx->src_fmt = find_format(&f, MFC_FMT_RAW); + f.fmt.pix_mp.pixelformat = DEF_DST_FMT_ENC; + ctx->dst_fmt = find_format(&f, MFC_FMT_ENC); +} + diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h index ca9fd66..5118d46 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h @@ -19,5 +19,6 @@ const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_enc_def_fmt(bool src); int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx); #endif /* S5P_MFC_ENC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c index 37860e2..5b8f0e0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c @@ -17,7 +17,6 @@ #include #include #include -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" @@ -28,7 +27,7 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) ret = wait_event_interruptible_timeout(dev->queue, (dev->int_cond && (dev->int_type == command - || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || dev->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); if (ret == 0) { mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n", @@ -40,7 +39,7 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) } mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n", dev->int_type, command); - if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET) + if (dev->int_type == S5P_MFC_R2H_CMD_ERR_RET) return 1; return 0; } @@ -60,12 +59,12 @@ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, if (interrupt) { ret = wait_event_interruptible_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } else { ret = wait_event_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } if (ret == 0) { @@ -78,7 +77,7 @@ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, } mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n", ctx->int_type, command); - if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET) + if (ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET) return 1; return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c new file mode 100644 index 0000000..b6246b2 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -0,0 +1,25 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" + +static struct s5p_mfc_hw_ops *s5p_mfc_ops; + +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) +{ + s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; + dev->mfc_ops = s5p_mfc_ops; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h new file mode 100644 index 0000000..420abec --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -0,0 +1,84 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Kamil Debski, Copyright (C) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef S5P_MFC_OPR_H_ +#define S5P_MFC_OPR_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_ops { + int (*alloc_dec_temp_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_dec_desc_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_codec_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_codec_buffers)(struct s5p_mfc_ctx *ctx); + int (*alloc_instance_buffer)(struct s5p_mfc_ctx *ctx); + void (*release_instance_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx); + void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx); + int (*set_dec_stream_buffer)(struct s5p_mfc_ctx *ctx, + int buf_addr, unsigned int start_num_byte, + unsigned int buf_size); + int (*set_dec_frame_buffer)(struct s5p_mfc_ctx *ctx); + int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size); + void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr); + void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr); + int (*set_enc_ref_buffer)(struct s5p_mfc_ctx *ctx); + int (*init_decode)(struct s5p_mfc_ctx *ctx); + int (*init_encode)(struct s5p_mfc_ctx *ctx); + int (*encode_one_frame)(struct s5p_mfc_ctx *ctx); + void (*try_run)(struct s5p_mfc_dev *dev); + void (*cleanup_queue)(struct list_head *lh, + struct vb2_queue *vq); + void (*clear_int_flags)(struct s5p_mfc_dev *dev); + void (*write_info)(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs); + unsigned int (*read_info)(struct s5p_mfc_ctx *ctx, + unsigned int ofs); + int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dec_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dspl_status)(struct s5p_mfc_dev *dev); + int (*get_dec_status)(struct s5p_mfc_dev *dev); + int (*get_dec_frame_type)(struct s5p_mfc_dev *dev); + int (*get_disp_frame_type)(struct s5p_mfc_ctx *ctx); + int (*get_consumed_stream)(struct s5p_mfc_dev *dev); + int (*get_int_reason)(struct s5p_mfc_dev *dev); + int (*get_int_err)(struct s5p_mfc_dev *dev); + int (*err_dec)(unsigned int err); + int (*err_dspl)(unsigned int err); + int (*get_img_width)(struct s5p_mfc_dev *dev); + int (*get_img_height)(struct s5p_mfc_dev *dev); + int (*get_dpb_count)(struct s5p_mfc_dev *dev); + int (*get_mv_count)(struct s5p_mfc_dev *dev); + int (*get_inst_no)(struct s5p_mfc_dev *dev); + int (*get_enc_strm_size)(struct s5p_mfc_dev *dev); + int (*get_enc_slice_type)(struct s5p_mfc_dev *dev); + int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev); + int (*get_enc_pic_count)(struct s5p_mfc_dev *dev); + int (*get_sei_avail_status)(struct s5p_mfc_ctx *ctx); + int (*get_mvc_num_views)(struct s5p_mfc_dev *dev); + int (*get_mvc_view_id)(struct s5p_mfc_dev *dev); + unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); +}; + +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); + +#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index baa05af6..17928c82 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1,5 +1,5 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.c + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.c * * Samsung MFC (Multi Function Codec - FIMV) driver * This file contains hw related functions. @@ -12,14 +12,14 @@ * published by the Free Software Foundation. */ -#include "regs-mfc.h" -#include "s5p_mfc_cmd_v5.h" #include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_ctrl.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" -#include "s5p_mfc_opr_v5.h" #include "s5p_mfc_pm.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" #include #include #include @@ -34,7 +34,7 @@ #define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) /* Allocate temporary buffers for decoding */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx) +int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) { void *desc_virt; struct s5p_mfc_dev *dev = ctx->dev; @@ -63,7 +63,7 @@ int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx) } /* Release temporary buffers for decoding */ -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx) +void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) { if (ctx->desc_phys) { vb2_dma_contig_memops.put(ctx->desc_buf); @@ -73,7 +73,7 @@ void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx) } /* Allocate codec buffers */ -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) +int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; unsigned int enc_ref_y_size = 0; @@ -89,7 +89,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height >> 1, @@ -111,14 +111,14 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) } /* Codecs have different memory requirements */ switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_DEC: ctx->bank1_size = ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + S5P_FIMV_DEC_VERT_NB_MV_SIZE, S5P_FIMV_DEC_BUF_ALIGN); ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; break; - case S5P_FIMV_CODEC_MPEG4_DEC: + case S5P_MFC_CODEC_MPEG4_DEC: ctx->bank1_size = ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + S5P_FIMV_DEC_UPNB_MV_SIZE + @@ -128,8 +128,8 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) S5P_FIMV_DEC_BUF_ALIGN); ctx->bank2_size = 0; break; - case S5P_FIMV_CODEC_VC1RCV_DEC: - case S5P_FIMV_CODEC_VC1_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: ctx->bank1_size = ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + S5P_FIMV_DEC_UPNB_MV_SIZE + @@ -139,11 +139,11 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) S5P_FIMV_DEC_BUF_ALIGN); ctx->bank2_size = 0; break; - case S5P_FIMV_CODEC_MPEG2_DEC: + case S5P_MFC_CODEC_MPEG2_DEC: ctx->bank1_size = 0; ctx->bank2_size = 0; break; - case S5P_FIMV_CODEC_H263_DEC: + case S5P_MFC_CODEC_H263_DEC: ctx->bank1_size = ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + S5P_FIMV_DEC_UPNB_MV_SIZE + @@ -152,7 +152,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) S5P_FIMV_DEC_BUF_ALIGN); ctx->bank2_size = 0; break; - case S5P_FIMV_CODEC_H264_ENC: + case S5P_MFC_CODEC_H264_ENC: ctx->bank1_size = (enc_ref_y_size * 2) + S5P_FIMV_ENC_UPMV_SIZE + S5P_FIMV_ENC_COLFLG_SIZE + @@ -162,7 +162,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) (enc_ref_c_size * 4) + S5P_FIMV_ENC_INTRAPRED_SIZE; break; - case S5P_FIMV_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_MPEG4_ENC: ctx->bank1_size = (enc_ref_y_size * 2) + S5P_FIMV_ENC_UPMV_SIZE + S5P_FIMV_ENC_COLFLG_SIZE + @@ -170,7 +170,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) ctx->bank2_size = (enc_ref_y_size * 2) + (enc_ref_c_size * 4); break; - case S5P_FIMV_CODEC_H263_ENC: + case S5P_MFC_CODEC_H263_ENC: ctx->bank1_size = (enc_ref_y_size * 2) + S5P_FIMV_ENC_UPMV_SIZE + S5P_FIMV_ENC_ACDCCOEF_SIZE; @@ -211,7 +211,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) } /* Release buffers allocated for codec */ -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx) +void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) { if (ctx->bank1_buf) { vb2_dma_contig_memops.put(ctx->bank1_buf); @@ -228,7 +228,7 @@ void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx) } /* Allocate memory for instance data buffer */ -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx) +int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) { void *context_virt; struct s5p_mfc_dev *dev = ctx->dev; @@ -289,7 +289,7 @@ int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx) } /* Release instance buffer */ -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx) +void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) { if (ctx->ctx_buf) { vb2_dma_contig_memops.put(ctx->ctx_buf); @@ -303,22 +303,44 @@ void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx) } } -void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, +int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + + return 0; +} + +void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ +} + +static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { writel(data, (ctx->shm + ofs)); wmb(); } -unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, +static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, unsigned int ofs) { rmb(); return readl(ctx->shm + ofs); } +void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ +} + +void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ +} + /* Set registers for decoding temporary buffers */ -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; @@ -334,7 +356,7 @@ static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) } /* Set registers for decoding stream buffer */ -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, +int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, int buf_addr, unsigned int start_num_byte, unsigned int buf_size) { struct s5p_mfc_dev *dev = ctx->dev; @@ -347,7 +369,7 @@ int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, } /* Set decoding frame buffer */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) +int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) { unsigned int frame_size, i; unsigned int frame_size_ch, frame_size_mv; @@ -366,7 +388,7 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) S5P_FIMV_SI_CH0_DPB_CONF_CTRL); s5p_mfc_set_shared_buffer(ctx); switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_DEC: mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_VERT_NB_MV_ADR); buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; @@ -375,7 +397,7 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; break; - case S5P_FIMV_CODEC_MPEG4_DEC: + case S5P_MFC_CODEC_MPEG4_DEC: mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; @@ -392,7 +414,7 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; break; - case S5P_FIMV_CODEC_H263_DEC: + case S5P_MFC_CODEC_H263_DEC: mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; @@ -406,8 +428,8 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; break; - case S5P_FIMV_CODEC_VC1_DEC: - case S5P_FIMV_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; @@ -430,7 +452,7 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; break; - case S5P_FIMV_CODEC_MPEG2_DEC: + case S5P_MFC_CODEC_MPEG2_DEC: break; default: mfc_err("Unknown codec for decoding (%x)\n", @@ -453,7 +475,7 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) ctx->dst_bufs[i].cookie.raw.chroma); mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), S5P_FIMV_DEC_CHROMA_ADR + i * 4); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { mfc_debug(2, "\tBuf2: %x, size: %d\n", buf_addr2, buf_size2); mfc_write(dev, OFFSETB(buf_addr2), @@ -471,7 +493,7 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) } s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), @@ -480,7 +502,7 @@ int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) } /* Set registers for encoding stream buffer */ -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, +int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, unsigned long addr, unsigned int size) { struct s5p_mfc_dev *dev = ctx->dev; @@ -490,7 +512,7 @@ int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, return 0; } -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, +void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, unsigned long y_addr, unsigned long c_addr) { struct s5p_mfc_dev *dev = ctx->dev; @@ -499,7 +521,7 @@ void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); } -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, +void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, unsigned long *y_addr, unsigned long *c_addr) { struct s5p_mfc_dev *dev = ctx->dev; @@ -511,7 +533,7 @@ void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, } /* Set encoding ref & codec buffer */ -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) +int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; size_t buf_addr1, buf_addr2; @@ -527,7 +549,7 @@ int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); @@ -541,7 +563,7 @@ int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) } mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_ENC: + case S5P_MFC_CODEC_H264_ENC: for (i = 0; i < 2; i++) { mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); @@ -581,7 +603,7 @@ int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); break; - case S5P_FIMV_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_MPEG4_ENC: for (i = 0; i < 2; i++) { mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); @@ -612,7 +634,7 @@ int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); break; - case S5P_FIMV_CODEC_H263_ENC: + case S5P_MFC_CODEC_H263_ENC: for (i = 0; i < 2; i++) { mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); @@ -1016,13 +1038,13 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) } /* Initialize decoding */ -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx) +int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; s5p_mfc_set_shared_buffer(ctx); /* Setup loop filter, for decoding this is only valid for MPEG4 */ - if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); else mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); @@ -1052,7 +1074,7 @@ static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) } /* Decode a single frame */ -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, +int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, enum s5p_mfc_decode_arg last_frame) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1081,15 +1103,15 @@ int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, return 0; } -int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) +int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) s5p_mfc_set_enc_params_h264(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC) + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) s5p_mfc_set_enc_params_mpeg4(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC) + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) s5p_mfc_set_enc_params_h263(ctx); else { mfc_err("Unknown codec for encoding (%x)\n", @@ -1103,7 +1125,7 @@ int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) } /* Encode a single frame */ -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) +int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; int cmd; @@ -1149,10 +1171,10 @@ static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0); + s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE); + s5p_mfc_decode_one_frame_v5(ctx, MFC_DEC_RES_CHANGE); } static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) @@ -1172,9 +1194,9 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) /* Get the next source buffer */ temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); temp_vb->flags |= MFC_BUF_FLAG_USED; - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, - temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); index = temp_vb->b->v4l2_buf.index; dev->curr_ctx = ctx->num; @@ -1184,7 +1206,7 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) mfc_debug(2, "Setting ctx->state to FINISHING\n"); ctx->state = MFCINST_FINISHING; } - s5p_mfc_decode_one_frame(ctx, last_frame); + s5p_mfc_decode_one_frame_v5(ctx, last_frame); return 0; } @@ -1210,7 +1232,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) } if (list_empty(&ctx->src_queue)) { /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, dev->bank2); + s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, dev->bank2); src_mb = NULL; } else { src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, @@ -1218,7 +1240,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) src_mb->flags |= MFC_BUF_FLAG_USED; if (src_mb->b->v4l2_planes[0].bytesused == 0) { /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, + s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, dev->bank2); ctx->state = MFCINST_FINISHING; } else { @@ -1226,7 +1248,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) 0); src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); - s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, + s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr, src_c_addr); if (src_mb->flags & MFC_BUF_FLAG_EOS) ctx->state = MFCINST_FINISHING; @@ -1236,13 +1258,13 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) dst_mb->flags |= MFC_BUF_FLAG_USED; dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); mfc_debug(2, "encoding buffer with index=%d state=%d", src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); - s5p_mfc_encode_one_frame(ctx); + s5p_mfc_encode_one_frame_v5(ctx); return 0; } @@ -1258,13 +1280,13 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); s5p_mfc_set_dec_desc_buffer(ctx); mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, + s5p_mfc_set_dec_stream_buffer_v5(ctx, vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_decode(ctx); + s5p_mfc_init_decode_v5(ctx); } static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) @@ -1275,16 +1297,16 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) unsigned long dst_addr; unsigned int dst_size; - s5p_mfc_set_enc_ref_buffer(ctx); + s5p_mfc_set_enc_ref_buffer_v5(ctx); spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_encode(ctx); + s5p_mfc_init_encode_v5(ctx); } static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) @@ -1313,13 +1335,13 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) } temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, + s5p_mfc_set_dec_stream_buffer_v5(ctx, vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, temp_vb->b->v4l2_planes[0].bytesused); spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_set_dec_frame_buffer(ctx); + ret = s5p_mfc_set_dec_frame_buffer_v5(ctx); if (ret) { mfc_err("Failed to alloc frame mem\n"); ctx->state = MFCINST_ERROR; @@ -1328,7 +1350,7 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) } /* Try running an operation on hardware */ -void s5p_mfc_try_run(struct s5p_mfc_dev *dev) +void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_ctx *ctx; int new_ctx; @@ -1373,11 +1395,13 @@ void s5p_mfc_try_run(struct s5p_mfc_dev *dev) break; case MFCINST_INIT: s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); break; case MFCINST_RETURN_INST: s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); break; case MFCINST_GOT_INST: s5p_mfc_run_init_dec(ctx); @@ -1409,11 +1433,13 @@ void s5p_mfc_try_run(struct s5p_mfc_dev *dev) break; case MFCINST_INIT: s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); break; case MFCINST_RETURN_INST: s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); break; case MFCINST_GOT_INST: s5p_mfc_run_init_enc(ctx); @@ -1440,7 +1466,7 @@ void s5p_mfc_try_run(struct s5p_mfc_dev *dev) } -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) +void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq) { struct s5p_mfc_buf *b; int i; @@ -1454,3 +1480,250 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) } } +void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) +{ + mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); +} + +int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_Y_ADR) << MFC_OFFSET_SHIFT; +} + +int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_Y_ADR) << MFC_OFFSET_SHIFT; +} + +int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_STATUS); +} + +int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_STATUS); +} + +int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_DECODE_FRAME_TYPE) & + S5P_FIMV_DECODE_FRAME_MASK; +} + +int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ + return -1; +} + +int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_CONSUMED_BYTES); +} + +int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) +{ + int reason; + reason = mfc_read(dev, S5P_FIMV_RISC2HOST_CMD) & + S5P_FIMV_RISC2HOST_CMD_MASK; + switch (reason) { + case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: + reason = S5P_MFC_R2H_CMD_SEQ_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + reason = S5P_MFC_R2H_CMD_FRAME_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: + reason = S5P_MFC_R2H_CMD_SLICE_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SYS_INIT_RET: + reason = S5P_MFC_R2H_CMD_SYS_INIT_RET; + break; + case S5P_FIMV_R2H_CMD_FW_STATUS_RET: + reason = S5P_MFC_R2H_CMD_FW_STATUS_RET; + break; + case S5P_FIMV_R2H_CMD_SLEEP_RET: + reason = S5P_MFC_R2H_CMD_SLEEP_RET; + break; + case S5P_FIMV_R2H_CMD_WAKEUP_RET: + reason = S5P_MFC_R2H_CMD_WAKEUP_RET; + break; + case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: + reason = S5P_MFC_R2H_CMD_INIT_BUFFERS_RET; + break; + case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: + reason = S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET; + break; + case S5P_FIMV_R2H_CMD_ERR_RET: + reason = S5P_MFC_R2H_CMD_ERR_RET; + break; + default: + reason = S5P_MFC_R2H_CMD_EMPTY; + }; + return reason; +} + +int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG2); +} + +int s5p_mfc_err_dec_v5(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT; +} + +int s5p_mfc_err_dspl_v5(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT; +} + +int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_HRESOL); +} + +int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_VRESOL); +} + +int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_BUF_NUMBER); +} + +int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + return -1; +} + +int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG1); +} + +int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_STRM_SIZE); +} + +int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_SLICE_TYPE); +} + +int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT); +} + +int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL); +} + +int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP); +} + +unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT); +} + +unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_H); +} + +unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_V); +} + +/* Initialize opr function pointers for MFC v5 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v5, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v5, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v5, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v5, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v5, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v5, + .alloc_dev_context_buffer = s5p_mfc_alloc_dev_context_buffer_v5, + .release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5, + .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v5, + .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v5, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5, + .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v5, + .init_decode = s5p_mfc_init_decode_v5, + .init_encode = s5p_mfc_init_encode_v5, + .encode_one_frame = s5p_mfc_encode_one_frame_v5, + .try_run = s5p_mfc_try_run_v5, + .cleanup_queue = s5p_mfc_cleanup_queue_v5, + .clear_int_flags = s5p_mfc_clear_int_flags_v5, + .write_info = s5p_mfc_write_info_v5, + .read_info = s5p_mfc_read_info_v5, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5, + .get_dspl_status = s5p_mfc_get_dspl_status_v5, + .get_dec_status = s5p_mfc_get_dec_status_v5, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v5, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v5, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v5, + .get_int_reason = s5p_mfc_get_int_reason_v5, + .get_int_err = s5p_mfc_get_int_err_v5, + .err_dec = s5p_mfc_err_dec_v5, + .err_dspl = s5p_mfc_err_dspl_v5, + .get_img_width = s5p_mfc_get_img_width_v5, + .get_img_height = s5p_mfc_get_img_height_v5, + .get_dpb_count = s5p_mfc_get_dpb_count_v5, + .get_mv_count = s5p_mfc_get_mv_count_v5, + .get_inst_no = s5p_mfc_get_inst_no_v5, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5, + .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v5, + .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v5, + .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v5, + .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v5, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v5, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v5, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v5, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void) +{ + return &s5p_mfc_ops_v5; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h index 97c1ecaf..ffee39a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h @@ -1,5 +1,5 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.h + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.h * * Header file for Samsung MFC (Multi Function Codec - FIMV) driver * Contains declarations of hw related functions. @@ -12,10 +12,11 @@ * published by the Free Software Foundation. */ -#ifndef S5P_MFC_OPR_H_ -#define S5P_MFC_OPR_H_ +#ifndef S5P_MFC_OPR_V5_H_ +#define S5P_MFC_OPR_V5_H_ #include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" enum MFC_SHM_OFS { EXTENEDED_DECODE_STATUS = 0x00, /* D */ @@ -80,84 +81,5 @@ enum MFC_SHM_OFS { FRAME_PACK_SEI_INFO = 0x17c, /* E */ }; -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx); -int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx); - -/* Decoding functions */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx); -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, - unsigned int buf_size); - -/* Encoding functions */ -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr); -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size); -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr); -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx); - -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame); -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx); - -/* Memory allocation */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx); - -void s5p_mfc_try_run(struct s5p_mfc_dev *dev); -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); - -/* Shared memory ops */ -void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, - unsigned int ofs); - -unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, - unsigned int ofs); - -#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_STATUS) -#define s5p_mfc_get_dec_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_STATUS) -#define s5p_mfc_get_frame_type() (readl(dev->regs_base + \ - S5P_FIMV_DECODE_FRAME_TYPE) \ - & S5P_FIMV_DECODE_FRAME_MASK) -#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ - S5P_FIMV_SI_CONSUMED_BYTES) -#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_CMD) & \ - S5P_FIMV_RISC2HOST_CMD_MASK) -#define s5p_mfc_get_int_err() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG2) -#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \ - S5P_FIMV_ERR_DEC_SHIFT) -#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \ - S5P_FIMV_ERR_DSPL_SHIFT) -#define s5p_mfc_get_img_width() readl(dev->regs_base + \ - S5P_FIMV_SI_HRESOL) -#define s5p_mfc_get_img_height() readl(dev->regs_base + \ - S5P_FIMV_SI_VRESOL) -#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \ - S5P_FIMV_SI_BUF_NUMBER) -#define s5p_mfc_get_inst_no() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG1) -#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_STRM_SIZE) -#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_SLICE_TYPE) - +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void); #endif /* S5P_MFC_OPR_H_ */ -- cgit v0.10.2 From 8f532a7fec5ee872a65d2096f846f76afd9ede6f Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Wed, 3 Oct 2012 22:19:09 -0300 Subject: [media] s5p-mfc: Add MFC variant data to device context MFC variant data replaces various macros used in the driver which will change in a different version of MFC hardware. Also does a cleanup of MFC context structure and common files. Signed-off-by: Jeongtae Park Signed-off-by: Janghyuck Kim Signed-off-by: Jaeryul Oh Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Arun Kumar K Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index a19bece..f33c54d 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -12,6 +12,9 @@ #ifndef _REGS_FIMV_H #define _REGS_FIMV_H +#include +#include + #define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) #define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) @@ -414,5 +417,22 @@ #define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078 #define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C #define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0 +#define S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT 2 + +/* Offset used by the hardware to store addresses */ +#define MFC_OFFSET_SHIFT 11 + +#define FIRMWARE_ALIGN (128 * SZ_1K) /* 128KB */ +#define MFC_H264_CTX_BUF_SIZE (600 * SZ_1K) /* 600KB per H264 instance */ +#define MFC_CTX_BUF_SIZE (10 * SZ_1K) /* 10KB per instance */ +#define DESC_BUF_SIZE (128 * SZ_1K) /* 128KB for DESC buffer */ +#define SHARED_BUF_SIZE (8 * SZ_1K) /* 8KB for shared buffer */ + +#define DEF_CPB_SIZE (256 * SZ_1K) /* 256KB */ +#define MAX_CPB_SIZE (4 * SZ_1M) /* 4MB */ +#define MAX_FW_SIZE (384 * SZ_1K) + +#define MFC_VERSION 0x51 +#define MFC_NUM_PORTS 2 #endif /* _REGS_FIMV_H */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d711b0f..7feae81 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -477,7 +477,6 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) { struct s5p_mfc_dev *dev; - unsigned int guard_width, guard_height; if (ctx == NULL) return; @@ -491,40 +490,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, dev); - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN); - ctx->buf_height = ALIGN(ctx->img_height, - S5P_FIMV_NV12MT_VALIGN); - mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, " - "buffer dimensions: %dx%d\n", ctx->img_width, - ctx->img_height, ctx->buf_width, - ctx->buf_height); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { - ctx->luma_size = ALIGN(ctx->buf_width * - ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN); - ctx->chroma_size = ALIGN(ctx->buf_width * - ALIGN((ctx->img_height >> 1), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - ctx->mv_size = ALIGN(ctx->buf_width * - ALIGN((ctx->buf_height >> 2), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 24, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN(ctx->img_height + 16, - S5P_FIMV_NV12MT_VALIGN); - ctx->luma_size = ALIGN(guard_width * - guard_height, S5P_FIMV_DEC_BUF_ALIGN); - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = ALIGN(guard_width * - guard_height, S5P_FIMV_DEC_BUF_ALIGN); - ctx->mv_size = 0; - } + s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); + ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, dev); if (ctx->img_width == 0 || ctx->img_height == 0) @@ -1066,6 +1033,9 @@ static int s5p_mfc_probe(struct platform_device *pdev) return -ENODEV; } + dev->variant = (struct s5p_mfc_variant *) + platform_get_device_id(pdev)->driver_data; + ret = s5p_mfc_init_pm(dev); if (ret < 0) { dev_err(&pdev->dev, "failed to get mfc clock source\n"); @@ -1309,9 +1279,43 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = { NULL) }; +struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { + .h264_ctx = MFC_H264_CTX_BUF_SIZE, + .non_h264_ctx = MFC_CTX_BUF_SIZE, + .dsc = DESC_BUF_SIZE, + .shm = SHARED_BUF_SIZE, +}; + +struct s5p_mfc_buf_size buf_size_v5 = { + .fw = MAX_FW_SIZE, + .cpb = MAX_CPB_SIZE, + .priv = &mfc_buf_size_v5, +}; + +struct s5p_mfc_buf_align mfc_buf_align_v5 = { + .base = MFC_BASE_ALIGN_ORDER, +}; + +static struct s5p_mfc_variant mfc_drvdata_v5 = { + .version = MFC_VERSION, + .port_num = MFC_NUM_PORTS, + .buf_size = &buf_size_v5, + .buf_align = &mfc_buf_align_v5, +}; + +static struct platform_device_id mfc_driver_ids[] = { + { + .name = "s5p-mfc", + .driver_data = (unsigned long)&mfc_drvdata_v5, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, mfc_driver_ids); + static struct platform_driver s5p_mfc_driver = { - .probe = s5p_mfc_probe, - .remove = __devexit_p(s5p_mfc_remove), + .probe = s5p_mfc_probe, + .remove = __devexit_p(s5p_mfc_remove), + .id_table = mfc_driver_ids, .driver = { .name = S5P_MFC_NAME, .owner = THIS_MODULE, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index e4eb956..13877808 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -113,8 +113,8 @@ int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) h2r_args.arg[0] = S5P_FIMV_CODEC_NONE; }; h2r_args.arg[1] = 0; /* no crc & no pixelcache */ - h2r_args.arg[2] = ctx->ctx_ofs; - h2r_args.arg[3] = ctx->ctx_size; + h2r_args.arg[2] = ctx->ctx.ofs; + h2r_args.arg[3] = ctx->ctx.size; ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, &h2r_args); if (ret) { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 82931d4..e495b13 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -30,17 +30,6 @@ * while mmaping */ #define DST_QUEUE_OFF_BASE (TASK_SIZE / 2) -/* Offset used by the hardware to store addresses */ -#define MFC_OFFSET_SHIFT 11 - -#define FIRMWARE_ALIGN 0x20000 /* 128KB */ -#define MFC_H264_CTX_BUF_SIZE 0x96000 /* 600KB per H264 instance */ -#define MFC_CTX_BUF_SIZE 0x2800 /* 10KB per instance */ -#define DESC_BUF_SIZE 0x20000 /* 128KB for DESC buffer */ -#define SHARED_BUF_SIZE 0x2000 /* 8KB for shared buffer */ - -#define DEF_CPB_SIZE 0x40000 /* 512KB */ - #define MFC_BANK1_ALLOC_CTX 0 #define MFC_BANK2_ALLOC_CTX 1 @@ -210,6 +199,48 @@ struct s5p_mfc_pm { struct device *device; }; +struct s5p_mfc_buf_size_v5 { + unsigned int h264_ctx; + unsigned int non_h264_ctx; + unsigned int dsc; + unsigned int shm; +}; + +struct s5p_mfc_buf_size { + unsigned int fw; + unsigned int cpb; + void *priv; +}; + +struct s5p_mfc_buf_align { + unsigned int base; +}; + +struct s5p_mfc_variant { + unsigned int version; + unsigned int port_num; + struct s5p_mfc_buf_size *buf_size; + struct s5p_mfc_buf_align *buf_align; +}; + +/** + * struct s5p_mfc_priv_buf - represents internal used buffer + * @alloc: allocation-specific context for each buffer + * (videobuf2 allocator) + * @ofs: offset of each buffer, will be used for MFC + * @virt: kernel virtual address, only valid when the + * buffer accessed by driver + * @dma: DMA address, only valid when kernel DMA API used + * @size: size of the buffer + */ +struct s5p_mfc_priv_buf { + void *alloc; + unsigned long ofs; + void *virt; + dma_addr_t dma; + size_t size; +}; + /** * struct s5p_mfc_dev - The struct containing driver internal parameters. * @@ -224,6 +255,7 @@ struct s5p_mfc_pm { * @dec_ctrl_handler: control framework handler for decoding * @enc_ctrl_handler: control framework handler for encoding * @pm: power management control + * @variant: MFC hardware variant information * @num_inst: couter of active MFC instances * @irqlock: lock for operations on videobuf2 queues * @condlock: lock for changing/checking if a context is ready to be @@ -262,6 +294,7 @@ struct s5p_mfc_dev { struct v4l2_ctrl_handler dec_ctrl_handler; struct v4l2_ctrl_handler enc_ctrl_handler; struct s5p_mfc_pm pm; + struct s5p_mfc_variant *variant; int num_inst; spinlock_t irqlock; /* lock when operating on videobuf2 queues */ spinlock_t condlock; /* lock when changing/checking if a context is @@ -302,7 +335,6 @@ struct s5p_mfc_h264_enc_params { u8 max_ref_pic; u8 num_ref_pic_4p; int _8x8_transform; - int rc_mb; int rc_mb_dark; int rc_mb_smooth; int rc_mb_static; @@ -321,6 +353,7 @@ struct s5p_mfc_h264_enc_params { enum v4l2_mpeg_video_h264_level level_v4l2; int level; u16 cpb_size; + int interlace; }; /** @@ -359,6 +392,7 @@ struct s5p_mfc_enc_params { u8 pad_cb; u8 pad_cr; int rc_frame; + int rc_mb; u32 rc_bitrate; u16 rc_reaction_coeff; u16 vbv_size; @@ -370,7 +404,6 @@ struct s5p_mfc_enc_params { u8 num_b_frame; u32 rc_framerate_num; u32 rc_framerate_denom; - int interlace; union { struct s5p_mfc_h264_enc_params h264; @@ -455,14 +488,9 @@ struct s5p_mfc_codec_ops { * @dpb_count: count of the DPB buffers required by MFC hw * @total_dpb_count: count of DPB buffers with additional buffers * requested by the application - * @ctx_buf: handle to the memory associated with this context - * @ctx_phys: address of the memory associated with this context - * @ctx_size: size of the memory associated with this context - * @desc_buf: description buffer for decoding handle - * @desc_phys: description buffer for decoding address - * @shm_alloc: handle for the shared memory buffer - * @shm: virtual address for the shared memory buffer - * @shm_ofs: address offset for shared memory + * @ctx: context buffer information + * @dsc: descriptor buffer information + * @shm: shared memory buffer information * @enc_params: encoding parameters for MFC * @enc_dst_buf_size: size of the buffers for encoder output * @frame_type: used to force the type of the next encoded frame @@ -547,18 +575,9 @@ struct s5p_mfc_ctx { int total_dpb_count; /* Buffers */ - void *ctx_buf; - size_t ctx_phys; - size_t ctx_ofs; - size_t ctx_size; - - void *desc_buf; - size_t desc_phys; - - - void *shm_alloc; - void *shm; - size_t shm_ofs; + struct s5p_mfc_priv_buf ctx; + struct s5p_mfc_priv_buf dsc; + struct s5p_mfc_priv_buf shm; struct s5p_mfc_enc_params enc_params; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 7666e94..311ec90 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -43,7 +43,12 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; } - dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN); + dev->fw_size = dev->variant->buf_size->fw; + if (fw_blob->size > dev->fw_size) { + mfc_err("MFC firmware is too big to be loaded\n"); + release_firmware(fw_blob); + return -ENOMEM; + } if (s5p_mfc_bitproc_buf) { mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); release_firmware(fw_blob); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 3b0e594..b0879f9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -977,45 +977,13 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n", pix_fmt_mp->width, pix_fmt_mp->height, ctx->img_width, ctx->img_height); - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN); - ctx->luma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height, - S5P_FIMV_NV12M_LVALIGN); - ctx->chroma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height - >> 1), S5P_FIMV_NV12M_CVALIGN); - - ctx->luma_size = ALIGN(ctx->luma_size, - S5P_FIMV_NV12M_SALIGN); - ctx->chroma_size = ALIGN(ctx->chroma_size, - S5P_FIMV_NV12M_SALIGN); - - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - - } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN); - ctx->luma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height, - S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height - >> 1), S5P_FIMV_NV12MT_VALIGN); - ctx->luma_size = ALIGN(ctx->luma_size, - S5P_FIMV_NV12MT_SALIGN); - ctx->chroma_size = ALIGN(ctx->chroma_size, - S5P_FIMV_NV12MT_SALIGN); - - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - } + + s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); + pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; + pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; + ctx->src_bufs_cnt = 0; ctx->output_state = QUEUE_FREE; } else { @@ -1357,7 +1325,7 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) p->codec.h264._8x8_transform = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: - p->codec.h264.rc_mb = ctrl->val; + p->rc_mb = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: p->codec.h264.rc_frame_qp = ctrl->val; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 17928c82..bf7d010 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -36,28 +36,29 @@ /* Allocate temporary buffers for decoding */ int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) { - void *desc_virt; struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; - ctx->desc_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE); - if (IS_ERR_VALUE((int)ctx->desc_buf)) { - ctx->desc_buf = NULL; + ctx->dsc.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], + buf_size->dsc); + if (IS_ERR_VALUE((int)ctx->dsc.alloc)) { + ctx->dsc.alloc = NULL; mfc_err("Allocating DESC buffer failed\n"); return -ENOMEM; } - ctx->desc_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf); - BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf); - if (desc_virt == NULL) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; + ctx->dsc.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->dsc.alloc); + BUG_ON(ctx->dsc.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + ctx->dsc.virt = vb2_dma_contig_memops.vaddr(ctx->dsc.alloc); + if (ctx->dsc.virt == NULL) { + vb2_dma_contig_memops.put(ctx->dsc.alloc); + ctx->dsc.dma = 0; + ctx->dsc.alloc = NULL; mfc_err("Remapping DESC buffer failed\n"); return -ENOMEM; } - memset(desc_virt, 0, DESC_BUF_SIZE); + memset(ctx->dsc.virt, 0, buf_size->dsc); wmb(); return 0; } @@ -65,10 +66,10 @@ int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) /* Release temporary buffers for decoding */ void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) { - if (ctx->desc_phys) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; + if (ctx->dsc.dma) { + vb2_dma_contig_memops.put(ctx->dsc.alloc); + ctx->dsc.alloc = NULL; + ctx->dsc.dma = 0; } } @@ -230,60 +231,60 @@ void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) /* Allocate memory for instance data buffer */ int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) { - void *context_virt; struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) - ctx->ctx_size = MFC_H264_CTX_BUF_SIZE; + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + ctx->ctx.size = buf_size->h264_ctx; else - ctx->ctx_size = MFC_CTX_BUF_SIZE; - ctx->ctx_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size); - if (IS_ERR(ctx->ctx_buf)) { + ctx->ctx.size = buf_size->non_h264_ctx; + ctx->ctx.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size); + if (IS_ERR(ctx->ctx.alloc)) { mfc_err("Allocating context buffer failed\n"); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; + ctx->ctx.alloc = NULL; return -ENOMEM; } - ctx->ctx_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf); - BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->ctx_ofs = OFFSETA(ctx->ctx_phys); - context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf); - if (context_virt == NULL) { + ctx->ctx.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc); + BUG_ON(ctx->ctx.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + ctx->ctx.ofs = OFFSETA(ctx->ctx.dma); + ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc); + if (!ctx->ctx.virt) { mfc_err("Remapping instance buffer failed\n"); - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.ofs = 0; + ctx->ctx.dma = 0; return -ENOMEM; } /* Zero content of the allocated memory */ - memset(context_virt, 0, ctx->ctx_size); + memset(ctx->ctx.virt, 0, ctx->ctx.size); wmb(); /* Initialize shared memory */ - ctx->shm_alloc = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], SHARED_BUF_SIZE); - if (IS_ERR(ctx->shm_alloc)) { + ctx->shm.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->shm); + if (IS_ERR(ctx->shm.alloc)) { mfc_err("failed to allocate shared memory\n"); - return PTR_ERR(ctx->shm_alloc); + return PTR_ERR(ctx->shm.alloc); } /* shared memory offset only keeps the offset from base (port a) */ - ctx->shm_ofs = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->shm_alloc) + ctx->shm.ofs = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->shm.alloc) - dev->bank1; - BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc); - if (!ctx->shm) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_ofs = 0; - ctx->shm_alloc = NULL; + ctx->shm.virt = vb2_dma_contig_memops.vaddr(ctx->shm.alloc); + if (!ctx->shm.virt) { + vb2_dma_contig_memops.put(ctx->shm.alloc); + ctx->shm.alloc = NULL; + ctx->shm.ofs = 0; mfc_err("failed to virt addr of shared memory\n"); return -ENOMEM; } - memset((void *)ctx->shm, 0, SHARED_BUF_SIZE); + memset((void *)ctx->shm.virt, 0, buf_size->shm); wmb(); return 0; } @@ -291,15 +292,18 @@ int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) /* Release instance buffer */ void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) { - if (ctx->ctx_buf) { - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; + if (ctx->ctx.alloc) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.ofs = 0; + ctx->ctx.virt = NULL; + ctx->ctx.dma = 0; } - if (ctx->shm_alloc) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_alloc = NULL; - ctx->shm = NULL; + if (ctx->shm.alloc) { + vb2_dma_contig_memops.put(ctx->shm.alloc); + ctx->shm.alloc = NULL; + ctx->shm.ofs = 0; + ctx->shm.virt = NULL; } } @@ -318,7 +322,7 @@ void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { - writel(data, (ctx->shm + ofs)); + writel(data, (ctx->shm.virt + ofs)); wmb(); } @@ -326,33 +330,94 @@ static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, unsigned int ofs) { rmb(); - return readl(ctx->shm + ofs); + return readl(ctx->shm.virt + ofs); } void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) { - /* NOP */ + unsigned int guard_width, guard_height; + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + mfc_debug(2, + "SEQ Done: Movie dimensions %dx%d, buffer dimensions: %dx%d\n", + ctx->img_width, ctx->img_height, ctx->buf_width, + ctx->buf_height); + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { + ctx->luma_size = ALIGN(ctx->buf_width * ctx->buf_height, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->chroma_size = ALIGN(ctx->buf_width * + ALIGN((ctx->img_height >> 1), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + ctx->mv_size = ALIGN(ctx->buf_width * + ALIGN((ctx->buf_height >> 2), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + } else { + guard_width = + ALIGN(ctx->img_width + 24, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN(ctx->img_height + 16, S5P_FIMV_NV12MT_VALIGN); + ctx->luma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + guard_width = + ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + ctx->mv_size = 0; + } } void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) { - /* NOP */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12M_LVALIGN); + ctx->chroma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12M_CVALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12M_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12M_SALIGN); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = + ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12MT_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12MT_SALIGN); + } } /* Set registers for decoding temporary buffers */ static void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; - mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR); - mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE); + mfc_write(dev, OFFSETA(ctx->dsc.dma), S5P_FIMV_SI_CH0_DESC_ADR); + mfc_write(dev, buf_size->dsc, S5P_FIMV_SI_CH0_DESC_SIZE); } /* Set registers for shared buffer */ static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); + mfc_write(dev, ctx->shm.ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); } /* Set registers for decoding stream buffer */ @@ -776,9 +841,9 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg |= p_264->profile; mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); /* interlace */ - mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT); + mfc_write(dev, p_264->interlace, S5P_FIMV_ENC_PIC_STRUCT); /* height */ - if (p->interlace) + if (p_264->interlace) mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); /* loopfilter ctrl */ mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); @@ -820,7 +885,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); /* macroblock level rate control */ reg &= ~(0x1 << 8); - reg |= (p_264->rc_mb << 8); + reg |= (p->rc_mb << 8); /* frame QP */ reg &= ~(0x3F); reg |= p_264->rc_frame_qp; @@ -841,7 +906,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg |= p_264->rc_min_qp; mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); /* macroblock adaptive scaling features */ - if (p_264->rc_mb) { + if (p->rc_mb) { reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); /* dark region */ reg &= ~(0x1 << 3); @@ -857,8 +922,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg |= p_264->rc_mb_activity; mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); } - if (!p->rc_frame && - !p_264->rc_mb) { + if (!p->rc_frame && !p->rc_mb) { shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); shm &= ~(0xFFF); shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); @@ -1515,8 +1579,9 @@ int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) { - /* NOP */ - return -1; + return (s5p_mfc_read_info_v5(ctx, DISP_PIC_FRAME_TYPE) >> + S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) & + S5P_FIMV_DECODE_FRAME_MASK; } int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) -- cgit v0.10.2 From 5b781e171ec8f03e640d3b1de6a7ad6a5349e4bf Mon Sep 17 00:00:00 2001 From: Jeongtae Park Date: Wed, 3 Oct 2012 22:19:10 -0300 Subject: [media] s5p-mfc: MFCv6 register definitions Adds register definitions for MFC v6.x firmware Signed-off-by: Jeongtae Park Signed-off-by: Janghyuck Kim Signed-off-by: Jaeryul Oh Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Arun Kumar K Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h new file mode 100644 index 0000000..363a97c --- /dev/null +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -0,0 +1,408 @@ +/* + * Register definition file for Samsung MFC V6.x Interface (FIMV) driver + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _REGS_FIMV_V6_H +#define _REGS_FIMV_V6_H + +#include +#include + +#define S5P_FIMV_REG_SIZE_V6 (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) +#define S5P_FIMV_REG_COUNT_V6 ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) + +/* Number of bits that the buffer address should be shifted for particular + * MFC buffers. */ +#define S5P_FIMV_MEM_OFFSET_V6 0 + +#define S5P_FIMV_START_ADDR_V6 0x0000 +#define S5P_FIMV_END_ADDR_V6 0xfd80 + +#define S5P_FIMV_REG_CLEAR_BEGIN_V6 0xf000 +#define S5P_FIMV_REG_CLEAR_COUNT_V6 1024 + +/* Codec Common Registers */ +#define S5P_FIMV_RISC_ON_V6 0x0000 +#define S5P_FIMV_RISC2HOST_INT_V6 0x003C +#define S5P_FIMV_HOST2RISC_INT_V6 0x0044 +#define S5P_FIMV_RISC_BASE_ADDRESS_V6 0x0054 + +#define S5P_FIMV_MFC_RESET_V6 0x1070 + +#define S5P_FIMV_HOST2RISC_CMD_V6 0x1100 +#define S5P_FIMV_H2R_CMD_EMPTY_V6 0 +#define S5P_FIMV_H2R_CMD_SYS_INIT_V6 1 +#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6 2 +#define S5P_FIMV_CH_SEQ_HEADER_V6 3 +#define S5P_FIMV_CH_INIT_BUFS_V6 4 +#define S5P_FIMV_CH_FRAME_START_V6 5 +#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6 6 +#define S5P_FIMV_H2R_CMD_SLEEP_V6 7 +#define S5P_FIMV_H2R_CMD_WAKEUP_V6 8 +#define S5P_FIMV_CH_LAST_FRAME_V6 9 +#define S5P_FIMV_H2R_CMD_FLUSH_V6 10 +/* RMVME: REALLOC used? */ +#define S5P_FIMV_CH_FRAME_START_REALLOC_V6 5 + +#define S5P_FIMV_RISC2HOST_CMD_V6 0x1104 +#define S5P_FIMV_R2H_CMD_EMPTY_V6 0 +#define S5P_FIMV_R2H_CMD_SYS_INIT_RET_V6 1 +#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET_V6 2 +#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET_V6 3 +#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET_V6 4 + +#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET_V6 6 +#define S5P_FIMV_R2H_CMD_SLEEP_RET_V6 7 +#define S5P_FIMV_R2H_CMD_WAKEUP_RET_V6 8 +#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET_V6 9 +#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET_V6 10 +#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET_V6 11 +#define S5P_FIMV_R2H_CMD_FW_STATUS_RET_V6 12 +#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET_V6 13 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET_V6 14 +#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET_V6 15 +#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET_V6 16 +#define S5P_FIMV_R2H_CMD_ERR_RET_V6 32 + +#define S5P_FIMV_FW_VERSION_V6 0xf000 + +#define S5P_FIMV_INSTANCE_ID_V6 0xf008 +#define S5P_FIMV_CODEC_TYPE_V6 0xf00c +#define S5P_FIMV_CONTEXT_MEM_ADDR_V6 0xf014 +#define S5P_FIMV_CONTEXT_MEM_SIZE_V6 0xf018 +#define S5P_FIMV_PIXEL_FORMAT_V6 0xf020 + +#define S5P_FIMV_METADATA_ENABLE_V6 0xf024 +#define S5P_FIMV_DBG_BUFFER_ADDR_V6 0xf030 +#define S5P_FIMV_DBG_BUFFER_SIZE_V6 0xf034 +#define S5P_FIMV_RET_INSTANCE_ID_V6 0xf070 + +#define S5P_FIMV_ERROR_CODE_V6 0xf074 +#define S5P_FIMV_ERR_WARNINGS_START_V6 160 +#define S5P_FIMV_ERR_DEC_MASK_V6 0xffff +#define S5P_FIMV_ERR_DEC_SHIFT_V6 0 +#define S5P_FIMV_ERR_DSPL_MASK_V6 0xffff0000 +#define S5P_FIMV_ERR_DSPL_SHIFT_V6 16 + +#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE_V6 0xf078 +#define S5P_FIMV_METADATA_STATUS_V6 0xf07C +#define S5P_FIMV_METADATA_ADDR_MB_INFO_V6 0xf080 +#define S5P_FIMV_METADATA_SIZE_MB_INFO_V6 0xf084 + +/* Decoder Registers */ +#define S5P_FIMV_D_CRC_CTRL_V6 0xf0b0 +#define S5P_FIMV_D_DEC_OPTIONS_V6 0xf0b4 +#define S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6 4 +#define S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6 3 +#define S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6 1 +#define S5P_FIMV_D_OPT_LF_CTRL_MASK_V6 0x3 +#define S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6 0 + +#define S5P_FIMV_D_DISPLAY_DELAY_V6 0xf0b8 + +#define S5P_FIMV_D_SET_FRAME_WIDTH_V6 0xf0bc +#define S5P_FIMV_D_SET_FRAME_HEIGHT_V6 0xf0c0 + +#define S5P_FIMV_D_SEI_ENABLE_V6 0xf0c4 + +/* Buffer setting registers */ +#define S5P_FIMV_D_MIN_NUM_DPB_V6 0xf0f0 +#define S5P_FIMV_D_MIN_LUMA_DPB_SIZE_V6 0xf0f4 +#define S5P_FIMV_D_MIN_CHROMA_DPB_SIZE_V6 0xf0f8 +#define S5P_FIMV_D_MVC_NUM_VIEWS_V6 0xf0fc +#define S5P_FIMV_D_MIN_NUM_MV_V6 0xf100 +#define S5P_FIMV_D_NUM_DPB_V6 0xf130 +#define S5P_FIMV_D_LUMA_DPB_SIZE_V6 0xf134 +#define S5P_FIMV_D_CHROMA_DPB_SIZE_V6 0xf138 +#define S5P_FIMV_D_MV_BUFFER_SIZE_V6 0xf13c + +#define S5P_FIMV_D_LUMA_DPB_V6 0xf140 +#define S5P_FIMV_D_CHROMA_DPB_V6 0xf240 +#define S5P_FIMV_D_MV_BUFFER_V6 0xf340 + +#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6 0xf440 +#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6 0xf444 +#define S5P_FIMV_D_METADATA_BUFFER_ADDR_V6 0xf448 +#define S5P_FIMV_D_METADATA_BUFFER_SIZE_V6 0xf44c +#define S5P_FIMV_D_NUM_MV_V6 0xf478 +#define S5P_FIMV_D_CPB_BUFFER_ADDR_V6 0xf4b0 +#define S5P_FIMV_D_CPB_BUFFER_SIZE_V6 0xf4b4 + +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER_V6 0xf4b8 +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6 0xf4bc +#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V6 0xf4c0 +#define S5P_FIMV_D_SLICE_IF_ENABLE_V6 0xf4c4 +#define S5P_FIMV_D_PICTURE_TAG_V6 0xf4c8 +#define S5P_FIMV_D_STREAM_DATA_SIZE_V6 0xf4d0 + +/* Display information register */ +#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6 0xf500 +#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6 0xf504 + +/* Display status */ +#define S5P_FIMV_D_DISPLAY_STATUS_V6 0xf508 + +#define S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6 0xf50c +#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6 0xf510 + +#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6 0xf514 + +#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 0xf518 +#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 0xf51c +#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V6 0xf520 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_TOP_V6 0xf524 +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_TOP_V6 0xf528 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_BOT_V6 0xf52c +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_BOT_V6 0xf530 +#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6 0xf534 +#define S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6 0xf538 + +/* Decoded picture information register */ +#define S5P_FIMV_D_DECODED_FRAME_WIDTH_V6 0xf53c +#define S5P_FIMV_D_DECODED_FRAME_HEIGHT_V6 0xf540 +#define S5P_FIMV_D_DECODED_STATUS_V6 0xf544 +#define S5P_FIMV_DEC_CRC_GEN_MASK_V6 0x1 +#define S5P_FIMV_DEC_CRC_GEN_SHIFT_V6 6 + +#define S5P_FIMV_D_DECODED_LUMA_ADDR_V6 0xf548 +#define S5P_FIMV_D_DECODED_CHROMA_ADDR_V6 0xf54c + +#define S5P_FIMV_D_DECODED_FRAME_TYPE_V6 0xf550 +#define S5P_FIMV_DECODE_FRAME_MASK_V6 7 + +#define S5P_FIMV_D_DECODED_CROP_INFO1_V6 0xf554 +#define S5P_FIMV_D_DECODED_CROP_INFO2_V6 0xf558 +#define S5P_FIMV_D_DECODED_PICTURE_PROFILE_V6 0xf55c +#define S5P_FIMV_D_DECODED_NAL_SIZE_V6 0xf560 +#define S5P_FIMV_D_DECODED_LUMA_CRC_TOP_V6 0xf564 +#define S5P_FIMV_D_DECODED_CHROMA_CRC_TOP_V6 0xf568 +#define S5P_FIMV_D_DECODED_LUMA_CRC_BOT_V6 0xf56c +#define S5P_FIMV_D_DECODED_CHROMA_CRC_BOT_V6 0xf570 + +/* Returned value register for specific setting */ +#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 0xf574 +#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 0xf578 +#define S5P_FIMV_D_RET_PICTURE_TIME_TOP_V6 0xf57c +#define S5P_FIMV_D_RET_PICTURE_TIME_BOT_V6 0xf580 +#define S5P_FIMV_D_CHROMA_FORMAT_V6 0xf588 +#define S5P_FIMV_D_MPEG4_INFO_V6 0xf58c +#define S5P_FIMV_D_H264_INFO_V6 0xf590 + +#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB_V6 0xf594 +#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB_V6 0xf598 +#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM_V6 0xf59c +#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM_V6 0xf5a0 +#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL_V6 0xf5a4 +#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL_V6 0xf5a8 +#define S5P_FIMV_D_METADATA_ADDR_VUI_V6 0xf5ac +#define S5P_FIMV_D_METADATA_SIZE_VUI_V6 0xf5b0 + +#define S5P_FIMV_D_MVC_VIEW_ID_V6 0xf5b4 + +/* SEI related information */ +#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6 0xf5f0 +#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID_V6 0xf5f4 +#define S5P_FIMV_D_FRAME_PACK_SEI_INFO_V6 0xf5f8 +#define S5P_FIMV_D_FRAME_PACK_GRID_POS_V6 0xf5fc + +/* Encoder Registers */ +#define S5P_FIMV_E_FRAME_WIDTH_V6 0xf770 +#define S5P_FIMV_E_FRAME_HEIGHT_V6 0xf774 +#define S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6 0xf778 +#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6 0xf77c +#define S5P_FIMV_E_FRAME_CROP_OFFSET_V6 0xf780 +#define S5P_FIMV_E_ENC_OPTIONS_V6 0xf784 +#define S5P_FIMV_E_PICTURE_PROFILE_V6 0xf788 +#define S5P_FIMV_E_FIXED_PICTURE_QP_V6 0xf790 + +#define S5P_FIMV_E_RC_CONFIG_V6 0xf794 +#define S5P_FIMV_E_RC_QP_BOUND_V6 0xf798 +#define S5P_FIMV_E_RC_RPARAM_V6 0xf79c +#define S5P_FIMV_E_MB_RC_CONFIG_V6 0xf7a0 +#define S5P_FIMV_E_PADDING_CTRL_V6 0xf7a4 +#define S5P_FIMV_E_MV_HOR_RANGE_V6 0xf7ac +#define S5P_FIMV_E_MV_VER_RANGE_V6 0xf7b0 + +#define S5P_FIMV_E_VBV_BUFFER_SIZE_V6 0xf84c +#define S5P_FIMV_E_VBV_INIT_DELAY_V6 0xf850 +#define S5P_FIMV_E_NUM_DPB_V6 0xf890 +#define S5P_FIMV_E_LUMA_DPB_V6 0xf8c0 +#define S5P_FIMV_E_CHROMA_DPB_V6 0xf904 +#define S5P_FIMV_E_ME_BUFFER_V6 0xf948 + +#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6 0xf98c +#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6 0xf990 +#define S5P_FIMV_E_TMV_BUFFER0_V6 0xf994 +#define S5P_FIMV_E_TMV_BUFFER1_V6 0xf998 +#define S5P_FIMV_E_SOURCE_LUMA_ADDR_V6 0xf9f0 +#define S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6 0xf9f4 +#define S5P_FIMV_E_STREAM_BUFFER_ADDR_V6 0xf9f8 +#define S5P_FIMV_E_STREAM_BUFFER_SIZE_V6 0xf9fc +#define S5P_FIMV_E_ROI_BUFFER_ADDR_V6 0xfA00 + +#define S5P_FIMV_E_PARAM_CHANGE_V6 0xfa04 +#define S5P_FIMV_E_IR_SIZE_V6 0xfa08 +#define S5P_FIMV_E_GOP_CONFIG_V6 0xfa0c +#define S5P_FIMV_E_MSLICE_MODE_V6 0xfa10 +#define S5P_FIMV_E_MSLICE_SIZE_MB_V6 0xfa14 +#define S5P_FIMV_E_MSLICE_SIZE_BITS_V6 0xfa18 +#define S5P_FIMV_E_FRAME_INSERTION_V6 0xfa1c + +#define S5P_FIMV_E_RC_FRAME_RATE_V6 0xfa20 +#define S5P_FIMV_E_RC_BIT_RATE_V6 0xfa24 +#define S5P_FIMV_E_RC_QP_OFFSET_V6 0xfa28 +#define S5P_FIMV_E_RC_ROI_CTRL_V6 0xfa2c +#define S5P_FIMV_E_PICTURE_TAG_V6 0xfa30 +#define S5P_FIMV_E_BIT_COUNT_ENABLE_V6 0xfa34 +#define S5P_FIMV_E_MAX_BIT_COUNT_V6 0xfa38 +#define S5P_FIMV_E_MIN_BIT_COUNT_V6 0xfa3c + +#define S5P_FIMV_E_METADATA_BUFFER_ADDR_V6 0xfa40 +#define S5P_FIMV_E_METADATA_BUFFER_SIZE_V6 0xfa44 +#define S5P_FIMV_E_STREAM_SIZE_V6 0xfa80 +#define S5P_FIMV_E_SLICE_TYPE_V6 0xfa84 +#define S5P_FIMV_E_PICTURE_COUNT_V6 0xfa88 +#define S5P_FIMV_E_RET_PICTURE_TAG_V6 0xfa8c +#define S5P_FIMV_E_STREAM_BUFFER_WRITE_POINTER_V6 0xfa90 + +#define S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6 0xfa94 +#define S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6 0xfa98 +#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6 0xfa9c +#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6 0xfaa0 +#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE_V6 0xfaa4 +#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE_V6 0xfaa8 + +#define S5P_FIMV_E_MPEG4_OPTIONS_V6 0xfb10 +#define S5P_FIMV_E_MPEG4_HEC_PERIOD_V6 0xfb14 +#define S5P_FIMV_E_ASPECT_RATIO_V6 0xfb50 +#define S5P_FIMV_E_EXTENDED_SAR_V6 0xfb54 + +#define S5P_FIMV_E_H264_OPTIONS_V6 0xfb58 +#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6 0xfb5c +#define S5P_FIMV_E_H264_LF_BETA_OFFSET_V6 0xfb60 +#define S5P_FIMV_E_H264_I_PERIOD_V6 0xfb64 + +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6 0xfb68 +#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6 0xfb6c +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6 0xfb70 +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6 0xfb74 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 0xfb78 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1_V6 0xfb7c +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2_V6 0xfb80 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3_V6 0xfb84 + +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 0xfb88 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1_V6 0xfb8c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2_V6 0xfb90 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3_V6 0xfb94 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4_V6 0xfb98 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5_V6 0xfb9c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6_V6 0xfba0 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7_V6 0xfba4 + +#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET_V6 0xfba8 +#define S5P_FIMV_E_H264_NUM_T_LAYER_V6 0xfbac + +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 0xfbb0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER1_V6 0xfbb4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER2_V6 0xfbb8 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER3_V6 0xfbbc +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER4_V6 0xfbc0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER5_V6 0xfbc4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER6_V6 0xfbc8 + +#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6 0xfc4c +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE_V6 0 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TOP_BOTTOM_V6 1 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TEMPORAL_V6 2 + +#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1_V6 0xfd40 +#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1_V6 0xfd44 +#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1_V6 0xfd48 +#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1_V6 0xfd4c +#define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6 0xfd50 +#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6 0xfd80 + +/* Codec numbers */ +#define S5P_FIMV_CODEC_NONE_V6 -1 + + +#define S5P_FIMV_CODEC_H264_DEC_V6 0 +#define S5P_FIMV_CODEC_H264_MVC_DEC_V6 1 + +#define S5P_FIMV_CODEC_MPEG4_DEC_V6 3 +#define S5P_FIMV_CODEC_FIMV1_DEC_V6 4 +#define S5P_FIMV_CODEC_FIMV2_DEC_V6 5 +#define S5P_FIMV_CODEC_FIMV3_DEC_V6 6 +#define S5P_FIMV_CODEC_FIMV4_DEC_V6 7 +#define S5P_FIMV_CODEC_H263_DEC_V6 8 +#define S5P_FIMV_CODEC_VC1RCV_DEC_V6 9 +#define S5P_FIMV_CODEC_VC1_DEC_V6 10 +/* FIXME: Add 11~12 */ +#define S5P_FIMV_CODEC_MPEG2_DEC_V6 13 +#define S5P_FIMV_CODEC_VP8_DEC_V6 14 +/* FIXME: Add 15~16 */ +#define S5P_FIMV_CODEC_H264_ENC_V6 20 +#define S5P_FIMV_CODEC_H264_MVC_ENC_V6 21 + +#define S5P_FIMV_CODEC_MPEG4_ENC_V6 23 +#define S5P_FIMV_CODEC_H263_ENC_V6 24 + +#define S5P_FIMV_NV12M_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_VALIGN_V6 16 + +#define S5P_FIMV_TMV_BUFFER_ALIGN_V6 16 +#define S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_ME_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6 256 + +#define S5P_FIMV_LUMA_MB_TO_PIXEL_V6 256 +#define S5P_FIMV_CHROMA_MB_TO_PIXEL_V6 128 +#define S5P_FIMV_NUM_TMV_BUFFERS_V6 2 + +#define S5P_FIMV_MAX_FRAME_SIZE_V6 (2 * SZ_1M) +#define S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6 16 +#define S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6 16 + +/* Buffer size requirements defined by hardware */ +#define S5P_FIMV_TMV_BUFFER_SIZE_V6(w, h) (((w) + 1) * ((h) + 1) * 8) +#define S5P_FIMV_ME_BUFFER_SIZE_V6(imw, imh, mbw, mbh) \ + ((DIV_ROUND_UP(imw, 64) * DIV_ROUND_UP(imh, 64) * 256) + \ + (DIV_ROUND_UP((mbw) * (mbh), 32) * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(w, h) (((w) * 192) + 64) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) \ + ((w) * ((h) * 64 + 144) + (2048/16 * (h) * 64) + \ + (2048/16 * 256 + 8320)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \ + (2096 * ((w) + (h) + 1)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) ((w) * 400) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(w, h) \ + ((w) * 32 + (h) * 128 + (((w) + 1) / 2) * 64 + 2112) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(w, h) \ + (((w) * 64) + (((w) + 1) * 16) + (4096 * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6(w, h) \ + (((w) * 16) + (((w) + 1) * 16)) + +/* MFC Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V6 (28 * SZ_1K) /* 28KB */ +#define MFC_H264_DEC_CTX_BUF_SIZE_V6 (2 * SZ_1M) /* 2MB */ +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V6 (20 * SZ_1K) /* 20KB */ +#define MFC_H264_ENC_CTX_BUF_SIZE_V6 (100 * SZ_1K) /* 100KB */ +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K) /* 12KB */ + +/* MFCv6 variant defines */ +#define MAX_FW_SIZE_V6 (SZ_1M) /* 1MB */ +#define MAX_CPB_SIZE_V6 (3 * SZ_1M) /* 3MB */ +#define MFC_VERSION_V6 0x61 +#define MFC_NUM_PORTS_V6 1 + +#endif /* _REGS_FIMV_V6_H */ -- cgit v0.10.2 From f96f3cfa0bb8f777fe877d7f881bf7ee58bd162a Mon Sep 17 00:00:00 2001 From: Jeongtae Park Date: Wed, 3 Oct 2012 22:19:11 -0300 Subject: [media] s5p-mfc: Update MFC v4l2 driver to support MFC6.x Multi Format Codec 6.x is a hardware video coding acceleration module present in new Exynos5 SoC series. It is capable of handling several new video codecs for decoding and encoding. Signed-off-by: Jeongtae Park Signed-off-by: Janghyuck Kim Signed-off-by: Jaeryul Oh Signed-off-by: Naveen Krishna Chatradhi Signed-off-by: Arun Kumar K Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f588d62..181c768 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -165,12 +165,12 @@ config VIDEO_SAMSUNG_S5P_JPEG This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec config VIDEO_SAMSUNG_S5P_MFC - tristate "Samsung S5P MFC 5.1 Video Codec" + tristate "Samsung S5P MFC Video Codec" depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P select VIDEOBUF2_DMA_CONTIG default n help - MFC 5.1 driver for V4L2. + MFC 5.1 and 6.x driver for V4L2 config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index cfb9ee9..379008c 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o -s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o +s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o -s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o -s5p-mfc-y += s5p_mfc_pm.o -s5p-mfc-y += s5p_mfc_opr_v5.o s5p_mfc_cmd_v5.o +s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_pm.o +s5p-mfc-y += s5p_mfc_opr.o s5p_mfc_opr_v5.o s5p_mfc_opr_v6.o +s5p-mfc-y += s5p_mfc_cmd.o s5p_mfc_cmd_v5.o s5p_mfc_cmd_v6.o diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index f33c54d..9319e93 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -147,6 +147,7 @@ #define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 #define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 #define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 +#define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3 #define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 #define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 #define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ @@ -216,6 +217,7 @@ #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) +#define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4 /* Decode frame address */ #define S5P_FIMV_DECODE_Y_ADR 0x2024 @@ -380,6 +382,16 @@ #define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 #define S5P_FIMV_R2H_CMD_ERR_RET 32 +/* Dummy definition for MFCv6 compatibilty */ +#define S5P_FIMV_CODEC_H264_MVC_DEC -1 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET -1 +#define S5P_FIMV_MFC_RESET -1 +#define S5P_FIMV_RISC_ON -1 +#define S5P_FIMV_RISC_BASE_ADDRESS -1 +#define S5P_FIMV_CODEC_VP8_DEC -1 +#define S5P_FIMV_REG_CLEAR_BEGIN 0 +#define S5P_FIMV_REG_CLEAR_COUNT 0 + /* Error handling defines */ #define S5P_FIMV_ERR_WARNINGS_START 145 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF @@ -435,4 +447,13 @@ #define MFC_VERSION 0x51 #define MFC_NUM_PORTS 2 +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL 0x16C +#define S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID 0x170 +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO 0x174 +#define S5P_FIMV_SHARED_FRAME_PACK_GRID_POS 0x178 + +/* Values for resolution change in display status */ +#define S5P_FIMV_RES_INCREASE 1 +#define S5P_FIMV_RES_DECREASE 2 + #endif /* _REGS_FIMV_H */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 7feae81..aa55133 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -330,12 +330,14 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; - res_change = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) - & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK; + res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) + & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK) + >> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT; mfc_debug(2, "Frame Status: %x\n", dst_frame_status); if (ctx->state == MFCINST_RES_CHANGE_INIT) ctx->state = MFCINST_RES_CHANGE_FLUSH; - if (res_change) { + if (res_change == S5P_FIMV_RES_INCREASE || + res_change == S5P_FIMV_RES_DECREASE) { ctx->state = MFCINST_RES_CHANGE_INIT; s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); @@ -494,10 +496,28 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, dev); + ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, + dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else ctx->state = MFCINST_HEAD_PARSED; + + if ((ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) && + !list_empty(&ctx->src_queue)) { + struct s5p_mfc_buf *src_buf; + src_buf = list_entry(ctx->src_queue.next, + struct s5p_mfc_buf, list); + if (s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream, + dev) < + src_buf->b->v4l2_planes[0].bytesused) + ctx->head_processed = 0; + else + ctx->head_processed = 1; + } else { + ctx->head_processed = 1; + } } s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); @@ -526,7 +546,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, clear_work_bit(ctx); if (err == 0) { ctx->state = MFCINST_RUNNING; - if (!ctx->dpb_flush_flag) { + if (!ctx->dpb_flush_flag && ctx->head_processed) { spin_lock_irqsave(&dev->irqlock, flags); if (!list_empty(&ctx->src_queue)) { src_buf = list_entry(ctx->src_queue.next, @@ -1071,6 +1091,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) ret = -ENODEV; goto err_res; } + dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r", match_child); if (!dev->mem_dev_r) { @@ -1301,12 +1322,47 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .port_num = MFC_NUM_PORTS, .buf_size = &buf_size_v5, .buf_align = &mfc_buf_align_v5, + .mclk_name = "sclk_mfc", + .fw_name = "s5p-mfc.fw", +}; + +struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V6, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V6, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, +}; + +struct s5p_mfc_buf_size buf_size_v6 = { + .fw = MAX_FW_SIZE_V6, + .cpb = MAX_CPB_SIZE_V6, + .priv = &mfc_buf_size_v6, +}; + +struct s5p_mfc_buf_align mfc_buf_align_v6 = { + .base = 0, +}; + +static struct s5p_mfc_variant mfc_drvdata_v6 = { + .version = MFC_VERSION_V6, + .port_num = MFC_NUM_PORTS_V6, + .buf_size = &buf_size_v6, + .buf_align = &mfc_buf_align_v6, + .mclk_name = "aclk_333", + .fw_name = "s5p-mfc-v6.fw", }; static struct platform_device_id mfc_driver_ids[] = { { .name = "s5p-mfc", .driver_data = (unsigned long)&mfc_drvdata_v5, + }, { + .name = "s5p-mfc-v5", + .driver_data = (unsigned long)&mfc_drvdata_v5, + }, { + .name = "s5p-mfc-v6", + .driver_data = (unsigned long)&mfc_drvdata_v6, }, {}, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c index 8ea304b..f0a41c9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c @@ -14,11 +14,16 @@ #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_cmd_v6.h" static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) { - s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); + if (IS_MFCV6(dev)) + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6(); + else + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); + dev->mfc_cmds = s5p_mfc_cmds; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c new file mode 100644 index 0000000..754bfbc --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -0,0 +1,156 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "s5p_mfc_common.h" + +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" + +int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + mfc_debug(2, "Issue the command: %d\n", cmd); + + /* Reset RISC2HOST command */ + mfc_write(dev, 0x0, S5P_FIMV_RISC2HOST_CMD_V6); + + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0x1, S5P_FIMV_HOST2RISC_INT_V6); + + return 0; +} + +int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev); + mfc_write(dev, dev->ctx_buf.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6, + &h2r_args); +} + +int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6, + &h2r_args); +} + +int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6, + &h2r_args); +} + +/* Open a new instance and get its number */ +int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int codec_type; + + mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + codec_type = S5P_FIMV_CODEC_H264_DEC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_DEC: + codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6; + break; + case S5P_MFC_CODEC_VC1_DEC: + codec_type = S5P_FIMV_CODEC_VC1_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6; + break; + case S5P_MFC_CODEC_H263_DEC: + codec_type = S5P_FIMV_CODEC_H263_DEC_V6; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6; + break; + case S5P_MFC_CODEC_VP8_DEC: + codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; + break; + case S5P_MFC_CODEC_H264_ENC: + codec_type = S5P_FIMV_CODEC_H264_ENC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_ENC: + codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6; + break; + case S5P_MFC_CODEC_H263_ENC: + codec_type = S5P_FIMV_CODEC_H263_ENC_V6; + break; + default: + codec_type = S5P_FIMV_CODEC_NONE_V6; + }; + mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6); + mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ + + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, + &h2r_args); +} + +/* Close instance */ +int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret = 0; + + dev->curr_ctx = ctx->num; + if (ctx->state != MFCINST_FREE) { + mfc_write(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + ret = s5p_mfc_cmd_host2risc_v6(dev, + S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6, + &h2r_args); + } else { + ret = -EINVAL; + } + + return ret; +} + +/* Initialize cmd function pointers for MFC v6 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, + .sleep_cmd = s5p_mfc_sleep_cmd_v6, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v6, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v6, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v6, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) +{ + return &s5p_mfc_cmds_v6; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h new file mode 100644 index 0000000..b7a8e57 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h @@ -0,0 +1,20 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5P_MFC_CMD_V6_H_ +#define S5P_MFC_CMD_V6_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index e495b13..f02e049 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -16,13 +16,14 @@ #ifndef S5P_MFC_COMMON_H_ #define S5P_MFC_COMMON_H_ -#include "regs-mfc.h" #include #include #include #include #include #include +#include "regs-mfc.h" +#include "regs-mfc-v6.h" /* Definitions related to MFC memory */ @@ -206,6 +207,14 @@ struct s5p_mfc_buf_size_v5 { unsigned int shm; }; +struct s5p_mfc_buf_size_v6 { + unsigned int dev_ctx; + unsigned int h264_dec_ctx; + unsigned int other_dec_ctx; + unsigned int h264_enc_ctx; + unsigned int other_enc_ctx; +}; + struct s5p_mfc_buf_size { unsigned int fw; unsigned int cpb; @@ -221,6 +230,8 @@ struct s5p_mfc_variant { unsigned int port_num; struct s5p_mfc_buf_size *buf_size; struct s5p_mfc_buf_align *buf_align; + char *mclk_name; + char *fw_name; }; /** @@ -277,6 +288,7 @@ struct s5p_mfc_priv_buf { * @watchdog_work: worker for the watchdog * @alloc_ctx: videobuf2 allocator contexts for two memory banks * @enter_suspend: flag set when entering suspend + * @ctx_buf: common context memory (MFCv6) * @warn_start: hardware error code from which warnings start * @mfc_ops: ops structure holding HW operation function pointers * @mfc_cmds: cmd structure holding HW commands function pointers @@ -318,6 +330,7 @@ struct s5p_mfc_dev { void *alloc_ctx[2]; unsigned long enter_suspend; + struct s5p_mfc_priv_buf ctx_buf; int warn_start; struct s5p_mfc_hw_ops *mfc_ops; struct s5p_mfc_hw_cmds *mfc_cmds; @@ -354,6 +367,22 @@ struct s5p_mfc_h264_enc_params { int level; u16 cpb_size; int interlace; + u8 hier_qp; + u8 hier_qp_type; + u8 hier_qp_layer; + u8 hier_qp_layer_qp[7]; + u8 sei_frame_packing; + u8 sei_fp_curr_frame_0; + u8 sei_fp_arrangement_type; + + u8 fmo; + u8 fmo_map_type; + u8 fmo_slice_grp; + u8 fmo_chg_dir; + u32 fmo_chg_rate; + u32 fmo_run_len[4]; + u8 aso; + u32 aso_slice_order[8]; }; /** @@ -396,6 +425,7 @@ struct s5p_mfc_enc_params { u32 rc_bitrate; u16 rc_reaction_coeff; u16 vbv_size; + u32 vbv_delay; enum v4l2_mpeg_video_header_mode seq_hdr_mode; enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; @@ -461,6 +491,8 @@ struct s5p_mfc_codec_ops { * decoding buffer * @dpb_flush_flag: flag used to indicate that a DPB buffers are being * flushed + * @head_processed: flag mentioning whether the header data is processed + * completely or not * @bank1_buf: handle to memory allocated for temporary buffers from * memory bank 1 * @bank1_phys: address of the temporary buffers from memory bank 1 @@ -485,14 +517,20 @@ struct s5p_mfc_codec_ops { * @display_delay_enable: display delay for H264 enable flag * @after_packed_pb: flag used to track buffer when stream is in * Packed PB format + * @sei_fp_parse: enable/disable parsing of frame packing SEI information * @dpb_count: count of the DPB buffers required by MFC hw * @total_dpb_count: count of DPB buffers with additional buffers * requested by the application * @ctx: context buffer information * @dsc: descriptor buffer information * @shm: shared memory buffer information + * @mv_count: number of MV buffers allocated for decoding * @enc_params: encoding parameters for MFC * @enc_dst_buf_size: size of the buffers for encoder output + * @luma_dpb_size: dpb buffer size for luma + * @chroma_dpb_size: dpb buffer size for chroma + * @me_buffer_size: size of the motion estimation buffer + * @tmv_buffer_size: size of temporal predictor motion vector buffer * @frame_type: used to force the type of the next encoded frame * @ref_queue: list of the reference buffers for encoding * @ref_queue_cnt: number of the buffers in the reference list @@ -541,6 +579,7 @@ struct s5p_mfc_ctx { unsigned long consumed_stream; unsigned int dpb_flush_flag; + unsigned int head_processed; /* Buffers */ void *bank1_buf; @@ -570,10 +609,11 @@ struct s5p_mfc_ctx { int display_delay; int display_delay_enable; int after_packed_pb; + int sei_fp_parse; int dpb_count; int total_dpb_count; - + int mv_count; /* Buffers */ struct s5p_mfc_priv_buf ctx; struct s5p_mfc_priv_buf dsc; @@ -582,16 +622,28 @@ struct s5p_mfc_ctx { struct s5p_mfc_enc_params enc_params; size_t enc_dst_buf_size; + size_t luma_dpb_size; + size_t chroma_dpb_size; + size_t me_buffer_size; + size_t tmv_buffer_size; enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; struct list_head ref_queue; unsigned int ref_queue_cnt; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + union { + unsigned int mb; + unsigned int bits; + } slice_size; + struct s5p_mfc_codec_ops *c_ops; struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; struct v4l2_ctrl_handler ctrl_handler; + unsigned int frame_tag; + size_t scratch_buf_size; }; /* @@ -637,4 +689,9 @@ void set_work_bit(struct s5p_mfc_ctx *ctx); void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); +#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \ + (dev->variant->port_num ? 1 : 0) : 0) : 0) +#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) +#define IS_MFCV6(dev) (dev->variant->version >= 0x60 ? 1 : 0) + #endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 311ec90..585b7b0e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -37,8 +37,9 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); + err = request_firmware((const struct firmware **)&fw_blob, - "s5p-mfc.fw", dev->v4l2_dev.dev); + dev->variant->fw_name, dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; @@ -82,32 +83,37 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) return -EIO; } dev->bank1 = s5p_mfc_bitproc_phys; - b_base = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BASE_ALIGN_ORDER); - if (IS_ERR(b_base)) { - vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); - s5p_mfc_bitproc_phys = 0; - s5p_mfc_bitproc_buf = NULL; - mfc_err("Allocating bank2 base failed\n"); - release_firmware(fw_blob); - return -ENOMEM; - } - bank2_base_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); - vb2_dma_contig_memops.put(b_base); - if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { - mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); - vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); - s5p_mfc_bitproc_phys = 0; - s5p_mfc_bitproc_buf = NULL; - release_firmware(fw_blob); - return -EIO; + if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { + b_base = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], + 1 << MFC_BASE_ALIGN_ORDER); + if (IS_ERR(b_base)) { + vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); + s5p_mfc_bitproc_phys = 0; + s5p_mfc_bitproc_buf = NULL; + mfc_err("Allocating bank2 base failed\n"); + release_firmware(fw_blob); + return -ENOMEM; + } + bank2_base_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); + vb2_dma_contig_memops.put(b_base); + if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { + mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); + vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); + s5p_mfc_bitproc_phys = 0; + s5p_mfc_bitproc_buf = NULL; + release_firmware(fw_blob); + return -EIO; + } + /* Valid buffers passed to MFC encoder with LAST_FRAME command + * should not have address of bank2 - MFC will treat it as a null frame. + * To avoid such situation we set bank2 address below the pool address. + */ + dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); + } else { + dev->bank2 = dev->bank1; } - /* Valid buffers passed to MFC encoder with LAST_FRAME command - * should not have address of bank2 - MFC will treat it as a null frame. - * To avoid such situation we set bank2 address below the pool address. - */ - dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); wmb(); release_firmware(fw_blob); @@ -124,8 +130,9 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); + err = request_firmware((const struct firmware **)&fw_blob, - "s5p-mfc.fw", dev->v4l2_dev.dev); + dev->variant->fw_name, dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; @@ -166,46 +173,81 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) { unsigned int mc_status; unsigned long timeout; + int i; mfc_debug_enter(); - /* Stop procedure */ - /* reset RISC */ - mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); - /* All reset except for MC */ - mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); - mdelay(10); - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* Check MC status */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while resetting MFC\n"); - return -EIO; - } - mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); + if (IS_MFCV6(dev)) { + /* Reset IP */ + /* except RISC, reset */ + mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6); + /* reset release */ + mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6); + + /* Zero Initialization of MFC registers */ + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); + + for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) + mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); + + /* Reset */ + mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); + mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); + mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); + } else { + /* Stop procedure */ + /* reset RISC */ + mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); + /* All reset except for MC */ + mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); + mdelay(10); - } while (mc_status & 0x3); + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* Check MC status */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while resetting MFC\n"); + return -EIO; + } + + mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); + + } while (mc_status & 0x3); + + mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); + mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); + } - mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); - mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); mfc_debug_leave(); return 0; } static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) { - mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); - mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); - mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2); + if (IS_MFCV6(dev)) { + mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); + mfc_debug(2, "Base Address : %08x\n", dev->bank1); + } else { + mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); + mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); + mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", + dev->bank1, dev->bank2); + } } static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) { - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); - mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); - mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); + if (IS_MFCV6(dev)) { + /* Zero initialization should be done before RESET. + * Nothing to do here. */ + } else { + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); + } } /* Initialize hardware */ @@ -233,7 +275,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); /* 3. Release reset signal to the RISC */ s5p_mfc_clean_dev_int_flags(dev); - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + if (IS_MFCV6(dev)) + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + else + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); @@ -267,7 +312,11 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clock_off(); return -EIO; } - ver = mfc_read(dev, S5P_FIMV_FW_VERSION); + if (IS_MFCV6(dev)) + ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); + else + ver = mfc_read(dev, S5P_FIMV_FW_VERSION); + mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); s5p_mfc_clock_off(); @@ -342,7 +391,10 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) return ret; } /* 4. Release reset signal to the RISC */ - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + if (IS_MFCV6(dev)) + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + else + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { mfc_err("Failed to load firmware\n"); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 107609c..eb6a70b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -31,10 +31,17 @@ #include "s5p_mfc_pm.h" #define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264 -#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT +#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT_16X16 static struct s5p_mfc_fmt formats[] = { { + .name = "4:2:0 2 Planes 16x16 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { .name = "4:2:0 2 Planes 64x32 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT, .codec_mode = S5P_MFC_CODEC_NONE, @@ -42,67 +49,88 @@ static struct s5p_mfc_fmt formats[] = { .num_planes = 2, }, { - .name = "4:2:0 2 Planes", - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "4:2:0 2 Planes Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_MFC_CODEC_H264_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H264/MVC Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264_MVC, + .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "H263 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_MFC_CODEC_H263_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H263 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG1 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG1, - .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG1 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG1, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG2 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG2, - .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG2 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG2, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "XviD Encoded Stream", - .fourcc = V4L2_PIX_FMT_XVID, - .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "XviD Encoded Stream", + .fourcc = V4L2_PIX_FMT_XVID, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "VC1 Encoded Stream", - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, - .codec_mode = S5P_MFC_CODEC_VC1_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "VC1 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, + .codec_mode = S5P_MFC_CODEC_VC1_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "VC1 RCV Encoded Stream", - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, - .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "VC1 RCV Encoded Stream", + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, + .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + }, + { + .name = "VP8 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VP8, + .codec_mode = S5P_MFC_CODEC_VP8_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, }; @@ -343,21 +371,36 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) /* Try format */ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; - if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - mfc_err("This node supports decoding only\n"); - return -EINVAL; - } - fmt = find_format(f, MFC_FMT_DEC); - if (!fmt) { - mfc_err("Unsupported format\n"); - return -EINVAL; - } - if (fmt->type != MFC_FMT_DEC) { - mfc_err("\n"); - return -EINVAL; + mfc_debug(2, "Type is %d\n", f->type); + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt = find_format(f, MFC_FMT_DEC); + if (!fmt) { + mfc_err("Unsupported format for source.\n"); + return -EINVAL; + } + if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("Unsupported format for destination.\n"); + return -EINVAL; + } + if (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (!IS_MFCV6(dev) && + (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } } + return 0; } @@ -380,6 +423,27 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) ret = -EBUSY; goto out; } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("Unsupported format for source.\n"); + return -EINVAL; + } + if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + ctx->dst_fmt = fmt; + mfc_debug_leave(); + return ret; + } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_err("Wrong type error for S_FMT : %d", f->type); + return -EINVAL; + } fmt = find_format(f, MFC_FMT_DEC); if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { mfc_err("Unknown codec\n"); @@ -392,6 +456,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) ret = -EINVAL; goto out; } + if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } ctx->src_fmt = fmt; ctx->codec_mode = fmt->codec_mode; mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); @@ -756,6 +824,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; /* Video output for decoding (source) * this can be set after getting an instance */ @@ -791,7 +860,13 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { psize[0] = ctx->luma_size; psize[1] = ctx->chroma_size; - allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + + if (IS_MFCV6(dev)) + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + else + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && ctx->state == MFCINST_INIT) { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index b0879f9..2af6d52 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -36,39 +36,53 @@ static struct s5p_mfc_fmt formats[] = { { - .name = "4:2:0 2 Planes 64x32 Tiles", - .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes 16x16 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "4:2:0 2 Planes", - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes 64x32 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_MFC_CODEC_H264_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "4:2:0 2 Planes Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "4:2:0 2 Planes Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "H263 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_MFC_CODEC_H263_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + }, + { + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + }, + { + .name = "H263 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, }, }; @@ -576,7 +590,8 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) return 1; /* context is ready to encode a frame */ - if (ctx->state == MFCINST_RUNNING && + if ((ctx->state == MFCINST_RUNNING || + ctx->state == MFCINST_HEAD_PARSED) && ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) return 1; /* context is ready to encode remaining frames */ @@ -645,10 +660,19 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); spin_unlock_irqrestore(&dev->irqlock, flags); } - ctx->state = MFCINST_RUNNING; - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + if (IS_MFCV6(dev)) { + ctx->state = MFCINST_HEAD_PARSED; /* for INIT_BUFFER cmd */ + } else { + ctx->state = MFCINST_RUNNING; + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } + + if (IS_MFCV6(dev)) + ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, + get_enc_dpb_count, dev); + return 0; } @@ -965,6 +989,17 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_err("failed to set output format\n"); return -EINVAL; } + + if (!IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + if (fmt->num_planes != pix_fmt_mp->num_planes) { mfc_err("failed to set output format\n"); ret = -EINVAL; @@ -998,6 +1033,7 @@ out: static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { + struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; @@ -1017,13 +1053,16 @@ static int vidioc_reqbufs(struct file *file, void *priv, return ret; } ctx->capture_state = QUEUE_BUFS_REQUESTED; - ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, alloc_codec_buffers, - ctx); - if (ret) { - mfc_err("Failed to allocate encoding buffers\n"); - reqbufs->count = 0; - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - return -ENOMEM; + + if (!IS_MFCV6(dev)) { + ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, + alloc_codec_buffers, ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers\n"); + reqbufs->count = 0; + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + return -ENOMEM; + } } } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->output_state != QUEUE_FREE) { @@ -1286,6 +1325,13 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) p->codec.h264.profile = S5P_FIMV_ENC_PROFILE_H264_BASELINE; break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + if (IS_MFCV6(dev)) + p->codec.h264.profile = + S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE; + else + ret = -EINVAL; + break; default: ret = -EINVAL; } @@ -1559,6 +1605,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int psize[], void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; if (ctx->state != MFCINST_GOT_INST) { mfc_err("inavlid state: %d\n", ctx->state); @@ -1587,8 +1634,17 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, *buf_count = MFC_MAX_BUFFERS; psize[0] = ctx->luma_size; psize[1] = ctx->chroma_size; - allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; - allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + if (IS_MFCV6(dev)) { + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + allocators[1] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + } else { + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + allocators[1] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + } } else { mfc_err("inavlid queue type: %d\n", vq->type); return -EINVAL; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index b6246b2..6932e90 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -14,12 +14,18 @@ #include "s5p_mfc_opr.h" #include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_opr_v6.h" static struct s5p_mfc_hw_ops *s5p_mfc_ops; void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) { - s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); - dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; + if (IS_MFCV6(dev)) { + s5p_mfc_ops = s5p_mfc_init_hw_ops_v6(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6; + } else { + s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; + } dev->mfc_ops = s5p_mfc_ops; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c new file mode 100644 index 0000000..50b5bee --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -0,0 +1,1956 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v6.h" + +/* #define S5P_MFC_DEBUG_REGWRITE */ +#ifdef S5P_MFC_DEBUG_REGWRITE +#undef writel +#define writel(v, r) \ + do { \ + pr_err("MFCWRITE(%p): %08x\n", r, (unsigned int)v); \ + __raw_writel(v, r); \ + } while (0) +#endif /* S5P_MFC_DEBUG_REGWRITE */ + +#define READL(offset) readl(dev->regs_base + (offset)) +#define WRITEL(data, offset) writel((data), dev->regs_base + (offset)) +#define OFFSETA(x) (((x) - dev->port_a) >> S5P_FIMV_MEM_OFFSET) +#define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET) + +/* Allocate temporary buffers for decoding */ +int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ + + return 0; +} + +/* Release temproary buffers for decoding */ +void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ +} + +int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) +{ + /* NOP */ + return -1; +} + +/* Allocate codec buffers */ +int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int mb_width, mb_height; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * + ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), + S5P_FIMV_TMV_BUFFER_ALIGN_V6); + ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_LUMA_MB_TO_PIXEL_V6, + S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); + ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, + S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( + ctx->img_width, ctx->img_height, + mb_width, mb_height), + S5P_FIMV_ME_BUFFER_ALIGN_V6); + + mfc_debug(2, "recon luma size: %d chroma size: %d\n", + ctx->luma_dpb_size, ctx->chroma_dpb_size); + } else { + return -EINVAL; + } + + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; + case S5P_MFC_CODEC_MPEG4_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + ctx->bank1_size = 0; + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_H263_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VP8_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->dpb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->dpb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2_size = 0; + break; + default: + break; + } + + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1_size > 0) { + ctx->bank1_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); + if (IS_ERR(ctx->bank1_buf)) { + ctx->bank1_buf = 0; + pr_err("Buf alloc for decoding failed (port A)\n"); + return -ENOMEM; + } + ctx->bank1_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); + BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + + return 0; +} + +/* Release buffers allocated for codec */ +void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + if (ctx->bank1_buf) { + vb2_dma_contig_memops.put(ctx->bank1_buf); + ctx->bank1_buf = 0; + ctx->bank1_phys = 0; + ctx->bank1_size = 0; + } +} + +/* Allocate memory for instance data buffer */ +int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + mfc_debug_enter(); + + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + ctx->ctx.size = buf_size->h264_dec_ctx; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + case S5P_MFC_CODEC_H263_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_MPEG2_DEC: + case S5P_MFC_CODEC_VP8_DEC: + ctx->ctx.size = buf_size->other_dec_ctx; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->ctx.size = buf_size->h264_enc_ctx; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + ctx->ctx.size = buf_size->other_enc_ctx; + break; + default: + ctx->ctx.size = 0; + mfc_err("Codec type(%d) should be checked!\n", ctx->codec_mode); + break; + } + + ctx->ctx.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size); + if (IS_ERR(ctx->ctx.alloc)) { + mfc_err("Allocating context buffer failed.\n"); + return PTR_ERR(ctx->ctx.alloc); + } + + ctx->ctx.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc); + + ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc); + if (!ctx->ctx.virt) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.dma = 0; + ctx->ctx.virt = NULL; + + mfc_err("Remapping context buffer failed.\n"); + return -ENOMEM; + } + + memset(ctx->ctx.virt, 0, ctx->ctx.size); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release instance buffer */ +void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + mfc_debug_enter(); + + if (ctx->ctx.alloc) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.dma = 0; + ctx->ctx.virt = NULL; + } + + mfc_debug_leave(); +} + +/* Allocate context buffers for SYS_INIT */ +int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + mfc_debug_enter(); + + dev->ctx_buf.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->dev_ctx); + if (IS_ERR(dev->ctx_buf.alloc)) { + mfc_err("Allocating DESC buffer failed.\n"); + return PTR_ERR(dev->ctx_buf.alloc); + } + + dev->ctx_buf.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], + dev->ctx_buf.alloc); + + dev->ctx_buf.virt = vb2_dma_contig_memops.vaddr(dev->ctx_buf.alloc); + if (!dev->ctx_buf.virt) { + vb2_dma_contig_memops.put(dev->ctx_buf.alloc); + dev->ctx_buf.alloc = NULL; + dev->ctx_buf.dma = 0; + + mfc_err("Remapping DESC buffer failed.\n"); + return -ENOMEM; + } + + memset(dev->ctx_buf.virt, 0, buf_size->dev_ctx); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release context buffers for SYS_INIT */ +void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + if (dev->ctx_buf.alloc) { + vb2_dma_contig_memops.put(dev->ctx_buf.alloc); + dev->ctx_buf.alloc = NULL; + dev->ctx_buf.dma = 0; + dev->ctx_buf.virt = NULL; + } +} + +static int calc_plane(int width, int height) +{ + int mbX, mbY; + + mbX = DIV_ROUND_UP(width, S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); + mbY = DIV_ROUND_UP(height, S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6); + + if (width * height < S5P_FIMV_MAX_FRAME_SIZE_V6) + mbY = (mbY + 1) / 2 * 2; + + return (mbX * S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6) * + (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); +} + +void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) +{ + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); + mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" + "buffer dimensions: %dx%d\n", ctx->img_width, + ctx->img_height, ctx->buf_width, ctx->buf_height); + + ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); + ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + ctx->img_height); + ctx->mv_size = ALIGN(ctx->mv_size, 16); + } else { + ctx->mv_size = 0; + } +} + +void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int mb_width, mb_height; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6); + ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256); + ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256); +} + +/* Set registers for decoding stream buffer */ +int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr, + unsigned int start_num_byte, unsigned int strm_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; + + mfc_debug_enter(); + mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" + "buf_size: 0x%08x (%d)\n", + ctx->inst_no, buf_addr, strm_size, strm_size); + WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6); + WRITEL(buf_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6); + WRITEL(buf_size->cpb, S5P_FIMV_D_CPB_BUFFER_SIZE_V6); + WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6); + + mfc_debug_leave(); + return 0; +} + +/* Set decoding frame buffer */ +int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1; + int buf_size1; + int align_gap; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count); + mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay); + + WRITEL(ctx->total_dpb_count, S5P_FIMV_D_NUM_DPB_V6); + WRITEL(ctx->luma_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6); + WRITEL(ctx->chroma_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6); + + WRITEL(buf_addr1, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6); + WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6); + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ + WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6); + WRITEL(ctx->mv_count, S5P_FIMV_D_NUM_MV_V6); + } + + frame_size = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", + frame_size, frame_size_ch, frame_size_mv); + + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + WRITEL(ctx->dst_bufs[i].cookie.raw.luma, + S5P_FIMV_D_LUMA_DPB_V6 + i * 4); + mfc_debug(2, "\tChroma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + WRITEL(ctx->dst_bufs[i].cookie.raw.chroma, + S5P_FIMV_D_CHROMA_DPB_V6 + i * 4); + } + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + for (i = 0; i < ctx->mv_count; i++) { + /* To test alignment */ + align_gap = buf_addr1; + buf_addr1 = ALIGN(buf_addr1, 16); + align_gap = buf_addr1 - align_gap; + buf_size1 -= align_gap; + + mfc_debug(2, "\tBuf1: %x, size: %d\n", + buf_addr1, buf_size1); + WRITEL(buf_addr1, S5P_FIMV_D_MV_BUFFER_V6 + i * 4); + buf_addr1 += frame_size_mv; + buf_size1 -= frame_size_mv; + } + } + + mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n", + buf_addr1, buf_size1, ctx->total_dpb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug(2, "After setting buffers.\n"); + return 0; +} + +/* Set registers for encoding stream buffer */ +int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); /* 16B align */ + WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6); + + mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d", + addr, size); + + return 0; +} + +void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); /* 256B align */ + WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6); + + mfc_debug(2, "enc src y buf addr: 0x%08lx", y_addr); + mfc_debug(2, "enc src c buf addr: 0x%08lx", c_addr); +} + +void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long enc_recon_y_addr, enc_recon_c_addr; + + *y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6); + *c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6); + + enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6); + enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6); + + mfc_debug(2, "recon y addr: 0x%08lx", enc_recon_y_addr); + mfc_debug(2, "recon c addr: 0x%08lx", enc_recon_c_addr); +} + +/* Set encoding ref & codec buffer */ +int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1, buf_size1; + int i; + + mfc_debug_enter(); + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + + for (i = 0; i < ctx->dpb_count; i++) { + WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB_V6 + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB_V6 + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + WRITEL(buf_addr1, S5P_FIMV_E_ME_BUFFER_V6 + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + + ctx->me_buffer_size); + } + + WRITEL(buf_addr1, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6); + WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6); + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER0_V6); + buf_addr1 += ctx->tmv_buffer_size >> 1; + WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER1_V6); + buf_addr1 += ctx->tmv_buffer_size >> 1; + buf_size1 -= ctx->tmv_buffer_size; + + mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n", + buf_addr1, buf_size1, ctx->dpb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + WRITEL(ctx->slice_mode, S5P_FIMV_E_MSLICE_MODE_V6); + if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + WRITEL(ctx->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6); + } else if (ctx->slice_mode == + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + WRITEL(ctx->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); + } else { + WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB_V6); + WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); + } + + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg = 0; + + mfc_debug_enter(); + + /* width */ + WRITEL(ctx->img_width, S5P_FIMV_E_FRAME_WIDTH_V6); /* 16 align */ + /* height */ + WRITEL(ctx->img_height, S5P_FIMV_E_FRAME_HEIGHT_V6); /* 16 align */ + + /* cropped width */ + WRITEL(ctx->img_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6); + /* cropped height */ + WRITEL(ctx->img_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); + /* cropped offset */ + WRITEL(0x0, S5P_FIMV_E_FRAME_CROP_OFFSET_V6); + + /* pictype : IDR period */ + reg = 0; + reg |= p->gop_size & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + ctx->slice_mode = p->slice_mode; + reg = 0; + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + reg |= (0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + ctx->slice_size.mb = p->slice_mb; + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + reg |= (0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + ctx->slice_size.bits = p->slice_bit; + } else { + reg &= ~(0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + } + + s5p_mfc_set_slice_mode(ctx); + + /* cyclic intra refresh */ + WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE_V6); + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + if (p->intra_refresh_mb == 0) + reg &= ~(0x1 << 4); + else + reg |= (0x1 << 4); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* 'NON_REFERENCE_STORE_ENABLE' for debugging */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 9); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg |= (0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + } + + /* memory structure recon. frame */ + /* 0: Linear, 1: 2D tiled */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg |= (0x1 << 8); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* padding control & value */ + WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL_V6); + if (p->pad) { + reg = 0; + /** enable */ + reg |= (1 << 31); + /** cr value */ + reg |= ((p->pad_cr & 0xFF) << 16); + /** cb value */ + reg |= ((p->pad_cb & 0xFF) << 8); + /** y value */ + reg |= p->pad_luma & 0xFF; + WRITEL(reg, S5P_FIMV_E_PADDING_CTRL_V6); + } + + /* rate control config. */ + reg = 0; + /* frame-level rate control */ + reg |= ((p->rc_frame & 0x1) << 9); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* bit rate */ + if (p->rc_frame) + WRITEL(p->rc_bitrate, + S5P_FIMV_E_RC_BIT_RATE_V6); + else + WRITEL(1, S5P_FIMV_E_RC_BIT_RATE_V6); + + /* reaction coefficient */ + if (p->rc_frame) { + if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */ + WRITEL(1, S5P_FIMV_E_RC_RPARAM_V6); + else /* loose CBR */ + WRITEL(2, S5P_FIMV_E_RC_RPARAM_V6); + } + + /* seq header ctrl */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 2); + reg |= ((p->seq_hdr_mode & 0x1) << 2); + + /* frame skip mode */ + reg &= ~(0x3); + reg |= (p->frame_skip_mode & 0x3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* 'DROP_CONTROL_ENABLE', disable */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + reg &= ~(0x1 << 10); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* setting for MV range [16, 256] */ + reg = 0; + reg &= ~(0x3FFF); + reg = 256; + WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE_V6); + + reg = 0; + reg &= ~(0x3FFF); + reg = 256; + WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE_V6); + + WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION_V6); + WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR_V6); + WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE_V6); + WRITEL(0x0, S5P_FIMV_E_RC_ROI_CTRL_V6); + WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG_V6); + + WRITEL(0x0, S5P_FIMV_E_BIT_COUNT_ENABLE_V6); + WRITEL(0x0, S5P_FIMV_E_MAX_BIT_COUNT_V6); + WRITEL(0x0, S5P_FIMV_E_MIN_BIT_COUNT_V6); + + WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6); + WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_h264->level & 0xFF) << 8); + /** profile - 0 ~ 3 */ + reg |= p_h264->profile & 0x3F; + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h264->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h264->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h264->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h264->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p_h264->cpb_size & 0xFFFF, + S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + /* interlace */ + reg = 0; + reg |= ((p_h264->interlace & 0x1) << 3); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* height */ + if (p_h264->interlace) { + WRITEL(ctx->img_height >> 1, + S5P_FIMV_E_FRAME_HEIGHT_V6); /* 32 align */ + /* cropped height */ + WRITEL(ctx->img_height >> 1, + S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); + } + + /* loop filter ctrl */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 1); + reg |= ((p_h264->loop_filter_mode & 0x3) << 1); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* loopfilter alpha offset */ + if (p_h264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_alpha & 0xF); + } + WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6); + + /* loopfilter beta offset */ + if (p_h264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_beta & 0xF); + } + WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6); + + /* entropy coding mode */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1); + reg |= p_h264->entropy_mode & 0x1; + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* number of ref. picture */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 7); + reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* 8x8 transform enable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 12); + reg |= ((p_h264->_8x8_transform & 0x3) << 12); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* macroblock adaptive scaling features */ + WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG_V6); + if (p->rc_mb) { + reg = 0; + /** dark region */ + reg |= ((p_h264->rc_mb_dark & 0x1) << 3); + /** smooth region */ + reg |= ((p_h264->rc_mb_smooth & 0x1) << 2); + /** static region */ + reg |= ((p_h264->rc_mb_static & 0x1) << 1); + /** high activity region */ + reg |= p_h264->rc_mb_activity & 0x1; + WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG_V6); + } + + /* aspect ratio VUI */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 5); + reg |= ((p_h264->vui_sar & 0x1) << 5); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO_V6); + WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR_V6); + if (p_h264->vui_sar) { + /* aspect ration IDC */ + reg = 0; + reg |= p_h264->vui_sar_idc & 0xFF; + WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO_V6); + if (p_h264->vui_sar_idc == 0xFF) { + /* extended SAR */ + reg = 0; + reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16; + reg |= p_h264->vui_ext_sar_height & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR_V6); + } + } + + /* intra picture period for H.264 open GOP */ + /* control */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 4); + reg |= ((p_h264->open_gop & 0x1) << 4); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + /* value */ + WRITEL(0x0, S5P_FIMV_E_H264_I_PERIOD_V6); + if (p_h264->open_gop) { + reg = 0; + reg |= p_h264->open_gop_size & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_H264_I_PERIOD_V6); + } + + /* 'WEIGHTED_BI_PREDICTION' for B is disable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 9); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 14); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* ASO */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 6); + reg |= ((p_h264->aso & 0x1) << 6); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* hier qp enable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 8); + reg |= ((p_h264->open_gop & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + reg = 0; + if (p_h264->hier_qp && p_h264->hier_qp_layer) { + reg |= (p_h264->hier_qp_type & 0x1) << 0x3; + reg |= p_h264->hier_qp_layer & 0x7; + WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); + /* QP value for each layer */ + for (i = 0; i < (p_h264->hier_qp_layer & 0x7); i++) + WRITEL(p_h264->hier_qp_layer_qp[i], + S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 + + i * 4); + } + /* number of coding layer should be zero when hierarchical is disable */ + WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); + + /* frame packing SEI generation */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 25); + reg |= ((p_h264->sei_frame_packing & 0x1) << 25); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + if (p_h264->sei_frame_packing) { + reg = 0; + /** current frame0 flag */ + reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2); + /** arrangement type */ + reg |= p_h264->sei_fp_arrangement_type & 0x3; + WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6); + } + + if (p_h264->fmo) { + switch (p_h264->fmo_map_type) { + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++) + WRITEL(p_h264->fmo_run_len[i] - 1, + S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 + + i * 4); + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN: + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: + if (p_h264->fmo_slice_grp > 2) + p_h264->fmo_slice_grp = 2; + WRITEL(p_h264->fmo_chg_dir & 0x1, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6); + /* the valid range is 0 ~ number of macroblocks -1 */ + WRITEL(p_h264->fmo_chg_rate, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6); + break; + default: + mfc_err("Unsupported map type for FMO: %d\n", + p_h264->fmo_map_type); + p_h264->fmo_map_type = 0; + p_h264->fmo_slice_grp = 1; + break; + } + + WRITEL(p_h264->fmo_map_type, + S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6); + WRITEL(p_h264->fmo_slice_grp - 1, + S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); + } else { + WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); + } + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_mpeg4->level & 0xFF) << 8); + /** profile - 0 ~ 1 */ + reg |= p_mpeg4->profile & 0x3F; + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_mpeg4->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + /* Disable HEC */ + WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS_V6); + WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* profile & level */ + reg = 0; + /** profile */ + reg |= (0x1 << 4); + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h263->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h263->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h263->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + mfc_debug_leave(); + + return 0; +} + +/* Initialize decoding */ +int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int reg = 0; + int fmo_aso_ctrl = 0; + + mfc_debug_enter(); + mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, + S5P_FIMV_CH_SEQ_HEADER_V6); + mfc_debug(2, "BUFs: %08x %08x %08x\n", + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6)); + + /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ + reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); + + /* When user sets desplay_delay to 0, + * It works as "display_delay enable" and delay set to 0. + * If user wants display_delay disable, It should be + * set to negative value. */ + if (ctx->display_delay >= 0) { + reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); + WRITEL(ctx->display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6); + } + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) { + mfc_debug(2, "Set loop filter to: %d\n", + ctx->loop_filter_mpeg4); + reg |= (ctx->loop_filter_mpeg4 << + S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6); + } + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) + reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6); + + WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6); + + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M) + WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); + else + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + + /* sei parse */ + WRITEL(ctx->sei_fp_parse & 0x1, S5P_FIMV_D_SEI_ENABLE_V6); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + mfc_debug_leave(); + return 0; +} + +static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + if (flush) + dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (1 << 14); + else + dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~(1 << 14); + WRITEL(dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); +} + +/* Decode a single frame */ +int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(ctx->dec_dst_flag, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6); + WRITEL(ctx->slice_interface & 0x1, S5P_FIMV_D_SLICE_IF_ENABLE_V6); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case 0: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_FRAME_START_V6, NULL); + break; + case 1: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_LAST_FRAME_V6, NULL); + break; + default: + mfc_err("Unsupported last frame arg.\n"); + return -EINVAL; + } + + mfc_debug(2, "Decoding a usual frame.\n"); + return 0; +} + +int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else { + mfc_err("Unknown codec for encoding (%x).\n", + ctx->codec_mode); + return -EINVAL; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + return 0; +} + +int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + int i; + + if (p_h264->aso) { + for (i = 0; i < 8; i++) + WRITEL(p_h264->aso_slice_order[i], + S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 + i * 4); + } + return 0; +} + +/* Encode a single frame */ +int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_debug(2, "++\n"); + + /* memory structure cur. frame */ + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_h264_set_aso_slice_order_v6(ctx); + + s5p_mfc_set_slice_mode(ctx); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_FRAME_START_V6, NULL); + + mfc_debug(2, "--\n"); + + return 0; +} + +static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int new_ctx; + int cnt; + + spin_lock_irqsave(&dev->condlock, flags); + mfc_debug(2, "Previos context: %d (bits %08lx)\n", dev->curr_ctx, + dev->ctx_work_bits); + new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; + cnt = 0; + while (!test_bit(new_ctx, &dev->ctx_work_bits)) { + new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; + cnt++; + if (cnt > MFC_NUM_CONTEXTS) { + /* No contexts to run */ + spin_unlock_irqrestore(&dev->condlock, flags); + return -EAGAIN; + } + } + spin_unlock_irqrestore(&dev->condlock, flags); + return new_ctx; +} + +static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + + spin_lock_irqsave(&dev->irqlock, flags); + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, 0); + spin_unlock_irqrestore(&dev->irqlock, flags); + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v6(ctx, 1); +} + +static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + int last_frame = 0; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + ctx->consumed_stream, + temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + + index = temp_vb->b->v4l2_buf.index; + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + if (temp_vb->b->v4l2_planes[0].bytesused == 0) { + last_frame = 1; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame_v6(ctx, last_frame); + + return 0; +} + +static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + /* + unsigned int src_y_size, src_c_size; + */ + unsigned int dst_size; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "no src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + src_mb->flags |= MFC_BUF_FLAG_USED; + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); + + mfc_debug(2, "enc src y addr: 0x%08lx", src_y_addr); + mfc_debug(2, "enc src c addr: 0x%08lx", src_c_addr); + + s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr); + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + + spin_unlock_irqrestore(&dev->irqlock, flags); + + index = src_mb->b->v4l2_buf.index; + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_encode_one_frame_v6(ctx); + + return 0; +} + +static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + spin_lock_irqsave(&dev->irqlock, flags); + mfc_debug(2, "Preparing to init decoding.\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, + temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_decode_v6(ctx); +} + +static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + spin_lock_irqsave(&dev->irqlock, flags); + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_encode_v6(ctx); +} + +static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + /* Header was parsed now start processing + * First set the output frame buffers + * s5p_mfc_alloc_dec_buffers(ctx); */ + + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destionation buffers were\n" + "mmaped.MFC requires that all destination are mmaped\n" + "before starting processing.\n"); + return -EAGAIN; + } + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_dec_frame_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + + ret = s5p_mfc_alloc_codec_buffers_v6(ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers.\n"); + return -ENOMEM; + } + + /* Header was generated now starting processing + * First set the reference frame buffers + */ + if (ctx->capture_state != QUEUE_BUFS_REQUESTED) { + mfc_err("It seems that destionation buffers were not\n" + "requested.MFC requires that header should be generated\n" + "before allocating codec buffer.\n"); + return -EAGAIN; + } + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + mfc_debug(1, "Try run dev: %p\n", dev); + + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW.\n"); + return; + } + + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware.\n"); + return; + } + + mfc_debug(1, "No ctx is scheduled to be run.\n"); + return; + } + + mfc_debug(1, "New context: %d\n", new_ctx); + ctx = dev->ctx[new_ctx]; + mfc_debug(1, "Seting new context to %p\n", ctx); + /* Got context to run in ctx */ + mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", + ctx->dst_queue_cnt, ctx->dpb_count, ctx->src_queue_cnt); + mfc_debug(1, "ctx->state=%d\n", ctx->state); + /* Last frame has already been sent to MFC + * Now obtaining frames from MFC buffer */ + + s5p_mfc_clock_on(); + if (ctx->type == MFCINST_DECODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change.\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec`.\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + case MFCINST_HEAD_PARSED: /* Only for MFC6.x */ + ret = s5p_mfc_run_init_enc_buffers(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware.\n"); + + /* This is in deed imporant, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + + +void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->num_planes; i++) + vb2_set_plane_payload(b->b, i, 0); + vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + +void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) +{ + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_INT_V6); +} + +void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_clock_on(); + WRITEL(data, ofs); + s5p_mfc_clock_off(); +} + +unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + + s5p_mfc_clock_on(); + ret = READL(ofs); + s5p_mfc_clock_off(); + + return ret; +} + +int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); +} + +int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); +} + +int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6); +} + +int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6); +} + +int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_FRAME_TYPE_V6) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) +{ + return mfc_read(ctx->dev, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_NAL_SIZE_V6); +} + +int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_CMD_V6) & + S5P_FIMV_RISC2HOST_CMD_MASK; +} + +int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ERROR_CODE_V6); +} + +int s5p_mfc_err_dec_v6(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; +} + +int s5p_mfc_err_dspl_v6(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6; +} + +int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6); +} + +int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6); +} + +int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MIN_NUM_DPB_V6); +} + +int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MIN_NUM_MV_V6); +} + +int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RET_INSTANCE_ID_V6); +} + +int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_NUM_DPB_V6); +} + +int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_STREAM_SIZE_V6); +} + +int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_SLICE_TYPE_V6); +} + +int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_PICTURE_COUNT_V6); +} + +int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) +{ + return mfc_read(ctx->dev, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6); +} + +int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MVC_NUM_VIEWS_V6); +} + +int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MVC_VIEW_ID_V6); +} + +unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, PIC_TIME_TOP_V6); +} + +unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, PIC_TIME_BOT_V6); +} + +unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, CROP_INFO_H_V6); +} + +unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, CROP_INFO_V_V6); +} + +/* Initialize opr function pointers for MFC v6 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v6, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v6, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v6, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v6, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v6, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v6, + .alloc_dev_context_buffer = + s5p_mfc_alloc_dev_context_buffer_v6, + .release_dev_context_buffer = + s5p_mfc_release_dev_context_buffer_v6, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6, + .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v6, + .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v6, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6, + .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v6, + .init_decode = s5p_mfc_init_decode_v6, + .init_encode = s5p_mfc_init_encode_v6, + .encode_one_frame = s5p_mfc_encode_one_frame_v6, + .try_run = s5p_mfc_try_run_v6, + .cleanup_queue = s5p_mfc_cleanup_queue_v6, + .clear_int_flags = s5p_mfc_clear_int_flags_v6, + .write_info = s5p_mfc_write_info_v6, + .read_info = s5p_mfc_read_info_v6, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6, + .get_dspl_status = s5p_mfc_get_dspl_status_v6, + .get_dec_status = s5p_mfc_get_dec_status_v6, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v6, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v6, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v6, + .get_int_reason = s5p_mfc_get_int_reason_v6, + .get_int_err = s5p_mfc_get_int_err_v6, + .err_dec = s5p_mfc_err_dec_v6, + .err_dspl = s5p_mfc_err_dspl_v6, + .get_img_width = s5p_mfc_get_img_width_v6, + .get_img_height = s5p_mfc_get_img_height_v6, + .get_dpb_count = s5p_mfc_get_dpb_count_v6, + .get_mv_count = s5p_mfc_get_mv_count_v6, + .get_inst_no = s5p_mfc_get_inst_no_v6, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6, + .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v6, + .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v6, + .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v6, + .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v6, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v6, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) +{ + return &s5p_mfc_ops_v6; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h new file mode 100644 index 0000000..ab164ef --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -0,0 +1,50 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef S5P_MFC_OPR_V6_H_ +#define S5P_MFC_OPR_V6_H_ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" + +#define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SFR + +#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, 16) +#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) +#define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) + +/* Definition */ +#define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) +#define ENC_MULTI_SLICE_BIT_MIN 2800 +#define ENC_INTRA_REFRESH_MB_MAX ((1 << 18) - 1) +#define ENC_VBV_BUF_SIZE_MAX ((1 << 30) - 1) +#define ENC_H264_LOOP_FILTER_AB_MIN -12 +#define ENC_H264_LOOP_FILTER_AB_MAX 12 +#define ENC_H264_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H263_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H264_PROFILE_MAX 3 +#define ENC_H264_LEVEL_MAX 42 +#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) +#define FRAME_DELTA_H264_H263 1 +#define TIGHT_CBR_MAX 10 + +/* Definitions for shared memory compatibility */ +#define PIC_TIME_TOP_V6 S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 +#define PIC_TIME_BOT_V6 S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 +#define CROP_INFO_H_V6 S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 +#define CROP_INFO_V_V6 S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); +#endif /* S5P_MFC_OPR_V6_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 0503d14..367db75 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -20,7 +20,6 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_pm.h" -#define MFC_CLKNAME "sclk_mfc" #define MFC_GATE_CLK_NAME "mfc" #define CLK_DEBUG @@ -51,7 +50,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) goto err_p_ip_clk; } - pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); + pm->clock = clk_get(&dev->plat_dev->dev, dev->variant->mclk_name); if (IS_ERR(pm->clock)) { mfc_err("Failed to get MFC clock\n"); ret = PTR_ERR(pm->clock); -- cgit v0.10.2 From cdcf45e70027d7f65eb04df789bd63c0a2f6f47f Mon Sep 17 00:00:00 2001 From: Arun Kumar K Date: Thu, 4 Oct 2012 16:14:56 -0300 Subject: [media] s5p-mfc: Set vfl_dir for encoder The vfl_dir flag is presently set to VFL_DIR_M2M only for decoder. The encoder is not working because of this. So adding this flag to the encoder part also. Signed-off-by: Arun Kumar K Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index aa55133..130f4ac 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1155,6 +1155,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) vfd->release = video_device_release, vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); dev->vfd_enc = vfd; ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); -- cgit v0.10.2 From 78a0b0608be3746cd6bbba6ec158928df7974ebf Mon Sep 17 00:00:00 2001 From: Tomasz Stanislawski Date: Thu, 4 Oct 2012 12:42:39 -0300 Subject: [media] media: s5p-hdmi: add HPD GPIO to platform data This patch extends s5p-hdmi platform data by a GPIO identifier for Hot-Plug-Detection pin. Signed-off-by: Tomasz Stanislawski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/s5p_hdmi.h b/include/media/s5p_hdmi.h index 361a751..181642b 100644 --- a/include/media/s5p_hdmi.h +++ b/include/media/s5p_hdmi.h @@ -20,6 +20,7 @@ struct i2c_board_info; * @hdmiphy_info: template for HDMIPHY I2C device * @mhl_bus: controller id for MHL control bus * @mhl_info: template for MHL I2C device + * @hpd_gpio: GPIO for Hot-Plug-Detect pin * * NULL pointer for *_info fields indicates that * the corresponding chip is not present @@ -29,6 +30,7 @@ struct s5p_hdmi_platform_data { struct i2c_board_info *hdmiphy_info; int mhl_bus; struct i2c_board_info *mhl_info; + int hpd_gpio; }; #endif /* S5P_HDMI_H */ -- cgit v0.10.2 From 44e0d7de4e4ce8a126ec44e4fb7d1f7ad0197bd0 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 5 Oct 2012 18:50:12 -0300 Subject: [media] cxd2820r: silence compiler warning drivers/media/dvb-frontends/cxd2820r_core.c: In function 'cxd2820r_attach': drivers/media/dvb-frontends/cxd2820r_core.c:691:10: warning: unused variable 'gpio' [-Wunused-variable] Reported-by: Fengguang Wu Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 4264864..9b658c1 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -688,7 +688,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, { struct cxd2820r_priv *priv; int ret; - u8 tmp, gpio[GPIO_COUNT]; + u8 tmp; priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); if (!priv) { @@ -735,6 +735,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, * Use static GPIO configuration if GPIOLIB is undefined. * This is fallback condition. */ + u8 gpio[GPIO_COUNT]; gpio[0] = (*gpio_chip_base >> 0) & 0x07; gpio[1] = (*gpio_chip_base >> 3) & 0x07; gpio[2] = 0; -- cgit v0.10.2 From 082c0576d62d7732528d195792f7c80cae5360a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfredo=20Jes=C3=BAs=20Delaiti?= Date: Fri, 21 Sep 2012 10:33:51 -0300 Subject: [media] Mygica X8507 audio for YPbPr, AV and S-Video Adds audio support for input YPbPr, AV and S-Video on Mygica X8507 card. Remains to be done: IR, FM and ISDBT Signed-off-by: Alfredo J. Delaiti Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 39a4a4b..5acdf95 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -542,11 +542,13 @@ struct cx23885_board cx23885_boards[] = { { .type = CX23885_VMUX_COMPOSITE1, .vmux = CX25840_COMPOSITE8, + .amux = CX25840_AUDIO7, }, { .type = CX23885_VMUX_SVIDEO, .vmux = CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4, + .amux = CX25840_AUDIO7, }, { .type = CX23885_VMUX_COMPONENT, @@ -554,6 +556,7 @@ struct cx23885_board cx23885_boards[] = { CX25840_VIN1_CH1 | CX25840_VIN6_CH2 | CX25840_VIN7_CH3, + .amux = CX25840_AUDIO7, }, }, }, diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 8c4a9a5..1a21926 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -508,7 +508,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || + (dev->board == CX23885_BOARD_MYGICA_X8507)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); -- cgit v0.10.2 From 6ec93f01938aae1e1a9fa49bd794afc4e95849bd Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 6 Sep 2012 12:09:14 -0300 Subject: [media] drivers/media/pci/cx88/cx88-blackbird.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index def363f..62184eb 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -721,7 +721,7 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; @@ -739,7 +739,7 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", dev->width, dev->height, fh->mpegq.field ); @@ -755,7 +755,7 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; -- cgit v0.10.2 From 1c4bbfd1c9f25bb35f82641d02ecd0299cfa809c Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 6 Sep 2012 12:09:13 -0300 Subject: [media] drivers/media/dvb-frontends/itd1000.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c index 3164575..c1c3400 100644 --- a/drivers/media/dvb-frontends/itd1000.c +++ b/drivers/media/dvb-frontends/itd1000.c @@ -231,7 +231,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF; itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln); - itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */; + itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */ itd1000_write_reg(state, PLLNL, plln & 0xff); itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f)); itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff); -- cgit v0.10.2 From a6224d46d0152a55cc45e5ce27d6768f626f74f8 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 6 Sep 2012 12:09:12 -0300 Subject: [media] drivers/media/dvb-frontends/sp8870.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index e37274c..2aa8ef7 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -188,7 +188,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->hierarchy) { case HIERARCHY_NONE: @@ -207,7 +207,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->code_rate_HP) { case FEC_1_2: @@ -229,7 +229,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } if (known_parameters) *reg0xc05 |= (2 << 1); /* use specified parameters */ -- cgit v0.10.2 From cb9e40fc98847375a8cddf3449985d0784aba868 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 6 Sep 2012 12:09:11 -0300 Subject: [media] drivers/media/radio/si4713-i2c.c: removes unnecessary semicolon removes unnecessary semicolon Found by Coccinelle: http://coccinelle.lip6.fr/ Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index a9e6d17..e3079c1 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1009,7 +1009,7 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id, default: rval = -EINVAL; - }; + } return rval; } @@ -1081,7 +1081,7 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev, default: rval = -EINVAL; break; - }; + } exit: return rval; @@ -1130,7 +1130,7 @@ static int si4713_write_econtrol_tune(struct si4713_device *sdev, default: rval = -EINVAL; goto unlock; - }; + } if (sdev->power_state) rval = si4713_tx_tune_power(sdev, power, antcap); @@ -1420,7 +1420,7 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev, default: rval = -EINVAL; break; - }; + } exit: return rval; @@ -1473,7 +1473,7 @@ static int si4713_read_econtrol_tune(struct si4713_device *sdev, break; default: rval = -EINVAL; - }; + } unlock: mutex_unlock(&sdev->mutex); @@ -1698,7 +1698,7 @@ static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) default: rval = -EINVAL; break; - }; + } return rval; } -- cgit v0.10.2 From eb3c311cde590cf28362019caafeb00a6d3e44db Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 22 Aug 2012 18:03:30 -0300 Subject: [media] soc-camera: Use new selection target definitions Replace the deprecated V4L2_SEL_TGT_*_ACTIVE selection target names with their new unified counterparts. Compatibility definitions are already in linux/v4l2-common.h. Signed-off-by: Sylwester Nawrocki Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 3be9294..d9b5356 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -950,11 +950,11 @@ static int soc_camera_s_selection(struct file *file, void *fh, /* In all these cases cropping emulation will not help */ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - (s->target != V4L2_SEL_TGT_COMPOSE_ACTIVE && - s->target != V4L2_SEL_TGT_CROP_ACTIVE)) + (s->target != V4L2_SEL_TGT_COMPOSE && + s->target != V4L2_SEL_TGT_CROP)) return -EINVAL; - if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + if (s->target == V4L2_SEL_TGT_COMPOSE) { /* No output size change during a running capture! */ if (is_streaming(ici, icd) && (icd->user_width != s->r.width || @@ -974,7 +974,7 @@ static int soc_camera_s_selection(struct file *file, void *fh, ret = ici->ops->set_selection(icd, s); if (!ret && - s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + s->target == V4L2_SEL_TGT_COMPOSE) { icd->user_width = s->r.width; icd->user_height = s->r.height; if (!icd->streamer) -- cgit v0.10.2 From 1aeed35575c39a4716cd7e0103cb1bb4fe6c8c8a Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Mon, 20 Aug 2012 06:49:24 -0300 Subject: [media] media: mx2_camera: Don't modify non volatile parameters in try_fmt Signed-off-by: Javier Martin [g.liakhovetski@gmx.de: also don't clear pcdev->resizing in .try_fmt()] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 403d7f1..8d25871 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1376,6 +1376,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, __u32 pixfmt = pix->pixelformat; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_fmt_cfg *emma_prp; unsigned int width_limit; int ret; @@ -1438,12 +1439,11 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, __func__, pcdev->s_width, pcdev->s_height); /* If the sensor does not support image size try PrP resizing */ - pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, + emma_prp = mx27_emma_prp_get_format(xlate->code, xlate->host_fmt->fourcc); - memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); if ((mf.width != pix->width || mf.height != pix->height) && - pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { + emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) dev_dbg(icd->parent, "%s: can't resize\n", __func__); } -- cgit v0.10.2 From ec0341b3b7817a5e8ebcf26091dde28dce2d7821 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 5 Sep 2012 08:25:27 -0300 Subject: [media] soc_camera: Use module_platform_driver macro module_platform_driver simplifies the code by eliminating module_init and module_exit calls. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index d9b5356..1234767 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1586,18 +1586,7 @@ static struct platform_driver __refdata soc_camera_pdrv = { }, }; -static int __init soc_camera_init(void) -{ - return platform_driver_register(&soc_camera_pdrv); -} - -static void __exit soc_camera_exit(void) -{ - platform_driver_unregister(&soc_camera_pdrv); -} - -module_init(soc_camera_init); -module_exit(soc_camera_exit); +module_platform_driver(soc_camera_pdrv); MODULE_DESCRIPTION("Image capture bus driver"); MODULE_AUTHOR("Guennadi Liakhovetski "); -- cgit v0.10.2 From 02249369352879343337ee63b45dee1e1cfc2550 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 5 Sep 2012 08:25:26 -0300 Subject: [media] soc_camera: Use devm_kzalloc function devm_kzalloc() has been used to simplify error handling. While at it, the soc_camera_device_register function has been moved to save a few lines of code and a variable. Signed-off-by: Sachin Kamat [g.liakhovetski@gmx.de: remove a superfluous empty line] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 1234767..96c3c6e 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1529,12 +1529,11 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) { struct soc_camera_link *icl = pdev->dev.platform_data; struct soc_camera_device *icd; - int ret; if (!icl) return -EINVAL; - icd = kzalloc(sizeof(*icd), GFP_KERNEL); + icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL); if (!icd) return -ENOMEM; @@ -1543,19 +1542,10 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) icd->pdev = &pdev->dev; platform_set_drvdata(pdev, icd); - ret = soc_camera_device_register(icd); - if (ret < 0) - goto escdevreg; - icd->user_width = DEFAULT_WIDTH; icd->user_height = DEFAULT_HEIGHT; - return 0; - -escdevreg: - kfree(icd); - - return ret; + return soc_camera_device_register(icd); } /* @@ -1572,8 +1562,6 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) list_del(&icd->list); - kfree(icd); - return 0; } -- cgit v0.10.2 From 58dec65d714f9f2872fdfe8f6a1f36027431de95 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Mon, 24 Sep 2012 06:11:03 -0300 Subject: [media] drivers/media/platform/soc_camera/mx2_camera.c: fix error return code Convert a nonnegative error return code to a negative one, as returned elsewhere in the function. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // [mchehab@redhat.com: Second hunk removed, as it doesn't apply anymore, due to a merge conflict] Signed-off-by: Peter Senna Tschudin Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 8d25871..9fd9d1c 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1655,6 +1655,7 @@ static int __devinit mx27_camera_emma_init(struct platform_device *pdev) irq_emma = platform_get_irq(pdev, 1); if (!res_emma || !irq_emma) { dev_err(pcdev->dev, "no EMMA resources\n"); + err = -ENODEV; goto out; } -- cgit v0.10.2 From ab99cb18ae5cbb93f650ba7bc305aae6155da880 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Thu, 6 Sep 2012 12:24:00 -0300 Subject: [media] drivers/media/platform/soc_camera/soc_camera.c: fix error return code Convert a nonnegative error return code to a negative one, as returned elsewhere in the function. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // ( if@p1 (\(ret < 0\|ret != 0\)) { ... return ret; } | ret@p1 = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Peter Senna Tschudin [g.liakhovetski@gmx.de: follow the soc_camera.c style: check "ret < 0"] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 96c3c6e..d3f0b84 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1184,7 +1184,8 @@ static int soc_camera_probe(struct soc_camera_device *icd) sd->grp_id = soc_camera_grp_id(icd); v4l2_set_subdev_hostdata(sd, icd); - if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL)) + ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL); + if (ret < 0) goto ectrl; /* At this point client .probe() should have run already */ -- cgit v0.10.2 From a52eb6c02fa27efb5f8980312785fce1f77377e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Sch=C3=A4fer?= Date: Sun, 23 Sep 2012 17:16:34 -0300 Subject: [media] ov2640: select sensor register bank before applying h/v-flip settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently don't select the register bank in ov2640_s_ctrl, so we can end up writing to DSP register 0x04 instead of sensor register 0x04. This happens for example when calling ov2640_s_ctrl after ov2640_s_fmt. Signed-off-by: Frank Schäfer Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 78ac574..d2d298b 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -684,6 +684,11 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); u8 val; + int ret; + + ret = i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); + if (ret < 0) + return ret; switch (ctrl->id) { case V4L2_CID_VFLIP: -- cgit v0.10.2 From 48cafec9a941c2dfe94d76642662bc20bf87fe08 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Sep 2012 07:11:24 -0300 Subject: [media] rc: divide by zero bugs in s_tx_carrier() "carrier" comes from a get_user() in ir_lirc_ioctl(). We need to test that it's not zero before using it as a divisor. It might have been nice to test for this ir_lirc_ioctl() but the mceusb driver uses zero to disable carrier modulation. The bug in redrat3 is a little more subtle. The ->carrier is passed to mod_freq_to_val() which uses it as a divisor. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 647dd95..d05ac15 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -881,10 +881,13 @@ static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask) static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier) { struct ene_device *dev = rdev->priv; - u32 period = 2000000 / carrier; + u32 period; dbg("TX: attempt to set tx carrier to %d kHz", carrier); + if (carrier == 0) + return -EINVAL; + period = 2000000 / carrier; if (period && (period > ENE_CIRMOD_PRD_MAX || period < ENE_CIRMOD_PRD_MIN)) { diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 699eef3..2ea913a 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -517,6 +517,9 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) struct nvt_dev *nvt = dev->priv; u16 val; + if (carrier == 0) + return -EINVAL; + nvt_cir_reg_write(nvt, 1, CIR_CP); val = 3000000 / (carrier) - 1; nvt_cir_reg_write(nvt, val & 0xff, CIR_CC); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 49731b1..9f5a17b 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -890,6 +890,9 @@ static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) struct device *dev = rr3->dev; rr3_dbg(dev, "Setting modulation frequency to %u", carrier); + if (carrier == 0) + return -EINVAL; + rr3->carrier = carrier; return carrier; -- cgit v0.10.2 From 5f49908adb1ff4f0cec429923f1f49e79f318812 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Sep 2012 07:11:53 -0300 Subject: [media] rc-core: fix return codes in ir_lirc_ioctl() These should be -ENOSYS because not -EINVAL. Reported-by: Sean Young Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 569124b..870c930 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -203,13 +203,13 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, /* TX settings */ case LIRC_SET_TRANSMITTER_MASK: if (!dev->s_tx_mask) - return -EINVAL; + return -ENOSYS; return dev->s_tx_mask(dev, val); case LIRC_SET_SEND_CARRIER: if (!dev->s_tx_carrier) - return -EINVAL; + return -ENOSYS; return dev->s_tx_carrier(dev, val); -- cgit v0.10.2 From 3f037426d61027d40063a1fc2d00a08154c7c187 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:56:04 -0300 Subject: [media] drivers/media/dvb-frontends/dvb_dummy_fe.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c index dcfc902..d5acc30 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c @@ -121,16 +121,13 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; @@ -141,16 +138,13 @@ struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; @@ -161,16 +155,13 @@ struct dvb_frontend *dvb_dummy_fe_qam_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { -- cgit v0.10.2 From 1a5d2da1134c4d7371db71377815aa3fff9f75cd Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:56:03 -0300 Subject: [media] drivers/media/dvb-frontends/lg2160.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index cc11260..5fd14f8 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1421,8 +1421,8 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, config ? config->i2c_addr : 0); state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL); - if (state == NULL) - goto fail; + if (!state) + return NULL; state->cfg = config; state->i2c_adap = i2c_adap; @@ -1449,10 +1449,6 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, state->frontend.dtv_property_cache.atscmh_parade_id = 1; return &state->frontend; -fail: - lg_warn("unable to detect LG216x hardware\n"); - kfree(state); - return NULL; } EXPORT_SYMBOL(lg2160_attach); -- cgit v0.10.2 From 47aab4ab20259526419712df4c5d98b914d968dc Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:56:02 -0300 Subject: [media] drivers/media/dvb-frontends/s5h1432.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c index 8352ce1..6ec16a2 100644 --- a/drivers/media/dvb-frontends/s5h1432.c +++ b/drivers/media/dvb-frontends/s5h1432.c @@ -351,8 +351,8 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n"); /* allocate memory for the internal state */ state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; /* setup the state */ state->config = config; @@ -367,10 +367,6 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } EXPORT_SYMBOL(s5h1432_attach); -- cgit v0.10.2 From 4a0543ee8d17515420d9133c0e733298d1658523 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:56:01 -0300 Subject: [media] drivers/media/dvb-frontends/s921.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c index cd2288c..a271ac3 100644 --- a/drivers/media/dvb-frontends/s921.c +++ b/drivers/media/dvb-frontends/s921.c @@ -487,9 +487,9 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, kzalloc(sizeof(struct s921_state), GFP_KERNEL); dprintk("\n"); - if (state == NULL) { + if (!state) { rc("Unable to kzalloc\n"); - goto rcor; + return NULL; } /* setup the state */ @@ -502,11 +502,6 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, state->frontend.demodulator_priv = state; return &state->frontend; - -rcor: - kfree(state); - - return NULL; } EXPORT_SYMBOL(s921_attach); -- cgit v0.10.2 From e4533e65b3a4194c859e79d8cf9659f1cf1705aa Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:56:00 -0300 Subject: [media] drivers/media/dvb-frontends/stb6100.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index 2e93e65..45f9523 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -575,8 +575,8 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, struct stb6100_state *state = NULL; state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -587,10 +587,6 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, printk("%s: Attaching STB6100 \n", __func__); return fe; - -error: - kfree(state); - return NULL; } static int stb6100_release(struct dvb_frontend *fe) -- cgit v0.10.2 From 0df1042751b0047966834a33e81bb29ac95984e9 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:55:59 -0300 Subject: [media] drivers/media/dvb-frontends/tda665x.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c index 2c1c759..63cc123 100644 --- a/drivers/media/dvb-frontends/tda665x.c +++ b/drivers/media/dvb-frontends/tda665x.c @@ -228,8 +228,8 @@ struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, struct dvb_tuner_info *info; state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL); - if (state == NULL) - goto exit; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -246,10 +246,6 @@ struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name); return fe; - -exit: - kfree(state); - return NULL; } EXPORT_SYMBOL(tda665x_attach); -- cgit v0.10.2 From 0ae13e9e673786985b6910d5a051bc7cea038ea6 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:55:58 -0300 Subject: [media] drivers/media/platform/davinci/vpbe.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 9b623bc..953cf8c 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -755,7 +755,6 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) return 0; vpbe_fail_amp_register: - kfree(vpbe_dev->amp); vpbe_fail_sd_register: kfree(vpbe_dev->encoders); vpbe_fail_v4l2_device: -- cgit v0.10.2 From 6f0fdc498e30ce34da559f43e359c4b517cb5b8b Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Wed, 12 Sep 2012 08:55:57 -0300 Subject: [media] drivers/media/tuners/mt2063.c: Removes useless kfree() Remove useless kfree() and clean up code related to the removal. The semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ position p1,p2; expression x; @@ if (x@p1 == NULL) { ... kfree@p2(x); ... return ...; } @unchanged exists@ position r.p1,r.p2; expression e <= r.x,x,e1; iterator I; statement S; @@ if (x@p1 == NULL) { ... when != I(x,...) S when != e = e1 when != e += e1 when != e -= e1 when != ++e when != --e when != e++ when != e-- when != &e kfree@p2(x); ... return ...; } @ok depends on unchanged exists@ position any r.p1; position r.p2; expression x; @@ ... when != true x@p1 == NULL kfree@p2(x); @depends on !ok && unchanged@ position r.p2; expression x; @@ *kfree@p2(x); // Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 0ed9091..620c4fa 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -2249,8 +2249,8 @@ struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, dprintk(2, "\n"); state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -2261,10 +2261,6 @@ struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, printk(KERN_INFO "%s: Attaching MT2063\n", __func__); return fe; - -error: - kfree(state); - return NULL; } EXPORT_SYMBOL_GPL(mt2063_attach); -- cgit v0.10.2 From 20eb13a77ebcba4341095c453c33dacba44519f9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 6 Oct 2012 11:21:02 -0300 Subject: [media] mt2063: properly handle return error codes Fix a series of warnings when compiled with W=1: drivers/media/tuners/mt2063.c: In function 'mt2063_setreg': drivers/media/tuners/mt2063.c:290:2: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] ... drivers/media/tuners/mt2063.c:2013:2: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] drivers/media/tuners/mt2063.c:2271:14: warning: no previous prototype for 'tuner_MT2063_SoftwareShutdown' [-Wmissing-prototypes] drivers/media/tuners/mt2063.c:2286:14: warning: no previous prototype for 'tuner_MT2063_ClearPowerMaskBits' [-Wmissing-prototypes] Several of those warnings are real bugs: the error status code used to be unsigned, but they're assigned to negative error codes. Fix it by using unsigned int. While here, comment the two power management functions, while we don't add a code there to properly handle tuner suspend/resume. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 620c4fa..2e1a02e 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -245,7 +245,7 @@ struct mt2063_state { /* * mt2063_write - Write data into the I2C bus */ -static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) +static int mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) { struct dvb_frontend *fe = state->frontend; int ret; @@ -277,9 +277,9 @@ static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) /* * mt2063_write - Write register data into the I2C bus, caching the value */ -static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) +static int mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) { - u32 status; + int status; dprintk(2, "\n"); @@ -298,10 +298,10 @@ static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) /* * mt2063_read - Read data from the I2C bus */ -static u32 mt2063_read(struct mt2063_state *state, +static int mt2063_read(struct mt2063_state *state, u8 subAddress, u8 *pData, u32 cnt) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ struct dvb_frontend *fe = state->frontend; u32 i = 0; @@ -816,7 +816,7 @@ static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, */ static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) { - u32 status = 0; + int status = 0; u32 fm, fp; /* restricted range on LO's */ pAS_Info->bSpurAvoided = 0; pAS_Info->nSpursFound = 0; @@ -935,14 +935,14 @@ static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) * * This function returns 0, if no lock, 1 if locked and a value < 1 if error */ -static unsigned int mt2063_lockStatus(struct mt2063_state *state) +static int mt2063_lockStatus(struct mt2063_state *state) { const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ const u32 nPollRate = 2; /* poll status bits every 2 ms */ const u32 nMaxLoops = nMaxWait / nPollRate; const u8 LO1LK = 0x80; u8 LO2LK = 0x08; - u32 status; + int status; u32 nDelays = 0; dprintk(2, "\n"); @@ -1069,7 +1069,7 @@ static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, enum MT2063_DNC_Output_Enable nValue) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ u8 val = 0; dprintk(2, "\n"); @@ -1203,7 +1203,7 @@ static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, static u32 MT2063_SetReceiverMode(struct mt2063_state *state, enum mt2063_delivery_sys Mode) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ u8 val; u32 longval; @@ -1345,7 +1345,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits) { - u32 status = 0; + int status = 0; dprintk(2, "\n"); Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ @@ -1374,7 +1374,7 @@ static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, */ static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) { - u32 status; + int status; dprintk(2, "\n"); if (Shutdown == 1) @@ -1540,7 +1540,7 @@ static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) { /* RF input center frequency */ - u32 status = 0; + int status = 0; u32 LO1; /* 1st LO register value */ u32 Num1; /* Numerator for LO1 reg. value */ u32 f_IF1; /* 1st IF requested */ @@ -1803,7 +1803,7 @@ static const u8 MT2063B3_defaults[] = { static int mt2063_init(struct dvb_frontend *fe) { - u32 status; + int status; struct mt2063_state *state = fe->tuner_priv; u8 all_resets = 0xF0; /* reset/load bits */ const u8 *def = NULL; @@ -2264,11 +2264,12 @@ struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, } EXPORT_SYMBOL_GPL(mt2063_attach); +#if 0 /* * Ancillary routines visible outside mt2063 * FIXME: Remove them in favor of using standard tuner callbacks */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) +static int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; @@ -2281,9 +2282,8 @@ unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) return err; } -EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) +static int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; @@ -2296,7 +2296,7 @@ unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) return err; } -EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); +#endif MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_DESCRIPTION("MT2063 Silicon tuner"); diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h index 3f5cfd9..ab24170 100644 --- a/drivers/media/tuners/mt2063.h +++ b/drivers/media/tuners/mt2063.h @@ -23,10 +23,6 @@ static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, return NULL; } -/* FIXME: Should use the standard DVB attachment interfaces */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); - #endif /* CONFIG_DVB_MT2063 */ #endif /* __MT2063_H__ */ -- cgit v0.10.2 From ac0fe5ba7f2b81a0bc4a7b97455d26e127875393 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Fri, 14 Sep 2012 12:46:52 -0300 Subject: [media] drivers/media/platform/davinci/vpbe.c: Remove unused label and rename remaining labels Remove unused label and rename remaining labels Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 953cf8c..69d7a58 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -610,11 +610,11 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); if (IS_ERR(vpbe_dev->dac_clk)) { ret = PTR_ERR(vpbe_dev->dac_clk); - goto vpbe_unlock; + goto fail_mutex_unlock; } if (clk_enable(vpbe_dev->dac_clk)) { ret = -ENODEV; - goto vpbe_unlock; + goto fail_mutex_unlock; } } @@ -626,7 +626,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) if (ret) { v4l2_err(dev->driver, "Unable to register v4l2 device.\n"); - goto vpbe_fail_clock; + goto fail_clk_put; } v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); @@ -642,7 +642,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "vpbe unable to init venc sub device\n"); ret = -ENODEV; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } /* initialize osd device */ osd_device = vpbe_dev->osd_device; @@ -653,7 +653,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "unable to initialize the OSD device"); err = -ENOMEM; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } } @@ -669,7 +669,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "unable to allocate memory for encoders sub devices"); ret = -ENOMEM; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); @@ -695,7 +695,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) " failed to register", enc_info->module_name); ret = -ENODEV; - goto vpbe_fail_sd_register; + goto fail_kfree_encoders; } } else v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" @@ -714,7 +714,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) "amplifier %s failed to register", amp_info->module_name); ret = -ENODEV; - goto vpbe_fail_amp_register; + goto fail_kfree_encoders; } v4l2_info(&vpbe_dev->v4l2_dev, "v4l2 sub device %s registered\n", @@ -754,15 +754,14 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) /* TBD handling of bootargs for default output and mode */ return 0; -vpbe_fail_amp_register: -vpbe_fail_sd_register: +fail_kfree_encoders: kfree(vpbe_dev->encoders); -vpbe_fail_v4l2_device: +fail_dev_unregister: v4l2_device_unregister(&vpbe_dev->v4l2_dev); -vpbe_fail_clock: +fail_clk_put: if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) clk_put(vpbe_dev->dac_clk); -vpbe_unlock: +fail_mutex_unlock: mutex_unlock(&vpbe_dev->lock); return ret; } -- cgit v0.10.2 From b7e13ef7e61f19ecf0b5d4b7d2483ae7b9f15513 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 24 Sep 2012 02:17:45 -0300 Subject: [media] mem2mem_testdev: Fix incorrect location of v4l2_m2m_release() v4l2_m2m_release() was placed after the return statement and outside any of the goto labels and hence was not getting executed under the error exit path. This patch moves it under the exit path label. Signed-off-by: Sachin Kamat Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index d036375..43395df 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -1067,8 +1067,8 @@ static int m2mtest_probe(struct platform_device *pdev) return 0; - v4l2_m2m_release(dev->m2m_dev); err_m2m: + v4l2_m2m_release(dev->m2m_dev); video_unregister_device(dev->vfd); rel_vdev: video_device_release(vfd); -- cgit v0.10.2 From 56ed221f099afe5c234e5c2cd1371acc8ddbcd88 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 24 Sep 2012 02:17:46 -0300 Subject: [media] mem2mem_testdev: Add missing braces around sizeof Fixes the following checkpatch warnings: WARNING: sizeof *ctx should be sizeof(*ctx) WARNING: sizeof *dev should be sizeof(*dev) Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 43395df..8b27a7e 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -894,7 +894,7 @@ static int m2mtest_open(struct file *file) if (mutex_lock_interruptible(&dev->dev_mutex)) return -ERESTARTSYS; - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) { rc = -ENOMEM; goto open_unlock; @@ -1020,7 +1020,7 @@ static int m2mtest_probe(struct platform_device *pdev) struct video_device *vfd; int ret; - dev = kzalloc(sizeof *dev, GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; -- cgit v0.10.2 From 26fdcf0980225f8b3d5fa258d9f41433cb0664ed Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 24 Sep 2012 02:17:47 -0300 Subject: [media] mem2mem_testdev: Use pr_err instead of printk printk(KERN_ERR...) is replaced with pr_err to silence checkpatch warning. WARNING: Prefer netdev_err(netdev, ... then dev_err(dev, ... then pr_err(... to printk(KERN_ERR ... Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 8b27a7e..7627335 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -397,8 +397,7 @@ static void device_isr(unsigned long priv) curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev); if (NULL == curr_ctx) { - printk(KERN_ERR - "Instance released before the end of transaction\n"); + pr_err("Instance released before the end of transaction\n"); return; } -- cgit v0.10.2 From 38a7996cbb26ddd6b595e2fafa9742aefcb2f115 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 24 Sep 2012 02:17:48 -0300 Subject: [media] mem2mem_testdev: Use devm_kzalloc() in probe devm_kzalloc() makes error handling and cleanup simpler. Signed-off-by: Sachin Kamat Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 7627335..2e2121e 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -1019,7 +1019,7 @@ static int m2mtest_probe(struct platform_device *pdev) struct video_device *vfd; int ret; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1027,7 +1027,7 @@ static int m2mtest_probe(struct platform_device *pdev) ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) - goto free_dev; + return ret; atomic_set(&dev->num_inst, 0); mutex_init(&dev->dev_mutex); @@ -1073,8 +1073,6 @@ rel_vdev: video_device_release(vfd); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); -free_dev: - kfree(dev); return ret; } @@ -1089,7 +1087,6 @@ static int m2mtest_remove(struct platform_device *pdev) del_timer_sync(&dev->timer); video_unregister_device(dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); return 0; } -- cgit v0.10.2 From 34e59a7d45950b1a03e498d34c1baf4998218cd7 Mon Sep 17 00:00:00 2001 From: Guilherme Herrmann Destefani Date: Tue, 25 Sep 2012 18:10:52 -0300 Subject: [media] bt8xx: Add video4linux control V4L2_CID_COLOR_KILLER Added V4L2_CID_COLOR_KILLER control to the bt8xx driver. The control V4L2_CID_PRIVATE_CHROMA_AGC was changed too because with this change the bttv driver must touch two bits in the SC Loop Control Registers, for controls V4L2_CID_COLOR_KILLER and V4L2_CID_PRIVATE_CHROMA_AGC. Signed-off-by: Guilherme Herrmann Destefani Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 16f5ca2..8bad444 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -668,6 +668,12 @@ static const struct v4l2_queryctrl bttv_ctls[] = { .default_value = 32768, .type = V4L2_CTRL_TYPE_INTEGER, },{ + .id = V4L2_CID_COLOR_KILLER, + .name = "Color killer", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { .id = V4L2_CID_HUE, .name = "Hue", .minimum = 0, @@ -1474,6 +1480,9 @@ static int bttv_g_ctrl(struct file *file, void *priv, case V4L2_CID_SATURATION: c->value = btv->saturation; break; + case V4L2_CID_COLOR_KILLER: + c->value = btv->opt_color_killer; + break; case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_VOLUME: @@ -1526,7 +1535,6 @@ static int bttv_s_ctrl(struct file *file, void *f, struct v4l2_control *c) { int err; - int val; struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -1547,6 +1555,16 @@ static int bttv_s_ctrl(struct file *file, void *f, case V4L2_CID_SATURATION: bt848_sat(btv, c->value); break; + case V4L2_CID_COLOR_KILLER: + btv->opt_color_killer = c->value; + if (btv->opt_color_killer) { + btor(BT848_SCLOOP_CKILL, BT848_E_SCLOOP); + btor(BT848_SCLOOP_CKILL, BT848_O_SCLOOP); + } else { + btand(~BT848_SCLOOP_CKILL, BT848_E_SCLOOP); + btand(~BT848_SCLOOP_CKILL, BT848_O_SCLOOP); + } + break; case V4L2_CID_AUDIO_MUTE: audio_mute(btv, c->value); /* fall through */ @@ -1564,9 +1582,13 @@ static int bttv_s_ctrl(struct file *file, void *f, case V4L2_CID_PRIVATE_CHROMA_AGC: btv->opt_chroma_agc = c->value; - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); + if (btv->opt_chroma_agc) { + btor(BT848_SCLOOP_CAGC, BT848_E_SCLOOP); + btor(BT848_SCLOOP_CAGC, BT848_O_SCLOOP); + } else { + btand(~BT848_SCLOOP_CAGC, BT848_E_SCLOOP); + btand(~BT848_SCLOOP_CAGC, BT848_O_SCLOOP); + } break; case V4L2_CID_PRIVATE_COMBFILTER: btv->opt_combfilter = c->value; diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 70fd4f23..9ec0adb 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -429,6 +429,7 @@ struct bttv { int opt_lumafilter; int opt_automute; int opt_chroma_agc; + int opt_color_killer; int opt_adc_crush; int opt_vcr_hack; int opt_whitecrush_upper; -- cgit v0.10.2 From e0f6e4d6ff8d82ca6813f47d12f85224d7491d9e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 26 Sep 2012 06:25:12 -0300 Subject: [media] em28xx: Replace memcpy with struct assignment This kind of memcpy() is error-prone and its replacement with a struct assignment is prefered. Signed-off-by: Ezequiel Garcia Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index ab98d08..bd5e180 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2203,7 +2203,7 @@ EXPORT_SYMBOL_GPL(em28xx_tuner_callback); static inline void em28xx_set_model(struct em28xx *dev) { - memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board)); + dev->board = em28xx_boards[dev->model]; /* Those are the default values for the majority of boards Use those values if not specified otherwise at boards entry -- cgit v0.10.2 From 5712661d643099bda44909cfd75560fcda72c387 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 26 Sep 2012 07:30:34 -0300 Subject: [media] uvc: Add return code check at vb2_queue_init() This function returns an integer and it's mandatory to check the return code. Signed-off-by: Ezequiel Garcia Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 5577381..18a91fa 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -122,21 +122,27 @@ static struct vb2_ops uvc_queue_qops = { .buf_finish = uvc_buffer_finish, }; -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int drop_corrupted) { + int ret; + queue->queue.type = type; queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; queue->queue.drv_priv = queue; queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; - vb2_queue_init(&queue->queue); + ret = vb2_queue_init(&queue->queue); + if (ret) + return ret; mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->irqqueue); queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; + + return 0; } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 1c15b42..57c3076 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1755,7 +1755,9 @@ int uvc_video_init(struct uvc_streaming *stream) atomic_set(&stream->active, 0); /* Initialize the video buffers queue. */ - uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); + ret = uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); + if (ret) + return ret; /* Alternate setting 0 should be the default, yet the XBox Live Vision * Cam (and possibly other devices) crash or otherwise misbehave if diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 3764040..af216ec 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -600,7 +600,7 @@ extern struct uvc_driver uvc_driver; extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); /* Video buffers queue management. */ -extern void uvc_queue_init(struct uvc_video_queue *queue, +extern int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int drop_corrupted); extern int uvc_alloc_buffers(struct uvc_video_queue *queue, struct v4l2_requestbuffers *rb); -- cgit v0.10.2 From 5bdb7872cdadcd630dd2129633e1a3f8aeac69f8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 Sep 2012 09:55:14 -0300 Subject: [media] dvb-usb: print small buffers via %*ph Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c index 8d7fef8..83684ed 100644 --- a/drivers/media/usb/dvb-usb/a800.c +++ b/drivers/media/usb/dvb-usb/a800.c @@ -93,7 +93,7 @@ static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) /* call the universal NEC remote processor, to find out the key's state and event */ dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_rc("key: %*ph\n", 5, key); ret = 0; out: kfree(key); diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c index 0a98548..9fd1527 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -172,8 +172,7 @@ static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) if (*event != d->last_event) st->rc_counter = 0; - deb_rc("key: %x %x %x %x %x\n", - key[0], key[1], key[2], key[3], key[4]); + deb_rc("key: %*ph\n", 5, key); } return 0; } diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index a76bbb2..af0d432 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -473,7 +473,7 @@ int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) dvb_usb_generic_rw(d,&cmd,1,key,5,0); dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_info("key: %*ph\n", 5, key); return 0; } EXPORT_SYMBOL(dibusb_rc_query); diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index ff34419..772bde3 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -253,7 +253,7 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) } if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_rc("key: %*ph\n", 5, key); return 0; } diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index 66f205c..c357fb3 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -84,7 +84,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) dvb_usb_generic_rw(d,&cmd,1,key,5,0); dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_info("key: %*ph\n", 5, key); return 0; } diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 288af29..661bb75 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -358,7 +358,7 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) goto done; - deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]); + deb("%*ph\n", 4, read); if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) goto done; -- cgit v0.10.2 From 947c48086623d9ca2207dd0434bd58458af4ba86 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 27 Sep 2012 10:38:18 -0300 Subject: [media] omap3isp: Replace cpu_is_omap3630() with ISP revision check Drivers must not rely on cpu_is_omap* macros (they will soon become private). Use the ISP revision instead to identify the hardware. Signed-off-by: Laurent Pinchart Acked-by: Tony Lindgren Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index d7aa513..6034dca 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1345,10 +1345,7 @@ static int isp_enable_clocks(struct isp_device *isp) * has to be twice of what is set on OMAP3430 to get * the required value for cam_mclk */ - if (cpu_is_omap3630()) - divisor = 1; - else - divisor = 2; + divisor = isp->revision == ISP_REVISION_15_0 ? 1 : 2; r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); if (r) { @@ -2093,7 +2090,11 @@ static int __devinit isp_probe(struct platform_device *pdev) isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1"); isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2"); - /* Clocks */ + /* Clocks + * + * The ISP clock tree is revision-dependent. We thus need to enable ICLK + * manually to read the revision before calling __omap3isp_get(). + */ ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN); if (ret < 0) goto error; @@ -2102,6 +2103,16 @@ static int __devinit isp_probe(struct platform_device *pdev) if (ret < 0) goto error; + ret = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); + if (ret < 0) + goto error; + + isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); + dev_info(isp->dev, "Revision %d.%d found\n", + (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); + + clk_disable(isp->clock[ISP_CLK_CAM_ICK]); + if (__omap3isp_get(isp, false) == NULL) { ret = -ENODEV; goto error; @@ -2112,10 +2123,6 @@ static int __devinit isp_probe(struct platform_device *pdev) goto error_isp; /* Memory resources */ - isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); - dev_info(isp->dev, "Revision %d.%d found\n", - (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); - for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++) if (isp->revision == isp_res_maps[m].isp_rev) break; -- cgit v0.10.2 From 48b0fa6afa7ee6a274e060564d2389ffea413762 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 28 Sep 2012 04:44:29 -0300 Subject: [media] iguanair: cannot send data from the stack Note that the firmware already disables the receiver before transmit, there is no need to do this from the driver. Reported-by: Fengguang Wu Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 1e4c68a..51d7057 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -28,6 +28,7 @@ #include #define DRIVER_NAME "iguanair" +#define BUF_SIZE 152 struct iguanair { struct rc_dev *rc; @@ -35,26 +36,23 @@ struct iguanair { struct device *dev; struct usb_device *udev; - int pipe_out; uint16_t version; uint8_t bufsize; + uint8_t cycle_overhead; struct mutex lock; /* receiver support */ bool receiver_on; - dma_addr_t dma_in; + dma_addr_t dma_in, dma_out; uint8_t *buf_in; - struct urb *urb_in; + struct urb *urb_in, *urb_out; struct completion completion; /* transmit support */ bool tx_overflow; uint32_t carrier; - uint8_t cycle_overhead; - uint8_t channels; - uint8_t busy4; - uint8_t busy7; + struct send_packet *packet; char name[64]; char phys[64]; @@ -73,7 +71,8 @@ struct iguanair { #define DIR_IN 0xdc #define DIR_OUT 0xcd -#define MAX_PACKET_SIZE 8u +#define MAX_IN_PACKET 8u +#define MAX_OUT_PACKET (sizeof(struct send_packet) + BUF_SIZE) #define TIMEOUT 1000 #define RX_RESOLUTION 21333 @@ -191,20 +190,25 @@ static void iguanair_rx(struct urb *urb) dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc); } -static int iguanair_send(struct iguanair *ir, void *data, unsigned size) +static void iguanair_irq_out(struct urb *urb) { - int rc, transferred; + struct iguanair *ir = urb->context; + + if (urb->status) + dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status); +} + +static int iguanair_send(struct iguanair *ir, unsigned size) +{ + int rc; INIT_COMPLETION(ir->completion); - rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size, - &transferred, TIMEOUT); + ir->urb_out->transfer_buffer_length = size; + rc = usb_submit_urb(ir->urb_out, GFP_KERNEL); if (rc) return rc; - if (transferred != size) - return -EIO; - if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0) return -ETIMEDOUT; @@ -213,14 +217,13 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size) static int iguanair_get_features(struct iguanair *ir) { - struct packet packet; int rc; - packet.start = 0; - packet.direction = DIR_OUT; - packet.cmd = CMD_GET_VERSION; + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = CMD_GET_VERSION; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get version\n"); goto out; @@ -235,17 +238,23 @@ static int iguanair_get_features(struct iguanair *ir) ir->bufsize = 150; ir->cycle_overhead = 65; - packet.cmd = CMD_GET_BUFSIZE; + ir->packet->header.cmd = CMD_GET_BUFSIZE; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get buffer size\n"); goto out; } - packet.cmd = CMD_GET_FEATURES; + if (ir->bufsize > BUF_SIZE) { + dev_info(ir->dev, "buffer size %u larger than expected\n", + ir->bufsize); + ir->bufsize = BUF_SIZE; + } + + ir->packet->header.cmd = CMD_GET_FEATURES; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get features\n"); goto out; @@ -257,13 +266,18 @@ out: static int iguanair_receiver(struct iguanair *ir, bool enable) { - struct packet packet = { 0, DIR_OUT, enable ? - CMD_RECEIVER_ON : CMD_RECEIVER_OFF }; + int rc; + + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF; if (enable) ir_raw_event_reset(ir->rc); - return iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); + + return rc; } /* @@ -308,8 +322,8 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier) fours = (cycles - sevens * 7) / 4; /* magic happens here */ - ir->busy7 = (4 - sevens) * 2; - ir->busy4 = 110 - fours; + ir->packet->busy7 = (4 - sevens) * 2; + ir->packet->busy4 = 110 - fours; } mutex_unlock(&ir->lock); @@ -325,7 +339,7 @@ static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask) return 4; mutex_lock(&ir->lock); - ir->channels = mask; + ir->packet->channels = mask << 4; mutex_unlock(&ir->lock); return 0; @@ -337,16 +351,9 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) uint8_t space; unsigned i, size, periods, bytes; int rc; - struct send_packet *packet; mutex_lock(&ir->lock); - packet = kmalloc(sizeof(*packet) + ir->bufsize, GFP_KERNEL); - if (!packet) { - rc = -ENOMEM; - goto out; - } - /* convert from us to carrier periods */ for (i = space = size = 0; i < count; i++) { periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); @@ -356,11 +363,11 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) break; } while (periods > 127) { - packet->payload[size++] = 127 | space; + ir->packet->payload[size++] = 127 | space; periods -= 127; } - packet->payload[size++] = periods | space; + ir->packet->payload[size++] = periods | space; space ^= 0x80; } @@ -369,36 +376,19 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) goto out; } - packet->header.start = 0; - packet->header.direction = DIR_OUT; - packet->header.cmd = CMD_SEND; - packet->length = size; - packet->channels = ir->channels << 4; - packet->busy7 = ir->busy7; - packet->busy4 = ir->busy4; - - if (ir->receiver_on) { - rc = iguanair_receiver(ir, false); - if (rc) { - dev_warn(ir->dev, "disable receiver before transmit failed\n"); - goto out; - } - } + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = CMD_SEND; + ir->packet->length = size; ir->tx_overflow = false; - rc = iguanair_send(ir, packet, size + 8); + rc = iguanair_send(ir, sizeof(*ir->packet) + size); if (rc == 0 && ir->tx_overflow) rc = -EOVERFLOW; - if (ir->receiver_on) { - if (iguanair_receiver(ir, true)) - dev_warn(ir->dev, "re-enable receiver after transmit failed\n"); - } - out: - kfree(packet); mutex_unlock(&ir->lock); return rc ? rc : count; @@ -411,8 +401,6 @@ static int iguanair_open(struct rc_dev *rdev) mutex_lock(&ir->lock); - BUG_ON(ir->receiver_on); - rc = iguanair_receiver(ir, true); if (rc == 0) ir->receiver_on = true; @@ -443,7 +431,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf, struct usb_device *udev = interface_to_usbdev(intf); struct iguanair *ir; struct rc_dev *rc; - int ret, pipein; + int ret, pipein, pipeout; struct usb_host_interface *idesc; ir = kzalloc(sizeof(*ir), GFP_KERNEL); @@ -453,11 +441,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, goto out; } - ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL, + ir->buf_in = usb_alloc_coherent(udev, MAX_IN_PACKET, GFP_KERNEL, &ir->dma_in); + ir->packet = usb_alloc_coherent(udev, MAX_OUT_PACKET, GFP_KERNEL, + &ir->dma_out); ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); + ir->urb_out = usb_alloc_urb(0, GFP_KERNEL); - if (!ir->buf_in || !ir->urb_in) { + if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) { ret = -ENOMEM; goto out; } @@ -472,13 +463,18 @@ static int __devinit iguanair_probe(struct usb_interface *intf, ir->rc = rc; ir->dev = &intf->dev; ir->udev = udev; - ir->pipe_out = usb_sndintpipe(udev, - idesc->endpoint[1].desc.bEndpointAddress); mutex_init(&ir->lock); + init_completion(&ir->completion); + pipeout = usb_sndintpipe(udev, + idesc->endpoint[1].desc.bEndpointAddress); + usb_fill_int_urb(ir->urb_out, udev, pipeout, ir->packet, MAX_OUT_PACKET, + iguanair_irq_out, ir, 1); + ir->urb_out->transfer_dma = ir->dma_out; + ir->urb_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress); - usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE, + usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_IN_PACKET, iguanair_rx, ir, 1); ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -528,11 +524,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, return 0; out2: usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); out: if (ir) { usb_free_urb(ir->urb_in); - usb_free_coherent(udev, MAX_PACKET_SIZE, ir->buf_in, - ir->dma_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); + usb_free_coherent(udev, MAX_OUT_PACKET, ir->packet, + ir->dma_out); } rc_free_device(rc); kfree(ir); @@ -546,8 +545,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf) rc_unregister_device(ir->rc); usb_set_intfdata(intf, NULL); usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); usb_free_urb(ir->urb_in); - usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); + usb_free_coherent(ir->udev, MAX_OUT_PACKET, ir->packet, ir->dma_out); kfree(ir); } @@ -565,6 +567,7 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message) } usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); mutex_unlock(&ir->lock); -- cgit v0.10.2 From 54fd321e131587b008c47289e4066ac65935cfb5 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 28 Sep 2012 04:44:33 -0300 Subject: [media] winbond: remove space from driver name -snip- ACTION=add DEVPATH=/devices/pnp0/00:04/rc/rc0 DRV_NAME=Winbond CIR NAME=rc-rc6-mce SUBSYSTEM=rc UDEV_LOG=6 USEC_INITIALIZED=88135858 run: '/usr/bin/ir-keytable -a /etc/rc_maps.cfg -s rc0' Having a space makes it impossible to match in /etc/rc_maps.cfg. [root@pequod ~]# udevadm test /sys/class/rc/rc0 Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 30ae1f2..7c9b5f3 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -184,7 +184,7 @@ enum wbcir_txstate { }; /* Misc */ -#define WBCIR_NAME "Winbond CIR" +#define WBCIR_NAME "winbond-cir" #define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ #define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ #define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ -- cgit v0.10.2 From c2c1b4156a447f113ef4d167decce29399c2667c Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Fri, 28 Sep 2012 05:37:22 -0300 Subject: [media] drivers/media: Remove unnecessary semicolon A simplified version of the semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r1@ statement S; position p,p1; @@ S@p1;@p @script:python r2@ p << r1.p; p1 << r1.p1; @@ if p[0].line != p1[0].line_end: cocci.include_match(False) @@ position r1.p; @@ -;@p // [mchehab@redhat.com: some hunks got bitroted; applied only the ones that succeeds] Signed-off-by: Peter Senna Tschudin [crope@iki.fi: For my drivers a8293, af9013, af9015, af9035] Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 8f58f24..41af996 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2309,7 +2309,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, fepriv->tune_mode_flags = (unsigned long) parg; err = 0; break; - }; + } return err; } diff --git a/drivers/media/dvb-frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c index cff44a3..74fbb5d 100644 --- a/drivers/media/dvb-frontends/a8293.c +++ b/drivers/media/dvb-frontends/a8293.c @@ -90,7 +90,7 @@ static int a8293_set_voltage(struct dvb_frontend *fe, default: ret = -EINVAL; goto err; - }; + } ret = a8293_wr(priv, &priv->reg[0], 1); if (ret) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index e9f04a3..a204f28 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -241,7 +241,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) KBUILD_MODNAME, gpio); ret = -EINVAL; goto err; - }; + } switch (gpio) { case 0: @@ -253,7 +253,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) default: pos = 4; break; - }; + } ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval); if (ret) @@ -726,7 +726,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__); auto_mode = 1; - }; + } switch (c->modulation) { case QAM_AUTO: diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 033cd7a..1b77909 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -527,7 +527,7 @@ static int bcm3510_set_frontend(struct dvb_frontend *fe) cmd.ACQUIRE1.IF_FREQ = 0x0; default: return -EINVAL; - }; + } cmd.ACQUIRE0.OFFSET = 0; cmd.ACQUIRE0.NTSCSWEEP = 1; cmd.ACQUIRE0.FA = 1; diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c index 3180f5b..0cd6927 100644 --- a/drivers/media/dvb-frontends/cx24110.c +++ b/drivers/media/dvb-frontends/cx24110.c @@ -218,7 +218,7 @@ static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec) } else return -EOPNOTSUPP; /* fixme (low): which is the correct return code? */ - }; + } return 0; } @@ -275,7 +275,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) cx24110_writereg(state,0x07,tmp|0x3); cx24110_writereg(state,0x06,0x78); fclk=90999000UL; - }; + } dprintk("cx24110 debug: fclk %d Hz\n",fclk); /* we need to divide two integers with approx. 27 bits in 32 bit arithmetic giving a 25 bit result */ @@ -362,7 +362,7 @@ static int cx24110_initfe(struct dvb_frontend* fe) for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) { cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data); - }; + } return 0; } diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index f380eb4..6d98537 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -991,7 +991,7 @@ static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult) if (nrRetries > DRXD_MAX_RETRIES) { status = -1; break; - }; + } status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0); } while (waitCmd != 0); diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c index 33d33f4..0c642a5 100644 --- a/drivers/media/dvb-frontends/isl6405.c +++ b/drivers/media/dvb-frontends/isl6405.c @@ -77,7 +77,7 @@ static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage break; default: return -EINVAL; - }; + } } isl6405->config |= isl6405->override_or; isl6405->config &= isl6405->override_and; diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index 684c8ec..0cb3f0f 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -63,7 +63,7 @@ static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage break; default: return -EINVAL; - }; + } isl6421->config |= isl6421->override_or; isl6421->config &= isl6421->override_and; diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c index 13437259..f3ba7b5 100644 --- a/drivers/media/dvb-frontends/lnbp21.c +++ b/drivers/media/dvb-frontends/lnbp21.c @@ -65,7 +65,7 @@ static int lnbp21_set_voltage(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } lnbp21->config |= lnbp21->override_or; lnbp21->config &= lnbp21->override_and; @@ -108,7 +108,7 @@ static int lnbp21_set_tone(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } lnbp21->config |= lnbp21->override_or; lnbp21->config &= lnbp21->override_and; diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c index 84ad039..c463da7 100644 --- a/drivers/media/dvb-frontends/lnbp22.c +++ b/drivers/media/dvb-frontends/lnbp22.c @@ -73,7 +73,7 @@ static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) break; default: return -EINVAL; - }; + } dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]); return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO; diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index a68a648..73b47cc 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -343,7 +343,7 @@ static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -472,7 +472,7 @@ static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) break; default: return -EINVAL; - }; + } } static int si21xx_init(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index f4096cc..1bb81b5 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -229,7 +229,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->hierarchy) { case HIERARCHY_NONE: @@ -248,7 +248,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->code_rate_HP) { case FEC_1_2: @@ -270,7 +270,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } if (known_parameters) *reg0xc05 |= (2 << 1); /* use specified parameters */ diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c index 057b5f8..92a6075 100644 --- a/drivers/media/dvb-frontends/stv0299.c +++ b/drivers/media/dvb-frontends/stv0299.c @@ -199,7 +199,7 @@ static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -216,7 +216,7 @@ static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -387,7 +387,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag break; default: return -EINVAL; - }; + } if (state->config->op0_off) reg0x0c &= ~0x10; diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 7f1bada..262dfa5 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1552,8 +1552,8 @@ static int stv0900_status(struct stv0900_internal *intp, bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) * (tsbitrate1_val << 8 | tsbitrate0_val); bitrate /= 16384; - dprintk("TS bitrate = %d Mbit/sec \n", bitrate); - }; + dprintk("TS bitrate = %d Mbit/sec\n", bitrate); + } return locked; } diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c index 15912c9..9d08350 100644 --- a/drivers/media/dvb-frontends/tda8083.c +++ b/drivers/media/dvb-frontends/tda8083.c @@ -175,7 +175,7 @@ static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) !(tda8083_readreg(state, 0x02) & 0x80)) { msleep(50); - }; + } } static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) @@ -215,7 +215,7 @@ static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_c break; default: return -EINVAL; - }; + } tda8083_wait_diseqc_fifo (state, 100); diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index d8eac3e..2cee69e 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -599,7 +599,7 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write4(client, 0x114, 0x01bf0c9e); cx25840_write4(client, 0x110, 0x000a030c); break; - }; + } /* ADC2 input select */ cx25840_write(client, 0x102, 0x10); diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index ee3884f..7d96fab 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -646,7 +646,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); default: result = -EOPNOTSUPP; - }; + } free_mem_and_exit: kfree (p_ca_message); kfree (p_ca_slot_info); diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index aee7f0d..495781e 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -416,7 +416,7 @@ static void netup_read_ci_status(struct work_struct *work) DVB_CA_EN50221_POLL_CAM_READY : 0); ci_dbg_print("%s: setting CI[1] status = 0x%x\n", __func__, inter->state[1]->status); - }; + } if (inter->state[0] != NULL) { inter->state[0]->status = @@ -425,7 +425,7 @@ static void netup_read_ci_status(struct work_struct *work) DVB_CA_EN50221_POLL_CAM_READY : 0); ci_dbg_print("%s: setting CI[0] status = 0x%x\n", __func__, inter->state[0]->status); - }; + } } /* CI irq handler */ diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index c9f15d6..6617774 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -193,7 +193,7 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, 0, &store, 1); if (ret != 0) return ret; - }; + } state->current_ci_flag = flag; mutex_lock(&dev->gpio_lock); diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index d803bba..666f83b 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -896,7 +896,7 @@ static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO; } diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index cd5386e..95c0c47 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -450,7 +450,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) cx88_core_irq(core,status); if (status & PCI_INT_TSINT) cx8802_mpeg_irq(dev); - }; + } if (MAX_IRQ_LOOP == loop) { dprintk( 0, "clearing mask\n" ); printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index 770ec05..424fd97 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -373,7 +373,7 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) set_audio_registers(core, nicam_bgdki_common); set_audio_registers(core, nicam_default); break; - }; + } mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS; set_audio_finish(core, mode); @@ -639,7 +639,7 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode) dprintk("%s Warning: wrong value\n", __func__); return; break; - }; + } mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; set_audio_finish(core, mode); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index a146d50..0517145 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1535,7 +1535,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) cx88_core_irq(core,status); if (status & PCI_INT_VIDINT) cx8800_vid_irq(dev); - }; + } if (10 == loop) { printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", core->name); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 22f8758..4a77124 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1204,7 +1204,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str break; default: /* nothing */; - }; + } switch (c->id) { case V4L2_CID_BRIGHTNESS: dev->ctl_bright = c->value; diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c index 0d8625f..0146b35 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.c +++ b/drivers/media/platform/exynos-gsc/gsc-regs.c @@ -212,7 +212,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx) else cfg |= GSC_IN_YUV422_3P; break; - }; + } writel(cfg, dev->regs + GSC_IN_CON); } @@ -332,7 +332,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx) case 3: cfg |= GSC_OUT_YUV420_3P; break; - }; + } end_set: writel(cfg, dev->regs + GSC_OUT_CON); diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index e5024cf..4ef55ec 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -308,7 +308,7 @@ static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) READCHAN_BLERD) >> 10; rds = radio->registers[RDSD]; break; - }; + } /* Fill the V4L2 RDS buffer */ put_unaligned_le16(rds, &tmpbuf); diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index be076f7..62f3ede 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -446,7 +446,7 @@ static void si470x_int_in_callback(struct urb *urb) READCHAN_BLERD) >> 10; rds = radio->registers[RDSD]; break; - }; + } /* Fill the V4L2 RDS buffer */ put_unaligned_le16(rds, &tmpbuf); diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 824f191..3d7526e 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -500,7 +500,7 @@ static int af9015_read_config(struct dvb_usb_device *d) case 3: state->af9013_config[i].clock = 25000000; break; - }; + } dev_dbg(&d->udev->dev, "%s: [%d] xtal=%d set clock=%d\n", __func__, i, val, state->af9013_config[i].clock); @@ -568,7 +568,7 @@ static int af9015_read_config(struct dvb_usb_device *d) "supported, please report!\n", KBUILD_MODNAME, val); return -ENODEV; - }; + } state->af9013_config[i].tuner = val; dev_dbg(&d->udev->dev, "%s: [%d] tuner id=%d\n", diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index aabd3fc..ea27eaf 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -520,7 +520,7 @@ static int af9035_read_config(struct dvb_usb_device *d) dev_warn(&d->udev->dev, "%s: tuner id=%02x not " \ "supported, please report!", KBUILD_MODNAME, tmp); - }; + } /* tuner IF frequency */ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); -- cgit v0.10.2 From 034351ff6372c1a880ed4c5d333e430e9c83d467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Cardona?= Date: Fri, 28 Sep 2012 08:59:31 -0300 Subject: [media] ds3000: add module parameter to force firmware upload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [mchehab@redhat.com: Fix a merge conflict] Signed-off-by: RĂ©mi Cardona Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 4c8ac26..5b63908 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -30,6 +30,7 @@ #include "ds3000.h" static int debug; +static int force_fw_upload; #define dprintk(args...) \ do { \ @@ -392,11 +393,13 @@ static int ds3000_firmware_ondemand(struct dvb_frontend *fe) dprintk("%s()\n", __func__); - if (ds3000_readreg(state, 0xb2) <= 0) + ret = ds3000_readreg(state, 0xb2); + if (ret < 0) return ret; - if (state->skip_fw_load) - return 0; + if (state->skip_fw_load || !force_fw_upload) + return 0; /* Firmware already uploaded, skipping */ + /* Load firmware */ /* request the firmware, this will block until someone uploads it */ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, @@ -1306,6 +1309,9 @@ static struct dvb_frontend_ops ds3000_ops = { module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); +module_param(force_fw_upload, int, 0644); +MODULE_PARM_DESC(force_fw_upload, "Force firmware upload (default:0)"); + MODULE_DESCRIPTION("DVB Frontend module for Montage Technology " "DS3000/TS2020 hardware"); MODULE_AUTHOR("Konstantin Dimitrov"); -- cgit v0.10.2 From 78ef81f6ea9649fd09d1fafcfa0ad68763172c42 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 28 Sep 2012 11:04:21 -0300 Subject: [media] tda18271-common: hold the I2C adapter during write transfers The tda18271 datasheet says: "The image rejection calibration and RF tracking filter calibration must be launched exactly as described in the flowchart, otherwise bad calibration or even blocking of the TDA18211HD can result making it impossible to communicate via the I2C-bus." (yeah, tda18271 refers there to tda18211 - likely a typo at their datasheets) That likely explains why sometimes tda18271 stops answering. That is now happening more often on designs with drx-k chips, as the firmware is now loaded asyncrousnly there. While the above text doesn't explicitly tell that the I2C bus couldn't be used by other devices during such initialization, that seems to be a requirement there. So, let's explicitly use the I2C lock there, avoiding I2C bus share during those critical moments. Compile-tested only. Please test. Acked-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 221171e..18c77af 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -187,7 +187,8 @@ int tda18271_read_extended(struct dvb_frontend *fe) return (ret == 2 ? 0 : ret); } -int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -198,7 +199,6 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) BUG_ON((len == 0) || (idx + len > sizeof(buf))); - switch (priv->small_i2c) { case TDA18271_03_BYTE_CHUNK_INIT: max = 3; @@ -214,7 +214,19 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) max = 39; } - tda18271_i2c_gate_ctrl(fe, 1); + + /* + * If lock_i2c is true, it will take the I2C bus for tda18271 private + * usage during the entire write ops, as otherwise, bad things could + * happen. + * During device init, several write operations will happen. So, + * tda18271_init_regs controls the I2C lock directly, + * disabling lock_i2c here. + */ + if (lock_i2c) { + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + } while (len) { if (max > len) max = len; @@ -226,14 +238,17 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) msg.len = max + 1; /* write registers */ - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + ret = __i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret != 1) break; idx += max; len -= max; } - tda18271_i2c_gate_ctrl(fe, 0); + if (lock_i2c) { + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); + } if (ret != 1) tda_err("ERROR: idx = 0x%x, len = %d, " @@ -242,10 +257,16 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) return (ret == 1 ? 0 : ret); } +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + return __tda18271_write_regs(fe, idx, len, true); +} + /*---------------------------------------------------------------------*/ -int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force) +static int __tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -255,9 +276,16 @@ int tda18271_charge_pump_source(struct dvb_frontend *fe, regs[r_cp] &= ~0x20; regs[r_cp] |= ((force & 1) << 5); - return tda18271_write_regs(fe, r_cp, 1); + return __tda18271_write_regs(fe, r_cp, 1, lock_i2c); +} + +int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force) +{ + return __tda18271_charge_pump_source(fe, pll, force, true); } + int tda18271_init_regs(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -267,6 +295,13 @@ int tda18271_init_regs(struct dvb_frontend *fe) i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); + /* + * Don't let any other I2C transfer to happen at adapter during init, + * as those could cause bad things + */ + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + /* initialize registers */ switch (priv->id) { case TDA18271HDC1: @@ -352,28 +387,28 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_EB22] = 0x48; regs[R_EB23] = 0xb0; - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + __tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS, false); /* setup agc1 gain */ regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); /* setup agc2 gain */ if ((priv->id) == TDA18271HDC1) { regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); } /* image rejection calibration */ @@ -391,21 +426,21 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD2] = 0x08; regs[R_MD3] = 0x00; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); if ((priv->id) == TDA18271HDC2) { /* main pll cp source on */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1, false); msleep(1); /* main pll cp source off */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0, false); } msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted low measurement */ regs[R_EP5] = 0x85; @@ -413,11 +448,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0x70; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image low optimization completion */ /* mid-band */ @@ -428,11 +463,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x73; regs[R_MD2] = 0x1a; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted mid measurement */ regs[R_EP5] = 0x86; @@ -440,11 +475,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0xa0; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image mid optimization completion */ /* high-band */ @@ -456,30 +491,33 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x71; regs[R_MD2] = 0xcd; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted high measurement */ regs[R_EP5] = 0x87; regs[R_CD1] = 0x65; regs[R_CD2] = 0x50; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image high optimization completion */ /* return to normal mode */ regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); + __tda18271_write_regs(fe, R_EP4, 1, false); /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); + + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); return 0; } -- cgit v0.10.2 From 546196addefb2e25810964c41ce2186eba8cad4b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 29 Sep 2012 03:12:53 -0300 Subject: [media] cx25821: testing the wrong variable ->input_filename could be NULL here. The intent was to test ->_filename. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c index c8c94fb..d33fc1a 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c @@ -761,7 +761,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, } /* Default if filename is empty string */ - if (strcmp(dev->input_filename_ch2, "") == 0) { + if (strcmp(dev->_filename_ch2, "") == 0) { if (dev->_isNTSC_ch2) { dev->_filename_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? "/root/vid411.yuv" : diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 52c13e0..6759fff 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -808,7 +808,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, } /* Default if filename is empty string */ - if (strcmp(dev->input_filename, "") == 0) { + if (strcmp(dev->_filename, "") == 0) { if (dev->_isNTSC) { dev->_filename = (dev->_pixel_format == PIXEL_FRMT_411) ? -- cgit v0.10.2 From b45681a60ed52b3716f3faf79f81e55b81bc7335 Mon Sep 17 00:00:00 2001 From: Wolfgang Bail Date: Sat, 29 Sep 2012 23:49:26 -0300 Subject: [media] rc-msi-digivox-ii: Add full scan keycodes The ir-rc from my MSI DigiVox mini II Version 3 (af9015) will not work since kernel 3.2.x. sudo ir-keytable -t shows: 1348890734.303273: event MSC: scancode = 317 1348890734.303280: event key down: KEY_POWER (0x0074) 1348890734.303282: event sync 1348890734.553961: event key up: KEY_POWER (0x0074) 1348890734.553963: event sync 1348890741.303451: event MSC: scancode = 30d 1348890741.303457: event key down: KEY_DOWN (0x006c) 1348890741.303459: event sync 1348890741.553956: event key up: KEY_DOWN (0x006c) So I changed in rc-msi-digivox-ii.c { 0x0002, KEY_2 }, to { 0x0302, KEY_2 }, and so on. And now it works well. Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index c64e9e3..2fa71d0 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -22,24 +22,24 @@ #include static struct rc_map_table msi_digivox_ii[] = { - { 0x0002, KEY_2 }, - { 0x0003, KEY_UP }, /* up */ - { 0x0004, KEY_3 }, - { 0x0005, KEY_CHANNELDOWN }, - { 0x0008, KEY_5 }, - { 0x0009, KEY_0 }, - { 0x000b, KEY_8 }, - { 0x000d, KEY_DOWN }, /* down */ - { 0x0010, KEY_9 }, - { 0x0011, KEY_7 }, - { 0x0014, KEY_VOLUMEUP }, - { 0x0015, KEY_CHANNELUP }, - { 0x0016, KEY_OK }, - { 0x0017, KEY_POWER2 }, - { 0x001a, KEY_1 }, - { 0x001c, KEY_4 }, - { 0x001d, KEY_6 }, - { 0x001f, KEY_VOLUMEDOWN }, + { 0x0302, KEY_2 }, + { 0x0303, KEY_UP }, /* up */ + { 0x0304, KEY_3 }, + { 0x0305, KEY_CHANNELDOWN }, + { 0x0308, KEY_5 }, + { 0x0309, KEY_0 }, + { 0x030b, KEY_8 }, + { 0x030d, KEY_DOWN }, /* down */ + { 0x0310, KEY_9 }, + { 0x0311, KEY_7 }, + { 0x0314, KEY_VOLUMEUP }, + { 0x0315, KEY_CHANNELUP }, + { 0x0316, KEY_OK }, + { 0x0317, KEY_POWER2 }, + { 0x031a, KEY_1 }, + { 0x031c, KEY_4 }, + { 0x031d, KEY_6 }, + { 0x031f, KEY_VOLUMEDOWN }, }; static struct rc_map_list msi_digivox_ii_map = { -- cgit v0.10.2 From 8a18382c3196978164f0f6290aac98f2f6f43c00 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Mon, 1 Oct 2012 18:46:27 -0300 Subject: [media] omap3isp: Fix compilation error in ispreg.h Commit c49f34bc ("ARM: OMAP2+ Move SoC specific headers to be local to mach-omap2") moved omap34xx.h to mach-omap2. This broke omap3isp, as it includes omap34xx.h. Instead of moving omap34xx to platform_data, simply add the two definitions the driver needs and remove the include altogether. Signed-off-by: Ido Yariv Acked-by: Tony Lindgren Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index 084ea77..e2c57f3 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -27,13 +27,13 @@ #ifndef OMAP3_ISP_REG_H #define OMAP3_ISP_REG_H -#include - - #define CM_CAM_MCLK_HZ 172800000 /* Hz */ /* ISP Submodules offset */ +#define L4_34XX_BASE 0x48000000 +#define OMAP3430_ISP_BASE (L4_34XX_BASE + 0xBC000) + #define OMAP3ISP_REG_BASE OMAP3430_ISP_BASE #define OMAP3ISP_REG(offset) (OMAP3ISP_REG_BASE + (offset)) -- cgit v0.10.2 From 1b8b10cc7e6bd9bf017c58e32b1e7f632e23850d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 2 Oct 2012 02:47:58 -0300 Subject: [media] v4l2-ioctl: add blocks check for VIDIOC_SUBDEV_G/S_EDID The maximum size of an EDID is 32768 bytes, which is 32768 / 128 = 256 blocks. Return -EINVAL if blocks > 256 to ensure that the memory allocation is sane. Signed-off-by: Hans Verkuil Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 16205d9..11874c1 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2212,6 +2212,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, struct v4l2_subdev_edid *edid = parg; if (edid->blocks) { + if (edid->blocks > 256) { + ret = -EINVAL; + break; + } *user_ptr = (void __user *)edid->edid; *kernel_ptr = (void *)&edid->edid; *array_size = edid->blocks * 128; -- cgit v0.10.2 From d92462401dde1effa04a51d0a15000e6246d2a43 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 2 Oct 2012 02:47:59 -0300 Subject: [media] v4l2-ioctl: fix W=1 warnings Since the prt_names() macro is always called with an unsigned index the ((a) >= 0) condition is always true and gives a compiler warning when compiling with W=1. Rewrite the macro to avoid that warning, but cast the index to unsigned just in case it is ever called with a signed argument. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 11874c1..8f388ff 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -157,8 +157,7 @@ static const char *v4l2_memory_names[] = { [V4L2_MEMORY_OVERLAY] = "overlay", }; -#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ - arr[a] : "unknown") +#define prt_names(a, arr) (((unsigned)(a)) < ARRAY_SIZE(arr) ? arr[a] : "unknown") /* ------------------------------------------------------------------ */ /* debug help functions */ -- cgit v0.10.2 From 33eebec55c94c755f5f4785e46a72af9238999e2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 3 Oct 2012 04:28:56 -0300 Subject: [media] dvb: LNA implementation changes * use dvb property cache * implement get (thus API minor++) * PCTV 290e: 1=LNA ON, all the other values LNA OFF Also fix PCTV 290e LNA comment, it is disabled by default Hans and Mauro proposed use of cache implementation of get as they were planning to extend LNA usage for analog side too. Reported-by: Hans Verkuil Reported-by: Mauro Carvalho Chehab Signed-off-by: Antti Palosaari Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 41af996..7e92793 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -966,6 +966,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) break; } + c->lna = LNA_AUTO; + return 0; } @@ -1054,6 +1056,8 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0), + + _DTV_CMD(DTV_LNA, 0, 0), }; static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp) @@ -1440,6 +1444,10 @@ static int dtv_property_process_get(struct dvb_frontend *fe, tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d; break; + case DTV_LNA: + tvp->u.data = c->lna; + break; + default: return -EINVAL; } @@ -1731,10 +1739,6 @@ static int dtv_property_process_set(struct dvb_frontend *fe, case DTV_INTERLEAVING: c->interleaving = tvp->u.data; break; - case DTV_LNA: - if (fe->ops.set_lna) - r = fe->ops.set_lna(fe, tvp->u.data); - break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: @@ -1806,6 +1810,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe, fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; break; + case DTV_LNA: + c->lna = tvp->u.data; + if (fe->ops.set_lna) + r = fe->ops.set_lna(fe); + break; + default: return -EINVAL; } diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 44a445c..97112cd 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -303,7 +303,7 @@ struct dvb_frontend_ops { int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); - int (*set_lna)(struct dvb_frontend *, int); + int (*set_lna)(struct dvb_frontend *); /* These callbacks are for devices that implement their own * tuning algorithms, rather than a simple swzigzag @@ -391,6 +391,8 @@ struct dtv_frontend_properties { u8 atscmh_sccc_code_mode_b; u8 atscmh_sccc_code_mode_c; u8 atscmh_sccc_code_mode_d; + + u32 lna; }; struct dvb_frontend { diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 913e522..13ae821 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -574,18 +574,19 @@ static void pctv_520e_init(struct em28xx *dev) i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); }; -static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe, int val) +static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct em28xx *dev = fe->dvb->priv; #ifdef CONFIG_GPIOLIB struct em28xx_dvb *dvb = dev->dvb; int ret; unsigned long flags; - if (val) - flags = GPIOF_OUT_INIT_LOW; + if (c->lna == 1) + flags = GPIOF_OUT_INIT_HIGH; /* enable LNA */ else - flags = GPIOF_OUT_INIT_HIGH; + flags = GPIOF_OUT_INIT_LOW; /* disable LNA */ ret = gpio_request_one(dvb->lna_gpio, flags, NULL); if (ret) @@ -595,8 +596,8 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe, int val) return ret; #else - dev_warn(&dev->udev->dev, "%s: LNA control is disabled\n", - KBUILD_MODNAME); + dev_warn(&dev->udev->dev, "%s: LNA control is disabled (lna=%u)\n", + KBUILD_MODNAME, c->lna); return 0; #endif } diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h index 20e5eac..827cce7 100644 --- a/include/linux/dvb/version.h +++ b/include/linux/dvb/version.h @@ -24,6 +24,6 @@ #define _DVBVERSION_H_ #define DVB_API_VERSION 5 -#define DVB_API_VERSION_MINOR 8 +#define DVB_API_VERSION_MINOR 9 #endif /*_DVBVERSION_H_*/ -- cgit v0.10.2 From d6d022e7382343b57184c83f5fea0532be240b98 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Oct 2012 19:28:00 -0300 Subject: Revert "[media] omap3isp: Replace cpu_is_omap3630() with ISP revision check" Reverted, as requested by Laurent: I don't consider it as being ready yet, as Sakari pointed out we need to investigate whether the right fix shouldn't be at the OMAP3 clocks level instead. This reverts commit 947c48086623d9ca2207dd0434bd58458af4ba86. Requested-by: Laurent Pinchart Cc: Tony Lindgren Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 6034dca..d7aa513 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1345,7 +1345,10 @@ static int isp_enable_clocks(struct isp_device *isp) * has to be twice of what is set on OMAP3430 to get * the required value for cam_mclk */ - divisor = isp->revision == ISP_REVISION_15_0 ? 1 : 2; + if (cpu_is_omap3630()) + divisor = 1; + else + divisor = 2; r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); if (r) { @@ -2090,11 +2093,7 @@ static int __devinit isp_probe(struct platform_device *pdev) isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1"); isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2"); - /* Clocks - * - * The ISP clock tree is revision-dependent. We thus need to enable ICLK - * manually to read the revision before calling __omap3isp_get(). - */ + /* Clocks */ ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN); if (ret < 0) goto error; @@ -2103,16 +2102,6 @@ static int __devinit isp_probe(struct platform_device *pdev) if (ret < 0) goto error; - ret = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); - if (ret < 0) - goto error; - - isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); - dev_info(isp->dev, "Revision %d.%d found\n", - (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); - - clk_disable(isp->clock[ISP_CLK_CAM_ICK]); - if (__omap3isp_get(isp, false) == NULL) { ret = -ENODEV; goto error; @@ -2123,6 +2112,10 @@ static int __devinit isp_probe(struct platform_device *pdev) goto error_isp; /* Memory resources */ + isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); + dev_info(isp->dev, "Revision %d.%d found\n", + (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); + for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++) if (isp->revision == isp_res_maps[m].isp_rev) break; -- cgit v0.10.2 From 56a960bf3fedc7dcf72ae072a64ffffe584e1f0e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 9 Oct 2012 18:01:03 -0300 Subject: [media] stk1160: Add support for S-Video input In order to fully replace easycap driver with stk1160, it's also necessary to add S-Video support. A similar patch backported for v3.2 kernel has been tested by three different users. Signed-off-by: Ezequiel Garcia Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index b627408..34a26e0 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -100,12 +100,21 @@ int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value) void stk1160_select_input(struct stk1160 *dev) { + int route; static const u8 gctrl[] = { - 0x98, 0x90, 0x88, 0x80 + 0x98, 0x90, 0x88, 0x80, 0x98 }; - if (dev->ctl_input < ARRAY_SIZE(gctrl)) + if (dev->ctl_input == STK1160_SVIDEO_INPUT) + route = SAA7115_SVIDEO3; + else + route = SAA7115_COMPOSITE0; + + if (dev->ctl_input < ARRAY_SIZE(gctrl)) { + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + route, 0, 0); stk1160_write_reg(dev, STK1160_GCTRL, gctrl[dev->ctl_input]); + } } /* TODO: We should break this into pieces */ @@ -351,8 +360,6 @@ static int stk1160_probe(struct usb_interface *interface, /* i2c reset saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, - 0, 0, 0); v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); /* reset stk1160 to default values */ diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index fe6e857..6694f9e 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -419,7 +419,12 @@ static int vidioc_enum_input(struct file *file, void *priv, if (i->index > STK1160_MAX_INPUT) return -EINVAL; - sprintf(i->name, "Composite%d", i->index); + /* S-Video special handling */ + if (i->index == STK1160_SVIDEO_INPUT) + sprintf(i->name, "S-Video"); + else + sprintf(i->name, "Composite%d", i->index); + i->type = V4L2_INPUT_TYPE_CAMERA; i->std = dev->vdev.tvnorms; return 0; diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 3feba00..68c8707 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -46,7 +46,8 @@ #define STK1160_MIN_PKT_SIZE 3072 -#define STK1160_MAX_INPUT 3 +#define STK1160_MAX_INPUT 4 +#define STK1160_SVIDEO_INPUT 4 #define STK1160_I2C_TIMEOUT 100 -- cgit v0.10.2 From 1fdead8ad31d3aa833bc37739273fcde89ace93c Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sat, 6 Oct 2012 15:04:40 -0300 Subject: [media] m5mols: Add missing #include Include header that is missing after commit ab7ef22419927 "[media] m5mols: Implement .get_frame_desc subdev callback". It prevents possible build errors due to undefined SZ_1M. This header is currently included only when m5mols is compiled on arm; if build on other archs, the compilation will break. Reported-by: Jan Hoogenraad Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h index 4ab8b37..90a6c52 100644 --- a/drivers/media/i2c/m5mols/m5mols.h +++ b/drivers/media/i2c/m5mols/m5mols.h @@ -16,6 +16,7 @@ #ifndef M5MOLS_H #define M5MOLS_H +#include #include #include "m5mols_reg.h" -- cgit v0.10.2