Hi Guennadi,
thank you for your review.
On 20 February 2012 15:13, Guennadi Liakhovetski <[email protected]> wrote:
>> @@ -707,6 +732,74 @@ static void mx27_camera_emma_buf_init(struct
>> soc_camera_device *icd,
>> writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
>> }
>>
>> +static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
>> +{
>> + int dir;
>> +
>> + for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
>> + unsigned char *s = pcdev->resizing[dir].s;
>> + int len = pcdev->resizing[dir].len;
>> + unsigned int coeff[2] = {0, 0};
>> + unsigned int valid = 0;
>> + int i;
>> +
>> + if (len == 0)
>> + continue;
>> +
>> + for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) {
>> + int j;
>> +
>> + j = i > 9 ? 1 : 0;
>> + coeff[j] = (coeff[j] << BC_COEF) |
>> + (s[i] & (SZ_COEF - 1));
>
> Please, remember to indent line continuations.
Yes, sorry.
>
>> +
>> + if (i == 5 || i == 15)
>> + coeff[j] <<= 1;
>> +
>> + valid = (valid << 1) | (s[i] >> BC_COEF);
>> + }
>> +
>> + valid |= PRP_RZ_VALID_TBL_LEN(len);
>> +
>> + if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR)
>> + valid |= PRP_RZ_VALID_BILINEAR;
>> +
>> + if (pcdev->emma_prp->cfg.channel == 1) {
>
> Maybe put horizontal and vertical register addresses in an array too to
> avoid this "if?" Just an idea - if you don't think, the code would look
> nicer, just leave as is.
I don't know about that, we can't avoid the fact that the code would
look more compact but I think it would be less clear.
>> + if (dir == RESIZE_DIR_H) {
>> + writel(coeff[0], pcdev->base_emma +
>> + PRP_CH1_RZ_HORI_COEF1);
>> + writel(coeff[1], pcdev->base_emma +
>> + PRP_CH1_RZ_HORI_COEF2);
>> + writel(valid, pcdev->base_emma +
>> + PRP_CH1_RZ_HORI_VALID);
>> + } else {
>> + writel(coeff[0], pcdev->base_emma +
>> + PRP_CH1_RZ_VERT_COEF1);
>> + writel(coeff[1], pcdev->base_emma +
>> + PRP_CH1_RZ_VERT_COEF2);
>> + writel(valid, pcdev->base_emma +
>> + PRP_CH1_RZ_VERT_VALID);
>> + }
>> + } else {
>> + if (dir == RESIZE_DIR_H) {
>> + writel(coeff[0], pcdev->base_emma +
>> + PRP_CH2_RZ_HORI_COEF1);
>> + writel(coeff[1], pcdev->base_emma +
>> + PRP_CH2_RZ_HORI_COEF2);
>> + writel(valid, pcdev->base_emma +
>> + PRP_CH2_RZ_HORI_VALID);
>> + } else {
>> + writel(coeff[0], pcdev->base_emma +
>> + PRP_CH2_RZ_VERT_COEF1);
>> + writel(coeff[1], pcdev->base_emma +
>> + PRP_CH2_RZ_VERT_COEF2);
>> + writel(valid, pcdev->base_emma +
>> + PRP_CH2_RZ_VERT_VALID);
>> + }
>> + }
>> + }
>> +}
>> +
>> static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
>> {
>> struct soc_camera_device *icd = soc_camera_from_vb2q(q);
>> @@ -773,6 +866,8 @@ static int mx2_start_streaming(struct vb2_queue *q,
>> unsigned int count)
>> list_add_tail(&pcdev->buf_discard[1].queue,
>> &pcdev->discard);
>>
>> + mx2_prp_resize_commit(pcdev);
>> +
>> mx27_camera_emma_buf_init(icd, bytesperline);
>>
>> if (prp->cfg.channel == 1) {
>> @@ -1059,6 +1154,119 @@ static int mx2_camera_get_formats(struct
>> soc_camera_device *icd,
>> return formats;
>> }
>>
>> +static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
>> + struct v4l2_mbus_framefmt *mf_in,
>> + struct v4l2_pix_format *pix_out)
>> +{
>> + int num, den;
>> + unsigned long m;
>> + int i, dir;
>> +
>> + for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
>> + unsigned char *s = pcdev->resizing[dir].s;
>> + int len = 0;
>> + int in, out;
>> +
>> + if (dir == RESIZE_DIR_H) {
>> + in = mf_in->width;
>> + out = pix_out->width;
>> + } else {
>> + in = mf_in->height;
>> + out = pix_out->height;
>> + }
>> +
>> + if (in < out)
>> + return -EINVAL;
>> + else if (in == out)
>> + continue;
>> +
>> + /* Calculate ratio */
>> + m = gcd(in, out);
>> + num = in / m;
>> + den = out / m;
>> + if (num > RESIZE_NUM_MAX)
>> + return -EINVAL;
>> +
>> + if ((num >= 2 * den) && (den == 1) &&
>> + (num < 9) && (!(num & 0x01))) {
>> + int sum = 0;
>> + int j;
>> +
>> + /* Average scaling for > 2:1 ratios */
>
> ">=" rather than ">"
You are right.
>> + /* Support can be added for num >=9 and odd values */
>
> So, this is only used for downscaling by 1/2, 1/4, 1/6, and 1/8?
Yes.
>> +
>> + pcdev->resizing[dir].algo = RESIZE_ALGO_AVERAGING;
>> + len = num;
>> +
>> + for (i = 0; i < (len / 2); i++)
>> + s[i] = 8;
>> +
>> + do {
>> + for (i = 0; i < (len / 2); i++) {
>> + s[i] = s[i] >> 1;
>> + sum = 0;
>> + for (j = 0; j < (len / 2); j++)
>> + sum += s[j];
>> + if (sum == 4)
>> + break;
>> + }
>> + } while (sum != 4);
>> +
>> + for (i = (len / 2); i < len; i++)
>> + s[i] = s[len - i - 1];
>> +
>> + s[len - 1] |= SZ_COEF;
>> + } else {
>> + /* bilinear scaling for < 2:1 ratios */
>> + int v; /* overflow counter */
>> + int coeff, nxt; /* table output */
>> + int in_pos_inc = 2 * den;
>> + int out_pos = num;
>> + int out_pos_inc = 2 * num;
>> + int init_carry = num - den;
>> + int carry = init_carry;
>> +
>> + pcdev->resizing[dir].algo = RESIZE_ALGO_BILINEAR;
>> + v = den + in_pos_inc;
>> + do {
>> + coeff = v - out_pos;
>> + out_pos += out_pos_inc;
>> + carry += out_pos_inc;
>> + for (nxt = 0; v < out_pos; nxt++) {
>> + v += in_pos_inc;
>> + carry -= in_pos_inc;
>> + }
>> +
>> + if (len > RESIZE_NUM_MAX)
>> + return -EINVAL;
>> +
>> + coeff = ((coeff << BC_COEF) +
>> + (in_pos_inc >> 1)) / in_pos_inc;
>> +
>> + if (coeff >= (SZ_COEF - 1))
>> + coeff--;
>> +
>> + coeff |= SZ_COEF;
>> + s[len] = (unsigned char)coeff;
>> + len++;
>> +
>> + for (i = 1; i < nxt; i++) {
>> + if (len >= RESIZE_NUM_MAX)
>> + return -EINVAL;
>> + s[len] = 0;
>> + len++;
>> + }
>> + } while (carry != init_carry);
>> + }
>> + pcdev->resizing[dir].len = len;
>> + if (dir == RESIZE_DIR_H)
>> + mf_in->width = mf_in->width * den / num;
>> + else
>> + mf_in->height = mf_in->height * den / num;
>
> Aren't your calculations exact, so that here you can just use
> pix_out->width and pix_out->height?
Yes, they are. I can save these operations. Thank you.
>> + }
>> + return 0;
>> +}
>> +
>> static int mx2_camera_set_fmt(struct soc_camera_device *icd,
>> struct v4l2_format *f)
>> {
>> @@ -1070,6 +1278,9 @@ static int mx2_camera_set_fmt(struct soc_camera_device
>> *icd,
>> struct v4l2_mbus_framefmt mf;
>> int ret;
>>
>> + dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
>> + __func__, pix->width, pix->height);
>> +
>> xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
>> if (!xlate) {
>> dev_warn(icd->parent, "Format %x not found\n",
>> @@ -1087,6 +1298,18 @@ static int mx2_camera_set_fmt(struct
>> soc_camera_device *icd,
>> if (ret < 0 && ret != -ENOIOCTLCMD)
>> return ret;
>>
>> + /* Store width and height returned by the sensor for resizing */
>> + pcdev->s_width = mf.width;
>> + pcdev->s_height = mf.height;
>> + dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
>> + __func__, pcdev->s_width, pcdev->s_height);
>> +
>> + memset(pcdev->resizing, 0, sizeof(struct emma_prp_resize) << 1);
>
> I think, just sizeof(pcdev->resizing) will do the trick.
No problem.
>> + if (mf.width != pix->width || mf.height != pix->height) {
>> + if (mx2_emmaprp_resize(pcdev, &mf, pix) < 0)
>> + return -EINVAL;
>
> Hmmm... This looks like a regression, not an improvement - you return more
> errors now, than without this resizing support. Wouldn't it be possible to
> fall back to the current behaviour if prp resizing is impossible?
You are right. I did this for testing purposes and forgot to update it.
>> + }
>> +
>> if (mf.code != xlate->code)
>> return -EINVAL;
>>
>> @@ -1100,6 +1323,9 @@ static int mx2_camera_set_fmt(struct soc_camera_device
>> *icd,
>> pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
>> xlate->host_fmt->fourcc);
>>
>> + dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
>> + __func__, pix->width, pix->height);
>> +
>> return 0;
>> }
>>
>> @@ -1109,11 +1335,16 @@ static int mx2_camera_try_fmt(struct
>> soc_camera_device *icd,
>> struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
>> const struct soc_camera_format_xlate *xlate;
>> struct v4l2_pix_format *pix = &f->fmt.pix;
>> - struct v4l2_mbus_framefmt mf;
>> __u32 pixfmt = pix->pixelformat;
>> + struct v4l2_mbus_framefmt mf;
>
> This swap doesn't seem to be needed.
Fine, I'll fix it.
>> + struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
>> + struct mx2_camera_dev *pcdev = ici->priv;
>> unsigned int width_limit;
>> int ret;
>>
>> + dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
>> + __func__, pix->width, pix->height);
>> +
>> xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
>> if (pixfmt && !xlate) {
>> dev_warn(icd->parent, "Format %x not found\n", pixfmt);
>> @@ -1163,6 +1394,19 @@ static int mx2_camera_try_fmt(struct
>> soc_camera_device *icd,
>> if (ret < 0)
>> return ret;
>>
>> + /* Store width and height returned by the sensor for resizing */
>> + pcdev->s_width = mf.width;
>> + pcdev->s_height = mf.height;
>
> You don't need these in .try_fmt().
Right.
>> + dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
>> + __func__, pcdev->s_width, pcdev->s_height);
>> +
>> + /* If the sensor does not support image size try PrP resizing */
>> + memset(pcdev->resizing, 0, sizeof(struct emma_prp_resize) << 1);
>
> Same for sizeof()
>
>> + if (mf.width != pix->width || mf.height != pix->height) {
>> + if (mx2_emmaprp_resize(pcdev, &mf, pix) < 0)
>> + return -EINVAL;
>
> .try_fmt() really shouldn't fail.
It's the same issue as with s_fmt, I will fix it.
I'll try to send a v2 tomorrow.
Regards.
--
Javier Martin
Vista Silicon S.L.
CDTUC - FASE C - Oficina S-345
Avda de los Castros s/n
39005- Santander. Cantabria. Spain
+34 942 25 32 60
www.vista-silicon.com
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html