Curious experiences with a Radeon on the fritz
Michael Witten
mfwitten at gmail.com
Wed Sep 21 11:52:19 PDT 2011
On Mon, 12 Sep 2011 18:13:46 -0000, Michael Witten wrote:
> I hope you find this adventure interesting, and I hope you
> provide me with some insight.
>
> Recently, I booted my computer, a Dell Latitude D810 that has a
> Radeon Mobility x600 (R300); all systems were waking up as normal:
>
> * The Dell logo popped up in some ancient VGA mode.
> * The GRUB menu appeared for 3 seconds as instructed.
> * Linux loaded and started spewing out log messages.
>
> and then:
>
> BAM!
>
> At around:
>
> 2011-09-09 20:27:07 +0000
>
> the Darkness overcame me; my laptop's LCD panel went black with nary
> a sign of life. After poking around a bit via ssh, I couldn't figure
> out what was going on; I had been running all the relevant code
> without trouble for some time now, so it just didn't make sense, and
> I began suspecting hardware failure.
>
> I strolled on over to freenode/#radeon, where I explained that I was
> still getting graphics at early boot time, but that it was dying
> shortly after Linux loaded. A one named Tari suggested that I boot
> with `nomodeset' in order to avoid anything more complicated than
> the standards of the Ancients.
>
> And Lo! With that very kernel command line parameter, the boot
> process did indeed land me safely in a working, albeit cramped
> VGA-backed virtual console.
>
> Searching the logs a bit more revealed the following:
>
> [drm:drm_calc_timestamping_constants] *ERROR* crtc 10: Can't
> calculate constants, dotclock = 0!
>
> Then (skipping a few interesting adventures), I ultimately discovered
> this kernel message:
>
> [drm] Panel Size 1920x4095
>
> which is curious indeed!, because my laptop's panel size should be
> `1920x1200'. I booted into the computer's BIOS only to find that
> it too was being fooled into thinking that the display dimensions
> are `1920x4095'.
>
> Why might this have happened? Are bits stuck? Did something get fried?
>
> Naturally, I set off to hardcode the right values into the DRM/KMS
> Radeon driver, and after overturning stones, scraping away ivy,
> digging tunnels, and wading through forgotten moats, I managed to
> make my way to the beginning of that labyrinthine beast, where I
> could successfully exert my will:
>
> diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
> index 6367524..9119dd6 100644
> --- a/drivers/gpu/drm/radeon/radeon_combios.c
> +++ b/drivers/gpu/drm/radeon/radeon_combios.c
> @@ -1245,7 +1245,7 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
> DRM_INFO("Panel ID String: %s\n", stmp);
>
> lvds->native_mode.hdisplay = RBIOS16(lcd_info + 0x19);
> - lvds->native_mode.vdisplay = RBIOS16(lcd_info + 0x1b);
> + lvds->native_mode.vdisplay = 1200; /*RBIOS16(lcd_info + 0x1b);*/
>
> DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.hdisplay,
> lvds->native_mode.vdisplay);
>
> With that small change, the driver in question loaded none the wiser,
> yielding a KMS-driven frame-buffer-backed virtual console as desired:
>
> [drm] radeon defaulting to kernel modesetting.
> [drm] radeon kernel modesetting enabled.
> ...
> [drm] Panel Size 1920x1200
> ...
> [drm] fb depth is 24
> [drm] pitch is 7680
> fbcon: radeondrmfb (fb0) is primary device
> Console: switching to colour frame buffer device 240x75
> fb0: radeondrmfb frame buffer device
>
> Unfortunately, X marks the spot where things get hairy again.
>
> Most noticeably, when I run:
>
> startx
>
> I get an Xorg.log that looks unblemished, yet X clearly renders the
> screen based on an erroneous DPI. In fact, even though Xorg.log
> clearly shows:
>
> (**) RADEON(0): Display dimensions: (331, 207) mm
> (**) RADEON(0): DPI set to (147, 147)
>
> I end up getting the following from xdpyinfo:
>
> dimensions: 1920x1200 pixels (507x317 millimeters)
> resolution: 96x96 dots per inch
>
> Why is this the case?
>
> Fortunately, I can solve the DPI issue by specifying the desired
> value directly on the command line:
>
> startx -- -dpi 147
>
> Why does this work when xorg.conf does not? (especially given that
> xorg.conf alone used to be enough to achieve the desired effect).
>
> Unfortunately, the troubles do not end there. Rudimentary benchmarking
> (playing 720p H.264 videos, running glxgears, etc.) indicates by low
> CPU usage that hardware acceleration is indeed enabled, which is in
> agreement with all the logs and diagnostics:
>
> Linux:
>
> [drm] radeon: 128M of VRAM memory ready
> [drm] radeon: 512M of GTT memory ready.
> ...
> [drm] radeon: 1 quad pipes, 1 Z pipes initialized.
> [drm] PCIE GART of 512M enabled (table at 0xD0040000).
>
> Xorg:
>
> (II) [KMS] Kernel modesetting enabled.
> ...
> (==) RADEON(0): Depth 24, (--) framebuffer bpp 32
> (II) RADEON(0): Pixel depth = 24 bits stored in 4 bytes (32 bpp pixmaps)
> (==) RADEON(0): Default visual is TrueColor
> (==) RADEON(0): RGB weight 888
> (II) RADEON(0): Using 8 bits per RGB (8 bit DAC)
> (--) RADEON(0): Chipset: "ATI Radeon Mobility X600 (M24) 3150 (PCIE)" (ChipID = 0x3150)
> ...
> (II) RADEON(0): KMS Color Tiling: enabled
> (II) RADEON(0): KMS Pageflipping: enabled
> (II) RADEON(0): SwapBuffers wait for vsync: enabled
> ...
> (++) RADEON(0): DPI set to (147, 147)
> ...
> (II) RADEON(0): [DRI2] Setup complete
> (II) RADEON(0): [DRI2] DRI driver: r300
> ...
> (II) RADEON(0): Direct rendering enabled
> (II) RADEON(0): Render acceleration enabled for R300/R400/R500 type cards.
> ...
> (II) EXA(0): Driver allocated offscreen pixmaps
> (II) EXA(0): Driver registered support for the following operations:
> (II) Solid
> (II) Copy
> (II) Composite (RENDER acceleration)
> (II) UploadToScreen
> (II) DownloadFromScreen
> (II) RADEON(0): Acceleration enabled > (==) RADEON(0): DPMS enabled
> (==) RADEON(0): Silken mouse enabled
> (II) RADEON(0): Set up textured video
> (II) RADEON(0): RandR 1.2 enabled, ignore the following RandR disabled message.
> (--) RandR disabled
> ...
> (II) AIGLX: enabled GLX_MESA_copy_sub_buffer
> (II) AIGLX: enabled GLX_INTEL_swap_event
> (II) AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control
> (II) AIGLX: enabled GLX_SGI_make_current_read
> (II) AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects
> (II) AIGLX: Loaded and initialized /usr/lib/xorg/modules/dri/r300_dri.so
> (II) GLX: Initialized DRI2 GL provider for screen 0
> (II) RADEON(0): Setting screen physical size to 331 x 207
>
> glxinfo:
>
> direct rendering: Yes
>
> However, within at least some colors, window locations, and so on,
> there is this strange but subtle flickering and subtle striation.
> The mouse kind of jitters about rather than moving smoothly; the
> frame rate seems too low, a fact that is confirmed by glxgears:
>
> $ glxgears
> Running synchronized to the vertical refresh. The framerate should
> be approximately the same as the monitor refresh rate.
> 99 frames in 5.0 seconds = 19.628 FPS
> 97 frames in 5.0 seconds = 19.285 FPS
> 97 frames in 5.0 seconds = 19.285 FPS
> 97 frames in 5.0 seconds = 19.285 FPS
> 97 frames in 5.0 seconds = 19.285 FPS
> 97 frames in 5.0 seconds = 19.285 FPS
>
> Note that while running glxgears, the CPU is hardly used at all, so
> the GPU is pulling its weight. (In contrast, when hardware acceleration
> is disabled, the CPU gets pegged at 100%, but more importantly, the FPS
> is no longer synchronized to the vertical refresh rate, so it actually
> becomes higher (at around 26 FPS), though there are still the same
> problems of flickering and striation).
>
> Thus, the vertical refresh rate is in fact the bottleneck. Consider
> these:
>
> Xorg:
>
> (II) RADEON(0): Printing probed modes for output LVDS
> (II) RADEON(0): Modeline "1920x1200"x9.4 162.00 1920 2016 2072 2160 1200 49753 49756 7985 (75.0 kHz)
> ...
> (II) RADEON(0): Output LVDS using initial mode 1920x1200
>
> xrandr --verbose:
>
> 1920x1200 (0x55) 162.0MHz *current +preferred
> h: width 1920 start 2016 end 2072 total 2160 skew 0 clock 75.0KHz
> v: height 1200 start 49753 end 49756 total 7985 clock 9.4Hz
>
> That's right: A vertical refresh of 9.4Hz! You can see from the
> vertical `start', `end', and `total' numbers in the xrandr output
> that something really bizarre is going on (there are other wrong
> data besides just the panel height).
>
> Is the striation from some kind of interlacing? (after all, 9.4*2 Hz
> is ALMOST near the FPS reported by glxgears).
>
> What other bits can I hardcode in the software? What might be failing?
>
> Interestingly, Xorg.conf and xrandr report other, seemingly correct
> modelines (which I assume are supplied by built-in alternatives):
>
> Xorg:
>
> (II) RADEON(0): Printing probed modes for output LVDS
> (II) RADEON(0): Modeline "1920x1200"x9.4 162.00 1920 2016 2072 2160 1200 49753 49756 7985 (75.0 kHz)
> (II) RADEON(0): Modeline "1920x1080"x60.0 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync (67.2 kHz)
> (II) RADEON(0): Modeline "1600x1200"x59.9 161.00 1600 1712 1880 2160 1200 1203 1207 1245 -hsync +vsync (74.5 kHz)
> (II) RADEON(0): Modeline "1680x1050"x60.0 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync (65.3 kHz)
> (II) RADEON(0): Modeline "1400x1050"x60.0 121.75 1400 1488 1632 1864 1050 1053 1057 1089 -hsync +vsync (65.3 kHz)
> (II) RADEON(0): Modeline "1280x1024"x59.9 109.00 1280 1368 1496 1712 1024 1027 1034 1063 -hsync +vsync (63.7 kHz)
> (II) RADEON(0): Modeline "1440x900"x59.9 106.50 1440 1528 1672 1904 900 903 909 934 -hsync +vsync (55.9 kHz)
> (II) RADEON(0): Modeline "1280x960"x59.9 101.25 1280 1360 1488 1696 960 963 967 996 -hsync +vsync (59.7 kHz)
> (II) RADEON(0): Modeline "1280x854"x59.9 89.25 1280 1352 1480 1680 854 857 867 887 -hsync +vsync (53.1 kHz)
> (II) RADEON(0): Modeline "1280x800"x59.8 83.50 1280 1352 1480 1680 800 803 809 831 -hsync +vsync (49.7 kHz)
> (II) RADEON(0): Modeline "1280x720"x59.9 74.50 1280 1344 1472 1664 720 723 728 748 -hsync +vsync (44.8 kHz)
> (II) RADEON(0): Modeline "1152x768"x59.8 71.75 1152 1216 1328 1504 768 771 781 798 -hsync +vsync (47.7 kHz)
> (II) RADEON(0): Modeline "1024x768"x59.9 63.50 1024 1072 1176 1328 768 771 775 798 -hsync +vsync (47.8 kHz)
> (II) RADEON(0): Modeline "800x600"x59.9 38.25 800 832 912 1024 600 603 607 624 -hsync +vsync (37.4 kHz)
> (II) RADEON(0): Modeline "848x480"x59.7 31.50 848 872 952 1056 480 483 493 500 -hsync +vsync (29.8 kHz)
> (II) RADEON(0): Modeline "720x480"x59.7 26.75 720 744 808 896 480 483 493 500 -hsync +vsync (29.9 kHz)
> (II) RADEON(0): Modeline "640x480"x59.4 23.75 640 664 720 800 480 483 487 500 -hsync +vsync (29.7 kHz)
> ...
> (II) RADEON(0): Output LVDS using initial mode 1920x1200
>
> xrandr:
>
> 1920x1200 (0x55) 162.0MHz +preferred
> h: width 1920 start 2016 end 2072 total 2160 skew 0 clock 75.0KHz
> v: height 1200 start 49753 end 49756 total 7985 clock 9.4Hz
> 1920x1080 (0x56) 173.0MHz -HSync +VSync
> h: width 1920 start 2048 end 2248 total 2576 skew 0 clock 67.2KHz
> v: height 1080 start 1083 end 1088 total 1120 clock 60.0Hz
> 1600x1200 (0x57) 161.0MHz -HSync +VSync
> h: width 1600 start 1712 end 1880 total 2160 skew 0 clock 74.5KHz
> v: height 1200 start 1203 end 1207 total 1245 clock 59.9Hz
> 1680x1050 (0x58) 146.2MHz -HSync +VSync
> h: width 1680 start 1784 end 1960 total 2240 skew 0 clock 65.3KHz
> v: height 1050 start 1053 end 1059 total 1089 clock 60.0Hz
> 1400x1050 (0x59) 121.8MHz -HSync +VSync
> h: width 1400 start 1488 end 1632 total 1864 skew 0 clock 65.3KHz
> v: height 1050 start 1053 end 1057 total 1089 clock 60.0Hz
> 1280x1024 (0x5a) 109.0MHz -HSync +VSync
> h: width 1280 start 1368 end 1496 total 1712 skew 0 clock 63.7KHz
> v: height 1024 start 1027 end 1034 total 1063 clock 59.9Hz
> 1440x900 (0x5b) 106.5MHz -HSync +VSync
> h: width 1440 start 1528 end 1672 total 1904 skew 0 clock 55.9KHz
> v: height 900 start 903 end 909 total 934 clock 59.9Hz
> 1280x960 (0x5c) 101.2MHz -HSync +VSync
> h: width 1280 start 1360 end 1488 total 1696 skew 0 clock 59.7KHz
> v: height 960 start 963 end 967 total 996 clock 59.9Hz
> 1280x854 (0x5d) 89.2MHz -HSync +VSync
> h: width 1280 start 1352 end 1480 total 1680 skew 0 clock 53.1KHz
> v: height 854 start 857 end 867 total 887 clock 59.9Hz
> 1280x800 (0x5e) 83.5MHz -HSync +VSync
> h: width 1280 start 1352 end 1480 total 1680 skew 0 clock 49.7KHz
> v: height 800 start 803 end 809 total 831 clock 59.8Hz
> 1280x720 (0x5f) 74.5MHz -HSync +VSync
> h: width 1280 start 1344 end 1472 total 1664 skew 0 clock 44.8KHz
> v: height 720 start 723 end 728 total 748 clock 59.9Hz
> 1152x768 (0x60) 71.8MHz -HSync +VSync
> h: width 1152 start 1216 end 1328 total 1504 skew 0 clock 47.7KHz
> v: height 768 start 771 end 781 total 798 clock 59.8Hz
> 1024x768 (0x61) 63.5MHz -HSync +VSync
> h: width 1024 start 1072 end 1176 total 1328 skew 0 clock 47.8KHz
> v: height 768 start 771 end 775 total 798 clock 59.9Hz
> 800x600 (0x62) 38.2MHz -HSync +VSync
> h: width 800 start 832 end 912 total 1024 skew 0 clock 37.4KHz
> v: height 600 start 603 end 607 total 624 clock 59.9Hz
> 848x480 (0x63) 31.5MHz -HSync +VSync
> h: width 848 start 872 end 952 total 1056 skew 0 clock 29.8KHz
> v: height 480 start 483 end 493 total 500 clock 59.7Hz
> 720x480 (0x64) 26.8MHz -HSync +VSync
> h: width 720 start 744 end 808 total 896 skew 0 clock 29.9KHz
> v: height 480 start 483 end 493 total 500 clock 59.7Hz
> 640x480 (0x65) 23.8MHz -HSync +VSync
> h: width 640 start 664 end 720 total 800 skew 0 clock 29.7KHz
> v: height 480 start 483 end 487 total 500 clock 59.4Hz
>
> However, switching to one of these other modes or defining my own
> through xorg.conf does nothing to fix the troubles; while the
> resolution does change, the flickering and striation remain, and
> glxgears continues to report the same 19+ FPS.
>
> Is there anything that can be done to work around these last
> troubles?
>
> Sincerely,
> Michael Witten
>
> P.S.
>
> I'm running i686 Linux 3.1.0-rc5, specifically this commit
> (with my patch):
>
> 473e2bc9d3649e072d0a1bff84afa95b072d056b
Woops! That should be:
79016f648872549392d232cd648bd02298c2d2bb
> and:
>
> X.Org X Server 1.10.3.901 (1.10.4 RC 1)
> Release Date: 2011-07-29
> X Protocol Version 11, Revision 0
> Kernel command line: root=/dev/sda2 ro 3
> Build Date: 08 August 2011 08:28:07AM
> Current version of pixman: 0.22.2
After talking it over with the following people on freenode/#radeon:
airlied
mjg59
MrCooper
it was decided that I should hardcode a ModeLine into the same
function into which I had already hardcoded the vertical resolution:
radeon_combios_get_lvds_info()
I used the following:
http://www.arachnoid.com/modelines/index.html
to caclculate this `frame buffer' mode:
mode "1920x1200 60Hz 32bit (GTF)"
# PCLK: 193.16 MHz, H: 74.52 kHz, V: 60.00 Hz
geometry 1920 1200 1920 1200 32
timings 5177 336 128 38 1 208 3
hsync low
vsync high
endmode
and this Xorg ModeLine (which I used directly to hardcode the values):
# 1920x1200 @ 60.00 Hz (GTF) hsync: 74.52 kHz; pclk: 193.16 MHz
ModeLine "1920x1200_60.00" 193.16 1920 2048 2256 2592 1200 1201 1204 1242 -HSync +Vsync
Here is the resulting patch to 79016f648872549392d232cd648bd02298c2d2bb
(more or less):
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 6367524..833ed97 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -1244,8 +1244,8 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
DRM_INFO("Panel ID String: %s\n", stmp);
- lvds->native_mode.hdisplay = RBIOS16(lcd_info + 0x19);
- lvds->native_mode.vdisplay = RBIOS16(lcd_info + 0x1b);
+ lvds->native_mode.hdisplay = 1920;
+ lvds->native_mode.vdisplay = 1200;
DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.hdisplay,
lvds->native_mode.vdisplay);
@@ -1300,34 +1300,21 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
lvds->lvds_gen_cntl |= (panel_setup & 0xf0000000);
- for (i = 0; i < 32; i++) {
- tmp = RBIOS16(lcd_info + 64 + i * 2);
- if (tmp == 0)
- break;
-
- if ((RBIOS16(tmp) == lvds->native_mode.hdisplay) &&
- (RBIOS16(tmp + 2) == lvds->native_mode.vdisplay)) {
- lvds->native_mode.htotal = lvds->native_mode.hdisplay +
- (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8;
- lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
- (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) - 1) * 8;
- lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
- (RBIOS8(tmp + 23) * 8);
-
- lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
- (RBIOS16(tmp + 24) - RBIOS16(tmp + 26));
- lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
- ((RBIOS16(tmp + 28) & 0x7ff) - RBIOS16(tmp + 26));
- lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
- ((RBIOS16(tmp + 28) & 0xf800) >> 11);
-
- lvds->native_mode.clock = RBIOS16(tmp + 9) * 10;
- lvds->native_mode.flags = 0;
- /* set crtc values */
- drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
-
- }
- }
+ lvds->native_mode.htotal = 2592;
+ lvds->native_mode.hsync_start = 2048;
+ lvds->native_mode.hsync_end = 2256;
+
+ lvds->native_mode.vtotal = 1242;
+ lvds->native_mode.vsync_start = 1201;
+ lvds->native_mode.vsync_end = 1204;
+
+ /* kHz */
+ lvds->native_mode.clock = 193160;
+ lvds->native_mode.flags = 0;
+
+ /* set crtc values */
+ drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
+
} else {
DRM_INFO("No panel info found in BIOS\n");
lvds = radeon_legacy_get_lvds_info_from_regs(rdev);
This indeed fixed nearly all of the problems; the flickering and
striations disappeared, but Xorg still refuses to set the DPI
to the value that I specify in Xorg.conf (I have to use the command
line option `-dpi' instead).
Because my hardware does appear to be malfunctioning due to a corrupt
video BIOS, it seems prudent to salvage as much as possible from
its output, so that it is possible to figure out which other values
need to be hardcoded in case of further corruption.
To do this, I did 2 things:
* Export the video BIOS data via debugfs, so that it can be
easily backed up in secondary storage.
* Hack the existing Radeon driver code to log information
about which values are being read from the video BIOS
data and from which offsets these values are being read.
I first wrote the following patch to export the video BIOS via debugfs
(I wrote a little more than necessary; it should be generally applicable):
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 32807ba..95aa0a6 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1171,6 +1171,7 @@ struct radeon_device {
int disp_priority;
/* BIOS */
uint8_t *bios;
+ size_t bios_size;
bool is_atom_bios;
uint16_t bios_header_start;
struct radeon_bo *stollen_vga_memory;
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 229a20f..c54e6a6 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -53,6 +53,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
return false;
rdev->bios = NULL;
+ rdev->bios_size = 0;
vram_base = pci_resource_start(rdev->pdev, 0);
bios = ioremap(vram_base, size);
if (!bios) {
@@ -69,6 +70,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
return false;
}
memcpy_fromio(rdev->bios, bios, size);
+ rdev->bios_size = size;
iounmap(bios);
return true;
}
@@ -79,6 +81,7 @@ static bool radeon_read_bios(struct radeon_device *rdev)
size_t size;
rdev->bios = NULL;
+ rdev->bios_size = 0;
/* XXX: some cards may return 0 for rom size? ddx has a workaround */
bios = pci_map_rom(rdev->pdev, &size);
if (!bios) {
@@ -94,6 +97,7 @@ static bool radeon_read_bios(struct radeon_device *rdev)
pci_unmap_rom(rdev->pdev, bios);
return false;
}
+ rdev->bios_size = size;
pci_unmap_rom(rdev->pdev, bios);
return true;
}
@@ -110,6 +114,7 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
if (!radeon_atrm_supported(rdev->pdev))
return false;
+ rdev->bios_size = 0;
rdev->bios = kmalloc(size, GFP_KERNEL);
if (!rdev->bios) {
DRM_ERROR("Unable to allocate bios\n");
@@ -128,6 +133,7 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
kfree(rdev->bios);
return false;
}
+ rdev->bios_size = size;
return true;
}
@@ -476,6 +482,40 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
return legacy_read_disabled_bios(rdev);
}
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+#define SEQ_FILE_TO_RADEON(m) \
+ ((struct radeon_device*) \
+ ((struct drm_info_node*)m->private)->minor->dev->dev_private)
+
+static int radeon_debugfs_bios_info(struct seq_file *m, void *data)
+{
+ struct radeon_device *r = SEQ_FILE_TO_RADEON(m);
+ seq_write(m, r->bios, r->bios_size);
+ return 0;
+}
+
+static int radeon_debugfs_bios_size_info(struct seq_file *m, void *data)
+{
+ struct radeon_device *r = SEQ_FILE_TO_RADEON(m);
+ seq_printf(m, "%d bytes\n", r->bios_size);
+ return 0;
+}
+
+static int radeon_debugfs_bios_init(struct radeon_device *r)
+{
+ static struct drm_info_list i[] = {
+ {"bios", radeon_debugfs_bios_info},
+ {"bios_size", radeon_debugfs_bios_size_info}
+ };
+
+ radeon_debugfs_add_files(r, i, ARRAY_SIZE(i));
+
+ return 0;
+}
+#undef SEQ_FILE_TO_RADEON
+#endif
bool radeon_get_bios(struct radeon_device *rdev)
{
@@ -510,6 +550,13 @@ bool radeon_get_bios(struct radeon_device *rdev)
if (!rdev->bios_header_start) {
goto free_bios;
}
+
+#ifdef CONFIG_DEBUG_FS
+ if (radeon_debugfs_bios_init(rdev)) {
+ DRM_ERROR("Unable to create debugfs file for the BIOS ROM\n");
+ }
+#endif
+
tmp = rdev->bios_header_start + 4;
if (!memcmp(rdev->bios + tmp, "ATOM", 4) ||
!memcmp(rdev->bios + tmp, "MOTA", 4)) {
Then, to make the backup, I just needed to mount debugfs and copy
as usual:
$ sudo mount -t debugfs none /sys/kernel/debug
$ cp /sys/kernel/debug/dri/0/bios ~/bios-BWAHAHAHAHAAA\!
$ mv ~/bios-BWAHAHAHAHAAA\! ~/bios # Let's not be silly
Of course, it's really tedious to parse that binary blob, especially
when there are currently 112 values that are needed for my system,
many of which are at offsets derived from the other values).
Consequently, I created the following monstrous GCC-specific hack
to make use of the existing Radeon driver code for logging what the
values are and where they are located (the macro function `RBIOS_INFO'
expands into what GCC calls:
a statement-expression
which is mainly useful for expanding macro functions without resulting
in any repetitive evaluation of expressions that produce side-effects;
of course, maybe this hack was necessary in this case because of the
macro hacks already in place...):
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 95aa0a6..2960483 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1400,9 +1400,26 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
/*
* BIOS helpers.
*/
-#define RBIOS8(i) (rdev->bios[i])
-#define RBIOS16(i) (RBIOS8(i) | (RBIOS8((i)+1) << 8))
-#define RBIOS32(i) ((RBIOS16(i)) | (RBIOS16((i)+2) << 16))
+#define RBIOS8_REAL(i) (rdev->bios[i])
+#define RBIOS16_REAL(i) (RBIOS8_REAL(i) | (RBIOS8_REAL((i)+1) << 8))
+#define RBIOS32_REAL(i) ((RBIOS16_REAL(i)) | (RBIOS16_REAL((i)+2) << 16))
+
+#define MKSTR_REALLY(s) #s
+#define MKSTR(s) MKSTR_REALLY(s)
+
+#define RBIOS_INFO(i,f) ({ \
+ typeof(i) j = i; \
+ unsigned int r = f##_REAL(j); \
+ DRM_INFO( \
+ __FILE__":"MKSTR(__LINE__)":%s:"#f"("#i" => 0x%x) => u%u => s%d => 0x%x",\
+ __func__, j, r, r, r \
+ ); \
+ r; \
+})
+
+#define RBIOS8(i) RBIOS_INFO(i,RBIOS8 )
+#define RBIOS16(i) RBIOS_INFO(i,RBIOS16)
+#define RBIOS32(i) RBIOS_INFO(i,RBIOS32)
int radeon_combios_init(struct radeon_device *rdev);
void radeon_combios_fini(struct radeon_device *rdev);
The relevant dmesg output can be gotten with the following:
$ dmesg | sed -n '/RBIOS/s_^.*drivers/gpu/drm/radeon/__p'
which produced:
radeon_bios.c:543:radeon_get_bios:RBIOS16(0x18 => 0x18) => u380 => s380 => 0x17c
radeon_bios.c:544:radeon_get_bios:RBIOS8(tmp + 0x14 => 0x190) => u0 => s0 => 0x0
radeon_bios.c:549:radeon_get_bios:RBIOS16(0x48 => 0x48) => u272 => s272 => 0x110
radeon_combios.c:184:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x30 => 0x140) => u3544 => s3544 => 0xdd8
radeon_combios.c:810:radeon_combios_get_clock_info:RBIOS8(pll_info => 0xdd8) => u10 => s10 => 0xa
radeon_combios.c:813:radeon_combios_get_clock_info:RBIOS16(pll_info + 0xe => 0xde6) => u2700 => s2700 => 0xa8c
radeon_combios.c:814:radeon_combios_get_clock_info:RBIOS16(pll_info + 0x10 => 0xde8) => u6 => s6 => 0x6
radeon_combios.c:815:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x12 => 0xdea) => u20000 => s20000 => 0x4e20
radeon_combios.c:816:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x16 => 0xdee) => u35000 => s35000 => 0x88b8
radeon_combios.c:821:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x36 => 0xe0e) => u40 => s40 => 0x28
radeon_combios.c:822:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x3a => 0xe12) => u3000 => s3000 => 0xbb8
radeon_combios.c:830:radeon_combios_get_clock_info:RBIOS16(pll_info + 0x1a => 0xdf2) => u2700 => s2700 => 0xa8c
radeon_combios.c:831:radeon_combios_get_clock_info:RBIOS16(pll_info + 0x1c => 0xdf4) => u4 => s4 => 0x4
radeon_combios.c:832:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x1e => 0xdf6) => u25000 => s25000 => 0x61a8
radeon_combios.c:833:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x22 => 0xdfa) => u80000 => s80000 => 0x13880
radeon_combios.c:845:radeon_combios_get_clock_info:RBIOS16(pll_info + 0x26 => 0xdfe) => u2700 => s2700 => 0xa8c
radeon_combios.c:846:radeon_combios_get_clock_info:RBIOS16(pll_info + 0x28 => 0xe00) => u4 => s4 => 0x4
radeon_combios.c:847:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x2a => 0xe02) => u25000 => s25000 => 0x61a8
radeon_combios.c:848:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x2e => 0xe06) => u75000 => s75000 => 0x124f8
radeon_combios.c:860:radeon_combios_get_clock_info:RBIOS16(pll_info + 0xa => 0xde2) => u39825 => s39825 => 0x9b91
radeon_combios.c:861:radeon_combios_get_clock_info:RBIOS16(pll_info + 0x8 => 0xde0) => u26325 => s26325 => 0x66d5
radeon_combios.c:870:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x16 => 0xdee) => u35000 => s35000 => 0x88b8
radeon_combios.c:871:radeon_combios_get_clock_info:RBIOS32(pll_info + 0x16 => 0xdee) => u35000 => s35000 => 0x88b8
radeon_combios.c:239:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x4c => 0x15c) => u0 => s0 => 0x0
radeon_combios.c:249:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x50 => 0x160) => u2169 => s2169 => 0x879
radeon_combios.c:2286:radeon_get_legacy_connector_info_from_bios:RBIOS16(entry => 0x87b) => u8960 => s8960 => 0x2300
radeon_combios.c:2289:radeon_get_legacy_connector_info_from_bios:RBIOS16(entry => 0x87b) => u8960 => s8960 => 0x2300
radeon_combios.c:284:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x60 => 0x170) => u532 => s532 => 0x214
radeon_combios.c:946:radeon_combios_get_primary_dac_info:RBIOS8(dac_info => 0x214) => u1 => s1 => 0x1
radeon_combios.c:948:radeon_combios_get_primary_dac_info:RBIOS8(dac_info + 0x2 => 0x216) => u136 => s136 => 0x88
radeon_combios.c:949:radeon_combios_get_primary_dac_info:RBIOS8(dac_info + 0x2 => 0x216) => u136 => s136 => 0x88
radeon_combios.c:2286:radeon_get_legacy_connector_info_from_bios:RBIOS16(entry => 0x87d) => u16896 => s16896 => 0x4200
radeon_combios.c:2289:radeon_get_legacy_connector_info_from_bios:RBIOS16(entry => 0x87d) => u16896 => s16896 => 0x4200
radeon_combios.c:194:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x34 => 0x144) => u2177 => s2177 => 0x881
radeon_combios.c:1426:radeon_legacy_get_tmds_info_from_combios:RBIOS8(tmds_info => 0x881) => u4 => s4 => 0x4
radeon_combios.c:1443:radeon_legacy_get_tmds_info_from_combios:RBIOS8(tmds_info + 5 => 0x886) => u2 => s2 => 0x2
radeon_combios.c:1448:radeon_legacy_get_tmds_info_from_combios:RBIOS32(tmds_info + stride + 0x08 => 0x889) => u532611350 => s532611350 => 0x1fbf0116
radeon_combios.c:1450:radeon_legacy_get_tmds_info_from_combios:RBIOS16(tmds_info + stride + 0x10 => 0x891) => u16600 => s16600 => 0x40d8
radeon_combios.c:1448:radeon_legacy_get_tmds_info_from_combios:RBIOS32(tmds_info + stride + 0x08 => 0x893) => u532611350 => s532611350 => 0x1fbf0116
radeon_combios.c:1450:radeon_legacy_get_tmds_info_from_combios:RBIOS16(tmds_info + stride + 0x10 => 0x89b) => u20000 => s20000 => 0x4e20
radeon_combios.c:1448:radeon_legacy_get_tmds_info_from_combios:RBIOS32(tmds_info + stride + 0x08 => 0x899) => u1310720006 => s1310720006 => 0x4e200006
radeon_combios.c:1450:radeon_legacy_get_tmds_info_from_combios:RBIOS16(tmds_info + stride + 0x10 => 0x8a1) => u0 => s0 => 0x0
radeon_combios.c:2286:radeon_get_legacy_connector_info_from_bios:RBIOS16(entry => 0x87f) => u0 => s0 => 0x0
radeon_combios.c:214:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x40 => 0x150) => u62432 => s62432 => 0xf3e0
radeon_combios.c:219:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x42 => 0x152) => u2211 => s2211 => 0x8a3
radeon_combios.c:409:combios_get_table_offset:RBIOS16(check_offset + 0x15 => 0x8b8) => u2241 => s2241 => 0x8c1
radeon_combios.c:214:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x40 => 0x150) => u62432 => s62432 => 0xf3e0
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e1) => u82 => s82 => 0x52
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e2) => u67 => s67 => 0x43
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e3) => u57 => s57 => 0x39
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e4) => u48 => s48 => 0x30
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e5) => u57 => s57 => 0x39
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e6) => u49 => s49 => 0x31
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e7) => u49 => s49 => 0x31
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e8) => u53 => s53 => 0x35
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3e9) => u52 => s52 => 0x34
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3ea) => u87 => s87 => 0x57
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3eb) => u85 => s85 => 0x55
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3ec) => u49 => s49 => 0x31
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3ed) => u10 => s10 => 0xa
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3ee) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3ef) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f0) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f1) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f2) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f3) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f4) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f5) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f6) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f7) => u32 => s32 => 0x20
radeon_combios.c:1242:radeon_combios_get_lvds_info:RBIOS8(lcd_info + i + 1 => 0xf3f8) => u32 => s32 => 0x20
radeon_combios.c:1253:radeon_combios_get_lvds_info:RBIOS16(lcd_info + 0x2c => 0xf40c) => u1000 => s1000 => 0x3e8
radeon_combios.c:1256:radeon_combios_get_lvds_info:RBIOS8(lcd_info + 0x24 => 0xf404) => u10 => s10 => 0xa
radeon_combios.c:1257:radeon_combios_get_lvds_info:RBIOS16(lcd_info + 0x38 => 0xf418) => u4257 => s4257 => 0x10a1
radeon_combios.c:1258:radeon_combios_get_lvds_info:RBIOS16(lcd_info + 0x38 => 0xf418) => u4257 => s4257 => 0x10a1
radeon_combios.c:1260:radeon_combios_get_lvds_info:RBIOS16(lcd_info + 0x2e => 0xf40e) => u6 => s6 => 0x6
radeon_combios.c:1261:radeon_combios_get_lvds_info:RBIOS8(lcd_info + 0x30 => 0xf410) => u0 => s0 => 0x0
radeon_combios.c:1262:radeon_combios_get_lvds_info:RBIOS16(lcd_info + 0x31 => 0xf411) => u36 => s36 => 0x24
radeon_combios.c:1267:radeon_combios_get_lvds_info:RBIOS32(lcd_info + 0x39 => 0xf419) => u197136 => s197136 => 0x30210
radeon_combios.c:2515:radeon_get_legacy_connector_info_from_bios:RBIOS8(lcd_ddc_info + 2 => 0x8c3) => u0 => s0 => 0x0
radeon_combios.c:189:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x32 => 0x142) => u51426 => s51426 => 0xc8e2
radeon_combios.c:2558:radeon_get_legacy_connector_info_from_bios:RBIOS8(tv_info + 6 => 0xc8e8) => u84 => s84 => 0x54
radeon_combios.c:189:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x32 => 0x142) => u51426 => s51426 => 0xc8e2
radeon_combios.c:1080:radeon_combios_get_tv_dac_info:RBIOS8(dac_info + 0x3 => 0xc8e5) => u2 => s2 => 0x2
radeon_combios.c:1097:radeon_combios_get_tv_dac_info:RBIOS8(dac_info + 0xc => 0xc8ee) => u133 => s133 => 0x85
radeon_combios.c:1098:radeon_combios_get_tv_dac_info:RBIOS8(dac_info + 0xc => 0xc8ee) => u133 => s133 => 0x85
radeon_combios.c:1101:radeon_combios_get_tv_dac_info:RBIOS8(dac_info + 0xd => 0xc8ef) => u133 => s133 => 0x85
radeon_combios.c:1102:radeon_combios_get_tv_dac_info:RBIOS8(dac_info + 0xd => 0xc8ef) => u133 => s133 => 0x85
radeon_combios.c:1105:radeon_combios_get_tv_dac_info:RBIOS8(dac_info + 0xe => 0xc8f0) => u133 => s133 => 0x85
radeon_combios.c:1106:radeon_combios_get_tv_dac_info:RBIOS8(dac_info + 0xe => 0xc8f0) => u133 => s133 => 0x85
radeon_combios.c:189:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x32 => 0x142) => u51426 => s51426 => 0xc8e2
radeon_combios.c:976:radeon_combios_get_tv_info:RBIOS8(tv_info + 6 => 0xc8e8) => u84 => s84 => 0x54
radeon_combios.c:977:radeon_combios_get_tv_info:RBIOS8(tv_info + 7 => 0xc8e9) => u1 => s1 => 0x1
radeon_combios.c:1009:radeon_combios_get_tv_info:RBIOS8(tv_info + 9 => 0xc8eb) => u15 => s15 => 0xf
radeon_combios.c:189:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x32 => 0x142) => u51426 => s51426 => 0xc8e2
radeon_combios.c:976:radeon_combios_get_tv_info:RBIOS8(tv_info + 6 => 0xc8e8) => u84 => s84 => 0x54
radeon_combios.c:977:radeon_combios_get_tv_info:RBIOS8(tv_info + 7 => 0xc8e9) => u1 => s1 => 0x1
radeon_combios.c:1009:radeon_combios_get_tv_info:RBIOS8(tv_info + 9 => 0xc8eb) => u15 => s15 => 0xf
radeon_combios.c:304:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x68 => 0x178) => u0 => s0 => 0x0
radeon_combios.c:219:combios_get_table_offset:RBIOS16(rdev->bios_header_start + 0x42 => 0x152) => u2211 => s2211 => 0x8a3
radeon_combios.c:391:combios_get_table_offset:RBIOS16(check_offset + 0x11 => 0x8b4) => u2255 => s2255 => 0x8cf
radeon_combios.c:2680:radeon_combios_get_power_modes:RBIOS8(offset => 0x8cf) => u7 => s7 => 0x7
radeon_combios.c:2681:radeon_combios_get_power_modes:RBIOS8(offset + 0x2 => 0x8d1) => u4 => s4 => 0x4
radeon_combios.c:2684:radeon_combios_get_power_modes:RBIOS32(offset + 0x5 + 0x2 => 0x8d6) => u12000 => s12000 => 0x2ee0
radeon_combios.c:2685:radeon_combios_get_power_modes:RBIOS32(offset + 0x5 + 0x6 => 0x8da) => u10000 => s10000 => 0x2710
radeon_combios.c:2691:radeon_combios_get_power_modes:RBIOS16(offset + 0x5 + 0x0 => 0x8d4) => u29820 => s29820 => 0x747c
radeon_combios.c:2693:radeon_combios_get_power_modes:RBIOS16(offset + 0x5 + 0xe => 0x8e2) => u2 => s2 => 0x2
radeon_combios.c:2711:radeon_combios_get_power_modes:RBIOS8(offset + 0x5 + 0xb => 0x8df) => u1 => s1 => 0x1
radeon_combios.c:2712:radeon_combios_get_power_modes:RBIOS16(offset + 0x5 + 0xc => 0x8e0) => u2252 => s2252 => 0x8cc
radeon_combios.c:2715:radeon_combios_get_power_modes:RBIOS16(voltage_table_offset => 0x8cc) => u103 => s103 => 0x67
radeon_combios.c:2716:radeon_combios_get_power_modes:RBIOS8(voltage_table_offset + 0x2 => 0x8ce) => u15 => s15 => 0xf
radeon_combios.c:2743:radeon_combios_get_power_modes:RBIOS8(offset + 0x5 + 0x10 => 0x8e4) => u1 => s1 => 0x1
I would be mightily interested in the results that can be gotten on
a fully working system. Please contact me if you have access to the
following hardware:
Dell Latitude D810
ATI Technologies Inc M24 1P [Radeon Mobility X600]
Sincerely,
Michael Witten
More information about the dri-devel
mailing list