Control intel backlight on FreeBSD (and OpenBSD)
openbsd
at master 305 lines 6.7 kB view raw
1/* 2 * Copyright © 2008 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Eric Anholt <eric@anholt.net> 25 * Ben Widawsky <ben@bwidawsk.net> 26 * 27 */ 28 29#include <unistd.h> 30#include <fcntl.h> 31#include <stdio.h> 32#include <stdarg.h> 33#include <stdlib.h> 34#include <stdint.h> 35#include <stdbool.h> 36#include <string.h> 37#include <errno.h> 38#include <err.h> 39#include <assert.h> 40#include <sys/ioctl.h> 41#include <sys/stat.h> 42#include <sys/mman.h> 43 44#include "intel_gpu_tools.h" 45 46#define FAKEKEY 0x2468ace0 47 48void *mmio; 49 50static struct _mmio_data { 51 int inited; 52 bool safe; 53 char debugfs_path[FILENAME_MAX]; 54 char debugfs_forcewake_path[FILENAME_MAX]; 55 uint32_t i915_devid; 56 struct intel_register_map map; 57 int key; 58} mmio_data; 59 60void 61intel_map_file(char *file) 62{ 63 int fd; 64 struct stat st; 65 66 fd = open(file, O_RDWR); 67 if (fd == -1) { 68 fprintf(stderr, "Couldn't open %s: %s\n", file, 69 strerror(errno)); 70 exit(1); 71 } 72 fstat(fd, &st); 73 mmio = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); 74 if (mmio == MAP_FAILED) { 75 fprintf(stderr, "Couldn't mmap %s: %s\n", file, 76 strerror(errno)); 77 exit(1); 78 } 79 close(fd); 80} 81 82void 83intel_get_mmio(struct pci_device *pci_dev) 84{ 85 uint32_t devid, gen; 86 int mmio_bar, mmio_size; 87 int error; 88 89 devid = pci_dev->device_id; 90 if (IS_GEN2(devid)) 91 mmio_bar = 1; 92 else 93 mmio_bar = 0; 94 95 gen = intel_gen(devid); 96 if (gen < 3) 97 mmio_size = 512*1024; 98 else if (gen < 5) 99 mmio_size = 512*1024; 100 else 101 mmio_size = 2*1024*1024; 102 103#ifdef __OpenBSD__ 104 int ap = open("/dev/xf86", O_RDWR); 105 if (ap < 0) { 106 fprintf(stderr, "Couldn't open /dev/xf86: %s " 107 "(is machdep.allowaperture=3?)\n", strerror(errno)); 108 exit(1); 109 } 110 111 pci_system_init_dev_mem(ap); 112#endif 113 114 error = pci_device_map_range (pci_dev, 115 pci_dev->regions[mmio_bar].base_addr, 116 mmio_size, 117 PCI_DEV_MAP_FLAG_WRITABLE, 118 &mmio); 119 120 if (error != 0) { 121 fprintf(stderr, "Couldn't map MMIO region: %s\n", 122 strerror(error)); 123 exit(1); 124 } 125} 126 127/* 128 * If successful, i915_debugfs_path and i915_debugfs_forcewake_path are both 129 * updated with the correct path. 130 */ 131static int 132find_debugfs_path(const char *dri_base) 133{ 134 char buf[FILENAME_MAX]; 135 struct stat sb; 136 int i, ret; 137 138 for (i = 0; i < 16; i++) { 139 snprintf(buf, FILENAME_MAX, "%s/%i/name", dri_base, i); 140 141 snprintf(mmio_data.debugfs_path, FILENAME_MAX, 142 "%s/%i/", dri_base, i); 143 snprintf(mmio_data.debugfs_forcewake_path, FILENAME_MAX, 144 "%s/%i/i915_forcewake_user", dri_base, i); 145 146 ret = stat(mmio_data.debugfs_forcewake_path, &sb); 147 if (ret) { 148 mmio_data.debugfs_path[0] = 0; 149 mmio_data.debugfs_forcewake_path[0] = 0; 150 } else 151 return 0; 152 } 153 154 return -1; 155} 156 157static int 158get_forcewake_lock(void) 159{ 160 return open(mmio_data.debugfs_forcewake_path, 0); 161} 162 163static void 164release_forcewake_lock(int fd) 165{ 166 close(fd); 167} 168 169/* Dumb check to see if i915 was loaded */ 170static bool 171i915_loaded(void) 172{ 173 struct stat sb; 174 int ret; 175 176 ret = stat("/sys/module/i915/", &sb); 177 if (ret) { 178 return false; 179 } 180 181 assert(S_ISDIR(sb.st_mode)); 182 return true; 183} 184 185/* 186 * Initialize register access library. 187 * 188 * @pci_dev: pci device we're mucking with 189 * @safe: use safe register access tables 190 */ 191int 192intel_register_access_init(struct pci_device *pci_dev, int safe) 193{ 194 int ret; 195 196 /* after old API is deprecated, remove this */ 197 if (mmio == NULL) 198 intel_get_mmio(pci_dev); 199 200 assert(mmio != NULL); 201 202 if (mmio_data.inited) 203 return -1; 204 205 mmio_data.safe = (safe != 0 && 206 intel_gen(pci_dev->device_id) >= 4) ? true : false; 207 mmio_data.i915_devid = pci_dev->device_id; 208 if (mmio_data.safe) 209 mmio_data.map = intel_get_register_map(mmio_data.i915_devid); 210 211 /* Find where the forcewake lock is. Forcewake doesn't exist 212 * gen < 6, but the debugfs should do the right things for us. 213 */ 214 ret = find_debugfs_path("/sys/kernel/debug/dri"); 215 if (ret) { 216 ret = find_debugfs_path("/debug/dri"); 217 if (ret) { 218 fprintf(stderr, "Couldn't find path to dri/debugfs entry\n"); 219 if (i915_loaded()) { 220 fprintf(stderr, "i915 loaded; not proceeding.\n"); 221 return ret; 222 } 223 } 224 mmio_data.key = FAKEKEY; 225 } else 226 mmio_data.key = get_forcewake_lock(); 227 228 mmio_data.inited++; 229 return 0; 230} 231static int 232intel_register_access_needs_wake(void) 233{ 234 return mmio_data.key != FAKEKEY; 235} 236 237int intel_register_access_needs_fakewake(void) 238{ 239 return mmio_data.key == FAKEKEY; 240} 241 242void 243intel_register_access_fini(void) 244{ 245 if (mmio_data.key && intel_register_access_needs_wake()) 246 release_forcewake_lock(mmio_data.key); 247 mmio_data.inited--; 248} 249 250uint32_t 251intel_register_read(uint32_t reg) 252{ 253 struct intel_register_range *range; 254 uint32_t ret; 255 256 assert(mmio_data.inited); 257 258 if (intel_gen(mmio_data.i915_devid) >= 6) 259 assert(mmio_data.key != -1); 260 261 if (!mmio_data.safe) 262 goto read_out; 263 264 range = intel_get_register_range(mmio_data.map, 265 reg, 266 INTEL_RANGE_READ); 267 268 if(!range) { 269 fprintf(stderr, "Register read blocked for safety " 270 "(*0x%08x)\n", reg); 271 ret = 0xffffffff; 272 goto out; 273 } 274 275read_out: 276 ret = *(volatile uint32_t *)((volatile char *)mmio + reg); 277out: 278 return ret; 279} 280 281void 282intel_register_write(uint32_t reg, uint32_t val) 283{ 284 struct intel_register_range *range; 285 286 assert(mmio_data.inited); 287 288 if (intel_gen(mmio_data.i915_devid) >= 6) 289 assert(mmio_data.key != -1); 290 291 if (!mmio_data.safe) 292 goto write_out; 293 294 range = intel_get_register_range(mmio_data.map, 295 reg, 296 INTEL_RANGE_WRITE); 297 298 if (!range) { 299 fprintf(stderr, "Register write blocked for safety " 300 "(*0x%08x = 0x%x)\n", reg, val); 301 } 302 303write_out: 304 *(volatile uint32_t *)((volatile char *)mmio + reg) = val; 305}