.. | .. |
---|
30 | 30 | * authorization from the copyright holder(s) and author(s). |
---|
31 | 31 | */ |
---|
32 | 32 | |
---|
| 33 | +#include <linux/ctype.h> |
---|
33 | 34 | #include <linux/list.h> |
---|
34 | 35 | #include <linux/list_sort.h> |
---|
35 | 36 | #include <linux/export.h> |
---|
36 | | -#include <drm/drmP.h> |
---|
37 | | -#include <drm/drm_crtc.h> |
---|
| 37 | + |
---|
38 | 38 | #include <video/of_videomode.h> |
---|
39 | 39 | #include <video/videomode.h> |
---|
| 40 | + |
---|
| 41 | +#include <drm/drm_crtc.h> |
---|
| 42 | +#include <drm/drm_device.h> |
---|
40 | 43 | #include <drm/drm_modes.h> |
---|
| 44 | +#include <drm/drm_print.h> |
---|
41 | 45 | |
---|
42 | 46 | #include "drm_crtc_internal.h" |
---|
43 | 47 | |
---|
.. | .. |
---|
71 | 75 | if (!nmode) |
---|
72 | 76 | return NULL; |
---|
73 | 77 | |
---|
74 | | - if (drm_mode_object_add(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) { |
---|
75 | | - kfree(nmode); |
---|
76 | | - return NULL; |
---|
77 | | - } |
---|
78 | | - |
---|
79 | 78 | return nmode; |
---|
80 | 79 | } |
---|
81 | 80 | EXPORT_SYMBOL(drm_mode_create); |
---|
.. | .. |
---|
91 | 90 | { |
---|
92 | 91 | if (!mode) |
---|
93 | 92 | return; |
---|
94 | | - |
---|
95 | | - drm_mode_object_unregister(dev, &mode->base); |
---|
96 | 93 | |
---|
97 | 94 | kfree(mode); |
---|
98 | 95 | } |
---|
.. | .. |
---|
160 | 157 | int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync; |
---|
161 | 158 | int interlace; |
---|
162 | 159 | u64 tmp; |
---|
| 160 | + |
---|
| 161 | + if (!hdisplay || !vdisplay) |
---|
| 162 | + return NULL; |
---|
163 | 163 | |
---|
164 | 164 | /* allocate the drm_display_mode structure. If failure, we will |
---|
165 | 165 | * return directly |
---|
.. | .. |
---|
396 | 396 | int hsync, hfront_porch, vodd_front_porch_lines; |
---|
397 | 397 | unsigned int tmp1, tmp2; |
---|
398 | 398 | |
---|
| 399 | + if (!hdisplay || !vdisplay) |
---|
| 400 | + return NULL; |
---|
| 401 | + |
---|
399 | 402 | drm_mode = drm_mode_create(dev); |
---|
400 | 403 | if (!drm_mode) |
---|
401 | 404 | return NULL; |
---|
.. | .. |
---|
545 | 548 | * Generalized Timing Formula is derived from: |
---|
546 | 549 | * |
---|
547 | 550 | * GTF Spreadsheet by Andy Morrish (1/5/97) |
---|
548 | | - * available at http://www.vesa.org |
---|
| 551 | + * available at https://www.vesa.org |
---|
549 | 552 | * |
---|
550 | 553 | * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c. |
---|
551 | 554 | * What I have done is to translate it by using integer calculation. |
---|
.. | .. |
---|
663 | 666 | * @bus_flags: information about pixelclk, sync and DE polarity will be stored |
---|
664 | 667 | * here |
---|
665 | 668 | * |
---|
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 |
---|
668 | 671 | * found in @vm |
---|
669 | 672 | */ |
---|
670 | 673 | void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags) |
---|
671 | 674 | { |
---|
672 | 675 | *bus_flags = 0; |
---|
673 | 676 | if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) |
---|
674 | | - *bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE; |
---|
| 677 | + *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; |
---|
675 | 678 | if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) |
---|
676 | | - *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE; |
---|
| 679 | + *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE; |
---|
677 | 680 | |
---|
678 | 681 | if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE) |
---|
679 | | - *bus_flags |= DRM_BUS_FLAG_SYNC_POSEDGE; |
---|
| 682 | + *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE; |
---|
680 | 683 | if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE) |
---|
681 | | - *bus_flags |= DRM_BUS_FLAG_SYNC_NEGEDGE; |
---|
| 684 | + *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE; |
---|
682 | 685 | |
---|
683 | 686 | if (vm->flags & DISPLAY_FLAGS_DE_LOW) |
---|
684 | 687 | *bus_flags |= DRM_BUS_FLAG_DE_LOW; |
---|
.. | .. |
---|
717 | 720 | if (bus_flags) |
---|
718 | 721 | drm_bus_flags_from_videomode(&vm, bus_flags); |
---|
719 | 722 | |
---|
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); |
---|
722 | 725 | drm_mode_debug_printmodeline(dmode); |
---|
723 | 726 | |
---|
724 | 727 | return 0; |
---|
.. | .. |
---|
745 | 748 | EXPORT_SYMBOL(drm_mode_set_name); |
---|
746 | 749 | |
---|
747 | 750 | /** |
---|
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 | | -/** |
---|
774 | 751 | * drm_mode_vrefresh - get the vrefresh of a mode |
---|
775 | 752 | * @mode: mode |
---|
776 | 753 | * |
---|
.. | .. |
---|
780 | 757 | */ |
---|
781 | 758 | int drm_mode_vrefresh(const struct drm_display_mode *mode) |
---|
782 | 759 | { |
---|
783 | | - int refresh = 0; |
---|
| 760 | + unsigned int num, den; |
---|
784 | 761 | |
---|
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; |
---|
789 | 764 | |
---|
790 | | - num = mode->clock * 1000; |
---|
791 | | - den = mode->htotal * mode->vtotal; |
---|
| 765 | + num = mode->clock; |
---|
| 766 | + den = mode->htotal * mode->vtotal; |
---|
792 | 767 | |
---|
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; |
---|
799 | 774 | |
---|
800 | | - refresh = DIV_ROUND_CLOSEST(num, den); |
---|
801 | | - } |
---|
802 | | - return refresh; |
---|
| 775 | + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(num, 1000), den); |
---|
803 | 776 | } |
---|
804 | 777 | EXPORT_SYMBOL(drm_mode_vrefresh); |
---|
805 | 778 | |
---|
.. | .. |
---|
912 | 885 | */ |
---|
913 | 886 | void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src) |
---|
914 | 887 | { |
---|
915 | | - int id = dst->base.id; |
---|
916 | 888 | struct list_head head = dst->head; |
---|
917 | 889 | |
---|
918 | 890 | *dst = *src; |
---|
919 | | - dst->base.id = id; |
---|
920 | 891 | dst->head = head; |
---|
921 | 892 | } |
---|
922 | 893 | EXPORT_SYMBOL(drm_mode_copy); |
---|
.. | .. |
---|
1282 | 1253 | * @verbose: be verbose about it |
---|
1283 | 1254 | * |
---|
1284 | 1255 | * 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 |
---|
1286 | 1257 | * removed from the list, and if @verbose the status code and mode name is also |
---|
1287 | 1258 | * printed to dmesg. |
---|
1288 | 1259 | */ |
---|
.. | .. |
---|
1333 | 1304 | if (diff) |
---|
1334 | 1305 | return diff; |
---|
1335 | 1306 | |
---|
1336 | | - diff = b->vrefresh - a->vrefresh; |
---|
| 1307 | + diff = drm_mode_vrefresh(b) - drm_mode_vrefresh(a); |
---|
1337 | 1308 | if (diff) |
---|
1338 | 1309 | return diff; |
---|
1339 | 1310 | |
---|
.. | .. |
---|
1415 | 1386 | } |
---|
1416 | 1387 | EXPORT_SYMBOL(drm_connector_list_update); |
---|
1417 | 1388 | |
---|
| 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, °)) |
---|
| 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 | + |
---|
1418 | 1688 | /** |
---|
1419 | 1689 | * drm_mode_parse_command_line_for_connector - parse command line modeline for connector |
---|
1420 | 1690 | * @mode_option: optional per connector mode option |
---|
.. | .. |
---|
1430 | 1700 | * |
---|
1431 | 1701 | * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd] |
---|
1432 | 1702 | * |
---|
| 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 | + * |
---|
1433 | 1707 | * The intermediate drm_cmdline_mode structure is required to store additional |
---|
1434 | 1708 | * options from the command line modline like the force-enable/disable flag. |
---|
1435 | 1709 | * |
---|
.. | .. |
---|
1437 | 1711 | * True if a valid modeline has been parsed, false otherwise. |
---|
1438 | 1712 | */ |
---|
1439 | 1713 | bool drm_mode_parse_command_line_for_connector(const char *mode_option, |
---|
1440 | | - struct drm_connector *connector, |
---|
| 1714 | + const struct drm_connector *connector, |
---|
1441 | 1715 | struct drm_cmdline_mode *mode) |
---|
1442 | 1716 | { |
---|
1443 | 1717 | 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; |
---|
1451 | 1725 | |
---|
1452 | | -#ifdef CONFIG_FB |
---|
| 1726 | + memset(mode, 0, sizeof(*mode)); |
---|
| 1727 | + mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; |
---|
| 1728 | + |
---|
1453 | 1729 | if (!mode_option) |
---|
1454 | | - mode_option = fb_mode_option; |
---|
1455 | | -#endif |
---|
1456 | | - |
---|
1457 | | - if (!mode_option) { |
---|
1458 | | - mode->specified = false; |
---|
1459 | 1730 | return false; |
---|
1460 | | - } |
---|
1461 | 1731 | |
---|
1462 | 1732 | 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; |
---|
1519 | 1733 | |
---|
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; |
---|
1526 | 1738 | |
---|
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; |
---|
1537 | 1742 | |
---|
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; |
---|
1539 | 1770 | break; |
---|
1540 | | - default: |
---|
1541 | | - goto done; |
---|
1542 | 1771 | } |
---|
1543 | 1772 | } |
---|
1544 | 1773 | |
---|
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; |
---|
1563 | 1782 | |
---|
1564 | | - if (res_specified) { |
---|
1565 | 1783 | mode->specified = true; |
---|
1566 | | - mode->xres = xres; |
---|
1567 | | - mode->yres = yres; |
---|
1568 | 1784 | } |
---|
1569 | 1785 | |
---|
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; |
---|
1573 | 1799 | } |
---|
1574 | 1800 | |
---|
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 | + |
---|
1576 | 1806 | mode->bpp_specified = true; |
---|
1577 | | - mode->bpp = bpp; |
---|
1578 | 1807 | } |
---|
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 | + } |
---|
1584 | 1848 | |
---|
1585 | 1849 | return true; |
---|
1586 | 1850 | } |
---|
.. | .. |
---|
1635 | 1899 | void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, |
---|
1636 | 1900 | const struct drm_display_mode *in) |
---|
1637 | 1901 | { |
---|
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 | | - |
---|
1645 | 1902 | out->clock = in->clock; |
---|
1646 | 1903 | out->hdisplay = in->hdisplay; |
---|
1647 | 1904 | out->hsync_start = in->hsync_start; |
---|
.. | .. |
---|
1653 | 1910 | out->vsync_end = in->vsync_end; |
---|
1654 | 1911 | out->vtotal = in->vtotal; |
---|
1655 | 1912 | out->vscan = in->vscan; |
---|
1656 | | - out->vrefresh = in->vrefresh; |
---|
| 1913 | + out->vrefresh = drm_mode_vrefresh(in); |
---|
1657 | 1914 | out->flags = in->flags; |
---|
1658 | 1915 | out->type = in->type; |
---|
1659 | 1916 | |
---|
.. | .. |
---|
1670 | 1927 | case HDMI_PICTURE_ASPECT_256_135: |
---|
1671 | 1928 | out->flags |= DRM_MODE_FLAG_PIC_AR_256_135; |
---|
1672 | 1929 | break; |
---|
1673 | | - case HDMI_PICTURE_ASPECT_RESERVED: |
---|
1674 | 1930 | 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: |
---|
1675 | 1935 | out->flags |= DRM_MODE_FLAG_PIC_AR_NONE; |
---|
1676 | 1936 | break; |
---|
1677 | 1937 | } |
---|
.. | .. |
---|
1679 | 1939 | strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); |
---|
1680 | 1940 | out->name[DRM_DISPLAY_MODE_LEN-1] = 0; |
---|
1681 | 1941 | } |
---|
| 1942 | +EXPORT_SYMBOL_GPL(drm_mode_convert_to_umode); |
---|
1682 | 1943 | |
---|
1683 | 1944 | /** |
---|
1684 | 1945 | * drm_crtc_convert_umode - convert a modeinfo into a drm_display_mode |
---|
.. | .. |
---|
1710 | 1971 | out->vsync_end = in->vsync_end; |
---|
1711 | 1972 | out->vtotal = in->vtotal; |
---|
1712 | 1973 | out->vscan = in->vscan; |
---|
1713 | | - out->vrefresh = in->vrefresh; |
---|
1714 | 1974 | out->flags = in->flags; |
---|
1715 | 1975 | /* |
---|
1716 | 1976 | * Old xf86-video-vmware (possibly others too) used to |
---|
.. | .. |
---|
1730 | 1990 | |
---|
1731 | 1991 | switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) { |
---|
1732 | 1992 | 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; |
---|
1734 | 1994 | break; |
---|
1735 | 1995 | 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; |
---|
1737 | 1997 | break; |
---|
1738 | 1998 | 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; |
---|
1740 | 2000 | break; |
---|
1741 | 2001 | 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; |
---|
1743 | 2003 | break; |
---|
1744 | | - default: |
---|
| 2004 | + case DRM_MODE_FLAG_PIC_AR_NONE: |
---|
1745 | 2005 | out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; |
---|
1746 | 2006 | break; |
---|
| 2007 | + default: |
---|
| 2008 | + return -EINVAL; |
---|
1747 | 2009 | } |
---|
1748 | 2010 | |
---|
1749 | 2011 | out->status = drm_mode_validate_driver(dev, out); |
---|