Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: MIT
nvkm-y += nvkm/subdev/gpio/base.o
nvkm-y += nvkm/subdev/gpio/nv10.o
nvkm-y += nvkm/subdev/gpio/nv50.o
nvkm-y += nvkm/subdev/gpio/g94.o
nvkm-y += nvkm/subdev/gpio/gf119.o
nvkm-y += nvkm/subdev/gpio/gk104.o
nvkm-y += nvkm/subdev/gpio/ga102.o
@@ -0,0 +1,237 @@
/*
* Copyright 2011 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "priv.h"
#include <core/option.h>
static int
nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out)
{
return gpio->func->drive(gpio, line, dir, out);
}
static int
nvkm_gpio_sense(struct nvkm_gpio *gpio, int idx, int line)
{
return gpio->func->sense(gpio, line);
}
void
nvkm_gpio_reset(struct nvkm_gpio *gpio, u8 func)
{
if (gpio->func->reset)
gpio->func->reset(gpio, func);
}
int
nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line,
struct dcb_gpio_func *func)
{
struct nvkm_device *device = gpio->subdev.device;
struct nvkm_bios *bios = device->bios;
u8 ver, len;
u16 data;
if (line == 0xff && tag == 0xff)
return -EINVAL;
data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
if (data)
return 0;
/* Apple iMac G4 NV18 */
if (device->quirk && device->quirk->tv_gpio) {
if (tag == DCB_GPIO_TVDAC0) {
*func = (struct dcb_gpio_func) {
.func = DCB_GPIO_TVDAC0,
.line = device->quirk->tv_gpio,
.log[0] = 0,
.log[1] = 1,
};
return 0;
}
}
return -ENOENT;
}
int
nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state)
{
struct dcb_gpio_func func;
int ret;
ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
if (ret == 0) {
int dir = !!(func.log[state] & 0x02);
int out = !!(func.log[state] & 0x01);
ret = nvkm_gpio_drive(gpio, idx, func.line, dir, out);
}
return ret;
}
int
nvkm_gpio_get(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line)
{
struct dcb_gpio_func func;
int ret;
ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
if (ret == 0) {
ret = nvkm_gpio_sense(gpio, idx, func.line);
if (ret >= 0)
ret = (ret == (func.log[1] & 1));
}
return ret;
}
static void
nvkm_gpio_intr_fini(struct nvkm_event *event, int type, int index)
{
struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
gpio->func->intr_mask(gpio, type, 1 << index, 0);
}
static void
nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index)
{
struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
gpio->func->intr_mask(gpio, type, 1 << index, 1 << index);
}
static const struct nvkm_event_func
nvkm_gpio_intr_func = {
.init = nvkm_gpio_intr_init,
.fini = nvkm_gpio_intr_fini,
};
static void
nvkm_gpio_intr(struct nvkm_subdev *subdev)
{
struct nvkm_gpio *gpio = nvkm_gpio(subdev);
u32 hi, lo, i;
gpio->func->intr_stat(gpio, &hi, &lo);
for (i = 0; (hi | lo) && i < gpio->func->lines; i++) {
u32 mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
(NVKM_GPIO_LO * !!(lo & (1 << i)));
nvkm_event_ntfy(&gpio->event, i, mask);
}
}
static int
nvkm_gpio_fini(struct nvkm_subdev *subdev, enum nvkm_suspend_state suspend)
{
struct nvkm_gpio *gpio = nvkm_gpio(subdev);
u32 mask = (1ULL << gpio->func->lines) - 1;
gpio->func->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
gpio->func->intr_stat(gpio, &mask, &mask);
return 0;
}
static const struct dmi_system_id gpio_reset_ids[] = {
{
.ident = "Apple Macbook 10,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
}
},
{ }
};
static enum dcb_gpio_func_name power_checks[] = {
DCB_GPIO_THERM_EXT_POWER_EVENT,
DCB_GPIO_POWER_ALERT,
DCB_GPIO_EXT_POWER_LOW,
};
static int
nvkm_gpio_init(struct nvkm_subdev *subdev)
{
struct nvkm_gpio *gpio = nvkm_gpio(subdev);
struct dcb_gpio_func func;
int ret;
int i;
if (dmi_check_system(gpio_reset_ids))
nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED);
if (nvkm_boolopt(subdev->device->cfgopt, "NvPowerChecks", true)) {
for (i = 0; i < ARRAY_SIZE(power_checks); ++i) {
ret = nvkm_gpio_find(gpio, 0, power_checks[i],
DCB_GPIO_UNUSED, &func);
if (ret)
continue;
ret = nvkm_gpio_get(gpio, 0, func.func, func.line);
if (!ret)
continue;
nvkm_error(&gpio->subdev,
"GPU is missing power, check its power "
"cables. Boot with "
"nouveau.config=NvPowerChecks=0 to "
"disable.\n");
return -EINVAL;
}
}
return 0;
}
static void *
nvkm_gpio_dtor(struct nvkm_subdev *subdev)
{
struct nvkm_gpio *gpio = nvkm_gpio(subdev);
nvkm_event_fini(&gpio->event);
return gpio;
}
static const struct nvkm_subdev_func
nvkm_gpio = {
.dtor = nvkm_gpio_dtor,
.init = nvkm_gpio_init,
.fini = nvkm_gpio_fini,
.intr = nvkm_gpio_intr,
};
int
nvkm_gpio_new_(const struct nvkm_gpio_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_gpio **pgpio)
{
struct nvkm_gpio *gpio;
if (!(gpio = *pgpio = kzalloc_obj(*gpio)))
return -ENOMEM;
nvkm_subdev_ctor(&nvkm_gpio, device, type, inst, &gpio->subdev);
gpio->func = func;
return nvkm_event_init(&nvkm_gpio_intr_func, &gpio->subdev, 2, func->lines, &gpio->event);
}
@@ -0,0 +1,75 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "priv.h"
void
g94_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
{
struct nvkm_device *device = gpio->subdev.device;
u32 intr0 = nvkm_rd32(device, 0x00e054);
u32 intr1 = nvkm_rd32(device, 0x00e074);
u32 stat0 = nvkm_rd32(device, 0x00e050) & intr0;
u32 stat1 = nvkm_rd32(device, 0x00e070) & intr1;
*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
nvkm_wr32(device, 0x00e054, intr0);
nvkm_wr32(device, 0x00e074, intr1);
}
void
g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
{
struct nvkm_device *device = gpio->subdev.device;
u32 inte0 = nvkm_rd32(device, 0x00e050);
u32 inte1 = nvkm_rd32(device, 0x00e070);
if (type & NVKM_GPIO_LO)
inte0 = (inte0 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
mask >>= 16;
data >>= 16;
if (type & NVKM_GPIO_LO)
inte1 = (inte1 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte1 = (inte1 & ~mask) | data;
nvkm_wr32(device, 0x00e050, inte0);
nvkm_wr32(device, 0x00e070, inte1);
}
static const struct nvkm_gpio_func
g94_gpio = {
.lines = 32,
.intr_stat = g94_gpio_intr_stat,
.intr_mask = g94_gpio_intr_mask,
.drive = nv50_gpio_drive,
.sense = nv50_gpio_sense,
.reset = nv50_gpio_reset,
};
int
g94_gpio_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_gpio **pgpio)
{
return nvkm_gpio_new_(&g94_gpio, device, type, inst, pgpio);
}
@@ -0,0 +1,124 @@
/*
* Copyright 2021 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "priv.h"
#include <subdev/gsp.h>
static void
ga102_gpio_reset(struct nvkm_gpio *gpio, u8 match)
{
struct nvkm_device *device = gpio->subdev.device;
struct nvkm_bios *bios = device->bios;
u8 ver, len;
u16 entry;
int ent = -1;
while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
u32 data = nvbios_rd32(bios, entry);
u8 line = (data & 0x0000003f);
u8 defs = !!(data & 0x00000080);
u8 func = (data & 0x0000ff00) >> 8;
u8 unk0 = (data & 0x00ff0000) >> 16;
u8 unk1 = (data & 0x1f000000) >> 24;
if ( func == DCB_GPIO_UNUSED ||
(match != DCB_GPIO_UNUSED && match != func))
continue;
nvkm_gpio_set(gpio, 0, func, line, defs);
nvkm_mask(device, 0x021200 + (line * 4), 0xff, unk0);
if (unk1--)
nvkm_mask(device, 0x00d740 + (unk1 * 4), 0xff, line);
}
}
static int
ga102_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
{
struct nvkm_device *device = gpio->subdev.device;
u32 data = ((dir ^ 1) << 13) | (out << 12);
nvkm_mask(device, 0x021200 + (line * 4), 0x00003000, data);
nvkm_mask(device, 0x00d604, 0x00000001, 0x00000001); /* update? */
return 0;
}
static int
ga102_gpio_sense(struct nvkm_gpio *gpio, int line)
{
struct nvkm_device *device = gpio->subdev.device;
return !!(nvkm_rd32(device, 0x021200 + (line * 4)) & 0x00004000);
}
static void
ga102_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
{
struct nvkm_device *device = gpio->subdev.device;
u32 intr0 = nvkm_rd32(device, 0x021640);
u32 intr1 = nvkm_rd32(device, 0x02164c);
u32 stat0 = nvkm_rd32(device, 0x021648) & intr0;
u32 stat1 = nvkm_rd32(device, 0x021654) & intr1;
*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
nvkm_wr32(device, 0x021640, intr0);
nvkm_wr32(device, 0x02164c, intr1);
}
static void
ga102_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
{
struct nvkm_device *device = gpio->subdev.device;
u32 inte0 = nvkm_rd32(device, 0x021648);
u32 inte1 = nvkm_rd32(device, 0x021654);
if (type & NVKM_GPIO_LO)
inte0 = (inte0 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
mask >>= 16;
data >>= 16;
if (type & NVKM_GPIO_LO)
inte1 = (inte1 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte1 = (inte1 & ~mask) | data;
nvkm_wr32(device, 0x021648, inte0);
nvkm_wr32(device, 0x021654, inte1);
}
static const struct nvkm_gpio_func
ga102_gpio = {
.lines = 32,
.intr_stat = ga102_gpio_intr_stat,
.intr_mask = ga102_gpio_intr_mask,
.drive = ga102_gpio_drive,
.sense = ga102_gpio_sense,
.reset = ga102_gpio_reset,
};
int
ga102_gpio_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_gpio **pgpio)
{
if (nvkm_gsp_rm(device->gsp))
return -ENODEV;
return nvkm_gpio_new_(&ga102_gpio, device, type, inst, pgpio);
}
@@ -0,0 +1,87 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "priv.h"
void
gf119_gpio_reset(struct nvkm_gpio *gpio, u8 match)
{
struct nvkm_device *device = gpio->subdev.device;
struct nvkm_bios *bios = device->bios;
u8 ver, len;
u16 entry;
int ent = -1;
while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
u32 data = nvbios_rd32(bios, entry);
u8 line = (data & 0x0000003f);
u8 defs = !!(data & 0x00000080);
u8 func = (data & 0x0000ff00) >> 8;
u8 unk0 = (data & 0x00ff0000) >> 16;
u8 unk1 = (data & 0x1f000000) >> 24;
if ( func == DCB_GPIO_UNUSED ||
(match != DCB_GPIO_UNUSED && match != func))
continue;
nvkm_gpio_set(gpio, 0, func, line, defs);
nvkm_mask(device, 0x00d610 + (line * 4), 0xff, unk0);
if (unk1--)
nvkm_mask(device, 0x00d740 + (unk1 * 4), 0xff, line);
}
}
int
gf119_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
{
struct nvkm_device *device = gpio->subdev.device;
u32 data = ((dir ^ 1) << 13) | (out << 12);
nvkm_mask(device, 0x00d610 + (line * 4), 0x00003000, data);
nvkm_mask(device, 0x00d604, 0x00000001, 0x00000001); /* update? */
return 0;
}
int
gf119_gpio_sense(struct nvkm_gpio *gpio, int line)
{
struct nvkm_device *device = gpio->subdev.device;
return !!(nvkm_rd32(device, 0x00d610 + (line * 4)) & 0x00004000);
}
static const struct nvkm_gpio_func
gf119_gpio = {
.lines = 32,
.intr_stat = g94_gpio_intr_stat,
.intr_mask = g94_gpio_intr_mask,
.drive = gf119_gpio_drive,
.sense = gf119_gpio_sense,
.reset = gf119_gpio_reset,
};
int
gf119_gpio_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_gpio **pgpio)
{
return nvkm_gpio_new_(&gf119_gpio, device, type, inst, pgpio);
}
@@ -0,0 +1,80 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "priv.h"
#include <subdev/gsp.h>
static void
gk104_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
{
struct nvkm_device *device = gpio->subdev.device;
u32 intr0 = nvkm_rd32(device, 0x00dc00);
u32 intr1 = nvkm_rd32(device, 0x00dc80);
u32 stat0 = nvkm_rd32(device, 0x00dc08) & intr0;
u32 stat1 = nvkm_rd32(device, 0x00dc88) & intr1;
*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
nvkm_wr32(device, 0x00dc00, intr0);
nvkm_wr32(device, 0x00dc80, intr1);
}
static void
gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
{
struct nvkm_device *device = gpio->subdev.device;
u32 inte0 = nvkm_rd32(device, 0x00dc08);
u32 inte1 = nvkm_rd32(device, 0x00dc88);
if (type & NVKM_GPIO_LO)
inte0 = (inte0 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
mask >>= 16;
data >>= 16;
if (type & NVKM_GPIO_LO)
inte1 = (inte1 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte1 = (inte1 & ~mask) | data;
nvkm_wr32(device, 0x00dc08, inte0);
nvkm_wr32(device, 0x00dc88, inte1);
}
static const struct nvkm_gpio_func
gk104_gpio = {
.lines = 32,
.intr_stat = gk104_gpio_intr_stat,
.intr_mask = gk104_gpio_intr_mask,
.drive = gf119_gpio_drive,
.sense = gf119_gpio_sense,
.reset = gf119_gpio_reset,
};
int
gk104_gpio_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_gpio **pgpio)
{
if (nvkm_gsp_rm(device->gsp))
return -ENODEV;
return nvkm_gpio_new_(&gk104_gpio, device, type, inst, pgpio);
}
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2009 Francisco Jerez.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "priv.h"
static int
nv10_gpio_sense(struct nvkm_gpio *gpio, int line)
{
struct nvkm_device *device = gpio->subdev.device;
if (line < 2) {
line = line * 16;
line = nvkm_rd32(device, 0x600818) >> line;
return !!(line & 0x0100);
} else
if (line < 10) {
line = (line - 2) * 4;
line = nvkm_rd32(device, 0x60081c) >> line;
return !!(line & 0x04);
} else
if (line < 14) {
line = (line - 10) * 4;
line = nvkm_rd32(device, 0x600850) >> line;
return !!(line & 0x04);
}
return -EINVAL;
}
static int
nv10_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
{
struct nvkm_device *device = gpio->subdev.device;
u32 reg, mask, data;
if (line < 2) {
line = line * 16;
reg = 0x600818;
mask = 0x00000011;
data = (dir << 4) | out;
} else
if (line < 10) {
line = (line - 2) * 4;
reg = 0x60081c;
mask = 0x00000003;
data = (dir << 1) | out;
} else
if (line < 14) {
line = (line - 10) * 4;
reg = 0x600850;
mask = 0x00000003;
data = (dir << 1) | out;
} else {
return -EINVAL;
}
nvkm_mask(device, reg, mask << line, data << line);
return 0;
}
static void
nv10_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
{
struct nvkm_device *device = gpio->subdev.device;
u32 intr = nvkm_rd32(device, 0x001104);
u32 stat = nvkm_rd32(device, 0x001144) & intr;
*lo = (stat & 0xffff0000) >> 16;
*hi = (stat & 0x0000ffff);
nvkm_wr32(device, 0x001104, intr);
}
static void
nv10_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
{
struct nvkm_device *device = gpio->subdev.device;
u32 inte = nvkm_rd32(device, 0x001144);
if (type & NVKM_GPIO_LO)
inte = (inte & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte = (inte & ~mask) | data;
nvkm_wr32(device, 0x001144, inte);
}
static const struct nvkm_gpio_func
nv10_gpio = {
.lines = 16,
.intr_stat = nv10_gpio_intr_stat,
.intr_mask = nv10_gpio_intr_mask,
.drive = nv10_gpio_drive,
.sense = nv10_gpio_sense,
};
int
nv10_gpio_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_gpio **pgpio)
{
return nvkm_gpio_new_(&nv10_gpio, device, type, inst, pgpio);
}
@@ -0,0 +1,133 @@
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "priv.h"
void
nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match)
{
struct nvkm_device *device = gpio->subdev.device;
struct nvkm_bios *bios = device->bios;
u8 ver, len;
u16 entry;
int ent = -1;
while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
static const u32 regs[] = { 0xe100, 0xe28c };
u32 data = nvbios_rd32(bios, entry);
u8 line = (data & 0x0000001f);
u8 func = (data & 0x0000ff00) >> 8;
u8 defs = !!(data & 0x01000000);
u8 unk0 = !!(data & 0x02000000);
u8 unk1 = !!(data & 0x04000000);
u32 val = (unk1 << 16) | unk0;
u32 reg = regs[line >> 4];
u32 lsh = line & 0x0f;
if ( func == DCB_GPIO_UNUSED ||
(match != DCB_GPIO_UNUSED && match != func))
continue;
nvkm_gpio_set(gpio, 0, func, line, defs);
nvkm_mask(device, reg, 0x00010001 << lsh, val << lsh);
}
}
static int
nv50_gpio_location(int line, u32 *reg, u32 *shift)
{
const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
if (line >= 32)
return -EINVAL;
*reg = nv50_gpio_reg[line >> 3];
*shift = (line & 7) << 2;
return 0;
}
int
nv50_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
{
struct nvkm_device *device = gpio->subdev.device;
u32 reg, shift;
if (nv50_gpio_location(line, &reg, &shift))
return -EINVAL;
nvkm_mask(device, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift);
return 0;
}
int
nv50_gpio_sense(struct nvkm_gpio *gpio, int line)
{
struct nvkm_device *device = gpio->subdev.device;
u32 reg, shift;
if (nv50_gpio_location(line, &reg, &shift))
return -EINVAL;
return !!(nvkm_rd32(device, reg) & (4 << shift));
}
static void
nv50_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
{
struct nvkm_device *device = gpio->subdev.device;
u32 intr = nvkm_rd32(device, 0x00e054);
u32 stat = nvkm_rd32(device, 0x00e050) & intr;
*lo = (stat & 0xffff0000) >> 16;
*hi = (stat & 0x0000ffff);
nvkm_wr32(device, 0x00e054, intr);
}
static void
nv50_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
{
struct nvkm_device *device = gpio->subdev.device;
u32 inte = nvkm_rd32(device, 0x00e050);
if (type & NVKM_GPIO_LO)
inte = (inte & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte = (inte & ~mask) | data;
nvkm_wr32(device, 0x00e050, inte);
}
static const struct nvkm_gpio_func
nv50_gpio = {
.lines = 16,
.intr_stat = nv50_gpio_intr_stat,
.intr_mask = nv50_gpio_intr_mask,
.drive = nv50_gpio_drive,
.sense = nv50_gpio_sense,
.reset = nv50_gpio_reset,
};
int
nv50_gpio_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_gpio **pgpio)
{
return nvkm_gpio_new_(&nv50_gpio, device, type, inst, pgpio);
}
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_GPIO_PRIV_H__
#define __NVKM_GPIO_PRIV_H__
#define nvkm_gpio(p) container_of((p), struct nvkm_gpio, subdev)
#include <subdev/gpio.h>
struct nvkm_gpio_func {
int lines;
/* read and ack pending interrupts, returning only data
* for lines that have not been masked off, while still
* performing the ack for anything that was pending.
*/
void (*intr_stat)(struct nvkm_gpio *, u32 *, u32 *);
/* mask on/off interrupts for hi/lo transitions on a
* given set of gpio lines
*/
void (*intr_mask)(struct nvkm_gpio *, u32, u32, u32);
/* configure gpio direction and output value */
int (*drive)(struct nvkm_gpio *, int line, int dir, int out);
/* sense current state of given gpio line */
int (*sense)(struct nvkm_gpio *, int line);
/*XXX*/
void (*reset)(struct nvkm_gpio *, u8);
};
int nvkm_gpio_new_(const struct nvkm_gpio_func *, struct nvkm_device *, enum nvkm_subdev_type, int,
struct nvkm_gpio **);
void nv50_gpio_reset(struct nvkm_gpio *, u8);
int nv50_gpio_drive(struct nvkm_gpio *, int, int, int);
int nv50_gpio_sense(struct nvkm_gpio *, int);
void g94_gpio_intr_stat(struct nvkm_gpio *, u32 *, u32 *);
void g94_gpio_intr_mask(struct nvkm_gpio *, u32, u32, u32);
void gf119_gpio_reset(struct nvkm_gpio *, u8);
int gf119_gpio_drive(struct nvkm_gpio *, int, int, int);
int gf119_gpio_sense(struct nvkm_gpio *, int);
#endif