Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2011 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
0023  */
0024 #include "priv.h"
0025 
0026 #include <core/option.h>
0027 #include <core/notify.h>
0028 
0029 static int
0030 nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out)
0031 {
0032     return gpio->func->drive(gpio, line, dir, out);
0033 }
0034 
0035 static int
0036 nvkm_gpio_sense(struct nvkm_gpio *gpio, int idx, int line)
0037 {
0038     return gpio->func->sense(gpio, line);
0039 }
0040 
0041 void
0042 nvkm_gpio_reset(struct nvkm_gpio *gpio, u8 func)
0043 {
0044     if (gpio->func->reset)
0045         gpio->func->reset(gpio, func);
0046 }
0047 
0048 int
0049 nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line,
0050            struct dcb_gpio_func *func)
0051 {
0052     struct nvkm_device *device = gpio->subdev.device;
0053     struct nvkm_bios *bios = device->bios;
0054     u8  ver, len;
0055     u16 data;
0056 
0057     if (line == 0xff && tag == 0xff)
0058         return -EINVAL;
0059 
0060     data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
0061     if (data)
0062         return 0;
0063 
0064     /* Apple iMac G4 NV18 */
0065     if (device->quirk && device->quirk->tv_gpio) {
0066         if (tag == DCB_GPIO_TVDAC0) {
0067             *func = (struct dcb_gpio_func) {
0068                 .func = DCB_GPIO_TVDAC0,
0069                 .line = device->quirk->tv_gpio,
0070                 .log[0] = 0,
0071                 .log[1] = 1,
0072             };
0073             return 0;
0074         }
0075     }
0076 
0077     return -ENOENT;
0078 }
0079 
0080 int
0081 nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state)
0082 {
0083     struct dcb_gpio_func func;
0084     int ret;
0085 
0086     ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
0087     if (ret == 0) {
0088         int dir = !!(func.log[state] & 0x02);
0089         int out = !!(func.log[state] & 0x01);
0090         ret = nvkm_gpio_drive(gpio, idx, func.line, dir, out);
0091     }
0092 
0093     return ret;
0094 }
0095 
0096 int
0097 nvkm_gpio_get(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line)
0098 {
0099     struct dcb_gpio_func func;
0100     int ret;
0101 
0102     ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
0103     if (ret == 0) {
0104         ret = nvkm_gpio_sense(gpio, idx, func.line);
0105         if (ret >= 0)
0106             ret = (ret == (func.log[1] & 1));
0107     }
0108 
0109     return ret;
0110 }
0111 
0112 static void
0113 nvkm_gpio_intr_fini(struct nvkm_event *event, int type, int index)
0114 {
0115     struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
0116     gpio->func->intr_mask(gpio, type, 1 << index, 0);
0117 }
0118 
0119 static void
0120 nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index)
0121 {
0122     struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
0123     gpio->func->intr_mask(gpio, type, 1 << index, 1 << index);
0124 }
0125 
0126 static int
0127 nvkm_gpio_intr_ctor(struct nvkm_object *object, void *data, u32 size,
0128             struct nvkm_notify *notify)
0129 {
0130     struct nvkm_gpio_ntfy_req *req = data;
0131     if (!WARN_ON(size != sizeof(*req))) {
0132         notify->size  = sizeof(struct nvkm_gpio_ntfy_rep);
0133         notify->types = req->mask;
0134         notify->index = req->line;
0135         return 0;
0136     }
0137     return -EINVAL;
0138 }
0139 
0140 static const struct nvkm_event_func
0141 nvkm_gpio_intr_func = {
0142     .ctor = nvkm_gpio_intr_ctor,
0143     .init = nvkm_gpio_intr_init,
0144     .fini = nvkm_gpio_intr_fini,
0145 };
0146 
0147 static void
0148 nvkm_gpio_intr(struct nvkm_subdev *subdev)
0149 {
0150     struct nvkm_gpio *gpio = nvkm_gpio(subdev);
0151     u32 hi, lo, i;
0152 
0153     gpio->func->intr_stat(gpio, &hi, &lo);
0154 
0155     for (i = 0; (hi | lo) && i < gpio->func->lines; i++) {
0156         struct nvkm_gpio_ntfy_rep rep = {
0157             .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
0158                 (NVKM_GPIO_LO * !!(lo & (1 << i))),
0159         };
0160         nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
0161     }
0162 }
0163 
0164 static int
0165 nvkm_gpio_fini(struct nvkm_subdev *subdev, bool suspend)
0166 {
0167     struct nvkm_gpio *gpio = nvkm_gpio(subdev);
0168     u32 mask = (1ULL << gpio->func->lines) - 1;
0169 
0170     gpio->func->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
0171     gpio->func->intr_stat(gpio, &mask, &mask);
0172     return 0;
0173 }
0174 
0175 static const struct dmi_system_id gpio_reset_ids[] = {
0176     {
0177         .ident = "Apple Macbook 10,1",
0178         .matches = {
0179             DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
0180             DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
0181         }
0182     },
0183     { }
0184 };
0185 
0186 static enum dcb_gpio_func_name power_checks[] = {
0187     DCB_GPIO_THERM_EXT_POWER_EVENT,
0188     DCB_GPIO_POWER_ALERT,
0189     DCB_GPIO_EXT_POWER_LOW,
0190 };
0191 
0192 static int
0193 nvkm_gpio_init(struct nvkm_subdev *subdev)
0194 {
0195     struct nvkm_gpio *gpio = nvkm_gpio(subdev);
0196     struct dcb_gpio_func func;
0197     int ret;
0198     int i;
0199 
0200     if (dmi_check_system(gpio_reset_ids))
0201         nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED);
0202 
0203     if (nvkm_boolopt(subdev->device->cfgopt, "NvPowerChecks", true)) {
0204         for (i = 0; i < ARRAY_SIZE(power_checks); ++i) {
0205             ret = nvkm_gpio_find(gpio, 0, power_checks[i],
0206                          DCB_GPIO_UNUSED, &func);
0207             if (ret)
0208                 continue;
0209 
0210             ret = nvkm_gpio_get(gpio, 0, func.func, func.line);
0211             if (!ret)
0212                 continue;
0213 
0214             nvkm_error(&gpio->subdev,
0215                    "GPU is missing power, check its power "
0216                    "cables.  Boot with "
0217                    "nouveau.config=NvPowerChecks=0 to "
0218                    "disable.\n");
0219             return -EINVAL;
0220         }
0221     }
0222 
0223     return 0;
0224 }
0225 
0226 static void *
0227 nvkm_gpio_dtor(struct nvkm_subdev *subdev)
0228 {
0229     struct nvkm_gpio *gpio = nvkm_gpio(subdev);
0230     nvkm_event_fini(&gpio->event);
0231     return gpio;
0232 }
0233 
0234 static const struct nvkm_subdev_func
0235 nvkm_gpio = {
0236     .dtor = nvkm_gpio_dtor,
0237     .init = nvkm_gpio_init,
0238     .fini = nvkm_gpio_fini,
0239     .intr = nvkm_gpio_intr,
0240 };
0241 
0242 int
0243 nvkm_gpio_new_(const struct nvkm_gpio_func *func, struct nvkm_device *device,
0244            enum nvkm_subdev_type type, int inst, struct nvkm_gpio **pgpio)
0245 {
0246     struct nvkm_gpio *gpio;
0247 
0248     if (!(gpio = *pgpio = kzalloc(sizeof(*gpio), GFP_KERNEL)))
0249         return -ENOMEM;
0250 
0251     nvkm_subdev_ctor(&nvkm_gpio, device, type, inst, &gpio->subdev);
0252     gpio->func = func;
0253 
0254     return nvkm_event_init(&nvkm_gpio_intr_func, 2, func->lines,
0255                    &gpio->event);
0256 }