hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/gpu/drm/drm_modes.c
....@@ -30,14 +30,18 @@
3030 * authorization from the copyright holder(s) and author(s).
3131 */
3232
33
+#include <linux/ctype.h>
3334 #include <linux/list.h>
3435 #include <linux/list_sort.h>
3536 #include <linux/export.h>
36
-#include <drm/drmP.h>
37
-#include <drm/drm_crtc.h>
37
+
3838 #include <video/of_videomode.h>
3939 #include <video/videomode.h>
40
+
41
+#include <drm/drm_crtc.h>
42
+#include <drm/drm_device.h>
4043 #include <drm/drm_modes.h>
44
+#include <drm/drm_print.h>
4145
4246 #include "drm_crtc_internal.h"
4347
....@@ -71,11 +75,6 @@
7175 if (!nmode)
7276 return NULL;
7377
74
- if (drm_mode_object_add(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
75
- kfree(nmode);
76
- return NULL;
77
- }
78
-
7978 return nmode;
8079 }
8180 EXPORT_SYMBOL(drm_mode_create);
....@@ -91,8 +90,6 @@
9190 {
9291 if (!mode)
9392 return;
94
-
95
- drm_mode_object_unregister(dev, &mode->base);
9693
9794 kfree(mode);
9895 }
....@@ -160,6 +157,9 @@
160157 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
161158 int interlace;
162159 u64 tmp;
160
+
161
+ if (!hdisplay || !vdisplay)
162
+ return NULL;
163163
164164 /* allocate the drm_display_mode structure. If failure, we will
165165 * return directly
....@@ -396,6 +396,9 @@
396396 int hsync, hfront_porch, vodd_front_porch_lines;
397397 unsigned int tmp1, tmp2;
398398
399
+ if (!hdisplay || !vdisplay)
400
+ return NULL;
401
+
399402 drm_mode = drm_mode_create(dev);
400403 if (!drm_mode)
401404 return NULL;
....@@ -545,7 +548,7 @@
545548 * Generalized Timing Formula is derived from:
546549 *
547550 * GTF Spreadsheet by Andy Morrish (1/5/97)
548
- * available at http://www.vesa.org
551
+ * available at https://www.vesa.org
549552 *
550553 * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
551554 * What I have done is to translate it by using integer calculation.
....@@ -663,22 +666,22 @@
663666 * @bus_flags: information about pixelclk, sync and DE polarity will be stored
664667 * here
665668 *
666
- * Sets DRM_BUS_FLAG_DE_(LOW|HIGH), DRM_BUS_FLAG_PIXDATA_(POS|NEG)EDGE and
667
- * DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS
669
+ * Sets DRM_BUS_FLAG_DE_(LOW|HIGH), DRM_BUS_FLAG_PIXDATA_DRIVE_(POS|NEG)EDGE
670
+ * and DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS
668671 * found in @vm
669672 */
670673 void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
671674 {
672675 *bus_flags = 0;
673676 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
674
- *bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
677
+ *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
675678 if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
676
- *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
679
+ *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
677680
678681 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
679
- *bus_flags |= DRM_BUS_FLAG_SYNC_POSEDGE;
682
+ *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
680683 if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE)
681
- *bus_flags |= DRM_BUS_FLAG_SYNC_NEGEDGE;
684
+ *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
682685
683686 if (vm->flags & DISPLAY_FLAGS_DE_LOW)
684687 *bus_flags |= DRM_BUS_FLAG_DE_LOW;
....@@ -717,8 +720,8 @@
717720 if (bus_flags)
718721 drm_bus_flags_from_videomode(&vm, bus_flags);
719722
720
- pr_debug("%pOF: got %dx%d display mode from %s\n",
721
- np, vm.hactive, vm.vactive, np->name);
723
+ pr_debug("%pOF: got %dx%d display mode\n",
724
+ np, vm.hactive, vm.vactive);
722725 drm_mode_debug_printmodeline(dmode);
723726
724727 return 0;
....@@ -745,32 +748,6 @@
745748 EXPORT_SYMBOL(drm_mode_set_name);
746749
747750 /**
748
- * drm_mode_hsync - get the hsync of a mode
749
- * @mode: mode
750
- *
751
- * Returns:
752
- * @modes's hsync rate in kHz, rounded to the nearest integer. Calculates the
753
- * value first if it is not yet set.
754
- */
755
-int drm_mode_hsync(const struct drm_display_mode *mode)
756
-{
757
- unsigned int calc_val;
758
-
759
- if (mode->hsync)
760
- return mode->hsync;
761
-
762
- if (mode->htotal <= 0)
763
- return 0;
764
-
765
- calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */
766
- calc_val += 500; /* round to 1000Hz */
767
- calc_val /= 1000; /* truncate to kHz */
768
-
769
- return calc_val;
770
-}
771
-EXPORT_SYMBOL(drm_mode_hsync);
772
-
773
-/**
774751 * drm_mode_vrefresh - get the vrefresh of a mode
775752 * @mode: mode
776753 *
....@@ -780,26 +757,22 @@
780757 */
781758 int drm_mode_vrefresh(const struct drm_display_mode *mode)
782759 {
783
- int refresh = 0;
760
+ unsigned int num, den;
784761
785
- if (mode->vrefresh > 0)
786
- refresh = mode->vrefresh;
787
- else if (mode->htotal > 0 && mode->vtotal > 0) {
788
- unsigned int num, den;
762
+ if (mode->htotal == 0 || mode->vtotal == 0)
763
+ return 0;
789764
790
- num = mode->clock * 1000;
791
- den = mode->htotal * mode->vtotal;
765
+ num = mode->clock;
766
+ den = mode->htotal * mode->vtotal;
792767
793
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
794
- num *= 2;
795
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
796
- den *= 2;
797
- if (mode->vscan > 1)
798
- den *= mode->vscan;
768
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
769
+ num *= 2;
770
+ if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
771
+ den *= 2;
772
+ if (mode->vscan > 1)
773
+ den *= mode->vscan;
799774
800
- refresh = DIV_ROUND_CLOSEST(num, den);
801
- }
802
- return refresh;
775
+ return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(num, 1000), den);
803776 }
804777 EXPORT_SYMBOL(drm_mode_vrefresh);
805778
....@@ -912,11 +885,9 @@
912885 */
913886 void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
914887 {
915
- int id = dst->base.id;
916888 struct list_head head = dst->head;
917889
918890 *dst = *src;
919
- dst->base.id = id;
920891 dst->head = head;
921892 }
922893 EXPORT_SYMBOL(drm_mode_copy);
....@@ -1282,7 +1253,7 @@
12821253 * @verbose: be verbose about it
12831254 *
12841255 * This helper function can be used to prune a display mode list after
1285
- * validation has been completed. All modes who's status is not MODE_OK will be
1256
+ * validation has been completed. All modes whose status is not MODE_OK will be
12861257 * removed from the list, and if @verbose the status code and mode name is also
12871258 * printed to dmesg.
12881259 */
....@@ -1333,7 +1304,7 @@
13331304 if (diff)
13341305 return diff;
13351306
1336
- diff = b->vrefresh - a->vrefresh;
1307
+ diff = drm_mode_vrefresh(b) - drm_mode_vrefresh(a);
13371308 if (diff)
13381309 return diff;
13391310
....@@ -1415,6 +1386,305 @@
14151386 }
14161387 EXPORT_SYMBOL(drm_connector_list_update);
14171388
1389
+static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
1390
+ struct drm_cmdline_mode *mode)
1391
+{
1392
+ unsigned int bpp;
1393
+
1394
+ if (str[0] != '-')
1395
+ return -EINVAL;
1396
+
1397
+ str++;
1398
+ bpp = simple_strtol(str, end_ptr, 10);
1399
+ if (*end_ptr == str)
1400
+ return -EINVAL;
1401
+
1402
+ mode->bpp = bpp;
1403
+ mode->bpp_specified = true;
1404
+
1405
+ return 0;
1406
+}
1407
+
1408
+static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
1409
+ struct drm_cmdline_mode *mode)
1410
+{
1411
+ unsigned int refresh;
1412
+
1413
+ if (str[0] != '@')
1414
+ return -EINVAL;
1415
+
1416
+ str++;
1417
+ refresh = simple_strtol(str, end_ptr, 10);
1418
+ if (*end_ptr == str)
1419
+ return -EINVAL;
1420
+
1421
+ mode->refresh = refresh;
1422
+ mode->refresh_specified = true;
1423
+
1424
+ return 0;
1425
+}
1426
+
1427
+static int drm_mode_parse_cmdline_extra(const char *str, int length,
1428
+ bool freestanding,
1429
+ const struct drm_connector *connector,
1430
+ struct drm_cmdline_mode *mode)
1431
+{
1432
+ int i;
1433
+
1434
+ for (i = 0; i < length; i++) {
1435
+ switch (str[i]) {
1436
+ case 'i':
1437
+ if (freestanding)
1438
+ return -EINVAL;
1439
+
1440
+ mode->interlace = true;
1441
+ break;
1442
+ case 'm':
1443
+ if (freestanding)
1444
+ return -EINVAL;
1445
+
1446
+ mode->margins = true;
1447
+ break;
1448
+ case 'D':
1449
+ if (mode->force != DRM_FORCE_UNSPECIFIED)
1450
+ return -EINVAL;
1451
+
1452
+ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1453
+ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1454
+ mode->force = DRM_FORCE_ON;
1455
+ else
1456
+ mode->force = DRM_FORCE_ON_DIGITAL;
1457
+ break;
1458
+ case 'd':
1459
+ if (mode->force != DRM_FORCE_UNSPECIFIED)
1460
+ return -EINVAL;
1461
+
1462
+ mode->force = DRM_FORCE_OFF;
1463
+ break;
1464
+ case 'e':
1465
+ if (mode->force != DRM_FORCE_UNSPECIFIED)
1466
+ return -EINVAL;
1467
+
1468
+ mode->force = DRM_FORCE_ON;
1469
+ break;
1470
+ default:
1471
+ return -EINVAL;
1472
+ }
1473
+ }
1474
+
1475
+ return 0;
1476
+}
1477
+
1478
+static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
1479
+ bool extras,
1480
+ const struct drm_connector *connector,
1481
+ struct drm_cmdline_mode *mode)
1482
+{
1483
+ const char *str_start = str;
1484
+ bool rb = false, cvt = false;
1485
+ int xres = 0, yres = 0;
1486
+ int remaining, i;
1487
+ char *end_ptr;
1488
+
1489
+ xres = simple_strtol(str, &end_ptr, 10);
1490
+ if (end_ptr == str)
1491
+ return -EINVAL;
1492
+
1493
+ if (end_ptr[0] != 'x')
1494
+ return -EINVAL;
1495
+ end_ptr++;
1496
+
1497
+ str = end_ptr;
1498
+ yres = simple_strtol(str, &end_ptr, 10);
1499
+ if (end_ptr == str)
1500
+ return -EINVAL;
1501
+
1502
+ remaining = length - (end_ptr - str_start);
1503
+ if (remaining < 0)
1504
+ return -EINVAL;
1505
+
1506
+ for (i = 0; i < remaining; i++) {
1507
+ switch (end_ptr[i]) {
1508
+ case 'M':
1509
+ cvt = true;
1510
+ break;
1511
+ case 'R':
1512
+ rb = true;
1513
+ break;
1514
+ default:
1515
+ /*
1516
+ * Try to pass that to our extras parsing
1517
+ * function to handle the case where the
1518
+ * extras are directly after the resolution
1519
+ */
1520
+ if (extras) {
1521
+ int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
1522
+ 1,
1523
+ false,
1524
+ connector,
1525
+ mode);
1526
+ if (ret)
1527
+ return ret;
1528
+ } else {
1529
+ return -EINVAL;
1530
+ }
1531
+ }
1532
+ }
1533
+
1534
+ mode->xres = xres;
1535
+ mode->yres = yres;
1536
+ mode->cvt = cvt;
1537
+ mode->rb = rb;
1538
+
1539
+ return 0;
1540
+}
1541
+
1542
+static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
1543
+{
1544
+ const char *value;
1545
+ char *endp;
1546
+
1547
+ /*
1548
+ * delim must point to the '=', otherwise it is a syntax error and
1549
+ * if delim points to the terminating zero, then delim + 1 wil point
1550
+ * past the end of the string.
1551
+ */
1552
+ if (*delim != '=')
1553
+ return -EINVAL;
1554
+
1555
+ value = delim + 1;
1556
+ *int_ret = simple_strtol(value, &endp, 10);
1557
+
1558
+ /* Make sure we have parsed something */
1559
+ if (endp == value)
1560
+ return -EINVAL;
1561
+
1562
+ return 0;
1563
+}
1564
+
1565
+static int drm_mode_parse_panel_orientation(const char *delim,
1566
+ struct drm_cmdline_mode *mode)
1567
+{
1568
+ const char *value;
1569
+
1570
+ if (*delim != '=')
1571
+ return -EINVAL;
1572
+
1573
+ value = delim + 1;
1574
+ delim = strchr(value, ',');
1575
+ if (!delim)
1576
+ delim = value + strlen(value);
1577
+
1578
+ if (!strncmp(value, "normal", delim - value))
1579
+ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
1580
+ else if (!strncmp(value, "upside_down", delim - value))
1581
+ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
1582
+ else if (!strncmp(value, "left_side_up", delim - value))
1583
+ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
1584
+ else if (!strncmp(value, "right_side_up", delim - value))
1585
+ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
1586
+ else
1587
+ return -EINVAL;
1588
+
1589
+ return 0;
1590
+}
1591
+
1592
+static int drm_mode_parse_cmdline_options(const char *str,
1593
+ bool freestanding,
1594
+ const struct drm_connector *connector,
1595
+ struct drm_cmdline_mode *mode)
1596
+{
1597
+ unsigned int deg, margin, rotation = 0;
1598
+ const char *delim, *option, *sep;
1599
+
1600
+ option = str;
1601
+ do {
1602
+ delim = strchr(option, '=');
1603
+ if (!delim) {
1604
+ delim = strchr(option, ',');
1605
+
1606
+ if (!delim)
1607
+ delim = option + strlen(option);
1608
+ }
1609
+
1610
+ if (!strncmp(option, "rotate", delim - option)) {
1611
+ if (drm_mode_parse_cmdline_int(delim, &deg))
1612
+ return -EINVAL;
1613
+
1614
+ switch (deg) {
1615
+ case 0:
1616
+ rotation |= DRM_MODE_ROTATE_0;
1617
+ break;
1618
+
1619
+ case 90:
1620
+ rotation |= DRM_MODE_ROTATE_90;
1621
+ break;
1622
+
1623
+ case 180:
1624
+ rotation |= DRM_MODE_ROTATE_180;
1625
+ break;
1626
+
1627
+ case 270:
1628
+ rotation |= DRM_MODE_ROTATE_270;
1629
+ break;
1630
+
1631
+ default:
1632
+ return -EINVAL;
1633
+ }
1634
+ } else if (!strncmp(option, "reflect_x", delim - option)) {
1635
+ rotation |= DRM_MODE_REFLECT_X;
1636
+ } else if (!strncmp(option, "reflect_y", delim - option)) {
1637
+ rotation |= DRM_MODE_REFLECT_Y;
1638
+ } else if (!strncmp(option, "margin_right", delim - option)) {
1639
+ if (drm_mode_parse_cmdline_int(delim, &margin))
1640
+ return -EINVAL;
1641
+
1642
+ mode->tv_margins.right = margin;
1643
+ } else if (!strncmp(option, "margin_left", delim - option)) {
1644
+ if (drm_mode_parse_cmdline_int(delim, &margin))
1645
+ return -EINVAL;
1646
+
1647
+ mode->tv_margins.left = margin;
1648
+ } else if (!strncmp(option, "margin_top", delim - option)) {
1649
+ if (drm_mode_parse_cmdline_int(delim, &margin))
1650
+ return -EINVAL;
1651
+
1652
+ mode->tv_margins.top = margin;
1653
+ } else if (!strncmp(option, "margin_bottom", delim - option)) {
1654
+ if (drm_mode_parse_cmdline_int(delim, &margin))
1655
+ return -EINVAL;
1656
+
1657
+ mode->tv_margins.bottom = margin;
1658
+ } else if (!strncmp(option, "panel_orientation", delim - option)) {
1659
+ if (drm_mode_parse_panel_orientation(delim, mode))
1660
+ return -EINVAL;
1661
+ } else {
1662
+ return -EINVAL;
1663
+ }
1664
+ sep = strchr(delim, ',');
1665
+ option = sep + 1;
1666
+ } while (sep);
1667
+
1668
+ if (rotation && freestanding)
1669
+ return -EINVAL;
1670
+
1671
+ if (!(rotation & DRM_MODE_ROTATE_MASK))
1672
+ rotation |= DRM_MODE_ROTATE_0;
1673
+
1674
+ /* Make sure there is exactly one rotation defined */
1675
+ if (!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK))
1676
+ return -EINVAL;
1677
+
1678
+ mode->rotation_reflection = rotation;
1679
+
1680
+ return 0;
1681
+}
1682
+
1683
+static const char * const drm_named_modes_whitelist[] = {
1684
+ "NTSC",
1685
+ "PAL",
1686
+};
1687
+
14181688 /**
14191689 * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
14201690 * @mode_option: optional per connector mode option
....@@ -1430,6 +1700,10 @@
14301700 *
14311701 * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
14321702 *
1703
+ * Additionals options can be provided following the mode, using a comma to
1704
+ * separate each option. Valid options can be found in
1705
+ * Documentation/fb/modedb.rst.
1706
+ *
14331707 * The intermediate drm_cmdline_mode structure is required to store additional
14341708 * options from the command line modline like the force-enable/disable flag.
14351709 *
....@@ -1437,150 +1711,140 @@
14371711 * True if a valid modeline has been parsed, false otherwise.
14381712 */
14391713 bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1440
- struct drm_connector *connector,
1714
+ const struct drm_connector *connector,
14411715 struct drm_cmdline_mode *mode)
14421716 {
14431717 const char *name;
1444
- unsigned int namelen;
1445
- bool res_specified = false, bpp_specified = false, refresh_specified = false;
1446
- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
1447
- bool yres_specified = false, cvt = false, rb = false;
1448
- bool interlace = false, margins = false, was_digit = false;
1449
- int i;
1450
- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
1718
+ bool freestanding = false, parse_extras = false;
1719
+ unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
1720
+ unsigned int mode_end = 0;
1721
+ const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
1722
+ const char *options_ptr = NULL;
1723
+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
1724
+ int i, len, ret;
14511725
1452
-#ifdef CONFIG_FB
1726
+ memset(mode, 0, sizeof(*mode));
1727
+ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
1728
+
14531729 if (!mode_option)
1454
- mode_option = fb_mode_option;
1455
-#endif
1456
-
1457
- if (!mode_option) {
1458
- mode->specified = false;
14591730 return false;
1460
- }
14611731
14621732 name = mode_option;
1463
- namelen = strlen(name);
1464
- for (i = namelen-1; i >= 0; i--) {
1465
- switch (name[i]) {
1466
- case '@':
1467
- if (!refresh_specified && !bpp_specified &&
1468
- !yres_specified && !cvt && !rb && was_digit) {
1469
- refresh = simple_strtol(&name[i+1], NULL, 10);
1470
- refresh_specified = true;
1471
- was_digit = false;
1472
- } else
1473
- goto done;
1474
- break;
1475
- case '-':
1476
- if (!bpp_specified && !yres_specified && !cvt &&
1477
- !rb && was_digit) {
1478
- bpp = simple_strtol(&name[i+1], NULL, 10);
1479
- bpp_specified = true;
1480
- was_digit = false;
1481
- } else
1482
- goto done;
1483
- break;
1484
- case 'x':
1485
- if (!yres_specified && was_digit) {
1486
- yres = simple_strtol(&name[i+1], NULL, 10);
1487
- yres_specified = true;
1488
- was_digit = false;
1489
- } else
1490
- goto done;
1491
- break;
1492
- case '0' ... '9':
1493
- was_digit = true;
1494
- break;
1495
- case 'M':
1496
- if (yres_specified || cvt || was_digit)
1497
- goto done;
1498
- cvt = true;
1499
- break;
1500
- case 'R':
1501
- if (yres_specified || cvt || rb || was_digit)
1502
- goto done;
1503
- rb = true;
1504
- break;
1505
- case 'm':
1506
- if (cvt || yres_specified || was_digit)
1507
- goto done;
1508
- margins = true;
1509
- break;
1510
- case 'i':
1511
- if (cvt || yres_specified || was_digit)
1512
- goto done;
1513
- interlace = true;
1514
- break;
1515
- case 'e':
1516
- if (yres_specified || bpp_specified || refresh_specified ||
1517
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
1518
- goto done;
15191733
1520
- force = DRM_FORCE_ON;
1521
- break;
1522
- case 'D':
1523
- if (yres_specified || bpp_specified || refresh_specified ||
1524
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
1525
- goto done;
1734
+ /* Try to locate the bpp and refresh specifiers, if any */
1735
+ bpp_ptr = strchr(name, '-');
1736
+ if (bpp_ptr)
1737
+ bpp_off = bpp_ptr - name;
15261738
1527
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1528
- (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1529
- force = DRM_FORCE_ON;
1530
- else
1531
- force = DRM_FORCE_ON_DIGITAL;
1532
- break;
1533
- case 'd':
1534
- if (yres_specified || bpp_specified || refresh_specified ||
1535
- was_digit || (force != DRM_FORCE_UNSPECIFIED))
1536
- goto done;
1739
+ refresh_ptr = strchr(name, '@');
1740
+ if (refresh_ptr)
1741
+ refresh_off = refresh_ptr - name;
15371742
1538
- force = DRM_FORCE_OFF;
1743
+ /* Locate the start of named options */
1744
+ options_ptr = strchr(name, ',');
1745
+ if (options_ptr)
1746
+ options_off = options_ptr - name;
1747
+
1748
+ /* Locate the end of the name / resolution, and parse it */
1749
+ if (bpp_ptr) {
1750
+ mode_end = bpp_off;
1751
+ } else if (refresh_ptr) {
1752
+ mode_end = refresh_off;
1753
+ } else if (options_ptr) {
1754
+ mode_end = options_off;
1755
+ parse_extras = true;
1756
+ } else {
1757
+ mode_end = strlen(name);
1758
+ parse_extras = true;
1759
+ }
1760
+
1761
+ /* First check for a named mode */
1762
+ for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
1763
+ ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
1764
+ if (ret == mode_end) {
1765
+ if (refresh_ptr)
1766
+ return false; /* named + refresh is invalid */
1767
+
1768
+ strcpy(mode->name, drm_named_modes_whitelist[i]);
1769
+ mode->specified = true;
15391770 break;
1540
- default:
1541
- goto done;
15421771 }
15431772 }
15441773
1545
- if (i < 0 && yres_specified) {
1546
- char *ch;
1547
- xres = simple_strtol(name, &ch, 10);
1548
- if ((ch != NULL) && (*ch == 'x'))
1549
- res_specified = true;
1550
- else
1551
- i = ch - name;
1552
- } else if (!yres_specified && was_digit) {
1553
- /* catch mode that begins with digits but has no 'x' */
1554
- i = 0;
1555
- }
1556
-done:
1557
- if (i >= 0) {
1558
- pr_warn("[drm] parse error at position %i in video mode '%s'\n",
1559
- i, name);
1560
- mode->specified = false;
1561
- return false;
1562
- }
1774
+ /* No named mode? Check for a normal mode argument, e.g. 1024x768 */
1775
+ if (!mode->specified && isdigit(name[0])) {
1776
+ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
1777
+ parse_extras,
1778
+ connector,
1779
+ mode);
1780
+ if (ret)
1781
+ return false;
15631782
1564
- if (res_specified) {
15651783 mode->specified = true;
1566
- mode->xres = xres;
1567
- mode->yres = yres;
15681784 }
15691785
1570
- if (refresh_specified) {
1571
- mode->refresh_specified = true;
1572
- mode->refresh = refresh;
1786
+ /* No mode? Check for freestanding extras and/or options */
1787
+ if (!mode->specified) {
1788
+ unsigned int len = strlen(mode_option);
1789
+
1790
+ if (bpp_ptr || refresh_ptr)
1791
+ return false; /* syntax error */
1792
+
1793
+ if (len == 1 || (len >= 2 && mode_option[1] == ','))
1794
+ extra_ptr = mode_option;
1795
+ else
1796
+ options_ptr = mode_option - 1;
1797
+
1798
+ freestanding = true;
15731799 }
15741800
1575
- if (bpp_specified) {
1801
+ if (bpp_ptr) {
1802
+ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
1803
+ if (ret)
1804
+ return false;
1805
+
15761806 mode->bpp_specified = true;
1577
- mode->bpp = bpp;
15781807 }
1579
- mode->rb = rb;
1580
- mode->cvt = cvt;
1581
- mode->interlace = interlace;
1582
- mode->margins = margins;
1583
- mode->force = force;
1808
+
1809
+ if (refresh_ptr) {
1810
+ ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
1811
+ &refresh_end_ptr, mode);
1812
+ if (ret)
1813
+ return false;
1814
+
1815
+ mode->refresh_specified = true;
1816
+ }
1817
+
1818
+ /*
1819
+ * Locate the end of the bpp / refresh, and parse the extras
1820
+ * if relevant
1821
+ */
1822
+ if (bpp_ptr && refresh_ptr)
1823
+ extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
1824
+ else if (bpp_ptr)
1825
+ extra_ptr = bpp_end_ptr;
1826
+ else if (refresh_ptr)
1827
+ extra_ptr = refresh_end_ptr;
1828
+
1829
+ if (extra_ptr) {
1830
+ if (options_ptr)
1831
+ len = options_ptr - extra_ptr;
1832
+ else
1833
+ len = strlen(extra_ptr);
1834
+
1835
+ ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
1836
+ connector, mode);
1837
+ if (ret)
1838
+ return false;
1839
+ }
1840
+
1841
+ if (options_ptr) {
1842
+ ret = drm_mode_parse_cmdline_options(options_ptr + 1,
1843
+ freestanding,
1844
+ connector, mode);
1845
+ if (ret)
1846
+ return false;
1847
+ }
15841848
15851849 return true;
15861850 }
....@@ -1635,13 +1899,6 @@
16351899 void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
16361900 const struct drm_display_mode *in)
16371901 {
1638
- WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1639
- in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1640
- in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1641
- in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1642
- in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1643
- "timing values too large for mode info\n");
1644
-
16451902 out->clock = in->clock;
16461903 out->hdisplay = in->hdisplay;
16471904 out->hsync_start = in->hsync_start;
....@@ -1653,7 +1910,7 @@
16531910 out->vsync_end = in->vsync_end;
16541911 out->vtotal = in->vtotal;
16551912 out->vscan = in->vscan;
1656
- out->vrefresh = in->vrefresh;
1913
+ out->vrefresh = drm_mode_vrefresh(in);
16571914 out->flags = in->flags;
16581915 out->type = in->type;
16591916
....@@ -1670,8 +1927,11 @@
16701927 case HDMI_PICTURE_ASPECT_256_135:
16711928 out->flags |= DRM_MODE_FLAG_PIC_AR_256_135;
16721929 break;
1673
- case HDMI_PICTURE_ASPECT_RESERVED:
16741930 default:
1931
+ WARN(1, "Invalid aspect ratio (0%x) on mode\n",
1932
+ in->picture_aspect_ratio);
1933
+ fallthrough;
1934
+ case HDMI_PICTURE_ASPECT_NONE:
16751935 out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
16761936 break;
16771937 }
....@@ -1679,6 +1939,7 @@
16791939 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
16801940 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
16811941 }
1942
+EXPORT_SYMBOL_GPL(drm_mode_convert_to_umode);
16821943
16831944 /**
16841945 * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode
....@@ -1710,7 +1971,6 @@
17101971 out->vsync_end = in->vsync_end;
17111972 out->vtotal = in->vtotal;
17121973 out->vscan = in->vscan;
1713
- out->vrefresh = in->vrefresh;
17141974 out->flags = in->flags;
17151975 /*
17161976 * Old xf86-video-vmware (possibly others too) used to
....@@ -1730,20 +1990,22 @@
17301990
17311991 switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
17321992 case DRM_MODE_FLAG_PIC_AR_4_3:
1733
- out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_4_3;
1993
+ out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
17341994 break;
17351995 case DRM_MODE_FLAG_PIC_AR_16_9:
1736
- out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_16_9;
1996
+ out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
17371997 break;
17381998 case DRM_MODE_FLAG_PIC_AR_64_27:
1739
- out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_64_27;
1999
+ out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27;
17402000 break;
17412001 case DRM_MODE_FLAG_PIC_AR_256_135:
1742
- out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_256_135;
2002
+ out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135;
17432003 break;
1744
- default:
2004
+ case DRM_MODE_FLAG_PIC_AR_NONE:
17452005 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
17462006 break;
2007
+ default:
2008
+ return -EINVAL;
17472009 }
17482010
17492011 out->status = drm_mode_validate_driver(dev, out);