Control intel backlight on FreeBSD (and OpenBSD)
openbsd
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}