Bug Summary

File:dev/pci/drm/i915/display/intel_opregion.c
Warning:line 828, column 30
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'fw')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name intel_opregion.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/pci/drm/i915/display/intel_opregion.c

/usr/src/sys/dev/pci/drm/i915/display/intel_opregion.c

1/*
2 * Copyright 2008 Intel Corporation <hong.liu@intel.com>
3 * Copyright 2008 Red Hat <mjg@redhat.com>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NON-INFRINGEMENT. IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 *
26 */
27
28#include <linux/acpi.h>
29#include <linux/dmi.h>
30#include <linux/firmware.h>
31#include <acpi/video.h>
32
33#include "display/intel_panel.h"
34
35#include "i915_drv.h"
36#include "intel_acpi.h"
37#include "intel_display_types.h"
38#include "intel_opregion.h"
39
40#define OPREGION_HEADER_OFFSET0 0
41#define OPREGION_ACPI_OFFSET0x100 0x100
42#define ACPI_CLID0x01ac 0x01ac /* current lid state indicator */
43#define ACPI_CDCK0x01b0 0x01b0 /* current docking state indicator */
44#define OPREGION_SWSCI_OFFSET0x200 0x200
45#define OPREGION_ASLE_OFFSET0x300 0x300
46#define OPREGION_VBT_OFFSET0x400 0x400
47#define OPREGION_ASLE_EXT_OFFSET0x1C00 0x1C00
48
49#define OPREGION_SIGNATURE"IntelGraphicsMem" "IntelGraphicsMem"
50#define MBOX_ACPI(1<<0) (1<<0)
51#define MBOX_SWSCI(1<<1) (1<<1)
52#define MBOX_ASLE(1<<2) (1<<2)
53#define MBOX_ASLE_EXT(1<<4) (1<<4)
54
55struct opregion_header {
56 u8 signature[16];
57 u32 size;
58 struct {
59 u8 rsvd;
60 u8 revision;
61 u8 minor;
62 u8 major;
63 } __packed__attribute__((__packed__)) over;
64 u8 bios_ver[32];
65 u8 vbios_ver[16];
66 u8 driver_ver[16];
67 u32 mboxes;
68 u32 driver_model;
69 u32 pcon;
70 u8 dver[32];
71 u8 rsvd[124];
72} __packed__attribute__((__packed__));
73
74/* OpRegion mailbox #1: public ACPI methods */
75struct opregion_acpi {
76 u32 drdy; /* driver readiness */
77 u32 csts; /* notification status */
78 u32 cevt; /* current event */
79 u8 rsvd1[20];
80 u32 didl[8]; /* supported display devices ID list */
81 u32 cpdl[8]; /* currently presented display list */
82 u32 cadl[8]; /* currently active display list */
83 u32 nadl[8]; /* next active devices list */
84 u32 aslp; /* ASL sleep time-out */
85 u32 tidx; /* toggle table index */
86 u32 chpd; /* current hotplug enable indicator */
87 u32 clid; /* current lid state*/
88 u32 cdck; /* current docking state */
89 u32 sxsw; /* Sx state resume */
90 u32 evts; /* ASL supported events */
91 u32 cnot; /* current OS notification */
92 u32 nrdy; /* driver status */
93 u32 did2[7]; /* extended supported display devices ID list */
94 u32 cpd2[7]; /* extended attached display devices list */
95 u8 rsvd2[4];
96} __packed__attribute__((__packed__));
97
98/* OpRegion mailbox #2: SWSCI */
99struct opregion_swsci {
100 u32 scic; /* SWSCI command|status|data */
101 u32 parm; /* command parameters */
102 u32 dslp; /* driver sleep time-out */
103 u8 rsvd[244];
104} __packed__attribute__((__packed__));
105
106/* OpRegion mailbox #3: ASLE */
107struct opregion_asle {
108 u32 ardy; /* driver readiness */
109 u32 aslc; /* ASLE interrupt command */
110 u32 tche; /* technology enabled indicator */
111 u32 alsi; /* current ALS illuminance reading */
112 u32 bclp; /* backlight brightness to set */
113 u32 pfit; /* panel fitting state */
114 u32 cblv; /* current brightness level */
115 u16 bclm[20]; /* backlight level duty cycle mapping table */
116 u32 cpfm; /* current panel fitting mode */
117 u32 epfm; /* enabled panel fitting modes */
118 u8 plut[74]; /* panel LUT and identifier */
119 u32 pfmb; /* PWM freq and min brightness */
120 u32 cddv; /* color correction default values */
121 u32 pcft; /* power conservation features */
122 u32 srot; /* supported rotation angles */
123 u32 iuer; /* IUER events */
124 u64 fdss;
125 u32 fdsp;
126 u32 stat;
127 u64 rvda; /* Physical (2.0) or relative from opregion (2.1+)
128 * address of raw VBT data. */
129 u32 rvds; /* Size of raw vbt data */
130 u8 rsvd[58];
131} __packed__attribute__((__packed__));
132
133/* OpRegion mailbox #5: ASLE ext */
134struct opregion_asle_ext {
135 u32 phed; /* Panel Header */
136 u8 bddc[256]; /* Panel EDID */
137 u8 rsvd[764];
138} __packed__attribute__((__packed__));
139
140/* Driver readiness indicator */
141#define ASLE_ARDY_READY(1 << 0) (1 << 0)
142#define ASLE_ARDY_NOT_READY(0 << 0) (0 << 0)
143
144/* ASLE Interrupt Command (ASLC) bits */
145#define ASLC_SET_ALS_ILLUM(1 << 0) (1 << 0)
146#define ASLC_SET_BACKLIGHT(1 << 1) (1 << 1)
147#define ASLC_SET_PFIT(1 << 2) (1 << 2)
148#define ASLC_SET_PWM_FREQ(1 << 3) (1 << 3)
149#define ASLC_SUPPORTED_ROTATION_ANGLES(1 << 4) (1 << 4)
150#define ASLC_BUTTON_ARRAY(1 << 5) (1 << 5)
151#define ASLC_CONVERTIBLE_INDICATOR(1 << 6) (1 << 6)
152#define ASLC_DOCKING_INDICATOR(1 << 7) (1 << 7)
153#define ASLC_ISCT_STATE_CHANGE(1 << 8) (1 << 8)
154#define ASLC_REQ_MSK0x1ff 0x1ff
155/* response bits */
156#define ASLC_ALS_ILLUM_FAILED(1 << 10) (1 << 10)
157#define ASLC_BACKLIGHT_FAILED(1 << 12) (1 << 12)
158#define ASLC_PFIT_FAILED(1 << 14) (1 << 14)
159#define ASLC_PWM_FREQ_FAILED(1 << 16) (1 << 16)
160#define ASLC_ROTATION_ANGLES_FAILED(1 << 18) (1 << 18)
161#define ASLC_BUTTON_ARRAY_FAILED(1 << 20) (1 << 20)
162#define ASLC_CONVERTIBLE_FAILED(1 << 22) (1 << 22)
163#define ASLC_DOCKING_FAILED(1 << 24) (1 << 24)
164#define ASLC_ISCT_STATE_FAILED(1 << 26) (1 << 26)
165
166/* Technology enabled indicator */
167#define ASLE_TCHE_ALS_EN(1 << 0) (1 << 0)
168#define ASLE_TCHE_BLC_EN(1 << 1) (1 << 1)
169#define ASLE_TCHE_PFIT_EN(1 << 2) (1 << 2)
170#define ASLE_TCHE_PFMB_EN(1 << 3) (1 << 3)
171
172/* ASLE backlight brightness to set */
173#define ASLE_BCLP_VALID(1<<31) (1<<31)
174#define ASLE_BCLP_MSK(~(1<<31)) (~(1<<31))
175
176/* ASLE panel fitting request */
177#define ASLE_PFIT_VALID(1<<31) (1<<31)
178#define ASLE_PFIT_CENTER(1<<0) (1<<0)
179#define ASLE_PFIT_STRETCH_TEXT(1<<1) (1<<1)
180#define ASLE_PFIT_STRETCH_GFX(1<<2) (1<<2)
181
182/* PWM frequency and minimum brightness */
183#define ASLE_PFMB_BRIGHTNESS_MASK(0xff) (0xff)
184#define ASLE_PFMB_BRIGHTNESS_VALID(1<<8) (1<<8)
185#define ASLE_PFMB_PWM_MASK(0x7ffffe00) (0x7ffffe00)
186#define ASLE_PFMB_PWM_VALID(1<<31) (1<<31)
187
188#define ASLE_CBLV_VALID(1<<31) (1<<31)
189
190/* IUER */
191#define ASLE_IUER_DOCKING(1 << 7) (1 << 7)
192#define ASLE_IUER_CONVERTIBLE(1 << 6) (1 << 6)
193#define ASLE_IUER_ROTATION_LOCK_BTN(1 << 4) (1 << 4)
194#define ASLE_IUER_VOLUME_DOWN_BTN(1 << 3) (1 << 3)
195#define ASLE_IUER_VOLUME_UP_BTN(1 << 2) (1 << 2)
196#define ASLE_IUER_WINDOWS_BTN(1 << 1) (1 << 1)
197#define ASLE_IUER_POWER_BTN(1 << 0) (1 << 0)
198
199/* Software System Control Interrupt (SWSCI) */
200#define SWSCI_SCIC_INDICATOR(1 << 0) (1 << 0)
201#define SWSCI_SCIC_MAIN_FUNCTION_SHIFT1 1
202#define SWSCI_SCIC_MAIN_FUNCTION_MASK(0xf << 1) (0xf << 1)
203#define SWSCI_SCIC_SUB_FUNCTION_SHIFT8 8
204#define SWSCI_SCIC_SUB_FUNCTION_MASK(0xff << 8) (0xff << 8)
205#define SWSCI_SCIC_EXIT_PARAMETER_SHIFT8 8
206#define SWSCI_SCIC_EXIT_PARAMETER_MASK(0xff << 8) (0xff << 8)
207#define SWSCI_SCIC_EXIT_STATUS_SHIFT5 5
208#define SWSCI_SCIC_EXIT_STATUS_MASK(7 << 5) (7 << 5)
209#define SWSCI_SCIC_EXIT_STATUS_SUCCESS1 1
210
211#define SWSCI_FUNCTION_CODE(main, sub)((main) << 1 | (sub) << 8) \
212 ((main) << SWSCI_SCIC_MAIN_FUNCTION_SHIFT1 | \
213 (sub) << SWSCI_SCIC_SUB_FUNCTION_SHIFT8)
214
215/* SWSCI: Get BIOS Data (GBDA) */
216#define SWSCI_GBDA4 4
217#define SWSCI_GBDA_SUPPORTED_CALLS((4) << 1 | (0) << 8) SWSCI_FUNCTION_CODE(SWSCI_GBDA, 0)((4) << 1 | (0) << 8)
218#define SWSCI_GBDA_REQUESTED_CALLBACKS((4) << 1 | (1) << 8) SWSCI_FUNCTION_CODE(SWSCI_GBDA, 1)((4) << 1 | (1) << 8)
219#define SWSCI_GBDA_BOOT_DISPLAY_PREF((4) << 1 | (4) << 8) SWSCI_FUNCTION_CODE(SWSCI_GBDA, 4)((4) << 1 | (4) << 8)
220#define SWSCI_GBDA_PANEL_DETAILS((4) << 1 | (5) << 8) SWSCI_FUNCTION_CODE(SWSCI_GBDA, 5)((4) << 1 | (5) << 8)
221#define SWSCI_GBDA_TV_STANDARD((4) << 1 | (6) << 8) SWSCI_FUNCTION_CODE(SWSCI_GBDA, 6)((4) << 1 | (6) << 8)
222#define SWSCI_GBDA_INTERNAL_GRAPHICS((4) << 1 | (7) << 8) SWSCI_FUNCTION_CODE(SWSCI_GBDA, 7)((4) << 1 | (7) << 8)
223#define SWSCI_GBDA_SPREAD_SPECTRUM((4) << 1 | (10) << 8) SWSCI_FUNCTION_CODE(SWSCI_GBDA, 10)((4) << 1 | (10) << 8)
224
225/* SWSCI: System BIOS Callbacks (SBCB) */
226#define SWSCI_SBCB6 6
227#define SWSCI_SBCB_SUPPORTED_CALLBACKS((6) << 1 | (0) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 0)((6) << 1 | (0) << 8)
228#define SWSCI_SBCB_INIT_COMPLETION((6) << 1 | (1) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 1)((6) << 1 | (1) << 8)
229#define SWSCI_SBCB_PRE_HIRES_SET_MODE((6) << 1 | (3) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 3)((6) << 1 | (3) << 8)
230#define SWSCI_SBCB_POST_HIRES_SET_MODE((6) << 1 | (4) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 4)((6) << 1 | (4) << 8)
231#define SWSCI_SBCB_DISPLAY_SWITCH((6) << 1 | (5) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 5)((6) << 1 | (5) << 8)
232#define SWSCI_SBCB_SET_TV_FORMAT((6) << 1 | (6) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 6)((6) << 1 | (6) << 8)
233#define SWSCI_SBCB_ADAPTER_POWER_STATE((6) << 1 | (7) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 7)((6) << 1 | (7) << 8)
234#define SWSCI_SBCB_DISPLAY_POWER_STATE((6) << 1 | (8) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 8)((6) << 1 | (8) << 8)
235#define SWSCI_SBCB_SET_BOOT_DISPLAY((6) << 1 | (9) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 9)((6) << 1 | (9) << 8)
236#define SWSCI_SBCB_SET_PANEL_DETAILS((6) << 1 | (10) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 10)((6) << 1 | (10) << 8)
237#define SWSCI_SBCB_SET_INTERNAL_GFX((6) << 1 | (11) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 11)((6) << 1 | (11) << 8)
238#define SWSCI_SBCB_POST_HIRES_TO_DOS_FS((6) << 1 | (16) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 16)((6) << 1 | (16) << 8)
239#define SWSCI_SBCB_SUSPEND_RESUME((6) << 1 | (17) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 17)((6) << 1 | (17) << 8)
240#define SWSCI_SBCB_SET_SPREAD_SPECTRUM((6) << 1 | (18) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 18)((6) << 1 | (18) << 8)
241#define SWSCI_SBCB_POST_VBE_PM((6) << 1 | (19) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19)((6) << 1 | (19) << 8)
242#define SWSCI_SBCB_ENABLE_DISABLE_AUDIO((6) << 1 | (21) << 8) SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21)((6) << 1 | (21) << 8)
243
244#define MAX_DSLP1500 1500
245
246static int swsci(struct drm_i915_privateinteldrm_softc *dev_priv,
247 u32 function, u32 parm, u32 *parm_out)
248{
249 struct opregion_swsci *swsci = dev_priv->opregion.swsci;
250 struct pci_dev *pdev = dev_priv->drm.pdev;
251 u32 main_function, sub_function, scic;
252 u16 swsci_val;
253 u32 dslp;
254
255 if (!swsci)
256 return -ENODEV19;
257
258 main_function = (function & SWSCI_SCIC_MAIN_FUNCTION_MASK(0xf << 1)) >>
259 SWSCI_SCIC_MAIN_FUNCTION_SHIFT1;
260 sub_function = (function & SWSCI_SCIC_SUB_FUNCTION_MASK(0xff << 8)) >>
261 SWSCI_SCIC_SUB_FUNCTION_SHIFT8;
262
263 /* Check if we can call the function. See swsci_setup for details. */
264 if (main_function == SWSCI_SBCB6) {
265 if ((dev_priv->opregion.swsci_sbcb_sub_functions &
266 (1 << sub_function)) == 0)
267 return -EINVAL22;
268 } else if (main_function == SWSCI_GBDA4) {
269 if ((dev_priv->opregion.swsci_gbda_sub_functions &
270 (1 << sub_function)) == 0)
271 return -EINVAL22;
272 }
273
274 /* Driver sleep timeout in ms. */
275 dslp = swsci->dslp;
276 if (!dslp) {
277 /* The spec says 2ms should be the default, but it's too small
278 * for some machines. */
279 dslp = 50;
280 } else if (dslp > MAX_DSLP1500) {
281 /* Hey bios, trust must be earned. */
282 DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, "({ static int __warned; if (!__warned) { printk("\0016" "[" "drm"
"] " "ACPI BIOS requests an excessive sleep of %u ms, " "using %u ms instead\n"
, dslp, 1500); __warned = 1; } })
283 "using %u ms instead\n", dslp, MAX_DSLP)({ static int __warned; if (!__warned) { printk("\0016" "[" "drm"
"] " "ACPI BIOS requests an excessive sleep of %u ms, " "using %u ms instead\n"
, dslp, 1500); __warned = 1; } })
;
284 dslp = MAX_DSLP1500;
285 }
286
287 /* The spec tells us to do this, but we are the only user... */
288 scic = swsci->scic;
289 if (scic & SWSCI_SCIC_INDICATOR(1 << 0)) {
290 drm_dbg(&dev_priv->drm, "SWSCI request already in progress\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI request already in progress\n"
)
;
291 return -EBUSY16;
292 }
293
294 scic = function | SWSCI_SCIC_INDICATOR(1 << 0);
295
296 swsci->parm = parm;
297 swsci->scic = scic;
298
299 /* Ensure SCI event is selected and event trigger is cleared. */
300 pci_read_config_word(pdev, SWSCI0xe8, &swsci_val);
301 if (!(swsci_val & SWSCI_SCISEL(1 << 15)) || (swsci_val & SWSCI_GSSCIE(1 << 0))) {
302 swsci_val |= SWSCI_SCISEL(1 << 15);
303 swsci_val &= ~SWSCI_GSSCIE(1 << 0);
304 pci_write_config_word(pdev, SWSCI0xe8, swsci_val);
305 }
306
307 /* Use event trigger to tell bios to check the mail. */
308 swsci_val |= SWSCI_GSSCIE(1 << 0);
309 pci_write_config_word(pdev, SWSCI0xe8, swsci_val);
310
311 /* Poll for the result. */
312#define C (((scic = swsci->scic) & SWSCI_SCIC_INDICATOR(1 << 0)) == 0)
313 if (wait_for(C, dslp)({ const ktime_t end__ = ktime_add_ns(ktime_get_raw(), 1000ll
* (((dslp) * 1000))); long wait__ = ((10)); int ret__; assertwaitok
(); for (;;) { const _Bool expired__ = ktime_after(ktime_get_raw
(), end__); ; __asm volatile("" : : : "memory"); if (((C))) {
ret__ = 0; break; } if (expired__) { ret__ = -60; break; } usleep_range
(wait__, wait__ * 2); if (wait__ < ((1000))) wait__ <<=
1; } ret__; })
) {
314 drm_dbg(&dev_priv->drm, "SWSCI request timed out\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI request timed out\n"
)
;
315 return -ETIMEDOUT60;
316 }
317
318 scic = (scic & SWSCI_SCIC_EXIT_STATUS_MASK(7 << 5)) >>
319 SWSCI_SCIC_EXIT_STATUS_SHIFT5;
320
321 /* Note: scic == 0 is an error! */
322 if (scic != SWSCI_SCIC_EXIT_STATUS_SUCCESS1) {
323 drm_dbg(&dev_priv->drm, "SWSCI request error %u\n", scic)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI request error %u\n"
, scic)
;
324 return -EIO5;
325 }
326
327 if (parm_out)
328 *parm_out = swsci->parm;
329
330 return 0;
331
332#undef C
333}
334
335#define DISPLAY_TYPE_CRT0 0
336#define DISPLAY_TYPE_TV1 1
337#define DISPLAY_TYPE_EXTERNAL_FLAT_PANEL2 2
338#define DISPLAY_TYPE_INTERNAL_FLAT_PANEL3 3
339
340int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
341 bool_Bool enable)
342{
343 struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(intel_encoder->base.dev);
344 u32 parm = 0;
345 u32 type = 0;
346 u32 port;
347
348 /* don't care about old stuff for now */
349 if (!HAS_DDI(dev_priv)((&(dev_priv)->__info)->display.has_ddi))
350 return 0;
351
352 if (intel_encoder->type == INTEL_OUTPUT_DSI)
353 port = 0;
354 else
355 port = intel_encoder->port;
356
357 if (port == PORT_E) {
358 port = 0;
359 } else {
360 parm |= 1 << port;
361 port++;
362 }
363
364 if (!enable)
365 parm |= 4 << 8;
366
367 switch (intel_encoder->type) {
368 case INTEL_OUTPUT_ANALOG:
369 type = DISPLAY_TYPE_CRT0;
370 break;
371 case INTEL_OUTPUT_DDI:
372 case INTEL_OUTPUT_DP:
373 case INTEL_OUTPUT_HDMI:
374 case INTEL_OUTPUT_DP_MST:
375 type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL2;
376 break;
377 case INTEL_OUTPUT_EDP:
378 case INTEL_OUTPUT_DSI:
379 type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL3;
380 break;
381 default:
382 drm_WARN_ONCE(&dev_priv->drm, 1,({ static int __warned; int __ret = !!(1); if (__ret &&
!__warned) { printf("%s %s: " "unsupported intel_encoder type %d\n"
, dev_driver_string((&dev_priv->drm)->dev), "", intel_encoder
->type); __warned = 1; } __builtin_expect(!!(__ret), 0); }
)
383 "unsupported intel_encoder type %d\n",({ static int __warned; int __ret = !!(1); if (__ret &&
!__warned) { printf("%s %s: " "unsupported intel_encoder type %d\n"
, dev_driver_string((&dev_priv->drm)->dev), "", intel_encoder
->type); __warned = 1; } __builtin_expect(!!(__ret), 0); }
)
384 intel_encoder->type)({ static int __warned; int __ret = !!(1); if (__ret &&
!__warned) { printf("%s %s: " "unsupported intel_encoder type %d\n"
, dev_driver_string((&dev_priv->drm)->dev), "", intel_encoder
->type); __warned = 1; } __builtin_expect(!!(__ret), 0); }
)
;
385 return -EINVAL22;
386 }
387
388 parm |= type << (16 + port * 3);
389
390 return swsci(dev_priv, SWSCI_SBCB_DISPLAY_POWER_STATE((6) << 1 | (8) << 8), parm, NULL((void *)0));
391}
392
393static const struct {
394 pci_power_t pci_power_state;
395 u32 parm;
396} power_state_map[] = {
397 { PCI_D0, 0x00 },
398 { PCI_D1, 0x01 },
399 { PCI_D2, 0x02 },
400 { PCI_D3hot, 0x04 },
401 { PCI_D3cold, 0x04 },
402};
403
404int intel_opregion_notify_adapter(struct drm_i915_privateinteldrm_softc *dev_priv,
405 pci_power_t state)
406{
407 int i;
408
409 if (!HAS_DDI(dev_priv)((&(dev_priv)->__info)->display.has_ddi))
410 return 0;
411
412 for (i = 0; i < ARRAY_SIZE(power_state_map)(sizeof((power_state_map)) / sizeof((power_state_map)[0])); i++) {
413 if (state == power_state_map[i].pci_power_state)
414 return swsci(dev_priv, SWSCI_SBCB_ADAPTER_POWER_STATE((6) << 1 | (7) << 8),
415 power_state_map[i].parm, NULL((void *)0));
416 }
417
418 return -EINVAL22;
419}
420
421static u32 asle_set_backlight(struct drm_i915_privateinteldrm_softc *dev_priv, u32 bclp)
422{
423 struct intel_connector *connector;
424 struct drm_connector_list_iter conn_iter;
425 struct opregion_asle *asle = dev_priv->opregion.asle;
426 struct drm_device *dev = &dev_priv->drm;
427
428 drm_dbg(&dev_priv->drm, "bclp = 0x%08x\n", bclp)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "bclp = 0x%08x\n"
, bclp)
;
429
430#ifdef __linux__
431 if (acpi_video_get_backlight_type() == acpi_backlight_native) {
432 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "opregion backlight request ignored\n"
)
433 "opregion backlight request ignored\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "opregion backlight request ignored\n"
)
;
434 return 0;
435 }
436#endif
437
438 if (!(bclp & ASLE_BCLP_VALID(1<<31)))
439 return ASLC_BACKLIGHT_FAILED(1 << 12);
440
441 bclp &= ASLE_BCLP_MSK(~(1<<31));
442 if (bclp > 255)
443 return ASLC_BACKLIGHT_FAILED(1 << 12);
444
445 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL((void *)0));
446
447 /*
448 * Update backlight on all connectors that support backlight (usually
449 * only one).
450 */
451 drm_dbg_kms(&dev_priv->drm, "updating opregion backlight %d/255\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "updating opregion backlight %d/255\n"
, bclp)
452 bclp)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "updating opregion backlight %d/255\n"
, bclp)
;
453 drm_connector_list_iter_begin(dev, &conn_iter);
454 for_each_intel_connector_iter(connector, &conn_iter)while ((connector = ({ const __typeof( ((struct intel_connector
*)0)->base ) *__mptr = (drm_connector_list_iter_next(&
conn_iter)); (struct intel_connector *)( (char *)__mptr - __builtin_offsetof
(struct intel_connector, base) );})))
455 intel_panel_set_backlight_acpi(connector->base.state, bclp, 255);
456 drm_connector_list_iter_end(&conn_iter);
457 asle->cblv = DIV_ROUND_UP(bclp * 100, 255)(((bclp * 100) + ((255) - 1)) / (255)) | ASLE_CBLV_VALID(1<<31);
458
459 drm_modeset_unlock(&dev->mode_config.connection_mutex);
460
461
462 return 0;
463}
464
465static u32 asle_set_als_illum(struct drm_i915_privateinteldrm_softc *dev_priv, u32 alsi)
466{
467 /* alsi is the current ALS reading in lux. 0 indicates below sensor
468 range, 0xffff indicates above sensor range. 1-0xfffe are valid */
469 drm_dbg(&dev_priv->drm, "Illum is not supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Illum is not supported\n"
)
;
470 return ASLC_ALS_ILLUM_FAILED(1 << 10);
471}
472
473static u32 asle_set_pwm_freq(struct drm_i915_privateinteldrm_softc *dev_priv, u32 pfmb)
474{
475 drm_dbg(&dev_priv->drm, "PWM freq is not supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "PWM freq is not supported\n"
)
;
476 return ASLC_PWM_FREQ_FAILED(1 << 16);
477}
478
479static u32 asle_set_pfit(struct drm_i915_privateinteldrm_softc *dev_priv, u32 pfit)
480{
481 /* Panel fitting is currently controlled by the X code, so this is a
482 noop until modesetting support works fully */
483 drm_dbg(&dev_priv->drm, "Pfit is not supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Pfit is not supported\n"
)
;
484 return ASLC_PFIT_FAILED(1 << 14);
485}
486
487static u32 asle_set_supported_rotation_angles(struct drm_i915_privateinteldrm_softc *dev_priv, u32 srot)
488{
489 drm_dbg(&dev_priv->drm, "SROT is not supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SROT is not supported\n"
)
;
490 return ASLC_ROTATION_ANGLES_FAILED(1 << 18);
491}
492
493static u32 asle_set_button_array(struct drm_i915_privateinteldrm_softc *dev_priv, u32 iuer)
494{
495 if (!iuer)
496 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (nothing)\n"
)
497 "Button array event is not supported (nothing)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (nothing)\n"
)
;
498 if (iuer & ASLE_IUER_ROTATION_LOCK_BTN(1 << 4))
499 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (rotation lock)\n"
)
500 "Button array event is not supported (rotation lock)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (rotation lock)\n"
)
;
501 if (iuer & ASLE_IUER_VOLUME_DOWN_BTN(1 << 3))
502 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (volume down)\n"
)
503 "Button array event is not supported (volume down)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (volume down)\n"
)
;
504 if (iuer & ASLE_IUER_VOLUME_UP_BTN(1 << 2))
505 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (volume up)\n"
)
506 "Button array event is not supported (volume up)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (volume up)\n"
)
;
507 if (iuer & ASLE_IUER_WINDOWS_BTN(1 << 1))
508 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (windows)\n"
)
509 "Button array event is not supported (windows)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (windows)\n"
)
;
510 if (iuer & ASLE_IUER_POWER_BTN(1 << 0))
511 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (power)\n"
)
512 "Button array event is not supported (power)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Button array event is not supported (power)\n"
)
;
513
514 return ASLC_BUTTON_ARRAY_FAILED(1 << 20);
515}
516
517static u32 asle_set_convertible(struct drm_i915_privateinteldrm_softc *dev_priv, u32 iuer)
518{
519 if (iuer & ASLE_IUER_CONVERTIBLE(1 << 6))
520 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Convertible is not supported (clamshell)\n"
)
521 "Convertible is not supported (clamshell)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Convertible is not supported (clamshell)\n"
)
;
522 else
523 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Convertible is not supported (slate)\n"
)
524 "Convertible is not supported (slate)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Convertible is not supported (slate)\n"
)
;
525
526 return ASLC_CONVERTIBLE_FAILED(1 << 22);
527}
528
529static u32 asle_set_docking(struct drm_i915_privateinteldrm_softc *dev_priv, u32 iuer)
530{
531 if (iuer & ASLE_IUER_DOCKING(1 << 7))
532 drm_dbg(&dev_priv->drm, "Docking is not supported (docked)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Docking is not supported (docked)\n"
)
;
533 else
534 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Docking is not supported (undocked)\n"
)
535 "Docking is not supported (undocked)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Docking is not supported (undocked)\n"
)
;
536
537 return ASLC_DOCKING_FAILED(1 << 24);
538}
539
540static u32 asle_isct_state(struct drm_i915_privateinteldrm_softc *dev_priv)
541{
542 drm_dbg(&dev_priv->drm, "ISCT is not supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ISCT is not supported\n"
)
;
543 return ASLC_ISCT_STATE_FAILED(1 << 26);
544}
545
546static void asle_work(struct work_struct *work)
547{
548 struct intel_opregion *opregion =
549 container_of(work, struct intel_opregion, asle_work)({ const __typeof( ((struct intel_opregion *)0)->asle_work
) *__mptr = (work); (struct intel_opregion *)( (char *)__mptr
- __builtin_offsetof(struct intel_opregion, asle_work) );})
;
550 struct drm_i915_privateinteldrm_softc *dev_priv =
551 container_of(opregion, struct drm_i915_private, opregion)({ const __typeof( ((struct inteldrm_softc *)0)->opregion )
*__mptr = (opregion); (struct inteldrm_softc *)( (char *)__mptr
- __builtin_offsetof(struct inteldrm_softc, opregion) );})
;
552 struct opregion_asle *asle = dev_priv->opregion.asle;
553 u32 aslc_stat = 0;
554 u32 aslc_req;
555
556 if (!asle)
557 return;
558
559 aslc_req = asle->aslc;
560
561 if (!(aslc_req & ASLC_REQ_MSK0x1ff)) {
562 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "No request on ASLC interrupt 0x%08x\n"
, aslc_req)
563 "No request on ASLC interrupt 0x%08x\n", aslc_req)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "No request on ASLC interrupt 0x%08x\n"
, aslc_req)
;
564 return;
565 }
566
567 if (aslc_req & ASLC_SET_ALS_ILLUM(1 << 0))
568 aslc_stat |= asle_set_als_illum(dev_priv, asle->alsi);
569
570 if (aslc_req & ASLC_SET_BACKLIGHT(1 << 1))
571 aslc_stat |= asle_set_backlight(dev_priv, asle->bclp);
572
573 if (aslc_req & ASLC_SET_PFIT(1 << 2))
574 aslc_stat |= asle_set_pfit(dev_priv, asle->pfit);
575
576 if (aslc_req & ASLC_SET_PWM_FREQ(1 << 3))
577 aslc_stat |= asle_set_pwm_freq(dev_priv, asle->pfmb);
578
579 if (aslc_req & ASLC_SUPPORTED_ROTATION_ANGLES(1 << 4))
580 aslc_stat |= asle_set_supported_rotation_angles(dev_priv,
581 asle->srot);
582
583 if (aslc_req & ASLC_BUTTON_ARRAY(1 << 5))
584 aslc_stat |= asle_set_button_array(dev_priv, asle->iuer);
585
586 if (aslc_req & ASLC_CONVERTIBLE_INDICATOR(1 << 6))
587 aslc_stat |= asle_set_convertible(dev_priv, asle->iuer);
588
589 if (aslc_req & ASLC_DOCKING_INDICATOR(1 << 7))
590 aslc_stat |= asle_set_docking(dev_priv, asle->iuer);
591
592 if (aslc_req & ASLC_ISCT_STATE_CHANGE(1 << 8))
593 aslc_stat |= asle_isct_state(dev_priv);
594
595 asle->aslc = aslc_stat;
596}
597
598void intel_opregion_asle_intr(struct drm_i915_privateinteldrm_softc *dev_priv)
599{
600 if (dev_priv->opregion.asle)
601 schedule_work(&dev_priv->opregion.asle_work);
602}
603
604#define ACPI_EV_DISPLAY_SWITCH(1<<0) (1<<0)
605#define ACPI_EV_LID(1<<1) (1<<1)
606#define ACPI_EV_DOCK(1<<2) (1<<2)
607
608#ifdef notyet
609
610/*
611 * The only video events relevant to opregion are 0x80. These indicate either a
612 * docking event, lid switch or display switch request. In Linux, these are
613 * handled by the dock, button and video drivers.
614 */
615static int intel_opregion_video_event(struct notifier_block *nb,
616 unsigned long val, void *data)
617{
618 struct intel_opregion *opregion = container_of(nb, struct intel_opregion,({ const __typeof( ((struct intel_opregion *)0)->acpi_notifier
) *__mptr = (nb); (struct intel_opregion *)( (char *)__mptr -
__builtin_offsetof(struct intel_opregion, acpi_notifier) );}
)
619 acpi_notifier)({ const __typeof( ((struct intel_opregion *)0)->acpi_notifier
) *__mptr = (nb); (struct intel_opregion *)( (char *)__mptr -
__builtin_offsetof(struct intel_opregion, acpi_notifier) );}
)
;
620 struct acpi_bus_event *event = data;
621 struct opregion_acpi *acpi;
622 int ret = NOTIFY_OK1;
623
624 if (strcmp(event->device_class, ACPI_VIDEO_CLASS"video") != 0)
625 return NOTIFY_DONE0;
626
627 acpi = opregion->acpi;
628
629 if (event->type == 0x80 && ((acpi->cevt & 1) == 0))
630 ret = NOTIFY_BAD2;
631
632 acpi->csts = 0;
633
634 return ret;
635}
636
637/*
638 * Initialise the DIDL field in opregion. This passes a list of devices to
639 * the firmware. Values are defined by section B.4.2 of the ACPI specification
640 * (version 3)
641 */
642
643static void set_did(struct intel_opregion *opregion, int i, u32 val)
644{
645 if (i < ARRAY_SIZE(opregion->acpi->didl)(sizeof((opregion->acpi->didl)) / sizeof((opregion->
acpi->didl)[0]))
) {
646 opregion->acpi->didl[i] = val;
647 } else {
648 i -= ARRAY_SIZE(opregion->acpi->didl)(sizeof((opregion->acpi->didl)) / sizeof((opregion->
acpi->didl)[0]))
;
649
650 if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2))({ int __ret = !!((i >= (sizeof((opregion->acpi->did2
)) / sizeof((opregion->acpi->did2)[0])))); if (__ret) printf
("%s", "WARN_ON(" "i >= (sizeof((opregion->acpi->did2)) / sizeof((opregion->acpi->did2)[0]))"
")"); __builtin_expect(!!(__ret), 0); })
)
651 return;
652
653 opregion->acpi->did2[i] = val;
654 }
655}
656
657static void intel_didl_outputs(struct drm_i915_privateinteldrm_softc *dev_priv)
658{
659 struct intel_opregion *opregion = &dev_priv->opregion;
660 struct intel_connector *connector;
661 struct drm_connector_list_iter conn_iter;
662 int i = 0, max_outputs;
663
664 /*
665 * In theory, did2, the extended didl, gets added at opregion version
666 * 3.0. In practice, however, we're supposed to set it for earlier
667 * versions as well, since a BIOS that doesn't understand did2 should
668 * not look at it anyway. Use a variable so we can tweak this if a need
669 * arises later.
670 */
671 max_outputs = ARRAY_SIZE(opregion->acpi->didl)(sizeof((opregion->acpi->didl)) / sizeof((opregion->
acpi->didl)[0]))
+
672 ARRAY_SIZE(opregion->acpi->did2)(sizeof((opregion->acpi->did2)) / sizeof((opregion->
acpi->did2)[0]))
;
673
674 intel_acpi_device_id_update(dev_priv);
675
676 drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
677 for_each_intel_connector_iter(connector, &conn_iter)while ((connector = ({ const __typeof( ((struct intel_connector
*)0)->base ) *__mptr = (drm_connector_list_iter_next(&
conn_iter)); (struct intel_connector *)( (char *)__mptr - __builtin_offsetof
(struct intel_connector, base) );})))
{
678 if (i < max_outputs)
679 set_did(opregion, i, connector->acpi_device_id);
680 i++;
681 }
682 drm_connector_list_iter_end(&conn_iter);
683
684 drm_dbg_kms(&dev_priv->drm, "%d outputs detected\n", i)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "%d outputs detected\n"
, i)
;
685
686 if (i > max_outputs)
687 drm_err(&dev_priv->drm,printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "More than %d outputs in connector list\n"
, ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc->p_p->ps_pid, __func__ , max_outputs
)
688 "More than %d outputs in connector list\n",printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "More than %d outputs in connector list\n"
, ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc->p_p->ps_pid, __func__ , max_outputs
)
689 max_outputs)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "More than %d outputs in connector list\n"
, ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc->p_p->ps_pid, __func__ , max_outputs
)
;
690
691 /* If fewer than max outputs, the list must be null terminated */
692 if (i < max_outputs)
693 set_did(opregion, i, 0);
694}
695
696static void intel_setup_cadls(struct drm_i915_privateinteldrm_softc *dev_priv)
697{
698 struct intel_opregion *opregion = &dev_priv->opregion;
699 struct intel_connector *connector;
700 struct drm_connector_list_iter conn_iter;
701 int i = 0;
702
703 /*
704 * Initialize the CADL field from the connector device ids. This is
705 * essentially the same as copying from the DIDL. Technically, this is
706 * not always correct as display outputs may exist, but not active. This
707 * initialization is necessary for some Clevo laptops that check this
708 * field before processing the brightness and display switching hotkeys.
709 *
710 * Note that internal panels should be at the front of the connector
711 * list already, ensuring they're not left out.
712 */
713 drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
714 for_each_intel_connector_iter(connector, &conn_iter)while ((connector = ({ const __typeof( ((struct intel_connector
*)0)->base ) *__mptr = (drm_connector_list_iter_next(&
conn_iter)); (struct intel_connector *)( (char *)__mptr - __builtin_offsetof
(struct intel_connector, base) );})))
{
715 if (i >= ARRAY_SIZE(opregion->acpi->cadl)(sizeof((opregion->acpi->cadl)) / sizeof((opregion->
acpi->cadl)[0]))
)
716 break;
717 opregion->acpi->cadl[i++] = connector->acpi_device_id;
718 }
719 drm_connector_list_iter_end(&conn_iter);
720
721 /* If fewer than 8 active devices, the list must be null terminated */
722 if (i < ARRAY_SIZE(opregion->acpi->cadl)(sizeof((opregion->acpi->cadl)) / sizeof((opregion->
acpi->cadl)[0]))
)
723 opregion->acpi->cadl[i] = 0;
724}
725
726#endif
727
728static void swsci_setup(struct drm_i915_privateinteldrm_softc *dev_priv)
729{
730 struct intel_opregion *opregion = &dev_priv->opregion;
731 bool_Bool requested_callbacks = false0;
732 u32 tmp;
733
734 /* Sub-function code 0 is okay, let's allow them. */
735 opregion->swsci_gbda_sub_functions = 1;
736 opregion->swsci_sbcb_sub_functions = 1;
737
738 /* We use GBDA to ask for supported GBDA calls. */
739 if (swsci(dev_priv, SWSCI_GBDA_SUPPORTED_CALLS((4) << 1 | (0) << 8), 0, &tmp) == 0) {
740 /* make the bits match the sub-function codes */
741 tmp <<= 1;
742 opregion->swsci_gbda_sub_functions |= tmp;
743 }
744
745 /*
746 * We also use GBDA to ask for _requested_ SBCB callbacks. The driver
747 * must not call interfaces that are not specifically requested by the
748 * bios.
749 */
750 if (swsci(dev_priv, SWSCI_GBDA_REQUESTED_CALLBACKS((4) << 1 | (1) << 8), 0, &tmp) == 0) {
751 /* here, the bits already match sub-function codes */
752 opregion->swsci_sbcb_sub_functions |= tmp;
753 requested_callbacks = true1;
754 }
755
756 /*
757 * But we use SBCB to ask for _supported_ SBCB calls. This does not mean
758 * the callback is _requested_. But we still can't call interfaces that
759 * are not requested.
760 */
761 if (swsci(dev_priv, SWSCI_SBCB_SUPPORTED_CALLBACKS((6) << 1 | (0) << 8), 0, &tmp) == 0) {
762 /* make the bits match the sub-function codes */
763 u32 low = tmp & 0x7ff;
764 u32 high = tmp & ~0xfff; /* bit 11 is reserved */
765 tmp = (high << 4) | (low << 1) | 1;
766
767 /* best guess what to do with supported wrt requested */
768 if (requested_callbacks) {
769 u32 req = opregion->swsci_sbcb_sub_functions;
770 if ((req & tmp) != req)
771 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n"
, req, tmp)
772 "SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n"
, req, tmp)
773 req, tmp)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n"
, req, tmp)
;
774 /* XXX: for now, trust the requested callbacks */
775 /* opregion->swsci_sbcb_sub_functions &= tmp; */
776 } else {
777 opregion->swsci_sbcb_sub_functions |= tmp;
778 }
779 }
780
781 drm_dbg(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n"
, opregion->swsci_gbda_sub_functions, opregion->swsci_sbcb_sub_functions
)
782 "SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n"
, opregion->swsci_gbda_sub_functions, opregion->swsci_sbcb_sub_functions
)
783 opregion->swsci_gbda_sub_functions,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n"
, opregion->swsci_gbda_sub_functions, opregion->swsci_sbcb_sub_functions
)
784 opregion->swsci_sbcb_sub_functions)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n"
, opregion->swsci_gbda_sub_functions, opregion->swsci_sbcb_sub_functions
)
;
785}
786
787static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
788{
789 DRM_DEBUG_KMS("Falling back to manually reading VBT from "__drm_dbg(DRM_UT_KMS, "Falling back to manually reading VBT from "
"VBIOS ROM for %s\n", id->ident)
790 "VBIOS ROM for %s\n", id->ident)__drm_dbg(DRM_UT_KMS, "Falling back to manually reading VBT from "
"VBIOS ROM for %s\n", id->ident)
;
791 return 1;
792}
793
794static const struct dmi_system_id intel_no_opregion_vbt[] = {
795 {
796 .callback = intel_no_opregion_vbt_callback,
797 .ident = "ThinkCentre A57",
798 .matches = {
799 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"){(DMI_SYS_VENDOR), ("LENOVO")},
800 DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"){(DMI_PRODUCT_NAME), ("97027RG")},
801 },
802 },
803 { }
804};
805
806static int intel_load_vbt_firmware(struct drm_i915_privateinteldrm_softc *dev_priv)
807{
808 struct intel_opregion *opregion = &dev_priv->opregion;
809 const struct firmware *fw = NULL((void *)0);
810 const char *name = dev_priv->params.vbt_firmware;
811 int ret;
812
813 if (!name || !*name)
16
Assuming 'name' is non-null
17
Assuming the condition is false
18
Taking false branch
814 return -ENOENT2;
815
816#ifdef __linux__
817 ret = request_firmware(&fw, name, &dev_priv->drm.pdev->dev);
818#else
819 ret = request_firmware(&fw, name, NULL((void *)0));
19
Calling 'request_firmware'
23
Returning from 'request_firmware'
820#endif
821 if (ret) {
24
Assuming 'ret' is 0
25
Taking false branch
822 drm_err(&dev_priv->drm,printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Requesting VBT firmware \"%s\" failed (%d)\n"
, ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc->p_p->ps_pid, __func__ , name, ret
)
823 "Requesting VBT firmware \"%s\" failed (%d)\n",printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Requesting VBT firmware \"%s\" failed (%d)\n"
, ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc->p_p->ps_pid, __func__ , name, ret
)
824 name, ret)printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Requesting VBT firmware \"%s\" failed (%d)\n"
, ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc->p_p->ps_pid, __func__ , name, ret
)
;
825 return ret;
826 }
827
828 if (intel_bios_is_valid_vbt(fw->data, fw->size)) {
26
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'fw')
829 opregion->vbt_firmware = kmemdup(fw->data, fw->size, GFP_KERNEL(0x0001 | 0x0004));
830 if (opregion->vbt_firmware) {
831 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Found valid VBT firmware \"%s\"\n"
, name)
832 "Found valid VBT firmware \"%s\"\n", name)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Found valid VBT firmware \"%s\"\n"
, name)
;
833 opregion->vbt = opregion->vbt_firmware;
834 opregion->vbt_size = fw->size;
835 ret = 0;
836 } else {
837 ret = -ENOMEM12;
838 }
839 } else {
840 drm_dbg_kms(&dev_priv->drm, "Invalid VBT firmware \"%s\"\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid VBT firmware \"%s\"\n"
, name)
841 name)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid VBT firmware \"%s\"\n"
, name)
;
842 ret = -EINVAL22;
843 }
844
845 release_firmware(fw);
846
847 return ret;
848}
849
850int intel_opregion_setup(struct drm_i915_privateinteldrm_softc *dev_priv)
851{
852 struct intel_opregion *opregion = &dev_priv->opregion;
853 struct pci_dev *pdev = dev_priv->drm.pdev;
854 u32 asls, mboxes;
855 char buf[sizeof(OPREGION_SIGNATURE"IntelGraphicsMem")];
856 int err = 0;
857 void *base;
858 const void *vbt;
859 u32 vbt_size;
860
861 BUILD_BUG_ON(sizeof(struct opregion_header) != 0x100)extern char _ctassert[(!(sizeof(struct opregion_header) != 0x100
)) ? 1 : -1 ] __attribute__((__unused__))
;
862 BUILD_BUG_ON(sizeof(struct opregion_acpi) != 0x100)extern char _ctassert[(!(sizeof(struct opregion_acpi) != 0x100
)) ? 1 : -1 ] __attribute__((__unused__))
;
863 BUILD_BUG_ON(sizeof(struct opregion_swsci) != 0x100)extern char _ctassert[(!(sizeof(struct opregion_swsci) != 0x100
)) ? 1 : -1 ] __attribute__((__unused__))
;
864 BUILD_BUG_ON(sizeof(struct opregion_asle) != 0x100)extern char _ctassert[(!(sizeof(struct opregion_asle) != 0x100
)) ? 1 : -1 ] __attribute__((__unused__))
;
865 BUILD_BUG_ON(sizeof(struct opregion_asle_ext) != 0x400)extern char _ctassert[(!(sizeof(struct opregion_asle_ext) != 0x400
)) ? 1 : -1 ] __attribute__((__unused__))
;
866
867 pci_read_config_dword(pdev, ASLS0xfc, &asls);
868 drm_dbg(&dev_priv->drm, "graphic opregion physical addr: 0x%x\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "graphic opregion physical addr: 0x%x\n"
, asls)
869 asls)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "graphic opregion physical addr: 0x%x\n"
, asls)
;
870 if (asls == 0) {
1
Assuming 'asls' is not equal to 0
2
Taking false branch
871 drm_dbg(&dev_priv->drm, "ACPI OpRegion not supported!\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ACPI OpRegion not supported!\n"
)
;
872 return -ENOTSUPP91;
873 }
874
875 INIT_WORK(&opregion->asle_work, asle_work);
876
877#ifdef __linux__
878 base = memremap(asls, OPREGION_SIZE(8 * 1024), MEMREMAP_WB);
879 if (!base)
880 return -ENOMEM12;
881#else
882 if (bus_space_map(dev_priv->bst, asls, OPREGION_SIZE(8 * 1024),
3
Assuming the condition is false
4
Taking false branch
883 BUS_SPACE_MAP_LINEAR0x0002, &dev_priv->opregion_ioh))
884 return -ENOMEM12;
885 base = bus_space_vaddr(dev_priv->bst, dev_priv->opregion_ioh)((dev_priv->bst)->vaddr((dev_priv->opregion_ioh)));
886#endif
887
888 memcpy(buf, base, sizeof(buf))__builtin_memcpy((buf), (base), (sizeof(buf)));
889
890 if (memcmp(buf, OPREGION_SIGNATURE, 16)__builtin_memcmp((buf), ("IntelGraphicsMem"), (16))) {
5
Assuming the condition is false
6
Taking false branch
891 drm_dbg(&dev_priv->drm, "opregion signature mismatch\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "opregion signature mismatch\n"
)
;
892 err = -EINVAL22;
893 goto err_out;
894 }
895 opregion->header = base;
896 opregion->lid_state = base + ACPI_CLID0x01ac;
897
898 drm_dbg(&dev_priv->drm, "ACPI OpRegion version %u.%u.%u\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ACPI OpRegion version %u.%u.%u\n"
, opregion->header->over.major, opregion->header->
over.minor, opregion->header->over.revision)
899 opregion->header->over.major,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ACPI OpRegion version %u.%u.%u\n"
, opregion->header->over.major, opregion->header->
over.minor, opregion->header->over.revision)
900 opregion->header->over.minor,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ACPI OpRegion version %u.%u.%u\n"
, opregion->header->over.major, opregion->header->
over.minor, opregion->header->over.revision)
901 opregion->header->over.revision)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ACPI OpRegion version %u.%u.%u\n"
, opregion->header->over.major, opregion->header->
over.minor, opregion->header->over.revision)
;
902
903 mboxes = opregion->header->mboxes;
904 if (mboxes & MBOX_ACPI(1<<0)) {
7
Assuming the condition is false
8
Taking false branch
905 drm_dbg(&dev_priv->drm, "Public ACPI methods supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "Public ACPI methods supported\n"
)
;
906 opregion->acpi = base + OPREGION_ACPI_OFFSET0x100;
907 /*
908 * Indicate we handle monitor hotplug events ourselves so we do
909 * not need ACPI notifications for them. Disabling these avoids
910 * triggering the AML code doing the notifation, which may be
911 * broken as Windows also seems to disable these.
912 */
913 opregion->acpi->chpd = 1;
914 }
915
916 if (mboxes & MBOX_SWSCI(1<<1)) {
9
Assuming the condition is false
10
Taking false branch
917 drm_dbg(&dev_priv->drm, "SWSCI supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "SWSCI supported\n"
)
;
918 opregion->swsci = base + OPREGION_SWSCI_OFFSET0x200;
919 swsci_setup(dev_priv);
920 }
921
922 if (mboxes & MBOX_ASLE(1<<2)) {
11
Assuming the condition is false
12
Taking false branch
923 drm_dbg(&dev_priv->drm, "ASLE supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ASLE supported\n"
)
;
924 opregion->asle = base + OPREGION_ASLE_OFFSET0x300;
925
926 opregion->asle->ardy = ASLE_ARDY_NOT_READY(0 << 0);
927 }
928
929 if (mboxes & MBOX_ASLE_EXT(1<<4))
13
Assuming the condition is false
14
Taking false branch
930 drm_dbg(&dev_priv->drm, "ASLE extension supported\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_DRIVER, "ASLE extension supported\n"
)
;
931
932 if (intel_load_vbt_firmware(dev_priv) == 0)
15
Calling 'intel_load_vbt_firmware'
933 goto out;
934
935 if (dmi_check_system(intel_no_opregion_vbt))
936 goto out;
937
938 if (opregion->header->over.major >= 2 && opregion->asle &&
939 opregion->asle->rvda && opregion->asle->rvds) {
940 resource_size_t rvda = opregion->asle->rvda;
941
942 /*
943 * opregion 2.0: rvda is the physical VBT address.
944 *
945 * opregion 2.1+: rvda is unsigned, relative offset from
946 * opregion base, and should never point within opregion.
947 */
948 if (opregion->header->over.major > 2 ||
949 opregion->header->over.minor >= 1) {
950 drm_WARN_ON(&dev_priv->drm, rvda < OPREGION_SIZE)({ int __ret = !!((rvda < (8 * 1024))); if (__ret) printf(
"%s %s: " "%s", dev_driver_string(((&dev_priv->drm))->
dev), "", "drm_WARN_ON(" "rvda < (8 * 1024)" ")"); __builtin_expect
(!!(__ret), 0); })
;
951
952 rvda += asls;
953 }
954
955#ifdef __linux__
956 opregion->rvda = memremap(rvda, opregion->asle->rvds,
957 MEMREMAP_WB);
958#else
959 if (bus_space_map(dev_priv->bst, rvda, opregion->asle->rvds,
960 BUS_SPACE_MAP_LINEAR0x0002, &dev_priv->opregion_rvda_ioh))
961 return -ENOMEM12;
962 opregion->rvda = bus_space_vaddr(dev_priv->bst,((dev_priv->bst)->vaddr((dev_priv->opregion_rvda_ioh
)))
963 dev_priv->opregion_rvda_ioh)((dev_priv->bst)->vaddr((dev_priv->opregion_rvda_ioh
)))
;
964 dev_priv->opregion_rvda_size = opregion->asle->rvds;
965#endif
966
967 vbt = opregion->rvda;
968 vbt_size = opregion->asle->rvds;
969 if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
970 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Found valid VBT in ACPI OpRegion (RVDA)\n"
)
971 "Found valid VBT in ACPI OpRegion (RVDA)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Found valid VBT in ACPI OpRegion (RVDA)\n"
)
;
972 opregion->vbt = vbt;
973 opregion->vbt_size = vbt_size;
974 goto out;
975 } else {
976 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid VBT in ACPI OpRegion (RVDA)\n"
)
977 "Invalid VBT in ACPI OpRegion (RVDA)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid VBT in ACPI OpRegion (RVDA)\n"
)
;
978#ifdef __linux__
979 memunmap(opregion->rvda);
980#else
981 bus_space_unmap(dev_priv->bst, dev_priv->opregion_rvda_ioh,
982 dev_priv->opregion_rvda_size);
983#endif
984 opregion->rvda = NULL((void *)0);
985 }
986 }
987
988 vbt = base + OPREGION_VBT_OFFSET0x400;
989 /*
990 * The VBT specification says that if the ASLE ext mailbox is not used
991 * its area is reserved, but on some CHT boards the VBT extends into the
992 * ASLE ext area. Allow this even though it is against the spec, so we
993 * do not end up rejecting the VBT on those boards (and end up not
994 * finding the LCD panel because of this).
995 */
996 vbt_size = (mboxes & MBOX_ASLE_EXT(1<<4)) ?
997 OPREGION_ASLE_EXT_OFFSET0x1C00 : OPREGION_SIZE(8 * 1024);
998 vbt_size -= OPREGION_VBT_OFFSET0x400;
999 if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
1000 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Found valid VBT in ACPI OpRegion (Mailbox #4)\n"
)
1001 "Found valid VBT in ACPI OpRegion (Mailbox #4)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Found valid VBT in ACPI OpRegion (Mailbox #4)\n"
)
;
1002 opregion->vbt = vbt;
1003 opregion->vbt_size = vbt_size;
1004 } else {
1005 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid VBT in ACPI OpRegion (Mailbox #4)\n"
)
1006 "Invalid VBT in ACPI OpRegion (Mailbox #4)\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid VBT in ACPI OpRegion (Mailbox #4)\n"
)
;
1007 }
1008
1009out:
1010 return 0;
1011
1012err_out:
1013#ifdef __linux__
1014 memunmap(base);
1015#else
1016 bus_space_unmap(dev_priv->bst, dev_priv->opregion_ioh, OPREGION_SIZE(8 * 1024));
1017#endif
1018 return err;
1019}
1020
1021static int intel_use_opregion_panel_type_callback(const struct dmi_system_id *id)
1022{
1023 DRM_INFO("Using panel type from OpRegion on %s\n", id->ident)printk("\0016" "[" "drm" "] " "Using panel type from OpRegion on %s\n"
, id->ident)
;
1024 return 1;
1025}
1026
1027static const struct dmi_system_id intel_use_opregion_panel_type[] = {
1028 {
1029 .callback = intel_use_opregion_panel_type_callback,
1030 .ident = "Conrac GmbH IX45GM2",
1031 .matches = {DMI_MATCH(DMI_SYS_VENDOR, "Conrac GmbH"){(DMI_SYS_VENDOR), ("Conrac GmbH")},
1032 DMI_MATCH(DMI_PRODUCT_NAME, "IX45GM2"){(DMI_PRODUCT_NAME), ("IX45GM2")},
1033 },
1034 },
1035 { }
1036};
1037
1038int
1039intel_opregion_get_panel_type(struct drm_i915_privateinteldrm_softc *dev_priv)
1040{
1041 u32 panel_details;
1042 int ret;
1043
1044 ret = swsci(dev_priv, SWSCI_GBDA_PANEL_DETAILS((4) << 1 | (5) << 8), 0x0, &panel_details);
1045 if (ret) {
1046 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Failed to get panel details from OpRegion (%d)\n"
, ret)
1047 "Failed to get panel details from OpRegion (%d)\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Failed to get panel details from OpRegion (%d)\n"
, ret)
1048 ret)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Failed to get panel details from OpRegion (%d)\n"
, ret)
;
1049 return ret;
1050 }
1051
1052 ret = (panel_details >> 8) & 0xff;
1053 if (ret > 0x10) {
1054 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid OpRegion panel type 0x%x\n"
, ret)
1055 "Invalid OpRegion panel type 0x%x\n", ret)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Invalid OpRegion panel type 0x%x\n"
, ret)
;
1056 return -EINVAL22;
1057 }
1058
1059 /* fall back to VBT panel type? */
1060 if (ret == 0x0) {
1061 drm_dbg_kms(&dev_priv->drm, "No panel type in OpRegion\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "No panel type in OpRegion\n"
)
;
1062 return -ENODEV19;
1063 }
1064
1065 /*
1066 * So far we know that some machined must use it, others must not use it.
1067 * There doesn't seem to be any way to determine which way to go, except
1068 * via a quirk list :(
1069 */
1070 if (!dmi_check_system(intel_use_opregion_panel_type)) {
1071 drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Ignoring OpRegion panel type (%d)\n"
, ret - 1)
1072 "Ignoring OpRegion panel type (%d)\n", ret - 1)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "Ignoring OpRegion panel type (%d)\n"
, ret - 1)
;
1073 return -ENODEV19;
1074 }
1075
1076 return ret - 1;
1077}
1078
1079void intel_opregion_register(struct drm_i915_privateinteldrm_softc *i915)
1080{
1081 struct intel_opregion *opregion = &i915->opregion;
1082
1083 if (!opregion->header)
1084 return;
1085
1086 if (opregion->acpi) {
1087#ifdef notyet
1088 opregion->acpi_notifier.notifier_call =
1089 intel_opregion_video_event;
1090 register_acpi_notifier(&opregion->acpi_notifier);
1091#endif
1092 }
1093
1094 intel_opregion_resume(i915);
1095}
1096
1097void intel_opregion_resume(struct drm_i915_privateinteldrm_softc *i915)
1098{
1099 struct intel_opregion *opregion = &i915->opregion;
1100
1101 if (!opregion->header)
1102 return;
1103
1104 if (opregion->acpi) {
1105#ifdef notyet
1106 intel_didl_outputs(i915);
1107 intel_setup_cadls(i915);
1108#endif
1109
1110 /*
1111 * Notify BIOS we are ready to handle ACPI video ext notifs.
1112 * Right now, all the events are handled by the ACPI video
1113 * module. We don't actually need to do anything with them.
1114 */
1115 opregion->acpi->csts = 0;
1116 opregion->acpi->drdy = 1;
1117 }
1118
1119 if (opregion->asle) {
1120 opregion->asle->tche = ASLE_TCHE_BLC_EN(1 << 1);
1121 opregion->asle->ardy = ASLE_ARDY_READY(1 << 0);
1122 }
1123
1124 intel_opregion_notify_adapter(i915, PCI_D0);
1125}
1126
1127void intel_opregion_suspend(struct drm_i915_privateinteldrm_softc *i915, pci_power_t state)
1128{
1129 struct intel_opregion *opregion = &i915->opregion;
1130
1131 if (!opregion->header)
1132 return;
1133
1134 intel_opregion_notify_adapter(i915, state);
1135
1136 if (opregion->asle)
1137 opregion->asle->ardy = ASLE_ARDY_NOT_READY(0 << 0);
1138
1139 cancel_work_sync(&i915->opregion.asle_work);
1140
1141 if (opregion->acpi)
1142 opregion->acpi->drdy = 0;
1143}
1144
1145void intel_opregion_unregister(struct drm_i915_privateinteldrm_softc *i915)
1146{
1147 struct intel_opregion *opregion = &i915->opregion;
1148
1149 intel_opregion_suspend(i915, PCI_D1);
1150
1151 if (!opregion->header)
1152 return;
1153
1154 if (opregion->acpi_notifier.notifier_call) {
1155 unregister_acpi_notifier(&opregion->acpi_notifier);
1156 opregion->acpi_notifier.notifier_call = NULL((void *)0);
1157 }
1158
1159 /* just clear all opregion memory pointers now */
1160#ifdef __linux__
1161 memunmap(opregion->header);
1162 if (opregion->rvda) {
1163 memunmap(opregion->rvda);
1164 opregion->rvda = NULL((void *)0);
1165 }
1166#else
1167 bus_space_unmap(i915->bst, i915->opregion_ioh, OPREGION_SIZE(8 * 1024));
1168 if (opregion->rvda) {
1169 bus_space_unmap(i915->bst, i915->opregion_rvda_ioh,
1170 i915->opregion_rvda_size);
1171 opregion->rvda = NULL((void *)0);
1172 }
1173#endif
1174 if (opregion->vbt_firmware) {
1175 kfree(opregion->vbt_firmware);
1176 opregion->vbt_firmware = NULL((void *)0);
1177 }
1178 opregion->header = NULL((void *)0);
1179 opregion->acpi = NULL((void *)0);
1180 opregion->swsci = NULL((void *)0);
1181 opregion->asle = NULL((void *)0);
1182 opregion->vbt = NULL((void *)0);
1183 opregion->lid_state = NULL((void *)0);
1184}

/usr/src/sys/dev/pci/drm/include/linux/firmware.h

1/* Public domain. */
2
3#ifndef _LINUX_FIRMWARE_H
4#define _LINUX_FIRMWARE_H
5
6#include <sys/types.h>
7#include <sys/malloc.h>
8#include <sys/device.h>
9#include <linux/types.h>
10#include <linux/gfp.h>
11
12#ifndef __DECONST
13#define __DECONST(type, var)((type)(__uintptr_t)(const void *)(var)) ((type)(__uintptr_t)(const void *)(var))
14#endif
15
16struct firmware {
17 size_t size;
18 const u8 *data;
19};
20
21static inline int
22request_firmware(const struct firmware **fw, const char *name,
23 struct device *device)
24{
25 int r;
26 struct firmware *f = malloc(sizeof(struct firmware), M_DRM145,
27 M_WAITOK0x0001 | M_ZERO0x0008);
28 r = loadfirmware(name, __DECONST(u_char **, &f->data)((u_char **)(__uintptr_t)(const void *)(&f->data)), &f->size);
29 if (r != 0) {
20
Assuming 'r' is not equal to 0
21
Taking true branch
30 free(f, M_DRM145, sizeof(struct firmware));
31 *fw = NULL((void *)0);
22
Null pointer value stored to 'fw'
32 return -r;
33 } else {
34 *fw = f;
35 return 0;
36 }
37}
38
39static inline int
40request_firmware_direct(const struct firmware **fw, const char *name,
41 struct device *device)
42{
43 return request_firmware(fw, name, device);
44}
45
46#define request_firmware_nowait(a, b, c, d, e, f, g)-22 -EINVAL22
47
48static inline void
49release_firmware(const struct firmware *fw)
50{
51 if (fw)
52 free(__DECONST(u_char *, fw->data)((u_char *)(__uintptr_t)(const void *)(fw->data)), M_DEVBUF2, fw->size);
53 free(__DECONST(struct firmware *, fw)((struct firmware *)(__uintptr_t)(const void *)(fw)), M_DRM145, sizeof(*fw));
54}
55
56#endif