~vcs-imports/suspend/trunk

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