Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * v4l2-dv-timings - dv-timings helper functions
0004  *
0005  * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/types.h>
0010 #include <linux/kernel.h>
0011 #include <linux/errno.h>
0012 #include <linux/rational.h>
0013 #include <linux/videodev2.h>
0014 #include <linux/v4l2-dv-timings.h>
0015 #include <media/v4l2-dv-timings.h>
0016 #include <linux/math64.h>
0017 #include <linux/hdmi.h>
0018 #include <media/cec.h>
0019 
0020 MODULE_AUTHOR("Hans Verkuil");
0021 MODULE_DESCRIPTION("V4L2 DV Timings Helper Functions");
0022 MODULE_LICENSE("GPL");
0023 
0024 const struct v4l2_dv_timings v4l2_dv_timings_presets[] = {
0025     V4L2_DV_BT_CEA_640X480P59_94,
0026     V4L2_DV_BT_CEA_720X480I59_94,
0027     V4L2_DV_BT_CEA_720X480P59_94,
0028     V4L2_DV_BT_CEA_720X576I50,
0029     V4L2_DV_BT_CEA_720X576P50,
0030     V4L2_DV_BT_CEA_1280X720P24,
0031     V4L2_DV_BT_CEA_1280X720P25,
0032     V4L2_DV_BT_CEA_1280X720P30,
0033     V4L2_DV_BT_CEA_1280X720P50,
0034     V4L2_DV_BT_CEA_1280X720P60,
0035     V4L2_DV_BT_CEA_1920X1080P24,
0036     V4L2_DV_BT_CEA_1920X1080P25,
0037     V4L2_DV_BT_CEA_1920X1080P30,
0038     V4L2_DV_BT_CEA_1920X1080I50,
0039     V4L2_DV_BT_CEA_1920X1080P50,
0040     V4L2_DV_BT_CEA_1920X1080I60,
0041     V4L2_DV_BT_CEA_1920X1080P60,
0042     V4L2_DV_BT_DMT_640X350P85,
0043     V4L2_DV_BT_DMT_640X400P85,
0044     V4L2_DV_BT_DMT_720X400P85,
0045     V4L2_DV_BT_DMT_640X480P72,
0046     V4L2_DV_BT_DMT_640X480P75,
0047     V4L2_DV_BT_DMT_640X480P85,
0048     V4L2_DV_BT_DMT_800X600P56,
0049     V4L2_DV_BT_DMT_800X600P60,
0050     V4L2_DV_BT_DMT_800X600P72,
0051     V4L2_DV_BT_DMT_800X600P75,
0052     V4L2_DV_BT_DMT_800X600P85,
0053     V4L2_DV_BT_DMT_800X600P120_RB,
0054     V4L2_DV_BT_DMT_848X480P60,
0055     V4L2_DV_BT_DMT_1024X768I43,
0056     V4L2_DV_BT_DMT_1024X768P60,
0057     V4L2_DV_BT_DMT_1024X768P70,
0058     V4L2_DV_BT_DMT_1024X768P75,
0059     V4L2_DV_BT_DMT_1024X768P85,
0060     V4L2_DV_BT_DMT_1024X768P120_RB,
0061     V4L2_DV_BT_DMT_1152X864P75,
0062     V4L2_DV_BT_DMT_1280X768P60_RB,
0063     V4L2_DV_BT_DMT_1280X768P60,
0064     V4L2_DV_BT_DMT_1280X768P75,
0065     V4L2_DV_BT_DMT_1280X768P85,
0066     V4L2_DV_BT_DMT_1280X768P120_RB,
0067     V4L2_DV_BT_DMT_1280X800P60_RB,
0068     V4L2_DV_BT_DMT_1280X800P60,
0069     V4L2_DV_BT_DMT_1280X800P75,
0070     V4L2_DV_BT_DMT_1280X800P85,
0071     V4L2_DV_BT_DMT_1280X800P120_RB,
0072     V4L2_DV_BT_DMT_1280X960P60,
0073     V4L2_DV_BT_DMT_1280X960P85,
0074     V4L2_DV_BT_DMT_1280X960P120_RB,
0075     V4L2_DV_BT_DMT_1280X1024P60,
0076     V4L2_DV_BT_DMT_1280X1024P75,
0077     V4L2_DV_BT_DMT_1280X1024P85,
0078     V4L2_DV_BT_DMT_1280X1024P120_RB,
0079     V4L2_DV_BT_DMT_1360X768P60,
0080     V4L2_DV_BT_DMT_1360X768P120_RB,
0081     V4L2_DV_BT_DMT_1366X768P60,
0082     V4L2_DV_BT_DMT_1366X768P60_RB,
0083     V4L2_DV_BT_DMT_1400X1050P60_RB,
0084     V4L2_DV_BT_DMT_1400X1050P60,
0085     V4L2_DV_BT_DMT_1400X1050P75,
0086     V4L2_DV_BT_DMT_1400X1050P85,
0087     V4L2_DV_BT_DMT_1400X1050P120_RB,
0088     V4L2_DV_BT_DMT_1440X900P60_RB,
0089     V4L2_DV_BT_DMT_1440X900P60,
0090     V4L2_DV_BT_DMT_1440X900P75,
0091     V4L2_DV_BT_DMT_1440X900P85,
0092     V4L2_DV_BT_DMT_1440X900P120_RB,
0093     V4L2_DV_BT_DMT_1600X900P60_RB,
0094     V4L2_DV_BT_DMT_1600X1200P60,
0095     V4L2_DV_BT_DMT_1600X1200P65,
0096     V4L2_DV_BT_DMT_1600X1200P70,
0097     V4L2_DV_BT_DMT_1600X1200P75,
0098     V4L2_DV_BT_DMT_1600X1200P85,
0099     V4L2_DV_BT_DMT_1600X1200P120_RB,
0100     V4L2_DV_BT_DMT_1680X1050P60_RB,
0101     V4L2_DV_BT_DMT_1680X1050P60,
0102     V4L2_DV_BT_DMT_1680X1050P75,
0103     V4L2_DV_BT_DMT_1680X1050P85,
0104     V4L2_DV_BT_DMT_1680X1050P120_RB,
0105     V4L2_DV_BT_DMT_1792X1344P60,
0106     V4L2_DV_BT_DMT_1792X1344P75,
0107     V4L2_DV_BT_DMT_1792X1344P120_RB,
0108     V4L2_DV_BT_DMT_1856X1392P60,
0109     V4L2_DV_BT_DMT_1856X1392P75,
0110     V4L2_DV_BT_DMT_1856X1392P120_RB,
0111     V4L2_DV_BT_DMT_1920X1200P60_RB,
0112     V4L2_DV_BT_DMT_1920X1200P60,
0113     V4L2_DV_BT_DMT_1920X1200P75,
0114     V4L2_DV_BT_DMT_1920X1200P85,
0115     V4L2_DV_BT_DMT_1920X1200P120_RB,
0116     V4L2_DV_BT_DMT_1920X1440P60,
0117     V4L2_DV_BT_DMT_1920X1440P75,
0118     V4L2_DV_BT_DMT_1920X1440P120_RB,
0119     V4L2_DV_BT_DMT_2048X1152P60_RB,
0120     V4L2_DV_BT_DMT_2560X1600P60_RB,
0121     V4L2_DV_BT_DMT_2560X1600P60,
0122     V4L2_DV_BT_DMT_2560X1600P75,
0123     V4L2_DV_BT_DMT_2560X1600P85,
0124     V4L2_DV_BT_DMT_2560X1600P120_RB,
0125     V4L2_DV_BT_CEA_3840X2160P24,
0126     V4L2_DV_BT_CEA_3840X2160P25,
0127     V4L2_DV_BT_CEA_3840X2160P30,
0128     V4L2_DV_BT_CEA_3840X2160P50,
0129     V4L2_DV_BT_CEA_3840X2160P60,
0130     V4L2_DV_BT_CEA_4096X2160P24,
0131     V4L2_DV_BT_CEA_4096X2160P25,
0132     V4L2_DV_BT_CEA_4096X2160P30,
0133     V4L2_DV_BT_CEA_4096X2160P50,
0134     V4L2_DV_BT_DMT_4096X2160P59_94_RB,
0135     V4L2_DV_BT_CEA_4096X2160P60,
0136     { }
0137 };
0138 EXPORT_SYMBOL_GPL(v4l2_dv_timings_presets);
0139 
0140 bool v4l2_valid_dv_timings(const struct v4l2_dv_timings *t,
0141                const struct v4l2_dv_timings_cap *dvcap,
0142                v4l2_check_dv_timings_fnc fnc,
0143                void *fnc_handle)
0144 {
0145     const struct v4l2_bt_timings *bt = &t->bt;
0146     const struct v4l2_bt_timings_cap *cap = &dvcap->bt;
0147     u32 caps = cap->capabilities;
0148 
0149     if (t->type != V4L2_DV_BT_656_1120)
0150         return false;
0151     if (t->type != dvcap->type ||
0152         bt->height < cap->min_height ||
0153         bt->height > cap->max_height ||
0154         bt->width < cap->min_width ||
0155         bt->width > cap->max_width ||
0156         bt->pixelclock < cap->min_pixelclock ||
0157         bt->pixelclock > cap->max_pixelclock ||
0158         (!(caps & V4L2_DV_BT_CAP_CUSTOM) &&
0159          cap->standards && bt->standards &&
0160          !(bt->standards & cap->standards)) ||
0161         (bt->interlaced && !(caps & V4L2_DV_BT_CAP_INTERLACED)) ||
0162         (!bt->interlaced && !(caps & V4L2_DV_BT_CAP_PROGRESSIVE)))
0163         return false;
0164     return fnc == NULL || fnc(t, fnc_handle);
0165 }
0166 EXPORT_SYMBOL_GPL(v4l2_valid_dv_timings);
0167 
0168 int v4l2_enum_dv_timings_cap(struct v4l2_enum_dv_timings *t,
0169                  const struct v4l2_dv_timings_cap *cap,
0170                  v4l2_check_dv_timings_fnc fnc,
0171                  void *fnc_handle)
0172 {
0173     u32 i, idx;
0174 
0175     memset(t->reserved, 0, sizeof(t->reserved));
0176     for (i = idx = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
0177         if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap,
0178                       fnc, fnc_handle) &&
0179             idx++ == t->index) {
0180             t->timings = v4l2_dv_timings_presets[i];
0181             return 0;
0182         }
0183     }
0184     return -EINVAL;
0185 }
0186 EXPORT_SYMBOL_GPL(v4l2_enum_dv_timings_cap);
0187 
0188 bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t,
0189                   const struct v4l2_dv_timings_cap *cap,
0190                   unsigned pclock_delta,
0191                   v4l2_check_dv_timings_fnc fnc,
0192                   void *fnc_handle)
0193 {
0194     int i;
0195 
0196     if (!v4l2_valid_dv_timings(t, cap, fnc, fnc_handle))
0197         return false;
0198 
0199     for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
0200         if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap,
0201                       fnc, fnc_handle) &&
0202             v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i,
0203                       pclock_delta, false)) {
0204             u32 flags = t->bt.flags & V4L2_DV_FL_REDUCED_FPS;
0205 
0206             *t = v4l2_dv_timings_presets[i];
0207             if (can_reduce_fps(&t->bt))
0208                 t->bt.flags |= flags;
0209 
0210             return true;
0211         }
0212     }
0213     return false;
0214 }
0215 EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cap);
0216 
0217 bool v4l2_find_dv_timings_cea861_vic(struct v4l2_dv_timings *t, u8 vic)
0218 {
0219     unsigned int i;
0220 
0221     for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
0222         const struct v4l2_bt_timings *bt =
0223             &v4l2_dv_timings_presets[i].bt;
0224 
0225         if ((bt->flags & V4L2_DV_FL_HAS_CEA861_VIC) &&
0226             bt->cea861_vic == vic) {
0227             *t = v4l2_dv_timings_presets[i];
0228             return true;
0229         }
0230     }
0231     return false;
0232 }
0233 EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cea861_vic);
0234 
0235 /**
0236  * v4l2_match_dv_timings - check if two timings match
0237  * @t1: compare this v4l2_dv_timings struct...
0238  * @t2: with this struct.
0239  * @pclock_delta: the allowed pixelclock deviation.
0240  * @match_reduced_fps: if true, then fail if V4L2_DV_FL_REDUCED_FPS does not
0241  *  match.
0242  *
0243  * Compare t1 with t2 with a given margin of error for the pixelclock.
0244  */
0245 bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1,
0246                const struct v4l2_dv_timings *t2,
0247                unsigned pclock_delta, bool match_reduced_fps)
0248 {
0249     if (t1->type != t2->type || t1->type != V4L2_DV_BT_656_1120)
0250         return false;
0251     if (t1->bt.width == t2->bt.width &&
0252         t1->bt.height == t2->bt.height &&
0253         t1->bt.interlaced == t2->bt.interlaced &&
0254         t1->bt.polarities == t2->bt.polarities &&
0255         t1->bt.pixelclock >= t2->bt.pixelclock - pclock_delta &&
0256         t1->bt.pixelclock <= t2->bt.pixelclock + pclock_delta &&
0257         t1->bt.hfrontporch == t2->bt.hfrontporch &&
0258         t1->bt.hsync == t2->bt.hsync &&
0259         t1->bt.hbackporch == t2->bt.hbackporch &&
0260         t1->bt.vfrontporch == t2->bt.vfrontporch &&
0261         t1->bt.vsync == t2->bt.vsync &&
0262         t1->bt.vbackporch == t2->bt.vbackporch &&
0263         (!match_reduced_fps ||
0264          (t1->bt.flags & V4L2_DV_FL_REDUCED_FPS) ==
0265         (t2->bt.flags & V4L2_DV_FL_REDUCED_FPS)) &&
0266         (!t1->bt.interlaced ||
0267         (t1->bt.il_vfrontporch == t2->bt.il_vfrontporch &&
0268          t1->bt.il_vsync == t2->bt.il_vsync &&
0269          t1->bt.il_vbackporch == t2->bt.il_vbackporch)))
0270         return true;
0271     return false;
0272 }
0273 EXPORT_SYMBOL_GPL(v4l2_match_dv_timings);
0274 
0275 void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix,
0276                const struct v4l2_dv_timings *t, bool detailed)
0277 {
0278     const struct v4l2_bt_timings *bt = &t->bt;
0279     u32 htot, vtot;
0280     u32 fps;
0281 
0282     if (t->type != V4L2_DV_BT_656_1120)
0283         return;
0284 
0285     htot = V4L2_DV_BT_FRAME_WIDTH(bt);
0286     vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
0287     if (bt->interlaced)
0288         vtot /= 2;
0289 
0290     fps = (htot * vtot) > 0 ? div_u64((100 * (u64)bt->pixelclock),
0291                   (htot * vtot)) : 0;
0292 
0293     if (prefix == NULL)
0294         prefix = "";
0295 
0296     pr_info("%s: %s%ux%u%s%u.%02u (%ux%u)\n", dev_prefix, prefix,
0297         bt->width, bt->height, bt->interlaced ? "i" : "p",
0298         fps / 100, fps % 100, htot, vtot);
0299 
0300     if (!detailed)
0301         return;
0302 
0303     pr_info("%s: horizontal: fp = %u, %ssync = %u, bp = %u\n",
0304             dev_prefix, bt->hfrontporch,
0305             (bt->polarities & V4L2_DV_HSYNC_POS_POL) ? "+" : "-",
0306             bt->hsync, bt->hbackporch);
0307     pr_info("%s: vertical: fp = %u, %ssync = %u, bp = %u\n",
0308             dev_prefix, bt->vfrontporch,
0309             (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
0310             bt->vsync, bt->vbackporch);
0311     if (bt->interlaced)
0312         pr_info("%s: vertical bottom field: fp = %u, %ssync = %u, bp = %u\n",
0313             dev_prefix, bt->il_vfrontporch,
0314             (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
0315             bt->il_vsync, bt->il_vbackporch);
0316     pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock);
0317     pr_info("%s: flags (0x%x):%s%s%s%s%s%s%s%s%s%s\n",
0318             dev_prefix, bt->flags,
0319             (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ?
0320             " REDUCED_BLANKING" : "",
0321             ((bt->flags & V4L2_DV_FL_REDUCED_BLANKING) &&
0322              bt->vsync == 8) ? " (V2)" : "",
0323             (bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS) ?
0324             " CAN_REDUCE_FPS" : "",
0325             (bt->flags & V4L2_DV_FL_REDUCED_FPS) ?
0326             " REDUCED_FPS" : "",
0327             (bt->flags & V4L2_DV_FL_HALF_LINE) ?
0328             " HALF_LINE" : "",
0329             (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) ?
0330             " CE_VIDEO" : "",
0331             (bt->flags & V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE) ?
0332             " FIRST_FIELD_EXTRA_LINE" : "",
0333             (bt->flags & V4L2_DV_FL_HAS_PICTURE_ASPECT) ?
0334             " HAS_PICTURE_ASPECT" : "",
0335             (bt->flags & V4L2_DV_FL_HAS_CEA861_VIC) ?
0336             " HAS_CEA861_VIC" : "",
0337             (bt->flags & V4L2_DV_FL_HAS_HDMI_VIC) ?
0338             " HAS_HDMI_VIC" : "");
0339     pr_info("%s: standards (0x%x):%s%s%s%s%s\n", dev_prefix, bt->standards,
0340             (bt->standards & V4L2_DV_BT_STD_CEA861) ?  " CEA" : "",
0341             (bt->standards & V4L2_DV_BT_STD_DMT) ?  " DMT" : "",
0342             (bt->standards & V4L2_DV_BT_STD_CVT) ?  " CVT" : "",
0343             (bt->standards & V4L2_DV_BT_STD_GTF) ?  " GTF" : "",
0344             (bt->standards & V4L2_DV_BT_STD_SDI) ?  " SDI" : "");
0345     if (bt->flags & V4L2_DV_FL_HAS_PICTURE_ASPECT)
0346         pr_info("%s: picture aspect (hor:vert): %u:%u\n", dev_prefix,
0347             bt->picture_aspect.numerator,
0348             bt->picture_aspect.denominator);
0349     if (bt->flags & V4L2_DV_FL_HAS_CEA861_VIC)
0350         pr_info("%s: CEA-861 VIC: %u\n", dev_prefix, bt->cea861_vic);
0351     if (bt->flags & V4L2_DV_FL_HAS_HDMI_VIC)
0352         pr_info("%s: HDMI VIC: %u\n", dev_prefix, bt->hdmi_vic);
0353 }
0354 EXPORT_SYMBOL_GPL(v4l2_print_dv_timings);
0355 
0356 struct v4l2_fract v4l2_dv_timings_aspect_ratio(const struct v4l2_dv_timings *t)
0357 {
0358     struct v4l2_fract ratio = { 1, 1 };
0359     unsigned long n, d;
0360 
0361     if (t->type != V4L2_DV_BT_656_1120)
0362         return ratio;
0363     if (!(t->bt.flags & V4L2_DV_FL_HAS_PICTURE_ASPECT))
0364         return ratio;
0365 
0366     ratio.numerator = t->bt.width * t->bt.picture_aspect.denominator;
0367     ratio.denominator = t->bt.height * t->bt.picture_aspect.numerator;
0368 
0369     rational_best_approximation(ratio.numerator, ratio.denominator,
0370                     ratio.numerator, ratio.denominator, &n, &d);
0371     ratio.numerator = n;
0372     ratio.denominator = d;
0373     return ratio;
0374 }
0375 EXPORT_SYMBOL_GPL(v4l2_dv_timings_aspect_ratio);
0376 
0377 /** v4l2_calc_timeperframe - helper function to calculate timeperframe based
0378  *  v4l2_dv_timings fields.
0379  * @t - Timings for the video mode.
0380  *
0381  * Calculates the expected timeperframe using the pixel clock value and
0382  * horizontal/vertical measures. This means that v4l2_dv_timings structure
0383  * must be correctly and fully filled.
0384  */
0385 struct v4l2_fract v4l2_calc_timeperframe(const struct v4l2_dv_timings *t)
0386 {
0387     const struct v4l2_bt_timings *bt = &t->bt;
0388     struct v4l2_fract fps_fract = { 1, 1 };
0389     unsigned long n, d;
0390     u32 htot, vtot, fps;
0391     u64 pclk;
0392 
0393     if (t->type != V4L2_DV_BT_656_1120)
0394         return fps_fract;
0395 
0396     htot = V4L2_DV_BT_FRAME_WIDTH(bt);
0397     vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
0398     pclk = bt->pixelclock;
0399 
0400     if ((bt->flags & V4L2_DV_FL_CAN_DETECT_REDUCED_FPS) &&
0401         (bt->flags & V4L2_DV_FL_REDUCED_FPS))
0402         pclk = div_u64(pclk * 1000ULL, 1001);
0403 
0404     fps = (htot * vtot) > 0 ? div_u64((100 * pclk), (htot * vtot)) : 0;
0405     if (!fps)
0406         return fps_fract;
0407 
0408     rational_best_approximation(fps, 100, fps, 100, &n, &d);
0409 
0410     fps_fract.numerator = d;
0411     fps_fract.denominator = n;
0412     return fps_fract;
0413 }
0414 EXPORT_SYMBOL_GPL(v4l2_calc_timeperframe);
0415 
0416 /*
0417  * CVT defines
0418  * Based on Coordinated Video Timings Standard
0419  * version 1.1 September 10, 2003
0420  */
0421 
0422 #define CVT_PXL_CLK_GRAN    250000  /* pixel clock granularity */
0423 #define CVT_PXL_CLK_GRAN_RB_V2 1000 /* granularity for reduced blanking v2*/
0424 
0425 /* Normal blanking */
0426 #define CVT_MIN_V_BPORCH    7   /* lines */
0427 #define CVT_MIN_V_PORCH_RND 3   /* lines */
0428 #define CVT_MIN_VSYNC_BP    550 /* min time of vsync + back porch (us) */
0429 #define CVT_HSYNC_PERCENT       8       /* nominal hsync as percentage of line */
0430 
0431 /* Normal blanking for CVT uses GTF to calculate horizontal blanking */
0432 #define CVT_CELL_GRAN       8   /* character cell granularity */
0433 #define CVT_M           600 /* blanking formula gradient */
0434 #define CVT_C           40  /* blanking formula offset */
0435 #define CVT_K           128 /* blanking formula scaling factor */
0436 #define CVT_J           20  /* blanking formula scaling factor */
0437 #define CVT_C_PRIME (((CVT_C - CVT_J) * CVT_K / 256) + CVT_J)
0438 #define CVT_M_PRIME (CVT_K * CVT_M / 256)
0439 
0440 /* Reduced Blanking */
0441 #define CVT_RB_MIN_V_BPORCH    7       /* lines  */
0442 #define CVT_RB_V_FPORCH        3       /* lines  */
0443 #define CVT_RB_MIN_V_BLANK   460       /* us     */
0444 #define CVT_RB_H_SYNC         32       /* pixels */
0445 #define CVT_RB_H_BLANK       160       /* pixels */
0446 /* Reduce blanking Version 2 */
0447 #define CVT_RB_V2_H_BLANK     80       /* pixels */
0448 #define CVT_RB_MIN_V_FPORCH    3       /* lines  */
0449 #define CVT_RB_V2_MIN_V_FPORCH 1       /* lines  */
0450 #define CVT_RB_V_BPORCH        6       /* lines  */
0451 
0452 /** v4l2_detect_cvt - detect if the given timings follow the CVT standard
0453  * @frame_height - the total height of the frame (including blanking) in lines.
0454  * @hfreq - the horizontal frequency in Hz.
0455  * @vsync - the height of the vertical sync in lines.
0456  * @active_width - active width of image (does not include blanking). This
0457  * information is needed only in case of version 2 of reduced blanking.
0458  * In other cases, this parameter does not have any effect on timings.
0459  * @polarities - the horizontal and vertical polarities (same as struct
0460  *      v4l2_bt_timings polarities).
0461  * @interlaced - if this flag is true, it indicates interlaced format
0462  * @fmt - the resulting timings.
0463  *
0464  * This function will attempt to detect if the given values correspond to a
0465  * valid CVT format. If so, then it will return true, and fmt will be filled
0466  * in with the found CVT timings.
0467  */
0468 bool v4l2_detect_cvt(unsigned frame_height,
0469              unsigned hfreq,
0470              unsigned vsync,
0471              unsigned active_width,
0472              u32 polarities,
0473              bool interlaced,
0474              struct v4l2_dv_timings *fmt)
0475 {
0476     int  v_fp, v_bp, h_fp, h_bp, hsync;
0477     int  frame_width, image_height, image_width;
0478     bool reduced_blanking;
0479     bool rb_v2 = false;
0480     unsigned pix_clk;
0481 
0482     if (vsync < 4 || vsync > 8)
0483         return false;
0484 
0485     if (polarities == V4L2_DV_VSYNC_POS_POL)
0486         reduced_blanking = false;
0487     else if (polarities == V4L2_DV_HSYNC_POS_POL)
0488         reduced_blanking = true;
0489     else
0490         return false;
0491 
0492     if (reduced_blanking && vsync == 8)
0493         rb_v2 = true;
0494 
0495     if (rb_v2 && active_width == 0)
0496         return false;
0497 
0498     if (!rb_v2 && vsync > 7)
0499         return false;
0500 
0501     if (hfreq == 0)
0502         return false;
0503 
0504     /* Vertical */
0505     if (reduced_blanking) {
0506         if (rb_v2) {
0507             v_bp = CVT_RB_V_BPORCH;
0508             v_fp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1;
0509             v_fp -= vsync + v_bp;
0510 
0511             if (v_fp < CVT_RB_V2_MIN_V_FPORCH)
0512                 v_fp = CVT_RB_V2_MIN_V_FPORCH;
0513         } else {
0514             v_fp = CVT_RB_V_FPORCH;
0515             v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1;
0516             v_bp -= vsync + v_fp;
0517 
0518             if (v_bp < CVT_RB_MIN_V_BPORCH)
0519                 v_bp = CVT_RB_MIN_V_BPORCH;
0520         }
0521     } else {
0522         v_fp = CVT_MIN_V_PORCH_RND;
0523         v_bp = (CVT_MIN_VSYNC_BP * hfreq) / 1000000 + 1 - vsync;
0524 
0525         if (v_bp < CVT_MIN_V_BPORCH)
0526             v_bp = CVT_MIN_V_BPORCH;
0527     }
0528 
0529     if (interlaced)
0530         image_height = (frame_height - 2 * v_fp - 2 * vsync - 2 * v_bp) & ~0x1;
0531     else
0532         image_height = (frame_height - v_fp - vsync - v_bp + 1) & ~0x1;
0533 
0534     if (image_height < 0)
0535         return false;
0536 
0537     /* Aspect ratio based on vsync */
0538     switch (vsync) {
0539     case 4:
0540         image_width = (image_height * 4) / 3;
0541         break;
0542     case 5:
0543         image_width = (image_height * 16) / 9;
0544         break;
0545     case 6:
0546         image_width = (image_height * 16) / 10;
0547         break;
0548     case 7:
0549         /* special case */
0550         if (image_height == 1024)
0551             image_width = (image_height * 5) / 4;
0552         else if (image_height == 768)
0553             image_width = (image_height * 15) / 9;
0554         else
0555             return false;
0556         break;
0557     case 8:
0558         image_width = active_width;
0559         break;
0560     default:
0561         return false;
0562     }
0563 
0564     if (!rb_v2)
0565         image_width = image_width & ~7;
0566 
0567     /* Horizontal */
0568     if (reduced_blanking) {
0569         int h_blank;
0570         int clk_gran;
0571 
0572         h_blank = rb_v2 ? CVT_RB_V2_H_BLANK : CVT_RB_H_BLANK;
0573         clk_gran = rb_v2 ? CVT_PXL_CLK_GRAN_RB_V2 : CVT_PXL_CLK_GRAN;
0574 
0575         pix_clk = (image_width + h_blank) * hfreq;
0576         pix_clk = (pix_clk / clk_gran) * clk_gran;
0577 
0578         h_bp  = h_blank / 2;
0579         hsync = CVT_RB_H_SYNC;
0580         h_fp  = h_blank - h_bp - hsync;
0581 
0582         frame_width = image_width + h_blank;
0583     } else {
0584         unsigned ideal_duty_cycle_per_myriad =
0585             100 * CVT_C_PRIME - (CVT_M_PRIME * 100000) / hfreq;
0586         int h_blank;
0587 
0588         if (ideal_duty_cycle_per_myriad < 2000)
0589             ideal_duty_cycle_per_myriad = 2000;
0590 
0591         h_blank = image_width * ideal_duty_cycle_per_myriad /
0592                     (10000 - ideal_duty_cycle_per_myriad);
0593         h_blank = (h_blank / (2 * CVT_CELL_GRAN)) * 2 * CVT_CELL_GRAN;
0594 
0595         pix_clk = (image_width + h_blank) * hfreq;
0596         pix_clk = (pix_clk / CVT_PXL_CLK_GRAN) * CVT_PXL_CLK_GRAN;
0597 
0598         h_bp = h_blank / 2;
0599         frame_width = image_width + h_blank;
0600 
0601         hsync = frame_width * CVT_HSYNC_PERCENT / 100;
0602         hsync = (hsync / CVT_CELL_GRAN) * CVT_CELL_GRAN;
0603         h_fp = h_blank - hsync - h_bp;
0604     }
0605 
0606     fmt->type = V4L2_DV_BT_656_1120;
0607     fmt->bt.polarities = polarities;
0608     fmt->bt.width = image_width;
0609     fmt->bt.height = image_height;
0610     fmt->bt.hfrontporch = h_fp;
0611     fmt->bt.vfrontporch = v_fp;
0612     fmt->bt.hsync = hsync;
0613     fmt->bt.vsync = vsync;
0614     fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync;
0615 
0616     if (!interlaced) {
0617         fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync;
0618         fmt->bt.interlaced = V4L2_DV_PROGRESSIVE;
0619     } else {
0620         fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp -
0621                       2 * vsync) / 2;
0622         fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp -
0623                     2 * vsync - fmt->bt.vbackporch;
0624         fmt->bt.il_vfrontporch = v_fp;
0625         fmt->bt.il_vsync = vsync;
0626         fmt->bt.flags |= V4L2_DV_FL_HALF_LINE;
0627         fmt->bt.interlaced = V4L2_DV_INTERLACED;
0628     }
0629 
0630     fmt->bt.pixelclock = pix_clk;
0631     fmt->bt.standards = V4L2_DV_BT_STD_CVT;
0632 
0633     if (reduced_blanking)
0634         fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING;
0635 
0636     return true;
0637 }
0638 EXPORT_SYMBOL_GPL(v4l2_detect_cvt);
0639 
0640 /*
0641  * GTF defines
0642  * Based on Generalized Timing Formula Standard
0643  * Version 1.1 September 2, 1999
0644  */
0645 
0646 #define GTF_PXL_CLK_GRAN    250000  /* pixel clock granularity */
0647 
0648 #define GTF_MIN_VSYNC_BP    550 /* min time of vsync + back porch (us) */
0649 #define GTF_V_FP        1   /* vertical front porch (lines) */
0650 #define GTF_CELL_GRAN       8   /* character cell granularity */
0651 
0652 /* Default */
0653 #define GTF_D_M         600 /* blanking formula gradient */
0654 #define GTF_D_C         40  /* blanking formula offset */
0655 #define GTF_D_K         128 /* blanking formula scaling factor */
0656 #define GTF_D_J         20  /* blanking formula scaling factor */
0657 #define GTF_D_C_PRIME ((((GTF_D_C - GTF_D_J) * GTF_D_K) / 256) + GTF_D_J)
0658 #define GTF_D_M_PRIME ((GTF_D_K * GTF_D_M) / 256)
0659 
0660 /* Secondary */
0661 #define GTF_S_M         3600    /* blanking formula gradient */
0662 #define GTF_S_C         40  /* blanking formula offset */
0663 #define GTF_S_K         128 /* blanking formula scaling factor */
0664 #define GTF_S_J         35  /* blanking formula scaling factor */
0665 #define GTF_S_C_PRIME ((((GTF_S_C - GTF_S_J) * GTF_S_K) / 256) + GTF_S_J)
0666 #define GTF_S_M_PRIME ((GTF_S_K * GTF_S_M) / 256)
0667 
0668 /** v4l2_detect_gtf - detect if the given timings follow the GTF standard
0669  * @frame_height - the total height of the frame (including blanking) in lines.
0670  * @hfreq - the horizontal frequency in Hz.
0671  * @vsync - the height of the vertical sync in lines.
0672  * @polarities - the horizontal and vertical polarities (same as struct
0673  *      v4l2_bt_timings polarities).
0674  * @interlaced - if this flag is true, it indicates interlaced format
0675  * @aspect - preferred aspect ratio. GTF has no method of determining the
0676  *      aspect ratio in order to derive the image width from the
0677  *      image height, so it has to be passed explicitly. Usually
0678  *      the native screen aspect ratio is used for this. If it
0679  *      is not filled in correctly, then 16:9 will be assumed.
0680  * @fmt - the resulting timings.
0681  *
0682  * This function will attempt to detect if the given values correspond to a
0683  * valid GTF format. If so, then it will return true, and fmt will be filled
0684  * in with the found GTF timings.
0685  */
0686 bool v4l2_detect_gtf(unsigned frame_height,
0687         unsigned hfreq,
0688         unsigned vsync,
0689         u32 polarities,
0690         bool interlaced,
0691         struct v4l2_fract aspect,
0692         struct v4l2_dv_timings *fmt)
0693 {
0694     int pix_clk;
0695     int  v_fp, v_bp, h_fp, hsync;
0696     int frame_width, image_height, image_width;
0697     bool default_gtf;
0698     int h_blank;
0699 
0700     if (vsync != 3)
0701         return false;
0702 
0703     if (polarities == V4L2_DV_VSYNC_POS_POL)
0704         default_gtf = true;
0705     else if (polarities == V4L2_DV_HSYNC_POS_POL)
0706         default_gtf = false;
0707     else
0708         return false;
0709 
0710     if (hfreq == 0)
0711         return false;
0712 
0713     /* Vertical */
0714     v_fp = GTF_V_FP;
0715     v_bp = (GTF_MIN_VSYNC_BP * hfreq + 500000) / 1000000 - vsync;
0716     if (interlaced)
0717         image_height = (frame_height - 2 * v_fp - 2 * vsync - 2 * v_bp) & ~0x1;
0718     else
0719         image_height = (frame_height - v_fp - vsync - v_bp + 1) & ~0x1;
0720 
0721     if (image_height < 0)
0722         return false;
0723 
0724     if (aspect.numerator == 0 || aspect.denominator == 0) {
0725         aspect.numerator = 16;
0726         aspect.denominator = 9;
0727     }
0728     image_width = ((image_height * aspect.numerator) / aspect.denominator);
0729     image_width = (image_width + GTF_CELL_GRAN/2) & ~(GTF_CELL_GRAN - 1);
0730 
0731     /* Horizontal */
0732     if (default_gtf) {
0733         u64 num;
0734         u32 den;
0735 
0736         num = ((image_width * GTF_D_C_PRIME * (u64)hfreq) -
0737               ((u64)image_width * GTF_D_M_PRIME * 1000));
0738         den = (hfreq * (100 - GTF_D_C_PRIME) + GTF_D_M_PRIME * 1000) *
0739               (2 * GTF_CELL_GRAN);
0740         h_blank = div_u64((num + (den >> 1)), den);
0741         h_blank *= (2 * GTF_CELL_GRAN);
0742     } else {
0743         u64 num;
0744         u32 den;
0745 
0746         num = ((image_width * GTF_S_C_PRIME * (u64)hfreq) -
0747               ((u64)image_width * GTF_S_M_PRIME * 1000));
0748         den = (hfreq * (100 - GTF_S_C_PRIME) + GTF_S_M_PRIME * 1000) *
0749               (2 * GTF_CELL_GRAN);
0750         h_blank = div_u64((num + (den >> 1)), den);
0751         h_blank *= (2 * GTF_CELL_GRAN);
0752     }
0753 
0754     frame_width = image_width + h_blank;
0755 
0756     pix_clk = (image_width + h_blank) * hfreq;
0757     pix_clk = pix_clk / GTF_PXL_CLK_GRAN * GTF_PXL_CLK_GRAN;
0758 
0759     hsync = (frame_width * 8 + 50) / 100;
0760     hsync = DIV_ROUND_CLOSEST(hsync, GTF_CELL_GRAN) * GTF_CELL_GRAN;
0761 
0762     h_fp = h_blank / 2 - hsync;
0763 
0764     fmt->type = V4L2_DV_BT_656_1120;
0765     fmt->bt.polarities = polarities;
0766     fmt->bt.width = image_width;
0767     fmt->bt.height = image_height;
0768     fmt->bt.hfrontporch = h_fp;
0769     fmt->bt.vfrontporch = v_fp;
0770     fmt->bt.hsync = hsync;
0771     fmt->bt.vsync = vsync;
0772     fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync;
0773 
0774     if (!interlaced) {
0775         fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync;
0776         fmt->bt.interlaced = V4L2_DV_PROGRESSIVE;
0777     } else {
0778         fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp -
0779                       2 * vsync) / 2;
0780         fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp -
0781                     2 * vsync - fmt->bt.vbackporch;
0782         fmt->bt.il_vfrontporch = v_fp;
0783         fmt->bt.il_vsync = vsync;
0784         fmt->bt.flags |= V4L2_DV_FL_HALF_LINE;
0785         fmt->bt.interlaced = V4L2_DV_INTERLACED;
0786     }
0787 
0788     fmt->bt.pixelclock = pix_clk;
0789     fmt->bt.standards = V4L2_DV_BT_STD_GTF;
0790 
0791     if (!default_gtf)
0792         fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING;
0793 
0794     return true;
0795 }
0796 EXPORT_SYMBOL_GPL(v4l2_detect_gtf);
0797 
0798 /** v4l2_calc_aspect_ratio - calculate the aspect ratio based on bytes
0799  *  0x15 and 0x16 from the EDID.
0800  * @hor_landscape - byte 0x15 from the EDID.
0801  * @vert_portrait - byte 0x16 from the EDID.
0802  *
0803  * Determines the aspect ratio from the EDID.
0804  * See VESA Enhanced EDID standard, release A, rev 2, section 3.6.2:
0805  * "Horizontal and Vertical Screen Size or Aspect Ratio"
0806  */
0807 struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait)
0808 {
0809     struct v4l2_fract aspect = { 16, 9 };
0810     u8 ratio;
0811 
0812     /* Nothing filled in, fallback to 16:9 */
0813     if (!hor_landscape && !vert_portrait)
0814         return aspect;
0815     /* Both filled in, so they are interpreted as the screen size in cm */
0816     if (hor_landscape && vert_portrait) {
0817         aspect.numerator = hor_landscape;
0818         aspect.denominator = vert_portrait;
0819         return aspect;
0820     }
0821     /* Only one is filled in, so interpret them as a ratio:
0822        (val + 99) / 100 */
0823     ratio = hor_landscape | vert_portrait;
0824     /* Change some rounded values into the exact aspect ratio */
0825     if (ratio == 79) {
0826         aspect.numerator = 16;
0827         aspect.denominator = 9;
0828     } else if (ratio == 34) {
0829         aspect.numerator = 4;
0830         aspect.denominator = 3;
0831     } else if (ratio == 68) {
0832         aspect.numerator = 15;
0833         aspect.denominator = 9;
0834     } else {
0835         aspect.numerator = hor_landscape + 99;
0836         aspect.denominator = 100;
0837     }
0838     if (hor_landscape)
0839         return aspect;
0840     /* The aspect ratio is for portrait, so swap numerator and denominator */
0841     swap(aspect.denominator, aspect.numerator);
0842     return aspect;
0843 }
0844 EXPORT_SYMBOL_GPL(v4l2_calc_aspect_ratio);
0845 
0846 /** v4l2_hdmi_rx_colorimetry - determine HDMI colorimetry information
0847  *  based on various InfoFrames.
0848  * @avi: the AVI InfoFrame
0849  * @hdmi: the HDMI Vendor InfoFrame, may be NULL
0850  * @height: the frame height
0851  *
0852  * Determines the HDMI colorimetry information, i.e. how the HDMI
0853  * pixel color data should be interpreted.
0854  *
0855  * Note that some of the newer features (DCI-P3, HDR) are not yet
0856  * implemented: the hdmi.h header needs to be updated to the HDMI 2.0
0857  * and CTA-861-G standards.
0858  */
0859 struct v4l2_hdmi_colorimetry
0860 v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
0861              const struct hdmi_vendor_infoframe *hdmi,
0862              unsigned int height)
0863 {
0864     struct v4l2_hdmi_colorimetry c = {
0865         V4L2_COLORSPACE_SRGB,
0866         V4L2_YCBCR_ENC_DEFAULT,
0867         V4L2_QUANTIZATION_FULL_RANGE,
0868         V4L2_XFER_FUNC_SRGB
0869     };
0870     bool is_ce = avi->video_code || (hdmi && hdmi->vic);
0871     bool is_sdtv = height <= 576;
0872     bool default_is_lim_range_rgb = avi->video_code > 1;
0873 
0874     switch (avi->colorspace) {
0875     case HDMI_COLORSPACE_RGB:
0876         /* RGB pixel encoding */
0877         switch (avi->colorimetry) {
0878         case HDMI_COLORIMETRY_EXTENDED:
0879             switch (avi->extended_colorimetry) {
0880             case HDMI_EXTENDED_COLORIMETRY_OPRGB:
0881                 c.colorspace = V4L2_COLORSPACE_OPRGB;
0882                 c.xfer_func = V4L2_XFER_FUNC_OPRGB;
0883                 break;
0884             case HDMI_EXTENDED_COLORIMETRY_BT2020:
0885                 c.colorspace = V4L2_COLORSPACE_BT2020;
0886                 c.xfer_func = V4L2_XFER_FUNC_709;
0887                 break;
0888             default:
0889                 break;
0890             }
0891             break;
0892         default:
0893             break;
0894         }
0895         switch (avi->quantization_range) {
0896         case HDMI_QUANTIZATION_RANGE_LIMITED:
0897             c.quantization = V4L2_QUANTIZATION_LIM_RANGE;
0898             break;
0899         case HDMI_QUANTIZATION_RANGE_FULL:
0900             break;
0901         default:
0902             if (default_is_lim_range_rgb)
0903                 c.quantization = V4L2_QUANTIZATION_LIM_RANGE;
0904             break;
0905         }
0906         break;
0907 
0908     default:
0909         /* YCbCr pixel encoding */
0910         c.quantization = V4L2_QUANTIZATION_LIM_RANGE;
0911         switch (avi->colorimetry) {
0912         case HDMI_COLORIMETRY_NONE:
0913             if (!is_ce)
0914                 break;
0915             if (is_sdtv) {
0916                 c.colorspace = V4L2_COLORSPACE_SMPTE170M;
0917                 c.ycbcr_enc = V4L2_YCBCR_ENC_601;
0918             } else {
0919                 c.colorspace = V4L2_COLORSPACE_REC709;
0920                 c.ycbcr_enc = V4L2_YCBCR_ENC_709;
0921             }
0922             c.xfer_func = V4L2_XFER_FUNC_709;
0923             break;
0924         case HDMI_COLORIMETRY_ITU_601:
0925             c.colorspace = V4L2_COLORSPACE_SMPTE170M;
0926             c.ycbcr_enc = V4L2_YCBCR_ENC_601;
0927             c.xfer_func = V4L2_XFER_FUNC_709;
0928             break;
0929         case HDMI_COLORIMETRY_ITU_709:
0930             c.colorspace = V4L2_COLORSPACE_REC709;
0931             c.ycbcr_enc = V4L2_YCBCR_ENC_709;
0932             c.xfer_func = V4L2_XFER_FUNC_709;
0933             break;
0934         case HDMI_COLORIMETRY_EXTENDED:
0935             switch (avi->extended_colorimetry) {
0936             case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
0937                 c.colorspace = V4L2_COLORSPACE_REC709;
0938                 c.ycbcr_enc = V4L2_YCBCR_ENC_XV709;
0939                 c.xfer_func = V4L2_XFER_FUNC_709;
0940                 break;
0941             case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
0942                 c.colorspace = V4L2_COLORSPACE_REC709;
0943                 c.ycbcr_enc = V4L2_YCBCR_ENC_XV601;
0944                 c.xfer_func = V4L2_XFER_FUNC_709;
0945                 break;
0946             case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
0947                 c.colorspace = V4L2_COLORSPACE_SRGB;
0948                 c.ycbcr_enc = V4L2_YCBCR_ENC_601;
0949                 c.xfer_func = V4L2_XFER_FUNC_SRGB;
0950                 break;
0951             case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
0952                 c.colorspace = V4L2_COLORSPACE_OPRGB;
0953                 c.ycbcr_enc = V4L2_YCBCR_ENC_601;
0954                 c.xfer_func = V4L2_XFER_FUNC_OPRGB;
0955                 break;
0956             case HDMI_EXTENDED_COLORIMETRY_BT2020:
0957                 c.colorspace = V4L2_COLORSPACE_BT2020;
0958                 c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
0959                 c.xfer_func = V4L2_XFER_FUNC_709;
0960                 break;
0961             case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
0962                 c.colorspace = V4L2_COLORSPACE_BT2020;
0963                 c.ycbcr_enc = V4L2_YCBCR_ENC_BT2020_CONST_LUM;
0964                 c.xfer_func = V4L2_XFER_FUNC_709;
0965                 break;
0966             default: /* fall back to ITU_709 */
0967                 c.colorspace = V4L2_COLORSPACE_REC709;
0968                 c.ycbcr_enc = V4L2_YCBCR_ENC_709;
0969                 c.xfer_func = V4L2_XFER_FUNC_709;
0970                 break;
0971             }
0972             break;
0973         default:
0974             break;
0975         }
0976         /*
0977          * YCC Quantization Range signaling is more-or-less broken,
0978          * let's just ignore this.
0979          */
0980         break;
0981     }
0982     return c;
0983 }
0984 EXPORT_SYMBOL_GPL(v4l2_hdmi_rx_colorimetry);
0985 
0986 /**
0987  * v4l2_get_edid_phys_addr() - find and return the physical address
0988  *
0989  * @edid:   pointer to the EDID data
0990  * @size:   size in bytes of the EDID data
0991  * @offset: If not %NULL then the location of the physical address
0992  *      bytes in the EDID will be returned here. This is set to 0
0993  *      if there is no physical address found.
0994  *
0995  * Return: the physical address or CEC_PHYS_ADDR_INVALID if there is none.
0996  */
0997 u16 v4l2_get_edid_phys_addr(const u8 *edid, unsigned int size,
0998                 unsigned int *offset)
0999 {
1000     unsigned int loc = cec_get_edid_spa_location(edid, size);
1001 
1002     if (offset)
1003         *offset = loc;
1004     if (loc == 0)
1005         return CEC_PHYS_ADDR_INVALID;
1006     return (edid[loc] << 8) | edid[loc + 1];
1007 }
1008 EXPORT_SYMBOL_GPL(v4l2_get_edid_phys_addr);
1009 
1010 /**
1011  * v4l2_set_edid_phys_addr() - find and set the physical address
1012  *
1013  * @edid:   pointer to the EDID data
1014  * @size:   size in bytes of the EDID data
1015  * @phys_addr:  the new physical address
1016  *
1017  * This function finds the location of the physical address in the EDID
1018  * and fills in the given physical address and updates the checksum
1019  * at the end of the EDID block. It does nothing if the EDID doesn't
1020  * contain a physical address.
1021  */
1022 void v4l2_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr)
1023 {
1024     unsigned int loc = cec_get_edid_spa_location(edid, size);
1025     u8 sum = 0;
1026     unsigned int i;
1027 
1028     if (loc == 0)
1029         return;
1030     edid[loc] = phys_addr >> 8;
1031     edid[loc + 1] = phys_addr & 0xff;
1032     loc &= ~0x7f;
1033 
1034     /* update the checksum */
1035     for (i = loc; i < loc + 127; i++)
1036         sum += edid[i];
1037     edid[i] = 256 - sum;
1038 }
1039 EXPORT_SYMBOL_GPL(v4l2_set_edid_phys_addr);
1040 
1041 /**
1042  * v4l2_phys_addr_for_input() - calculate the PA for an input
1043  *
1044  * @phys_addr:  the physical address of the parent
1045  * @input:  the number of the input port, must be between 1 and 15
1046  *
1047  * This function calculates a new physical address based on the input
1048  * port number. For example:
1049  *
1050  * PA = 0.0.0.0 and input = 2 becomes 2.0.0.0
1051  *
1052  * PA = 3.0.0.0 and input = 1 becomes 3.1.0.0
1053  *
1054  * PA = 3.2.1.0 and input = 5 becomes 3.2.1.5
1055  *
1056  * PA = 3.2.1.3 and input = 5 becomes f.f.f.f since it maxed out the depth.
1057  *
1058  * Return: the new physical address or CEC_PHYS_ADDR_INVALID.
1059  */
1060 u16 v4l2_phys_addr_for_input(u16 phys_addr, u8 input)
1061 {
1062     /* Check if input is sane */
1063     if (WARN_ON(input == 0 || input > 0xf))
1064         return CEC_PHYS_ADDR_INVALID;
1065 
1066     if (phys_addr == 0)
1067         return input << 12;
1068 
1069     if ((phys_addr & 0x0fff) == 0)
1070         return phys_addr | (input << 8);
1071 
1072     if ((phys_addr & 0x00ff) == 0)
1073         return phys_addr | (input << 4);
1074 
1075     if ((phys_addr & 0x000f) == 0)
1076         return phys_addr | input;
1077 
1078     /*
1079      * All nibbles are used so no valid physical addresses can be assigned
1080      * to the input.
1081      */
1082     return CEC_PHYS_ADDR_INVALID;
1083 }
1084 EXPORT_SYMBOL_GPL(v4l2_phys_addr_for_input);
1085 
1086 /**
1087  * v4l2_phys_addr_validate() - validate a physical address from an EDID
1088  *
1089  * @phys_addr:  the physical address to validate
1090  * @parent: if not %NULL, then this is filled with the parents PA.
1091  * @port:   if not %NULL, then this is filled with the input port.
1092  *
1093  * This validates a physical address as read from an EDID. If the
1094  * PA is invalid (such as 1.0.1.0 since '0' is only allowed at the end),
1095  * then it will return -EINVAL.
1096  *
1097  * The parent PA is passed into %parent and the input port is passed into
1098  * %port. For example:
1099  *
1100  * PA = 0.0.0.0: has parent 0.0.0.0 and input port 0.
1101  *
1102  * PA = 1.0.0.0: has parent 0.0.0.0 and input port 1.
1103  *
1104  * PA = 3.2.0.0: has parent 3.0.0.0 and input port 2.
1105  *
1106  * PA = f.f.f.f: has parent f.f.f.f and input port 0.
1107  *
1108  * Return: 0 if the PA is valid, -EINVAL if not.
1109  */
1110 int v4l2_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
1111 {
1112     int i;
1113 
1114     if (parent)
1115         *parent = phys_addr;
1116     if (port)
1117         *port = 0;
1118     if (phys_addr == CEC_PHYS_ADDR_INVALID)
1119         return 0;
1120     for (i = 0; i < 16; i += 4)
1121         if (phys_addr & (0xf << i))
1122             break;
1123     if (i == 16)
1124         return 0;
1125     if (parent)
1126         *parent = phys_addr & (0xfff0 << i);
1127     if (port)
1128         *port = (phys_addr >> i) & 0xf;
1129     for (i += 4; i < 16; i += 4)
1130         if ((phys_addr & (0xf << i)) == 0)
1131             return -EINVAL;
1132     return 0;
1133 }
1134 EXPORT_SYMBOL_GPL(v4l2_phys_addr_validate);