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 36static struct nouveau_dsm_priv { 37 bool dsm_detected; 38 acpi_handle dhandle; 39 acpi_handle rom_handle; 40} nouveau_dsm_priv; 41 42static 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 47static 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 93static 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 98static 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 109static 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 117static 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 126static int nouveau_dsm_init(void) 127{ 128 return 0; 129} 130 131static int nouveau_dsm_get_client_id(struct pci_dev *pdev) 132{ 133 if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) 134 return VGA_SWITCHEROO_IGD; 135 else 136 return VGA_SWITCHEROO_DIS; 137} 138 139static struct vga_switcheroo_handler nouveau_dsm_handler = { 140 .switchto = nouveau_dsm_switchto, 141 .power_state = nouveau_dsm_power_state, 142 .init = nouveau_dsm_init, 143 .get_client_id = nouveau_dsm_get_client_id, 144}; 145 146static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) 147{ 148 acpi_handle dhandle, nvidia_handle; 149 acpi_status status; 150 int ret; 151 uint32_t result; 152 153 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 154 if (!dhandle) 155 return false; 156 157 status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); 158 if (ACPI_FAILURE(status)) { 159 return false; 160 } 161 162 ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, 163 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); 164 if (ret < 0) 165 return false; 166 167 nouveau_dsm_priv.dhandle = dhandle; 168 return true; 169} 170 171static bool nouveau_dsm_detect(void) 172{ 173 char acpi_method_name[255] = { 0 }; 174 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 175 struct pci_dev *pdev = NULL; 176 int has_dsm = 0; 177 int vga_count = 0; 178 179 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 180 vga_count++; 181 182 has_dsm |= (nouveau_dsm_pci_probe(pdev) == true); 183 } 184 185 if (vga_count == 2 && has_dsm) { 186 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 187 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", 188 acpi_method_name); 189 nouveau_dsm_priv.dsm_detected = true; 190 return true; 191 } 192 return false; 193} 194 195void nouveau_register_dsm_handler(void) 196{ 197 bool r; 198 199 r = nouveau_dsm_detect(); 200 if (!r) 201 return; 202 203 vga_switcheroo_register_handler(&nouveau_dsm_handler); 204} 205 206void nouveau_unregister_dsm_handler(void) 207{ 208 vga_switcheroo_unregister_handler(); 209} 210 211/* retrieve the ROM in 4k blocks */ 212static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, 213 int offset, int len) 214{ 215 acpi_status status; 216 union acpi_object rom_arg_elements[2], *obj; 217 struct acpi_object_list rom_arg; 218 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; 219 220 rom_arg.count = 2; 221 rom_arg.pointer = &rom_arg_elements[0]; 222 223 rom_arg_elements[0].type = ACPI_TYPE_INTEGER; 224 rom_arg_elements[0].integer.value = offset; 225 226 rom_arg_elements[1].type = ACPI_TYPE_INTEGER; 227 rom_arg_elements[1].integer.value = len; 228 229 status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer); 230 if (ACPI_FAILURE(status)) { 231 printk(KERN_INFO "failed to evaluate ROM got %s\n", acpi_format_exception(status)); 232 return -ENODEV; 233 } 234 obj = (union acpi_object *)buffer.pointer; 235 memcpy(bios+offset, obj->buffer.pointer, len); 236 kfree(buffer.pointer); 237 return len; 238} 239 240bool nouveau_acpi_rom_supported(struct pci_dev *pdev) 241{ 242 acpi_status status; 243 acpi_handle dhandle, rom_handle; 244 245 if (!nouveau_dsm_priv.dsm_detected) 246 return false; 247 248 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 249 if (!dhandle) 250 return false; 251 252 status = acpi_get_handle(dhandle, "_ROM", &rom_handle); 253 if (ACPI_FAILURE(status)) 254 return false; 255 256 nouveau_dsm_priv.rom_handle = rom_handle; 257 return true; 258} 259 260int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) 261{ 262 return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); 263} 264 265int 266nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) 267{ 268 struct nouveau_connector *nv_connector = nouveau_connector(connector); 269 struct acpi_device *acpidev; 270 acpi_handle handle; 271 int type, ret; 272 void *edid; 273 274 switch (connector->connector_type) { 275 case DRM_MODE_CONNECTOR_LVDS: 276 case DRM_MODE_CONNECTOR_eDP: 277 type = ACPI_VIDEO_DISPLAY_LCD; 278 break; 279 default: 280 return -EINVAL; 281 } 282 283 handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); 284 if (!handle) 285 return -ENODEV; 286 287 ret = acpi_bus_get_device(handle, &acpidev); 288 if (ret) 289 return -ENODEV; 290 291 ret = acpi_video_get_edid(acpidev, type, -1, &edid); 292 if (ret < 0) 293 return ret; 294 295 nv_connector->edid = edid; 296 return 0; 297} 298