1.Framework purpose
The DRM/KMS framework is dedicated to the management of the display, graphic and composition subsystems. With the help of other Linux multimedia frameworks and applications, the DRM/KMS framework is typically used:
The DRM/KMS framework offers:
Examples of use cases involving the DRM/KMS framework:
1.1.Kernel Mode Setting (KMS)
Drivers must initialize the mode setting core by calling drm_mode_config_init() on the DRM device. The function initializes the struct drm_device mode_config field and never fails. Once done, mode configuration must be setup by initializing the following fields.
drivers/gpu/drm/radeon/radeon_display.c:
618 int radeon_modeset_init(struct radeon_device *rdev)
619 {
623 drm_mode_config_init(rdev->ddev);
624 rdev->mode_info.mode_config_initialized = true;
625
626 rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs;
627
628 if (ASIC_IS_AVIVO(rdev)) {
629 rdev->ddev->mode_config.max_width = 8192;
630 rdev->ddev->mode_config.max_height = 8192;
631 } else {
632 rdev->ddev->mode_config.max_width = 4096;
633 rdev->ddev->mode_config.max_height = 4096;
634 }
635
636 rdev->ddev->mode_config.fb_base = rdev->mc.aper_base;
637
639 for (i = 0; i < num_crtc; i++) {
640 radeon_crtc_init(rdev->ddev, i);
641 }
642
643 /* okay we should have all the bios connectors */
644 ret = radeon_setup_enc_conn(rdev->ddev);
648 drm_helper_initial_config(rdev->ddev);
649 return 0;
650 }
2.System overview
3.How to use the framework
3.1 modetest (DRM/KMS test tool)
root@uos-PC:/libdrm-2.4.100/tests/modetest# ./modetest -h
usage: /home/uos/libdrm-2.4.100/tests/modetest/.libs/modetest [-acDdefMPpsCvw]
Query options:
-c list connectors
-e list encoders
-f list framebuffers
-p list CRTCs and planes (pipes)
Test options:
-P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>] set a plane
-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>] set a mode
-C test hw cursor
-v test vsynced page flipping
-w <obj_id>:<prop_name>:<value> set property
-a use atomic API
-F pattern1,pattern2 specify fill patterns
Generic options:
-d drop master after mode set
-M module use the given driver
-D device use the given device
Default is to dump all info.
3.2. Show display overall status
Get the status of all display capabilities:
root@uos-PC:/libdrm-2.4.100/tests/modetest# ./modetest -M radeon
Encoders:
id crtc type possible crtcs possible clones
42 0 TMDS 0x00000003 0x00000000
44 0 TMDS 0x00000003 0x00000000
46 39 TVDAC 0x00000003 0x00000000
Connectors:
id encoder status name size (mm) modes encoders
43 0 disconnected HDMI-A-1 0x0 0 42
props:
1 EDID:
flags: immutable blob
blobs:
value:
2 DPMS:
flags: enum
enums: On=0 Standby=1 Suspend=2 Off=3
value: 0
5 link-status:
flags: enum
enums: Good=0 Bad=1
value: 0
6 non-desktop:
flags: immutable range
values: 0 1
value: 0
28 coherent:
flags: range
values: 0 1
value: 1
32 underscan:
flags: enum
enums: off=0 on=1 auto=2
value: 0
33 underscan hborder:
flags: range
values: 0 128
value: 0
34 underscan vborder:
flags: range
values: 0 128
value: 0
36 dither:
flags: enum
enums: off=0 on=1
value: 0
30 scaling mode:
flags: enum
enums: None=0 Full=1 Center=2 Full aspect=3
value: 0
35 audio:
flags: enum
enums: off=0 on=1 auto=2
value: 2
37 output_csc:
flags: enum
enums: bypass=0 tvrgb=1 ycbcr601=2 ycbcr709=3
value: 0
45 0 disconnected DVI-D-1 0x0 0 44
props:
1 EDID:
flags: immutable blob
blobs:
value:
2 DPMS:
flags: enum
enums: On=0 Standby=1 Suspend=2 Off=3
value: 0
5 link-status:
flags: enum
enums: Good=0 Bad=1
value: 0
6 non-desktop:
flags: immutable range
values: 0 1
value: 0
28 coherent:
flags: range
values: 0 1
value: 1
32 underscan:
flags: enum
enums: off=0 on=1 auto=2
value: 0
33 underscan hborder:
flags: range
values: 0 128
value: 0
34 underscan vborder:
flags: range
values: 0 128
value: 0
36 dither:
flags: enum
enums: off=0 on=1
value: 0
30 scaling mode:
flags: enum
enums: None=0 Full=1 Center=2 Full aspect=3
value: 0
35 audio:
flags: enum
enums: off=0 on=1 auto=2
value: 2
37 output_csc:
flags: enum
enums: bypass=0 tvrgb=1 ycbcr601=2 ycbcr709=3
value: 0
47 46 connected VGA-1 470x280 20 46
modes:
name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
1600x1200 60 1600 1664 1856 2160 1200 1201 1204 1250 162000 flags: phsync, pvsync; type: driver
1680x1050 60 1680 1784 1960 2240 1050 1053 1059 1089 146250 flags: nhsync, pvsync; type: driver
1600x900 60 1600 1712 1864 2128 900 901 904 932 118970 flags: nhsync, pvsync; type: driver
1280x1024 75 1280 1296 1440 1688 1024 1025 1028 1066 135000 flags: phsync, pvsync; type: driver
1280x1024 60 1280 1328 1440 1688 1024 1025 1028 1066 108000 flags: phsync, pvsync; type: driver
1440x900 60 1440 1520 1672 1904 900 903 909 934 106500 flags: nhsync, pvsync; type: driver
1280x960 60 1280 1376 1488 1800 960 961 964 1000 108000 flags: phsync, pvsync; type: driver
1280x800 60 1280 1352 1480 1680 800 803 809 831 83500 flags: nhsync, pvsync; type: driver
1024x768 75 1024 1040 1136 1312 768 769 772 800 78750 flags: phsync, pvsync; type: driver
1024x768 70 1024 1048 1184 1328 768 771 777 806 75000 flags: nhsync, nvsync; type: driver
1024x768 60 1024 1048 1184 1344 768 771 777 806 65000 flags: nhsync, nvsync; type: driver
800x600 75 800 816 896 1056 600 601 604 625 49500 flags: phsync, pvsync; type: driver
800x600 72 800 856 976 1040 600 637 643 666 50000 flags: phsync, pvsync; type: driver
800x600 60 800 840 968 1056 600 601 605 628 40000 flags: phsync, pvsync; type: driver
800x600 56 800 824 896 1024 600 601 603 625 36000 flags: phsync, pvsync; type: driver
640x480 75 640 656 720 840 480 481 484 500 31500 flags: nhsync, nvsync; type: driver
640x480 73 640 664 704 832 480 489 492 520 31500 flags: nhsync, nvsync; type: driver
640x480 60 640 656 752 800 480 490 492 525 25175 flags: nhsync, nvsync; type: driver
720x400 70 720 738 846 900 400 412 414 449 28320 flags: nhsync, pvsync; type: driver
props:
1 EDID:
flags: immutable blob
blobs:
value:
00ffffffffffff004c239a303e593f1e
011e01030e2f1c782a3581a656489a24
125054afcf008100814081809500a940
b30001010101023a801871382d40582c
4500dd0c1100001e792e401062842030
70981300bbf91000001c000000fd0038
4b1e5f12000a202020202020000000fc
004c4544204d4f4e49544f520a200048
2 DPMS:
flags: enum
enums: On=0 Standby=1 Suspend=2 Off=3
value: 0
5 link-status:
flags: enum
enums: Good=0 Bad=1
value: 0
6 non-desktop:
flags: immutable range
values: 0 1
value: 0
29 load detection:
flags: range
values: 0 1
value: 1
30 scaling mode:
flags: enum
enums: None=0 Full=1 Center=2 Full aspect=3
value: 0
37 output_csc:
flags: enum
enums: bypass=0 tvrgb=1 ycbcr601=2 ycbcr709=3
value: 0
CRTCs:
id fb pos size
39 70 (0,0) (1920x1080)
1920x1080 60 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
props:
41 0 (0,0) (0x0)
0 0 0 0 0 0 0 0 0 0 flags: ; type:
props:
Planes:
id crtc fb CRTC x,y x,y gamma size possible crtcs
38 39 70 0,0 0,0 0 0x00000001
formats: XR24 AR24
props:
7 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 1
40 0 0 0,0 0,0 0 0x00000002
formats: XR24 AR24
props:
7 type:
flags: immutable enum
enums: Overlay=0 Primary=1 Cursor=2
value: 1
Frame buffers:
id size pitch
3.3.Set a particular video mode
Using the modetest -M radeon command, let’s assume that the application returns the following results:
The command to set the 1280x720-50 video:
./modetest -M radeon -s 47@39:1600x1200-60 -d
By using the modetest option -d (drop master after mode set) in the above command, the next DRM-based application that will start will detect the current video mode and use it directly.
3.4 Send a test pattern to a display connector
Using the modetest -M stm command (see Show display overall status), let’s assume you have identified that:
./modetest -M radeon -s 47@39:1600x1200-60
3.5.How to get the name and current status of a DRM connector
Use the following command to get the DRM connector names and associated status:
Board > f o r p i n / s y s / c l a s s / d r m / ∗ / s t a t u s ; d o c o n = > for p in /sys/class/drm/*/status; do con= >forpin/sys/class/drm/∗/status;docon={p%/status}; echo -n "${con#*/card?-}: "; cat $p; done
Result example:
DSI-1: connected
HDMI-A-1: connected
4.Radeon初始化
内核驱动提供了两种方法给用户空间完成显示功能。
4.1.通过DRM(Radeon初始化)
DRM代码来从底层介绍显卡驱动的初始化过程,显卡类型是AMD的radeon r600以后的系列显卡。基本的过程就是驱动载入,硬件初始化,设置硬件独立的模块(如内存管理器),设置显示(分辨率等)。函数分析如下:
679 static int __init radeon_init(void)
680 {
689 if (radeon_modeset == 1) {
690 DRM_INFO("radeon kernel modesetting enabled.\n");
691 driver = &kms_driver;
692 pdriver = &radeon_kms_pci_driver;
693 driver->driver_features |= DRIVER_MODESET;
694 driver->num_ioctls = radeon_max_kms_ioctl;
695 radeon_register_atpx_handler();
697 }
701
702 return pci_register_driver(pdriver);
703 }
注册pdriver,匹配之后调用radeon_pci_probe,该函数调用drm_get_pci_dev,其中drm_get_pci_dev调用ret = dev->driver->load(dev, flags); 即radeon_driver_load_kms。
return drm_get_pci_dev(pdev, ent, &kms_driver);
其中kms_driver定义如下:
drivers/gpu/drm/radeon/radeon_drv.c:
586 static struct drm_driver kms_driver = {
587 .driver_features =
588 DRIVER_USE_AGP |
589 DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
590 DRIVER_PRIME | DRIVER_RENDER,
591 .load = radeon_driver_load_kms, //重点
592 .open = radeon_driver_open_kms,
593 .postclose = radeon_driver_postclose_kms,
594 .lastclose = radeon_driver_lastclose_kms,
595 .unload = radeon_driver_unload_kms,
596 .get_vblank_counter = radeon_get_vblank_counter_kms,
597 .enable_vblank = radeon_enable_vblank_kms,
598 .disable_vblank = radeon_disable_vblank_kms,
599 .get_vblank_timestamp = drm_calc_vbltimestamp_from_scanoutpos,
600 .get_scanout_position = radeon_get_crtc_scanout_position,
601 .irq_preinstall = radeon_driver_irq_preinstall_kms,
602 .irq_postinstall = radeon_driver_irq_postinstall_kms,
603 .irq_uninstall = radeon_driver_irq_uninstall_kms,
604 .irq_handler = radeon_driver_irq_handler_kms,
605 .ioctls = radeon_ioctls_kms,
606 .gem_free_object_unlocked = radeon_gem_object_free,
607 .gem_open_object = radeon_gem_object_open,
608 .gem_close_object = radeon_gem_object_close,
609 .dumb_create = radeon_mode_dumb_create,
610 .dumb_map_offset = radeon_mode_dumb_mmap,
611 .fops = &radeon_driver_kms_fops,
612 ...
631 };
暴露给用户空间的file_operations是:
563 static const struct file_operations radeon_driver_kms_fops = {
564 .owner = THIS_MODULE,
565 .open = drm_open,
566 .release = drm_release,
567 .unlocked_ioctl = radeon_drm_ioctl,
568 .mmap = radeon_mmap,
569 .poll = drm_poll,
570 .read = drm_read,
571 #ifdef CONFIG_COMPAT
572 .compat_ioctl = radeon_kms_compat_ioctl,
573 #endif
574 };
4.1.1.radeon_driver_load_kms()
这个函数是所有和GPU初始化相关的内容的起始点,调用radeon_device_init()来初始化非显示设备的硬件,调用radeon_modeset_init()来初始化显示设备相关的硬件(CRTC,connector, encoder等)。
radeon_device_init
->radeon_gem_init
->radeon_asic_setup
->radeon_asic_init
驱动初始化主要的工作都是由radeon_device_init()来完成。首先会初始化一大堆的驱动需要使用的结构,然后调用radeon_asic_init(),这个函数用于设置电路相关的一些函数指针,比如睡眠/恢复调用,硬件重置,设置和处理中断请求,设置和获取时钟等等。
1521 static struct radeon_asic btc_asic = {
1522 .init = &evergreen_init,
1523 .fini = &evergreen_fini,
1524 .suspend = &evergreen_suspend,
1525 .resume = &evergreen_resume,
1526 .asic_reset = &evergreen_asic_reset,
1527 .vga_set_state = &r600_vga_set_state,
1528 .mmio_hdp_flush = r600_mmio_hdp_flush,
1529 .gui_idle = &r600_gui_idle,
1530 .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
1531 .get_xclk = &rv770_get_xclk,
1532 .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
1533 .get_allowed_info_register = evergreen_get_allowed_info_register,
1534 .gart = {
1535 .tlb_flush = &evergreen_pcie_gart_tlb_flush,
1536 .get_page_entry = &rs600_gart_get_page_entry,
1537 .set_page = &rs600_gart_set_page,
1538 },
1539 .ring = {
1540 [RADEON_RING_TYPE_GFX_INDEX] = &evergreen_gfx_ring,
1541 [R600_RING_TYPE_DMA_INDEX] = &evergreen_dma_ring,
1542 [R600_RING_TYPE_UVD_INDEX] = &rv770_uvd_ring,
1543 },
1544 .irq = {
1545 .set = &evergreen_irq_set,
1546 .process = &evergreen_irq_process,
1547 },
1548 ...
1567 .hpd = {
1568 .init = &evergreen_hpd_init,
1569 .fini = &evergreen_hpd_fini,
1570 .sense = &evergreen_hpd_sense,
1571 .set_polarity = &evergreen_hpd_set_polarity,
1572 },
#define radeon_asic_init(rdev) (rdev)->asic->init((rdev))
evergreen_init 调用流程图:
1.显卡bios
主要用于存放显示芯片与驱动程序之间的控制程序,它控制着显卡各种工作状态,包括核心工作频率,显存工作频率,功耗限制、工作电压和显存时序等核心参数。一般来说,每一个显卡厂商都会根据NVIDIA或AMD提供的显卡原始BIOS进行修改,以达到更好的性能。而显卡刷BIOS就是通过新的核心控制程序来替换掉原本的控制程序,比如调整核心工作频率,显存工作频率,功耗限制、工作电压和显存时序等核心参数,以达到更好的显卡性能。
2.中断分析(evergreen_startup)
:
5074 /* Enable IRQ */
5075 if (!rdev->irq.installed) {
5077 r = radeon_irq_kms_init(rdev);
5078 if (r)
5079 return r;
5080 }
285 int radeon_irq_kms_init(struct radeon_device *rdev)
286 {
310
311 INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
312 INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
313 INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
314
315 rdev->need_recover = 0;
316 INIT_DEFERRABLE_WORK(&rdev->recover_work, radeon_recover_callback);
317
318 rdev->irq.installed = true;
319 r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
328 }
如上所示:
初始化工作队列:
INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
注册中断:
r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
注册中断函数:.irq_handler = radeon_driver_irq_handler_kms, // kms_driver定义
当发生中断时,调用radeon_driver_irq_handler_kms:
>> 48 irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg)
49 {
50 struct drm_device *dev = (struct drm_device *) arg;
>> 51 struct radeon_device *rdev = dev->dev_private;
>> 52 irqreturn_t ret;
53
>> 55 ret = radeon_irq_process(rdev);
>> 56 if (ret == IRQ_HANDLED)
>> 57 pm_runtime_mark_last_busy(dev->dev);
58 return ret;
59 }
其中radeon_irq_process调用evergreen_asic定义的.process = &evergreen_irq_process,
关于HDMI 热插拔(Hot Plug Detection) :
The HPD (Hot-Plug-Detect) feature is a communication mechanism between a source and a sink device that makes the source device aware that it has been connected/disconnected to/from the sink device. When an HDMI cable is inserted between the two devices, the resulting hot-plug detection instantiates a start-up communication sequence.
当热插拔HDMI时,判断满足42,则queue_hotplug=true, 然后调用hotplug_work,即radeon_hotplug_work_func。
drivers/gpu/drm/radeon/evergreen.c:
4796 case 42: /* HPD hotplug */
4797 if (src_data <= 5) {
4799 hpd_idx = src_data;
4800 mask = DC_HPD1_INTERRUPT;
4801 queue_hotplug = true;
4802 event_name = "HPD";
4918 if (queue_hotplug)
4920 schedule_delayed_work(&rdev->hotplug_work, 0);
75 static void radeon_hotplug_work_func(struct work_struct *work)
76 {
>> 77 struct radeon_device *rdev = container_of(work, struct radeon_device,
>> 78 hotplug_work.work);
>> 79 struct drm_device *dev = rdev->ddev;
>> 80 struct drm_mode_config *mode_config = &dev->mode_config;
81 struct drm_connector *connector;
82
84 /* we can race here at startup, some boards seem to trigger
85 * hotplug irqs when they shouldn't. */
>> 86 if (!rdev->mode_info.mode_config_initialized)
87 return;
88
>> 89 mutex_lock(&mode_config->mutex);
>> 90 list_for_each_entry(connector, &mode_config->connector_list, head)
91 radeon_connector_hotplug(connector);
>> 92 mutex_unlock(&mode_config->mutex);
93 /* Just fire off a uevent and let userspace tell us what to do */
>> 94 drm_helper_hpd_irq_event(dev);
95 }
分析drm_helper_hpd_irq_event(dev); //hotplug processing
322 if (funcs->detect_ctx)
323 return funcs->detect_ctx(connector, ctx, force);
324 else if (connector->funcs->detect)
325 return connector->funcs->detect(connector, force); //.detect = radeon_dvi_detect,
drivers/gpu/drm/radeon/radeon_connectors.c:
1525 static const struct drm_connector_funcs radeon_dvi_connector_funcs = {
1526 .dpms = drm_helper_connector_dpms,
1527 .detect = radeon_dvi_detect,
1528 .fill_modes = drm_helper_probe_single_connector_modes,
1529 .set_property = radeon_connector_set_property,
1530 .early_unregister = radeon_connector_unregister,
1531 .destroy = radeon_connector_destroy,
1532 .force = radeon_dvi_force,
1533 };
4.1.2.radeon_modeset_init
radeon_hpd_init:
radeon_hpd_init
->evergreen_hpd_init
->radeon_irq_kms_enable_hpd
->radeon_irq_set
->evergreen_irq_set
1753 /**
1754 * evergreen_hpd_init - hpd setup callback.
1755 *
1756 * @rdev: radeon_device pointer
1757 *
1758 * Setup the hpd pins used by the card (evergreen+).
1759 * Enable the pin, set the polarity, and enable the hpd interrupts.
1760 */
1761 void evergreen_hpd_init(struct radeon_device *rdev)
1762 {
1763 struct drm_device *dev = rdev->ddev;
1764 struct drm_connector *connector;
1765 unsigned enabled = 0;
1766 u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) |
1767 DC_HPDx_RX_INT_TIMER(0xfa) | DC_HPDx_EN;
1768
1769 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1770 enum radeon_hpd_id hpd =
1771 to_radeon_connector(connector)->hpd.hpd;
1772
1773 if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
1774 connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
1775 /* don't try to enable hpd on eDP or LVDS avoid breaking the
1776 * aux dp channel on imac and help (but not completely fix)
1777 * https://bugzilla.redhat.com/show_bug.cgi?id=726143
1778 * also avoid interrupt storms during dpms.
1779 */
1780 continue;
1781 }
1782
1783 if (hpd == RADEON_HPD_NONE)
1784 continue;
1785
1786 WREG32(DC_HPDx_CONTROL(hpd), tmp);
1787 enabled |= 1 << hpd;
1788
1789 radeon_hpd_set_polarity(rdev, hpd);
1790 }
1791 radeon_irq_kms_enable_hpd(rdev, enabled);
1792 }
4.2.radeon_fbdev_init
330 int radeon_fbdev_init(struct radeon_device *rdev)
331 {
335
336 /* don't enable fbdev if no connectors */
337 if (list_empty(&rdev->ddev->mode_config.connector_list))
338 return 0;
339
340 /* select 8 bpp console on 8MB cards, or 16 bpp on RN50 or 32MB */
341 if (rdev->mc.real_vram_size <= (8*1024*1024))
342 bpp_sel = 8;
343 else if (ASIC_IS_RN50(rdev) ||
344 rdev->mc.real_vram_size <= (32*1024*1024))
345 bpp_sel = 16;
346
347 rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
350
351 rfbdev->rdev = rdev;
352 rdev->mode_info.rfbdev = rfbdev;
353
354 drm_fb_helper_prepare(rdev->ddev, &rfbdev->helper,
355 &radeon_fb_helper_funcs);
356
357 ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
358 RADEONFB_CONN_LIMIT);
362 ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
363 if (ret)
365
366 /* disable all the possible outputs/crtcs before entering KMS mode */
367 drm_helper_disable_unused_functions(rdev->ddev);
368
369 ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
drm_fb_helper_initial_config调用流程:
drm_setup_crtcs():一个设置好每个一个CRTC,方法是从每个Connector的所有的模式,并为每个一个CRTC选择一个计算出最好的分数,出一个CRTC跟Connector之间的映射。
drm_fb_helper_single_fb_probe():初始化drm_framebuffer的其过程与一般的Frame Buffer初始化过程差不多,最后调用register_framebuffer()完成Frame Buffer的XML注册,然后,Frame Buffer就可以或使用了。
drm_fb_helper_initial_config ->
__drm_fb_helper_initial_config_and_unlock
drm_setup_crtcs
drm_fb_helper_probe_connector_modes
count += connector->funcs->fill_modes(connector, maxX, maxY); //.fill_modes = drm_helper_probe_single_connector_modes,(drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c)
drm_target_preferred
drm_has_preferred_mode
drm_fb_helper_single_fb_probe
drm_helper_probe_detect:
305 int
306 drm_helper_probe_detect(struct drm_connector *connector,
307 struct drm_modeset_acquire_ctx *ctx,
308 bool force)
309 {
310 const struct drm_connector_helper_funcs *funcs = connector->helper_private;
311 struct drm_device *dev = connector->dev;
312 int ret;
313
315 if (!ctx)
316 return drm_helper_probe_detect_ctx(connector, force);
317
318 ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
321
322 if (funcs->detect_ctx)
323 return funcs->detect_ctx(connector, ctx, force);
324 else if (connector->funcs->detect)
325 return connector->funcs->detect(connector, force);
326 else
327 return connector_status_connected;
328 }
radeon_vga_get_modes:
drivers/gpu/drm/radeon/radeon_connectors.c:
1114 static const struct drm_connector_funcs radeon_vga_connector_funcs = {
1115 .dpms = drm_helper_connector_dpms,
1116 .detect = radeon_vga_detect,
1117 .fill_modes = drm_helper_probe_single_connector_modes,
1118 .early_unregister = radeon_connector_unregister,
1119 .destroy = radeon_connector_destroy,
1120 .set_property = radeon_connector_set_property,
1121 };
1515 static const struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
1516 .get_modes = radeon_vga_get_modes,
1517 .mode_valid = radeon_dvi_mode_valid,
1518 .best_encoder = radeon_dvi_encoder,
1519 };
991 static int radeon_vga_get_modes(struct drm_connector *connector)
992 {
993 int ret;
994
995 radeon_connector_get_edid(connector);
996 ret = radeon_ddc_get_modes(connector);
997
998 radeon_get_native_mode(connector);
999
1000 return ret;
1001 }
drm_add_override_edid_modes:
调用流程:
drm_add_override_edid_modes
->drm_get_override_edid
->drm_add_edid_modes
1612 int drm_add_override_edid_modes(struct drm_connector *connector)
1613 {
1614 struct edid *override;
1615 int num_modes = 0;
1616
1617 override = drm_get_override_edid(connector);
1618 if (override) {
1619 drm_connector_update_edid_property(connector, override);
1620 num_modes = drm_add_edid_modes(connector, override);
1621 kfree(override);
1625 }
1627 return num_modes;
1628 }
5.How to trace
If you are facing some issues with graphics or DRM , display etc… sometime your may want to enable the DRM drivers all debugging messages so you can narrow down the problems. In Linux the drm kernel drivers source code can be found in drivers/gpu/drm.
Enabling verbose debug messages is done through the drm.debug parameter, each category being enabled by a bit:
- drm.debug=0x1 will enable CORE messages
- drm.debug=0x2 will enable DRIVER messages
- drm.debug=0x3 will enable CORE and DRIVER messages
…
drm.debug=0x1ff will enable all messages
Note: add the drm.debug in /etc/default/grub file:
GRUB_CMDLINE_LINUX_DEFAULT=“splash console=ttyS1,115200n8 no_console_suspend loglevel=7 drm.debug=0xf”
So, to enable the DRM logs, you simply need to echo following value to sysfs file from console,
$ echo 0xf > /sys/module/drm/parameters/debug
5.1.Enable DRM/KMS traces with the sysfs
The DRM/KMS traces can be enabled / disabled dynamically using the sysfs debug entry (/sys/module/drm/parameters/debug). The DRM/KMS traces are directed to the dmesg log.
The debug value to set is an OR combination of some debug levels defined in include/drm/drm_print.h . See below an extract of this file:
/*
* The following categories are defined:
*
* CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, drm_memory.c, ...
* This is the category used by the DRM_DEBUG() macro.
*
* DRIVER: Used in the vendor specific part of the driver: i915, radeon, ...
* This is the category used by the DRM_DEBUG_DRIVER() macro.
*
* KMS: used in the modesetting code.
* This is the category used by the DRM_DEBUG_KMS() macro.
*
* PRIME: used in the prime code.
* This is the category used by the DRM_DEBUG_PRIME() macro.
*
* ATOMIC: used in the atomic code.
* This is the category used by the DRM_DEBUG_ATOMIC() macro.
*
* VBL: used for verbose debug message in the vblank code
* This is the category used by the DRM_DEBUG_VBL() macro.
*
* Enabling verbose debug messages is done through the drm.debug parameter,
* each category being enabled by a bit.
*
* drm.debug=0x1 will enable CORE messages
* drm.debug=0x2 will enable DRIVER messages
* drm.debug=0x3 will enable CORE and DRIVER messages
* ...
* drm.debug=0x3f will enable all messages
*
* An interesting feature is that it's possible to enable verbose logging at
* run-time by echoing the debug value in its sysfs node:
* # echo 0xf > /sys/module/drm/parameters/debug
*/
Examples:
5.2. 查看系统当前使用的哪个显卡驱动
wenlian@uos-PC:$ hwinfo --display | grep "Driver Modules"
Driver Modules: "radeon"
wenlian@uos-PC:~$ lshw -c video
WARNING: you should run this program as super-user.
*-display
description: VGA compatible controller
product: Caicos [Radeon HD 6450/7450/8450 / R5 230 OEM]
vendor: Advanced Micro Devices, Inc. [AMD/ATI]
physical id: 0
bus info: pci@0000:04:00.0
version: 00
width: 64 bits
clock: 33MHz
capabilities: vga_controller bus_master cap_list rom
configuration: driver=radeon latency=0
resources: irq:136 memory:40000000-4fffffff memory:59300000-5931ffff ioport:5000(size=256) memory:50000000-5001ffff
WARNING: output may be incomplete or inaccurate, you should run this program as super-user.
uos@uos-PC:~$ lspci -k | grep -A 2 -E "(VGA|3D)"
00:00.1 Non-VGA unclassified device: Loongson Technology LLC Hyper Transport Bridge Controller
00:04.0 USB controller: Loongson Technology LLC OHCI USB Controller
Kernel driver in use: ohci-pci
--
00:06.1 VGA compatible controller: Loongson Technology LLC DC (Display Controller)
Kernel driver in use: loongson-drm
Kernel modules: loongson, lsdc
uos@uos-PC:~/work$ sudo apt-get install mesa-utils
uos@uos-PC:~/work$ glxinfo -B
name of display: :0
display: :0 screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
Vendor: X.Org (0x1002)
Device: AMD OLAND (DRM 2.50.0, 4.19.0-6-amd64, LLVM 7.0.1) (0x6611)
Version: 18.3.6
Accelerated: yes
Video memory: 2048MB
Unified memory: no
Preferred profile: core (0x1)
Max core profile version: 4.5
Max compat profile version: 4.5
Max GLES1 profile version: 1.1
Max GLES[23] profile version: 3.2
Memory info (GL_ATI_meminfo):
VBO free memory - total: 1094 MB, largest block: 1094 MB
VBO free aux. memory - total: 2020 MB, largest block: 2020 MB
Texture free memory - total: 1094 MB, largest block: 1094 MB
Texture free aux. memory - total: 2020 MB, largest block: 2020 MB
Renderbuffer free memory - total: 1094 MB, largest block: 1094 MB
Renderbuffer free aux. memory - total: 2020 MB, largest block: 2020 MB
Memory info (GL_NVX_gpu_memory_info):
Dedicated video memory: 2048 MB
Total available memory: 4091 MB
Currently available dedicated video memory: 1094 MB
OpenGL vendor string: X.Org
OpenGL renderer string: AMD OLAND (DRM 2.50.0, 4.19.0-6-amd64, LLVM 7.0.1)
OpenGL core profile version string: 4.5 (Core Profile) Mesa 18.3.6
OpenGL core profile shading language version string: 4.50
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile
OpenGL version string: 4.5 (Compatibility Profile) Mesa 18.3.6
OpenGL shading language version string: 4.50
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile
OpenGL ES profile version string: OpenGL ES 3.2 Mesa 18.3.6
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 3.20
$ xvinfo | head -10
X-Video Extension version 2.2
screen #0
Adaptor #0: "GLAMOR Textured Video"
number of ports: 16
port base: 63
operations supported: PutImage
supported visuals:
depth 24, visualID 0x21
number of attributes: 5
"XV_BRIGHTNESS" (range -1000 to 1000)
5.3. DRM sys node
The DRM module is responsible for that subtree in SysFS. You can browse the source code for that in drivers/gpu/drm/drm_sysfs.c.
The subdirectories are per-connector, with a name of the form card%d-%s with %d replaced by an index (that I know nothing about) and %s replaced with the connector name.
Five files per device should show up:
Connection status
Enabled (or not)
DPMS state
Mode list
EDID
节点如下:
root@uos-PC:/sys/class/drm# ls -l
总用量 0
lrwxrwxrwx 1 root root 0 12月 21 16:57 card0 -> ../../devices/pci0000:00/0000:00:11.0/0000:05:00.0/drm/card0
lrwxrwxrwx 1 root root 0 12月 21 16:57 card0-DVI-D-1 -> ../../devices/pci0000:00/0000:00:11.0/0000:05:00.0/drm/card0/card0-DVI-D-1
lrwxrwxrwx 1 root root 0 12月 21 16:57 card0-HDMI-A-1 -> ../../devices/pci0000:00/0000:00:11.0/0000:05:00.0/drm/card0/card0-HDMI-A-1
lrwxrwxrwx 1 root root 0 12月 21 16:57 card0-VGA-1 -> ../../devices/pci0000:00/0000:00:11.0/0000:05:00.0/drm/card0/card0-VGA-1
lrwxrwxrwx 1 root root 0 12月 21 16:57 renderD128 -> ../../devices/pci0000:00/0000:00:11.0/0000:05:00.0/drm/renderD128
lrwxrwxrwx 1 root root 0 12月 21 16:57 ttm -> ../../devices/virtual/drm/ttm
-r--r--r-- 1 root root 16384 12月 21 16:57 version
root@uos-PC:/sys/kernel/debug/dri/0# ls -l
总用量 0
-r--r--r-- 1 root root 0 12月 21 16:57 clients
drwxr-xr-x 2 root root 0 12月 21 16:57 crtc-0
drwxr-xr-x 2 root root 0 12月 21 16:57 crtc-1
drwxr-xr-x 2 root root 0 12月 21 16:57 DVI-D-1
-r--r--r-- 1 root root 0 12月 21 16:57 framebuffer
-r--r--r-- 1 root root 0 12月 21 16:57 gem_names
drwxr-xr-x 2 root root 0 12月 21 16:57 HDMI-A-1
-r--r--r-- 1 root root 0 12月 21 16:57 internal_clients
-r--r--r-- 1 root root 0 12月 21 16:57 name
-r--r--r-- 1 root root 0 12月 21 16:57 radeon_fence_info
-r--r--r-- 1 root root 0 12月 21 16:57 radeon_gem_info
-r--r--r-- 1 root root 0 12月 21 16:57 radeon_gpu_reset
-r--r--r-- 1 root root 0 12月 21 16:57 radeon_gtt
...
refer to