Linux DRM(三) -- DRM KMS/ Debug

  • DRM KMS overview

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:

  • to compose animated contents taking advantages of the hardware acceleration.
  • to control both display interfaces and external displays including their settings (resolution, frequencie, multi-screen…).
  • to display this animated contents on display panels or HDMI outputs.

  The DRM/KMS framework offers:

  • a kernel level interface driver for display, graphic and composition internal and external hardware peripherals.
  • a userland level interface, with the help of libdrm/libkms libraries, to get access to the related hardware features, configuration and hardware acceleration.

  Examples of use cases involving the DRM/KMS framework:

  • Display an animated content on a DSI or RGB panel.
  • Configure the HDMI output to a given resolution and frame rate.
  • Activate the HDMI output among several available display outputs.
  • Create and manage memory buffers dedicated to the display, which contains graphical content (animations, 3D objects, videos…).
  • Get display timing information to efficiently adjust the speed of animated content.

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.

  • int min_width, min_height; int max_width, max_height; Minimum and maximum width and height of the frame buffers in pixel units.
  • struct drm_mode_config_funcs *funcs; Mode setting functions.
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 }

框图如下:
Linux DRM(三) -- DRM KMS/ Debug_第1张图片

2.System overview
Linux DRM(三) -- DRM KMS/ Debug_第2张图片
3.How to use the framework

3.1 modetest (DRM/KMS test tool)

  • The tool modetest provided by the libdrm library is useful to:
  • Perform basic tests: display a test pattern, display 2 layers, perform a vsync test
  • Specify the video mode: resolution and refresh rate
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 HDMI-A-1 is on connector id 29, is connected and supports a resolution of 1280x720-50.
  • the CRTC is on id 33

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:

  • the VGA-1 is on connector id 47, is connected and supports a resolution of 1600x1200-60.
  • the CRTC is id 39
    So the command to send a test pattern is:
 ./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初始化

  内核驱动提供了两种方法给用户空间完成显示功能。

  • 一种是通过DRM,可以通过ioctl,也可以通过用户空间封装的DRM库libdrm来完成。
  • 还有一种方法是通过以往标准的framebuffer去做,也是通过ioctl完成。

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(),这个函数用于设置电路相关的一些函数指针,比如睡眠/恢复调用,硬件重置,设置和处理中断请求,设置和获取时钟等等。

  • radeon_asic_setup (register asic specific callbacks)
    根据判断rdev->family,设置rdev->asic,例如rdev->asic = &btc_asic;
  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     },
  • radeon_asic_init: 调用radeon_asic_setup 注册的回调函数evergreen_init。
#define radeon_asic_init(rdev) (rdev)->asic->init((rdev))

  evergreen_init 调用流程图:
Linux DRM(三) -- DRM KMS/ Debug_第3张图片
  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

  • drm_helper_probe_detect
  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_i2c_init: 对显卡i2c线的初始化
  • radeon_crtc_init: crtc初始化,对于每个connector通路,都有一个相应的crtc 和encoder帮助其解析framebuffer信息。
  • radeon_setup_enc_conn:获得显卡的connector,并绑定相应的encoder。
  • radeon_hpd_init : 调用evergreen_hpd_init进行hpd 初始化。
  • radeon_fbdev_init : radeondrmfb 初始化。

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   
  • .fill_modes = drm_helper_probe_single_connector_modes,
    • ret = drm_helper_probe_detect(connector, &ctx, true); //如果使用vga ,调用 radeon_vga_detect
    • count = (*connector_funcs->get_modes)(connector); //如果使用vga,调用radeon_vga_get_modes
    • count = drm_add_override_edid_modes(connector);

    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 } 
  • radeon_connector_get_edid -> drm_get_edid 读取显示屏的edid获取支持的分辨率。

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:

  • Enable all the DRM/KMS logs:
    Board $> echo 0xff > /sys/module/drm/parameters/debug
  • Enable only driver DRM/KMS logs:
    Board $> echo 0x02 > /sys/module/drm/parameters/debug
  • Disable all DRM/KMS logs:
    Board $> echo 0 > /sys/module/drm/parameters/debug

5.2. 查看系统当前使用的哪个显卡驱动

  • hwinfo --display | grep “Driver Modules”
wenlian@uos-PC:$ hwinfo --display | grep "Driver Modules"
  Driver Modules: "radeon"
  • sudo lshw -c video
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.
  • lspci -k | grep -A 2 -E “(VGA|3D)”
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
  • glxinfo -B //show information about the GLX implementation
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 1221 16:57 card0 -> ../../devices/pci0000:00/0000:00:11.0/0000:05:00.0/drm/card0
lrwxrwxrwx 1 root root     0 1221 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 1221 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 1221 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 1221 16:57 renderD128 -> ../../devices/pci0000:00/0000:00:11.0/0000:05:00.0/drm/renderD128
lrwxrwxrwx 1 root root     0 1221 16:57 ttm -> ../../devices/virtual/drm/ttm
-r--r--r-- 1 root root 16384 1221 16:57 version


root@uos-PC:/sys/kernel/debug/dri/0# ls -l
总用量 0
-r--r--r-- 1 root root 0 1221 16:57 clients
drwxr-xr-x 2 root root 0 1221 16:57 crtc-0
drwxr-xr-x 2 root root 0 1221 16:57 crtc-1
drwxr-xr-x 2 root root 0 1221 16:57 DVI-D-1
-r--r--r-- 1 root root 0 1221 16:57 framebuffer
-r--r--r-- 1 root root 0 1221 16:57 gem_names
drwxr-xr-x 2 root root 0 1221 16:57 HDMI-A-1
-r--r--r-- 1 root root 0 1221 16:57 internal_clients
-r--r--r-- 1 root root 0 1221 16:57 name
-r--r--r-- 1 root root 0 1221 16:57 radeon_fence_info
-r--r--r-- 1 root root 0 1221 16:57 radeon_gem_info
-r--r--r-- 1 root root 0 1221 16:57 radeon_gpu_reset
-r--r--r-- 1 root root 0 1221 16:57 radeon_gtt
...

refer to

  • https://www.kernel.org/doc/html/latest/gpu/drm-internals.html
  • https://wiki.st.com/stm32mpu/wiki/DRM_KMS_overview

你可能感兴趣的:(DRM,drm)