Home | History | Annotate | Line # | Download | only in nouveau
      1  1.5  riastrad /*	$NetBSD: nouveau_acpi.c,v 1.5 2024/04/16 14:34:02 riastradh Exp $	*/
      2  1.2  riastrad 
      3  1.3  riastrad // SPDX-License-Identifier: MIT
      4  1.2  riastrad #include <sys/cdefs.h>
      5  1.5  riastrad __KERNEL_RCSID(0, "$NetBSD: nouveau_acpi.c,v 1.5 2024/04/16 14:34:02 riastradh Exp $");
      6  1.2  riastrad 
      7  1.1  riastrad #include <linux/pci.h>
      8  1.1  riastrad #include <linux/acpi.h>
      9  1.1  riastrad #include <linux/slab.h>
     10  1.1  riastrad #include <linux/mxm-wmi.h>
     11  1.1  riastrad #include <linux/vga_switcheroo.h>
     12  1.1  riastrad #include <drm/drm_edid.h>
     13  1.1  riastrad #include <acpi/video.h>
     14  1.1  riastrad 
     15  1.3  riastrad #include "nouveau_drv.h"
     16  1.1  riastrad #include "nouveau_acpi.h"
     17  1.1  riastrad 
     18  1.5  riastrad #ifdef __NetBSD__
     19  1.5  riastrad #include <dev/acpi/acpireg.h>
     20  1.5  riastrad #define	_COMPONENT	ACPI_DISPLAY_COMPONENT
     21  1.5  riastrad ACPI_MODULE_NAME("nouveau_acpi")
     22  1.5  riastrad #include <linux/nbsd-namespace-acpi.h>
     23  1.5  riastrad #endif
     24  1.5  riastrad 
     25  1.1  riastrad #define NOUVEAU_DSM_LED 0x02
     26  1.1  riastrad #define NOUVEAU_DSM_LED_STATE 0x00
     27  1.1  riastrad #define NOUVEAU_DSM_LED_OFF 0x10
     28  1.1  riastrad #define NOUVEAU_DSM_LED_STAMINA 0x11
     29  1.1  riastrad #define NOUVEAU_DSM_LED_SPEED 0x12
     30  1.1  riastrad 
     31  1.1  riastrad #define NOUVEAU_DSM_POWER 0x03
     32  1.1  riastrad #define NOUVEAU_DSM_POWER_STATE 0x00
     33  1.1  riastrad #define NOUVEAU_DSM_POWER_SPEED 0x01
     34  1.1  riastrad #define NOUVEAU_DSM_POWER_STAMINA 0x02
     35  1.1  riastrad 
     36  1.1  riastrad #define NOUVEAU_DSM_OPTIMUS_CAPS 0x1A
     37  1.1  riastrad #define NOUVEAU_DSM_OPTIMUS_FLAGS 0x1B
     38  1.1  riastrad 
     39  1.1  riastrad #define NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 (3 << 24)
     40  1.1  riastrad #define NOUVEAU_DSM_OPTIMUS_NO_POWERDOWN_PS3 (2 << 24)
     41  1.1  riastrad #define NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED (1)
     42  1.1  riastrad 
     43  1.1  riastrad #define NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN (NOUVEAU_DSM_OPTIMUS_POWERDOWN_PS3 | NOUVEAU_DSM_OPTIMUS_FLAGS_CHANGED)
     44  1.1  riastrad 
     45  1.1  riastrad /* result of the optimus caps function */
     46  1.1  riastrad #define OPTIMUS_ENABLED (1 << 0)
     47  1.1  riastrad #define OPTIMUS_STATUS_MASK (3 << 3)
     48  1.1  riastrad #define OPTIMUS_STATUS_OFF  (0 << 3)
     49  1.1  riastrad #define OPTIMUS_STATUS_ON_ENABLED  (1 << 3)
     50  1.1  riastrad #define OPTIMUS_STATUS_PWR_STABLE  (3 << 3)
     51  1.1  riastrad #define OPTIMUS_DISPLAY_HOTPLUG (1 << 6)
     52  1.1  riastrad #define OPTIMUS_CAPS_MASK (7 << 24)
     53  1.1  riastrad #define OPTIMUS_DYNAMIC_PWR_CAP (1 << 24)
     54  1.1  riastrad 
     55  1.1  riastrad #define OPTIMUS_AUDIO_CAPS_MASK (3 << 27)
     56  1.1  riastrad #define OPTIMUS_HDA_CODEC_MASK (2 << 27) /* hda bios control */
     57  1.1  riastrad 
     58  1.1  riastrad static struct nouveau_dsm_priv {
     59  1.1  riastrad 	bool dsm_detected;
     60  1.1  riastrad 	bool optimus_detected;
     61  1.3  riastrad 	bool optimus_flags_detected;
     62  1.3  riastrad 	bool optimus_skip_dsm;
     63  1.1  riastrad 	acpi_handle dhandle;
     64  1.1  riastrad 	acpi_handle rom_handle;
     65  1.1  riastrad } nouveau_dsm_priv;
     66  1.1  riastrad 
     67  1.1  riastrad bool nouveau_is_optimus(void) {
     68  1.1  riastrad 	return nouveau_dsm_priv.optimus_detected;
     69  1.1  riastrad }
     70  1.1  riastrad 
     71  1.1  riastrad bool nouveau_is_v1_dsm(void) {
     72  1.1  riastrad 	return nouveau_dsm_priv.dsm_detected;
     73  1.1  riastrad }
     74  1.1  riastrad 
     75  1.1  riastrad #ifdef CONFIG_VGA_SWITCHEROO
     76  1.3  riastrad static const guid_t nouveau_dsm_muid =
     77  1.3  riastrad 	GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,
     78  1.3  riastrad 		  0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
     79  1.3  riastrad 
     80  1.3  riastrad static const guid_t nouveau_op_dsm_muid =
     81  1.3  riastrad 	GUID_INIT(0xA486D8F8, 0x0BDA, 0x471B,
     82  1.3  riastrad 		  0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0);
     83  1.1  riastrad 
     84  1.1  riastrad static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
     85  1.1  riastrad {
     86  1.1  riastrad 	int i;
     87  1.1  riastrad 	union acpi_object *obj;
     88  1.1  riastrad 	char args_buff[4];
     89  1.1  riastrad 	union acpi_object argv4 = {
     90  1.1  riastrad 		.buffer.type = ACPI_TYPE_BUFFER,
     91  1.1  riastrad 		.buffer.length = 4,
     92  1.1  riastrad 		.buffer.pointer = args_buff
     93  1.1  riastrad 	};
     94  1.1  riastrad 
     95  1.1  riastrad 	/* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
     96  1.1  riastrad 	for (i = 0; i < 4; i++)
     97  1.1  riastrad 		args_buff[i] = (arg >> i * 8) & 0xFF;
     98  1.1  riastrad 
     99  1.1  riastrad 	*result = 0;
    100  1.3  riastrad 	obj = acpi_evaluate_dsm_typed(handle, &nouveau_op_dsm_muid, 0x00000100,
    101  1.1  riastrad 				      func, &argv4, ACPI_TYPE_BUFFER);
    102  1.1  riastrad 	if (!obj) {
    103  1.1  riastrad 		acpi_handle_info(handle, "failed to evaluate _DSM\n");
    104  1.1  riastrad 		return AE_ERROR;
    105  1.1  riastrad 	} else {
    106  1.1  riastrad 		if (obj->buffer.length == 4) {
    107  1.1  riastrad 			*result |= obj->buffer.pointer[0];
    108  1.1  riastrad 			*result |= (obj->buffer.pointer[1] << 8);
    109  1.1  riastrad 			*result |= (obj->buffer.pointer[2] << 16);
    110  1.1  riastrad 			*result |= (obj->buffer.pointer[3] << 24);
    111  1.1  riastrad 		}
    112  1.1  riastrad 		ACPI_FREE(obj);
    113  1.1  riastrad 	}
    114  1.1  riastrad 
    115  1.1  riastrad 	return 0;
    116  1.1  riastrad }
    117  1.1  riastrad 
    118  1.1  riastrad /*
    119  1.1  riastrad  * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
    120  1.1  riastrad  * requirements on the fourth parameter, so a private implementation
    121  1.1  riastrad  * instead of using acpi_check_dsm().
    122  1.1  riastrad  */
    123  1.3  riastrad static int nouveau_dsm_get_optimus_functions(acpi_handle handle)
    124  1.1  riastrad {
    125  1.1  riastrad 	int result;
    126  1.1  riastrad 
    127  1.1  riastrad 	/*
    128  1.1  riastrad 	 * Function 0 returns a Buffer containing available functions.
    129  1.1  riastrad 	 * The args parameter is ignored for function 0, so just put 0 in it
    130  1.1  riastrad 	 */
    131  1.1  riastrad 	if (nouveau_optimus_dsm(handle, 0, 0, &result))
    132  1.1  riastrad 		return 0;
    133  1.1  riastrad 
    134  1.1  riastrad 	/*
    135  1.1  riastrad 	 * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
    136  1.1  riastrad 	 * If the n-th bit is enabled, function n is supported
    137  1.1  riastrad 	 */
    138  1.3  riastrad 	if (result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS))
    139  1.3  riastrad 		return result;
    140  1.3  riastrad 	return 0;
    141  1.1  riastrad }
    142  1.1  riastrad 
    143  1.1  riastrad static int nouveau_dsm(acpi_handle handle, int func, int arg)
    144  1.1  riastrad {
    145  1.1  riastrad 	int ret = 0;
    146  1.1  riastrad 	union acpi_object *obj;
    147  1.1  riastrad 	union acpi_object argv4 = {
    148  1.1  riastrad 		.integer.type = ACPI_TYPE_INTEGER,
    149  1.1  riastrad 		.integer.value = arg,
    150  1.1  riastrad 	};
    151  1.1  riastrad 
    152  1.3  riastrad 	obj = acpi_evaluate_dsm_typed(handle, &nouveau_dsm_muid, 0x00000102,
    153  1.1  riastrad 				      func, &argv4, ACPI_TYPE_INTEGER);
    154  1.1  riastrad 	if (!obj) {
    155  1.1  riastrad 		acpi_handle_info(handle, "failed to evaluate _DSM\n");
    156  1.1  riastrad 		return AE_ERROR;
    157  1.1  riastrad 	} else {
    158  1.1  riastrad 		if (obj->integer.value == 0x80000002)
    159  1.1  riastrad 			ret = -ENODEV;
    160  1.1  riastrad 		ACPI_FREE(obj);
    161  1.1  riastrad 	}
    162  1.1  riastrad 
    163  1.1  riastrad 	return ret;
    164  1.1  riastrad }
    165  1.1  riastrad 
    166  1.1  riastrad static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
    167  1.1  riastrad {
    168  1.1  riastrad 	mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
    169  1.1  riastrad 	mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
    170  1.1  riastrad 	return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id);
    171  1.1  riastrad }
    172  1.1  riastrad 
    173  1.1  riastrad static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
    174  1.1  riastrad {
    175  1.1  riastrad 	int arg;
    176  1.1  riastrad 	if (state == VGA_SWITCHEROO_ON)
    177  1.1  riastrad 		arg = NOUVEAU_DSM_POWER_SPEED;
    178  1.1  riastrad 	else
    179  1.1  riastrad 		arg = NOUVEAU_DSM_POWER_STAMINA;
    180  1.1  riastrad 	nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg);
    181  1.1  riastrad 	return 0;
    182  1.1  riastrad }
    183  1.1  riastrad 
    184  1.1  riastrad static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
    185  1.1  riastrad {
    186  1.1  riastrad 	if (!nouveau_dsm_priv.dsm_detected)
    187  1.1  riastrad 		return 0;
    188  1.1  riastrad 	if (id == VGA_SWITCHEROO_IGD)
    189  1.1  riastrad 		return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
    190  1.1  riastrad 	else
    191  1.1  riastrad 		return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED);
    192  1.1  riastrad }
    193  1.1  riastrad 
    194  1.1  riastrad static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
    195  1.1  riastrad 				   enum vga_switcheroo_state state)
    196  1.1  riastrad {
    197  1.1  riastrad 	if (id == VGA_SWITCHEROO_IGD)
    198  1.1  riastrad 		return 0;
    199  1.1  riastrad 
    200  1.1  riastrad 	/* Optimus laptops have the card already disabled in
    201  1.1  riastrad 	 * nouveau_switcheroo_set_state */
    202  1.1  riastrad 	if (!nouveau_dsm_priv.dsm_detected)
    203  1.1  riastrad 		return 0;
    204  1.1  riastrad 
    205  1.1  riastrad 	return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
    206  1.1  riastrad }
    207  1.1  riastrad 
    208  1.3  riastrad static enum vga_switcheroo_client_id nouveau_dsm_get_client_id(struct pci_dev *pdev)
    209  1.1  riastrad {
    210  1.1  riastrad 	/* easy option one - intel vendor ID means Integrated */
    211  1.1  riastrad 	if (pdev->vendor == PCI_VENDOR_ID_INTEL)
    212  1.1  riastrad 		return VGA_SWITCHEROO_IGD;
    213  1.1  riastrad 
    214  1.1  riastrad 	/* is this device on Bus 0? - this may need improving */
    215  1.1  riastrad 	if (pdev->bus->number == 0)
    216  1.1  riastrad 		return VGA_SWITCHEROO_IGD;
    217  1.1  riastrad 
    218  1.1  riastrad 	return VGA_SWITCHEROO_DIS;
    219  1.1  riastrad }
    220  1.1  riastrad 
    221  1.2  riastrad static const struct vga_switcheroo_handler nouveau_dsm_handler = {
    222  1.1  riastrad 	.switchto = nouveau_dsm_switchto,
    223  1.1  riastrad 	.power_state = nouveau_dsm_power_state,
    224  1.1  riastrad 	.get_client_id = nouveau_dsm_get_client_id,
    225  1.1  riastrad };
    226  1.1  riastrad 
    227  1.3  riastrad /*
    228  1.3  riastrad  * Firmware supporting Windows 8 or later do not use _DSM to put the device into
    229  1.3  riastrad  * D3cold, they instead rely on disabling power resources on the parent.
    230  1.3  riastrad  */
    231  1.3  riastrad static bool nouveau_pr3_present(struct pci_dev *pdev)
    232  1.3  riastrad {
    233  1.3  riastrad 	struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
    234  1.3  riastrad 	struct acpi_device *parent_adev;
    235  1.3  riastrad 
    236  1.3  riastrad 	if (!parent_pdev)
    237  1.3  riastrad 		return false;
    238  1.3  riastrad 
    239  1.3  riastrad 	if (!parent_pdev->bridge_d3) {
    240  1.3  riastrad 		/*
    241  1.3  riastrad 		 * Parent PCI bridge is currently not power managed.
    242  1.3  riastrad 		 * Since userspace can change these afterwards to be on
    243  1.3  riastrad 		 * the safe side we stick with _DSM and prevent usage of
    244  1.3  riastrad 		 * _PR3 from the bridge.
    245  1.3  riastrad 		 */
    246  1.3  riastrad 		pci_d3cold_disable(pdev);
    247  1.3  riastrad 		return false;
    248  1.3  riastrad 	}
    249  1.3  riastrad 
    250  1.3  riastrad 	parent_adev = ACPI_COMPANION(&parent_pdev->dev);
    251  1.3  riastrad 	if (!parent_adev)
    252  1.3  riastrad 		return false;
    253  1.3  riastrad 
    254  1.3  riastrad 	return parent_adev->power.flags.power_resources &&
    255  1.3  riastrad 		acpi_has_method(parent_adev->handle, "_PR3");
    256  1.3  riastrad }
    257  1.3  riastrad 
    258  1.3  riastrad static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
    259  1.3  riastrad 				  bool *has_mux, bool *has_opt,
    260  1.3  riastrad 				  bool *has_opt_flags, bool *has_pr3)
    261  1.1  riastrad {
    262  1.1  riastrad 	acpi_handle dhandle;
    263  1.3  riastrad 	bool supports_mux;
    264  1.3  riastrad 	int optimus_funcs;
    265  1.1  riastrad 
    266  1.5  riastrad #ifdef __NetBSD__
    267  1.5  riastrad 	dhandle = pdev->pd_ad->ad_handle;
    268  1.5  riastrad #else
    269  1.1  riastrad 	dhandle = ACPI_HANDLE(&pdev->dev);
    270  1.5  riastrad #endif
    271  1.1  riastrad 	if (!dhandle)
    272  1.3  riastrad 		return;
    273  1.1  riastrad 
    274  1.2  riastrad 	if (!acpi_has_method(dhandle, "_DSM"))
    275  1.3  riastrad 		return;
    276  1.3  riastrad 
    277  1.3  riastrad 	supports_mux = acpi_check_dsm(dhandle, &nouveau_dsm_muid, 0x00000102,
    278  1.3  riastrad 				      1 << NOUVEAU_DSM_POWER);
    279  1.3  riastrad 	optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);
    280  1.2  riastrad 
    281  1.3  riastrad 	/* Does not look like a Nvidia device. */
    282  1.3  riastrad 	if (!supports_mux && !optimus_funcs)
    283  1.3  riastrad 		return;
    284  1.1  riastrad 
    285  1.3  riastrad 	*dhandle_out = dhandle;
    286  1.3  riastrad 	*has_mux = supports_mux;
    287  1.3  riastrad 	*has_opt = !!optimus_funcs;
    288  1.3  riastrad 	*has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS);
    289  1.3  riastrad 	*has_pr3 = false;
    290  1.1  riastrad 
    291  1.3  riastrad 	if (optimus_funcs) {
    292  1.1  riastrad 		uint32_t result;
    293  1.1  riastrad 		nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0,
    294  1.1  riastrad 				    &result);
    295  1.1  riastrad 		dev_info(&pdev->dev, "optimus capabilities: %s, status %s%s\n",
    296  1.1  riastrad 			 (result & OPTIMUS_ENABLED) ? "enabled" : "disabled",
    297  1.1  riastrad 			 (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "",
    298  1.1  riastrad 			 (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : "");
    299  1.3  riastrad 
    300  1.3  riastrad 		*has_pr3 = nouveau_pr3_present(pdev);
    301  1.1  riastrad 	}
    302  1.1  riastrad }
    303  1.1  riastrad 
    304  1.1  riastrad static bool nouveau_dsm_detect(void)
    305  1.1  riastrad {
    306  1.1  riastrad 	char acpi_method_name[255] = { 0 };
    307  1.1  riastrad 	struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
    308  1.1  riastrad 	struct pci_dev *pdev = NULL;
    309  1.3  riastrad 	acpi_handle dhandle = NULL;
    310  1.3  riastrad 	bool has_mux = false;
    311  1.3  riastrad 	bool has_optimus = false;
    312  1.3  riastrad 	bool has_optimus_flags = false;
    313  1.3  riastrad 	bool has_power_resources = false;
    314  1.1  riastrad 	int vga_count = 0;
    315  1.1  riastrad 	bool guid_valid;
    316  1.1  riastrad 	bool ret = false;
    317  1.1  riastrad 
    318  1.1  riastrad 	/* lookup the MXM GUID */
    319  1.1  riastrad 	guid_valid = mxm_wmi_supported();
    320  1.1  riastrad 
    321  1.1  riastrad 	if (guid_valid)
    322  1.1  riastrad 		printk("MXM: GUID detected in BIOS\n");
    323  1.1  riastrad 
    324  1.1  riastrad 	/* now do DSM detection */
    325  1.1  riastrad 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
    326  1.1  riastrad 		vga_count++;
    327  1.1  riastrad 
    328  1.3  riastrad 		nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
    329  1.3  riastrad 				      &has_optimus_flags, &has_power_resources);
    330  1.1  riastrad 	}
    331  1.1  riastrad 
    332  1.1  riastrad 	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
    333  1.1  riastrad 		vga_count++;
    334  1.1  riastrad 
    335  1.3  riastrad 		nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
    336  1.3  riastrad 				      &has_optimus_flags, &has_power_resources);
    337  1.1  riastrad 	}
    338  1.1  riastrad 
    339  1.1  riastrad 	/* find the optimus DSM or the old v1 DSM */
    340  1.3  riastrad 	if (has_optimus) {
    341  1.3  riastrad 		nouveau_dsm_priv.dhandle = dhandle;
    342  1.1  riastrad 		acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
    343  1.1  riastrad 			&buffer);
    344  1.3  riastrad 		pr_info("VGA switcheroo: detected Optimus DSM method %s handle\n",
    345  1.1  riastrad 			acpi_method_name);
    346  1.3  riastrad 		if (has_power_resources)
    347  1.3  riastrad 			pr_info("nouveau: detected PR support, will not use DSM\n");
    348  1.1  riastrad 		nouveau_dsm_priv.optimus_detected = true;
    349  1.3  riastrad 		nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags;
    350  1.3  riastrad 		nouveau_dsm_priv.optimus_skip_dsm = has_power_resources;
    351  1.1  riastrad 		ret = true;
    352  1.3  riastrad 	} else if (vga_count == 2 && has_mux && guid_valid) {
    353  1.3  riastrad 		nouveau_dsm_priv.dhandle = dhandle;
    354  1.1  riastrad 		acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
    355  1.1  riastrad 			&buffer);
    356  1.3  riastrad 		pr_info("VGA switcheroo: detected DSM switching method %s handle\n",
    357  1.1  riastrad 			acpi_method_name);
    358  1.1  riastrad 		nouveau_dsm_priv.dsm_detected = true;
    359  1.1  riastrad 		ret = true;
    360  1.1  riastrad 	}
    361  1.1  riastrad 
    362  1.1  riastrad 
    363  1.1  riastrad 	return ret;
    364  1.1  riastrad }
    365  1.1  riastrad 
    366  1.1  riastrad void nouveau_register_dsm_handler(void)
    367  1.1  riastrad {
    368  1.1  riastrad 	bool r;
    369  1.1  riastrad 
    370  1.1  riastrad 	r = nouveau_dsm_detect();
    371  1.1  riastrad 	if (!r)
    372  1.1  riastrad 		return;
    373  1.1  riastrad 
    374  1.3  riastrad 	vga_switcheroo_register_handler(&nouveau_dsm_handler, 0);
    375  1.1  riastrad }
    376  1.1  riastrad 
    377  1.1  riastrad /* Must be called for Optimus models before the card can be turned off */
    378  1.1  riastrad void nouveau_switcheroo_optimus_dsm(void)
    379  1.1  riastrad {
    380  1.1  riastrad 	u32 result = 0;
    381  1.3  riastrad 	if (!nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.optimus_skip_dsm)
    382  1.1  riastrad 		return;
    383  1.1  riastrad 
    384  1.3  riastrad 	if (nouveau_dsm_priv.optimus_flags_detected)
    385  1.3  riastrad 		nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS,
    386  1.3  riastrad 				    0x3, &result);
    387  1.1  riastrad 
    388  1.1  riastrad 	nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS,
    389  1.1  riastrad 		NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result);
    390  1.1  riastrad 
    391  1.1  riastrad }
    392  1.1  riastrad 
    393  1.1  riastrad void nouveau_unregister_dsm_handler(void)
    394  1.1  riastrad {
    395  1.1  riastrad 	if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected)
    396  1.1  riastrad 		vga_switcheroo_unregister_handler();
    397  1.1  riastrad }
    398  1.1  riastrad #else
    399  1.1  riastrad void nouveau_register_dsm_handler(void) {}
    400  1.1  riastrad void nouveau_unregister_dsm_handler(void) {}
    401  1.1  riastrad void nouveau_switcheroo_optimus_dsm(void) {}
    402  1.1  riastrad #endif
    403  1.1  riastrad 
    404  1.1  riastrad /* retrieve the ROM in 4k blocks */
    405  1.1  riastrad static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios,
    406  1.1  riastrad 			    int offset, int len)
    407  1.1  riastrad {
    408  1.1  riastrad 	acpi_status status;
    409  1.1  riastrad 	union acpi_object rom_arg_elements[2], *obj;
    410  1.1  riastrad 	struct acpi_object_list rom_arg;
    411  1.1  riastrad 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
    412  1.1  riastrad 
    413  1.1  riastrad 	rom_arg.count = 2;
    414  1.1  riastrad 	rom_arg.pointer = &rom_arg_elements[0];
    415  1.1  riastrad 
    416  1.1  riastrad 	rom_arg_elements[0].type = ACPI_TYPE_INTEGER;
    417  1.1  riastrad 	rom_arg_elements[0].integer.value = offset;
    418  1.1  riastrad 
    419  1.1  riastrad 	rom_arg_elements[1].type = ACPI_TYPE_INTEGER;
    420  1.1  riastrad 	rom_arg_elements[1].integer.value = len;
    421  1.1  riastrad 
    422  1.1  riastrad 	status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer);
    423  1.1  riastrad 	if (ACPI_FAILURE(status)) {
    424  1.3  riastrad 		pr_info("failed to evaluate ROM got %s\n",
    425  1.3  riastrad 			acpi_format_exception(status));
    426  1.1  riastrad 		return -ENODEV;
    427  1.1  riastrad 	}
    428  1.1  riastrad 	obj = (union acpi_object *)buffer.pointer;
    429  1.2  riastrad 	len = min(len, (int)obj->buffer.length);
    430  1.1  riastrad 	memcpy(bios+offset, obj->buffer.pointer, len);
    431  1.4  riastrad 	ACPI_FREE(buffer.pointer);
    432  1.1  riastrad 	return len;
    433  1.1  riastrad }
    434  1.1  riastrad 
    435  1.5  riastrad #ifdef __NetBSD__
    436  1.5  riastrad bool nouveau_acpi_rom_supported(struct acpi_devnode *acpidev)
    437  1.5  riastrad #else
    438  1.2  riastrad bool nouveau_acpi_rom_supported(struct device *dev)
    439  1.5  riastrad #endif
    440  1.1  riastrad {
    441  1.1  riastrad 	acpi_status status;
    442  1.1  riastrad 	acpi_handle dhandle, rom_handle;
    443  1.1  riastrad 
    444  1.5  riastrad #ifdef __NetBSD__
    445  1.5  riastrad 	dhandle = (acpidev ? acpidev->ad_handle : NULL);
    446  1.5  riastrad #else
    447  1.2  riastrad 	dhandle = ACPI_HANDLE(dev);
    448  1.5  riastrad #endif
    449  1.1  riastrad 	if (!dhandle)
    450  1.1  riastrad 		return false;
    451  1.1  riastrad 
    452  1.1  riastrad 	status = acpi_get_handle(dhandle, "_ROM", &rom_handle);
    453  1.1  riastrad 	if (ACPI_FAILURE(status))
    454  1.1  riastrad 		return false;
    455  1.1  riastrad 
    456  1.1  riastrad 	nouveau_dsm_priv.rom_handle = rom_handle;
    457  1.1  riastrad 	return true;
    458  1.1  riastrad }
    459  1.1  riastrad 
    460  1.1  riastrad int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
    461  1.1  riastrad {
    462  1.1  riastrad 	return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
    463  1.1  riastrad }
    464  1.1  riastrad 
    465  1.1  riastrad void *
    466  1.1  riastrad nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
    467  1.1  riastrad {
    468  1.5  riastrad #ifdef __NetBSD__		/* XXX nouveau acpi video */
    469  1.5  riastrad 	return NULL;
    470  1.5  riastrad #else
    471  1.1  riastrad 	struct acpi_device *acpidev;
    472  1.1  riastrad 	acpi_handle handle;
    473  1.1  riastrad 	int type, ret;
    474  1.1  riastrad 	void *edid;
    475  1.1  riastrad 
    476  1.1  riastrad 	switch (connector->connector_type) {
    477  1.1  riastrad 	case DRM_MODE_CONNECTOR_LVDS:
    478  1.1  riastrad 	case DRM_MODE_CONNECTOR_eDP:
    479  1.1  riastrad 		type = ACPI_VIDEO_DISPLAY_LCD;
    480  1.1  riastrad 		break;
    481  1.1  riastrad 	default:
    482  1.1  riastrad 		return NULL;
    483  1.1  riastrad 	}
    484  1.1  riastrad 
    485  1.5  riastrad #ifdef __NetBSD__
    486  1.5  riastrad 	handle = (dev->pdev->pd_ad ? dev->pdev->pd_ad->ad_handle : NULL);
    487  1.5  riastrad #else
    488  1.1  riastrad 	handle = ACPI_HANDLE(&dev->pdev->dev);
    489  1.5  riastrad #endif
    490  1.1  riastrad 	if (!handle)
    491  1.1  riastrad 		return NULL;
    492  1.1  riastrad 
    493  1.1  riastrad 	ret = acpi_bus_get_device(handle, &acpidev);
    494  1.1  riastrad 	if (ret)
    495  1.1  riastrad 		return NULL;
    496  1.1  riastrad 
    497  1.1  riastrad 	ret = acpi_video_get_edid(acpidev, type, -1, &edid);
    498  1.1  riastrad 	if (ret < 0)
    499  1.1  riastrad 		return NULL;
    500  1.1  riastrad 
    501  1.1  riastrad 	return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
    502  1.5  riastrad #endif
    503  1.1  riastrad }
    504