#!/usr/bin/env python2 # -*- coding: utf-8 -*- # Copyright (C) 2014 Michał Masłowski # # Licensed under copyleft-next version 0.3.0. See # https://gitorious.org/copyleft-next/copyleft-next/raw/master:Releases/copyleft-next-0.3.0 # for more information. """Get values of interesting i945 graphics parameters from a running system. This script might show the values for GPU registers specified in devicetree.cb on coreboot mainboard ports using i945 native VGA init from . Run as root. """ import mmap import re import struct import subprocess _MEMORY = re.compile(r"^\s+Memory\s+at\s+([0-9a-f]+)\s+\(32-bit, non-prefetchable\)\s+\[size=[0-9]+K\]$") def get_pci_data(): # lspci has a machine readable format, but it doesn't have the needed data. for devid in ("8086:27a2",): lspci = subprocess.Popen(("lspci", "-vn", "-d", devid), stdout=subprocess.PIPE, stderr=subprocess.PIPE) address = None memory = None for line in lspci.communicate()[0].split("\n"): if line and line[0] == "0": address = line.split()[0] match = _MEMORY.match(line) if match is not None: memory = int(match.group(1), 16) break yield (address, memory) def config_byte(address, offset): """Return byte at specified offset in PCI config space of device identified by address.""" with open("/sys/bus/pci/devices/0000:%s/config" % address, "rb") as f: f.seek(offset) return struct.unpack("=B", f.read(1)) addr0, func0 = list(get_pci_data())[0] def read32(fo, base, offset): memory = mmap.mmap(fo.fileno(), offset + 4, mmap.MAP_SHARED, mmap.ACCESS_READ, offset=base) try: memory.seek(offset) val = memory.read(4) return struct.unpack("=I", val)[0] finally: memory.close() # Some i915 register names. PORT_HOTPLUG_EN = 0x61110 BLC_PWM_CTL = 0x61254 LVDS = 0x61180 # Bits in LVDS. LVDS_CLOCK_B_POWERUP_ALL = 3 << 4 LVDS_CLOCK_BOTH_POWERUP_ALL = 3 << 2 # Expansion of DPLL(1). DPLL1 = ((0x06014) + (1)*((0x06018)-(0x06014))) # Bits there. DPLL_INTEGRATED_CLOCK_VLV = (1<<13) DPLL_INTEGRATED_CRI_CLK_VLV = (1<<14) if __name__ == "__main__": with open("/dev/mem", "rb") as mem: print "gpu_hotplug = 0x%08x" % read32(mem, func0, PORT_HOTPLUG_EN) dpll = read32(mem, func0, DPLL1) spread_spectrum = dpll & (DPLL_INTEGRATED_CLOCK_VLV \ | DPLL_INTEGRATED_CRI_CLK_VLV) if spread_spectrum != 0: spread_spectrum = 1 print "gpu_lvds_use_spread_spectrum_clock = %d" % spread_spectrum lvds = read32(mem, func0, LVDS) dual_channel = lvds & (LVDS_CLOCK_B_POWERUP_ALL \ | LVDS_CLOCK_BOTH_POWERUP_ALL) if dual_channel != 0: dual_channel = 1 print "gpu_lvds_is_dual_channel = %d" % dual_channel backlight = read32(mem, func0, BLC_PWM_CTL) print "gpu_backlight = 0x%08x" % backlight # Using display clock from i945_get_display_clock_speed in # drivers/gpu/drm/i915/intel_display.c. Result multiplied by # two to match BIOS-reported PWM frequency on my X60t. mod_freq = 2 * 400000000 / ((backlight >> 16) * 128.0) print "backlight modulation frequency = %f Hz" % mod_freq print "duty cycle = %d%%" % (100.0 * (backlight & 0xffff) / (backlight >> 16)) print "legacy backlight brightness = 0x%02x" % config_byte(addr0, 0xf4)