2 * Copyright 2011 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
26 #include <core/option.h>
27 #include <core/notify.h>
30 nvkm_gpio_drive(struct nvkm_gpio
*gpio
, int idx
, int line
, int dir
, int out
)
32 return gpio
->func
->drive(gpio
, line
, dir
, out
);
36 nvkm_gpio_sense(struct nvkm_gpio
*gpio
, int idx
, int line
)
38 return gpio
->func
->sense(gpio
, line
);
42 nvkm_gpio_reset(struct nvkm_gpio
*gpio
, u8 func
)
44 if (gpio
->func
->reset
)
45 gpio
->func
->reset(gpio
, func
);
49 nvkm_gpio_find(struct nvkm_gpio
*gpio
, int idx
, u8 tag
, u8 line
,
50 struct dcb_gpio_func
*func
)
52 struct nvkm_device
*device
= gpio
->subdev
.device
;
53 struct nvkm_bios
*bios
= device
->bios
;
57 if (line
== 0xff && tag
== 0xff)
60 data
= dcb_gpio_match(bios
, idx
, tag
, line
, &ver
, &len
, func
);
64 /* Apple iMac G4 NV18 */
65 if (device
->quirk
&& device
->quirk
->tv_gpio
) {
66 if (tag
== DCB_GPIO_TVDAC0
) {
67 *func
= (struct dcb_gpio_func
) {
68 .func
= DCB_GPIO_TVDAC0
,
69 .line
= device
->quirk
->tv_gpio
,
81 nvkm_gpio_set(struct nvkm_gpio
*gpio
, int idx
, u8 tag
, u8 line
, int state
)
83 struct dcb_gpio_func func
;
86 ret
= nvkm_gpio_find(gpio
, idx
, tag
, line
, &func
);
88 int dir
= !!(func
.log
[state
] & 0x02);
89 int out
= !!(func
.log
[state
] & 0x01);
90 ret
= nvkm_gpio_drive(gpio
, idx
, func
.line
, dir
, out
);
97 nvkm_gpio_get(struct nvkm_gpio
*gpio
, int idx
, u8 tag
, u8 line
)
99 struct dcb_gpio_func func
;
102 ret
= nvkm_gpio_find(gpio
, idx
, tag
, line
, &func
);
104 ret
= nvkm_gpio_sense(gpio
, idx
, func
.line
);
106 ret
= (ret
== (func
.log
[1] & 1));
113 nvkm_gpio_intr_fini(struct nvkm_event
*event
, int type
, int index
)
115 struct nvkm_gpio
*gpio
= container_of(event
, typeof(*gpio
), event
);
116 gpio
->func
->intr_mask(gpio
, type
, 1 << index
, 0);
120 nvkm_gpio_intr_init(struct nvkm_event
*event
, int type
, int index
)
122 struct nvkm_gpio
*gpio
= container_of(event
, typeof(*gpio
), event
);
123 gpio
->func
->intr_mask(gpio
, type
, 1 << index
, 1 << index
);
127 nvkm_gpio_intr_ctor(struct nvkm_object
*object
, void *data
, u32 size
,
128 struct nvkm_notify
*notify
)
130 struct nvkm_gpio_ntfy_req
*req
= data
;
131 if (!WARN_ON(size
!= sizeof(*req
))) {
132 notify
->size
= sizeof(struct nvkm_gpio_ntfy_rep
);
133 notify
->types
= req
->mask
;
134 notify
->index
= req
->line
;
140 static const struct nvkm_event_func
141 nvkm_gpio_intr_func
= {
142 .ctor
= nvkm_gpio_intr_ctor
,
143 .init
= nvkm_gpio_intr_init
,
144 .fini
= nvkm_gpio_intr_fini
,
148 nvkm_gpio_intr(struct nvkm_subdev
*subdev
)
150 struct nvkm_gpio
*gpio
= nvkm_gpio(subdev
);
153 gpio
->func
->intr_stat(gpio
, &hi
, &lo
);
155 for (i
= 0; (hi
| lo
) && i
< gpio
->func
->lines
; i
++) {
156 struct nvkm_gpio_ntfy_rep rep
= {
157 .mask
= (NVKM_GPIO_HI
* !!(hi
& (1 << i
))) |
158 (NVKM_GPIO_LO
* !!(lo
& (1 << i
))),
160 nvkm_event_send(&gpio
->event
, rep
.mask
, i
, &rep
, sizeof(rep
));
165 nvkm_gpio_fini(struct nvkm_subdev
*subdev
, bool suspend
)
167 struct nvkm_gpio
*gpio
= nvkm_gpio(subdev
);
168 u32 mask
= (1ULL << gpio
->func
->lines
) - 1;
170 gpio
->func
->intr_mask(gpio
, NVKM_GPIO_TOGGLED
, mask
, 0);
171 gpio
->func
->intr_stat(gpio
, &mask
, &mask
);
175 static const struct dmi_system_id gpio_reset_ids
[] = {
177 .ident
= "Apple Macbook 10,1",
179 DMI_MATCH(DMI_SYS_VENDOR
, "Apple Inc."),
180 DMI_MATCH(DMI_PRODUCT_NAME
, "MacBookPro10,1"),
186 static enum dcb_gpio_func_name power_checks
[] = {
187 DCB_GPIO_THERM_EXT_POWER_EVENT
,
188 DCB_GPIO_POWER_ALERT
,
189 DCB_GPIO_EXT_POWER_LOW
,
193 nvkm_gpio_init(struct nvkm_subdev
*subdev
)
195 struct nvkm_gpio
*gpio
= nvkm_gpio(subdev
);
196 struct dcb_gpio_func func
;
200 if (dmi_check_system(gpio_reset_ids
))
201 nvkm_gpio_reset(gpio
, DCB_GPIO_UNUSED
);
203 if (nvkm_boolopt(subdev
->device
->cfgopt
, "NvPowerChecks", true)) {
204 for (i
= 0; i
< ARRAY_SIZE(power_checks
); ++i
) {
205 ret
= nvkm_gpio_find(gpio
, 0, power_checks
[i
],
206 DCB_GPIO_UNUSED
, &func
);
210 ret
= nvkm_gpio_get(gpio
, 0, func
.func
, func
.line
);
214 nvkm_error(&gpio
->subdev
,
215 "GPU is missing power, check its power "
217 "nouveau.config=NvPowerChecks=0 to "
227 nvkm_gpio_dtor(struct nvkm_subdev
*subdev
)
229 struct nvkm_gpio
*gpio
= nvkm_gpio(subdev
);
230 nvkm_event_fini(&gpio
->event
);
234 static const struct nvkm_subdev_func
236 .dtor
= nvkm_gpio_dtor
,
237 .init
= nvkm_gpio_init
,
238 .fini
= nvkm_gpio_fini
,
239 .intr
= nvkm_gpio_intr
,
243 nvkm_gpio_new_(const struct nvkm_gpio_func
*func
, struct nvkm_device
*device
,
244 int index
, struct nvkm_gpio
**pgpio
)
246 struct nvkm_gpio
*gpio
;
248 if (!(gpio
= *pgpio
= kzalloc(sizeof(*gpio
), GFP_KERNEL
)))
251 nvkm_subdev_ctor(&nvkm_gpio
, device
, index
, &gpio
->subdev
);
254 return nvkm_event_init(&nvkm_gpio_intr_func
, 2, func
->lines
,