5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
1 |
|
2 |
/* Radeontool v1.4
|
|
3 |
* by Frederick Dean <software@fdd.com>
|
|
4 |
* Copyright 2002-2004 Frederick Dean
|
|
5 |
* Use hereby granted under the zlib license.
|
|
6 |
*
|
|
7 |
* Warning: I do not have the Radeon documents, so this was engineered from
|
|
8 |
* the radeon_reg.h header file.
|
|
9 |
*
|
|
10 |
* USE RADEONTOOL AT YOUR OWN RISK
|
|
11 |
*
|
|
12 |
* Thanks to Deepak Chawla, Erno Kuusela, Rolf Offermanns, and Soos Peter
|
|
13 |
* for patches.
|
|
14 |
*
|
|
15 |
* Stripped down to bare bones by Pavel Machek <pavel@suse.cz> -- for use in s2ram.c
|
|
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
16 |
* Rework of the map_radeon_cntl_mem function and various cleanups
|
17 |
* by Stefan Seyfried <seife@suse.de>
|
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
18 |
*/
|
19 |
||
365
by rjwysocki
|
20 |
#include "config.h" |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
21 |
#include <stdio.h> |
22 |
#include <stdlib.h> |
|
23 |
#include <unistd.h> |
|
24 |
#include <string.h> |
|
25 |
#include <sys/types.h> |
|
26 |
#include <sys/stat.h> |
|
27 |
#include <fcntl.h> |
|
28 |
#include <sys/mman.h> |
|
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
29 |
#include <pci/pci.h> |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
30 |
|
31 |
#define RADEON_LVDS_GEN_CNTL 0x02d0
|
|
32 |
# define RADEON_LVDS_ON (1 << 0)
|
|
33 |
# define RADEON_LVDS_DISPLAY_DIS (1 << 1)
|
|
34 |
# define RADEON_LVDS_PANEL_TYPE (1 << 2)
|
|
35 |
# define RADEON_LVDS_PANEL_FORMAT (1 << 3)
|
|
36 |
# define RADEON_LVDS_EN (1 << 7)
|
|
37 |
# define RADEON_LVDS_DIGON (1 << 18)
|
|
38 |
# define RADEON_LVDS_BLON (1 << 19)
|
|
39 |
# define RADEON_LVDS_SEL_CRTC2 (1 << 23)
|
|
40 |
||
41 |
/* *radeon_cntl_mem is mapped to the actual device's memory mapped control area. */
|
|
42 |
/* Not the address but what it points to is volatile. */
|
|
41
by pavel
Build fixes from Stefan Seyfried, and radeontool fixes: |
43 |
volatile unsigned char * radeon_cntl_mem; |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
44 |
|
87
by seife
clean up radeontool: |
45 |
static unsigned long radeon_get(unsigned long offset) |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
46 |
{
|
47 |
unsigned long value; |
|
87
by seife
clean up radeontool: |
48 |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
49 |
if(radeon_cntl_mem == NULL) { |
87
by seife
clean up radeontool: |
50 |
fprintf(stderr, "radeon_get: radeon_cntl_mem == NULL"); |
51 |
return 0; |
|
52 |
}
|
|
53 |
||
54 |
value = *(volatile unsigned long *)(radeon_cntl_mem+offset); |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
55 |
return value; |
56 |
}
|
|
6
by pavel
Integrate radeontool into s2ram. |
57 |
|
87
by seife
clean up radeontool: |
58 |
static void radeon_set(unsigned long offset, unsigned long value) |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
59 |
{
|
60 |
if(radeon_cntl_mem == NULL) { |
|
87
by seife
clean up radeontool: |
61 |
fprintf(stderr, "radeon_set: radeon_cntl_mem == NULL"); |
62 |
return; |
|
63 |
}
|
|
64 |
||
65 |
*(volatile unsigned long *)(radeon_cntl_mem+offset) = value; |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
66 |
}
|
67 |
||
68 |
/* Ohh, life would be good if we could simply address all memory addresses */
|
|
69 |
/* with /dev/mem, then I could write this whole program in perl, */
|
|
70 |
/* but sadly this is only the size of physical RAM. If you */
|
|
71 |
/* want to be truely bad and poke into device memory you have to mmap() */
|
|
41
by pavel
Build fixes from Stefan Seyfried, and radeontool fixes: |
72 |
static volatile unsigned char * map_device_memory(unsigned int base,unsigned int length) |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
73 |
{
|
74 |
int mem_fd; |
|
41
by pavel
Build fixes from Stefan Seyfried, and radeontool fixes: |
75 |
volatile unsigned char *device_mem; |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
76 |
|
77 |
/* open /dev/mem */
|
|
78 |
if ((mem_fd = open("/dev/mem", O_RDWR) ) < 0) { |
|
87
by seife
clean up radeontool: |
79 |
perror("radeontool /dev/mem"); |
80 |
return NULL; |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
81 |
}
|
82 |
||
83 |
/* mmap graphics memory */
|
|
41
by pavel
Build fixes from Stefan Seyfried, and radeontool fixes: |
84 |
if ((device_mem = malloc(length + (getpagesize()-1))) == NULL) { |
87
by seife
clean up radeontool: |
85 |
perror("radeontool malloc"); |
86 |
close(mem_fd); |
|
87 |
return NULL; |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
88 |
}
|
41
by pavel
Build fixes from Stefan Seyfried, and radeontool fixes: |
89 |
if ((unsigned long)device_mem % getpagesize()) |
90 |
device_mem += getpagesize() - ((unsigned long)device_mem % getpagesize()); |
|
91 |
device_mem = (volatile unsigned char *)mmap( |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
92 |
(caddr_t)device_mem, |
93 |
length, |
|
94 |
PROT_READ|PROT_WRITE, |
|
95 |
MAP_SHARED|MAP_FIXED, |
|
96 |
mem_fd, |
|
97 |
base
|
|
98 |
);
|
|
41
by pavel
Build fixes from Stefan Seyfried, and radeontool fixes: |
99 |
if (device_mem == (volatile unsigned char *)-1) { |
87
by seife
clean up radeontool: |
100 |
perror("radeontool mmap"); |
101 |
return NULL; |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
102 |
}
|
103 |
return device_mem; |
|
104 |
}
|
|
105 |
||
87
by seife
clean up radeontool: |
106 |
void radeon_cmd_light(int param) |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
107 |
{
|
108 |
unsigned long lvds_gen_cntl; |
|
109 |
||
87
by seife
clean up radeontool: |
110 |
lvds_gen_cntl = radeon_get(RADEON_LVDS_GEN_CNTL); |
111 |
||
112 |
if (param) |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
113 |
lvds_gen_cntl |= RADEON_LVDS_ON; |
87
by seife
clean up radeontool: |
114 |
else
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
115 |
lvds_gen_cntl &= ~ RADEON_LVDS_ON; |
87
by seife
clean up radeontool: |
116 |
|
117 |
radeon_set(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); |
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
118 |
}
|
119 |
||
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
120 |
/* I have not got much feedback on my radeontool rework, hence i leave the old
|
121 |
* code #if 0-ed in for reference.
|
|
122 |
* Once some time passes without complaints about the new code, i will remove it.
|
|
123 |
* Sorry for the clutter - seife.
|
|
124 |
*/
|
|
125 |
#if 0
|
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
126 |
/* Here we fork() and exec() the lspci command to look for the Radeon hardware address. */
|
79
by seife
Cleanup: |
127 |
void map_radeon_cntl_mem(void)
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
128 |
{
|
129 |
int pipefd[2];
|
|
130 |
int forkrc;
|
|
131 |
FILE *fp;
|
|
132 |
char line[1000];
|
|
133 |
int base;
|
|
134 |
||
135 |
if(pipe(pipefd)) {
|
|
136 |
fatal("pipe failure\n");
|
|
137 |
}
|
|
138 |
forkrc = fork();
|
|
139 |
if(forkrc == -1) {
|
|
140 |
fatal("fork failure\n");
|
|
141 |
} else if(forkrc == 0) { /* if child */
|
|
142 |
close(pipefd[0]);
|
|
143 |
dup2(pipefd[1],1); /* stdout */
|
|
144 |
setenv("PATH","/sbin:/usr/sbin:/bin:/usr/bin",1);
|
|
145 |
execlp("lspci","lspci","-v",NULL);
|
|
146 |
fatal("exec lspci failure\n");
|
|
147 |
}
|
|
148 |
close(pipefd[1]);
|
|
149 |
fp = fdopen(pipefd[0],"r");
|
|
150 |
if(fp == NULL) {
|
|
151 |
fatal("fdopen error\n");
|
|
152 |
}
|
|
153 |
#if 0
|
|
154 |
This is an example output of "lspci -v" ...
|
|
155 |
||
156 |
00:1f.6 Modem: Intel Corp. 82801CA/CAM AC 97 Modem (rev 01) (prog-if 00 [Generic])
|
|
157 |
Subsystem: PCTel Inc: Unknown device 4c21
|
|
158 |
Flags: bus master, medium devsel, latency 0, IRQ 11
|
|
159 |
I/O ports at d400 [size=256]
|
|
160 |
I/O ports at dc00 [size=128]
|
|
161 |
||
162 |
01:00.0 VGA compatible controller: ATI Technologies Inc Radeon Mobility M6 LY (prog-if 00 [VGA])
|
|
163 |
Subsystem: Dell Computer Corporation: Unknown device 00e3
|
|
164 |
Flags: bus master, VGA palette snoop, stepping, 66Mhz, medium devsel, latency 32, IRQ 11
|
|
165 |
Memory at e0000000 (32-bit, prefetchable) [size=128M]
|
|
166 |
I/O ports at c000 [size=256]
|
|
167 |
Memory at fcff0000 (32-bit, non-prefetchable) [size=64K]
|
|
168 |
Expansion ROM at <unassigned> [disabled] [size=128K]
|
|
169 |
Capabilities: <available only to root>
|
|
170 |
||
171 |
02:00.0 Ethernet controller: 3Com Corporation 3c905C-TX/TX-M [Tornado] (rev 78)
|
|
172 |
Subsystem: Dell Computer Corporation: Unknown device 00e3
|
|
173 |
Flags: bus master, medium devsel, latency 32, IRQ 11
|
|
174 |
I/O ports at ec80 [size=128]
|
|
175 |
Memory at f8fffc00 (32-bit, non-prefetchable) [size=128]
|
|
176 |
Expansion ROM at f9000000 [disabled] [size=128K]
|
|
177 |
Capabilities: <available only to root>
|
|
178 |
||
179 |
We need to look through it to find the smaller region base address f8fffc00.
|
|
180 |
||
181 |
#endif
|
|
182 |
while(1) { /* for every line up to the "Radeon" string */
|
|
183 |
if(fgets(line,sizeof(line),fp) == NULL) { /* if end of file */
|
|
184 |
fatal("Radeon hardware not found in lspci output.\n");
|
|
185 |
}
|
|
186 |
if(strstr(line,"Radeon") || strstr(line,"ATI Tech")) { /* if line contains a "radeon" string */
|
|
187 |
break;
|
|
188 |
}
|
|
189 |
};
|
|
190 |
if(debug)
|
|
191 |
printf("%s",line);
|
|
192 |
while(1) { /* for every line up till memory statement */
|
|
193 |
if(fgets(line,sizeof(line),fp) == NULL || line[0] != '\t') { /* if end of file */
|
|
194 |
fatal("Radeon control memory not found.\n");
|
|
195 |
}
|
|
196 |
if(debug)
|
|
197 |
printf("%s",line);
|
|
198 |
if(strstr(line,"emory") && strstr(line,"K")) { /* if line contains a "Memory" and "K" string */
|
|
199 |
break;
|
|
200 |
}
|
|
201 |
};
|
|
202 |
if(sscanf(line,"%*s%*s%x",&base) == 0) { /* third token as hex number */
|
|
203 |
fatal("parse error of lspci output (control memory not found)\n");
|
|
204 |
}
|
|
205 |
if(debug)
|
|
206 |
printf("Radeon found. Base control address is %x.\n",base);
|
|
41
by pavel
Build fixes from Stefan Seyfried, and radeontool fixes: |
207 |
radeon_cntl_mem = map_device_memory(base,0x2000);
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
208 |
}
|
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
209 |
#else
|
210 |
||
211 |
static u32 |
|
212 |
get_conf_long(unsigned char *d, unsigned int pos) |
|
213 |
{
|
|
214 |
return d[pos] | (d[pos+1] << 8) | (d[pos+2] << 16) | (d[pos+3] << 24); |
|
215 |
}
|
|
216 |
||
217 |
/* Find out where the radeon memory is. The idea is taken from radeontool-1.5,
|
|
218 |
* but we no longer fork lspci and parse its output :-)
|
|
219 |
* The logic seems to be: the memory range that is not I/O space and smaller
|
|
220 |
* than 1 MB is the radeon chip control range. Let's hope that this is true.
|
|
221 |
*/
|
|
222 |
void map_radeon_cntl_mem(void) |
|
223 |
{
|
|
224 |
struct pci_access *pacc; |
|
225 |
struct pci_dev *dev; |
|
226 |
unsigned int class; |
|
227 |
int i; |
|
228 |
int base = -1; |
|
229 |
unsigned char *config; |
|
230 |
||
87
by seife
clean up radeontool: |
231 |
radeon_cntl_mem = NULL; |
232 |
||
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
233 |
config = malloc(64); |
87
by seife
clean up radeontool: |
234 |
if (!config) { |
235 |
perror("map_radeon_cntl_mem malloc(64)"); |
|
236 |
return; |
|
237 |
}
|
|
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
238 |
pacc = pci_alloc(); /* Get the pci_access structure */ |
239 |
pci_init(pacc); /* Initialize the PCI library */ |
|
240 |
pci_scan_bus(pacc); /* We want to get the list of devices */ |
|
87
by seife
clean up radeontool: |
241 |
for (dev=pacc->devices; dev; dev=dev->next) { /* Iterate over all devices */ |
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
242 |
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES);/* Fill in header info we need */ |
243 |
class = pci_read_word(dev, PCI_CLASS_DEVICE); /* Read config register directly */ |
|
244 |
if (dev->vendor_id == 0x1002 && class == 0x300) { /* ATI && Graphics card */ |
|
245 |
pci_read_block(dev, 0, config, 64); |
|
246 |
for (i=0; i<6; i++){ |
|
247 |
u32 flag = get_conf_long(config, PCI_BASE_ADDRESS_0 + 4*i); |
|
248 |
if (flag & PCI_BASE_ADDRESS_SPACE_IO) /* I/O-Ports, not memory */ |
|
249 |
continue; |
|
250 |
/* the original code parsed lspci for "emory" and "K", so it
|
|
251 |
* has to be at least 1K and less than 1M
|
|
252 |
*/
|
|
253 |
if (dev->size[i] >=1024 && dev->size[i] < 1024*1024) { |
|
254 |
base = dev->base_addr[i]; |
|
255 |
goto found; |
|
256 |
}
|
|
257 |
}
|
|
258 |
}
|
|
259 |
}
|
|
260 |
found: |
|
261 |
pci_cleanup(pacc); |
|
262 |
free(config); |
|
87
by seife
clean up radeontool: |
263 |
if (base == -1) { |
264 |
fprintf(stderr, "radeontool: Radeon not found.\n"); |
|
265 |
return; |
|
266 |
}
|
|
86
by seife
Rework the radeon detection: instead of forking lspci, we scan the bus using |
267 |
radeon_cntl_mem = map_device_memory(base,0x2000); |
268 |
}
|
|
269 |
#endif
|
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
270 |
|
6
by pavel
Integrate radeontool into s2ram. |
271 |
#ifndef S2RAM
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
272 |
int main(int argc,char *argv[]) |
273 |
{
|
|
274 |
map_radeon_cntl_mem(); |
|
87
by seife
clean up radeontool: |
275 |
if (radeon_cntl_mem == NULL) { |
276 |
fprintf(stderr, "Fatal error: radeon_cntl_mem == NULL.\n"); |
|
277 |
return 1; |
|
278 |
}
|
|
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
279 |
if (argc == 3) { |
280 |
if(strcmp(argv[1],"light") == 0) { |
|
87
by seife
clean up radeontool: |
281 |
radeon_cmd_light(strcmp(argv[2],"off")); |
5
by pavel
Stripped down radeontool, turning off backlight is neccessary on thinkpads. |
282 |
return 0; |
283 |
}
|
|
284 |
};
|
|
285 |
return 1; |
|
286 |
}
|
|
6
by pavel
Integrate radeontool into s2ram. |
287 |
#endif
|