1 /* 2 * Copyright (c) 2010 Red Hat Inc. 3 * Author : Dave Airlie <airlied@redhat.com> 4 * 5 * Licensed under GPLv2 6 * 7 * ATPX support for both Intel/ATI 8 */ 9 #include <linux/vga_switcheroo.h> 10 #include <linux/slab.h> 11 #include <acpi/acpi.h> 12 #include <acpi/acpi_bus.h> 13 #include <linux/pci.h> 14 15 #define ATPX_VERSION 0 16 #define ATPX_GPU_PWR 2 17 #define ATPX_MUX_SELECT 3 18 19 #define ATPX_INTEGRATED 0 20 #define ATPX_DISCRETE 1 21 22 #define ATPX_MUX_IGD 0 23 #define ATPX_MUX_DISCRETE 1 24 25 static struct radeon_atpx_priv { 26 bool atpx_detected; 27 /* handle for device - and atpx */ 28 acpi_handle dhandle; 29 acpi_handle atpx_handle; 30 acpi_handle atrm_handle; 31 } radeon_atpx_priv; 32 33 /* retrieve the ROM in 4k blocks */ 34 static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios, 35 int offset, int len) 36 { 37 acpi_status status; 38 union acpi_object atrm_arg_elements[2], *obj; 39 struct acpi_object_list atrm_arg; 40 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; 41 42 atrm_arg.count = 2; 43 atrm_arg.pointer = &atrm_arg_elements[0]; 44 45 atrm_arg_elements[0].type = ACPI_TYPE_INTEGER; 46 atrm_arg_elements[0].integer.value = offset; 47 48 atrm_arg_elements[1].type = ACPI_TYPE_INTEGER; 49 atrm_arg_elements[1].integer.value = len; 50 51 status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer); 52 if (ACPI_FAILURE(status)) { 53 printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status)); 54 return -ENODEV; 55 } 56 57 obj = (union acpi_object *)buffer.pointer; 58 memcpy(bios+offset, obj->buffer.pointer, len); 59 kfree(buffer.pointer); 60 return len; 61 } 62 63 bool radeon_atrm_supported(struct pci_dev *pdev) 64 { 65 /* get the discrete ROM only via ATRM */ 66 if (!radeon_atpx_priv.atpx_detected) 67 return false; 68 69 if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) 70 return false; 71 return true; 72 } 73 74 75 int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len) 76 { 77 return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len); 78 } 79 80 static int radeon_atpx_get_version(acpi_handle handle) 81 { 82 acpi_status status; 83 union acpi_object atpx_arg_elements[2], *obj; 84 struct acpi_object_list atpx_arg; 85 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 86 87 atpx_arg.count = 2; 88 atpx_arg.pointer = &atpx_arg_elements[0]; 89 90 atpx_arg_elements[0].type = ACPI_TYPE_INTEGER; 91 atpx_arg_elements[0].integer.value = ATPX_VERSION; 92 93 atpx_arg_elements[1].type = ACPI_TYPE_INTEGER; 94 atpx_arg_elements[1].integer.value = ATPX_VERSION; 95 96 status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer); 97 if (ACPI_FAILURE(status)) { 98 printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status)); 99 return -ENOSYS; 100 } 101 obj = (union acpi_object *)buffer.pointer; 102 if (obj && (obj->type == ACPI_TYPE_BUFFER)) 103 printk(KERN_INFO "radeon atpx: version is %d\n", *((u8 *)(obj->buffer.pointer) + 2)); 104 kfree(buffer.pointer); 105 return 0; 106 } 107 108 static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value) 109 { 110 acpi_status status; 111 union acpi_object atpx_arg_elements[2]; 112 struct acpi_object_list atpx_arg; 113 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 114 uint8_t buf[4] = {0}; 115 116 if (!handle) 117 return -EINVAL; 118 119 atpx_arg.count = 2; 120 atpx_arg.pointer = &atpx_arg_elements[0]; 121 122 atpx_arg_elements[0].type = ACPI_TYPE_INTEGER; 123 atpx_arg_elements[0].integer.value = cmd_id; 124 125 buf[2] = value & 0xff; 126 buf[3] = (value >> 8) & 0xff; 127 128 atpx_arg_elements[1].type = ACPI_TYPE_BUFFER; 129 atpx_arg_elements[1].buffer.length = 4; 130 atpx_arg_elements[1].buffer.pointer = buf; 131 132 status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer); 133 if (ACPI_FAILURE(status)) { 134 printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status)); 135 return -ENOSYS; 136 } 137 kfree(buffer.pointer); 138 139 return 0; 140 } 141 142 static int radeon_atpx_set_discrete_state(acpi_handle handle, int state) 143 { 144 return radeon_atpx_execute(handle, ATPX_GPU_PWR, state); 145 } 146 147 static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id) 148 { 149 return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id); 150 } 151 152 153 static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) 154 { 155 if (id == VGA_SWITCHEROO_IGD) 156 radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0); 157 else 158 radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1); 159 return 0; 160 } 161 162 static int radeon_atpx_power_state(enum vga_switcheroo_client_id id, 163 enum vga_switcheroo_state state) 164 { 165 /* on w500 ACPI can't change intel gpu state */ 166 if (id == VGA_SWITCHEROO_IGD) 167 return 0; 168 169 radeon_atpx_set_discrete_state(radeon_atpx_priv.atpx_handle, state); 170 return 0; 171 } 172 173 static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) 174 { 175 acpi_handle dhandle, atpx_handle, atrm_handle; 176 acpi_status status; 177 178 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 179 if (!dhandle) 180 return false; 181 182 status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); 183 if (ACPI_FAILURE(status)) 184 return false; 185 186 status = acpi_get_handle(dhandle, "ATRM", &atrm_handle); 187 if (ACPI_FAILURE(status)) 188 return false; 189 190 radeon_atpx_priv.dhandle = dhandle; 191 radeon_atpx_priv.atpx_handle = atpx_handle; 192 radeon_atpx_priv.atrm_handle = atrm_handle; 193 return true; 194 } 195 196 static int radeon_atpx_init(void) 197 { 198 /* set up the ATPX handle */ 199 200 radeon_atpx_get_version(radeon_atpx_priv.atpx_handle); 201 return 0; 202 } 203 204 static int radeon_atpx_get_client_id(struct pci_dev *pdev) 205 { 206 if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) 207 return VGA_SWITCHEROO_IGD; 208 else 209 return VGA_SWITCHEROO_DIS; 210 } 211 212 static struct vga_switcheroo_handler radeon_atpx_handler = { 213 .switchto = radeon_atpx_switchto, 214 .power_state = radeon_atpx_power_state, 215 .init = radeon_atpx_init, 216 .get_client_id = radeon_atpx_get_client_id, 217 }; 218 219 static bool radeon_atpx_detect(void) 220 { 221 char acpi_method_name[255] = { 0 }; 222 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 223 struct pci_dev *pdev = NULL; 224 bool has_atpx = false; 225 int vga_count = 0; 226 227 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 228 vga_count++; 229 230 has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true); 231 } 232 233 if (has_atpx && vga_count == 2) { 234 acpi_get_name(radeon_atpx_priv.atpx_handle, ACPI_FULL_PATHNAME, &buffer); 235 printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", 236 acpi_method_name); 237 radeon_atpx_priv.atpx_detected = true; 238 return true; 239 } 240 return false; 241 } 242 243 void radeon_register_atpx_handler(void) 244 { 245 bool r; 246 247 /* detect if we have any ATPX + 2 VGA in the system */ 248 r = radeon_atpx_detect(); 249 if (!r) 250 return; 251 252 vga_switcheroo_register_handler(&radeon_atpx_handler); 253 } 254 255 void radeon_unregister_atpx_handler(void) 256 { 257 vga_switcheroo_unregister_handler(); 258 } 259