~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to drivers/gpu/drm/nouveau/nouveau_acpi.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <linux/pci.h>
 
2
#include <linux/acpi.h>
 
3
#include <linux/slab.h>
 
4
#include <acpi/acpi_drivers.h>
 
5
#include <acpi/acpi_bus.h>
 
6
#include <acpi/video.h>
 
7
 
 
8
#include "drmP.h"
 
9
#include "drm.h"
 
10
#include "drm_sarea.h"
 
11
#include "drm_crtc_helper.h"
 
12
#include "nouveau_drv.h"
 
13
#include "nouveau_drm.h"
 
14
#include "nv50_display.h"
 
15
#include "nouveau_connector.h"
 
16
 
 
17
#include <linux/vga_switcheroo.h>
 
18
 
 
19
#define NOUVEAU_DSM_SUPPORTED 0x00
 
20
#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
 
21
 
 
22
#define NOUVEAU_DSM_ACTIVE 0x01
 
23
#define NOUVEAU_DSM_ACTIVE_QUERY 0x00
 
24
 
 
25
#define NOUVEAU_DSM_LED 0x02
 
26
#define NOUVEAU_DSM_LED_STATE 0x00
 
27
#define NOUVEAU_DSM_LED_OFF 0x10
 
28
#define NOUVEAU_DSM_LED_STAMINA 0x11
 
29
#define NOUVEAU_DSM_LED_SPEED 0x12
 
30
 
 
31
#define NOUVEAU_DSM_POWER 0x03
 
32
#define NOUVEAU_DSM_POWER_STATE 0x00
 
33
#define NOUVEAU_DSM_POWER_SPEED 0x01
 
34
#define NOUVEAU_DSM_POWER_STAMINA 0x02
 
35
 
 
36
static struct nouveau_dsm_priv {
 
37
        bool dsm_detected;
 
38
        acpi_handle dhandle;
 
39
        acpi_handle rom_handle;
 
40
} nouveau_dsm_priv;
 
41
 
 
42
static const char nouveau_dsm_muid[] = {
 
43
        0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
 
44
        0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
 
45
};
 
46
 
 
47
static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 
48
{
 
49
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 
50
        struct acpi_object_list input;
 
51
        union acpi_object params[4];
 
52
        union acpi_object *obj;
 
53
        int err;
 
54
 
 
55
        input.count = 4;
 
56
        input.pointer = params;
 
57
        params[0].type = ACPI_TYPE_BUFFER;
 
58
        params[0].buffer.length = sizeof(nouveau_dsm_muid);
 
59
        params[0].buffer.pointer = (char *)nouveau_dsm_muid;
 
60
        params[1].type = ACPI_TYPE_INTEGER;
 
61
        params[1].integer.value = 0x00000102;
 
62
        params[2].type = ACPI_TYPE_INTEGER;
 
63
        params[2].integer.value = func;
 
64
        params[3].type = ACPI_TYPE_INTEGER;
 
65
        params[3].integer.value = arg;
 
66
 
 
67
        err = acpi_evaluate_object(handle, "_DSM", &input, &output);
 
68
        if (err) {
 
69
                printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
 
70
                return err;
 
71
        }
 
72
 
 
73
        obj = (union acpi_object *)output.pointer;
 
74
 
 
75
        if (obj->type == ACPI_TYPE_INTEGER)
 
76
                if (obj->integer.value == 0x80000002)
 
77
                        return -ENODEV;
 
78
 
 
79
        if (obj->type == ACPI_TYPE_BUFFER) {
 
80
                if (obj->buffer.length == 4 && result) {
 
81
                        *result = 0;
 
82
                        *result |= obj->buffer.pointer[0];
 
83
                        *result |= (obj->buffer.pointer[1] << 8);
 
84
                        *result |= (obj->buffer.pointer[2] << 16);
 
85
                        *result |= (obj->buffer.pointer[3] << 24);
 
86
                }
 
87
        }
 
88
 
 
89
        kfree(output.pointer);
 
90
        return 0;
 
91
}
 
92
 
 
93
static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 
94
{
 
95
        return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
 
96
}
 
97
 
 
98
static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
 
99
{
 
100
        int arg;
 
101
        if (state == VGA_SWITCHEROO_ON)
 
102
                arg = NOUVEAU_DSM_POWER_SPEED;
 
103
        else
 
104
                arg = NOUVEAU_DSM_POWER_STAMINA;
 
105
        nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL);
 
106
        return 0;
 
107
}
 
108
 
 
109
static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
 
110
{
 
111
        if (id == VGA_SWITCHEROO_IGD)
 
112
                return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
 
113
        else
 
114
                return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED);
 
115
}
 
116
 
 
117
static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
 
118
                                   enum vga_switcheroo_state state)
 
119
{
 
120
        if (id == VGA_SWITCHEROO_IGD)
 
121
                return 0;
 
122
 
 
123
        return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 
124
}
 
125
 
 
126
static int nouveau_dsm_init(void)
 
127
{
 
128
        return 0;
 
129
}
 
130
 
 
131
static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
 
132
{
 
133
        /* easy option one - intel vendor ID means Integrated */
 
134
        if (pdev->vendor == PCI_VENDOR_ID_INTEL)
 
135
                return VGA_SWITCHEROO_IGD;
 
136
 
 
137
        /* is this device on Bus 0? - this may need improving */
 
138
        if (pdev->bus->number == 0)
 
139
                return VGA_SWITCHEROO_IGD;
 
140
 
 
141
        return VGA_SWITCHEROO_DIS;
 
142
}
 
143
 
 
144
static struct vga_switcheroo_handler nouveau_dsm_handler = {
 
145
        .switchto = nouveau_dsm_switchto,
 
146
        .power_state = nouveau_dsm_power_state,
 
147
        .init = nouveau_dsm_init,
 
148
        .get_client_id = nouveau_dsm_get_client_id,
 
149
};
 
150
 
 
151
static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
 
152
{
 
153
        acpi_handle dhandle, nvidia_handle;
 
154
        acpi_status status;
 
155
        int ret;
 
156
        uint32_t result;
 
157
 
 
158
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
 
159
        if (!dhandle)
 
160
                return false;
 
161
 
 
162
        status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle);
 
163
        if (ACPI_FAILURE(status)) {
 
164
                return false;
 
165
        }
 
166
 
 
167
        ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
 
168
                          NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
 
169
        if (ret < 0)
 
170
                return false;
 
171
 
 
172
        nouveau_dsm_priv.dhandle = dhandle;
 
173
        return true;
 
174
}
 
175
 
 
176
static bool nouveau_dsm_detect(void)
 
177
{
 
178
        char acpi_method_name[255] = { 0 };
 
179
        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
 
180
        struct pci_dev *pdev = NULL;
 
181
        int has_dsm = 0;
 
182
        int vga_count = 0;
 
183
 
 
184
        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
 
185
                vga_count++;
 
186
 
 
187
                has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
 
188
        }
 
189
 
 
190
        if (vga_count == 2 && has_dsm) {
 
191
                acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
 
192
                printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
 
193
                       acpi_method_name);
 
194
                nouveau_dsm_priv.dsm_detected = true;
 
195
                return true;
 
196
        }
 
197
        return false;
 
198
}
 
199
 
 
200
void nouveau_register_dsm_handler(void)
 
201
{
 
202
        bool r;
 
203
 
 
204
        r = nouveau_dsm_detect();
 
205
        if (!r)
 
206
                return;
 
207
 
 
208
        vga_switcheroo_register_handler(&nouveau_dsm_handler);
 
209
}
 
210
 
 
211
void nouveau_unregister_dsm_handler(void)
 
212
{
 
213
        vga_switcheroo_unregister_handler();
 
214
}
 
215
 
 
216
/* retrieve the ROM in 4k blocks */
 
217
static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios,
 
218
                            int offset, int len)
 
219
{
 
220
        acpi_status status;
 
221
        union acpi_object rom_arg_elements[2], *obj;
 
222
        struct acpi_object_list rom_arg;
 
223
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
 
224
 
 
225
        rom_arg.count = 2;
 
226
        rom_arg.pointer = &rom_arg_elements[0];
 
227
 
 
228
        rom_arg_elements[0].type = ACPI_TYPE_INTEGER;
 
229
        rom_arg_elements[0].integer.value = offset;
 
230
 
 
231
        rom_arg_elements[1].type = ACPI_TYPE_INTEGER;
 
232
        rom_arg_elements[1].integer.value = len;
 
233
 
 
234
        status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer);
 
235
        if (ACPI_FAILURE(status)) {
 
236
                printk(KERN_INFO "failed to evaluate ROM got %s\n", acpi_format_exception(status));
 
237
                return -ENODEV;
 
238
        }
 
239
        obj = (union acpi_object *)buffer.pointer;
 
240
        memcpy(bios+offset, obj->buffer.pointer, len);
 
241
        kfree(buffer.pointer);
 
242
        return len;
 
243
}
 
244
 
 
245
bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
 
246
{
 
247
        acpi_status status;
 
248
        acpi_handle dhandle, rom_handle;
 
249
 
 
250
        if (!nouveau_dsm_priv.dsm_detected)
 
251
                return false;
 
252
 
 
253
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
 
254
        if (!dhandle)
 
255
                return false;
 
256
 
 
257
        status = acpi_get_handle(dhandle, "_ROM", &rom_handle);
 
258
        if (ACPI_FAILURE(status))
 
259
                return false;
 
260
 
 
261
        nouveau_dsm_priv.rom_handle = rom_handle;
 
262
        return true;
 
263
}
 
264
 
 
265
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
 
266
{
 
267
        return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
 
268
}
 
269
 
 
270
int
 
271
nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
 
272
{
 
273
        struct nouveau_connector *nv_connector = nouveau_connector(connector);
 
274
        struct acpi_device *acpidev;
 
275
        acpi_handle handle;
 
276
        int type, ret;
 
277
        void *edid;
 
278
 
 
279
        switch (connector->connector_type) {
 
280
        case DRM_MODE_CONNECTOR_LVDS:
 
281
        case DRM_MODE_CONNECTOR_eDP:
 
282
                type = ACPI_VIDEO_DISPLAY_LCD;
 
283
                break;
 
284
        default:
 
285
                return -EINVAL;
 
286
        }
 
287
 
 
288
        handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
 
289
        if (!handle)
 
290
                return -ENODEV;
 
291
 
 
292
        ret = acpi_bus_get_device(handle, &acpidev);
 
293
        if (ret)
 
294
                return -ENODEV;
 
295
 
 
296
        ret = acpi_video_get_edid(acpidev, type, -1, &edid);
 
297
        if (ret < 0)
 
298
                return ret;
 
299
 
 
300
        nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
 
301
        return 0;
 
302
}