/* Copyright (C) 2014 Michał Masłowski This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* Try several backlight PWM frequencies and duty cycles to see which expose the noise on X60 with coreboot. */ #include #include #include #include #include #include #include #include #include #include static struct pci_access *pacc; static uint32_t *map; static int fd; #define REGISTER 0x61254 static void init (void) { fd = -1; /* Find the device. */ struct pci_dev *dev; pacc = pci_alloc (); pacc->writeable = 1; pci_init (pacc); pci_scan_bus (pacc); for (dev = pacc->devices; dev != NULL; dev = dev->next) { pci_fill_info (dev, PCI_FILL_IDENT | PCI_FILL_BASES); if (dev->vendor_id != 0x8086 || dev->device_id != 0x27a2) continue; break; } if (dev == NULL) { fprintf (stderr, "Device not found.\n"); goto fail; } /* Map a part of its MMIO. */ fd = open ("/dev/mem", O_RDWR); if (fd == -1) { fprintf (stderr, "Cannot open memory. Are you root?\n"); goto fail; } map = mmap (NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, dev->base_addr[0] + (REGISTER & (~4095))); if (map != MAP_FAILED) return; else perror ("mmap failed"); fail: if (pacc != NULL) pci_cleanup (pacc); if (fd != -1) close (fd); exit (1); } static void set_pwm (uint16_t freq, uint16_t duty) { assert (duty <= freq); map[((REGISTER - 4) & 4095) >> 2] = 0x80000000; map[(REGISTER & 4095) >> 2] = ((freq | 1) << 16) | duty; } int main (void) { init (); int exponent = 8; int diff = 0; int divisor = 2; uint16_t freq = 0x61; uint16_t duties[] = { #if 1 // i945 0xf, 0x13, 0x19, 0x1f, 0x23, 0x29, 0x2f, 0x35, 0x39, 0x3f, 0x45, 0x4b, 0x4f, 0x55, 0x5b, 0x61 #else // gm45 0x2, 0x4, 0x5, 0x7, 0x9, 0xb, 0xd, 0x11, 0x14, 0x17, 0x1c, 0x20, 0x27, 0x31, 0x41, 0x61, #endif }; #if 1 for (unsigned int di = 0; di < sizeof (duties) / sizeof (duties[0]); di++) { uint16_t duty = duties[di]; #else for (uint16_t duty = 0; duty < 0x61; duty++) { #endif #if 0 } #endif uint16_t pwm_freq = (freq + diff) << exponent; pwm_freq += (pwm_freq >> divisor); //pwm_freq |= 0x33; uint16_t pwm_duty = (duty + diff) << exponent; pwm_duty += (pwm_duty >> divisor); //pwm_duty |= 0x32; set_pwm (pwm_freq, pwm_duty); sleep (1); } if (pacc != NULL) pci_cleanup (pacc); if (map != NULL) munmap (map, 4096); if (fd != -1) close (fd); return 0; }